diff options
author | John Crispin <john@openwrt.org> | 2013-06-23 15:50:49 +0000 |
---|---|---|
committer | John Crispin <john@openwrt.org> | 2013-06-23 15:50:49 +0000 |
commit | 55fb6f3a05deb4a8b5e600cc10bae9555a9f90be (patch) | |
tree | a2ef24cfc434f5eb47364d944947588c5d51fc69 /target/linux/ramips/patches-3.8 | |
parent | 43a3d87b8370872c5720b4bb6616b797486d38d8 (diff) | |
download | mtk-20170518-55fb6f3a05deb4a8b5e600cc10bae9555a9f90be.zip mtk-20170518-55fb6f3a05deb4a8b5e600cc10bae9555a9f90be.tar.gz mtk-20170518-55fb6f3a05deb4a8b5e600cc10bae9555a9f90be.tar.bz2 |
ralink: update patches
Signed-off-by: John Crispin <blogic@openwrt.org>
SVN-Revision: 37016
Diffstat (limited to 'target/linux/ramips/patches-3.8')
83 files changed, 13616 insertions, 4091 deletions
diff --git a/target/linux/ramips/patches-3.8/0001-MIPS-ralink-adds-include-files.patch b/target/linux/ramips/patches-3.8/0001-MIPS-ralink-adds-include-files.patch index 3539ece..cc32caa 100644 --- a/target/linux/ramips/patches-3.8/0001-MIPS-ralink-adds-include-files.patch +++ b/target/linux/ramips/patches-3.8/0001-MIPS-ralink-adds-include-files.patch @@ -1,7 +1,7 @@ -From 8563991026ee98bb5e477167236972a45dfea0e3 Mon Sep 17 00:00:00 2001 +From 72bd3fcd16225f46ca318435a4d8f3f3f154b1bc Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Mon, 21 Jan 2013 18:25:59 +0100 -Subject: [PATCH 01/14] MIPS: ralink: adds include files +Subject: [PATCH 01/79] MIPS: ralink: adds include files Before we start adding the platform code we add the common include files. @@ -17,6 +17,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4893/ create mode 100644 arch/mips/include/asm/mach-ralink/war.h create mode 100644 arch/mips/ralink/common.h +diff --git a/arch/mips/include/asm/mach-ralink/ralink_regs.h b/arch/mips/include/asm/mach-ralink/ralink_regs.h +new file mode 100644 +index 0000000..5a508f9 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/ralink_regs.h @@ -0,0 +1,39 @@ @@ -59,6 +62,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4893/ +} + +#endif /* _RALINK_REGS_H_ */ +diff --git a/arch/mips/include/asm/mach-ralink/war.h b/arch/mips/include/asm/mach-ralink/war.h +new file mode 100644 +index 0000000..a7b712c --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/war.h @@ -0,0 +1,25 @@ @@ -87,6 +93,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4893/ +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MACH_RALINK_WAR_H */ +diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h +new file mode 100644 +index 0000000..3009903 --- /dev/null +++ b/arch/mips/ralink/common.h @@ -0,0 +1,44 @@ @@ -134,3 +143,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4893/ +__iomem void *plat_of_remap_node(const char *node); + +#endif /* _RALINK_COMMON_H__ */ +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0002-MIPS-ralink-adds-irq-code.patch b/target/linux/ramips/patches-3.8/0002-MIPS-ralink-adds-irq-code.patch index c559a87..01beef7 100644 --- a/target/linux/ramips/patches-3.8/0002-MIPS-ralink-adds-irq-code.patch +++ b/target/linux/ramips/patches-3.8/0002-MIPS-ralink-adds-irq-code.patch @@ -1,7 +1,7 @@ -From 19d3814e7b325f8965fd71f329b3467a97f8d217 Mon Sep 17 00:00:00 2001 +From 833836f47b4191e93267b91fcab38dd15affcd28 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 20 Jan 2013 22:00:50 +0100 -Subject: [PATCH 02/14] MIPS: ralink: adds irq code +Subject: [PATCH 02/79] MIPS: ralink: adds irq code All of the Ralink Wifi SoC currently supported by this series share the same interrupt controller (INTC). @@ -14,6 +14,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4890/ 1 file changed, 176 insertions(+) create mode 100644 arch/mips/ralink/irq.c +diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c +new file mode 100644 +index 0000000..e62c975 --- /dev/null +++ b/arch/mips/ralink/irq.c @@ -0,0 +1,176 @@ @@ -193,3 +196,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4890/ + of_irq_init(of_irq_ids); +} + +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0003-MIPS-ralink-adds-reset-code.patch b/target/linux/ramips/patches-3.8/0003-MIPS-ralink-adds-reset-code.patch index 57cad76..ee9a509 100644 --- a/target/linux/ramips/patches-3.8/0003-MIPS-ralink-adds-reset-code.patch +++ b/target/linux/ramips/patches-3.8/0003-MIPS-ralink-adds-reset-code.patch @@ -1,7 +1,7 @@ -From c06e836ada59fbc6d1109277e693e5b3e056ac12 Mon Sep 17 00:00:00 2001 +From 3cdf3d713c81ffd3032d7c664f0be89d1ddce3e3 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 20 Jan 2013 22:00:57 +0100 -Subject: [PATCH 03/14] MIPS: ralink: adds reset code +Subject: [PATCH 03/79] MIPS: ralink: adds reset code Resetting these SoCs requires no real magic. The code is straight forward. @@ -13,6 +13,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4891/ 1 file changed, 44 insertions(+) create mode 100644 arch/mips/ralink/reset.c +diff --git a/arch/mips/ralink/reset.c b/arch/mips/ralink/reset.c +new file mode 100644 +index 0000000..22120e5 --- /dev/null +++ b/arch/mips/ralink/reset.c @@ -0,0 +1,44 @@ @@ -60,3 +63,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4891/ +} + +arch_initcall(mips_reboot_setup); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0004-MIPS-ralink-adds-prom-and-cmdline-code.patch b/target/linux/ramips/patches-3.8/0004-MIPS-ralink-adds-prom-and-cmdline-code.patch index da38629..8b8bb56 100644 --- a/target/linux/ramips/patches-3.8/0004-MIPS-ralink-adds-prom-and-cmdline-code.patch +++ b/target/linux/ramips/patches-3.8/0004-MIPS-ralink-adds-prom-and-cmdline-code.patch @@ -1,7 +1,7 @@ -From 7e47cefa69c8ed2c889522ce29fcce73ce8cf08e Mon Sep 17 00:00:00 2001 +From 36424b3f1f184c752562d19d0df1a427c8c584a2 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 20 Jan 2013 22:01:05 +0100 -Subject: [PATCH 04/14] MIPS: ralink: adds prom and cmdline code +Subject: [PATCH 04/79] MIPS: ralink: adds prom and cmdline code Add minimal code to handle commandlines. @@ -13,6 +13,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4892/ 1 file changed, 69 insertions(+) create mode 100644 arch/mips/ralink/prom.c +diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c +new file mode 100644 +index 0000000..9c64f02 --- /dev/null +++ b/arch/mips/ralink/prom.c @@ -0,0 +1,69 @@ @@ -85,3 +88,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4892/ +void __init prom_free_prom_memory(void) +{ +} +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0005-MIPS-ralink-adds-clkdev-code.patch b/target/linux/ramips/patches-3.8/0005-MIPS-ralink-adds-clkdev-code.patch index a8218d1..1fd6057 100644 --- a/target/linux/ramips/patches-3.8/0005-MIPS-ralink-adds-clkdev-code.patch +++ b/target/linux/ramips/patches-3.8/0005-MIPS-ralink-adds-clkdev-code.patch @@ -1,7 +1,7 @@ -From 3f0a06b0368d25608841843e9d65a7289ad9f14a Mon Sep 17 00:00:00 2001 +From b99289db258ee8a84e1bd555b2897476acf390c1 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 20 Jan 2013 22:01:29 +0100 -Subject: [PATCH 05/14] MIPS: ralink: adds clkdev code +Subject: [PATCH 05/79] MIPS: ralink: adds clkdev code These SoCs have a limited number of fixed rate clocks. Add support for the clk and clkdev api. @@ -14,6 +14,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4894/ 1 file changed, 72 insertions(+) create mode 100644 arch/mips/ralink/clk.c +diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c +new file mode 100644 +index 0000000..8dfa22f --- /dev/null +++ b/arch/mips/ralink/clk.c @@ -0,0 +1,72 @@ @@ -89,3 +92,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4894/ + mips_hpt_frequency = clk_get_rate(clk) / 2; + clk_put(clk); +} +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0006-MIPS-ralink-adds-OF-code.patch b/target/linux/ramips/patches-3.8/0006-MIPS-ralink-adds-OF-code.patch index b6bd78b..7747c81 100644 --- a/target/linux/ramips/patches-3.8/0006-MIPS-ralink-adds-OF-code.patch +++ b/target/linux/ramips/patches-3.8/0006-MIPS-ralink-adds-OF-code.patch @@ -1,7 +1,7 @@ -From 3a5bfe7bdbfd37c9206d7c6dfd7eb9664ccc5038 Mon Sep 17 00:00:00 2001 +From 4b2f9abbbaf3463a0fc1a65afeb0d12f890ada35 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 20 Jan 2013 22:02:01 +0100 -Subject: [PATCH 06/14] MIPS: ralink: adds OF code +Subject: [PATCH 06/79] MIPS: ralink: adds OF code Until there is a generic MIPS way of handing the DTB over from bootloader to kernel we rely on a built in devicetrees. The OF code also remaps those register @@ -15,6 +15,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4895/ 1 file changed, 107 insertions(+) create mode 100644 arch/mips/ralink/of.c +diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c +new file mode 100644 +index 0000000..4165e70 --- /dev/null +++ b/arch/mips/ralink/of.c @@ -0,0 +1,107 @@ @@ -125,3 +128,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4895/ +} + +arch_initcall(plat_of_setup); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0007-MIPS-ralink-adds-early_printk-support.patch b/target/linux/ramips/patches-3.8/0007-MIPS-ralink-adds-early_printk-support.patch index 80a5b1e..e22bbbd 100644 --- a/target/linux/ramips/patches-3.8/0007-MIPS-ralink-adds-early_printk-support.patch +++ b/target/linux/ramips/patches-3.8/0007-MIPS-ralink-adds-early_printk-support.patch @@ -1,7 +1,7 @@ -From 5fff610b7c60195de98e68bec00c357f393ce634 Mon Sep 17 00:00:00 2001 +From 4efba82d0e4059588f2b2fc0ac2576eaf37f1d22 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 20 Jan 2013 22:02:55 +0100 -Subject: [PATCH 07/14] MIPS: ralink: adds early_printk support +Subject: [PATCH 07/79] MIPS: ralink: adds early_printk support Add the code needed to make early printk work. @@ -13,6 +13,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4897/ 1 file changed, 44 insertions(+) create mode 100644 arch/mips/ralink/early_printk.c +diff --git a/arch/mips/ralink/early_printk.c b/arch/mips/ralink/early_printk.c +new file mode 100644 +index 0000000..c4ae47e --- /dev/null +++ b/arch/mips/ralink/early_printk.c @@ -0,0 +1,44 @@ @@ -60,3 +63,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4897/ + while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0) + ; +} +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0008-MIPS-ralink-adds-support-for-RT305x-SoC-family.patch b/target/linux/ramips/patches-3.8/0008-MIPS-ralink-adds-support-for-RT305x-SoC-family.patch index 083526b..01b0869 100644 --- a/target/linux/ramips/patches-3.8/0008-MIPS-ralink-adds-support-for-RT305x-SoC-family.patch +++ b/target/linux/ramips/patches-3.8/0008-MIPS-ralink-adds-support-for-RT305x-SoC-family.patch @@ -1,7 +1,7 @@ -From 2809b31770d7fd934a748692e1922a5e613f06e5 Mon Sep 17 00:00:00 2001 +From 433f4f524aba81358353ca4ebc00c3e916521ec6 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 20 Jan 2013 22:03:46 +0100 -Subject: [PATCH 08/14] MIPS: ralink: adds support for RT305x SoC family +Subject: [PATCH 08/79] MIPS: ralink: adds support for RT305x SoC family Add support code for rt3050, rt3052, rt3350, rt3352 and rt5350 SOC. @@ -17,6 +17,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4896/ create mode 100644 arch/mips/include/asm/mach-ralink/rt305x.h create mode 100644 arch/mips/ralink/rt305x.c +diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h +new file mode 100644 +index 0000000..7d344f2 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -0,0 +1,139 @@ @@ -159,6 +162,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4896/ +#define RT305X_GPIO_MODE_RGMII BIT(9) + +#endif +diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c +new file mode 100644 +index 0000000..0a4bbdc --- /dev/null +++ b/arch/mips/ralink/rt305x.c @@ -0,0 +1,242 @@ @@ -404,3 +410,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4896/ + (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, + (id & CHIP_ID_REV_MASK)); +} +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0009-MIPS-ralink-adds-rt305x-devicetree.patch b/target/linux/ramips/patches-3.8/0009-MIPS-ralink-adds-rt305x-devicetree.patch index 2c2bb14..81d9fea 100644 --- a/target/linux/ramips/patches-3.8/0009-MIPS-ralink-adds-rt305x-devicetree.patch +++ b/target/linux/ramips/patches-3.8/0009-MIPS-ralink-adds-rt305x-devicetree.patch @@ -1,7 +1,7 @@ -From 5644da4f635a30fc03b4f12d81b2197d716d9cef Mon Sep 17 00:00:00 2001 +From 8208a43c301d9164802dedeec7455dbdd70ca286 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Tue, 22 Jan 2013 20:19:33 +0100 -Subject: [PATCH 09/14] MIPS: ralink: adds rt305x devicetree +Subject: [PATCH 09/79] MIPS: ralink: adds rt305x devicetree This adds the devicetree file that describes the rt305x evaluation kit. @@ -15,6 +15,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4898/ create mode 100644 arch/mips/ralink/dts/rt3050.dtsi create mode 100644 arch/mips/ralink/dts/rt3052_eval.dts +diff --git a/arch/mips/ralink/dts/rt3050.dtsi b/arch/mips/ralink/dts/rt3050.dtsi +new file mode 100644 +index 0000000..fd49daa --- /dev/null +++ b/arch/mips/ralink/dts/rt3050.dtsi @@ -0,0 +1,96 @@ @@ -114,6 +117,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4898/ + }; + }; +}; +diff --git a/arch/mips/ralink/dts/rt3052_eval.dts b/arch/mips/ralink/dts/rt3052_eval.dts +new file mode 100644 +index 0000000..dc56e58 --- /dev/null +++ b/arch/mips/ralink/dts/rt3052_eval.dts @@ -0,0 +1,52 @@ @@ -169,3 +175,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4898/ + }; + }; +}; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0010-MIPS-ralink-adds-Kbuild-files.patch b/target/linux/ramips/patches-3.8/0010-MIPS-ralink-adds-Kbuild-files.patch index bccc3b8..88c018c 100644 --- a/target/linux/ramips/patches-3.8/0010-MIPS-ralink-adds-Kbuild-files.patch +++ b/target/linux/ramips/patches-3.8/0010-MIPS-ralink-adds-Kbuild-files.patch @@ -1,7 +1,7 @@ -From ae2b5bb6570481b50a7175c64176b82da0a81836 Mon Sep 17 00:00:00 2001 +From 79e69b7a01246e945448039f7dce170eef0b6e3b Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 20 Jan 2013 22:05:30 +0100 -Subject: [PATCH 10/14] MIPS: ralink: adds Kbuild files +Subject: [PATCH 10/79] MIPS: ralink: adds Kbuild files Add the Kbuild symbols and Makefiles needed to actually build the ralink code from this series @@ -22,6 +22,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/4899/ create mode 100644 arch/mips/ralink/Platform create mode 100644 arch/mips/ralink/dts/Makefile +diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms +index 91b9d69..9a73ce6 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -22,6 +22,7 @@ platforms += pmc-sierra @@ -32,6 +34,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/4899/ platforms += rb532 platforms += sgi-ip22 platforms += sgi-ip27 +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 2ac626a..b5081b5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -434,6 +434,22 @@ config POWERTV @@ -65,6 +69,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4899/ source "arch/mips/sgi-ip27/Kconfig" source "arch/mips/sibyte/Kconfig" source "arch/mips/txx9/Kconfig" +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +new file mode 100644 +index 0000000..a0b0197 --- /dev/null +++ b/arch/mips/ralink/Kconfig @@ -0,0 +1,32 @@ @@ -100,6 +107,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4899/ +endchoice + +endif +diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile +new file mode 100644 +index 0000000..939757f --- /dev/null +++ b/arch/mips/ralink/Makefile @@ -0,0 +1,15 @@ @@ -118,6 +128,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4899/ +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +obj-y += dts/ +diff --git a/arch/mips/ralink/Platform b/arch/mips/ralink/Platform +new file mode 100644 +index 0000000..6babd65 --- /dev/null +++ b/arch/mips/ralink/Platform @@ -0,0 +1,10 @@ @@ -131,7 +144,13 @@ Patchwork: http://patchwork.linux-mips.org/patch/4899/ +# Ralink RT305x +# +load-$(CONFIG_SOC_RT305X) += 0xffffffff80000000 +diff --git a/arch/mips/ralink/dts/Makefile b/arch/mips/ralink/dts/Makefile +new file mode 100644 +index 0000000..1a69fb3 --- /dev/null +++ b/arch/mips/ralink/dts/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DTB_RT305X_EVAL) := rt3052_eval.dtb.o +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0011-MIPS-ralink-adds-default-config-file.patch b/target/linux/ramips/patches-3.8/0011-MIPS-ralink-adds-default-config-file.patch index 5998b11..1f4a1e2 100644 --- a/target/linux/ramips/patches-3.8/0011-MIPS-ralink-adds-default-config-file.patch +++ b/target/linux/ramips/patches-3.8/0011-MIPS-ralink-adds-default-config-file.patch @@ -1,7 +1,7 @@ -From 6d63d70f9fe4c1b3d293ac3b9d2fcaf937d95cea Mon Sep 17 00:00:00 2001 +From 428bb7af86ffb6171e11c36dfcdacd87ed5341e6 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 1 Feb 2013 12:50:49 +0100 -Subject: [PATCH 11/14] MIPS: ralink: adds default config file +Subject: [PATCH 11/79] MIPS: ralink: adds default config file Signed-off-by: John Crispin <blogic@openwrt.org> --- @@ -9,6 +9,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> 1 file changed, 167 insertions(+) create mode 100644 arch/mips/configs/rt305x_defconfig +diff --git a/arch/mips/configs/rt305x_defconfig b/arch/mips/configs/rt305x_defconfig +new file mode 100644 +index 0000000..d1741bc --- /dev/null +++ b/arch/mips/configs/rt305x_defconfig @@ -0,0 +1,167 @@ @@ -179,3 +182,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set +CONFIG_AVERAGE=y +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0012-Document-devicetree-add-OF-documents-for-MIPS-interr.patch b/target/linux/ramips/patches-3.8/0012-Document-devicetree-add-OF-documents-for-MIPS-interr.patch index 6a07d8d..b7ce7c9 100644 --- a/target/linux/ramips/patches-3.8/0012-Document-devicetree-add-OF-documents-for-MIPS-interr.patch +++ b/target/linux/ramips/patches-3.8/0012-Document-devicetree-add-OF-documents-for-MIPS-interr.patch @@ -1,7 +1,7 @@ -From dcc7310e144c3bf17a86d2f058d60fb525d4b34a Mon Sep 17 00:00:00 2001 +From dae867771332e7541783ebb6bacf33356ad449b3 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 31 Jan 2013 13:44:10 +0100 -Subject: [PATCH 12/14] Document: devicetree: add OF documents for MIPS +Subject: [PATCH 12/79] Document: devicetree: add OF documents for MIPS interrupt controller Signed-off-by: John Crispin <blogic@openwrt.org> @@ -12,6 +12,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/4901/ 1 file changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/mips/cpu_irq.txt +diff --git a/Documentation/devicetree/bindings/mips/cpu_irq.txt b/Documentation/devicetree/bindings/mips/cpu_irq.txt +new file mode 100644 +index 0000000..13aa4b6 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cpu_irq.txt @@ -0,0 +1,47 @@ @@ -62,3 +65,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4901/ +{ + of_irq_init(of_irq_ids); +} +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0013-MIPS-add-irqdomain-support-for-the-CPU-IRQ-controlle.patch b/target/linux/ramips/patches-3.8/0013-MIPS-add-irqdomain-support-for-the-CPU-IRQ-controlle.patch index 3139106..e5387a2 100644 --- a/target/linux/ramips/patches-3.8/0013-MIPS-add-irqdomain-support-for-the-CPU-IRQ-controlle.patch +++ b/target/linux/ramips/patches-3.8/0013-MIPS-add-irqdomain-support-for-the-CPU-IRQ-controlle.patch @@ -1,7 +1,7 @@ -From 0916b46962cbcac9465d253d0a398435b3965fd5 Mon Sep 17 00:00:00 2001 +From 65e39f763eeca6fb93f48ed5a9b296277a543429 Mon Sep 17 00:00:00 2001 From: Gabor Juhos <juhosg@openwrt.org> Date: Thu, 31 Jan 2013 12:20:43 +0000 -Subject: [PATCH 13/14] MIPS: add irqdomain support for the CPU IRQ controller +Subject: [PATCH 13/79] MIPS: add irqdomain support for the CPU IRQ controller Add code to load a irq_domain for the MIPS IRQ controller from a devicetree file. @@ -15,6 +15,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/4902/ arch/mips/kernel/irq_cpu.c | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) +diff --git a/arch/mips/include/asm/irq_cpu.h b/arch/mips/include/asm/irq_cpu.h +index ef6a07c..3f11fdb 100644 --- a/arch/mips/include/asm/irq_cpu.h +++ b/arch/mips/include/asm/irq_cpu.h @@ -17,4 +17,10 @@ extern void mips_cpu_irq_init(void); @@ -28,6 +30,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/4902/ +#endif + #endif /* _ASM_IRQ_CPU_H */ +diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c +index 972263b..49bc9ca 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -31,6 +31,7 @@ @@ -83,3 +87,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4902/ + return 0; +} +#endif /* CONFIG_IRQ_DOMAIN */ +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0014-MIPS-ralink-add-CPU-interrupt-controller-to-of_irq_i.patch b/target/linux/ramips/patches-3.8/0014-MIPS-ralink-add-CPU-interrupt-controller-to-of_irq_i.patch index e9e2f56..e346131 100644 --- a/target/linux/ramips/patches-3.8/0014-MIPS-ralink-add-CPU-interrupt-controller-to-of_irq_i.patch +++ b/target/linux/ramips/patches-3.8/0014-MIPS-ralink-add-CPU-interrupt-controller-to-of_irq_i.patch @@ -1,7 +1,7 @@ -From d3d2b4200b5a42851365e903d101f8f0882eb9eb Mon Sep 17 00:00:00 2001 +From 9afd2ba44145009578d9d445183480a698cc04f2 Mon Sep 17 00:00:00 2001 From: Gabor Juhos <juhosg@openwrt.org> Date: Thu, 31 Jan 2013 20:43:30 +0100 -Subject: [PATCH 14/14] MIPS: ralink: add CPU interrupt controller to +Subject: [PATCH 14/79] MIPS: ralink: add CPU interrupt controller to of_irq_ids Convert the ralink IRQ code to make use of the new MIPS IRQ controller OF @@ -16,6 +16,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/4900/ arch/mips/ralink/irq.c | 10 +++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) +diff --git a/arch/mips/ralink/dts/rt3050.dtsi b/arch/mips/ralink/dts/rt3050.dtsi +index fd49daa..069d066 100644 --- a/arch/mips/ralink/dts/rt3050.dtsi +++ b/arch/mips/ralink/dts/rt3050.dtsi @@ -13,6 +13,13 @@ @@ -42,9 +44,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/4900/ }; memc@300 { +diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c +index e62c975..6d054c5 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c -@@ -128,8 +128,11 @@ static int __init intc_of_init(struct de +@@ -128,8 +128,11 @@ static int __init intc_of_init(struct device_node *node, { struct resource res; struct irq_domain *domain; @@ -57,7 +61,7 @@ Patchwork: http://patchwork.linux-mips.org/patch/4900/ if (of_address_to_resource(node, 0, &res)) panic("Failed to get intc memory range"); -@@ -156,8 +159,8 @@ static int __init intc_of_init(struct de +@@ -156,8 +159,8 @@ static int __init intc_of_init(struct device_node *node, rt_intc_w32(INTC_INT_GLOBAL, INTC_REG_ENABLE); @@ -68,7 +72,7 @@ Patchwork: http://patchwork.linux-mips.org/patch/4900/ cp0_perfcount_irq = irq_create_mapping(domain, 9); -@@ -165,6 +168,7 @@ static int __init intc_of_init(struct de +@@ -165,6 +168,7 @@ static int __init intc_of_init(struct device_node *node, } static struct of_device_id __initdata of_irq_ids[] = { @@ -76,3 +80,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/4900/ { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, {}, }; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0015-serial-ralink-adds-support-for-the-serial-core-found.patch b/target/linux/ramips/patches-3.8/0015-serial-ralink-adds-support-for-the-serial-core-found.patch index 38ef41a..b995422 100644 --- a/target/linux/ramips/patches-3.8/0015-serial-ralink-adds-support-for-the-serial-core-found.patch +++ b/target/linux/ramips/patches-3.8/0015-serial-ralink-adds-support-for-the-serial-core-found.patch @@ -1,8 +1,8 @@ -From c420811f117a59a4a7d4e34b362437b91c7fafa1 Mon Sep 17 00:00:00 2001 +From 219ec2244c2e9085e6900dc515a24f6655c79827 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 25 Jan 2013 19:39:51 +0100 -Subject: [PATCH] serial: ralink: adds support for the serial core found on - ralink wisoc +Subject: [PATCH 15/79] serial: ralink: adds support for the serial core found + on ralink wisoc The MIPS based Ralink WiSoC platform has 1 or more 8250 compatible serial cores. To make them work we require the same quirks that are used by AU1x00. @@ -15,9 +15,11 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> include/linux/serial_core.h | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) +diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c +index f932043..f72eb7d 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c -@@ -345,9 +345,9 @@ static void default_serial_dl_write(stru +@@ -324,9 +324,9 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value) serial_out(up, UART_DLM, value >> 8 & 0xff); } @@ -29,7 +31,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> static const u8 au_io_in_map[] = { [UART_RX] = 0, [UART_IER] = 2, -@@ -527,7 +527,7 @@ static void set_io_from_upio(struct uart +@@ -506,7 +506,7 @@ static void set_io_from_upio(struct uart_port *p) break; #endif @@ -38,6 +40,8 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> case UPIO_AU: p->serial_in = au_serial_in; p->serial_out = au_serial_out; +diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig +index c31133a..9e4febd 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -277,3 +277,11 @@ config SERIAL_8250_EM @@ -52,6 +56,8 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> + If you have a Ralink RT288x/RT305x SoC based board and want to use the + serial port, say Y to this option. The driver can handle up to 2 serial + ports. If unsure, say N. +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index c6690a2..0b428d6 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -134,7 +134,7 @@ struct uart_port { @@ -63,3 +69,6 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> #define UPIO_TSI (5) /* Tsi108/109 type IO */ #define UPIO_RM9000 (6) /* RM9000 type IO */ +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0100-MIPS-move-mips_-set-get-_machine_name-to-a-more-gene.patch b/target/linux/ramips/patches-3.8/0016-MIPS-move-mips_-set-get-_machine_name-to-a-more-gene.patch index d5fe653..8886cd7 100644 --- a/target/linux/ramips/patches-3.8/0100-MIPS-move-mips_-set-get-_machine_name-to-a-more-gene.patch +++ b/target/linux/ramips/patches-3.8/0016-MIPS-move-mips_-set-get-_machine_name-to-a-more-gene.patch @@ -1,7 +1,7 @@ -From dd4bb7e821d112bff981016fd4e7c014ca9425f9 Mon Sep 17 00:00:00 2001 +From 231e989ef4a11073ad6be8af797f96d51256d07a Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 11 Apr 2013 05:34:59 +0000 -Subject: [PATCH 100/137] MIPS: move mips_{set,get}_machine_name() to a more +Subject: [PATCH 16/79] MIPS: move mips_{set,get}_machine_name() to a more generic place Previously this functionality was only available to users of the mips_machine @@ -17,6 +17,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5164/ arch/mips/kernel/prom.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 35 insertions(+), 26 deletions(-) +diff --git a/arch/mips/include/asm/mips_machine.h b/arch/mips/include/asm/mips_machine.h +index 363bb35..9d00aeb 100644 --- a/arch/mips/include/asm/mips_machine.h +++ b/arch/mips/include/asm/mips_machine.h @@ -42,13 +42,9 @@ extern long __mips_machines_end; @@ -33,9 +35,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5164/ #endif /* CONFIG_MIPS_MACHINE */ #endif /* __ASM_MIPS_MACHINE_H */ +diff --git a/arch/mips/include/asm/prom.h b/arch/mips/include/asm/prom.h +index 8808bf5..1e7e096 100644 --- a/arch/mips/include/asm/prom.h +++ b/arch/mips/include/asm/prom.h -@@ -48,4 +48,7 @@ extern void __dt_setup_arch(struct boot_ +@@ -48,4 +48,7 @@ extern void __dt_setup_arch(struct boot_param_header *bph); static inline void device_tree_init(void) { } #endif /* CONFIG_OF */ @@ -43,6 +47,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5164/ +extern void mips_set_machine_name(const char *name); + #endif /* __ASM_PROM_H */ +diff --git a/arch/mips/kernel/mips_machine.c b/arch/mips/kernel/mips_machine.c +index 411a058..6dc5866 100644 --- a/arch/mips/kernel/mips_machine.c +++ b/arch/mips/kernel/mips_machine.c @@ -13,7 +13,6 @@ @@ -53,7 +59,7 @@ Patchwork: http://patchwork.linux-mips.org/patch/5164/ #define for_each_machine(mach) \ for ((mach) = (struct mips_machine *)&__mips_machines_start; \ -@@ -21,25 +20,6 @@ static char *mips_machine_name = "Unknow +@@ -21,25 +20,6 @@ static char *mips_machine_name = "Unknown"; (unsigned long)(mach) < (unsigned long)&__mips_machines_end; \ (mach)++) @@ -87,6 +93,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5164/ if (mips_machine->mach_setup) mips_machine->mach_setup(); +diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c +index 07dff54..8779237 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -12,7 +12,7 @@ @@ -98,6 +106,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5164/ unsigned int vced_count, vcei_count; +diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c +index 028f6f8..b68e53b 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -23,6 +23,22 @@ @@ -123,7 +133,7 @@ Patchwork: http://patchwork.linux-mips.org/patch/5164/ int __init early_init_dt_scan_memory_arch(unsigned long node, const char *uname, int depth, void *data) -@@ -50,6 +66,18 @@ void __init early_init_dt_setup_initrd_a +@@ -50,6 +66,18 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start, } #endif @@ -142,7 +152,7 @@ Patchwork: http://patchwork.linux-mips.org/patch/5164/ void __init early_init_devtree(void *params) { /* Setup flat device-tree pointer */ -@@ -65,6 +93,9 @@ void __init early_init_devtree(void *par +@@ -65,6 +93,9 @@ void __init early_init_devtree(void *params) /* Scan memory nodes */ of_scan_flat_dt(early_init_dt_scan_root, NULL); of_scan_flat_dt(early_init_dt_scan_memory_arch, NULL); @@ -152,3 +162,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5164/ } void __init __dt_setup_arch(struct boot_param_header *bph) +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0101-MIPS-ralink-add-PCI-IRQ-handling.patch b/target/linux/ramips/patches-3.8/0017-MIPS-ralink-add-PCI-IRQ-handling.patch index bdb5cfc..c18817e 100644 --- a/target/linux/ramips/patches-3.8/0101-MIPS-ralink-add-PCI-IRQ-handling.patch +++ b/target/linux/ramips/patches-3.8/0017-MIPS-ralink-add-PCI-IRQ-handling.patch @@ -1,7 +1,7 @@ -From 16d9eaf22f30ed0b0deddfe8e11426889ccdb556 Mon Sep 17 00:00:00 2001 +From 98ab228172e66e43766d9e2a0ddb73603c22dbd1 Mon Sep 17 00:00:00 2001 From: Gabor Juhos <juhosg@openwrt.org> Date: Wed, 10 Apr 2013 09:07:27 +0200 -Subject: [PATCH 101/137] MIPS: ralink: add PCI IRQ handling +Subject: [PATCH 17/79] MIPS: ralink: add PCI IRQ handling The Ralink IRQ code was not handling the PCI IRQ yet. Add this functionaility to make PCI work on rt3883. @@ -13,6 +13,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5165/ arch/mips/ralink/irq.c | 4 ++++ 1 file changed, 4 insertions(+) +diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c +index 6d054c5..d9807d0 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c @@ -31,6 +31,7 @@ @@ -33,3 +35,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5165/ else if (pending & STATUSF_IP2) do_IRQ(RALINK_CPU_IRQ_INTC); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0102-MIPS-ralink-add-RT3352-register-defines.patch b/target/linux/ramips/patches-3.8/0018-MIPS-ralink-add-RT3352-register-defines.patch index 2d296db..1a8950f 100644 --- a/target/linux/ramips/patches-3.8/0102-MIPS-ralink-add-RT3352-register-defines.patch +++ b/target/linux/ramips/patches-3.8/0018-MIPS-ralink-add-RT3352-register-defines.patch @@ -1,7 +1,7 @@ -From e6bcdad6f0811daedc2a448f5d7fb98c116a5241 Mon Sep 17 00:00:00 2001 +From 8667d984d1b4f3be1c5da71788762b9945a25c90 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 21 Mar 2013 19:01:49 +0100 -Subject: [PATCH 102/137] MIPS: ralink: add RT3352 register defines +Subject: [PATCH 18/79] MIPS: ralink: add RT3352 register defines Add a few missing defines that are needed to make USB and clock detection work on the RT3352. @@ -13,6 +13,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5166/ arch/mips/include/asm/mach-ralink/rt305x.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) +diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h +index 7d344f2..e36c3c5 100644 --- a/arch/mips/include/asm/mach-ralink/rt305x.h +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -136,4 +136,17 @@ static inline int soc_is_rt5350(void) @@ -33,3 +35,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5166/ +#define RT3352_SYSCFG1_USB0_HOST_MODE BIT(10) + #endif +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0103-MIPS-ralink-fix-RT305x-clock-setup.patch b/target/linux/ramips/patches-3.8/0019-MIPS-ralink-fix-RT305x-clock-setup.patch index 7d682e7..ebecdf2 100644 --- a/target/linux/ramips/patches-3.8/0103-MIPS-ralink-fix-RT305x-clock-setup.patch +++ b/target/linux/ramips/patches-3.8/0019-MIPS-ralink-fix-RT305x-clock-setup.patch @@ -1,7 +1,7 @@ -From 845f786c561c0991d9b4088a2d77b8fd4831d487 Mon Sep 17 00:00:00 2001 +From 853823a469a8123657bf32bc5e1843c40529a20d Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 22 Mar 2013 19:25:59 +0100 -Subject: [PATCH 103/137] MIPS: ralink: fix RT305x clock setup +Subject: [PATCH 19/79] MIPS: ralink: fix RT305x clock setup Add a few missing clocks. @@ -12,6 +12,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5167/ arch/mips/ralink/rt305x.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) +diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c +index 0a4bbdc..5d49a54 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -124,6 +124,8 @@ struct ralink_pinmux gpio_pinmux = { @@ -45,3 +47,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5167/ } void __init ralink_of_remap(void) +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0104-MIPS-ralink-add-missing-comment-in-irq-driver.patch b/target/linux/ramips/patches-3.8/0020-MIPS-ralink-add-missing-comment-in-irq-driver.patch index 3218384..51cfe0c 100644 --- a/target/linux/ramips/patches-3.8/0104-MIPS-ralink-add-missing-comment-in-irq-driver.patch +++ b/target/linux/ramips/patches-3.8/0020-MIPS-ralink-add-missing-comment-in-irq-driver.patch @@ -1,7 +1,7 @@ -From 2747613b1bba0d4497ed2c4a77e2011d02029153 Mon Sep 17 00:00:00 2001 +From 7c268f1b47669be2efce1607ee02193cb49424cf Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 16 Mar 2013 16:28:54 +0100 -Subject: [PATCH 104/137] MIPS: ralink: add missing comment in irq driver +Subject: [PATCH 20/79] MIPS: ralink: add missing comment in irq driver Trivial patch that adds a comment that makes the code more readable. @@ -12,9 +12,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5168/ arch/mips/ralink/irq.c | 1 + 1 file changed, 1 insertion(+) +diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c +index d9807d0..320b1f1 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c -@@ -166,6 +166,7 @@ static int __init intc_of_init(struct de +@@ -166,6 +166,7 @@ static int __init intc_of_init(struct device_node *node, irq_set_chained_handler(irq, ralink_intc_irq_handler); irq_set_handler_data(irq, domain); @@ -22,3 +24,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5168/ cp0_perfcount_irq = irq_create_mapping(domain, 9); return 0; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0105-MIPS-ralink-add-RT5350-sdram-register-defines.patch b/target/linux/ramips/patches-3.8/0021-MIPS-ralink-add-RT5350-sdram-register-defines.patch index ccabcbd..8ecaea2 100644 --- a/target/linux/ramips/patches-3.8/0105-MIPS-ralink-add-RT5350-sdram-register-defines.patch +++ b/target/linux/ramips/patches-3.8/0021-MIPS-ralink-add-RT5350-sdram-register-defines.patch @@ -1,7 +1,7 @@ -From 31f4b3ca1c9bb4bcbbebbe5db5a33ac82f130d9c Mon Sep 17 00:00:00 2001 +From 0df8c2fdd0fe1095b834fbf2b098d6f1b3e56608 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Mon, 25 Mar 2013 11:19:58 +0100 -Subject: [PATCH 105/137] MIPS: ralink: add RT5350 sdram register defines +Subject: [PATCH 21/79] MIPS: ralink: add RT5350 sdram register defines Add a few missing defines that are needed to make memory detection work on the RT5350. @@ -13,6 +13,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5169/ arch/mips/include/asm/mach-ralink/rt305x.h | 8 ++++++++ 1 file changed, 8 insertions(+) +diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h +index e36c3c5..80cda8a 100644 --- a/arch/mips/include/asm/mach-ralink/rt305x.h +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -97,6 +97,14 @@ static inline int soc_is_rt5350(void) @@ -30,3 +32,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5169/ /* multi function gpio pins */ #define RT305X_GPIO_I2C_SD 1 #define RT305X_GPIO_I2C_SCLK 2 +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0106-MIPS-ralink-make-early_printk-work-on-RT2880.patch b/target/linux/ramips/patches-3.8/0022-MIPS-ralink-make-early_printk-work-on-RT2880.patch index 4636862..2788397 100644 --- a/target/linux/ramips/patches-3.8/0106-MIPS-ralink-make-early_printk-work-on-RT2880.patch +++ b/target/linux/ramips/patches-3.8/0022-MIPS-ralink-make-early_printk-work-on-RT2880.patch @@ -1,7 +1,7 @@ -From d83e83a544258b68b4411232a31ccce134244a19 Mon Sep 17 00:00:00 2001 +From 9ed190912864c8b96d888af2cb66efcf1dc5562a Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Tue, 9 Apr 2013 18:31:15 +0200 -Subject: [PATCH 106/137] MIPS: ralink: make early_printk work on RT2880 +Subject: [PATCH 22/79] MIPS: ralink: make early_printk work on RT2880 RT2880 has a different location for the early serial port. @@ -12,6 +12,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5170/ arch/mips/ralink/early_printk.c | 4 ++++ 1 file changed, 4 insertions(+) +diff --git a/arch/mips/ralink/early_printk.c b/arch/mips/ralink/early_printk.c +index c4ae47e..b46d041 100644 --- a/arch/mips/ralink/early_printk.c +++ b/arch/mips/ralink/early_printk.c @@ -11,7 +11,11 @@ @@ -26,3 +28,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5170/ #define UART_REG_RX 0x00 #define UART_REG_TX 0x04 +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0107-MIPS-ralink-rename-gpio_pinmux-to-rt_gpio_pinmux.patch b/target/linux/ramips/patches-3.8/0023-MIPS-ralink-rename-gpio_pinmux-to-rt_gpio_pinmux.patch index d10b159..03d95df 100644 --- a/target/linux/ramips/patches-3.8/0107-MIPS-ralink-rename-gpio_pinmux-to-rt_gpio_pinmux.patch +++ b/target/linux/ramips/patches-3.8/0023-MIPS-ralink-rename-gpio_pinmux-to-rt_gpio_pinmux.patch @@ -1,7 +1,7 @@ -From b4c597bd073d5e4c9cee800ac5a25fb9ff1c0ef7 Mon Sep 17 00:00:00 2001 +From d5b75031f6ad0f9f82c3b8faeab3cda1cb4ebfe9 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 12 Apr 2013 22:12:09 +0200 -Subject: [PATCH 107/137] MIPS: ralink: rename gpio_pinmux to rt_gpio_pinmux +Subject: [PATCH 23/79] MIPS: ralink: rename gpio_pinmux to rt_gpio_pinmux Add proper namespacing to the variable. @@ -12,6 +12,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5171/ arch/mips/ralink/rt305x.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) +diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h +index 3009903..f4b19c6 100644 --- a/arch/mips/ralink/common.h +++ b/arch/mips/ralink/common.h @@ -24,7 +24,7 @@ struct ralink_pinmux { @@ -23,6 +25,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5171/ struct ralink_soc_info { unsigned char sys_type[RAMIPS_SYS_TYPE_LEN]; +diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c +index 5d49a54..f1a6c33 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -114,7 +114,7 @@ void rt305x_wdt_reset(void) @@ -34,3 +38,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5171/ .mode = mode_mux, .uart = uart_mux, .uart_shift = RT305X_GPIO_MODE_UART0_SHIFT, +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0108-MIPS-ralink-make-the-RT305x-pinmuxing-structure-stat.patch b/target/linux/ramips/patches-3.8/0024-MIPS-ralink-make-the-RT305x-pinmuxing-structure-stat.patch index f09d57f..60a8a53 100644 --- a/target/linux/ramips/patches-3.8/0108-MIPS-ralink-make-the-RT305x-pinmuxing-structure-stat.patch +++ b/target/linux/ramips/patches-3.8/0024-MIPS-ralink-make-the-RT305x-pinmuxing-structure-stat.patch @@ -1,7 +1,7 @@ -From 96eba63bf18cd3d96ded62fb809c8cf7e0f2e2c1 Mon Sep 17 00:00:00 2001 +From 2793deaf4d3d364ba2ed075abf2b9022a152f253 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 12 Apr 2013 22:16:12 +0200 -Subject: [PATCH 108/137] MIPS: ralink: make the RT305x pinmuxing structure +Subject: [PATCH 24/79] MIPS: ralink: make the RT305x pinmuxing structure static These structures are exported via struct ralink_pinmux rt_gpio_pinmux and can @@ -13,6 +13,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5172/ arch/mips/ralink/rt305x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) +diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c +index f1a6c33..5b42078 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -22,7 +22,7 @@ @@ -42,3 +44,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5172/ { u32 t; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0109-MIPS-ralink-add-pci-group-to-struct-ralink_pinmux.patch b/target/linux/ramips/patches-3.8/0025-MIPS-ralink-add-pci-group-to-struct-ralink_pinmux.patch index 36e187d..368fcde 100644 --- a/target/linux/ramips/patches-3.8/0109-MIPS-ralink-add-pci-group-to-struct-ralink_pinmux.patch +++ b/target/linux/ramips/patches-3.8/0025-MIPS-ralink-add-pci-group-to-struct-ralink_pinmux.patch @@ -1,7 +1,7 @@ -From 61d50d9625dcb454759950ebd45a335c3aaacf84 Mon Sep 17 00:00:00 2001 +From e859bf709e73acb5735cf1207422f53fc3202632 Mon Sep 17 00:00:00 2001 From: Gabor Juhos <juhosg@openwrt.org> Date: Fri, 12 Apr 2013 12:40:23 +0200 -Subject: [PATCH 109/137] MIPS: ralink: add pci group to struct ralink_pinmux +Subject: [PATCH 25/79] MIPS: ralink: add pci group to struct ralink_pinmux This will be used for RT3662/RT3883. @@ -12,6 +12,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5173/ arch/mips/ralink/common.h | 3 +++ 1 file changed, 3 insertions(+) +diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h +index f4b19c6..bebd149 100644 --- a/arch/mips/ralink/common.h +++ b/arch/mips/ralink/common.h @@ -23,6 +23,9 @@ struct ralink_pinmux { @@ -24,3 +26,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5173/ }; extern struct ralink_pinmux rt_gpio_pinmux; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0110-MIPS-ralink-add-uart-mask-to-struct-ralink_pinmux.patch b/target/linux/ramips/patches-3.8/0026-MIPS-ralink-add-uart-mask-to-struct-ralink_pinmux.patch index d4474e1..1ee9fd4 100644 --- a/target/linux/ramips/patches-3.8/0110-MIPS-ralink-add-uart-mask-to-struct-ralink_pinmux.patch +++ b/target/linux/ramips/patches-3.8/0026-MIPS-ralink-add-uart-mask-to-struct-ralink_pinmux.patch @@ -1,7 +1,7 @@ -From faf5989efed503b2ee689dad82bb2d60da718d99 Mon Sep 17 00:00:00 2001 +From 6e09e0465b342b52ecda583cbc41e6a31c363b3f Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 12 Apr 2013 12:45:27 +0200 -Subject: [PATCH 110/137] MIPS: ralink: add uart mask to struct ralink_pinmux +Subject: [PATCH 26/79] MIPS: ralink: add uart mask to struct ralink_pinmux Add a field for the uart muxing mask and set it inside the rt305x setup code. @@ -12,6 +12,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5744/ arch/mips/ralink/rt305x.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) +diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h +index bebd149..299119b 100644 --- a/arch/mips/ralink/common.h +++ b/arch/mips/ralink/common.h @@ -22,6 +22,7 @@ struct ralink_pinmux { @@ -22,9 +24,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5744/ void (*wdt_reset)(void); struct ralink_pinmux_grp *pci; int pci_shift; +diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c +index 5b42078..6aa3cb1 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c -@@ -91,12 +91,12 @@ static struct ralink_pinmux_grp uart_mux +@@ -91,12 +91,12 @@ static struct ralink_pinmux_grp uart_mux[] = { .name = "gpio uartf", .mask = RT305X_GPIO_MODE_GPIO_UARTF, .gpio_first = RT305X_GPIO_7, @@ -47,3 +51,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5744/ .wdt_reset = rt305x_wdt_reset, }; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0111-MIPS-ralink-adds-support-for-RT2880-SoC-family.patch b/target/linux/ramips/patches-3.8/0027-MIPS-ralink-adds-support-for-RT2880-SoC-family.patch index 9cfa509..bd8ad22 100644 --- a/target/linux/ramips/patches-3.8/0111-MIPS-ralink-adds-support-for-RT2880-SoC-family.patch +++ b/target/linux/ramips/patches-3.8/0027-MIPS-ralink-adds-support-for-RT2880-SoC-family.patch @@ -1,7 +1,7 @@ -From cccb9a7b42227a442ca42d590c838c8b6fa0eba1 Mon Sep 17 00:00:00 2001 +From 2a0d9878985bb3274bb61535f76ea293991635a9 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 27 Jan 2013 09:17:20 +0100 -Subject: [PATCH 111/137] MIPS: ralink: adds support for RT2880 SoC family +Subject: [PATCH 27/79] MIPS: ralink: adds support for RT2880 SoC family Add support code for rt2880 SOC. @@ -21,9 +21,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5176/ create mode 100644 arch/mips/include/asm/mach-ralink/rt288x.h create mode 100644 arch/mips/ralink/rt288x.c +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index b5081b5..b5fd476 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -1189,7 +1189,7 @@ config BOOT_ELF32 +@@ -1177,7 +1177,7 @@ config BOOT_ELF32 config MIPS_L1_CACHE_SHIFT int @@ -32,6 +34,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5176/ default "6" if MIPS_CPU_SCACHE default "7" if SGI_IP22 || SGI_IP27 || SGI_IP28 || SNI_RM || CPU_CAVIUM_OCTEON default "5" +diff --git a/arch/mips/include/asm/mach-ralink/rt288x.h b/arch/mips/include/asm/mach-ralink/rt288x.h +new file mode 100644 +index 0000000..ad8b42d --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/rt288x.h @@ -0,0 +1,49 @@ @@ -84,6 +89,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5176/ +#define CLKCFG_SRAM_CS_N_WDT BIT(9) + +#endif +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index a0b0197..6723b94 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -6,6 +6,9 @@ choice @@ -96,6 +103,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5176/ config SOC_RT305X bool "RT305x" select USB_ARCH_HAS_HCD +diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile +index 939757f..6d826f2 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile @@ -8,6 +8,7 @@ @@ -106,9 +115,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5176/ obj-$(CONFIG_SOC_RT305X) += rt305x.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +diff --git a/arch/mips/ralink/Platform b/arch/mips/ralink/Platform +index 6babd65..3f49e51 100644 --- a/arch/mips/ralink/Platform +++ b/arch/mips/ralink/Platform -@@ -5,6 +5,11 @@ core-$(CONFIG_RALINK) += arch/mips/rali +@@ -5,6 +5,11 @@ core-$(CONFIG_RALINK) += arch/mips/ralink/ cflags-$(CONFIG_RALINK) += -I$(srctree)/arch/mips/include/asm/mach-ralink # @@ -120,6 +131,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5176/ # Ralink RT305x # load-$(CONFIG_SOC_RT305X) += 0xffffffff80000000 +diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c +new file mode 100644 +index 0000000..1e0788e --- /dev/null +++ b/arch/mips/ralink/rt288x.c @@ -0,0 +1,139 @@ @@ -262,3 +276,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5176/ + (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, + (id & CHIP_ID_REV_MASK)); +} +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0112-MIPS-ralink-adds-support-for-RT3883-SoC-family.patch b/target/linux/ramips/patches-3.8/0028-MIPS-ralink-adds-support-for-RT3883-SoC-family.patch index 162d0cc..f124fec 100644 --- a/target/linux/ramips/patches-3.8/0112-MIPS-ralink-adds-support-for-RT3883-SoC-family.patch +++ b/target/linux/ramips/patches-3.8/0028-MIPS-ralink-adds-support-for-RT3883-SoC-family.patch @@ -1,7 +1,7 @@ -From 5eb4dfe5072595e0706de3364f2da45378dbaca6 Mon Sep 17 00:00:00 2001 +From c75f4a5af758494595fded27efb95732365d10db Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 27 Jan 2013 09:39:02 +0100 -Subject: [PATCH 112/137] MIPS: ralink: adds support for RT3883 SoC family +Subject: [PATCH 28/79] MIPS: ralink: adds support for RT3883 SoC family Add support code for rt3883 SOC. @@ -20,9 +20,12 @@ Patchwork: http://patchwork.linux-mips.org/patch/5185/ create mode 100644 arch/mips/include/asm/mach-ralink/rt3883.h create mode 100644 arch/mips/ralink/rt3883.c +diff --git a/arch/mips/include/asm/mach-ralink/rt3883.h b/arch/mips/include/asm/mach-ralink/rt3883.h +new file mode 100644 +index 0000000..b91c6c1 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/rt3883.h -@@ -0,0 +1,248 @@ +@@ -0,0 +1,247 @@ +/* + * Ralink RT3662/RT3883 SoC register definitions + * @@ -177,7 +180,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5185/ +#define RT3883_GPIO_SPI_MISO 6 +#define RT3883_GPIO_7 7 +#define RT3883_GPIO_10 10 -+#define RT3883_GPIO_11 11 +#define RT3883_GPIO_14 14 +#define RT3883_GPIO_UART1_TXD 15 +#define RT3883_GPIO_UART1_RXD 16 @@ -271,6 +273,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5185/ +#define RT3883_FLASH_CFG_WIDTH_32BIT 0x2 + +#endif /* _RT3883_REGS_H_ */ +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index 6723b94..ce57d3e 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -15,6 +15,11 @@ choice @@ -285,6 +289,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5185/ endchoice choice +diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile +index 6d826f2..ba9669c 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile @@ -10,6 +10,7 @@ obj-y := prom.o of.o reset.o clk.o irq.o @@ -295,9 +301,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5185/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +diff --git a/arch/mips/ralink/Platform b/arch/mips/ralink/Platform +index 3f49e51..f67c08d 100644 --- a/arch/mips/ralink/Platform +++ b/arch/mips/ralink/Platform -@@ -13,3 +13,8 @@ load-$(CONFIG_SOC_RT288X) += 0xffffffff8 +@@ -13,3 +13,8 @@ load-$(CONFIG_SOC_RT288X) += 0xffffffff88000000 # Ralink RT305x # load-$(CONFIG_SOC_RT305X) += 0xffffffff80000000 @@ -306,6 +314,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5185/ +# Ralink RT3883 +# +load-$(CONFIG_SOC_RT3883) += 0xffffffff80000000 +diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c +new file mode 100644 +index 0000000..2d90aa9 --- /dev/null +++ b/arch/mips/ralink/rt3883.c @@ -0,0 +1,242 @@ @@ -551,3 +562,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5185/ + (id >> RT3883_REVID_VER_ID_SHIFT) & RT3883_REVID_VER_ID_MASK, + (id & RT3883_REVID_ECO_ID_MASK)); +} +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0113-MIPS-ralink-adds-support-for-MT7620-SoC-family.patch b/target/linux/ramips/patches-3.8/0029-MIPS-ralink-adds-support-for-MT7620-SoC-family.patch index d528034..f03c10f 100644 --- a/target/linux/ramips/patches-3.8/0113-MIPS-ralink-adds-support-for-MT7620-SoC-family.patch +++ b/target/linux/ramips/patches-3.8/0029-MIPS-ralink-adds-support-for-MT7620-SoC-family.patch @@ -1,7 +1,7 @@ -From a8d7045a9530d0a9e0c65c0f81852bd57ebde53c Mon Sep 17 00:00:00 2001 +From 41b7b06b494eef5a081363566314960306437d73 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 21 Mar 2013 17:49:02 +0100 -Subject: [PATCH 113/137] MIPS: ralink: adds support for MT7620 SoC family +Subject: [PATCH 29/79] MIPS: ralink: adds support for MT7620 SoC family Add support code for mt7620 SOC. @@ -20,6 +20,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5177/ create mode 100644 arch/mips/include/asm/mach-ralink/mt7620.h create mode 100644 arch/mips/ralink/mt7620.c +diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h +new file mode 100644 +index 0000000..b272649 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/mt7620.h @@ -0,0 +1,76 @@ @@ -99,6 +102,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5177/ +#define MT7620_GPIO_MODE_WDT BIT(22) + +#endif +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index ce57d3e..86f6c77 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -20,6 +20,9 @@ choice @@ -111,6 +116,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5177/ endchoice choice +diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile +index ba9669c..38cf1a8 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile @@ -11,6 +11,7 @@ obj-y := prom.o of.o reset.o clk.o irq.o @@ -121,9 +128,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5177/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +diff --git a/arch/mips/ralink/Platform b/arch/mips/ralink/Platform +index f67c08d..b2cbf16 100644 --- a/arch/mips/ralink/Platform +++ b/arch/mips/ralink/Platform -@@ -18,3 +18,8 @@ load-$(CONFIG_SOC_RT305X) += 0xffffffff8 +@@ -18,3 +18,8 @@ load-$(CONFIG_SOC_RT305X) += 0xffffffff80000000 # Ralink RT3883 # load-$(CONFIG_SOC_RT3883) += 0xffffffff80000000 @@ -132,6 +141,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5177/ +# Ralink MT7620 +# +load-$(CONFIG_SOC_MT7620) += 0xffffffff80000000 +diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c +new file mode 100644 +index 0000000..eb00ab8 --- /dev/null +++ b/arch/mips/ralink/mt7620.c @@ -0,0 +1,214 @@ @@ -349,3 +361,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5177/ + cfg0 = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG0); + dram_type = (cfg0 >> SYSCFG0_DRAM_TYPE_SHIFT) & SYSCFG0_DRAM_TYPE_MASK; +} +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0114-MIPS-ralink-add-cpu-feature-overrides.h.patch b/target/linux/ramips/patches-3.8/0030-MIPS-ralink-add-cpu-feature-overrides.h.patch index dc5dab9..21205a3 100644 --- a/target/linux/ramips/patches-3.8/0114-MIPS-ralink-add-cpu-feature-overrides.h.patch +++ b/target/linux/ramips/patches-3.8/0030-MIPS-ralink-add-cpu-feature-overrides.h.patch @@ -1,7 +1,7 @@ -From 33c525913af22d1b799a7218ee48579c22a50cf8 Mon Sep 17 00:00:00 2001 +From 8a7cac5e324f044f3970d686d79e3489260f6d21 Mon Sep 17 00:00:00 2001 From: Gabor Juhos <juhosg@openwrt.org> Date: Wed, 10 Apr 2013 09:19:07 +0200 -Subject: [PATCH 114/137] MIPS: ralink: add cpu-feature-overrides.h +Subject: [PATCH 30/79] MIPS: ralink: add cpu-feature-overrides.h Add cpu-feature-overrides.h for RT288x, RT305x and RT3883. @@ -18,6 +18,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5175/ create mode 100644 arch/mips/include/asm/mach-ralink/rt305x/cpu-feature-overrides.h create mode 100644 arch/mips/include/asm/mach-ralink/rt3883/cpu-feature-overrides.h +diff --git a/arch/mips/include/asm/mach-ralink/rt288x/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ralink/rt288x/cpu-feature-overrides.h +new file mode 100644 +index 0000000..72fc106 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/rt288x/cpu-feature-overrides.h @@ -0,0 +1,56 @@ @@ -77,6 +80,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5175/ +#define cpu_icache_line_size() 16 + +#endif /* _RT288X_CPU_FEATURE_OVERRIDES_H */ +diff --git a/arch/mips/include/asm/mach-ralink/rt305x/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ralink/rt305x/cpu-feature-overrides.h +new file mode 100644 +index 0000000..917c286 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/rt305x/cpu-feature-overrides.h @@ -0,0 +1,56 @@ @@ -136,6 +142,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5175/ +#define cpu_icache_line_size() 32 + +#endif /* _RT305X_CPU_FEATURE_OVERRIDES_H */ +diff --git a/arch/mips/include/asm/mach-ralink/rt3883/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ralink/rt3883/cpu-feature-overrides.h +new file mode 100644 +index 0000000..181fbf4 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/rt3883/cpu-feature-overrides.h @@ -0,0 +1,55 @@ @@ -194,9 +203,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5175/ +#define cpu_icache_line_size() 32 + +#endif /* _RT3883_CPU_FEATURE_OVERRIDES_H */ +diff --git a/arch/mips/ralink/Platform b/arch/mips/ralink/Platform +index b2cbf16..cda4b66 100644 --- a/arch/mips/ralink/Platform +++ b/arch/mips/ralink/Platform -@@ -8,16 +8,19 @@ cflags-$(CONFIG_RALINK) += -I$(srctree) +@@ -8,16 +8,19 @@ cflags-$(CONFIG_RALINK) += -I$(srctree)/arch/mips/include/asm/mach-ralink # Ralink RT288x # load-$(CONFIG_SOC_RT288X) += 0xffffffff88000000 @@ -216,3 +227,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5175/ # # Ralink MT7620 +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0115-DT-add-vendor-prefixes-for-Ralink.patch b/target/linux/ramips/patches-3.8/0031-DT-add-vendor-prefixes-for-Ralink.patch index a9a99b4..7a81af6 100644 --- a/target/linux/ramips/patches-3.8/0115-DT-add-vendor-prefixes-for-Ralink.patch +++ b/target/linux/ramips/patches-3.8/0031-DT-add-vendor-prefixes-for-Ralink.patch @@ -1,7 +1,7 @@ -From 9377ecb9f1fb5da25a0fbd324e7add7644b1d43d Mon Sep 17 00:00:00 2001 +From f13cb76f8ad8714eaf691ef24aebfb57f62dab66 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 13 Apr 2013 10:11:51 +0200 -Subject: [PATCH 115/137] DT: add vendor prefixes for Ralink +Subject: [PATCH 31/79] DT: add vendor prefixes for Ralink Signed-off-by: John Crispin <blogic@openwrt.org> Acked-by: Grant Likely <grant.likely@secretlab.ca> @@ -9,6 +9,8 @@ Acked-by: Grant Likely <grant.likely@secretlab.ca> Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) +diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt +index 902b1b1..d1cc7bb 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -40,6 +40,7 @@ onnn ON Semiconductor Corp. @@ -19,3 +21,6 @@ Acked-by: Grant Likely <grant.likely@secretlab.ca> ramtron Ramtron International realtek Realtek Semiconductor Corp. samsung Samsung Semiconductor +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0116-DT-add-documentation-for-the-Ralink-MIPS-SoCs.patch b/target/linux/ramips/patches-3.8/0032-DT-add-documentation-for-the-Ralink-MIPS-SoCs.patch index f9463c4..1a66e63 100644 --- a/target/linux/ramips/patches-3.8/0116-DT-add-documentation-for-the-Ralink-MIPS-SoCs.patch +++ b/target/linux/ramips/patches-3.8/0032-DT-add-documentation-for-the-Ralink-MIPS-SoCs.patch @@ -1,7 +1,7 @@ -From fed1ff0d85b481bb3dbebf31e0720d65ce4170c9 Mon Sep 17 00:00:00 2001 +From 441d0189a47391c6882bbc6a11494e7cd394f1fc Mon Sep 17 00:00:00 2001 From: Gabor Juhos <juhosg@openwrt.org> Date: Sat, 13 Apr 2013 09:02:40 +0200 -Subject: [PATCH 116/137] DT: add documentation for the Ralink MIPS SoCs +Subject: [PATCH 32/79] DT: add documentation for the Ralink MIPS SoCs This patch adds binding documentation for the compatible values of the Ralink MIPS SoCs. @@ -15,6 +15,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5187/ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/mips/ralink.txt +diff --git a/Documentation/devicetree/bindings/mips/ralink.txt b/Documentation/devicetree/bindings/mips/ralink.txt +new file mode 100644 +index 0000000..59b6a35 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/ralink.txt @@ -0,0 +1,18 @@ @@ -36,3 +39,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5187/ + ralink,mt7620a-soc + ralink,mt7620n-soc + +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0117-DT-MIPS-ralink-clean-up-RT3050-dtsi-and-dts-file.patch b/target/linux/ramips/patches-3.8/0033-DT-MIPS-ralink-clean-up-RT3050-dtsi-and-dts-file.patch index 1328b43..a3a674f 100644 --- a/target/linux/ramips/patches-3.8/0117-DT-MIPS-ralink-clean-up-RT3050-dtsi-and-dts-file.patch +++ b/target/linux/ramips/patches-3.8/0033-DT-MIPS-ralink-clean-up-RT3050-dtsi-and-dts-file.patch @@ -1,7 +1,7 @@ -From 7a30e00a278fe94ac8e42d0967ffde99d1ab74ee Mon Sep 17 00:00:00 2001 +From 29d1bb6fc97d4391e4ecf96298b6ac42d0daefca Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> -Date: Thu, 21 Mar 2013 17:47:07 +0100 -Subject: [PATCH 117/137] DT: MIPS: ralink: clean up RT3050 dtsi and dts file +Date: Thu, 20 Jun 2013 18:44:43 +0200 +Subject: [PATCH 33/79] DT: MIPS: ralink: clean up RT3050 dtsi and dts file * remove nodes for cores whose drivers are not upstream yet * add compat string for an additional soc @@ -15,6 +15,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5186/ arch/mips/ralink/dts/rt3052_eval.dts | 10 ++----- 2 files changed, 4 insertions(+), 58 deletions(-) +diff --git a/arch/mips/ralink/dts/rt3050.dtsi b/arch/mips/ralink/dts/rt3050.dtsi +index 069d066..ef7da1e 100644 --- a/arch/mips/ralink/dts/rt3050.dtsi +++ b/arch/mips/ralink/dts/rt3050.dtsi @@ -1,7 +1,7 @@ @@ -104,6 +106,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5186/ uartlite@c00 { compatible = "ralink,rt3052-uart", "ralink,rt2880-uart", "ns16550a"; reg = <0xc00 0x100>; +diff --git a/arch/mips/ralink/dts/rt3052_eval.dts b/arch/mips/ralink/dts/rt3052_eval.dts +index dc56e58..df17f5f 100644 --- a/arch/mips/ralink/dts/rt3052_eval.dts +++ b/arch/mips/ralink/dts/rt3052_eval.dts @@ -3,8 +3,6 @@ @@ -115,3 +119,21 @@ Patchwork: http://patchwork.linux-mips.org/patch/5186/ compatible = "ralink,rt3052-eval-board", "ralink,rt3052-soc"; model = "Ralink RT3052 evaluation board"; +@@ -12,12 +10,8 @@ + reg = <0x0 0x2000000>; + }; + +- palmbus@10000000 { +- sysc@0 { +- ralink,pinmux = "uartlite", "spi"; +- ralink,uartmux = "gpio"; +- ralink,wdtmux = <0>; +- }; ++ chosen { ++ bootargs = "console=ttyS0,57600"; + }; + + cfi@1f000000 { +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0118-DT-MIPS-ralink-add-RT2880-dts-files.patch b/target/linux/ramips/patches-3.8/0034-DT-MIPS-ralink-add-RT2880-dts-files.patch index 8ad9b18..affa771 100644 --- a/target/linux/ramips/patches-3.8/0118-DT-MIPS-ralink-add-RT2880-dts-files.patch +++ b/target/linux/ramips/patches-3.8/0034-DT-MIPS-ralink-add-RT2880-dts-files.patch @@ -1,7 +1,7 @@ -From b39e659770cb71939765de8c9e73c0a0cfa832db Mon Sep 17 00:00:00 2001 +From b3cda181b5f9986b05bd95ee322504a8f2ed0b69 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 12 Apr 2013 06:27:37 +0000 -Subject: [PATCH 118/137] DT: MIPS: ralink: add RT2880 dts files +Subject: [PATCH 34/79] DT: MIPS: ralink: add RT2880 dts files Add a dtsi file for RT2880 SoC and a sample dts file. @@ -17,6 +17,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5188/ create mode 100644 arch/mips/ralink/dts/rt2880.dtsi create mode 100644 arch/mips/ralink/dts/rt2880_eval.dts +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index 86f6c77..2f6fbb8 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -34,6 +34,10 @@ choice @@ -30,11 +32,16 @@ Patchwork: http://patchwork.linux-mips.org/patch/5188/ config DTB_RT305X_EVAL bool "RT305x eval kit" depends on SOC_RT305X +diff --git a/arch/mips/ralink/dts/Makefile b/arch/mips/ralink/dts/Makefile +index 1a69fb3..f635a01 100644 --- a/arch/mips/ralink/dts/Makefile +++ b/arch/mips/ralink/dts/Makefile @@ -1 +1,2 @@ +obj-$(CONFIG_DTB_RT2880_EVAL) := rt2880_eval.dtb.o obj-$(CONFIG_DTB_RT305X_EVAL) := rt3052_eval.dtb.o +diff --git a/arch/mips/ralink/dts/rt2880.dtsi b/arch/mips/ralink/dts/rt2880.dtsi +new file mode 100644 +index 0000000..182afde --- /dev/null +++ b/arch/mips/ralink/dts/rt2880.dtsi @@ -0,0 +1,58 @@ @@ -96,6 +103,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5188/ + }; + }; +}; +diff --git a/arch/mips/ralink/dts/rt2880_eval.dts b/arch/mips/ralink/dts/rt2880_eval.dts +new file mode 100644 +index 0000000..322d700 --- /dev/null +++ b/arch/mips/ralink/dts/rt2880_eval.dts @@ -0,0 +1,46 @@ @@ -145,3 +155,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5188/ + }; + }; +}; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0119-DT-MIPS-ralink-add-RT3883-dts-files.patch b/target/linux/ramips/patches-3.8/0035-DT-MIPS-ralink-add-RT3883-dts-files.patch index 90b50ed..e416036 100644 --- a/target/linux/ramips/patches-3.8/0119-DT-MIPS-ralink-add-RT3883-dts-files.patch +++ b/target/linux/ramips/patches-3.8/0035-DT-MIPS-ralink-add-RT3883-dts-files.patch @@ -1,7 +1,7 @@ -From 8b02459b5aa171dc8726698c4b19341a4e441bb8 Mon Sep 17 00:00:00 2001 +From d702c2e334db0a75298654b12755fd5879dd29df Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 12 Apr 2013 06:27:39 +0000 -Subject: [PATCH 119/137] DT: MIPS: ralink: add RT3883 dts files +Subject: [PATCH 35/79] DT: MIPS: ralink: add RT3883 dts files Add a dtsi file for RT3883 SoC and a sample dts file. @@ -17,6 +17,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5189/ create mode 100644 arch/mips/ralink/dts/rt3883.dtsi create mode 100644 arch/mips/ralink/dts/rt3883_eval.dts +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index 2f6fbb8..493411f 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -42,6 +42,10 @@ choice @@ -30,12 +32,17 @@ Patchwork: http://patchwork.linux-mips.org/patch/5189/ endchoice endif +diff --git a/arch/mips/ralink/dts/Makefile b/arch/mips/ralink/dts/Makefile +index f635a01..040a986 100644 --- a/arch/mips/ralink/dts/Makefile +++ b/arch/mips/ralink/dts/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_DTB_RT2880_EVAL) := rt2880_eval.dtb.o obj-$(CONFIG_DTB_RT305X_EVAL) := rt3052_eval.dtb.o +obj-$(CONFIG_DTB_RT3883_EVAL) := rt3883_eval.dtb.o +diff --git a/arch/mips/ralink/dts/rt3883.dtsi b/arch/mips/ralink/dts/rt3883.dtsi +new file mode 100644 +index 0000000..3b131dd --- /dev/null +++ b/arch/mips/ralink/dts/rt3883.dtsi @@ -0,0 +1,58 @@ @@ -97,6 +104,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5189/ + }; + }; +}; +diff --git a/arch/mips/ralink/dts/rt3883_eval.dts b/arch/mips/ralink/dts/rt3883_eval.dts +new file mode 100644 +index 0000000..2fa6b33 --- /dev/null +++ b/arch/mips/ralink/dts/rt3883_eval.dts @@ -0,0 +1,16 @@ @@ -116,3 +126,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5189/ + bootargs = "console=ttyS0,57600"; + }; +}; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0120-DT-MIPS-ralink-add-MT7620A-dts-files.patch b/target/linux/ramips/patches-3.8/0036-DT-MIPS-ralink-add-MT7620A-dts-files.patch index 82a3086..1013c19 100644 --- a/target/linux/ramips/patches-3.8/0120-DT-MIPS-ralink-add-MT7620A-dts-files.patch +++ b/target/linux/ramips/patches-3.8/0036-DT-MIPS-ralink-add-MT7620A-dts-files.patch @@ -1,7 +1,7 @@ -From 07741f61fc94fad3c3d21fa1a2ad6f01455cc1dd Mon Sep 17 00:00:00 2001 +From 0757f88781dca6b29de4e1578a4900715371a926 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 12 Apr 2013 06:27:41 +0000 -Subject: [PATCH 120/137] DT: MIPS: ralink: add MT7620A dts files +Subject: [PATCH 36/79] DT: MIPS: ralink: add MT7620A dts files Add a dtsi file for MT7620A SoC and a sample dts file. @@ -17,6 +17,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5190/ create mode 100644 arch/mips/ralink/dts/mt7620a.dtsi create mode 100644 arch/mips/ralink/dts/mt7620a_eval.dts +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index 493411f..026e823 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -46,6 +46,10 @@ choice @@ -30,6 +32,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5190/ endchoice endif +diff --git a/arch/mips/ralink/dts/Makefile b/arch/mips/ralink/dts/Makefile +index 040a986..18194fa 100644 --- a/arch/mips/ralink/dts/Makefile +++ b/arch/mips/ralink/dts/Makefile @@ -1,3 +1,4 @@ @@ -37,6 +41,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5190/ obj-$(CONFIG_DTB_RT305X_EVAL) := rt3052_eval.dtb.o obj-$(CONFIG_DTB_RT3883_EVAL) := rt3883_eval.dtb.o +obj-$(CONFIG_DTB_MT7620A_EVAL) := mt7620a_eval.dtb.o +diff --git a/arch/mips/ralink/dts/mt7620a.dtsi b/arch/mips/ralink/dts/mt7620a.dtsi +new file mode 100644 +index 0000000..08bf24f --- /dev/null +++ b/arch/mips/ralink/dts/mt7620a.dtsi @@ -0,0 +1,58 @@ @@ -98,6 +105,9 @@ Patchwork: http://patchwork.linux-mips.org/patch/5190/ + }; + }; +}; +diff --git a/arch/mips/ralink/dts/mt7620a_eval.dts b/arch/mips/ralink/dts/mt7620a_eval.dts +new file mode 100644 +index 0000000..35eb874 --- /dev/null +++ b/arch/mips/ralink/dts/mt7620a_eval.dts @@ -0,0 +1,16 @@ @@ -117,3 +127,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5190/ + bootargs = "console=ttyS0,57600"; + }; +}; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0121-MIPS-add-detect_memory_region.patch b/target/linux/ramips/patches-3.8/0037-MIPS-add-detect_memory_region.patch index 8736e24..2f5626e 100644 --- a/target/linux/ramips/patches-3.8/0121-MIPS-add-detect_memory_region.patch +++ b/target/linux/ramips/patches-3.8/0037-MIPS-add-detect_memory_region.patch @@ -1,7 +1,7 @@ -From 9041c96ab5bd29d85ca95cffa44c755f68ae6bb1 Mon Sep 17 00:00:00 2001 +From 3350a0d29bc3f3d15b50835a20ffcc14a458e2d9 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 13 Apr 2013 13:15:47 +0200 -Subject: [PATCH 121/137] MIPS: add detect_memory_region() +Subject: [PATCH 37/79] MIPS: add detect_memory_region() Add a generic way of detecting the available RAM. This function is based on the implementation already used by ath79. @@ -13,6 +13,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5178/ arch/mips/kernel/setup.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) +diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h +index 7a51d87..6d6cfac 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -104,6 +104,7 @@ struct boot_mem_map { @@ -23,6 +25,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5178/ extern void prom_init(void); extern void prom_free_prom_memory(void); +diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c +index 8c41187..3937630 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -23,6 +23,7 @@ @@ -33,7 +37,7 @@ Patchwork: http://patchwork.linux-mips.org/patch/5178/ #include <asm/addrspace.h> #include <asm/bootinfo.h> -@@ -122,6 +123,25 @@ void __init add_memory_region(phys_t sta +@@ -122,6 +123,25 @@ void __init add_memory_region(phys_t start, phys_t size, long type) boot_mem_map.nr_map++; } @@ -59,3 +63,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5178/ static void __init print_memory_map(void) { int i; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0122-MIPS-ralink-add-memory-definition-to-struct-ralink_s.patch b/target/linux/ramips/patches-3.8/0038-MIPS-ralink-add-memory-definition-to-struct-ralink_s.patch index 3454a5b..36fc72a 100644 --- a/target/linux/ramips/patches-3.8/0122-MIPS-ralink-add-memory-definition-to-struct-ralink_s.patch +++ b/target/linux/ramips/patches-3.8/0038-MIPS-ralink-add-memory-definition-to-struct-ralink_s.patch @@ -1,7 +1,7 @@ -From 5155790ed1f270379ea98325f01e1c72a36a37d0 Mon Sep 17 00:00:00 2001 +From cfad83f59816f2be69a22955a398906d749ab108 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 13 Apr 2013 15:10:14 +0200 -Subject: [PATCH 122/137] MIPS: ralink: add memory definition to struct +Subject: [PATCH 38/79] MIPS: ralink: add memory definition to struct ralink_soc_info Depending on the actual SoC we have a different base address as well as minimum @@ -13,9 +13,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5179/ arch/mips/ralink/common.h | 5 +++++ 1 file changed, 5 insertions(+) +diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h +index 299119b..83144c3 100644 --- a/arch/mips/ralink/common.h +++ b/arch/mips/ralink/common.h -@@ -33,6 +33,11 @@ extern struct ralink_pinmux rt_gpio_pinm +@@ -33,6 +33,11 @@ extern struct ralink_pinmux rt_gpio_pinmux; struct ralink_soc_info { unsigned char sys_type[RAMIPS_SYS_TYPE_LEN]; unsigned char *compatible; @@ -27,3 +29,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5179/ }; extern struct ralink_soc_info soc_info; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0123-MIPS-ralink-add-memory-definition-for-RT305x.patch b/target/linux/ramips/patches-3.8/0039-MIPS-ralink-add-memory-definition-for-RT305x.patch index bf6d7f3..6738d9e 100644 --- a/target/linux/ramips/patches-3.8/0123-MIPS-ralink-add-memory-definition-for-RT305x.patch +++ b/target/linux/ramips/patches-3.8/0039-MIPS-ralink-add-memory-definition-for-RT305x.patch @@ -1,7 +1,7 @@ -From 016f1f659cf70cc78e72e12a2130d8f3e1a6e0d3 Mon Sep 17 00:00:00 2001 +From 7d0aa01494353532bbdc644469ef2a06ee089f3e Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 13 Apr 2013 15:13:40 +0200 -Subject: [PATCH 123/137] MIPS: ralink: add memory definition for RT305x +Subject: [PATCH 39/79] MIPS: ralink: add memory definition for RT305x Populate struct soc_info with the data that describes our RAM window. @@ -15,6 +15,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5180/ arch/mips/ralink/rt305x.c | 45 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) +diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h +index 80cda8a..069bf37 100644 --- a/arch/mips/include/asm/mach-ralink/rt305x.h +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -157,4 +157,10 @@ static inline int soc_is_rt5350(void) @@ -28,6 +30,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5180/ +#define RT3352_MEM_SIZE_MAX 256 + #endif +diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c +index 6aa3cb1..ca7ee3a 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -122,6 +122,40 @@ struct ralink_pinmux rt_gpio_pinmux = { @@ -65,13 +69,13 @@ Patchwork: http://patchwork.linux-mips.org/patch/5180/ + break; + } + -+ return ret * 1024 * 1024; ++ return ret; +} + void __init ralink_clk_init(void) { unsigned long cpu_rate, sys_rate, wdt_rate, uart_rate; -@@ -252,4 +286,15 @@ void prom_soc_init(struct ralink_soc_inf +@@ -252,4 +286,15 @@ void prom_soc_init(struct ralink_soc_info *soc_info) name, (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, (id & CHIP_ID_REV_MASK)); @@ -87,3 +91,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5180/ + soc_info->mem_size_max = RT3352_MEM_SIZE_MAX; + } } +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0124-MIPS-ralink-add-memory-definition-for-RT2880.patch b/target/linux/ramips/patches-3.8/0040-MIPS-ralink-add-memory-definition-for-RT2880.patch index 975fb48..e09d5b7 100644 --- a/target/linux/ramips/patches-3.8/0124-MIPS-ralink-add-memory-definition-for-RT2880.patch +++ b/target/linux/ramips/patches-3.8/0040-MIPS-ralink-add-memory-definition-for-RT2880.patch @@ -1,7 +1,7 @@ -From 0151f5f0dbf43b6b3718b0d1d403c87429ac0313 Mon Sep 17 00:00:00 2001 +From 1ca89d8a262f27f4ecd45d40b6774c415842421a Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 13 Apr 2013 15:37:37 +0200 -Subject: [PATCH 124/137] MIPS: ralink: add memory definition for RT2880 +Subject: [PATCH 40/79] MIPS: ralink: add memory definition for RT2880 Populate struct soc_info with the data that describes our RAM window. @@ -12,6 +12,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5181/ arch/mips/ralink/rt288x.c | 4 ++++ 2 files changed, 8 insertions(+) +diff --git a/arch/mips/include/asm/mach-ralink/rt288x.h b/arch/mips/include/asm/mach-ralink/rt288x.h +index ad8b42d..03ad716 100644 --- a/arch/mips/include/asm/mach-ralink/rt288x.h +++ b/arch/mips/include/asm/mach-ralink/rt288x.h @@ -46,4 +46,8 @@ @@ -23,9 +25,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5181/ +#define RT2880_MEM_SIZE_MAX 128 + #endif +diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c +index 1e0788e..f87de1a 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c -@@ -136,4 +136,8 @@ void prom_soc_init(struct ralink_soc_inf +@@ -136,4 +136,8 @@ void prom_soc_init(struct ralink_soc_info *soc_info) name, (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, (id & CHIP_ID_REV_MASK)); @@ -34,3 +38,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5181/ + soc_info->mem_size_min = RT2880_MEM_SIZE_MIN; + soc_info->mem_size_max = RT2880_MEM_SIZE_MAX; } +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0125-MIPS-ralink-add-memory-definition-for-RT3883.patch b/target/linux/ramips/patches-3.8/0041-MIPS-ralink-add-memory-definition-for-RT3883.patch index 2c015ad..1160906 100644 --- a/target/linux/ramips/patches-3.8/0125-MIPS-ralink-add-memory-definition-for-RT3883.patch +++ b/target/linux/ramips/patches-3.8/0041-MIPS-ralink-add-memory-definition-for-RT3883.patch @@ -1,20 +1,30 @@ -From de85c6c3e2d5ed9c721a282d91af504a845e1fad Mon Sep 17 00:00:00 2001 +From 42a816a8312734e6b438e799378044365e229a07 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 13 Apr 2013 20:23:19 +0200 -Subject: [PATCH 125/137] MIPS: ralink: add memory definition for RT3883 +Subject: [PATCH 41/79] MIPS: ralink: add memory definition for RT3883 Populate struct soc_info with the data that describes our RAM window. Signed-off-by: John Crispin <blogic@openwrt.org> Patchwork: http://patchwork.linux-mips.org/patch/5182/ --- - arch/mips/include/asm/mach-ralink/rt3883.h | 4 ++++ + arch/mips/include/asm/mach-ralink/rt3883.h | 5 +++++ arch/mips/ralink/rt3883.c | 4 ++++ - 2 files changed, 8 insertions(+) + 2 files changed, 9 insertions(+) +diff --git a/arch/mips/include/asm/mach-ralink/rt3883.h b/arch/mips/include/asm/mach-ralink/rt3883.h +index b91c6c1..058382f 100644 --- a/arch/mips/include/asm/mach-ralink/rt3883.h +++ b/arch/mips/include/asm/mach-ralink/rt3883.h -@@ -245,4 +245,8 @@ +@@ -152,6 +152,7 @@ + #define RT3883_GPIO_SPI_MISO 6 + #define RT3883_GPIO_7 7 + #define RT3883_GPIO_10 10 ++#define RT3883_GPIO_11 11 + #define RT3883_GPIO_14 14 + #define RT3883_GPIO_UART1_TXD 15 + #define RT3883_GPIO_UART1_RXD 16 +@@ -244,4 +245,8 @@ #define RT3883_FLASH_CFG_WIDTH_16BIT 0x1 #define RT3883_FLASH_CFG_WIDTH_32BIT 0x2 @@ -23,9 +33,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5182/ +#define RT3883_MEM_SIZE_MAX 256 + #endif /* _RT3883_REGS_H_ */ +diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c +index 2d90aa9..afbf2ce 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c -@@ -239,4 +239,8 @@ void prom_soc_init(struct ralink_soc_inf +@@ -239,4 +239,8 @@ void prom_soc_init(struct ralink_soc_info *soc_info) name, (id >> RT3883_REVID_VER_ID_SHIFT) & RT3883_REVID_VER_ID_MASK, (id & RT3883_REVID_ECO_ID_MASK)); @@ -34,3 +46,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5182/ + soc_info->mem_size_min = RT3883_MEM_SIZE_MIN; + soc_info->mem_size_max = RT3883_MEM_SIZE_MAX; } +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0126-MIPS-ralink-add-memory-definition-for-MT7620.patch b/target/linux/ramips/patches-3.8/0042-MIPS-ralink-add-memory-definition-for-MT7620.patch index b36ab33..da2610c 100644 --- a/target/linux/ramips/patches-3.8/0126-MIPS-ralink-add-memory-definition-for-MT7620.patch +++ b/target/linux/ramips/patches-3.8/0042-MIPS-ralink-add-memory-definition-for-MT7620.patch @@ -1,7 +1,7 @@ -From c1d35c42d697e9c28c817921a79c5f814529a4c6 Mon Sep 17 00:00:00 2001 +From e7dfbb1eafed754442099a33492a9e90fa33d3fa Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 14 Apr 2013 09:55:29 +0200 -Subject: [PATCH 126/137] MIPS: ralink: add memory definition for MT7620 +Subject: [PATCH 42/79] MIPS: ralink: add memory definition for MT7620 Populate struct soc_info with the data that describes our RAM window. @@ -12,6 +12,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5183/ arch/mips/ralink/mt7620.c | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) +diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h +index b272649..9809972 100644 --- a/arch/mips/include/asm/mach-ralink/mt7620.h +++ b/arch/mips/include/asm/mach-ralink/mt7620.h @@ -50,6 +50,14 @@ @@ -29,9 +31,11 @@ Patchwork: http://patchwork.linux-mips.org/patch/5183/ #define MT7620_GPIO_MODE_I2C BIT(0) #define MT7620_GPIO_MODE_UART0_SHIFT 2 #define MT7620_GPIO_MODE_UART0_MASK 0x7 +diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c +index eb00ab8..98ddb93 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c -@@ -211,4 +211,24 @@ void prom_soc_init(struct ralink_soc_inf +@@ -211,4 +211,24 @@ void prom_soc_init(struct ralink_soc_info *soc_info) cfg0 = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG0); dram_type = (cfg0 >> SYSCFG0_DRAM_TYPE_SHIFT) & SYSCFG0_DRAM_TYPE_MASK; @@ -56,3 +60,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5183/ + } + soc_info->mem_base = MT7620_DRAM_BASE; } +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0127-MIPS-ralink-make-use-of-the-new-memory-detection-cod.patch b/target/linux/ramips/patches-3.8/0043-MIPS-ralink-make-use-of-the-new-memory-detection-cod.patch index 59bdadd..1b6acf0 100644 --- a/target/linux/ramips/patches-3.8/0127-MIPS-ralink-make-use-of-the-new-memory-detection-cod.patch +++ b/target/linux/ramips/patches-3.8/0043-MIPS-ralink-make-use-of-the-new-memory-detection-cod.patch @@ -1,7 +1,7 @@ -From 1618a00f709817cbcdebf038d0b5e251c8d67237 Mon Sep 17 00:00:00 2001 +From 6142d0fa1c7ba6050664a27d7cca87043217b01f Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 13 Apr 2013 15:15:51 +0200 -Subject: [PATCH 127/137] MIPS: ralink: make use of the new memory detection +Subject: [PATCH 43/79] MIPS: ralink: make use of the new memory detection code Call detect_memory_region() from plat_mem_setup() unless the size was already @@ -13,6 +13,8 @@ Patchwork: http://patchwork.linux-mips.org/patch/5184/ arch/mips/ralink/of.c | 9 +++++++++ 1 file changed, 9 insertions(+) +diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c +index 4165e70..fb15695 100644 --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c @@ -11,6 +11,7 @@ @@ -38,3 +40,6 @@ Patchwork: http://patchwork.linux-mips.org/patch/5184/ } static int __init plat_of_setup(void) +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0044-MIPS-ralink-upstream-v3.10.patch b/target/linux/ramips/patches-3.8/0044-MIPS-ralink-upstream-v3.10.patch new file mode 100644 index 0000000..0ebbfe5 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0044-MIPS-ralink-upstream-v3.10.patch @@ -0,0 +1,23 @@ +From b6038567015683bc9541e2bee1b9bc0db50589a3 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 30 May 2013 16:16:13 +0200 +Subject: [PATCH 44/79] MIPS: ralink: upstream v3.10 + +patches prior to this were sent upstream and accepted for v3.10 + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + dummy | 1 + + 1 file changed, 1 insertion(+) + create mode 100644 dummy + +diff --git a/dummy b/dummy +new file mode 100644 +index 0000000..421376d +--- /dev/null ++++ b/dummy +@@ -0,0 +1 @@ ++dummy +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0128-MIPS-ralink-add-pinmux-driver.patch b/target/linux/ramips/patches-3.8/0045-MIPS-ralink-add-pinmux-driver.patch index f28115c..546719d 100644 --- a/target/linux/ramips/patches-3.8/0128-MIPS-ralink-add-pinmux-driver.patch +++ b/target/linux/ramips/patches-3.8/0045-MIPS-ralink-add-pinmux-driver.patch @@ -1,7 +1,7 @@ -From 5a2079532dfaf5762f658370ee7a0afb686f066e Mon Sep 17 00:00:00 2001 +From c7107291df4035794c67d7a904fe7419fedc5922 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Mon, 22 Apr 2013 23:11:42 +0200 -Subject: [PATCH 128/137] MIPS: ralink: add pinmux driver +Subject: [PATCH 45/79] MIPS: ralink: add pinmux driver Add code to setup the pinmux on ralonk SoC. The SoC has a single 32 bit register for this functionality with simple on/off bits. Building a full featured pinctrl @@ -12,10 +12,12 @@ Signed-off-by: John Crispin <blogic@openwrt.org> arch/mips/ralink/Makefile | 2 +- arch/mips/ralink/common.h | 2 ++ arch/mips/ralink/of.c | 2 ++ - arch/mips/ralink/pinmux.c | 76 +++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 81 insertions(+), 1 deletion(-) + arch/mips/ralink/pinmux.c | 77 +++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 arch/mips/ralink/pinmux.c +diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile +index 38cf1a8..341b4de 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile @@ -6,7 +6,7 @@ @@ -27,15 +29,19 @@ Signed-off-by: John Crispin <blogic@openwrt.org> obj-$(CONFIG_SOC_RT288X) += rt288x.o obj-$(CONFIG_SOC_RT305X) += rt305x.o +diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h +index 83144c3..f113fd6 100644 --- a/arch/mips/ralink/common.h +++ b/arch/mips/ralink/common.h -@@ -50,4 +50,6 @@ extern void prom_soc_init(struct ralink_ +@@ -50,4 +50,6 @@ extern void prom_soc_init(struct ralink_soc_info *soc_info); __iomem void *plat_of_remap_node(const char *node); +void ralink_pinmux(void); + #endif /* _RALINK_COMMON_H__ */ +diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c +index fb15695..f916774 100644 --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c @@ -110,6 +110,8 @@ static int __init plat_of_setup(void) @@ -47,6 +53,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> return 0; } +diff --git a/arch/mips/ralink/pinmux.c b/arch/mips/ralink/pinmux.c +new file mode 100644 +index 0000000..1720216 --- /dev/null +++ b/arch/mips/ralink/pinmux.c @@ -0,0 +1,77 @@ @@ -127,3 +136,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + + rt_sysc_w32(mode, SYSC_REG_GPIO_MODE); +} +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0129-MIPS-ralink-add-support-for-periodic-timer-irq.patch b/target/linux/ramips/patches-3.8/0046-MIPS-ralink-add-support-for-periodic-timer-irq.patch index 6664e11..18e001c 100644 --- a/target/linux/ramips/patches-3.8/0129-MIPS-ralink-add-support-for-periodic-timer-irq.patch +++ b/target/linux/ramips/patches-3.8/0046-MIPS-ralink-add-support-for-periodic-timer-irq.patch @@ -1,7 +1,7 @@ -From 1f307fd0fdca585d5c7c32963e8a8a6f38d8a78c Mon Sep 17 00:00:00 2001 +From f14edca84cd854dac7dd429b1fbeb80ac76fca16 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sat, 23 Mar 2013 19:44:41 +0100 -Subject: [PATCH 129/137] MIPS: ralink: add support for periodic timer irq +Subject: [PATCH 46/79] MIPS: ralink: add support for periodic timer irq Adds a driver for the periodic timer found on Ralink SoC. @@ -12,6 +12,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> 2 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 arch/mips/ralink/timer.c +diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile +index 341b4de..cae7d88 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile @@ -6,7 +6,7 @@ @@ -23,6 +25,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> obj-$(CONFIG_SOC_RT288X) += rt288x.o obj-$(CONFIG_SOC_RT305X) += rt305x.o +diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c +new file mode 100644 +index 0000000..0a6856c --- /dev/null +++ b/arch/mips/ralink/timer.c @@ -0,0 +1,192 @@ @@ -218,3 +223,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +MODULE_DESCRIPTION("Ralink RT2880 timer"); +MODULE_AUTHOR("John Crispin <blogic@openwrt.org"); +MODULE_LICENSE("GPL"); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0047-MIPS-ralink-add-rt_sysc_m32-helper.patch b/target/linux/ramips/patches-3.8/0047-MIPS-ralink-add-rt_sysc_m32-helper.patch new file mode 100644 index 0000000..6afdb5a --- /dev/null +++ b/target/linux/ramips/patches-3.8/0047-MIPS-ralink-add-rt_sysc_m32-helper.patch @@ -0,0 +1,31 @@ +From f7a5af8f5a3a4bc80a0c297c16c661d72ae356b4 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sun, 19 May 2013 00:42:23 +0200 +Subject: [PATCH 47/79] MIPS: ralink: add rt_sysc_m32 helper + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/include/asm/mach-ralink/ralink_regs.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/mips/include/asm/mach-ralink/ralink_regs.h b/arch/mips/include/asm/mach-ralink/ralink_regs.h +index 5a508f9..bd93014 100644 +--- a/arch/mips/include/asm/mach-ralink/ralink_regs.h ++++ b/arch/mips/include/asm/mach-ralink/ralink_regs.h +@@ -26,6 +26,13 @@ static inline u32 rt_sysc_r32(unsigned reg) + return __raw_readl(rt_sysc_membase + reg); + } + ++static inline void rt_sysc_m32(u32 clr, u32 set, unsigned reg) ++{ ++ u32 val = rt_sysc_r32(reg) & ~clr; ++ ++ __raw_writel(val | set, rt_sysc_membase + reg); ++} ++ + static inline void rt_memc_w32(u32 val, unsigned reg) + { + __raw_writel(val, rt_memc_membase + reg); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0048-MIPS-ralink-make-mt7620-ram-detect-verbose.patch b/target/linux/ramips/patches-3.8/0048-MIPS-ralink-make-mt7620-ram-detect-verbose.patch new file mode 100644 index 0000000..d17c227 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0048-MIPS-ralink-make-mt7620-ram-detect-verbose.patch @@ -0,0 +1,39 @@ +From 8c2015a6eed656d8578a78e392625869ba8f9bb4 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 20 May 2013 20:30:11 +0200 +Subject: [PATCH 48/79] MIPS: ralink: make mt7620 ram detect verbose + +Make the code print which of SDRAM, DDR1 or DDR2 was detected. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/ralink/mt7620.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c +index 98ddb93..28350d0 100644 +--- a/arch/mips/ralink/mt7620.c ++++ b/arch/mips/ralink/mt7620.c +@@ -214,16 +214,19 @@ void prom_soc_init(struct ralink_soc_info *soc_info) + + switch (dram_type) { + case SYSCFG0_DRAM_TYPE_SDRAM: ++ pr_info("Board has SDRAM\n"); + soc_info->mem_size_min = MT7620_SDRAM_SIZE_MIN; + soc_info->mem_size_max = MT7620_SDRAM_SIZE_MAX; + break; + + case SYSCFG0_DRAM_TYPE_DDR1: ++ pr_info("Board has DDR1\n"); + soc_info->mem_size_min = MT7620_DDR1_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR1_SIZE_MAX; + break; + + case SYSCFG0_DRAM_TYPE_DDR2: ++ pr_info("Board has DDR2\n"); + soc_info->mem_size_min = MT7620_DDR2_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR2_SIZE_MAX; + break; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0049-MIPS-ralink-add-verbose-pmu-info.patch b/target/linux/ramips/patches-3.8/0049-MIPS-ralink-add-verbose-pmu-info.patch new file mode 100644 index 0000000..206e9d8 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0049-MIPS-ralink-add-verbose-pmu-info.patch @@ -0,0 +1,64 @@ +From 1652cf71db797b249c0d384e6c3d31b312b7012e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 20 May 2013 20:57:09 +0200 +Subject: [PATCH 49/79] MIPS: ralink: add verbose pmu info + +Print the PMU and LDO settings on boot. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/ralink/mt7620.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c +index 28350d0..69729a5 100644 +--- a/arch/mips/ralink/mt7620.c ++++ b/arch/mips/ralink/mt7620.c +@@ -20,6 +20,22 @@ + + #include "common.h" + ++/* analog */ ++#define PMU0_CFG 0x88 ++#define PMU_SW_SET BIT(28) ++#define A_DCDC_EN BIT(24) ++#define A_SSC_PERI BIT(19) ++#define A_SSC_GEN BIT(18) ++#define A_SSC_M 0x3 ++#define A_SSC_S 16 ++#define A_DLY_M 0x7 ++#define A_DLY_S 8 ++#define A_VTUNE_M 0xff ++ ++/* digital */ ++#define PMU1_CFG 0x8C ++#define DIG_SW_SEL BIT(25) ++ + /* does the board have sdram or ddram */ + static int dram_type; + +@@ -187,6 +203,8 @@ void prom_soc_init(struct ralink_soc_info *soc_info) + u32 n1; + u32 rev; + u32 cfg0; ++ u32 pmu0; ++ u32 pmu1; + + n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); + n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); +@@ -234,4 +252,12 @@ void prom_soc_init(struct ralink_soc_info *soc_info) + BUG(); + } + soc_info->mem_base = MT7620_DRAM_BASE; ++ ++ pmu0 = __raw_readl(sysc + PMU0_CFG); ++ pmu1 = __raw_readl(sysc + PMU1_CFG); ++ ++ pr_info("Analog PMU set to %s control\n", ++ (pmu0 & PMU_SW_SET) ? ("sw") : ("hw")); ++ pr_info("Digital PMU set to %s control\n", ++ (pmu1 & DIG_SW_SEL) ? ("sw") : ("hw")); + } +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0050-MIPS-ralink-adds-a-bootrom-dumper-module.patch b/target/linux/ramips/patches-3.8/0050-MIPS-ralink-adds-a-bootrom-dumper-module.patch new file mode 100644 index 0000000..893a408 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0050-MIPS-ralink-adds-a-bootrom-dumper-module.patch @@ -0,0 +1,83 @@ +From d0d5dff525d921a7200d4919ea46c51fce27b7fb Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 May 2013 15:50:31 +0200 +Subject: [PATCH 50/79] MIPS: ralink: adds a bootrom dumper module + +This patch adds a trivial driver that allows userland to extract the bootrom of +a SoC via debugfs. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/ralink/Makefile | 2 ++ + arch/mips/ralink/bootrom.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+) + create mode 100644 arch/mips/ralink/bootrom.c + +diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile +index cae7d88..5fa6129 100644 +--- a/arch/mips/ralink/Makefile ++++ b/arch/mips/ralink/Makefile +@@ -15,4 +15,6 @@ obj-$(CONFIG_SOC_MT7620) += mt7620.o + + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + ++obj-$(CONFIG_DEBUG_FS) += bootrom.o ++ + obj-y += dts/ +diff --git a/arch/mips/ralink/bootrom.c b/arch/mips/ralink/bootrom.c +new file mode 100644 +index 0000000..f926f6f +--- /dev/null ++++ b/arch/mips/ralink/bootrom.c +@@ -0,0 +1,48 @@ ++/* ++ * 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) 2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/debugfs.h> ++#include <linux/seq_file.h> ++ ++#define BOOTROM_OFFSET 0x10118000 ++#define BOOTROM_SIZE 0x8000 ++ ++static void __iomem *membase = (void __iomem*) KSEG1ADDR(BOOTROM_OFFSET); ++ ++static int bootrom_show(struct seq_file *s, void *unused) ++{ ++ seq_write(s, membase, BOOTROM_SIZE); ++ ++ return 0; ++} ++ ++static int bootrom_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, bootrom_show, NULL); ++} ++ ++static const struct file_operations bootrom_file_ops = { ++ .open = bootrom_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int bootrom_setup(void) ++{ ++ if (!debugfs_create_file("bootrom", 0444, ++ NULL, NULL, &bootrom_file_ops)) { ++ pr_err("Failed to create bootrom debugfs file\n"); ++ ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++postcore_initcall(bootrom_setup); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0051-MIPS-ralink-add-missing-SZ_1M-multiplier.patch b/target/linux/ramips/patches-3.8/0051-MIPS-ralink-add-missing-SZ_1M-multiplier.patch new file mode 100644 index 0000000..161674e --- /dev/null +++ b/target/linux/ramips/patches-3.8/0051-MIPS-ralink-add-missing-SZ_1M-multiplier.patch @@ -0,0 +1,29 @@ +From 1996ffa03b1c6e0ab7db35dfd910923f4ab54b26 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 21 May 2013 17:15:54 +0200 +Subject: [PATCH 51/79] MIPS: ralink: add missing SZ_1M multiplier + +On RT5350 the memory size is set to Bytes and not MegaBytes due to a missing +multiplier. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/ralink/of.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c +index f916774..b25c1f2 100644 +--- a/arch/mips/ralink/of.c ++++ b/arch/mips/ralink/of.c +@@ -88,7 +88,7 @@ void __init plat_mem_setup(void) + __dt_setup_arch(&__dtb_start); + + if (soc_info.mem_size) +- add_memory_region(soc_info.mem_base, soc_info.mem_size, ++ add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M, + BOOT_MEM_RAM); + else + detect_memory_region(soc_info.mem_base, +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0052-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch b/target/linux/ramips/patches-3.8/0052-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch new file mode 100644 index 0000000..0a6ecc4 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0052-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch @@ -0,0 +1,78 @@ +From b9afea3f5cf6c2da3b88f2902c4377e9c5b22a6d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 3 May 2013 00:04:58 +0200 +Subject: [PATCH 52/79] MIPS: use set_mode() to enable/disable the cevt-r4k + irq + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/kernel/cevt-r4k.c | 39 ++++++++++++++++++++++++++------------- + 1 file changed, 26 insertions(+), 13 deletions(-) + +diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c +index 7532392..afc08e4 100644 +--- a/arch/mips/kernel/cevt-r4k.c ++++ b/arch/mips/kernel/cevt-r4k.c +@@ -39,12 +39,6 @@ static int mips_next_event(unsigned long delta, + + #endif /* CONFIG_MIPS_MT_SMTC */ + +-void mips_set_clock_mode(enum clock_event_mode mode, +- struct clock_event_device *evt) +-{ +- /* Nothing to do ... */ +-} +- + DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); + int cp0_timer_irq_installed; + +@@ -89,6 +83,32 @@ struct irqaction c0_compare_irqaction = { + .name = "timer", + }; + ++void mips_set_clock_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_ONESHOT: ++ if (cp0_timer_irq_installed) ++ break; ++ ++ cp0_timer_irq_installed = 1; ++ ++ setup_irq(evt->irq, &c0_compare_irqaction); ++ break; ++ ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ if (!cp0_timer_irq_installed) ++ break; ++ ++ cp0_timer_irq_installed = 0; ++ free_irq(evt->irq, &c0_compare_irqaction); ++ break; ++ ++ default: ++ pr_err("Unhandeled mips clock_mode\n"); ++ break; ++ } ++} + + void mips_event_handler(struct clock_event_device *dev) + { +@@ -208,13 +228,6 @@ int __cpuinit r4k_clockevent_init(void) + + clockevents_register_device(cd); + +- if (cp0_timer_irq_installed) +- return 0; +- +- cp0_timer_irq_installed = 1; +- +- setup_irq(irq, &c0_compare_irqaction); +- + return 0; + } + +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0053-MIPS-ralink-add-illegal-access-driver.patch b/target/linux/ramips/patches-3.8/0053-MIPS-ralink-add-illegal-access-driver.patch new file mode 100644 index 0000000..ef2fdb9 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0053-MIPS-ralink-add-illegal-access-driver.patch @@ -0,0 +1,121 @@ +From 69a5834d0a90588578df9689530fc8f3ab8ef59a Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 16 May 2013 23:28:23 +0200 +Subject: [PATCH 53/79] MIPS: ralink: add illegal access driver + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/ralink/Makefile | 2 +- + arch/mips/ralink/ill_acc.c | 87 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 88 insertions(+), 1 deletion(-) + create mode 100644 arch/mips/ralink/ill_acc.c + +diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile +index 5fa6129..55a5bfc 100644 +--- a/arch/mips/ralink/Makefile ++++ b/arch/mips/ralink/Makefile +@@ -6,7 +6,7 @@ + # Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> + # Copyright (C) 2013 John Crispin <blogic@openwrt.org> + +-obj-y := prom.o of.o reset.o clk.o irq.o pinmux.o timer.o ++obj-y := prom.o of.o reset.o clk.o irq.o pinmux.o timer.o ill_acc.o + + obj-$(CONFIG_SOC_RT288X) += rt288x.o + obj-$(CONFIG_SOC_RT305X) += rt305x.o +diff --git a/arch/mips/ralink/ill_acc.c b/arch/mips/ralink/ill_acc.c +new file mode 100644 +index 0000000..4a3f696 +--- /dev/null ++++ b/arch/mips/ralink/ill_acc.c +@@ -0,0 +1,87 @@ ++/* ++ * 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) 2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/interrupt.h> ++#include <linux/of_platform.h> ++#include <linux/of_irq.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#define REG_ILL_ACC_ADDR 0x10 ++#define REG_ILL_ACC_TYPE 0x14 ++ ++#define ILL_INT_STATUS BIT(31) ++#define ILL_ACC_WRITE BIT(30) ++#define ILL_ACC_LEN_M 0xff ++#define ILL_ACC_OFF_M 0xf ++#define ILL_ACC_OFF_S 16 ++#define ILL_ACC_ID_M 0x7 ++#define ILL_ACC_ID_S 8 ++ ++#define DRV_NAME "ill_acc" ++ ++static const char *ill_acc_ids[] = { ++ "cpu", "dma", "ppe", "pdma rx","pdma tx", "pci/e", "wmac", "usb", ++}; ++ ++static irqreturn_t ill_acc_irq_handler(int irq, void *_priv) ++{ ++ struct device *dev = (struct device *) _priv; ++ u32 addr = rt_memc_r32(REG_ILL_ACC_ADDR); ++ u32 type = rt_memc_r32(REG_ILL_ACC_TYPE); ++ ++ dev_err(dev, "illegal %s access from %s - addr:0x%08x offset:%d len:%d\n", ++ (type & ILL_ACC_WRITE) ? ("write") : ("read"), ++ ill_acc_ids[(type >> ILL_ACC_ID_S) & ILL_ACC_ID_M], ++ addr, (type >> ILL_ACC_OFF_S) & ILL_ACC_OFF_M, ++ type & ILL_ACC_LEN_M); ++ ++ rt_memc_w32(REG_ILL_ACC_TYPE, REG_ILL_ACC_TYPE); ++ ++ return IRQ_HANDLED; ++} ++ ++static int __init ill_acc_of_setup(void) ++{ ++ struct platform_device *pdev; ++ struct device_node *np; ++ int irq; ++ ++ /* somehow this driver breaks on RT5350 */ ++ if (of_machine_is_compatible("ralink,rt5350-soc")) ++ return -EINVAL; ++ ++ np = of_find_compatible_node(NULL, NULL, "ralink,rt3050-memc"); ++ if (!np) ++ return -EINVAL; ++ ++ pdev = of_find_device_by_node(np); ++ if (!pdev) { ++ pr_err("%s: failed to lookup pdev\n", np->name); ++ return -EINVAL; ++ } ++ ++ irq = irq_of_parse_and_map(np, 0); ++ if (!irq) { ++ dev_err(&pdev->dev, "failed to get irq\n"); ++ return -EINVAL; ++ } ++ ++ if (request_irq(irq, ill_acc_irq_handler, 0, "ill_acc", &pdev->dev)) { ++ dev_err(&pdev->dev, "failed to request irq\n"); ++ return -EINVAL; ++ } ++ ++ rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); ++ ++ dev_info(&pdev->dev, "irq registered\n"); ++ ++ return 0; ++} ++ ++arch_initcall(ill_acc_of_setup); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0054-MIPS-ralink-workaround-DTB-memory-issue.patch b/target/linux/ramips/patches-3.8/0054-MIPS-ralink-workaround-DTB-memory-issue.patch new file mode 100644 index 0000000..1a550ab --- /dev/null +++ b/target/linux/ramips/patches-3.8/0054-MIPS-ralink-workaround-DTB-memory-issue.patch @@ -0,0 +1,29 @@ +From 9b6da5fa57a40647f6d69ee1fcdabc5e5f7010dc Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 23 May 2013 18:50:56 +0200 +Subject: [PATCH 54/79] MIPS: ralink: workaround DTB memory issue + +If the DTB is too big a bug happens on boot when init ram is freed. +This is a temporary fix until the real cause is found. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/ralink/of.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c +index b25c1f2..8efb02b 100644 +--- a/arch/mips/ralink/of.c ++++ b/arch/mips/ralink/of.c +@@ -74,7 +74,7 @@ void __init device_tree_init(void) + unflatten_device_tree(); + + /* free the space reserved for the dt blob */ +- free_bootmem(base, size); ++ //free_bootmem(base, size); + } + + void __init plat_mem_setup(void) +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0055-MIPS-ralink-add-spi-clock-definition-to-mt7620a.patch b/target/linux/ramips/patches-3.8/0055-MIPS-ralink-add-spi-clock-definition-to-mt7620a.patch new file mode 100644 index 0000000..b6d91eb --- /dev/null +++ b/target/linux/ramips/patches-3.8/0055-MIPS-ralink-add-spi-clock-definition-to-mt7620a.patch @@ -0,0 +1,25 @@ +From 148d428995c21cc95350937d42ffd3b13e36daa5 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 23 May 2013 18:46:25 +0200 +Subject: [PATCH 55/79] MIPS: ralink: add spi clock definition to mt7620a + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/ralink/mt7620.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c +index 69729a5..08c96db6 100644 +--- a/arch/mips/ralink/mt7620.c ++++ b/arch/mips/ralink/mt7620.c +@@ -183,6 +183,7 @@ void __init ralink_clk_init(void) + ralink_clk_add("cpu", cpu_rate); + ralink_clk_add("10000100.timer", 40000000); + ralink_clk_add("10000500.uart", 40000000); ++ ralink_clk_add("10000b00.spi", 40000000); + ralink_clk_add("10000c00.uartlite", 40000000); + } + +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0056-MIPS-ralink-DTS-file-updates.patch b/target/linux/ramips/patches-3.8/0056-MIPS-ralink-DTS-file-updates.patch new file mode 100644 index 0000000..7081622 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0056-MIPS-ralink-DTS-file-updates.patch @@ -0,0 +1,1006 @@ +From 4f3d8fafc176d5d95957a4267c253d0c6ea5182d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 30 Apr 2013 17:27:46 +0200 +Subject: [PATCH 56/79] MIPS: ralink DTS file updates + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/ralink/Kconfig | 8 + + arch/mips/ralink/dts/Makefile | 2 + + arch/mips/ralink/dts/mt7620a.dtsi | 238 ++++++++++++++++++++++++- + arch/mips/ralink/dts/mt7620a_eval.dts | 111 ++++++++++++ + arch/mips/ralink/dts/mt7620a_mt7610e_eval.dts | 99 ++++++++++ + arch/mips/ralink/dts/rt2880.dtsi | 17 ++ + arch/mips/ralink/dts/rt2880_eval.dts | 6 + + arch/mips/ralink/dts/rt3050.dtsi | 31 +++- + arch/mips/ralink/dts/rt3052_eval.dts | 19 +- + arch/mips/ralink/dts/rt5350.dtsi | 227 +++++++++++++++++++++++ + arch/mips/ralink/dts/rt5350_eval.dts | 69 +++++++ + 11 files changed, 824 insertions(+), 3 deletions(-) + create mode 100644 arch/mips/ralink/dts/mt7620a_mt7610e_eval.dts + create mode 100644 arch/mips/ralink/dts/rt5350.dtsi + create mode 100644 arch/mips/ralink/dts/rt5350_eval.dts + +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index 026e823..38540a4 100644 +--- a/arch/mips/ralink/Kconfig ++++ b/arch/mips/ralink/Kconfig +@@ -42,6 +42,10 @@ choice + bool "RT305x eval kit" + depends on SOC_RT305X + ++ config DTB_RT5350_EVAL ++ bool "RT5350 eval kit" ++ depends on SOC_RT305X ++ + config DTB_RT3883_EVAL + bool "RT3883 eval kit" + depends on SOC_RT3883 +@@ -50,6 +54,10 @@ choice + bool "MT7620A eval kit" + depends on SOC_MT7620 + ++ config DTB_MT7620A_MT7610E_EVAL ++ bool "MT7620A + MT7610E eval kit" ++ depends on SOC_MT7620 ++ + endchoice + + endif +diff --git a/arch/mips/ralink/dts/Makefile b/arch/mips/ralink/dts/Makefile +index 18194fa..0bd12b5 100644 +--- a/arch/mips/ralink/dts/Makefile ++++ b/arch/mips/ralink/dts/Makefile +@@ -1,4 +1,6 @@ + obj-$(CONFIG_DTB_RT2880_EVAL) := rt2880_eval.dtb.o + obj-$(CONFIG_DTB_RT305X_EVAL) := rt3052_eval.dtb.o ++obj-$(CONFIG_DTB_RT5350_EVAL) := rt5350_eval.dtb.o + obj-$(CONFIG_DTB_RT3883_EVAL) := rt3883_eval.dtb.o + obj-$(CONFIG_DTB_MT7620A_EVAL) := mt7620a_eval.dtb.o ++obj-$(CONFIG_DTB_MT7620A_MT7610E_EVAL) := mt7620a_mt7610e_eval.dtb.o +diff --git a/arch/mips/ralink/dts/mt7620a.dtsi b/arch/mips/ralink/dts/mt7620a.dtsi +index 08bf24f..104abfb 100644 +--- a/arch/mips/ralink/dts/mt7620a.dtsi ++++ b/arch/mips/ralink/dts/mt7620a.dtsi +@@ -25,14 +25,36 @@ + #size-cells = <1>; + + sysc@0 { +- compatible = "ralink,mt7620a-sysc"; ++ compatible = "ralink,mt7620a-sysc", "ralink,rt3050-sysc"; + reg = <0x0 0x100>; + }; + ++ timer@100 { ++ compatible = "ralink,mt7620a-timer", "ralink,rt2880-timer"; ++ reg = <0x100 0x20>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <1>; ++ }; ++ ++ watchdog@120 { ++ compatible = "ralink,mt7620a-wdt", "ralink,rt2880-wdt"; ++ reg = <0x120 0x10>; ++ ++ resets = <&rstctrl 8>; ++ reset-names = "wdt"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <1>; ++ }; ++ + intc: intc@200 { + compatible = "ralink,mt7620a-intc", "ralink,rt2880-intc"; + reg = <0x200 0x100>; + ++ resets = <&rstctrl 19>; ++ reset-names = "intc"; ++ + interrupt-controller; + #interrupt-cells = <1>; + +@@ -43,16 +65,230 @@ + memc@300 { + compatible = "ralink,mt7620a-memc", "ralink,rt3050-memc"; + reg = <0x300 0x100>; ++ ++ resets = <&rstctrl 20>; ++ reset-names = "mc"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <3>; ++ }; ++ ++ uart@500 { ++ compatible = "ralink,mt7620a-uart", "ralink,rt2880-uart", "ns16550a"; ++ reg = <0x500 0x100>; ++ ++ resets = <&rstctrl 12>; ++ reset-names = "uart"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <5>; ++ ++ reg-shift = <2>; ++ ++ status = "disabled"; ++ }; ++ ++ gpio0: gpio@600 { ++ compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio"; ++ reg = <0x600 0x34>; ++ ++ resets = <&rstctrl 13>; ++ reset-names = "pio"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <6>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ ralink,gpio-base = <0>; ++ ralink,num-gpios = <24>; ++ ralink,register-map = [ 00 04 08 0c ++ 20 24 28 2c ++ 30 34 ]; ++ ++ status = "disabled"; ++ }; ++ ++ gpio1: gpio@638 { ++ compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio"; ++ reg = <0x638 0x24>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <6>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ ralink,gpio-base = <24>; ++ ralink,num-gpios = <16>; ++ ralink,register-map = [ 00 04 08 0c ++ 10 14 18 1c ++ 20 24 ]; ++ ++ status = "disabled"; ++ }; ++ ++ gpio2: gpio@660 { ++ compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio"; ++ reg = <0x660 0x24>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <6>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ ralink,gpio-base = <40>; ++ ralink,num-gpios = <32>; ++ ralink,register-map = [ 00 04 08 0c ++ 10 14 18 1c ++ 20 24 ]; ++ ++ status = "disabled"; ++ }; ++ ++ i2c@900 { ++ compatible = "link,mt7620a-i2c", "ralink,rt2880-i2c"; ++ reg = <0x900 0x100>; ++ ++ resets = <&rstctrl 16>; ++ reset-names = "i2c"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ ++ spi@b00 { ++ compatible = "ralink,mt7620a-spi", "ralink,rt2880-spi"; ++ reg = <0xb00 0x100>; ++ ++ resets = <&rstctrl 18>; ++ reset-names = "spi"; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ status = "disabled"; + }; + + uartlite@c00 { + compatible = "ralink,mt7620a-uart", "ralink,rt2880-uart", "ns16550a"; + reg = <0xc00 0x100>; + ++ resets = <&rstctrl 19>; ++ reset-names = "uartl"; ++ + interrupt-parent = <&intc>; + interrupts = <12>; + + reg-shift = <2>; + }; ++ ++ systick@d00 { ++ compatible = "ralink,mt7620a-systick", "ralink,cevt-systick"; ++ reg = <0xd00 0x10>; ++ ++ resets = <&rstctrl 28>; ++ reset-names = "intc"; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <7>; ++ }; ++ ++ gdma@2800 { ++ compatible = "ralink,mt7620a-gdma", "ralink,rt2880-gdma"; ++ reg = <0x2800 0x800>; ++ ++ resets = <&rstctrl 14>; ++ reset-names = "dma"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <7>; ++ }; ++ }; ++ ++ rstctrl: rstctrl { ++ compatible = "ralink,mt7620a-reset", "ralink,rt2880-reset"; ++ #reset-cells = <1>; ++ }; ++ ++ ubsphy { ++ compatible = "ralink,mt7620a-usbphy"; ++ ++ resets = <&rstctrl 22 &rstctrl 25>; ++ reset-names = "host", "device"; ++ }; ++ ++ ethernet@10100000 { ++ compatible = "ralink,mt7620a-eth"; ++ reg = <0x10100000 10000>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <5>; ++ ++ status = "disabled"; ++ ++ mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ }; ++ ++ gsw@10110000 { ++ compatible = "ralink,mt7620a-gsw"; ++ reg = <0x10110000 8000>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <17>; ++ ++ status = "disabled"; ++ }; ++ ++ sdhci@10130000 { ++ compatible = "ralink,mt7620a-sdhci"; ++ reg = <0x10130000 4000>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <14>; ++ ++ status = "disabled"; ++ }; ++ ++ ehci@101c0000 { ++ compatible = "ralink,rt3xxx-ehci"; ++ reg = <0x101c0000 0x1000>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <18>; ++ }; ++ ++ ohci@101c1000 { ++ compatible = "ralink,rt3xxx-ohci"; ++ reg = <0x101c1000 0x1000>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <18>; ++ }; ++ ++ pcie@10140000 { ++ compatible = "ralink,mt7620a-pci"; ++ reg = <0x10140000 0x100 ++ 0x10142000 0x100>; ++ ++ resets = <&rstctrl 26>; ++ reset-names = "pcie0"; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <4>; ++ ++ status = "disabled"; + }; + }; +diff --git a/arch/mips/ralink/dts/mt7620a_eval.dts b/arch/mips/ralink/dts/mt7620a_eval.dts +index 35eb874..b56f449 100644 +--- a/arch/mips/ralink/dts/mt7620a_eval.dts ++++ b/arch/mips/ralink/dts/mt7620a_eval.dts +@@ -13,4 +13,115 @@ + chosen { + bootargs = "console=ttyS0,57600"; + }; ++ ++ palmbus@10000000 { ++ sysc@0 { ++ ralink,pinmux = "spi", "uartlite", "mdio", "wled", "ephy", "rgmii1", "rgmii2"; ++ ralink,gpiomux = "i2c", "jtag"; ++ ralink,uartmux = "gpio"; ++ ralink,wdtmux = <1>; ++ }; ++ ++ gpio0: gpio@600 { ++ status = "okay"; ++ }; ++ ++ spi@b00 { ++ status = "okay"; ++ ++ m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "en25q64"; ++ reg = <0 0>; ++ linux,modalias = "m25p80", "en25q64"; ++ spi-max-frequency = <10000000>; ++ ++ partition@0 { ++ label = "u-boot"; ++ reg = <0x0 0x30000>; ++ read-only; ++ }; ++ ++ partition@30000 { ++ label = "u-boot-env"; ++ reg = <0x30000 0x10000>; ++ read-only; ++ }; ++ ++ factory: partition@40000 { ++ label = "factory"; ++ reg = <0x40000 0x10000>; ++ read-only; ++ }; ++ ++ partition@50000 { ++ label = "firmware"; ++ reg = <0x50000 0x7b0000>; ++ }; ++ }; ++ }; ++ }; ++ ++ ethernet@10100000 { ++ status = "okay"; ++ ++ port@4 { ++ compatible = "lantiq,mt7620a-gsw-port", "ralink,eth-port"; ++ reg = <4>; ++ phy-mode = "rgmii"; ++ phy-handle = <&phy4>; ++ }; ++ ++ port@5 { ++ compatible = "lantiq,mt7620a-gsw-port", "ralink,eth-port"; ++ reg = <5>; ++ phy-mode = "rgmii"; ++ phy-handle = <&phy5>; ++ }; ++ ++ mdio-bus { ++ status = "okay"; ++ ++ phy4: ethernet-phy@4 { ++ reg = <4>; ++ phy-mode = "rgmii"; ++ }; ++ ++ phy5: ethernet-phy@5 { ++ reg = <5>; ++ phy-mode = "rgmii"; ++ }; ++ }; ++ }; ++ ++ gsw@10110000 { ++ status = "okay"; ++ ralink,port4 = "gmac"; ++ }; ++ ++ sdhci@10130000 { ++ status = "okay"; ++ }; ++ ++ pcie@10140000 { ++ status = "okay"; ++ }; ++ ++ gpio-keys-polled { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ poll-interval = <20>; ++ s2 { ++ label = "S2"; ++ gpios = <&gpio0 1 1>; ++ linux,code = <0x100>; ++ }; ++ s3 { ++ label = "S3"; ++ gpios = <&gpio0 2 1>; ++ linux,code = <0x101>; ++ }; ++ }; + }; +diff --git a/arch/mips/ralink/dts/mt7620a_mt7610e_eval.dts b/arch/mips/ralink/dts/mt7620a_mt7610e_eval.dts +new file mode 100644 +index 0000000..0d7755b +--- /dev/null ++++ b/arch/mips/ralink/dts/mt7620a_mt7610e_eval.dts +@@ -0,0 +1,99 @@ ++/dts-v1/; ++ ++/include/ "mt7620a.dtsi" ++ ++/ { ++ compatible = "ralink,mt7620a-eval-board", "ralink,mt7620a-soc"; ++ model = "Ralink MT7620A evaluation board"; ++ ++ memory@0 { ++ reg = <0x0 0x2000000>; ++ }; ++ ++ chosen { ++ bootargs = "console=ttyS0,57600"; ++ }; ++ ++ palmbus@10000000 { ++ sysc@0 { ++ ralink,pinmux = "spi", "uartlite", "mdio", "wled", "ephy", "rgmii1", "rgmii2"; ++ ralink,gpiomux = "i2c", "jtag"; ++ ralink,uartmux = "gpio"; ++ ralink,wdtmux = <1>; ++ }; ++ ++ gpio0: gpio@600 { ++ status = "okay"; ++ }; ++ ++ spi@b00 { ++ status = "okay"; ++ ++ m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "en25q64"; ++ reg = <0 0>; ++ linux,modalias = "m25p80", "en25q64"; ++ spi-max-frequency = <10000000>; ++ ++ partition@0 { ++ label = "u-boot"; ++ reg = <0x0 0x30000>; ++ read-only; ++ }; ++ ++ partition@30000 { ++ label = "u-boot-env"; ++ reg = <0x30000 0x10000>; ++ read-only; ++ }; ++ ++ factory: partition@40000 { ++ label = "factory"; ++ reg = <0x40000 0x10000>; ++ read-only; ++ }; ++ ++ partition@50000 { ++ label = "firmware"; ++ reg = <0x50000 0x7b0000>; ++ }; ++ }; ++ }; ++ }; ++ ++ ethernet@10100000 { ++ status = "okay"; ++ }; ++ ++ gsw@10110000 { ++ status = "okay"; ++ ralink,port4 = "ephy"; ++ }; ++ ++ sdhci@10130000 { ++ status = "okay"; ++ }; ++ ++ pcie@10140000 { ++ status = "okay"; ++ }; ++ ++ gpio-keys-polled { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ poll-interval = <20>; ++ wps { ++ label = "wps"; ++ gpios = <&gpio0 12 1>; ++ linux,code = <0x100>; ++ }; ++ reset { ++ label = "reset"; ++ gpios = <&gpio0 13 1>; ++ linux,code = <0x101>; ++ }; ++ }; ++}; +diff --git a/arch/mips/ralink/dts/rt2880.dtsi b/arch/mips/ralink/dts/rt2880.dtsi +index 182afde..2a34b8d 100644 +--- a/arch/mips/ralink/dts/rt2880.dtsi ++++ b/arch/mips/ralink/dts/rt2880.dtsi +@@ -55,4 +55,21 @@ + reg-shift = <2>; + }; + }; ++ ++ ethernet@400000 { ++ compatible = "ralink,rt2880-eth"; ++ reg = <0x00400000 10000>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <5>; ++ ++ status = "disabled"; ++ ++ mdio-bus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ }; + }; +diff --git a/arch/mips/ralink/dts/rt2880_eval.dts b/arch/mips/ralink/dts/rt2880_eval.dts +index 322d700..58a1edf 100644 +--- a/arch/mips/ralink/dts/rt2880_eval.dts ++++ b/arch/mips/ralink/dts/rt2880_eval.dts +@@ -43,4 +43,10 @@ + reg = <0x50000 0x3b0000>; + }; + }; ++ ++ ethernet@400000 { ++ status = "okay"; ++ ++ ralink,fixed-link = <1000 1 1 1>; ++ }; + }; +diff --git a/arch/mips/ralink/dts/rt3050.dtsi b/arch/mips/ralink/dts/rt3050.dtsi +index ef7da1e..b1ac940 100644 +--- a/arch/mips/ralink/dts/rt3050.dtsi ++++ b/arch/mips/ralink/dts/rt3050.dtsi +@@ -1,7 +1,7 @@ + / { + #address-cells = <1>; + #size-cells = <1>; +- compatible = "ralink,rt3050-soc", "ralink,rt3052-soc", "ralink,rt3350-soc"; ++ compatible = "ralink,rt3050-soc", "ralink,rt3052-soc"; + + cpus { + cpu@0 { +@@ -45,6 +45,15 @@ + reg = <0x300 0x100>; + }; + ++ i2c@900 { ++ compatible = "link,rt3052-i2c", "ralink,rt2880-i2c"; ++ reg = <0x900 0x100>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ + uartlite@c00 { + compatible = "ralink,rt3052-uart", "ralink,rt2880-uart", "ns16550a"; + reg = <0xc00 0x100>; +@@ -55,4 +64,24 @@ + reg-shift = <2>; + }; + }; ++ ++ ethernet@10100000 { ++ compatible = "ralink,rt3050-eth"; ++ reg = <0x10100000 10000>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <5>; ++ ++ status = "disabled"; ++ }; ++ ++ esw@10110000 { ++ compatible = "ralink,rt3050-esw"; ++ reg = <0x10110000 8000>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <17>; ++ ++ status = "disabled"; ++ }; + }; +diff --git a/arch/mips/ralink/dts/rt3052_eval.dts b/arch/mips/ralink/dts/rt3052_eval.dts +index df17f5f..df02957 100644 +--- a/arch/mips/ralink/dts/rt3052_eval.dts ++++ b/arch/mips/ralink/dts/rt3052_eval.dts +@@ -3,7 +3,7 @@ + /include/ "rt3050.dtsi" + + / { +- compatible = "ralink,rt3052-eval-board", "ralink,rt3052-soc"; ++ compatible = "ralink,rt3052-eval-board", "ralink,rt3052-soc", "ralink,rt5350-soc"; + model = "Ralink RT3052 evaluation board"; + + memory@0 { +@@ -14,6 +14,14 @@ + bootargs = "console=ttyS0,57600"; + }; + ++ palmbus@10000000 { ++ sysc@0 { ++ ralink,pinmux = "i2c", "spi", "uartlite", "jtag", "mdio", "sdram", "rgmii"; ++ ralink,uartmux = "gpio"; ++ ralink,wdtmux = <1>; ++ }; ++ }; ++ + cfi@1f000000 { + compatible = "cfi-flash"; + reg = <0x1f000000 0x800000>; +@@ -43,4 +51,13 @@ + reg = <0x50000 0x7b0000>; + }; + }; ++ ++ ethernet@10100000 { ++ status = "okay"; ++ }; ++ ++ esw@10110000 { ++ status = "okay"; ++ ralink,portmap = <0x2f>; ++ }; + }; +diff --git a/arch/mips/ralink/dts/rt5350.dtsi b/arch/mips/ralink/dts/rt5350.dtsi +new file mode 100644 +index 0000000..3d6b3bc +--- /dev/null ++++ b/arch/mips/ralink/dts/rt5350.dtsi +@@ -0,0 +1,227 @@ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "ralink,rt5350-soc"; ++ ++ cpus { ++ cpu@0 { ++ compatible = "mips,mips24KEc"; ++ }; ++ }; ++ ++ cpuintc: cpuintc@0 { ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ interrupt-controller; ++ compatible = "mti,cpu-interrupt-controller"; ++ }; ++ ++ palmbus@10000000 { ++ compatible = "palmbus"; ++ reg = <0x10000000 0x200000>; ++ ranges = <0x0 0x10000000 0x1FFFFF>; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ sysc@0 { ++ compatible = "ralink,rt5350-sysc", "ralink,rt3050-sysc"; ++ reg = <0x0 0x100>; ++ }; ++ ++ timer@100 { ++ compatible = "ralink,rt5350-timer", "ralink,rt2880-timer"; ++ reg = <0x100 0x20>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <1>; ++ }; ++ ++ watchdog@120 { ++ compatible = "ralink,rt5350-wdt", "ralink,rt2880-wdt"; ++ reg = <0x120 0x10>; ++ ++ resets = <&rstctrl 8>; ++ reset-names = "wdt"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <1>; ++ }; ++ ++ intc: intc@200 { ++ compatible = "ralink,rt5350-intc", "ralink,rt2880-intc"; ++ reg = <0x200 0x100>; ++ ++ resets = <&rstctrl 19>; ++ reset-names = "intc"; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <2>; ++ }; ++ ++ memc@300 { ++ compatible = "ralink,rt5350-memc", "ralink,rt3050-memc"; ++ reg = <0x300 0x100>; ++ ++ resets = <&rstctrl 20>; ++ reset-names = "mc"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <3>; ++ }; ++ ++ uart@500 { ++ compatible = "ralink,rt5350-uart", "ralink,rt2880-uart", "ns16550a"; ++ reg = <0x500 0x100>; ++ ++ resets = <&rstctrl 12>; ++ reset-names = "uart"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <5>; ++ ++ reg-shift = <2>; ++ ++ status = "disabled"; ++ }; ++ ++ gpio0: gpio@600 { ++ compatible = "ralink,rt5350-gpio", "ralink,rt2880-gpio"; ++ reg = <0x600 0x34>; ++ ++ resets = <&rstctrl 13>; ++ reset-names = "pio"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <6>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ ralink,gpio-base = <0>; ++ ralink,num-gpios = <24>; ++ ralink,register-map = [ 00 04 08 0c ++ 20 24 28 2c ++ 30 34 ]; ++ ++ status = "disabled"; ++ }; ++ ++ gpio1: gpio@638 { ++ compatible = "ralink,rt5350-gpio", "ralink,rt2880-gpio"; ++ reg = <0x638 0x24>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <6>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ ++ ralink,gpio-base = <24>; ++ ralink,num-gpios = <16>; ++ ralink,register-map = [ 00 04 08 0c ++ 10 14 18 1c ++ 20 24 ]; ++ ++ status = "disabled"; ++ }; ++ ++ i2c@900 { ++ compatible = "link,rt5350-i2c", "ralink,rt2880-i2c"; ++ reg = <0x900 0x100>; ++ ++ resets = <&rstctrl 16>; ++ reset-names = "i2c"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ ++ spi@b00 { ++ compatible = "ralink,rt5350-spi", "ralink,rt2880-spi"; ++ reg = <0xb00 0x100>; ++ ++ resets = <&rstctrl 18>; ++ reset-names = "spi"; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ status = "disabled"; ++ }; ++ ++ uartlite@c00 { ++ compatible = "ralink,rt5350-uart", "ralink,rt2880-uart", "ns16550a"; ++ reg = <0xc00 0x100>; ++ ++ resets = <&rstctrl 19>; ++ reset-names = "uartl"; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <12>; ++ ++ reg-shift = <2>; ++ }; ++ ++ systick@d00 { ++ compatible = "ralink,rt5350-systick", "ralink,cevt-systick"; ++ reg = <0xd00 0x10>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <7>; ++ }; ++ }; ++ ++ rstctrl: rstctrl { ++ compatible = "ralink,rt5350-reset", "ralink,rt2880-reset"; ++ #reset-cells = <1>; ++ }; ++ ++ ubsphy { ++ compatible = "ralink,rt3xxx-usbphy"; ++ ++ resets = <&rstctrl 22 &rstctrl 25>; ++ reset-names = "host", "device"; ++ }; ++ ++ ethernet@10100000 { ++ compatible = "ralink,rt5350-eth"; ++ reg = <0x10100000 10000>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <5>; ++ ++ status = "disabled"; ++ }; ++ ++ esw@10110000 { ++ compatible = "ralink,rt3050-esw"; ++ reg = <0x10110000 8000>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <17>; ++ ++ status = "disabled"; ++ }; ++ ++ ehci@101c0000 { ++ compatible = "ralink,rt3xxx-ehci"; ++ reg = <0x101c0000 0x1000>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <18>; ++ }; ++ ++ ohci@101c1000 { ++ compatible = "ralink,rt3xxx-ohci"; ++ reg = <0x101c1000 0x1000>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <18>; ++ }; ++}; +diff --git a/arch/mips/ralink/dts/rt5350_eval.dts b/arch/mips/ralink/dts/rt5350_eval.dts +new file mode 100644 +index 0000000..ab92043 +--- /dev/null ++++ b/arch/mips/ralink/dts/rt5350_eval.dts +@@ -0,0 +1,69 @@ ++/dts-v1/; ++ ++/include/ "rt5350.dtsi" ++ ++/ { ++ compatible = "ralink,rt5350-eval-board", "ralink,rt5350-soc"; ++ model = "Ralink RT5350 evaluation board"; ++ ++ chosen { ++ bootargs = "console=ttyS0,57600"; ++ }; ++ ++ palmbus@10000000 { ++ sysc@0 { ++ ralink,pinmux = "i2c", "spi", "uartlite", "jtag", "mdio", "sdram", "rgmii"; ++ ralink,uartmux = "gpio"; ++ ralink,wdtmux = <1>; ++ }; ++ ++ gpio0: gpio@600 { ++ status = "okay"; ++ }; ++ ++ spi@b00 { ++ status = "okay"; ++ ++ m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "en25q64"; ++ reg = <0 0>; ++ linux,modalias = "m25p80", "mx25l3205d"; ++ spi-max-frequency = <10000000>; ++ ++ partition@0 { ++ label = "u-boot"; ++ reg = <0x0 0x30000>; ++ read-only; ++ }; ++ ++ partition@30000 { ++ label = "u-boot-env"; ++ reg = <0x30000 0x10000>; ++ read-only; ++ }; ++ ++ factory: partition@40000 { ++ label = "factory"; ++ reg = <0x40000 0x10000>; ++ read-only; ++ }; ++ ++ partition@50000 { ++ label = "firmware"; ++ reg = <0x50000 0x3b0000>; ++ }; ++ }; ++ }; ++ }; ++ ++ ethernet@10100000 { ++ status = "okay"; ++ }; ++ ++ esw@10110000 { ++ status = "okay"; ++ ralink,portmap = <0x2f>; ++ }; ++}; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0130-GPIO-MIPS-ralink-adds-ralink-gpio-support.patch b/target/linux/ramips/patches-3.8/0057-GPIO-MIPS-ralink-adds-ralink-gpio-support.patch index cdff431..3149ac2 100644 --- a/target/linux/ramips/patches-3.8/0130-GPIO-MIPS-ralink-adds-ralink-gpio-support.patch +++ b/target/linux/ramips/patches-3.8/0057-GPIO-MIPS-ralink-adds-ralink-gpio-support.patch @@ -1,7 +1,7 @@ -From 007ab7fe49bfcaa220372260eedeb4eed51f1631 Mon Sep 17 00:00:00 2001 +From de5e1cd11d62d2e1a00210b757dad35e1372963b Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Tue, 22 Jan 2013 18:24:34 +0100 -Subject: [PATCH 130/137] GPIO: MIPS: ralink: adds ralink gpio support +Subject: [PATCH 57/79] GPIO: MIPS: ralink: adds ralink gpio support Add gpio driver for Ralink SoC. This driver makes the gpio core on RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work. @@ -9,14 +9,16 @@ RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work. Signed-off-by: John Crispin <blogic@openwrt.org> --- arch/mips/Kconfig | 1 + - arch/mips/include/asm/mach-ralink/gpio.h | 24 ++++ + arch/mips/include/asm/mach-ralink/gpio.h | 24 +++ drivers/gpio/Kconfig | 6 + drivers/gpio/Makefile | 1 + - drivers/gpio/gpio-ralink.c | 176 ++++++++++++++++++++++++++++++ - 5 files changed, 208 insertions(+) + drivers/gpio/gpio-ralink.c | 326 ++++++++++++++++++++++++++++++ + 5 files changed, 358 insertions(+) create mode 100644 arch/mips/include/asm/mach-ralink/gpio.h create mode 100644 drivers/gpio/gpio-ralink.c +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index b5fd476..2498972 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -449,6 +449,7 @@ config RALINK @@ -27,6 +29,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> config SGI_IP22 bool "SGI IP22 (Indy/Indigo2)" +diff --git a/arch/mips/include/asm/mach-ralink/gpio.h b/arch/mips/include/asm/mach-ralink/gpio.h +new file mode 100644 +index 0000000..f68ee16 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/gpio.h @@ -0,0 +1,24 @@ @@ -54,6 +59,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +#define gpio_to_irq __gpio_to_irq + +#endif /* __ASM_MACH_RALINK_GPIO_H */ +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index 682de75..2e6e81c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -201,6 +201,12 @@ config GPIO_PXA @@ -69,9 +76,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> config GPIO_SPEAR_SPICS bool "ST SPEAr13xx SPI Chip Select as GPIO support" depends on PLAT_SPEAR +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index c5aebd0..a00adfc 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile -@@ -54,6 +54,7 @@ obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf85 +@@ -54,6 +54,7 @@ obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o @@ -79,9 +88,12 @@ Signed-off-by: John Crispin <blogic@openwrt.org> obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o +diff --git a/drivers/gpio/gpio-ralink.c b/drivers/gpio/gpio-ralink.c +new file mode 100644 +index 0000000..12984f1 --- /dev/null +++ b/drivers/gpio/gpio-ralink.c -@@ -0,0 +1,182 @@ +@@ -0,0 +1,326 @@ +/* + * 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 @@ -96,6 +108,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +#include <linux/gpio.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> ++#include <linux/of_irq.h> ++#include <linux/irqdomain.h> ++#include <linux/interrupt.h> + +enum ralink_gpio_reg { + GPIO_REG_INT = 0, @@ -117,13 +132,24 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + + spinlock_t lock; + void __iomem *membase; ++ struct irq_domain *domain; ++ int irq; ++ ++ u32 rising; ++ u32 falling; +}; + ++#define MAP_MAX 4 ++static struct irq_domain *irq_map[MAP_MAX]; ++static int irq_map_count; ++static atomic_t irq_refcount = ATOMIC_INIT(0); ++ +static inline struct ralink_gpio_chip *to_ralink_gpio(struct gpio_chip *chip) +{ + struct ralink_gpio_chip *rg; + + rg = container_of(chip, struct ralink_gpio_chip, chip); ++ + return rg; +} + @@ -183,32 +209,158 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + return 0; +} + ++static int ralink_gpio_to_irq(struct gpio_chip *chip, unsigned pin) ++{ ++ struct ralink_gpio_chip *rg = to_ralink_gpio(chip); ++ ++ if (rg->irq < 1) ++ return -1; ++ ++ ralink_gpio_direction_input(chip, pin); ++ ++ return irq_create_mapping(rg->domain, pin); ++} ++ ++static void ralink_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ int i; ++ ++ for (i = 0; i < irq_map_count; i++) { ++ struct irq_domain *domain = irq_map[i]; ++ struct ralink_gpio_chip *rg = (struct ralink_gpio_chip *) domain->host_data; ++ unsigned long pending = rt_gpio_r32(rg, GPIO_REG_INT); ++ int bit; ++ ++ for_each_set_bit(bit, &pending, rg->chip.ngpio) { ++ u32 map = irq_find_mapping(domain, bit); ++ generic_handle_irq(map); ++ rt_gpio_w32(rg, GPIO_REG_INT, BIT(bit)); ++ } ++ } ++} ++ ++static void ralink_gpio_irq_unmask(struct irq_data *d) ++{ ++ struct ralink_gpio_chip *rg = (struct ralink_gpio_chip *) d->domain->host_data; ++ u32 val = rt_gpio_r32(rg, GPIO_REG_RENA); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&rg->lock, flags); ++ rt_gpio_w32(rg, GPIO_REG_RENA, val | (BIT(d->hwirq) & rg->rising)); ++ rt_gpio_w32(rg, GPIO_REG_FENA, val | (BIT(d->hwirq) & rg->falling)); ++ spin_unlock_irqrestore(&rg->lock, flags); ++} ++ ++static void ralink_gpio_irq_mask(struct irq_data *d) ++{ ++ struct ralink_gpio_chip *rg = (struct ralink_gpio_chip *) d->domain->host_data; ++ u32 val = rt_gpio_r32(rg, GPIO_REG_RENA); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&rg->lock, flags); ++ rt_gpio_w32(rg, GPIO_REG_FENA, val & ~BIT(d->hwirq)); ++ rt_gpio_w32(rg, GPIO_REG_RENA, val & ~BIT(d->hwirq)); ++ spin_unlock_irqrestore(&rg->lock, flags); ++} ++ ++static int ralink_gpio_irq_type(struct irq_data *d, unsigned int type) ++{ ++ struct ralink_gpio_chip *rg = (struct ralink_gpio_chip *) d->domain->host_data; ++ u32 mask = BIT(d->hwirq); ++ ++ if (type == IRQ_TYPE_PROBE) { ++ if ((rg->rising | rg->falling) & mask) ++ return 0; ++ ++ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_RISING; ++ } ++ ++ if (type & IRQ_TYPE_EDGE_RISING) ++ rg->rising |= mask; ++ else ++ rg->rising &= mask; ++ ++ if (type & IRQ_TYPE_EDGE_RISING) ++ rg->falling |= mask; ++ else ++ rg->falling &= mask; ++ ++ return 0; ++} ++ ++static struct irq_chip ralink_gpio_irq_chip = { ++ .name = "GPIO", ++ .irq_unmask = ralink_gpio_irq_unmask, ++ .irq_mask = ralink_gpio_irq_mask, ++ .irq_mask_ack = ralink_gpio_irq_mask, ++ .irq_set_type = ralink_gpio_irq_type, ++}; ++ ++static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) ++{ ++ irq_set_chip_and_handler(irq, &ralink_gpio_irq_chip, handle_level_irq); ++ irq_set_handler_data(irq, d); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops irq_domain_ops = { ++ .xlate = irq_domain_xlate_onecell, ++ .map = gpio_map, ++}; ++ ++static void ralink_gpio_irq_init(struct device_node *np, struct ralink_gpio_chip *rg) ++{ ++ if (irq_map_count >= MAP_MAX) ++ return; ++ ++ rg->irq = irq_of_parse_and_map(np, 0); ++ if (!rg->irq) ++ return; ++ ++ rg->domain = irq_domain_add_linear(np, rg->chip.ngpio, &irq_domain_ops, rg); ++ if (!rg->domain) { ++ dev_err(rg->chip.dev, "irq_domain_add_linear failed\n"); ++ return; ++ } ++ ++ irq_map[irq_map_count++] = rg->domain; ++ ++ rt_gpio_w32(rg, GPIO_REG_RENA, 0x0); ++ rt_gpio_w32(rg, GPIO_REG_FENA, 0x0); ++ ++ if (!atomic_read(&irq_refcount)) ++ irq_set_chained_handler(rg->irq, ralink_gpio_irq_handler); ++ atomic_inc(&irq_refcount); ++ ++ dev_info(rg->chip.dev, "registering %d irq handlers\n", rg->chip.ngpio); ++} ++ +static int ralink_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ struct ralink_gpio_chip *gc; -+ const __be32 *ngpio; -+ const __be32 *gpiobase; ++ struct ralink_gpio_chip *rg; ++ const __be32 *ngpio, *gpiobase; + + if (!res) { + dev_err(&pdev->dev, "failed to find resource\n"); + return -ENOMEM; + } + -+ gc = devm_kzalloc(&pdev->dev, -+ sizeof(struct ralink_gpio_chip), GFP_KERNEL); -+ if (!gc) ++ rg = devm_kzalloc(&pdev->dev, ++ sizeof(struct ralink_gpio_chip), GFP_KERNEL); ++ if (!rg) + return -ENOMEM; + -+ gc->membase = devm_request_and_ioremap(&pdev->dev, res); -+ if (!gc->membase) { ++ rg->membase = devm_request_and_ioremap(&pdev->dev, res); ++ if (!rg->membase) { + dev_err(&pdev->dev, "cannot remap I/O memory region\n"); + return -ENOMEM; + } + + if (of_property_read_u8_array(np, "ralink,register-map", -+ gc->regs, GPIO_REG_MAX)) { ++ rg->regs, GPIO_REG_MAX)) { + dev_err(&pdev->dev, "failed to read register definition\n"); + return -EINVAL; + } @@ -221,26 +373,30 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + + gpiobase = of_get_property(np, "ralink,gpio-base", NULL); + if (gpiobase) -+ gc->chip.base = be32_to_cpu(*gpiobase); ++ rg->chip.base = be32_to_cpu(*gpiobase); + else -+ gc->chip.base = -1; ++ rg->chip.base = -1; + -+ gc->chip.label = dev_name(&pdev->dev); -+ gc->chip.of_node = np; -+ gc->chip.ngpio = be32_to_cpu(*ngpio); -+ gc->chip.direction_input = ralink_gpio_direction_input; -+ gc->chip.direction_output = ralink_gpio_direction_output; -+ gc->chip.get = ralink_gpio_get; -+ gc->chip.set = ralink_gpio_set; ++ spin_lock_init(&rg->lock); + -+ spin_lock_init(&gc->lock); ++ rg->chip.dev = &pdev->dev; ++ rg->chip.label = dev_name(&pdev->dev); ++ rg->chip.of_node = np; ++ rg->chip.ngpio = be32_to_cpu(*ngpio); ++ rg->chip.direction_input = ralink_gpio_direction_input; ++ rg->chip.direction_output = ralink_gpio_direction_output; ++ rg->chip.get = ralink_gpio_get; ++ rg->chip.set = ralink_gpio_set; ++ rg->chip.to_irq = ralink_gpio_to_irq; + + /* set polarity to low for all lines */ -+ rt_gpio_w32(gc, GPIO_REG_POL, 0); ++ rt_gpio_w32(rg, GPIO_REG_POL, 0); ++ ++ dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); + -+ dev_info(&pdev->dev, "registering %d gpios\n", gc->chip.ngpio); ++ ralink_gpio_irq_init(np, rg); + -+ return gpiochip_add(&gc->chip); ++ return gpiochip_add(&rg->chip); +} + +static const struct of_device_id ralink_gpio_match[] = { @@ -264,3 +420,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +} + +subsys_initcall(ralink_gpio_init); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0131-SPI-ralink-add-Ralink-SoC-spi-driver.patch b/target/linux/ramips/patches-3.8/0058-SPI-ralink-add-Ralink-SoC-spi-driver.patch index 8217b48..f1706f5 100644 --- a/target/linux/ramips/patches-3.8/0131-SPI-ralink-add-Ralink-SoC-spi-driver.patch +++ b/target/linux/ramips/patches-3.8/0058-SPI-ralink-add-Ralink-SoC-spi-driver.patch @@ -1,7 +1,7 @@ -From 32c1cff4c75925a0bbd305e85ed4adb30140cd42 Mon Sep 17 00:00:00 2001 +From cfb23fbd5be0276507a8af15be0738a7834555b5 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Mon, 22 Apr 2013 23:16:18 +0200 -Subject: [PATCH 131/137] SPI: ralink: add Ralink SoC spi driver +Subject: [PATCH 58/79] SPI: ralink: add Ralink SoC spi driver Add the driver needed to make SPI work on Ralink SoC. @@ -9,28 +9,32 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + - drivers/spi/spi-ralink.c | 472 ++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 479 insertions(+) + drivers/spi/spi-ralink.c | 475 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 482 insertions(+) create mode 100644 drivers/spi/spi-ralink.c +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 2e188e1..76c489a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig -@@ -324,6 +324,12 @@ config SPI_RSPI +@@ -315,6 +315,12 @@ config SPI_RSPI help SPI driver for Renesas RSPI blocks. +config SPI_RALINK + tristate "Ralink RT288x/RT305x/RT3662 SPI Controller" -+ depends on (SOC_RT288X || SOC_RT305X || SOC_RT3883) ++ depends on (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620) + help + This selects a driver for the Ralink RT288x/RT305x SPI Controller. + config SPI_S3C24XX tristate "Samsung S3C24XX series SPI" depends on ARCH_S3C24XX && EXPERIMENTAL +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index 64e970b..5b73cf8 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -51,6 +51,7 @@ obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx. +@@ -50,6 +50,7 @@ obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o @@ -38,9 +42,12 @@ Signed-off-by: John Crispin <blogic@openwrt.org> obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o spi-s3c24xx-hw-y := spi-s3c24xx.o spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o +diff --git a/drivers/spi/spi-ralink.c b/drivers/spi/spi-ralink.c +new file mode 100644 +index 0000000..b07cbaa --- /dev/null +++ b/drivers/spi/spi-ralink.c -@@ -0,0 +1,472 @@ +@@ -0,0 +1,475 @@ +/* + * spi-ralink.c -- Ralink RT288x/RT305x SPI controller driver + * @@ -61,9 +68,10 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/delay.h> -+#include <linux/platform_device.h> +#include <linux/io.h> ++#include <linux/reset.h> +#include <linux/spi/spi.h> ++#include <linux/platform_device.h> + +#define DRIVER_NAME "spi-ralink" +#define RALINK_NUM_CHIPSELECTS 1 /* only one slave is supported*/ @@ -457,6 +465,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + goto out_disable_clk; + } + ++ device_reset(&pdev->dev); ++ + ralink_spi_reset(rs); + + status = spi_register_master(master); @@ -513,3 +523,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +MODULE_AUTHOR("Sergiy <piratfm@gmail.com>"); +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_LICENSE("GPL"); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0132-serial-of-allow-au1x00-and-rt288x-to-load-from-OF.patch b/target/linux/ramips/patches-3.8/0059-serial-of-allow-au1x00-and-rt288x-to-load-from-OF.patch index bff0799..16a82ca 100644 --- a/target/linux/ramips/patches-3.8/0132-serial-of-allow-au1x00-and-rt288x-to-load-from-OF.patch +++ b/target/linux/ramips/patches-3.8/0059-serial-of-allow-au1x00-and-rt288x-to-load-from-OF.patch @@ -1,7 +1,7 @@ -From 15bcdbd78abacbe0986a1904d2e2b5dcfe780b5b Mon Sep 17 00:00:00 2001 +From 15a3839fa080feec3b4ce6d92b08893bf1eefe56 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Tue, 22 Jan 2013 16:01:07 +0100 -Subject: [PATCH 132/137] serial: of: allow au1x00 and rt288x to load from OF +Subject: [PATCH 59/79] serial: of: allow au1x00 and rt288x to load from OF In order to make serial_8250 loadable via OF on Au1x00 and Ralink WiSoC we need to default the iotype to UPIO_AU. @@ -11,9 +11,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> drivers/tty/serial/of_serial.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) +diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c +index e7cae1c..026e5d6 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c -@@ -97,7 +97,10 @@ static int of_platform_serial_setup(stru +@@ -97,7 +97,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->regshift = prop; port->irq = irq_of_parse_and_map(np, 0); @@ -25,3 +27,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { switch (prop) { case 1: +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0133-serial-ralink-adds-mt7620-serial.patch b/target/linux/ramips/patches-3.8/0060-serial-ralink-adds-mt7620-serial.patch index 1fce223..c935a5a 100644 --- a/target/linux/ramips/patches-3.8/0133-serial-ralink-adds-mt7620-serial.patch +++ b/target/linux/ramips/patches-3.8/0060-serial-ralink-adds-mt7620-serial.patch @@ -1,7 +1,7 @@ -From 6471ee7bbf3f8b70267ba1dc93f067e18803c246 Mon Sep 17 00:00:00 2001 +From d76f99c928f0cd6e6cd3d99c916d890ae9a1e073 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Fri, 15 Mar 2013 18:16:01 +0100 -Subject: [PATCH 133/137] serial: ralink: adds mt7620 serial +Subject: [PATCH 60/79] serial: ralink: adds mt7620 serial Add the config symbol for Mediatek7620 SoC to SERIAL_8250_RT288X @@ -10,6 +10,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> drivers/tty/serial/8250/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) +diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig +index 9e4febd..d1ec3a1 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -280,7 +280,7 @@ config SERIAL_8250_EM @@ -21,3 +23,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> help If you have a Ralink RT288x/RT305x SoC based board and want to use the serial port, say Y to this option. The driver can handle up to 2 serial +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0061-DMA-MIPS-ralink-add-dmaengine-driver.patch b/target/linux/ramips/patches-3.8/0061-DMA-MIPS-ralink-add-dmaengine-driver.patch new file mode 100644 index 0000000..a2f8f09 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0061-DMA-MIPS-ralink-add-dmaengine-driver.patch @@ -0,0 +1,341 @@ +From 1db0d19afe5830f7d020c7c5386be8cc20cf0f15 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 23 May 2013 18:45:29 +0200 +Subject: [PATCH 61/79] DMA: MIPS: ralink: add dmaengine driver + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + drivers/dma/Kconfig | 7 ++ + drivers/dma/Makefile | 1 + + drivers/dma/ralink_gdma.c | 229 +++++++++++++++++++++++++++++++++++++++++++++ + drivers/dma/ralink_gdma.h | 55 +++++++++++ + 4 files changed, 292 insertions(+) + create mode 100644 drivers/dma/ralink_gdma.c + create mode 100644 drivers/dma/ralink_gdma.h + +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index d4c1218..323f684 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -320,6 +320,13 @@ config MMP_PDMA + help + Support the MMP PDMA engine for PXA and MMP platfrom. + ++config RALINK_GDMA ++ bool "Ralink Generic DMA support" ++ depends on RALINK ++ select DMA_ENGINE ++ help ++ Support the GDMA engine for MIPS based Ralink SoC. ++ + config DMA_ENGINE + bool + +diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile +index 7428fea..a981e2c 100644 +--- a/drivers/dma/Makefile ++++ b/drivers/dma/Makefile +@@ -34,3 +34,4 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o + obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o + obj-$(CONFIG_DMA_OMAP) += omap-dma.o + obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o ++obj-$(CONFIG_RALINK_GDMA) += ralink_gdma.o +diff --git a/drivers/dma/ralink_gdma.c b/drivers/dma/ralink_gdma.c +new file mode 100644 +index 0000000..be7c317 +--- /dev/null ++++ b/drivers/dma/ralink_gdma.c +@@ -0,0 +1,229 @@ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/delay.h> ++#include <linux/dma-mapping.h> ++#include <linux/spinlock.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/of_platform.h> ++#include <linux/memory.h> ++ ++#include "ralink_gdma.h" ++ ++#define SURFBOARDINT_DMA 10 ++#define MEMCPY_DMA_CH 8 ++#define to_rt2880_dma_chan(chan) \ ++ container_of(chan, struct rt2880_dma_chan, common) ++ ++static dma_cookie_t rt2880_dma_tx_submit(struct dma_async_tx_descriptor *tx) ++{ ++ dma_cookie_t cookie; ++ ++ cookie = tx->chan->cookie; ++ ++ return cookie; ++} ++ ++#define MIN_RTDMA_PKT_LEN 128 ++static struct dma_async_tx_descriptor * ++rt2880_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, ++ size_t len, unsigned long flags) ++{ ++ struct rt2880_dma_chan *rt_chan = to_rt2880_dma_chan(chan); ++ unsigned long mid_offset; ++ ++ spin_lock_bh(&rt_chan->lock); ++ ++ if(len < MIN_RTDMA_PKT_LEN) { ++ memcpy(phys_to_virt(dest), phys_to_virt(src), len); ++ } else { ++ mid_offset = len/2; ++ ++ /* Lower parts are transferred by GDMA. ++ * Upper parts are transferred by CPU. ++ */ ++ RT_DMA_WRITE_REG(RT_DMA_SRC_REG(MEMCPY_DMA_CH), src); ++ RT_DMA_WRITE_REG(RT_DMA_DST_REG(MEMCPY_DMA_CH), dest); ++ RT_DMA_WRITE_REG(RT_DMA_CTRL_REG(MEMCPY_DMA_CH), (mid_offset << 16) | (3 << 3) | (3 << 0)); ++ ++ memcpy(phys_to_virt(dest)+mid_offset, phys_to_virt(src)+mid_offset, len-mid_offset); ++ ++ dma_async_tx_descriptor_init(&rt_chan->txd, chan); ++ ++ while((RT_DMA_READ_REG(RT_DMA_DONEINT) & (0x1<<MEMCPY_DMA_CH))==0); ++ RT_DMA_WRITE_REG(RT_DMA_DONEINT, (1<<MEMCPY_DMA_CH)); ++ } ++ ++ spin_unlock_bh(&rt_chan->lock); ++ ++ return &rt_chan->txd; ++} ++ ++/** ++ * rt2880_dma_status - poll the status of an XOR transaction ++ * @chan: XOR channel handle ++ * @cookie: XOR transaction identifier ++ * @txstate: XOR transactions state holder (or NULL) ++ */ ++static enum dma_status rt2880_dma_status(struct dma_chan *chan, ++ dma_cookie_t cookie, ++ struct dma_tx_state *txstate) ++{ ++ return 0; ++} ++ ++static irqreturn_t rt2880_dma_interrupt_handler(int irq, void *data) ++{ ++ ++ printk("%s\n",__FUNCTION__); ++ ++ return IRQ_HANDLED; ++} ++ ++static void rt2880_dma_issue_pending(struct dma_chan *chan) ++{ ++} ++ ++static int rt2880_dma_alloc_chan_resources(struct dma_chan *chan) ++{ ++// printk("%s\n",__FUNCTION__); ++ ++ return 0; ++} ++ ++static void rt2880_dma_free_chan_resources(struct dma_chan *chan) ++{ ++// printk("%s\n",__FUNCTION__); ++ ++} ++ ++static int rt2880_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case DMA_TERMINATE_ALL: ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ break; ++ case DMA_SLAVE_CONFIG: ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ break; ++ default: ++ return -ENXIO; ++ } ++ ++ return 0; ++} ++ ++static int rt2880_dma_probe(struct platform_device *pdev) ++{ ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ __iomem void *membase; ++ struct dma_device *dma_dev; ++ struct rt2880_dma_chan *rt_chan; ++ int err; ++ int ret; ++ int reg; ++ int irq; ++ ++ membase = devm_request_and_ioremap(&pdev->dev, res); ++ if (IS_ERR(membase)) ++ return PTR_ERR(membase); ++ ++ dma_dev = devm_kzalloc(&pdev->dev, sizeof(*dma_dev), GFP_KERNEL); ++ if (!dma_dev) ++ return -ENOMEM; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (!irq) { ++ dev_err(&pdev->dev, "failed to load irq\n"); ++ return -ENOENT; ++ } ++ ++ ++ INIT_LIST_HEAD(&dma_dev->channels); ++ dma_cap_zero(dma_dev->cap_mask); ++ dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask); ++ dma_cap_set(DMA_SLAVE, dma_dev->cap_mask); ++ dma_dev->device_alloc_chan_resources = rt2880_dma_alloc_chan_resources; ++ dma_dev->device_free_chan_resources = rt2880_dma_free_chan_resources; ++ dma_dev->device_tx_status = rt2880_dma_status; ++ dma_dev->device_issue_pending = rt2880_dma_issue_pending; ++ dma_dev->device_prep_dma_memcpy = rt2880_dma_prep_dma_memcpy; ++ dma_dev->device_control = rt2880_dma_control; ++ dma_dev->dev = &pdev->dev; ++ ++ rt_chan = devm_kzalloc(&pdev->dev, sizeof(*rt_chan), GFP_KERNEL); ++ if (!rt_chan) { ++ return -ENOMEM; ++ } ++ ++ spin_lock_init(&rt_chan->lock); ++ INIT_LIST_HEAD(&rt_chan->chain); ++ INIT_LIST_HEAD(&rt_chan->completed_slots); ++ INIT_LIST_HEAD(&rt_chan->all_slots); ++ rt_chan->common.device = dma_dev; ++ rt_chan->txd.tx_submit = rt2880_dma_tx_submit; ++ ++ list_add_tail(&rt_chan->common.device_node, &dma_dev->channels); ++ ++ err = dma_async_device_register(dma_dev); ++ if (0 != err) { ++ pr_err("ERR_MDMA:device_register failed: %d\n", err); ++ return 1; ++ } ++ ++ ret = request_irq(irq, rt2880_dma_interrupt_handler, 0, dev_name(&pdev->dev), NULL); ++ if(ret){ ++ pr_err("IRQ %d is not free.\n", SURFBOARDINT_DMA); ++ return 1; ++ } ++ ++ //set GDMA register in advance. ++ reg = (32 << 16) | (32 << 8) | (MEMCPY_DMA_CH << 3); ++ RT_DMA_WRITE_REG(RT_DMA_CTRL_REG1(MEMCPY_DMA_CH), reg); ++ ++ dev_info(&pdev->dev, "running\n"); ++ ++ return 0; ++} ++ ++static int rt2880_dma_remove(struct platform_device *dev) ++{ ++ struct dma_device *dma_dev = platform_get_drvdata(dev); ++ ++ printk("%s\n",__FUNCTION__); ++ ++ dma_async_device_unregister(dma_dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id rt2880_dma_match[] = { ++ { .compatible = "ralink,rt2880-gdma" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rt2880_wdt_match); ++ ++static struct platform_driver rt2880_dma_driver = { ++ .probe = rt2880_dma_probe, ++ .remove = rt2880_dma_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = RT_DMA_NAME, ++ .of_match_table = rt2880_dma_match, ++ }, ++}; ++ ++static int __init rt2880_dma_init(void) ++{ ++ int rc; ++ ++ rc = platform_driver_register(&rt2880_dma_driver); ++ return rc; ++} ++module_init(rt2880_dma_init); ++ ++MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>"); ++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("DMA engine driver for Ralink DMA engine"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/dma/ralink_gdma.h b/drivers/dma/ralink_gdma.h +new file mode 100644 +index 0000000..73e1948 +--- /dev/null ++++ b/drivers/dma/ralink_gdma.h +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2007, 2008, Marvell International Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef RT_DMA_H ++#define RT_DMA_H ++ ++#include <linux/types.h> ++#include <linux/io.h> ++#include <linux/dmaengine.h> ++#include <linux/interrupt.h> ++ ++#define RT_DMA_NAME "rt2880_dma" ++ ++#define RALINK_GDMA_BASE 0xB0002800 ++ ++struct rt2880_dma_chan { ++ int pending; ++ dma_cookie_t completed_cookie; ++ spinlock_t lock; /* protects the descriptor slot pool */ ++ void __iomem *mmr_base; ++ unsigned int idx; ++ enum dma_transaction_type current_type; ++ struct dma_async_tx_descriptor txd; ++ struct list_head chain; ++ struct list_head completed_slots; ++ struct dma_chan common; ++ struct list_head all_slots; ++ int slots_allocated; ++ struct tasklet_struct irq_tasklet; ++}; ++ ++#define RT_DMA_READ_REG(addr) le32_to_cpu(*(volatile u32 *)(addr)) ++#define RT_DMA_WRITE_REG(addr, val) *((volatile uint32_t *)(addr)) = cpu_to_le32(val) ++ ++#define RT_DMA_SRC_REG(ch) (RALINK_GDMA_BASE + ch*16) ++#define RT_DMA_DST_REG(ch) (RT_DMA_SRC_REG(ch) + 4) ++#define RT_DMA_CTRL_REG(ch) (RT_DMA_DST_REG(ch) + 4) ++#define RT_DMA_CTRL_REG1(ch) (RT_DMA_CTRL_REG(ch) + 4) ++#define RT_DMA_DONEINT (RALINK_GDMA_BASE + 0x204) ++ ++#endif +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0134-PCI-MIPS-adds-rt2880-pci-support.patch b/target/linux/ramips/patches-3.8/0062-PCI-MIPS-adds-rt2880-pci-support.patch index 70758f1..108455d 100644 --- a/target/linux/ramips/patches-3.8/0134-PCI-MIPS-adds-rt2880-pci-support.patch +++ b/target/linux/ramips/patches-3.8/0062-PCI-MIPS-adds-rt2880-pci-support.patch @@ -1,7 +1,7 @@ -From 55e9ae6a23cb799b7c1d402e1cfda11a6bd1e86e Mon Sep 17 00:00:00 2001 +From ac237657b04e464f28e8fe428d032386ca8b0b31 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 21 Mar 2013 18:27:29 +0100 -Subject: [PATCH 134/137] PCI: MIPS: adds rt2880 pci support +Subject: [PATCH 62/79] PCI: MIPS: adds rt2880 pci support Add support for the pci found on the rt2880 SoC. @@ -13,9 +13,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> 3 files changed, 283 insertions(+) create mode 100644 arch/mips/pci/pci-rt2880.c +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index ce995d3..c7c18ce 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile -@@ -42,6 +42,7 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1 +@@ -42,6 +42,7 @@ 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 @@ -23,6 +25,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> 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/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c +new file mode 100644 +index 0000000..e2c4730 --- /dev/null +++ b/arch/mips/pci/pci-rt2880.c @@ -0,0 +1,281 @@ @@ -307,6 +312,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +} + +arch_initcall(pcibios_init); +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index 38540a4..2d39329 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -8,6 +8,7 @@ choice @@ -317,3 +324,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> config SOC_RT305X bool "RT305x" +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0135-PCI-MIPS-adds-rt3883-pci-support.patch b/target/linux/ramips/patches-3.8/0063-PCI-MIPS-adds-rt3883-pci-support.patch index 9c4ca82..c1c8f75 100644 --- a/target/linux/ramips/patches-3.8/0135-PCI-MIPS-adds-rt3883-pci-support.patch +++ b/target/linux/ramips/patches-3.8/0063-PCI-MIPS-adds-rt3883-pci-support.patch @@ -1,7 +1,7 @@ -From 2a5dccdb00d85a6ad6111d7a2b13f9f4fae35838 Mon Sep 17 00:00:00 2001 +From 5b942b64c01b57cbde0dff2185728d5a8facea76 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Thu, 21 Mar 2013 17:34:08 +0100 -Subject: [PATCH 135/137] PCI: MIPS: adds rt3883 pci support +Subject: [PATCH 63/79] PCI: MIPS: adds rt3883 pci support Add support for the pcie found on the rt3883 SoC. @@ -13,9 +13,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> 3 files changed, 642 insertions(+) create mode 100644 arch/mips/pci/pci-rt3883.c +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index c7c18ce..a238158 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile -@@ -43,6 +43,7 @@ obj-$(CONFIG_SNI_RM) += fixup-sni.o ops +@@ -43,6 +43,7 @@ obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o obj-$(CONFIG_LANTIQ) += fixup-lantiq.o obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o obj-$(CONFIG_SOC_RT2880) += pci-rt2880.o @@ -23,6 +25,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> 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/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c +new file mode 100644 +index 0000000..212c90b --- /dev/null +++ b/arch/mips/pci/pci-rt3883.c @@ -0,0 +1,640 @@ @@ -666,6 +671,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +} + +postcore_initcall(rt3883_pci_init); +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index 2d39329..f2f20ec 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -20,6 +20,7 @@ choice @@ -676,3 +683,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> config SOC_MT7620 bool "MT7620" +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0064-PCI-MIPS-adds-mt7620a-pcie-driver.patch b/target/linux/ramips/patches-3.8/0064-PCI-MIPS-adds-mt7620a-pcie-driver.patch new file mode 100644 index 0000000..b3b0ad4 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0064-PCI-MIPS-adds-mt7620a-pcie-driver.patch @@ -0,0 +1,409 @@ +From 44712deb87f994f837796a55f670bf4c0d0d5b51 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 20 Jun 2013 18:48:58 +0200 +Subject: [PATCH 64/79] PCI: MIPS: adds mt7620a pcie driver + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/pci/Makefile | 1 + + arch/mips/pci/pci-mt7620a.c | 363 +++++++++++++++++++++++++++++++++++++++++++ + arch/mips/ralink/Kconfig | 1 + + 3 files changed, 365 insertions(+) + create mode 100644 arch/mips/pci/pci-mt7620a.c + +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index a238158..168d477 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -44,6 +44,7 @@ obj-$(CONFIG_LANTIQ) += fixup-lantiq.o + obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o + obj-$(CONFIG_SOC_RT2880) += pci-rt2880.o + obj-$(CONFIG_SOC_RT3883) += pci-rt3883.o ++obj-$(CONFIG_SOC_MT7620) += pci-mt7620a.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/pci-mt7620a.c b/arch/mips/pci/pci-mt7620a.c +new file mode 100644 +index 0000000..271763c +--- /dev/null ++++ b/arch/mips/pci/pci-mt7620a.c +@@ -0,0 +1,363 @@ ++/* ++ * Ralink MT7620A SoC PCI support ++ * ++ * Copyright (C) 2007-2013 Bruce Chang ++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include <linux/types.h> ++#include <linux/pci.h> ++#include <linux/io.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_irq.h> ++#include <linux/of_pci.h> ++#include <linux/reset.h> ++#include <linux/platform_device.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#define RALINK_PCI_MM_MAP_BASE 0x20000000 ++#define RALINK_PCI_IO_MAP_BASE 0x10160000 ++ ++#define RALINK_INT_PCIE0 4 ++#define RALINK_SYSTEM_CONTROL_BASE 0xb0000000 ++#define RALINK_SYSCFG1 0x14 ++#define RALINK_CLKCFG1 0x30 ++#define RALINK_GPIOMODE 0x60 ++#define RALINK_PCIE_CLK_GEN 0x7c ++#define RALINK_PCIE_CLK_GEN1 0x80 ++#define PCIEPHY0_CFG 0x90 ++#define PPLL_CFG1 0x9c ++#define PPLL_DRV 0xa0 ++#define RALINK_PCI_HOST_MODE_EN (1<<7) ++#define RALINK_PCIE_RC_MODE_EN (1<<8) ++#define RALINK_PCIE_RST (1<<23) ++#define RALINK_PCI_RST (1<<24) ++#define RALINK_PCI_CLK_EN (1<<19) ++#define RALINK_PCIE_CLK_EN (1<<21) ++#define PCI_SLOTx2 (1<<11) ++#define PCI_SLOTx1 (2<<11) ++#define PDRV_SW_SET (1<<31) ++#define LC_CKDRVPD_ (1<<19) ++ ++#define RALINK_PCI_CONFIG_ADDR 0x20 ++#define RALINK_PCI_CONFIG_DATA_VIRTUAL_REG 0x24 ++#define MEMORY_BASE 0x0 ++#define RALINK_PCIE0_RST (1<<26) ++#define RALINK_PCI_BASE 0xB0140000 ++#define RALINK_PCI_MEMBASE 0x28 ++#define RALINK_PCI_IOBASE 0x2C ++ ++#define RT6855_PCIE0_OFFSET 0x2000 ++ ++#define RALINK_PCI_PCICFG_ADDR 0x00 ++#define RALINK_PCI0_BAR0SETUP_ADDR 0x10 ++#define RALINK_PCI0_IMBASEBAR0_ADDR 0x18 ++#define RALINK_PCI0_ID 0x30 ++#define RALINK_PCI0_CLASS 0x34 ++#define RALINK_PCI0_SUBID 0x38 ++#define RALINK_PCI0_STATUS 0x50 ++#define RALINK_PCI_PCIMSK_ADDR 0x0C ++ ++#define RALINK_PCIE0_CLK_EN (1 << 26) ++ ++#define BUSY 0x80000000 ++#define WAITRETRY_MAX 10 ++#define WRITE_MODE (1UL << 23) ++#define DATA_SHIFT 0 ++#define ADDR_SHIFT 8 ++ ++ ++static void __iomem *bridge_base; ++static void __iomem *pcie_base; ++ ++static struct reset_control *rstpcie0; ++ ++static inline void bridge_w32(u32 val, unsigned reg) ++{ ++ iowrite32(val, bridge_base + reg); ++} ++ ++static inline u32 bridge_r32(unsigned reg) ++{ ++ return ioread32(bridge_base + reg); ++} ++ ++static inline void pcie_w32(u32 val, unsigned reg) ++{ ++ iowrite32(val, pcie_base + reg); ++} ++ ++static inline u32 pcie_r32(unsigned reg) ++{ ++ return ioread32(pcie_base + reg); ++} ++ ++static inline void pcie_m32(u32 clr, u32 set, unsigned reg) ++{ ++ u32 val = pcie_r32(reg); ++ val &= ~clr; ++ val |= set; ++ pcie_w32(val, reg); ++} ++ ++int wait_pciephy_busy(void) ++{ ++ unsigned long reg_value = 0x0, retry = 0; ++ ++ while (1) { ++ //reg_value = rareg(READMODE, PCIEPHY0_CFG, 0); ++ reg_value = pcie_r32(PCIEPHY0_CFG); ++ ++ if (reg_value & BUSY) ++ mdelay(100); ++ else ++ break; ++ if (retry++ > WAITRETRY_MAX){ ++ printk("PCIE-PHY retry failed.\n"); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++static void pcie_phy(unsigned long addr, unsigned long val) ++{ ++ wait_pciephy_busy(); ++ pcie_w32(WRITE_MODE | (val << DATA_SHIFT) | (addr << ADDR_SHIFT), PCIEPHY0_CFG); ++ mdelay(1); ++ wait_pciephy_busy(); ++} ++ ++static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) ++{ ++ unsigned int slot = PCI_SLOT(devfn); ++ u8 func = PCI_FUNC(devfn); ++ u32 address; ++ u32 data; ++ ++ address = (((where & 0xF00) >> 8) << 24) | (bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000; ++ bridge_w32(address, RALINK_PCI_CONFIG_ADDR); ++ data = bridge_r32(RALINK_PCI_CONFIG_DATA_VIRTUAL_REG); ++ ++ switch (size) { ++ case 1: ++ *val = (data >> ((where & 3) << 3)) & 0xff; ++ break; ++ case 2: ++ *val = (data >> ((where & 3) << 3)) & 0xffff; ++ break; ++ case 4: ++ *val = data; ++ break; ++ } ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) ++{ ++ unsigned int slot = PCI_SLOT(devfn); ++ u8 func = PCI_FUNC(devfn); ++ u32 address; ++ u32 data; ++ ++ address = (((where & 0xF00) >> 8) << 24) | (bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000; ++ bridge_w32(address, RALINK_PCI_CONFIG_ADDR); ++ data = bridge_r32(RALINK_PCI_CONFIG_DATA_VIRTUAL_REG); ++ ++ switch (size) { ++ case 1: ++ data = (data & ~(0xff << ((where & 3) << 3))) | ++ (val << ((where & 3) << 3)); ++ break; ++ case 2: ++ data = (data & ~(0xffff << ((where & 3) << 3))) | ++ (val << ((where & 3) << 3)); ++ break; ++ case 4: ++ data = val; ++ break; ++ } ++ ++ bridge_w32(data, RALINK_PCI_CONFIG_DATA_VIRTUAL_REG); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++struct pci_ops mt7620a_pci_ops= { ++ .read = pci_config_read, ++ .write = pci_config_write, ++}; ++ ++static struct resource mt7620a_res_pci_mem1 = { ++ .name = "pci memory", ++ .start = RALINK_PCI_MM_MAP_BASE, ++ .end = (u32) ((RALINK_PCI_MM_MAP_BASE + (unsigned char *)0x0fffffff)), ++ .flags = IORESOURCE_MEM, ++}; ++static struct resource mt7620a_res_pci_io1 = { ++ .name = "pci io", ++ .start = RALINK_PCI_IO_MAP_BASE, ++ .end = (u32) ((RALINK_PCI_IO_MAP_BASE + (unsigned char *)0x0ffff)), ++ .flags = IORESOURCE_IO, ++}; ++ ++struct pci_controller mt7620a_controller = { ++ .pci_ops = &mt7620a_pci_ops, ++ .mem_resource = &mt7620a_res_pci_mem1, ++ .io_resource = &mt7620a_res_pci_io1, ++ .mem_offset = 0x00000000UL, ++ .io_offset = 0x00000000UL, ++ .io_map_base = 0xa0000000, ++}; ++ ++static int mt7620a_pci_probe(struct platform_device *pdev) ++{ ++ struct resource *bridge_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ struct resource *pcie_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ ++ rstpcie0 = devm_reset_control_get(&pdev->dev, "pcie0"); ++ if (IS_ERR(rstpcie0)) ++ return PTR_ERR(rstpcie0); ++ ++ bridge_base = devm_request_and_ioremap(&pdev->dev, bridge_res); ++ if (!bridge_base) ++ return -ENOMEM; ++ ++ pcie_base = devm_request_and_ioremap(&pdev->dev, pcie_res); ++ if (!pcie_base) ++ return -ENOMEM; ++ ++ iomem_resource.start = 0; ++ iomem_resource.end= ~0; ++ ioport_resource.start= 0; ++ ioport_resource.end = ~0; ++ ++ /* PCIE: bypass PCIe DLL */ ++ pcie_phy(0x0, 0x80); ++ pcie_phy(0x1, 0x04); ++ /* PCIE: Elastic buffer control */ ++ pcie_phy(0x68, 0xB4); ++ ++ reset_control_assert(rstpcie0); ++ rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1); ++ rt_sysc_m32(1<<19, 1<<31, PPLL_DRV); ++ rt_sysc_m32(0x3 << 16, 0, RALINK_GPIOMODE); ++ ++ reset_control_deassert(rstpcie0); ++ rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1); ++ ++ mdelay(100); ++ ++ if (!(rt_sysc_r32(PPLL_CFG1) & 1<<23)) { ++ printk("MT7620 PPLL unlock\n"); ++ reset_control_assert(rstpcie0); ++ rt_sysc_m32(BIT(26), 0, RALINK_CLKCFG1); ++ return 0; ++ } ++ rt_sysc_m32((0x1<<18) | (0x1<<17), (0x1 << 19) | (0x1 << 31), PPLL_DRV); ++ ++ mdelay(100); ++ reset_control_assert(rstpcie0); ++ rt_sysc_m32(0x30, 2 << 4, RALINK_SYSCFG1); ++ ++ rt_sysc_m32(~0x7fffffff, 0x80000000, RALINK_PCIE_CLK_GEN); ++ rt_sysc_m32(~0x80ffffff, 0xa << 24, RALINK_PCIE_CLK_GEN1); ++ ++ mdelay(50); ++ reset_control_deassert(rstpcie0); ++ pcie_m32(BIT(1), 0, RALINK_PCI_PCICFG_ADDR); ++ mdelay(100); ++ ++ if (( pcie_r32(RALINK_PCI0_STATUS) & 0x1) == 0) { ++ reset_control_assert(rstpcie0); ++ rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1); ++ rt_sysc_m32(LC_CKDRVPD_, PDRV_SW_SET, PPLL_DRV); ++ printk("PCIE0 no card, disable it(RST&CLK)\n"); ++ } ++ ++ bridge_w32(0xffffffff, RALINK_PCI_MEMBASE); ++ bridge_w32(RALINK_PCI_IO_MAP_BASE, RALINK_PCI_IOBASE); ++ ++ pcie_w32(0x7FFF0000, RALINK_PCI0_BAR0SETUP_ADDR); ++ pcie_w32(MEMORY_BASE, RALINK_PCI0_IMBASEBAR0_ADDR); ++ pcie_w32(0x08021814, RALINK_PCI0_ID); ++ pcie_w32(0x06040001, RALINK_PCI0_CLASS); ++ pcie_w32(0x28801814, RALINK_PCI0_SUBID); ++ pcie_m32(0, BIT(20), RALINK_PCI_PCIMSK_ADDR); ++ ++ register_pci_controller(&mt7620a_controller); ++ ++ return 0; ++} ++ ++int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ const struct resource *res; ++ u16 cmd; ++ u32 val; ++ int i, irq = 0; ++ ++ if ((dev->bus->number == 0) && (slot == 0)) { ++ pcie_w32(0x7FFF0001, RALINK_PCI0_BAR0SETUP_ADDR); //open 7FFF:2G; ENABLE ++ pci_config_write(dev->bus, 0, PCI_BASE_ADDRESS_0, 4, MEMORY_BASE); ++ pci_config_read(dev->bus, 0, PCI_BASE_ADDRESS_0, 4, &val); ++ } else if ((dev->bus->number == 1) && (slot == 0x0)) { ++ irq = RALINK_INT_PCIE0; ++ } else { ++ printk("bus=0x%x, slot = 0x%x\n", dev->bus->number, slot); ++ return 0; ++ } ++ ++ for (i = 0; i < 6; i++) { ++ res = &dev->resource[i]; ++ } ++ ++ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14); //configure cache line size 0x14 ++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xFF); //configure latency timer 0x10 ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ ++ // FIXME ++ cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); ++ //pci_write_config_byte(dev, PCI_INTERRUPT_PIN, dev->irq); ++ ++ return irq; ++} ++ ++int pcibios_plat_dev_init(struct pci_dev *dev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id mt7620a_pci_ids[] = { ++ { .compatible = "ralink,mt7620a-pci" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mt7620a_pci_ids); ++ ++static struct platform_driver mt7620a_pci_driver = { ++ .probe = mt7620a_pci_probe, ++ .driver = { ++ .name = "mt7620a-pci", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(mt7620a_pci_ids), ++ }, ++}; ++ ++static int __init mt7620a_pci_init(void) ++{ ++ return platform_driver_register(&mt7620a_pci_driver); ++} ++ ++arch_initcall(mt7620a_pci_init); +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index f2f20ec..f89fdf8 100644 +--- a/arch/mips/ralink/Kconfig ++++ b/arch/mips/ralink/Kconfig +@@ -24,6 +24,7 @@ choice + + config SOC_MT7620 + bool "MT7620" ++ select HW_HAS_PCI + + endchoice + +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0065-watchdog-adds-ralink-wdt.patch b/target/linux/ramips/patches-3.8/0065-watchdog-adds-ralink-wdt.patch new file mode 100644 index 0000000..5d446ee --- /dev/null +++ b/target/linux/ramips/patches-3.8/0065-watchdog-adds-ralink-wdt.patch @@ -0,0 +1,275 @@ +From 8eaa4bef40d38a4954389a2552504ea2d1c4a68a Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 22 Apr 2013 23:23:07 +0200 +Subject: [PATCH 65/79] watchdog: adds ralink wdt + +Adds the watchdog driver for ralink SoC. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/ralink/mt7620.c | 1 + + drivers/watchdog/Kconfig | 7 ++ + drivers/watchdog/Makefile | 1 + + drivers/watchdog/rt2880_wdt.c | 208 +++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 217 insertions(+) + create mode 100644 drivers/watchdog/rt2880_wdt.c + +diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c +index 08c96db6..4956d96 100644 +--- a/arch/mips/ralink/mt7620.c ++++ b/arch/mips/ralink/mt7620.c +@@ -182,6 +182,7 @@ void __init ralink_clk_init(void) + + ralink_clk_add("cpu", cpu_rate); + ralink_clk_add("10000100.timer", 40000000); ++ ralink_clk_add("10000120.watchdog", 40000000); + ralink_clk_add("10000500.uart", 40000000); + ralink_clk_add("10000b00.spi", 40000000); + ralink_clk_add("10000c00.uartlite", 40000000); +diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +index 7f809fd..c8c7454 100644 +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -1076,6 +1076,13 @@ config LANTIQ_WDT + help + Hardware driver for the Lantiq SoC Watchdog Timer. + ++config RALINK_WDT ++ tristate "Ralink SoC watchdog" ++ select WATCHDOG_CORE ++ depends on RALINK ++ help ++ Hardware driver for the Ralink SoC Watchdog Timer. ++ + # PARISC Architecture + + # POWERPC Architecture +diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile +index 97bbdb3a..0203784 100644 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -132,6 +132,7 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o + obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o + octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o + obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o ++obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o + + # PARISC Architecture + +diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c +new file mode 100644 +index 0000000..3df65a4 +--- /dev/null ++++ b/drivers/watchdog/rt2880_wdt.c +@@ -0,0 +1,208 @@ ++/* ++ * Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer ++ * ++ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org> ++ * ++ * This driver was based on: drivers/watchdog/softdog.c ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/reset.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/watchdog.h> ++#include <linux/miscdevice.h> ++#include <linux/moduleparam.h> ++#include <linux/platform_device.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#define SYSC_RSTSTAT 0x38 ++#define WDT_RST_CAUSE BIT(1) ++ ++#define RALINK_WDT_TIMEOUT 30 ++#define RALINK_WDT_PRESCALE 65536 ++ ++#define TIMER_REG_TMR1LOAD 0x00 ++#define TIMER_REG_TMR1CTL 0x08 ++ ++#define TMRSTAT_TMR1RST BIT(5) ++ ++#define TMR1CTL_ENABLE BIT(7) ++#define TMR1CTL_MODE_SHIFT 4 ++#define TMR1CTL_MODE_MASK 0x3 ++#define TMR1CTL_MODE_FREE_RUNNING 0x0 ++#define TMR1CTL_MODE_PERIODIC 0x1 ++#define TMR1CTL_MODE_TIMEOUT 0x2 ++#define TMR1CTL_MODE_WDT 0x3 ++#define TMR1CTL_PRESCALE_MASK 0xf ++#define TMR1CTL_PRESCALE_65536 0xf ++ ++static struct clk *rt288x_wdt_clk; ++static unsigned long rt288x_wdt_freq; ++static void __iomem *rt288x_wdt_base; ++ ++static bool nowayout = WATCHDOG_NOWAYOUT; ++module_param(nowayout, bool, 0); ++MODULE_PARM_DESC(nowayout, ++ "Watchdog cannot be stopped once started (default=" ++ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); ++ ++static inline void rt_wdt_w32(unsigned reg, u32 val) ++{ ++ iowrite32(val, rt288x_wdt_base + reg); ++} ++ ++static inline u32 rt_wdt_r32(unsigned reg) ++{ ++ return ioread32(rt288x_wdt_base + reg); ++} ++ ++static int rt288x_wdt_ping(struct watchdog_device *w) ++{ ++ rt_wdt_w32(TIMER_REG_TMR1LOAD, w->timeout * rt288x_wdt_freq); ++ ++ return 0; ++} ++ ++static int rt288x_wdt_start(struct watchdog_device *w) ++{ ++ u32 t; ++ ++ t = rt_wdt_r32(TIMER_REG_TMR1CTL); ++ t &= ~(TMR1CTL_MODE_MASK << TMR1CTL_MODE_SHIFT | ++ TMR1CTL_PRESCALE_MASK); ++ t |= (TMR1CTL_MODE_WDT << TMR1CTL_MODE_SHIFT | ++ TMR1CTL_PRESCALE_65536); ++ rt_wdt_w32(TIMER_REG_TMR1CTL, t); ++ ++ rt288x_wdt_ping(w); ++ ++ t = rt_wdt_r32(TIMER_REG_TMR1CTL); ++ t |= TMR1CTL_ENABLE; ++ rt_wdt_w32(TIMER_REG_TMR1CTL, t); ++ ++ return 0; ++} ++ ++static int rt288x_wdt_stop(struct watchdog_device *w) ++{ ++ u32 t; ++ ++ rt288x_wdt_ping(w); ++ ++ t = rt_wdt_r32(TIMER_REG_TMR1CTL); ++ t &= ~TMR1CTL_ENABLE; ++ rt_wdt_w32(TIMER_REG_TMR1CTL, t); ++ ++ return 0; ++} ++ ++static int rt288x_wdt_set_timeout(struct watchdog_device *w, unsigned int t) ++{ ++ w->timeout = t; ++ rt288x_wdt_ping(w); ++ ++ return 0; ++} ++ ++static int rt288x_wdt_bootcause(void) ++{ ++ if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE) ++ return WDIOF_CARDRESET; ++ ++ return 0; ++} ++ ++static struct watchdog_info rt288x_wdt_info = { ++ .identity = "Ralink Watchdog", ++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, ++}; ++ ++static struct watchdog_ops rt288x_wdt_ops = { ++ .owner = THIS_MODULE, ++ .start = rt288x_wdt_start, ++ .stop = rt288x_wdt_stop, ++ .ping = rt288x_wdt_ping, ++ .set_timeout = rt288x_wdt_set_timeout, ++}; ++ ++static struct watchdog_device rt288x_wdt_dev = { ++ .info = &rt288x_wdt_info, ++ .ops = &rt288x_wdt_ops, ++ .min_timeout = 1, ++}; ++ ++static int rt288x_wdt_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ int ret; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ rt288x_wdt_base = devm_request_and_ioremap(&pdev->dev, res); ++ if (IS_ERR(rt288x_wdt_base)) ++ return PTR_ERR(rt288x_wdt_base); ++ ++ rt288x_wdt_clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(rt288x_wdt_clk)) ++ return PTR_ERR(rt288x_wdt_clk); ++ ++ device_reset(&pdev->dev); ++ ++ rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE; ++ ++ rt288x_wdt_dev.dev = &pdev->dev; ++ rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); ++ ++ rt288x_wdt_dev.timeout = RALINK_WDT_TIMEOUT; ++ rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); ++ ++ watchdog_set_nowayout(&rt288x_wdt_dev, nowayout); ++ ++ ret = watchdog_register_device(&rt288x_wdt_dev); ++ if (!ret) ++ dev_info(&pdev->dev, "Initialized\n"); ++ ++ return 0; ++} ++ ++static int rt288x_wdt_remove(struct platform_device *pdev) ++{ ++ watchdog_unregister_device(&rt288x_wdt_dev); ++ ++ return 0; ++} ++ ++static void rt288x_wdt_shutdown(struct platform_device *pdev) ++{ ++ rt288x_wdt_stop(&rt288x_wdt_dev); ++} ++ ++static const struct of_device_id rt288x_wdt_match[] = { ++ { .compatible = "ralink,rt2880-wdt" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rt288x_wdt_match); ++ ++static struct platform_driver rt288x_wdt_driver = { ++ .probe = rt288x_wdt_probe, ++ .remove = rt288x_wdt_remove, ++ .shutdown = rt288x_wdt_shutdown, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rt288x_wdt_match, ++ }, ++}; ++ ++module_platform_driver(rt288x_wdt_driver); ++ ++MODULE_DESCRIPTION("MediaTek/Ralink RT288x/RT3xxx hardware watchdog driver"); ++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0066-i2c-MIPS-adds-ralink-I2C-driver.patch b/target/linux/ramips/patches-3.8/0066-i2c-MIPS-adds-ralink-I2C-driver.patch new file mode 100644 index 0000000..286020a --- /dev/null +++ b/target/linux/ramips/patches-3.8/0066-i2c-MIPS-adds-ralink-I2C-driver.patch @@ -0,0 +1,358 @@ +From 68fc18202484e98861ef7eed2a78b64b16c73db9 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 29 Apr 2013 14:40:43 +0200 +Subject: [PATCH 66/79] i2c: MIPS: adds ralink I2C driver + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../devicetree/bindings/i2c/i2c-ralink.txt | 27 ++ + drivers/i2c/busses/Kconfig | 4 + + drivers/i2c/busses/Makefile | 1 + + drivers/i2c/busses/i2c-ralink.c | 274 ++++++++++++++++++++ + 4 files changed, 306 insertions(+) + create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ralink.txt + create mode 100644 drivers/i2c/busses/i2c-ralink.c + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-ralink.txt b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt +new file mode 100644 +index 0000000..8fa8ac3 +--- /dev/null ++++ b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt +@@ -0,0 +1,27 @@ ++I2C for Ralink platforms ++ ++Required properties : ++- compatible : Must be "link,rt3052-i2c" ++- reg: physical base address of the controller and length of memory mapped ++ region. ++- #address-cells = <1>; ++- #size-cells = <0>; ++ ++Optional properties: ++- Child nodes conforming to i2c bus binding ++ ++Example : ++ ++palmbus@10000000 { ++ i2c@900 { ++ compatible = "link,rt3052-i2c"; ++ reg = <0x900 0x100>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hwmon@4b { ++ compatible = "national,lm92"; ++ reg = <0x4b>; ++ }; ++ }; ++}; +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index bdca511..19b1105 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -604,6 +604,10 @@ config I2C_PXA_SLAVE + is necessary for systems where the PXA may be a target on the + I2C bus. + ++config I2C_RALINK ++ tristate "Ralink I2C Controller" ++ select OF_I2C ++ + config HAVE_S3C2410_I2C + bool + help +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index 6181f3f..4cf4a88 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -60,6 +60,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o + obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o + obj-$(CONFIG_I2C_PXA) += i2c-pxa.o + obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o ++obj-$(CONFIG_I2C_RALINK) += i2c-ralink.o + obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o + obj-$(CONFIG_I2C_S6000) += i2c-s6000.o + obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o +diff --git a/drivers/i2c/busses/i2c-ralink.c b/drivers/i2c/busses/i2c-ralink.c +new file mode 100644 +index 0000000..b5abf0f +--- /dev/null ++++ b/drivers/i2c/busses/i2c-ralink.c +@@ -0,0 +1,274 @@ ++/* ++ * drivers/i2c/busses/i2c-ralink.c ++ * ++ * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com> ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include <linux/interrupt.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/reset.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/platform_device.h> ++#include <linux/i2c.h> ++#include <linux/io.h> ++#include <linux/of_i2c.h> ++#include <linux/err.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#define REG_CONFIG_REG 0x00 ++#define REG_CLKDIV_REG 0x04 ++#define REG_DEVADDR_REG 0x08 ++#define REG_ADDR_REG 0x0C ++#define REG_DATAOUT_REG 0x10 ++#define REG_DATAIN_REG 0x14 ++#define REG_STATUS_REG 0x18 ++#define REG_STARTXFR_REG 0x1C ++#define REG_BYTECNT_REG 0x20 ++ ++#define I2C_STARTERR BIT(4) ++#define I2C_ACKERR BIT(3) ++#define I2C_DATARDY BIT(2) ++#define I2C_SDOEMPTY BIT(1) ++#define I2C_BUSY BIT(0) ++ ++#define I2C_DEVADLEN_7 (6 << 2) ++#define I2C_ADDRDIS BIT(1) ++ ++#define I2C_RETRY 0x400 ++ ++#define CLKDIV_VALUE 600 ++ ++#define READ_CMD 0x01 ++#define WRITE_CMD 0x00 ++#define READ_BLOCK 64 ++ ++static void __iomem *membase; ++static struct i2c_adapter *adapter; ++ ++static void rt_i2c_w32(u32 val, unsigned reg) ++{ ++ iowrite32(val, membase + reg); ++} ++ ++static u32 rt_i2c_r32(unsigned reg) ++{ ++ return ioread32(membase + reg); ++} ++ ++static inline int rt_i2c_wait_rx_done(void) ++{ ++ int retries = I2C_RETRY; ++ ++ do { ++ if (!retries--) ++ break; ++ } while(!(rt_i2c_r32(REG_STATUS_REG) & I2C_DATARDY)); ++ ++ return (retries < 0); ++} ++ ++static inline int rt_i2c_wait_idle(void) ++{ ++ int retries = I2C_RETRY; ++ ++ do { ++ if (!retries--) ++ break; ++ } while(rt_i2c_r32(REG_STATUS_REG) & I2C_BUSY); ++ ++ return (retries < 0); ++} ++ ++static inline int rt_i2c_wait_tx_done(void) ++{ ++ int retries = I2C_RETRY; ++ ++ do { ++ if (!retries--) ++ break; ++ } while(!(rt_i2c_r32(REG_STATUS_REG) & I2C_SDOEMPTY)); ++ ++ return (retries < 0); ++} ++ ++static int rt_i2c_handle_msg(struct i2c_adapter *a, struct i2c_msg* msg) ++{ ++ int i = 0, j = 0, pos = 0; ++ int nblock = msg->len / READ_BLOCK; ++ int rem = msg->len % READ_BLOCK; ++ ++ if (msg->flags & I2C_M_TEN) { ++ printk("10 bits addr not supported\n"); ++ return -EINVAL; ++ } ++ ++ if (msg->flags & I2C_M_RD) { ++ for (i = 0; i < nblock; i++) { ++ rt_i2c_wait_idle(); ++ rt_i2c_w32(READ_BLOCK - 1, REG_BYTECNT_REG); ++ rt_i2c_w32(READ_CMD, REG_STARTXFR_REG); ++ for (j = 0; j < READ_BLOCK; j++) { ++ if (rt_i2c_wait_rx_done()) ++ return -1; ++ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); ++ } ++ } ++ ++ rt_i2c_wait_idle(); ++ rt_i2c_w32(rem - 1, REG_BYTECNT_REG); ++ rt_i2c_w32(READ_CMD, REG_STARTXFR_REG); ++ for (i = 0; i < rem; i++) { ++ if (rt_i2c_wait_rx_done()) ++ return -1; ++ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); ++ } ++ } else { ++ rt_i2c_wait_idle(); ++ rt_i2c_w32(msg->len - 1, REG_BYTECNT_REG); ++ rt_i2c_w32(msg->buf[0], REG_DATAOUT_REG); ++ rt_i2c_w32(WRITE_CMD, REG_STARTXFR_REG); ++ for (i = 1; i < msg->len; i++) { ++ rt_i2c_w32(msg->buf[i], REG_DATAOUT_REG); ++ if (rt_i2c_wait_tx_done()) ++ return -1; ++ } ++ } ++ ++ return msg->len; ++} ++ ++static int rt_i2c_master_xfer(struct i2c_adapter *a, struct i2c_msg *m, int n) ++{ ++ int i = 0; ++ int ret = 0; ++ ++ if (rt_i2c_wait_idle()) { ++ printk("i2c transfer failed\n"); ++ return 0; ++ } ++ ++ device_reset(a->dev.parent); ++ ++ rt_i2c_w32(m->addr, REG_DEVADDR_REG); ++ rt_i2c_w32(I2C_DEVADLEN_7 | I2C_ADDRDIS, REG_CONFIG_REG); ++ rt_i2c_w32(CLKDIV_VALUE, REG_CLKDIV_REG); ++ ++ for (i = 0; i < n && !ret; i++) ++ ret = rt_i2c_handle_msg(a, &m[i]); ++ ++ if (ret) { ++ printk("i2c transfer failed\n"); ++ return 0; ++ } ++ ++ return n; ++} ++ ++static u32 rt_i2c_func(struct i2c_adapter *a) ++{ ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; ++} ++ ++static const struct i2c_algorithm rt_i2c_algo = { ++ .master_xfer = rt_i2c_master_xfer, ++ .functionality = rt_i2c_func, ++}; ++ ++static int rt_i2c_probe(struct platform_device *pdev) ++{ ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ int ret; ++ ++ if (!res) { ++ dev_err(&pdev->dev, "no memory resource found\n"); ++ return -ENODEV; ++ } ++ ++ adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter), GFP_KERNEL); ++ if (!adapter) { ++ dev_err(&pdev->dev, "failed to allocate i2c_adapter\n"); ++ return -ENOMEM; ++ } ++ ++ membase = devm_request_and_ioremap(&pdev->dev, res); ++ if (IS_ERR(membase)) ++ return PTR_ERR(membase); ++ ++ strlcpy(adapter->name, dev_name(&pdev->dev), sizeof(adapter->name)); ++ adapter->owner = THIS_MODULE; ++ adapter->nr = pdev->id; ++ adapter->timeout = HZ; ++ adapter->algo = &rt_i2c_algo; ++ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; ++ adapter->dev.parent = &pdev->dev; ++ adapter->dev.of_node = pdev->dev.of_node; ++ ++ ret = i2c_add_numbered_adapter(adapter); ++ if (ret) ++ return ret; ++ ++ of_i2c_register_devices(adapter); ++ ++ platform_set_drvdata(pdev, adapter); ++ ++ dev_info(&pdev->dev, "loaded\n"); ++ ++ return 0; ++} ++ ++static int rt_i2c_remove(struct platform_device *pdev) ++{ ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++static const struct of_device_id i2c_rt_dt_ids[] = { ++ { .compatible = "ralink,rt2880-i2c", }, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids); ++ ++static struct platform_driver rt_i2c_driver = { ++ .probe = rt_i2c_probe, ++ .remove = rt_i2c_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "i2c-ralink", ++ .of_match_table = i2c_rt_dt_ids, ++ }, ++}; ++ ++static int __init i2c_rt_init (void) ++{ ++ return platform_driver_register(&rt_i2c_driver); ++} ++subsys_initcall(i2c_rt_init); ++ ++static void __exit i2c_rt_exit (void) ++{ ++ platform_driver_unregister(&rt_i2c_driver); ++} ++ ++module_exit (i2c_rt_exit); ++ ++MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>"); ++MODULE_DESCRIPTION("Ralink I2c host driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:Ralink-I2C"); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0067-reset-Add-reset-controller-API.patch b/target/linux/ramips/patches-3.8/0067-reset-Add-reset-controller-API.patch new file mode 100644 index 0000000..55bbb56 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0067-reset-Add-reset-controller-API.patch @@ -0,0 +1,554 @@ +From 8951e08252c6c254d68c350468c40f88a12bcc1d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Mon, 20 May 2013 15:42:01 +0200 +Subject: [PATCH 67/79] reset: Add reset controller API + +backport from v3.10-rc1 +61fc41317666be400802ac793f47de816ef7bd57 +6034bb22d8387708075c083385e5d2e1072a4f33 +4e11f848c65b1c87782cb232a6e3b47a9d4c1f98 + +This adds a simple API for devices to request being reset +by separate reset controller hardware and implements the +reset signal device tree binding. + +Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> +Reviewed-by: Stephen Warren <swarren@nvidia.com> +Reviewed-by: Shawn Guo <shawn.guo@linaro.org> +Reviewed-by: Marek Vasut <marex@denx.de> +Reviewed-by: Pavel Machek <pavel@ucw.cz> +--- + Documentation/devicetree/bindings/reset/reset.txt | 75 ++++++ + drivers/Kconfig | 2 + + drivers/Makefile | 3 + + drivers/reset/Kconfig | 13 + + drivers/reset/Makefile | 1 + + drivers/reset/core.c | 297 +++++++++++++++++++++ + include/linux/reset-controller.h | 51 ++++ + include/linux/reset.h | 17 ++ + 8 files changed, 459 insertions(+) + create mode 100644 Documentation/devicetree/bindings/reset/reset.txt + create mode 100644 drivers/reset/Kconfig + create mode 100644 drivers/reset/Makefile + create mode 100644 drivers/reset/core.c + create mode 100644 include/linux/reset-controller.h + create mode 100644 include/linux/reset.h + +diff --git a/Documentation/devicetree/bindings/reset/reset.txt b/Documentation/devicetree/bindings/reset/reset.txt +new file mode 100644 +index 0000000..31db6ff +--- /dev/null ++++ b/Documentation/devicetree/bindings/reset/reset.txt +@@ -0,0 +1,75 @@ ++= Reset Signal Device Tree Bindings = ++ ++This binding is intended to represent the hardware reset signals present ++internally in most IC (SoC, FPGA, ...) designs. Reset signals for whole ++standalone chips are most likely better represented as GPIOs, although there ++are likely to be exceptions to this rule. ++ ++Hardware blocks typically receive a reset signal. This signal is generated by ++a reset provider (e.g. power management or clock module) and received by a ++reset consumer (the module being reset, or a module managing when a sub- ++ordinate module is reset). This binding exists to represent the provider and ++consumer, and provide a way to couple the two together. ++ ++A reset signal is represented by the phandle of the provider, plus a reset ++specifier - a list of DT cells that represents the reset signal within the ++provider. The length (number of cells) and semantics of the reset specifier ++are dictated by the binding of the reset provider, although common schemes ++are described below. ++ ++A word on where to place reset signal consumers in device tree: It is possible ++in hardware for a reset signal to affect multiple logically separate HW blocks ++at once. In this case, it would be unwise to represent this reset signal in ++the DT node of each affected HW block, since if activated, an unrelated block ++may be reset. Instead, reset signals should be represented in the DT node ++where it makes most sense to control it; this may be a bus node if all ++children of the bus are affected by the reset signal, or an individual HW ++block node for dedicated reset signals. The intent of this binding is to give ++appropriate software access to the reset signals in order to manage the HW, ++rather than to slavishly enumerate the reset signal that affects each HW ++block. ++ ++= Reset providers = ++ ++Required properties: ++#reset-cells: Number of cells in a reset specifier; Typically 0 for nodes ++ with a single reset output and 1 for nodes with multiple ++ reset outputs. ++ ++For example: ++ ++ rst: reset-controller { ++ #reset-cells = <1>; ++ }; ++ ++= Reset consumers = ++ ++Required properties: ++resets: List of phandle and reset specifier pairs, one pair ++ for each reset signal that affects the device, or that the ++ device manages. Note: if the reset provider specifies '0' for ++ #reset-cells, then only the phandle portion of the pair will ++ appear. ++ ++Optional properties: ++reset-names: List of reset signal name strings sorted in the same order as ++ the resets property. Consumers drivers will use reset-names to ++ match reset signal names with reset specifiers. ++ ++For example: ++ ++ device { ++ resets = <&rst 20>; ++ reset-names = "reset"; ++ }; ++ ++This represents a device with a single reset signal named "reset". ++ ++ bus { ++ resets = <&rst 10> <&rst 11> <&rst 12> <&rst 11>; ++ reset-names = "i2s1", "i2s2", "dma", "mixer"; ++ }; ++ ++This represents a bus that controls the reset signal of each of four sub- ++ordinate devices. Consider for example a bus that fails to operate unless no ++child device has reset asserted. +diff --git a/drivers/Kconfig b/drivers/Kconfig +index f5fb072..51f73ae 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -158,4 +158,6 @@ source "drivers/irqchip/Kconfig" + + source "drivers/ipack/Kconfig" + ++source "drivers/reset/Kconfig" ++ + endmenu +diff --git a/drivers/Makefile b/drivers/Makefile +index 7863b9f..2819ac0 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -37,6 +37,9 @@ obj-$(CONFIG_XEN) += xen/ + # regulators early, since some subsystems rely on them to initialize + obj-$(CONFIG_REGULATOR) += regulator/ + ++# reset controllers early, since gpu drivers might rely on them to initialize ++obj-$(CONFIG_RESET_CONTROLLER) += reset/ ++ + # tty/ comes before char/ so that the VT console is the boot-time + # default. + obj-y += tty/ +diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig +new file mode 100644 +index 0000000..c9d04f7 +--- /dev/null ++++ b/drivers/reset/Kconfig +@@ -0,0 +1,13 @@ ++config ARCH_HAS_RESET_CONTROLLER ++ bool ++ ++menuconfig RESET_CONTROLLER ++ bool "Reset Controller Support" ++ default y if ARCH_HAS_RESET_CONTROLLER ++ help ++ Generic Reset Controller support. ++ ++ This framework is designed to abstract reset handling of devices ++ via GPIOs or SoC-internal reset controller modules. ++ ++ If unsure, say no. +diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile +new file mode 100644 +index 0000000..1e2d83f +--- /dev/null ++++ b/drivers/reset/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_RESET_CONTROLLER) += core.o +diff --git a/drivers/reset/core.c b/drivers/reset/core.c +new file mode 100644 +index 0000000..d1b6089 +--- /dev/null ++++ b/drivers/reset/core.c +@@ -0,0 +1,297 @@ ++/* ++ * Reset Controller framework ++ * ++ * Copyright 2013 Philipp Zabel, Pengutronix ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++#include <linux/device.h> ++#include <linux/err.h> ++#include <linux/export.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/reset.h> ++#include <linux/reset-controller.h> ++#include <linux/slab.h> ++ ++static DEFINE_MUTEX(reset_controller_list_mutex); ++static LIST_HEAD(reset_controller_list); ++ ++/** ++ * struct reset_control - a reset control ++ * @rcdev: a pointer to the reset controller device ++ * this reset control belongs to ++ * @id: ID of the reset controller in the reset ++ * controller device ++ */ ++struct reset_control { ++ struct reset_controller_dev *rcdev; ++ struct device *dev; ++ unsigned int id; ++}; ++ ++/** ++ * of_reset_simple_xlate - translate reset_spec to the reset line number ++ * @rcdev: a pointer to the reset controller device ++ * @reset_spec: reset line specifier as found in the device tree ++ * @flags: a flags pointer to fill in (optional) ++ * ++ * This simple translation function should be used for reset controllers ++ * with 1:1 mapping, where reset lines can be indexed by number without gaps. ++ */ ++int of_reset_simple_xlate(struct reset_controller_dev *rcdev, ++ const struct of_phandle_args *reset_spec) ++{ ++ if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) ++ return -EINVAL; ++ ++ if (reset_spec->args[0] >= rcdev->nr_resets) ++ return -EINVAL; ++ ++ return reset_spec->args[0]; ++} ++EXPORT_SYMBOL_GPL(of_reset_simple_xlate); ++ ++/** ++ * reset_controller_register - register a reset controller device ++ * @rcdev: a pointer to the initialized reset controller device ++ */ ++int reset_controller_register(struct reset_controller_dev *rcdev) ++{ ++ if (!rcdev->of_xlate) { ++ rcdev->of_reset_n_cells = 1; ++ rcdev->of_xlate = of_reset_simple_xlate; ++ } ++ ++ mutex_lock(&reset_controller_list_mutex); ++ list_add(&rcdev->list, &reset_controller_list); ++ mutex_unlock(&reset_controller_list_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(reset_controller_register); ++ ++/** ++ * reset_controller_unregister - unregister a reset controller device ++ * @rcdev: a pointer to the reset controller device ++ */ ++void reset_controller_unregister(struct reset_controller_dev *rcdev) ++{ ++ mutex_lock(&reset_controller_list_mutex); ++ list_del(&rcdev->list); ++ mutex_unlock(&reset_controller_list_mutex); ++} ++EXPORT_SYMBOL_GPL(reset_controller_unregister); ++ ++/** ++ * reset_control_reset - reset the controlled device ++ * @rstc: reset controller ++ */ ++int reset_control_reset(struct reset_control *rstc) ++{ ++ if (rstc->rcdev->ops->reset) ++ return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); ++ ++ return -ENOSYS; ++} ++EXPORT_SYMBOL_GPL(reset_control_reset); ++ ++/** ++ * reset_control_assert - asserts the reset line ++ * @rstc: reset controller ++ */ ++int reset_control_assert(struct reset_control *rstc) ++{ ++ if (rstc->rcdev->ops->assert) ++ return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id); ++ ++ return -ENOSYS; ++} ++EXPORT_SYMBOL_GPL(reset_control_assert); ++ ++/** ++ * reset_control_deassert - deasserts the reset line ++ * @rstc: reset controller ++ */ ++int reset_control_deassert(struct reset_control *rstc) ++{ ++ if (rstc->rcdev->ops->deassert) ++ return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id); ++ ++ return -ENOSYS; ++} ++EXPORT_SYMBOL_GPL(reset_control_deassert); ++ ++/** ++ * reset_control_get - Lookup and obtain a reference to a reset controller. ++ * @dev: device to be reset by the controller ++ * @id: reset line name ++ * ++ * Returns a struct reset_control or IS_ERR() condition containing errno. ++ * ++ * Use of id names is optional. ++ */ ++struct reset_control *reset_control_get(struct device *dev, const char *id) ++{ ++ struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER); ++ struct reset_controller_dev *r, *rcdev; ++ struct of_phandle_args args; ++ int index = 0; ++ int rstc_id; ++ int ret; ++ ++ if (!dev) ++ return ERR_PTR(-EINVAL); ++ ++ if (id) ++ index = of_property_match_string(dev->of_node, ++ "reset-names", id); ++ ret = of_parse_phandle_with_args(dev->of_node, "resets", "#reset-cells", ++ index, &args); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ mutex_lock(&reset_controller_list_mutex); ++ rcdev = NULL; ++ list_for_each_entry(r, &reset_controller_list, list) { ++ if (args.np == r->of_node) { ++ rcdev = r; ++ break; ++ } ++ } ++ of_node_put(args.np); ++ ++ if (!rcdev) { ++ mutex_unlock(&reset_controller_list_mutex); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ rstc_id = rcdev->of_xlate(rcdev, &args); ++ if (rstc_id < 0) { ++ mutex_unlock(&reset_controller_list_mutex); ++ return ERR_PTR(rstc_id); ++ } ++ ++ try_module_get(rcdev->owner); ++ mutex_unlock(&reset_controller_list_mutex); ++ ++ rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); ++ if (!rstc) { ++ module_put(rcdev->owner); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ rstc->dev = dev; ++ rstc->rcdev = rcdev; ++ rstc->id = rstc_id; ++ ++ return rstc; ++} ++EXPORT_SYMBOL_GPL(reset_control_get); ++ ++/** ++ * reset_control_put - free the reset controller ++ * @rstc: reset controller ++ */ ++ ++void reset_control_put(struct reset_control *rstc) ++{ ++ if (IS_ERR(rstc)) ++ return; ++ ++ module_put(rstc->rcdev->owner); ++ kfree(rstc); ++} ++EXPORT_SYMBOL_GPL(reset_control_put); ++ ++static void devm_reset_control_release(struct device *dev, void *res) ++{ ++ reset_control_put(*(struct reset_control **)res); ++} ++ ++/** ++ * devm_reset_control_get - resource managed reset_control_get() ++ * @dev: device to be reset by the controller ++ * @id: reset line name ++ * ++ * Managed reset_control_get(). For reset controllers returned from this ++ * function, reset_control_put() is called automatically on driver detach. ++ * See reset_control_get() for more information. ++ */ ++struct reset_control *devm_reset_control_get(struct device *dev, const char *id) ++{ ++ struct reset_control **ptr, *rstc; ++ ++ ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr), ++ GFP_KERNEL); ++ if (!ptr) ++ return ERR_PTR(-ENOMEM); ++ ++ rstc = reset_control_get(dev, id); ++ if (!IS_ERR(rstc)) { ++ *ptr = rstc; ++ devres_add(dev, ptr); ++ } else { ++ devres_free(ptr); ++ } ++ ++ return rstc; ++} ++EXPORT_SYMBOL_GPL(devm_reset_control_get); ++ ++static int devm_reset_control_match(struct device *dev, void *res, void *data) ++{ ++ struct reset_control **rstc = res; ++ if (WARN_ON(!rstc || !*rstc)) ++ return 0; ++ return *rstc == data; ++} ++ ++/** ++ * devm_reset_control_put - resource managed reset_control_put() ++ * @rstc: reset controller to free ++ * ++ * Deallocate a reset control allocated withd devm_reset_control_get(). ++ * This function will not need to be called normally, as devres will take ++ * care of freeing the resource. ++ */ ++void devm_reset_control_put(struct reset_control *rstc) ++{ ++ int ret; ++ ++ ret = devres_release(rstc->dev, devm_reset_control_release, ++ devm_reset_control_match, rstc); ++ if (ret) ++ WARN_ON(ret); ++} ++EXPORT_SYMBOL_GPL(devm_reset_control_put); ++ ++/** ++ * device_reset - find reset controller associated with the device ++ * and perform reset ++ * @dev: device to be reset by the controller ++ * ++ * Convenience wrapper for reset_control_get() and reset_control_reset(). ++ * This is useful for the common case of devices with single, dedicated reset ++ * lines. ++ */ ++int device_reset(struct device *dev) ++{ ++ struct reset_control *rstc; ++ int ret; ++ ++ rstc = reset_control_get(dev, NULL); ++ if (IS_ERR(rstc)) ++ return PTR_ERR(rstc); ++ ++ ret = reset_control_reset(rstc); ++ ++ reset_control_put(rstc); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(device_reset); +diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h +new file mode 100644 +index 0000000..2f61311 +--- /dev/null ++++ b/include/linux/reset-controller.h +@@ -0,0 +1,51 @@ ++#ifndef _LINUX_RESET_CONTROLLER_H_ ++#define _LINUX_RESET_CONTROLLER_H_ ++ ++#include <linux/list.h> ++ ++struct reset_controller_dev; ++ ++/** ++ * struct reset_control_ops ++ * ++ * @reset: for self-deasserting resets, does all necessary ++ * things to reset the device ++ * @assert: manually assert the reset line, if supported ++ * @deassert: manually deassert the reset line, if supported ++ */ ++struct reset_control_ops { ++ int (*reset)(struct reset_controller_dev *rcdev, unsigned long id); ++ int (*assert)(struct reset_controller_dev *rcdev, unsigned long id); ++ int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id); ++}; ++ ++struct module; ++struct device_node; ++ ++/** ++ * struct reset_controller_dev - reset controller entity that might ++ * provide multiple reset controls ++ * @ops: a pointer to device specific struct reset_control_ops ++ * @owner: kernel module of the reset controller driver ++ * @list: internal list of reset controller devices ++ * @of_node: corresponding device tree node as phandle target ++ * @of_reset_n_cells: number of cells in reset line specifiers ++ * @of_xlate: translation function to translate from specifier as found in the ++ * device tree to id as given to the reset control ops ++ * @nr_resets: number of reset controls in this reset controller device ++ */ ++struct reset_controller_dev { ++ struct reset_control_ops *ops; ++ struct module *owner; ++ struct list_head list; ++ struct device_node *of_node; ++ int of_reset_n_cells; ++ int (*of_xlate)(struct reset_controller_dev *rcdev, ++ const struct of_phandle_args *reset_spec); ++ unsigned int nr_resets; ++}; ++ ++int reset_controller_register(struct reset_controller_dev *rcdev); ++void reset_controller_unregister(struct reset_controller_dev *rcdev); ++ ++#endif +diff --git a/include/linux/reset.h b/include/linux/reset.h +new file mode 100644 +index 0000000..6082247 +--- /dev/null ++++ b/include/linux/reset.h +@@ -0,0 +1,17 @@ ++#ifndef _LINUX_RESET_H_ ++#define _LINUX_RESET_H_ ++ ++struct device; ++struct reset_control; ++ ++int reset_control_reset(struct reset_control *rstc); ++int reset_control_assert(struct reset_control *rstc); ++int reset_control_deassert(struct reset_control *rstc); ++ ++struct reset_control *reset_control_get(struct device *dev, const char *id); ++void reset_control_put(struct reset_control *rstc); ++struct reset_control *devm_reset_control_get(struct device *dev, const char *id); ++ ++int device_reset(struct device *dev); ++ ++#endif +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0068-reset-MIPS-ralink-add-core-device-reset-wrapper.patch b/target/linux/ramips/patches-3.8/0068-reset-MIPS-ralink-add-core-device-reset-wrapper.patch new file mode 100644 index 0000000..29a0991 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0068-reset-MIPS-ralink-add-core-device-reset-wrapper.patch @@ -0,0 +1,135 @@ +From 42c26796ae7bcfe0b33a4145de5a392e32bc9bac Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 8 May 2013 22:08:39 +0200 +Subject: [PATCH 68/79] reset: MIPS: ralink: add core/device reset wrapper + +Add a helper for reseting different devices ont he SoC. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/Kconfig | 1 + + arch/mips/ralink/of.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++ + arch/mips/ralink/reset.c | 1 + + 3 files changed, 61 insertions(+) + +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 2498972..ef5272f 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -450,6 +450,7 @@ config RALINK + select HAVE_MACH_CLKDEV + select CLKDEV_LOOKUP + select ARCH_REQUIRE_GPIOLIB ++ select ARCH_HAS_RESET_CONTROLLER + + config SGI_IP22 + bool "SGI IP22 (Indy/Indigo2)" +diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c +index 8efb02b..2faf478 100644 +--- a/arch/mips/ralink/of.c ++++ b/arch/mips/ralink/of.c +@@ -14,16 +14,22 @@ + #include <linux/sizes.h> + #include <linux/of_fdt.h> + #include <linux/kernel.h> ++#include <linux/module.h> + #include <linux/bootmem.h> + #include <linux/of_platform.h> + #include <linux/of_address.h> ++#include <linux/reset-controller.h> + + #include <asm/reboot.h> + #include <asm/bootinfo.h> + #include <asm/addrspace.h> + ++#include <asm/mach-ralink/ralink_regs.h> ++ + #include "common.h" + ++#define SYSC_REG_RESET_CTRL 0x034 ++ + __iomem void *rt_sysc_membase; + __iomem void *rt_memc_membase; + +@@ -96,6 +102,53 @@ void __init plat_mem_setup(void) + soc_info.mem_size_max * SZ_1M); + } + ++static int ralink_assert_device(struct reset_controller_dev *rcdev, unsigned long id) ++{ ++ u32 val; ++ ++ if (id < 8) ++ return -1; ++ ++ val = rt_sysc_r32(SYSC_REG_RESET_CTRL); ++ val |= BIT(id); ++ rt_sysc_w32(val, SYSC_REG_RESET_CTRL); ++ ++ return 0; ++} ++ ++static int ralink_deassert_device(struct reset_controller_dev *rcdev, unsigned long id) ++{ ++ u32 val; ++ ++ if (id < 8) ++ return -1; ++ ++ val = rt_sysc_r32(SYSC_REG_RESET_CTRL); ++ val &= ~BIT(id); ++ rt_sysc_w32(val, SYSC_REG_RESET_CTRL); ++ ++ return 0; ++} ++ ++static int ralink_reset_device(struct reset_controller_dev *rcdev, unsigned long id) ++{ ++ ralink_assert_device(rcdev, id); ++ return ralink_deassert_device(rcdev, id); ++} ++ ++static struct reset_control_ops reset_ops = { ++ .reset = ralink_reset_device, ++ .assert = ralink_assert_device, ++ .deassert = ralink_deassert_device, ++}; ++ ++static struct reset_controller_dev reset_dev = { ++ .ops = &reset_ops, ++ .owner = THIS_MODULE, ++ .nr_resets = 32, ++ .of_reset_n_cells = 1, ++}; ++ + static int __init plat_of_setup(void) + { + static struct of_device_id of_ids[3]; +@@ -110,6 +163,12 @@ static int __init plat_of_setup(void) + if (of_platform_populate(NULL, of_ids, NULL, NULL)) + panic("failed to populate DT\n"); + ++ reset_dev.of_node = of_find_compatible_node(NULL, NULL, "ralink,rt2880-reset"); ++ if (!reset_dev.of_node) ++ panic("Failed to find reset controller node"); ++ ++ reset_controller_register(&reset_dev); ++ + ralink_pinmux(); + + return 0; +diff --git a/arch/mips/ralink/reset.c b/arch/mips/ralink/reset.c +index 22120e5..6c15f4f 100644 +--- a/arch/mips/ralink/reset.c ++++ b/arch/mips/ralink/reset.c +@@ -10,6 +10,7 @@ + + #include <linux/pm.h> + #include <linux/io.h> ++#include <linux/module.h> + + #include <asm/reboot.h> + +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0201-owrt-OF-NET-add-of_get_mac_address_mtd.patch b/target/linux/ramips/patches-3.8/0069-NET-add-of_get_mac_address_mtd.patch index b7c79ab..6efccf0 100644 --- a/target/linux/ramips/patches-3.8/0201-owrt-OF-NET-add-of_get_mac_address_mtd.patch +++ b/target/linux/ramips/patches-3.8/0069-NET-add-of_get_mac_address_mtd.patch @@ -1,7 +1,7 @@ -From 1809af0f73208ec67363347ddf5370e1f08222e8 Mon Sep 17 00:00:00 2001 +From d30d4c01d2b97eed1fc109819b9c8747343ff4d7 Mon Sep 17 00:00:00 2001 From: John Crispin <blogic@openwrt.org> Date: Sun, 17 Mar 2013 09:29:15 +0100 -Subject: [PATCH 201/208] owrt: OF: NET: add of_get_mac_address_mtd() +Subject: [PATCH 69/79] NET: add of_get_mac_address_mtd() Many embedded devices have information such as mac addresses stored inside mtd devices. This patch allows us to add a property inside a node describing a @@ -14,6 +14,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> include/linux/of_net.h | 1 + 2 files changed, 38 insertions(+) +diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c +index ffab033..15f4a71 100644 --- a/drivers/of/of_net.c +++ b/drivers/of/of_net.c @@ -10,6 +10,7 @@ @@ -24,7 +26,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> /** * It maps 'enum phy_interface_t' found in include/linux/phy.h -@@ -92,3 +93,39 @@ const void *of_get_mac_address(struct de +@@ -92,3 +93,39 @@ const void *of_get_mac_address(struct device_node *np) return NULL; } EXPORT_SYMBOL(of_get_mac_address); @@ -64,6 +66,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + return ret; +} +EXPORT_SYMBOL_GPL(of_get_mac_address_mtd); +diff --git a/include/linux/of_net.h b/include/linux/of_net.h +index f474641..9d3304f 100644 --- a/include/linux/of_net.h +++ b/include/linux/of_net.h @@ -11,6 +11,7 @@ @@ -74,3 +78,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org> #endif #endif /* __LINUX_OF_NET_H */ +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0070-NET-multi-phy-support.patch b/target/linux/ramips/patches-3.8/0070-NET-multi-phy-support.patch new file mode 100644 index 0000000..4e8fbda --- /dev/null +++ b/target/linux/ramips/patches-3.8/0070-NET-multi-phy-support.patch @@ -0,0 +1,61 @@ +From c00adb2a1ac75eaef1e71cd9819636b86eabebd9 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sat, 11 May 2013 23:40:19 +0200 +Subject: [PATCH 70/79] NET: multi phy support + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + drivers/net/phy/phy.c | 9 ++++++--- + include/linux/phy.h | 2 +- + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c +index ef9ea92..27f9b45 100644 +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -800,7 +800,8 @@ void phy_state_machine(struct work_struct *work) + * negotiation for now */ + if (!phydev->link) { + phydev->state = PHY_NOLINK; +- netif_carrier_off(phydev->attached_dev); ++ if (!phydev->no_auto_carrier_off) ++ netif_carrier_off(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + break; + } +@@ -891,7 +892,8 @@ void phy_state_machine(struct work_struct *work) + netif_carrier_on(phydev->attached_dev); + } else { + phydev->state = PHY_NOLINK; +- netif_carrier_off(phydev->attached_dev); ++ if (!phydev->no_auto_carrier_off) ++ netif_carrier_off(phydev->attached_dev); + } + + phydev->adjust_link(phydev->attached_dev); +@@ -903,7 +905,8 @@ void phy_state_machine(struct work_struct *work) + case PHY_HALTED: + if (phydev->link) { + phydev->link = 0; +- netif_carrier_off(phydev->attached_dev); ++ if (!phydev->no_auto_carrier_off) ++ netif_carrier_off(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + } + break; +diff --git a/include/linux/phy.h b/include/linux/phy.h +index 93b3cf7..c09b4ad 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -298,7 +298,7 @@ struct phy_device { + + struct phy_c45_device_ids c45_ids; + bool is_c45; +- ++ bool no_auto_carrier_off; + enum phy_state state; + + u32 dev_flags; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0072-NET-MIPS-add-ralink-SoC-ethernet-driver.patch b/target/linux/ramips/patches-3.8/0072-NET-MIPS-add-ralink-SoC-ethernet-driver.patch new file mode 100644 index 0000000..5e35b5b --- /dev/null +++ b/target/linux/ramips/patches-3.8/0072-NET-MIPS-add-ralink-SoC-ethernet-driver.patch @@ -0,0 +1,4732 @@ +From 34564578e57bd2bffddbd5f463c55db4a220f2a0 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 20 Jun 2013 18:52:00 +0200 +Subject: [PATCH 72/79] NET: MIPS: add ralink SoC ethernet driver + +Add support for Ralink FE and ESW. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + .../include/asm/mach-ralink/rt305x_esw_platform.h | 27 + + arch/mips/ralink/rt305x.c | 1 + + drivers/net/ethernet/Kconfig | 1 + + drivers/net/ethernet/Makefile | 1 + + drivers/net/ethernet/ralink/Kconfig | 31 + + drivers/net/ethernet/ralink/Makefile | 18 + + drivers/net/ethernet/ralink/esw_rt3052.c | 1463 ++++++++++++++++++++ + drivers/net/ethernet/ralink/esw_rt3052.h | 32 + + drivers/net/ethernet/ralink/gsw_mt7620a.c | 1027 ++++++++++++++ + drivers/net/ethernet/ralink/gsw_mt7620a.h | 29 + + drivers/net/ethernet/ralink/mdio.c | 245 ++++ + drivers/net/ethernet/ralink/mdio.h | 29 + + drivers/net/ethernet/ralink/mdio_rt2880.c | 163 +++ + drivers/net/ethernet/ralink/mdio_rt2880.h | 25 + + drivers/net/ethernet/ralink/ralink_soc_eth.c | 759 ++++++++++ + drivers/net/ethernet/ralink/ralink_soc_eth.h | 372 +++++ + drivers/net/ethernet/ralink/soc_mt7620.c | 111 ++ + drivers/net/ethernet/ralink/soc_rt2880.c | 51 + + drivers/net/ethernet/ralink/soc_rt305x.c | 102 ++ + drivers/net/ethernet/ralink/soc_rt3883.c | 59 + + 20 files changed, 4546 insertions(+) + create mode 100644 arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h + create mode 100644 drivers/net/ethernet/ralink/Kconfig + create mode 100644 drivers/net/ethernet/ralink/Makefile + create mode 100644 drivers/net/ethernet/ralink/esw_rt3052.c + create mode 100644 drivers/net/ethernet/ralink/esw_rt3052.h + create mode 100644 drivers/net/ethernet/ralink/gsw_mt7620a.c + create mode 100644 drivers/net/ethernet/ralink/gsw_mt7620a.h + create mode 100644 drivers/net/ethernet/ralink/mdio.c + create mode 100644 drivers/net/ethernet/ralink/mdio.h + create mode 100644 drivers/net/ethernet/ralink/mdio_rt2880.c + create mode 100644 drivers/net/ethernet/ralink/mdio_rt2880.h + create mode 100644 drivers/net/ethernet/ralink/ralink_soc_eth.c + create mode 100644 drivers/net/ethernet/ralink/ralink_soc_eth.h + create mode 100644 drivers/net/ethernet/ralink/soc_mt7620.c + create mode 100644 drivers/net/ethernet/ralink/soc_rt2880.c + create mode 100644 drivers/net/ethernet/ralink/soc_rt305x.c + create mode 100644 drivers/net/ethernet/ralink/soc_rt3883.c + +diff --git a/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h b/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h +new file mode 100644 +index 0000000..2098c5c +--- /dev/null ++++ b/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h +@@ -0,0 +1,27 @@ ++/* ++ * Ralink RT305x SoC platform device registration ++ * ++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#ifndef _RT305X_ESW_PLATFORM_H ++#define _RT305X_ESW_PLATFORM_H ++ ++enum { ++ RT305X_ESW_VLAN_CONFIG_NONE = 0, ++ RT305X_ESW_VLAN_CONFIG_LLLLW, ++ RT305X_ESW_VLAN_CONFIG_WLLLL, ++}; ++ ++struct rt305x_esw_platform_data ++{ ++ u8 vlan_config; ++ u32 reg_initval_fct2; ++ u32 reg_initval_fpa2; ++}; ++ ++#endif /* _RT305X_ESW_PLATFORM_H */ +diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c +index ca7ee3a..1a6b458 100644 +--- a/arch/mips/ralink/rt305x.c ++++ b/arch/mips/ralink/rt305x.c +@@ -221,6 +221,7 @@ void __init ralink_clk_init(void) + } + + ralink_clk_add("cpu", cpu_rate); ++ ralink_clk_add("sys", sys_rate); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000100.timer", wdt_rate); + ralink_clk_add("10000120.watchdog", wdt_rate); +diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig +index e4ff389..08c3c93 100644 +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -137,6 +137,7 @@ source "drivers/net/ethernet/pasemi/Kconfig" + source "drivers/net/ethernet/qlogic/Kconfig" + source "drivers/net/ethernet/racal/Kconfig" + source "drivers/net/ethernet/realtek/Kconfig" ++source "drivers/net/ethernet/ralink/Kconfig" + source "drivers/net/ethernet/renesas/Kconfig" + source "drivers/net/ethernet/rdc/Kconfig" + +diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile +index d447307..f6bffb1 100644 +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -55,6 +55,7 @@ obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/ + obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/ + obj-$(CONFIG_NET_VENDOR_RACAL) += racal/ + obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/ ++obj-$(CONFIG_NET_RALINK) += ralink/ + obj-$(CONFIG_SH_ETH) += renesas/ + obj-$(CONFIG_NET_VENDOR_RDC) += rdc/ + obj-$(CONFIG_S6GMAC) += s6gmac.o +diff --git a/drivers/net/ethernet/ralink/Kconfig b/drivers/net/ethernet/ralink/Kconfig +new file mode 100644 +index 0000000..ca2c9ad +--- /dev/null ++++ b/drivers/net/ethernet/ralink/Kconfig +@@ -0,0 +1,31 @@ ++config NET_RALINK ++ tristate "Ralink RT288X/RT3X5X/RT3662/RT3883/MT7620 ethernet driver" ++ depends on RALINK ++ help ++ This driver supports the ethernet mac inside the ralink wisocs ++ ++if NET_RALINK ++ ++config NET_RALINK_MDIO ++ def_bool NET_RALINK ++ depends on (SOC_RT288X || SOC_RT3883 || SOC_MT7620) ++ select PHYLIB ++ ++config NET_RALINK_MDIO_RT2880 ++ def_bool NET_RALINK ++ depends on (SOC_RT288X || SOC_RT3883) ++ select NET_RALINK_MDIO ++ ++config NET_RALINK_ESW_RT3052 ++ def_bool NET_RALINK ++ depends on SOC_RT305X ++ select PHYLIB ++ select SWCONFIG ++ ++config NET_RALINK_GSW_MT7620 ++ def_bool NET_RALINK ++ depends on SOC_MT7620 ++ select NET_RALINK_MDIO ++ select PHYLIB ++ select SWCONFIG ++endif +diff --git a/drivers/net/ethernet/ralink/Makefile b/drivers/net/ethernet/ralink/Makefile +new file mode 100644 +index 0000000..a38fa21 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/Makefile +@@ -0,0 +1,18 @@ ++# ++# Makefile for the Ralink SoCs built-in ethernet macs ++# ++ ++ralink-eth-y += ralink_soc_eth.o ++ ++ralink-eth-$(CONFIG_NET_RALINK_MDIO) += mdio.o ++ralink-eth-$(CONFIG_NET_RALINK_MDIO_RT2880) += mdio_rt2880.o ++ ++ralink-eth-$(CONFIG_NET_RALINK_ESW_RT3052) += esw_rt3052.o ++ralink-eth-$(CONFIG_NET_RALINK_GSW_MT7620) += gsw_mt7620a.o ++ ++ralink-eth-$(CONFIG_SOC_RT288X) += soc_rt2880.o ++ralink-eth-$(CONFIG_SOC_RT305X) += soc_rt305x.o ++ralink-eth-$(CONFIG_SOC_RT3883) += soc_rt3883.o ++ralink-eth-$(CONFIG_SOC_MT7620) += soc_mt7620.o ++ ++obj-$(CONFIG_NET_RALINK) += ralink-eth.o +diff --git a/drivers/net/ethernet/ralink/esw_rt3052.c b/drivers/net/ethernet/ralink/esw_rt3052.c +new file mode 100644 +index 0000000..b937062 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/esw_rt3052.c +@@ -0,0 +1,1463 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/dma-mapping.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/etherdevice.h> ++#include <linux/ethtool.h> ++#include <linux/platform_device.h> ++#include <linux/of_device.h> ++#include <linux/clk.h> ++#include <linux/of_net.h> ++#include <linux/of_mdio.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#include "ralink_soc_eth.h" ++ ++#include <linux/ioport.h> ++#include <linux/switch.h> ++#include <linux/mii.h> ++ ++#include <ralink_regs.h> ++#include <asm/mach-ralink/rt305x.h> ++#include <asm/mach-ralink/rt305x_esw_platform.h> ++ ++/* ++ * HW limitations for this switch: ++ * - No large frame support (PKT_MAX_LEN at most 1536) ++ * - Can't have untagged vlan and tagged vlan on one port at the same time, ++ * though this might be possible using the undocumented PPE. ++ */ ++ ++#define RT305X_ESW_REG_ISR 0x00 ++#define RT305X_ESW_REG_IMR 0x04 ++#define RT305X_ESW_REG_FCT0 0x08 ++#define RT305X_ESW_REG_PFC1 0x14 ++#define RT305X_ESW_REG_ATS 0x24 ++#define RT305X_ESW_REG_ATS0 0x28 ++#define RT305X_ESW_REG_ATS1 0x2c ++#define RT305X_ESW_REG_ATS2 0x30 ++#define RT305X_ESW_REG_PVIDC(_n) (0x40 + 4 * (_n)) ++#define RT305X_ESW_REG_VLANI(_n) (0x50 + 4 * (_n)) ++#define RT305X_ESW_REG_VMSC(_n) (0x70 + 4 * (_n)) ++#define RT305X_ESW_REG_POA 0x80 ++#define RT305X_ESW_REG_FPA 0x84 ++#define RT305X_ESW_REG_SOCPC 0x8c ++#define RT305X_ESW_REG_POC0 0x90 ++#define RT305X_ESW_REG_POC1 0x94 ++#define RT305X_ESW_REG_POC2 0x98 ++#define RT305X_ESW_REG_SGC 0x9c ++#define RT305X_ESW_REG_STRT 0xa0 ++#define RT305X_ESW_REG_PCR0 0xc0 ++#define RT305X_ESW_REG_PCR1 0xc4 ++#define RT305X_ESW_REG_FPA2 0xc8 ++#define RT305X_ESW_REG_FCT2 0xcc ++#define RT305X_ESW_REG_SGC2 0xe4 ++#define RT305X_ESW_REG_P0LED 0xa4 ++#define RT305X_ESW_REG_P1LED 0xa8 ++#define RT305X_ESW_REG_P2LED 0xac ++#define RT305X_ESW_REG_P3LED 0xb0 ++#define RT305X_ESW_REG_P4LED 0xb4 ++#define RT305X_ESW_REG_PXPC(_x) (0xe8 + (4 * _x)) ++#define RT305X_ESW_REG_P1PC 0xec ++#define RT305X_ESW_REG_P2PC 0xf0 ++#define RT305X_ESW_REG_P3PC 0xf4 ++#define RT305X_ESW_REG_P4PC 0xf8 ++#define RT305X_ESW_REG_P5PC 0xfc ++ ++#define RT305X_ESW_LED_LINK 0 ++#define RT305X_ESW_LED_100M 1 ++#define RT305X_ESW_LED_DUPLEX 2 ++#define RT305X_ESW_LED_ACTIVITY 3 ++#define RT305X_ESW_LED_COLLISION 4 ++#define RT305X_ESW_LED_LINKACT 5 ++#define RT305X_ESW_LED_DUPLCOLL 6 ++#define RT305X_ESW_LED_10MACT 7 ++#define RT305X_ESW_LED_100MACT 8 ++/* Additional led states not in datasheet: */ ++#define RT305X_ESW_LED_BLINK 10 ++#define RT305X_ESW_LED_ON 12 ++ ++#define RT305X_ESW_LINK_S 25 ++#define RT305X_ESW_DUPLEX_S 9 ++#define RT305X_ESW_SPD_S 0 ++ ++#define RT305X_ESW_PCR0_WT_NWAY_DATA_S 16 ++#define RT305X_ESW_PCR0_WT_PHY_CMD BIT(13) ++#define RT305X_ESW_PCR0_CPU_PHY_REG_S 8 ++ ++#define RT305X_ESW_PCR1_WT_DONE BIT(0) ++ ++#define RT305X_ESW_ATS_TIMEOUT (5 * HZ) ++#define RT305X_ESW_PHY_TIMEOUT (5 * HZ) ++ ++#define RT305X_ESW_PVIDC_PVID_M 0xfff ++#define RT305X_ESW_PVIDC_PVID_S 12 ++ ++#define RT305X_ESW_VLANI_VID_M 0xfff ++#define RT305X_ESW_VLANI_VID_S 12 ++ ++#define RT305X_ESW_VMSC_MSC_M 0xff ++#define RT305X_ESW_VMSC_MSC_S 8 ++ ++#define RT305X_ESW_SOCPC_DISUN2CPU_S 0 ++#define RT305X_ESW_SOCPC_DISMC2CPU_S 8 ++#define RT305X_ESW_SOCPC_DISBC2CPU_S 16 ++#define RT305X_ESW_SOCPC_CRC_PADDING BIT(25) ++ ++#define RT305X_ESW_POC0_EN_BP_S 0 ++#define RT305X_ESW_POC0_EN_FC_S 8 ++#define RT305X_ESW_POC0_DIS_RMC2CPU_S 16 ++#define RT305X_ESW_POC0_DIS_PORT_M 0x7f ++#define RT305X_ESW_POC0_DIS_PORT_S 23 ++ ++#define RT305X_ESW_POC2_UNTAG_EN_M 0xff ++#define RT305X_ESW_POC2_UNTAG_EN_S 0 ++#define RT305X_ESW_POC2_ENAGING_S 8 ++#define RT305X_ESW_POC2_DIS_UC_PAUSE_S 16 ++ ++#define RT305X_ESW_SGC2_DOUBLE_TAG_M 0x7f ++#define RT305X_ESW_SGC2_DOUBLE_TAG_S 0 ++#define RT305X_ESW_SGC2_LAN_PMAP_M 0x3f ++#define RT305X_ESW_SGC2_LAN_PMAP_S 24 ++ ++#define RT305X_ESW_PFC1_EN_VLAN_M 0xff ++#define RT305X_ESW_PFC1_EN_VLAN_S 16 ++#define RT305X_ESW_PFC1_EN_TOS_S 24 ++ ++#define RT305X_ESW_VLAN_NONE 0xfff ++ ++#define RT305X_ESW_GSC_BC_STROM_MASK 0x3 ++#define RT305X_ESW_GSC_BC_STROM_SHIFT 4 ++ ++#define RT305X_ESW_GSC_LED_FREQ_MASK 0x3 ++#define RT305X_ESW_GSC_LED_FREQ_SHIFT 23 ++ ++#define RT305X_ESW_POA_LINK_MASK 0x1f ++#define RT305X_ESW_POA_LINK_SHIFT 25 ++ ++#define RT305X_ESW_PORT_ST_CHG BIT(26) ++#define RT305X_ESW_PORT0 0 ++#define RT305X_ESW_PORT1 1 ++#define RT305X_ESW_PORT2 2 ++#define RT305X_ESW_PORT3 3 ++#define RT305X_ESW_PORT4 4 ++#define RT305X_ESW_PORT5 5 ++#define RT305X_ESW_PORT6 6 ++ ++#define RT305X_ESW_PORTS_NONE 0 ++ ++#define RT305X_ESW_PMAP_LLLLLL 0x3f ++#define RT305X_ESW_PMAP_LLLLWL 0x2f ++#define RT305X_ESW_PMAP_WLLLLL 0x3e ++ ++#define RT305X_ESW_PORTS_INTERNAL \ ++ (BIT(RT305X_ESW_PORT0) | BIT(RT305X_ESW_PORT1) | \ ++ BIT(RT305X_ESW_PORT2) | BIT(RT305X_ESW_PORT3) | \ ++ BIT(RT305X_ESW_PORT4)) ++ ++#define RT305X_ESW_PORTS_NOCPU \ ++ (RT305X_ESW_PORTS_INTERNAL | BIT(RT305X_ESW_PORT5)) ++ ++#define RT305X_ESW_PORTS_CPU BIT(RT305X_ESW_PORT6) ++ ++#define RT305X_ESW_PORTS_ALL \ ++ (RT305X_ESW_PORTS_NOCPU | RT305X_ESW_PORTS_CPU) ++ ++#define RT305X_ESW_NUM_VLANS 16 ++#define RT305X_ESW_NUM_VIDS 4096 ++#define RT305X_ESW_NUM_PORTS 7 ++#define RT305X_ESW_NUM_LANWAN 6 ++#define RT305X_ESW_NUM_LEDS 5 ++ ++#define RT5350_ESW_REG_PXTPC(_x) (0x150 + (4 * _x)) ++#define RT5350_EWS_REG_LED_POLARITY 0x168 ++#define RT5350_RESET_EPHY BIT(24) ++#define SYSC_REG_RESET_CTRL 0x34 ++ ++enum { ++ /* Global attributes. */ ++ RT305X_ESW_ATTR_ENABLE_VLAN, ++ RT305X_ESW_ATTR_ALT_VLAN_DISABLE, ++ RT305X_ESW_ATTR_BC_STATUS, ++ RT305X_ESW_ATTR_LED_FREQ, ++ /* Port attributes. */ ++ RT305X_ESW_ATTR_PORT_DISABLE, ++ RT305X_ESW_ATTR_PORT_DOUBLETAG, ++ RT305X_ESW_ATTR_PORT_UNTAG, ++ RT305X_ESW_ATTR_PORT_LED, ++ RT305X_ESW_ATTR_PORT_LAN, ++ RT305X_ESW_ATTR_PORT_RECV_BAD, ++ RT305X_ESW_ATTR_PORT_RECV_GOOD, ++ RT5350_ESW_ATTR_PORT_TR_BAD, ++ RT5350_ESW_ATTR_PORT_TR_GOOD, ++}; ++ ++struct esw_port { ++ bool disable; ++ bool doubletag; ++ bool untag; ++ u8 led; ++ u16 pvid; ++}; ++ ++struct esw_vlan { ++ u8 ports; ++ u16 vid; ++}; ++ ++struct rt305x_esw { ++ struct device *dev; ++ void __iomem *base; ++ int irq; ++ const struct rt305x_esw_platform_data *pdata; ++ /* Protects against concurrent register rmw operations. */ ++ spinlock_t reg_rw_lock; ++ ++ unsigned char port_map; ++ unsigned int reg_initval_fct2; ++ unsigned int reg_initval_fpa2; ++ unsigned int reg_led_polarity; ++ ++ ++ struct switch_dev swdev; ++ bool global_vlan_enable; ++ bool alt_vlan_disable; ++ int bc_storm_protect; ++ int led_frequency; ++ struct esw_vlan vlans[RT305X_ESW_NUM_VLANS]; ++ struct esw_port ports[RT305X_ESW_NUM_PORTS]; ++ ++}; ++ ++static inline void esw_w32(struct rt305x_esw *esw, u32 val, unsigned reg) ++{ ++ __raw_writel(val, esw->base + reg); ++} ++ ++static inline u32 esw_r32(struct rt305x_esw *esw, unsigned reg) ++{ ++ return __raw_readl(esw->base + reg); ++} ++ ++static inline void esw_rmw_raw(struct rt305x_esw *esw, unsigned reg, unsigned long mask, ++ unsigned long val) ++{ ++ unsigned long t; ++ ++ t = __raw_readl(esw->base + reg) & ~mask; ++ __raw_writel(t | val, esw->base + reg); ++} ++ ++static void esw_rmw(struct rt305x_esw *esw, unsigned reg, unsigned long mask, ++ unsigned long val) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&esw->reg_rw_lock, flags); ++ esw_rmw_raw(esw, reg, mask, val); ++ spin_unlock_irqrestore(&esw->reg_rw_lock, flags); ++} ++ ++static u32 rt305x_mii_write(struct rt305x_esw *esw, u32 phy_addr, u32 phy_register, ++ u32 write_data) ++{ ++ unsigned long t_start = jiffies; ++ int ret = 0; ++ ++ while (1) { ++ if (!(esw_r32(esw, RT305X_ESW_REG_PCR1) & ++ RT305X_ESW_PCR1_WT_DONE)) ++ break; ++ if (time_after(jiffies, t_start + RT305X_ESW_PHY_TIMEOUT)) { ++ ret = 1; ++ goto out; ++ } ++ } ++ ++ write_data &= 0xffff; ++ esw_w32(esw, ++ (write_data << RT305X_ESW_PCR0_WT_NWAY_DATA_S) | ++ (phy_register << RT305X_ESW_PCR0_CPU_PHY_REG_S) | ++ (phy_addr) | RT305X_ESW_PCR0_WT_PHY_CMD, ++ RT305X_ESW_REG_PCR0); ++ ++ t_start = jiffies; ++ while (1) { ++ if (esw_r32(esw, RT305X_ESW_REG_PCR1) & ++ RT305X_ESW_PCR1_WT_DONE) ++ break; ++ ++ if (time_after(jiffies, t_start + RT305X_ESW_PHY_TIMEOUT)) { ++ ret = 1; ++ break; ++ } ++ } ++out: ++ if (ret) ++ printk(KERN_ERR "ramips_eth: MDIO timeout\n"); ++ return ret; ++} ++ ++static unsigned esw_get_vlan_id(struct rt305x_esw *esw, unsigned vlan) ++{ ++ unsigned s; ++ unsigned val; ++ ++ s = RT305X_ESW_VLANI_VID_S * (vlan % 2); ++ val = esw_r32(esw, RT305X_ESW_REG_VLANI(vlan / 2)); ++ val = (val >> s) & RT305X_ESW_VLANI_VID_M; ++ ++ return val; ++} ++ ++static void esw_set_vlan_id(struct rt305x_esw *esw, unsigned vlan, unsigned vid) ++{ ++ unsigned s; ++ ++ s = RT305X_ESW_VLANI_VID_S * (vlan % 2); ++ esw_rmw(esw, ++ RT305X_ESW_REG_VLANI(vlan / 2), ++ RT305X_ESW_VLANI_VID_M << s, ++ (vid & RT305X_ESW_VLANI_VID_M) << s); ++} ++ ++static unsigned esw_get_pvid(struct rt305x_esw *esw, unsigned port) ++{ ++ unsigned s, val; ++ ++ s = RT305X_ESW_PVIDC_PVID_S * (port % 2); ++ val = esw_r32(esw, RT305X_ESW_REG_PVIDC(port / 2)); ++ return (val >> s) & RT305X_ESW_PVIDC_PVID_M; ++} ++ ++static void esw_set_pvid(struct rt305x_esw *esw, unsigned port, unsigned pvid) ++{ ++ unsigned s; ++ ++ s = RT305X_ESW_PVIDC_PVID_S * (port % 2); ++ esw_rmw(esw, ++ RT305X_ESW_REG_PVIDC(port / 2), ++ RT305X_ESW_PVIDC_PVID_M << s, ++ (pvid & RT305X_ESW_PVIDC_PVID_M) << s); ++} ++ ++static unsigned esw_get_vmsc(struct rt305x_esw *esw, unsigned vlan) ++{ ++ unsigned s, val; ++ ++ s = RT305X_ESW_VMSC_MSC_S * (vlan % 4); ++ val = esw_r32(esw, RT305X_ESW_REG_VMSC(vlan / 4)); ++ val = (val >> s) & RT305X_ESW_VMSC_MSC_M; ++ ++ return val; ++} ++ ++static void esw_set_vmsc(struct rt305x_esw *esw, unsigned vlan, unsigned msc) ++{ ++ unsigned s; ++ ++ s = RT305X_ESW_VMSC_MSC_S * (vlan % 4); ++ esw_rmw(esw, ++ RT305X_ESW_REG_VMSC(vlan / 4), ++ RT305X_ESW_VMSC_MSC_M << s, ++ (msc & RT305X_ESW_VMSC_MSC_M) << s); ++} ++ ++static unsigned esw_get_port_disable(struct rt305x_esw *esw) ++{ ++ unsigned reg; ++ reg = esw_r32(esw, RT305X_ESW_REG_POC0); ++ return (reg >> RT305X_ESW_POC0_DIS_PORT_S) & ++ RT305X_ESW_POC0_DIS_PORT_M; ++} ++ ++static void esw_set_port_disable(struct rt305x_esw *esw, unsigned disable_mask) ++{ ++ unsigned old_mask; ++ unsigned enable_mask; ++ unsigned changed; ++ int i; ++ ++ old_mask = esw_get_port_disable(esw); ++ changed = old_mask ^ disable_mask; ++ enable_mask = old_mask & disable_mask; ++ ++ /* enable before writing to MII */ ++ esw_rmw(esw, RT305X_ESW_REG_POC0, ++ (RT305X_ESW_POC0_DIS_PORT_M << ++ RT305X_ESW_POC0_DIS_PORT_S), ++ enable_mask << RT305X_ESW_POC0_DIS_PORT_S); ++ ++ for (i = 0; i < RT305X_ESW_NUM_LEDS; i++) { ++ if (!(changed & (1 << i))) ++ continue; ++ if (disable_mask & (1 << i)) { ++ /* disable */ ++ rt305x_mii_write(esw, i, MII_BMCR, ++ BMCR_PDOWN); ++ } else { ++ /* enable */ ++ rt305x_mii_write(esw, i, MII_BMCR, ++ BMCR_FULLDPLX | ++ BMCR_ANENABLE | ++ BMCR_ANRESTART | ++ BMCR_SPEED100); ++ } ++ } ++ ++ /* disable after writing to MII */ ++ esw_rmw(esw, RT305X_ESW_REG_POC0, ++ (RT305X_ESW_POC0_DIS_PORT_M << ++ RT305X_ESW_POC0_DIS_PORT_S), ++ disable_mask << RT305X_ESW_POC0_DIS_PORT_S); ++} ++ ++static void esw_set_gsc(struct rt305x_esw *esw) ++{ ++ esw_rmw(esw, RT305X_ESW_REG_SGC, ++ RT305X_ESW_GSC_BC_STROM_MASK << RT305X_ESW_GSC_BC_STROM_SHIFT, ++ esw->bc_storm_protect << RT305X_ESW_GSC_BC_STROM_SHIFT); ++ esw_rmw(esw, RT305X_ESW_REG_SGC, ++ RT305X_ESW_GSC_LED_FREQ_MASK << RT305X_ESW_GSC_LED_FREQ_SHIFT, ++ esw->led_frequency << RT305X_ESW_GSC_LED_FREQ_SHIFT); ++} ++ ++static int esw_apply_config(struct switch_dev *dev); ++ ++static void esw_hw_init(struct rt305x_esw *esw) ++{ ++ int i; ++ u8 port_disable = 0; ++ u8 port_map = RT305X_ESW_PMAP_LLLLLL; ++ ++ /* vodoo from original driver */ ++ esw_w32(esw, 0xC8A07850, RT305X_ESW_REG_FCT0); ++ esw_w32(esw, 0x00000000, RT305X_ESW_REG_SGC2); ++ /* Port priority 1 for all ports, vlan enabled. */ ++ esw_w32(esw, 0x00005555 | ++ (RT305X_ESW_PORTS_ALL << RT305X_ESW_PFC1_EN_VLAN_S), ++ RT305X_ESW_REG_PFC1); ++ ++ /* Enable Back Pressure, and Flow Control */ ++ esw_w32(esw, ++ ((RT305X_ESW_PORTS_ALL << RT305X_ESW_POC0_EN_BP_S) | ++ (RT305X_ESW_PORTS_ALL << RT305X_ESW_POC0_EN_FC_S)), ++ RT305X_ESW_REG_POC0); ++ ++ /* Enable Aging, and VLAN TAG removal */ ++ esw_w32(esw, ++ ((RT305X_ESW_PORTS_ALL << RT305X_ESW_POC2_ENAGING_S) | ++ (RT305X_ESW_PORTS_NOCPU << RT305X_ESW_POC2_UNTAG_EN_S)), ++ RT305X_ESW_REG_POC2); ++ ++ if (esw->reg_initval_fct2) ++ esw_w32(esw, esw->reg_initval_fct2, RT305X_ESW_REG_FCT2); ++ else ++ esw_w32(esw, esw->pdata->reg_initval_fct2, RT305X_ESW_REG_FCT2); ++ ++ /* ++ * 300s aging timer, max packet len 1536, broadcast storm prevention ++ * disabled, disable collision abort, mac xor48 hash, 10 packet back ++ * pressure jam, GMII disable was_transmit, back pressure disabled, ++ * 30ms led flash, unmatched IGMP as broadcast, rmc tb fault to all ++ * ports. ++ */ ++ esw_w32(esw, 0x0008a301, RT305X_ESW_REG_SGC); ++ ++ /* Setup SoC Port control register */ ++ esw_w32(esw, ++ (RT305X_ESW_SOCPC_CRC_PADDING | ++ (RT305X_ESW_PORTS_CPU << RT305X_ESW_SOCPC_DISUN2CPU_S) | ++ (RT305X_ESW_PORTS_CPU << RT305X_ESW_SOCPC_DISMC2CPU_S) | ++ (RT305X_ESW_PORTS_CPU << RT305X_ESW_SOCPC_DISBC2CPU_S)), ++ RT305X_ESW_REG_SOCPC); ++ ++ if (esw->reg_initval_fpa2) ++ esw_w32(esw, esw->reg_initval_fpa2, RT305X_ESW_REG_FPA2); ++ else ++ esw_w32(esw, esw->pdata->reg_initval_fpa2, RT305X_ESW_REG_FPA2); ++ esw_w32(esw, 0x00000000, RT305X_ESW_REG_FPA); ++ ++ /* Force Link/Activity on ports */ ++ esw_w32(esw, 0x00000005, RT305X_ESW_REG_P0LED); ++ esw_w32(esw, 0x00000005, RT305X_ESW_REG_P1LED); ++ esw_w32(esw, 0x00000005, RT305X_ESW_REG_P2LED); ++ esw_w32(esw, 0x00000005, RT305X_ESW_REG_P3LED); ++ esw_w32(esw, 0x00000005, RT305X_ESW_REG_P4LED); ++ ++ /* Copy disabled port configuration from bootloader setup */ ++ port_disable = esw_get_port_disable(esw); ++ for (i = 0; i < 6; i++) ++ esw->ports[i].disable = (port_disable & (1 << i)) != 0; ++ ++ if (soc_is_rt3352()) { ++ /* reset EPHY */ ++ u32 val = rt_sysc_r32(SYSC_REG_RESET_CTRL); ++ rt_sysc_w32(val | RT5350_RESET_EPHY, SYSC_REG_RESET_CTRL); ++ rt_sysc_w32(val, SYSC_REG_RESET_CTRL); ++ ++ rt305x_mii_write(esw, 0, 31, 0x8000); ++ for (i = 0; i < 5; i++) { ++ if (esw->ports[i].disable) { ++ rt305x_mii_write(esw, i, MII_BMCR, BMCR_PDOWN); ++ } else { ++ rt305x_mii_write(esw, i, MII_BMCR, ++ BMCR_FULLDPLX | ++ BMCR_ANENABLE | ++ BMCR_SPEED100); ++ } ++ /* TX10 waveform coefficient LSB=0 disable PHY */ ++ rt305x_mii_write(esw, i, 26, 0x1601); ++ /* TX100/TX10 AD/DA current bias */ ++ rt305x_mii_write(esw, i, 29, 0x7016); ++ /* TX100 slew rate control */ ++ rt305x_mii_write(esw, i, 30, 0x0038); ++ } ++ ++ /* select global register */ ++ rt305x_mii_write(esw, 0, 31, 0x0); ++ /* enlarge agcsel threshold 3 and threshold 2 */ ++ rt305x_mii_write(esw, 0, 1, 0x4a40); ++ /* enlarge agcsel threshold 5 and threshold 4 */ ++ rt305x_mii_write(esw, 0, 2, 0x6254); ++ /* enlarge agcsel threshold */ ++ rt305x_mii_write(esw, 0, 3, 0xa17f); ++ rt305x_mii_write(esw, 0,12, 0x7eaa); ++ /* longer TP_IDL tail length */ ++ rt305x_mii_write(esw, 0, 14, 0x65); ++ /* increased squelch pulse count threshold. */ ++ rt305x_mii_write(esw, 0, 16, 0x0684); ++ /* set TX10 signal amplitude threshold to minimum */ ++ rt305x_mii_write(esw, 0, 17, 0x0fe0); ++ /* set squelch amplitude to higher threshold */ ++ rt305x_mii_write(esw, 0, 18, 0x40ba); ++ /* tune TP_IDL tail and head waveform, enable power down slew rate control */ ++ rt305x_mii_write(esw, 0, 22, 0x253f); ++ /* set PLL/Receive bias current are calibrated */ ++ rt305x_mii_write(esw, 0, 27, 0x2fda); ++ /* change PLL/Receive bias current to internal(RT3350) */ ++ rt305x_mii_write(esw, 0, 28, 0xc410); ++ /* change PLL bias current to internal(RT3052_MP3) */ ++ rt305x_mii_write(esw, 0, 29, 0x598b); ++ /* select local register */ ++ rt305x_mii_write(esw, 0, 31, 0x8000); ++ } else if (soc_is_rt5350()) { ++ /* reset EPHY */ ++ u32 val = rt_sysc_r32(SYSC_REG_RESET_CTRL); ++ rt_sysc_w32(val | RT5350_RESET_EPHY, SYSC_REG_RESET_CTRL); ++ rt_sysc_w32(val, SYSC_REG_RESET_CTRL); ++ ++ /* set the led polarity */ ++ esw_w32(esw, esw->reg_led_polarity & 0x1F, RT5350_EWS_REG_LED_POLARITY); ++ ++ /* local registers */ ++ rt305x_mii_write(esw, 0, 31, 0x8000); ++ for (i = 0; i < 5; i++) { ++ if (esw->ports[i].disable) { ++ rt305x_mii_write(esw, i, MII_BMCR, BMCR_PDOWN); ++ } else { ++ rt305x_mii_write(esw, i, MII_BMCR, ++ BMCR_FULLDPLX | ++ BMCR_ANENABLE | ++ BMCR_SPEED100); ++ } ++ /* TX10 waveform coefficient LSB=0 disable PHY */ ++ rt305x_mii_write(esw, i, 26, 0x1601); ++ /* TX100/TX10 AD/DA current bias */ ++ rt305x_mii_write(esw, i, 29, 0x7015); ++ /* TX100 slew rate control */ ++ rt305x_mii_write(esw, i, 30, 0x0038); ++ } ++ ++ /* global registers */ ++ rt305x_mii_write(esw, 0, 31, 0x0); ++ /* enlarge agcsel threshold 3 and threshold 2 */ ++ rt305x_mii_write(esw, 0, 1, 0x4a40); ++ /* enlarge agcsel threshold 5 and threshold 4 */ ++ rt305x_mii_write(esw, 0, 2, 0x6254); ++ /* enlarge agcsel threshold 6 */ ++ rt305x_mii_write(esw, 0, 3, 0xa17f); ++ rt305x_mii_write(esw, 0, 12, 0x7eaa); ++ /* longer TP_IDL tail length */ ++ rt305x_mii_write(esw, 0, 14, 0x65); ++ /* increased squelch pulse count threshold. */ ++ rt305x_mii_write(esw, 0, 16, 0x0684); ++ /* set TX10 signal amplitude threshold to minimum */ ++ rt305x_mii_write(esw, 0, 17, 0x0fe0); ++ /* set squelch amplitude to higher threshold */ ++ rt305x_mii_write(esw, 0, 18, 0x40ba); ++ /* tune TP_IDL tail and head waveform, enable power down slew rate control */ ++ rt305x_mii_write(esw, 0, 22, 0x253f); ++ /* set PLL/Receive bias current are calibrated */ ++ rt305x_mii_write(esw, 0, 27, 0x2fda); ++ /* change PLL/Receive bias current to internal(RT3350) */ ++ rt305x_mii_write(esw, 0, 28, 0xc410); ++ /* change PLL bias current to internal(RT3052_MP3) */ ++ rt305x_mii_write(esw, 0, 29, 0x598b); ++ /* select local register */ ++ rt305x_mii_write(esw, 0, 31, 0x8000); ++ } else { ++ rt305x_mii_write(esw, 0, 31, 0x8000); ++ for (i = 0; i < 5; i++) { ++ if (esw->ports[i].disable) { ++ rt305x_mii_write(esw, i, MII_BMCR, BMCR_PDOWN); ++ } else { ++ rt305x_mii_write(esw, i, MII_BMCR, ++ BMCR_FULLDPLX | ++ BMCR_ANENABLE | ++ BMCR_SPEED100); ++ } ++ /* TX10 waveform coefficient */ ++ rt305x_mii_write(esw, i, 26, 0x1601); ++ /* TX100/TX10 AD/DA current bias */ ++ rt305x_mii_write(esw, i, 29, 0x7058); ++ /* TX100 slew rate control */ ++ rt305x_mii_write(esw, i, 30, 0x0018); ++ } ++ ++ /* PHY IOT */ ++ /* select global register */ ++ rt305x_mii_write(esw, 0, 31, 0x0); ++ /* tune TP_IDL tail and head waveform */ ++ rt305x_mii_write(esw, 0, 22, 0x052f); ++ /* set TX10 signal amplitude threshold to minimum */ ++ rt305x_mii_write(esw, 0, 17, 0x0fe0); ++ /* set squelch amplitude to higher threshold */ ++ rt305x_mii_write(esw, 0, 18, 0x40ba); ++ /* longer TP_IDL tail length */ ++ rt305x_mii_write(esw, 0, 14, 0x65); ++ /* select local register */ ++ rt305x_mii_write(esw, 0, 31, 0x8000); ++ } ++ ++ if (esw->port_map) ++ port_map = esw->port_map; ++ else ++ port_map = RT305X_ESW_PMAP_LLLLLL; ++ ++ /* ++ * Unused HW feature, but still nice to be consistent here... ++ * This is also exported to userspace ('lan' attribute) so it's ++ * conveniently usable to decide which ports go into the wan vlan by ++ * default. ++ */ ++ esw_rmw(esw, RT305X_ESW_REG_SGC2, ++ RT305X_ESW_SGC2_LAN_PMAP_M << RT305X_ESW_SGC2_LAN_PMAP_S, ++ port_map << RT305X_ESW_SGC2_LAN_PMAP_S); ++ ++ /* make the switch leds blink */ ++ for (i = 0; i < RT305X_ESW_NUM_LEDS; i++) ++ esw->ports[i].led = 0x05; ++ ++ /* Apply the empty config. */ ++ esw_apply_config(&esw->swdev); ++ ++ /* Only unmask the port change interrupt */ ++ esw_w32(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR); ++} ++ ++static irqreturn_t esw_interrupt(int irq, void *_esw) ++{ ++ struct rt305x_esw *esw = (struct rt305x_esw *) _esw; ++ u32 status; ++ ++ status = esw_r32(esw, RT305X_ESW_REG_ISR); ++ if (status & RT305X_ESW_PORT_ST_CHG) { ++ u32 link = esw_r32(esw, RT305X_ESW_REG_POA); ++ link >>= RT305X_ESW_POA_LINK_SHIFT; ++ link &= RT305X_ESW_POA_LINK_MASK; ++ dev_info(esw->dev, "link changed 0x%02X\n", link); ++ } ++ esw_w32(esw, status, RT305X_ESW_REG_ISR); ++ ++ return IRQ_HANDLED; ++} ++ ++static int esw_apply_config(struct switch_dev *dev) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ int i; ++ u8 disable = 0; ++ u8 doubletag = 0; ++ u8 en_vlan = 0; ++ u8 untag = 0; ++ ++ for (i = 0; i < RT305X_ESW_NUM_VLANS; i++) { ++ u32 vid, vmsc; ++ if (esw->global_vlan_enable) { ++ vid = esw->vlans[i].vid; ++ vmsc = esw->vlans[i].ports; ++ } else { ++ vid = RT305X_ESW_VLAN_NONE; ++ vmsc = RT305X_ESW_PORTS_NONE; ++ } ++ esw_set_vlan_id(esw, i, vid); ++ esw_set_vmsc(esw, i, vmsc); ++ } ++ ++ for (i = 0; i < RT305X_ESW_NUM_PORTS; i++) { ++ u32 pvid; ++ disable |= esw->ports[i].disable << i; ++ if (esw->global_vlan_enable) { ++ doubletag |= esw->ports[i].doubletag << i; ++ en_vlan |= 1 << i; ++ untag |= esw->ports[i].untag << i; ++ pvid = esw->ports[i].pvid; ++ } else { ++ int x = esw->alt_vlan_disable ? 0 : 1; ++ doubletag |= x << i; ++ en_vlan |= x << i; ++ untag |= x << i; ++ pvid = 0; ++ } ++ esw_set_pvid(esw, i, pvid); ++ if (i < RT305X_ESW_NUM_LEDS) ++ esw_w32(esw, esw->ports[i].led, ++ RT305X_ESW_REG_P0LED + 4*i); ++ } ++ ++ esw_set_gsc(esw); ++ esw_set_port_disable(esw, disable); ++ esw_rmw(esw, RT305X_ESW_REG_SGC2, ++ (RT305X_ESW_SGC2_DOUBLE_TAG_M << ++ RT305X_ESW_SGC2_DOUBLE_TAG_S), ++ doubletag << RT305X_ESW_SGC2_DOUBLE_TAG_S); ++ esw_rmw(esw, RT305X_ESW_REG_PFC1, ++ RT305X_ESW_PFC1_EN_VLAN_M << RT305X_ESW_PFC1_EN_VLAN_S, ++ en_vlan << RT305X_ESW_PFC1_EN_VLAN_S); ++ esw_rmw(esw, RT305X_ESW_REG_POC2, ++ RT305X_ESW_POC2_UNTAG_EN_M << RT305X_ESW_POC2_UNTAG_EN_S, ++ untag << RT305X_ESW_POC2_UNTAG_EN_S); ++ ++ if (!esw->global_vlan_enable) { ++ /* ++ * Still need to put all ports into vlan 0 or they'll be ++ * isolated. ++ * NOTE: vlan 0 is special, no vlan tag is prepended ++ */ ++ esw_set_vlan_id(esw, 0, 0); ++ esw_set_vmsc(esw, 0, RT305X_ESW_PORTS_ALL); ++ } ++ ++ return 0; ++} ++ ++static int esw_reset_switch(struct switch_dev *dev) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ esw->global_vlan_enable = 0; ++ memset(esw->ports, 0, sizeof(esw->ports)); ++ memset(esw->vlans, 0, sizeof(esw->vlans)); ++ esw_hw_init(esw); ++ ++ return 0; ++} ++ ++static int esw_get_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ val->value.i = esw->global_vlan_enable; ++ ++ return 0; ++} ++ ++static int esw_set_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ esw->global_vlan_enable = val->value.i != 0; ++ ++ return 0; ++} ++ ++static int esw_get_alt_vlan_disable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ val->value.i = esw->alt_vlan_disable; ++ ++ return 0; ++} ++ ++static int esw_set_alt_vlan_disable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ esw->alt_vlan_disable = val->value.i != 0; ++ ++ return 0; ++} ++ ++static int ++rt305x_esw_set_bc_status(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ esw->bc_storm_protect = val->value.i & RT305X_ESW_GSC_BC_STROM_MASK; ++ ++ return 0; ++} ++ ++static int ++rt305x_esw_get_bc_status(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ val->value.i = esw->bc_storm_protect; ++ ++ return 0; ++} ++ ++static int ++rt305x_esw_set_led_freq(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ esw->led_frequency = val->value.i & RT305X_ESW_GSC_LED_FREQ_MASK; ++ ++ return 0; ++} ++ ++static int ++rt305x_esw_get_led_freq(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ val->value.i = esw->led_frequency; ++ ++ return 0; ++} ++ ++static int esw_get_port_link(struct switch_dev *dev, ++ int port, ++ struct switch_port_link *link) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ u32 speed, poa; ++ ++ if (port < 0 || port >= RT305X_ESW_NUM_PORTS) ++ return -EINVAL; ++ ++ poa = esw_r32(esw, RT305X_ESW_REG_POA) >> port; ++ ++ link->link = (poa >> RT305X_ESW_LINK_S) & 1; ++ link->duplex = (poa >> RT305X_ESW_DUPLEX_S) & 1; ++ if (port < RT305X_ESW_NUM_LEDS) { ++ speed = (poa >> RT305X_ESW_SPD_S) & 1; ++ } else { ++ if (port == RT305X_ESW_NUM_PORTS - 1) ++ poa >>= 1; ++ speed = (poa >> RT305X_ESW_SPD_S) & 3; ++ } ++ switch (speed) { ++ case 0: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case 1: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case 2: ++ case 3: /* forced gige speed can be 2 or 3 */ ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ default: ++ link->speed = SWITCH_PORT_SPEED_UNKNOWN; ++ break; ++ } ++ ++ return 0; ++} ++ ++static int esw_get_port_bool(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ int idx = val->port_vlan; ++ u32 x, reg, shift; ++ ++ if (idx < 0 || idx >= RT305X_ESW_NUM_PORTS) ++ return -EINVAL; ++ ++ switch (attr->id) { ++ case RT305X_ESW_ATTR_PORT_DISABLE: ++ reg = RT305X_ESW_REG_POC0; ++ shift = RT305X_ESW_POC0_DIS_PORT_S; ++ break; ++ case RT305X_ESW_ATTR_PORT_DOUBLETAG: ++ reg = RT305X_ESW_REG_SGC2; ++ shift = RT305X_ESW_SGC2_DOUBLE_TAG_S; ++ break; ++ case RT305X_ESW_ATTR_PORT_UNTAG: ++ reg = RT305X_ESW_REG_POC2; ++ shift = RT305X_ESW_POC2_UNTAG_EN_S; ++ break; ++ case RT305X_ESW_ATTR_PORT_LAN: ++ reg = RT305X_ESW_REG_SGC2; ++ shift = RT305X_ESW_SGC2_LAN_PMAP_S; ++ if (idx >= RT305X_ESW_NUM_LANWAN) ++ return -EINVAL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ x = esw_r32(esw, reg); ++ val->value.i = (x >> (idx + shift)) & 1; ++ ++ return 0; ++} ++ ++static int esw_set_port_bool(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ int idx = val->port_vlan; ++ ++ if (idx < 0 || idx >= RT305X_ESW_NUM_PORTS || ++ val->value.i < 0 || val->value.i > 1) ++ return -EINVAL; ++ ++ switch (attr->id) { ++ case RT305X_ESW_ATTR_PORT_DISABLE: ++ esw->ports[idx].disable = val->value.i; ++ break; ++ case RT305X_ESW_ATTR_PORT_DOUBLETAG: ++ esw->ports[idx].doubletag = val->value.i; ++ break; ++ case RT305X_ESW_ATTR_PORT_UNTAG: ++ esw->ports[idx].untag = val->value.i; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int esw_get_port_recv_badgood(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ int idx = val->port_vlan; ++ int shift = attr->id == RT305X_ESW_ATTR_PORT_RECV_GOOD ? 0 : 16; ++ u32 reg; ++ ++ if (idx < 0 || idx >= RT305X_ESW_NUM_LANWAN) ++ return -EINVAL; ++ reg = esw_r32(esw, RT305X_ESW_REG_PXPC(idx)); ++ val->value.i = (reg >> shift) & 0xffff; ++ ++ return 0; ++} ++ ++static int ++esw_get_port_tr_badgood(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ int idx = val->port_vlan; ++ int shift = attr->id == RT5350_ESW_ATTR_PORT_TR_GOOD ? 0 : 16; ++ u32 reg; ++ ++ if (!soc_is_rt5350()) ++ return -EINVAL; ++ ++ if (idx < 0 || idx >= RT305X_ESW_NUM_LANWAN) ++ return -EINVAL; ++ ++ reg = esw_r32(esw, RT5350_ESW_REG_PXTPC(idx)); ++ val->value.i = (reg >> shift) & 0xffff; ++ ++ return 0; ++} ++ ++static int esw_get_port_led(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ int idx = val->port_vlan; ++ ++ if (idx < 0 || idx >= RT305X_ESW_NUM_PORTS || ++ idx >= RT305X_ESW_NUM_LEDS) ++ return -EINVAL; ++ ++ val->value.i = esw_r32(esw, RT305X_ESW_REG_P0LED + 4*idx); ++ ++ return 0; ++} ++ ++static int esw_set_port_led(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ int idx = val->port_vlan; ++ ++ if (idx < 0 || idx >= RT305X_ESW_NUM_LEDS) ++ return -EINVAL; ++ ++ esw->ports[idx].led = val->value.i; ++ ++ return 0; ++} ++ ++static int esw_get_port_pvid(struct switch_dev *dev, int port, int *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ if (port >= RT305X_ESW_NUM_PORTS) ++ return -EINVAL; ++ ++ *val = esw_get_pvid(esw, port); ++ ++ return 0; ++} ++ ++static int esw_set_port_pvid(struct switch_dev *dev, int port, int val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ ++ if (port >= RT305X_ESW_NUM_PORTS) ++ return -EINVAL; ++ ++ esw->ports[port].pvid = val; ++ ++ return 0; ++} ++ ++static int esw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ u32 vmsc, poc2; ++ int vlan_idx = -1; ++ int i; ++ ++ val->len = 0; ++ ++ if (val->port_vlan < 0 || val->port_vlan >= RT305X_ESW_NUM_VIDS) ++ return -EINVAL; ++ ++ /* valid vlan? */ ++ for (i = 0; i < RT305X_ESW_NUM_VLANS; i++) { ++ if (esw_get_vlan_id(esw, i) == val->port_vlan && ++ esw_get_vmsc(esw, i) != RT305X_ESW_PORTS_NONE) { ++ vlan_idx = i; ++ break; ++ } ++ } ++ ++ if (vlan_idx == -1) ++ return -EINVAL; ++ ++ vmsc = esw_get_vmsc(esw, vlan_idx); ++ poc2 = esw_r32(esw, RT305X_ESW_REG_POC2); ++ ++ for (i = 0; i < RT305X_ESW_NUM_PORTS; i++) { ++ struct switch_port *p; ++ int port_mask = 1 << i; ++ ++ if (!(vmsc & port_mask)) ++ continue; ++ ++ p = &val->value.ports[val->len++]; ++ p->id = i; ++ if (poc2 & (port_mask << RT305X_ESW_POC2_UNTAG_EN_S)) ++ p->flags = 0; ++ else ++ p->flags = 1 << SWITCH_PORT_FLAG_TAGGED; ++ } ++ ++ return 0; ++} ++ ++static int esw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); ++ int ports; ++ int vlan_idx = -1; ++ int i; ++ ++ if (val->port_vlan < 0 || val->port_vlan >= RT305X_ESW_NUM_VIDS || ++ val->len > RT305X_ESW_NUM_PORTS) ++ return -EINVAL; ++ ++ /* one of the already defined vlans? */ ++ for (i = 0; i < RT305X_ESW_NUM_VLANS; i++) { ++ if (esw->vlans[i].vid == val->port_vlan && ++ esw->vlans[i].ports != RT305X_ESW_PORTS_NONE) { ++ vlan_idx = i; ++ break; ++ } ++ } ++ ++ /* select a free slot */ ++ for (i = 0; vlan_idx == -1 && i < RT305X_ESW_NUM_VLANS; i++) { ++ if (esw->vlans[i].ports == RT305X_ESW_PORTS_NONE) ++ vlan_idx = i; ++ } ++ ++ /* bail if all slots are in use */ ++ if (vlan_idx == -1) ++ return -EINVAL; ++ ++ ports = RT305X_ESW_PORTS_NONE; ++ for (i = 0; i < val->len; i++) { ++ struct switch_port *p = &val->value.ports[i]; ++ int port_mask = 1 << p->id; ++ bool untagged = !(p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)); ++ ++ if (p->id >= RT305X_ESW_NUM_PORTS) ++ return -EINVAL; ++ ++ ports |= port_mask; ++ esw->ports[p->id].untag = untagged; ++ } ++ esw->vlans[vlan_idx].ports = ports; ++ if (ports == RT305X_ESW_PORTS_NONE) ++ esw->vlans[vlan_idx].vid = RT305X_ESW_VLAN_NONE; ++ else ++ esw->vlans[vlan_idx].vid = val->port_vlan; ++ ++ return 0; ++} ++ ++static const struct switch_attr esw_global[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "VLAN mode (1:enabled)", ++ .max = 1, ++ .id = RT305X_ESW_ATTR_ENABLE_VLAN, ++ .get = esw_get_vlan_enable, ++ .set = esw_set_vlan_enable, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "alternate_vlan_disable", ++ .description = "Use en_vlan instead of doubletag to disable" ++ " VLAN mode", ++ .max = 1, ++ .id = RT305X_ESW_ATTR_ALT_VLAN_DISABLE, ++ .get = esw_get_alt_vlan_disable, ++ .set = esw_set_alt_vlan_disable, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "bc_storm_protect", ++ .description = "Global broadcast storm protection (0:Disable, 1:64 blocks, 2:96 blocks, 3:128 blocks)", ++ .max = 3, ++ .id = RT305X_ESW_ATTR_BC_STATUS, ++ .get = rt305x_esw_get_bc_status, ++ .set = rt305x_esw_set_bc_status, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "led_frequency", ++ .description = "LED Flash frequency (0:30mS, 1:60mS, 2:240mS, 3:480mS)", ++ .max = 3, ++ .id = RT305X_ESW_ATTR_LED_FREQ, ++ .get = rt305x_esw_get_led_freq, ++ .set = rt305x_esw_set_led_freq, ++ } ++}; ++ ++static const struct switch_attr esw_port[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "disable", ++ .description = "Port state (1:disabled)", ++ .max = 1, ++ .id = RT305X_ESW_ATTR_PORT_DISABLE, ++ .get = esw_get_port_bool, ++ .set = esw_set_port_bool, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "doubletag", ++ .description = "Double tagging for incoming vlan packets " ++ "(1:enabled)", ++ .max = 1, ++ .id = RT305X_ESW_ATTR_PORT_DOUBLETAG, ++ .get = esw_get_port_bool, ++ .set = esw_set_port_bool, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "untag", ++ .description = "Untag (1:strip outgoing vlan tag)", ++ .max = 1, ++ .id = RT305X_ESW_ATTR_PORT_UNTAG, ++ .get = esw_get_port_bool, ++ .set = esw_set_port_bool, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "led", ++ .description = "LED mode (0:link, 1:100m, 2:duplex, 3:activity," ++ " 4:collision, 5:linkact, 6:duplcoll, 7:10mact," ++ " 8:100mact, 10:blink, 11:off, 12:on)", ++ .max = 15, ++ .id = RT305X_ESW_ATTR_PORT_LED, ++ .get = esw_get_port_led, ++ .set = esw_set_port_led, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "lan", ++ .description = "HW port group (0:wan, 1:lan)", ++ .max = 1, ++ .id = RT305X_ESW_ATTR_PORT_LAN, ++ .get = esw_get_port_bool, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "recv_bad", ++ .description = "Receive bad packet counter", ++ .id = RT305X_ESW_ATTR_PORT_RECV_BAD, ++ .get = esw_get_port_recv_badgood, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "recv_good", ++ .description = "Receive good packet counter", ++ .id = RT305X_ESW_ATTR_PORT_RECV_GOOD, ++ .get = esw_get_port_recv_badgood, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "tr_bad", ++ ++ .description = "Transmit bad packet counter. rt5350 only", ++ .id = RT5350_ESW_ATTR_PORT_TR_BAD, ++ .get = esw_get_port_tr_badgood, ++ }, ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "tr_good", ++ ++ .description = "Transmit good packet counter. rt5350 only", ++ .id = RT5350_ESW_ATTR_PORT_TR_GOOD, ++ .get = esw_get_port_tr_badgood, ++ }, ++}; ++ ++static const struct switch_attr esw_vlan[] = { ++}; ++ ++static const struct switch_dev_ops esw_ops = { ++ .attr_global = { ++ .attr = esw_global, ++ .n_attr = ARRAY_SIZE(esw_global), ++ }, ++ .attr_port = { ++ .attr = esw_port, ++ .n_attr = ARRAY_SIZE(esw_port), ++ }, ++ .attr_vlan = { ++ .attr = esw_vlan, ++ .n_attr = ARRAY_SIZE(esw_vlan), ++ }, ++ .get_vlan_ports = esw_get_vlan_ports, ++ .set_vlan_ports = esw_set_vlan_ports, ++ .get_port_pvid = esw_get_port_pvid, ++ .set_port_pvid = esw_set_port_pvid, ++ .get_port_link = esw_get_port_link, ++ .apply_config = esw_apply_config, ++ .reset_switch = esw_reset_switch, ++}; ++ ++static struct rt305x_esw_platform_data rt3050_esw_data = { ++ /* All ports are LAN ports. */ ++ .vlan_config = RT305X_ESW_VLAN_CONFIG_NONE, ++ .reg_initval_fct2 = 0x00d6500c, ++ /* ++ * ext phy base addr 31, enable port 5 polling, rx/tx clock skew 1, ++ * turbo mii off, rgmi 3.3v off ++ * port5: disabled ++ * port6: enabled, gige, full-duplex, rx/tx-flow-control ++ */ ++ .reg_initval_fpa2 = 0x3f502b28, ++}; ++ ++static const struct of_device_id ralink_esw_match[] = { ++ { .compatible = "ralink,rt3050-esw", .data = &rt3050_esw_data }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ralink_esw_match); ++ ++static int esw_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ const struct rt305x_esw_platform_data *pdata; ++ const __be32 *port_map, *reg_init; ++ struct rt305x_esw *esw; ++ struct switch_dev *swdev; ++ struct resource *res, *irq; ++ int err; ++ ++ pdata = pdev->dev.platform_data; ++ if (!pdata) { ++ const struct of_device_id *match; ++ match = of_match_device(ralink_esw_match, &pdev->dev); ++ if (match) ++ pdata = (struct rt305x_esw_platform_data *) match->data; ++ } ++ if (!pdata) ++ return -EINVAL; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "no memory resource found\n"); ++ return -ENOMEM; ++ } ++ ++ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (!irq) { ++ dev_err(&pdev->dev, "no irq resource found\n"); ++ return -ENOMEM; ++ } ++ ++ esw = kzalloc(sizeof(struct rt305x_esw), GFP_KERNEL); ++ if (!esw) { ++ dev_err(&pdev->dev, "no memory for private data\n"); ++ return -ENOMEM; ++ } ++ ++ esw->dev = &pdev->dev; ++ esw->irq = irq->start; ++ esw->base = ioremap(res->start, resource_size(res)); ++ if (!esw->base) { ++ dev_err(&pdev->dev, "ioremap failed\n"); ++ err = -ENOMEM; ++ goto free_esw; ++ } ++ ++ port_map = of_get_property(np, "ralink,portmap", NULL); ++ if (port_map) ++ esw->port_map = be32_to_cpu(*port_map); ++ ++ reg_init = of_get_property(np, "ralink,fct2", NULL); ++ if (reg_init) ++ esw->reg_initval_fct2 = be32_to_cpu(*reg_init); ++ ++ reg_init = of_get_property(np, "ralink,fpa2", NULL); ++ if (reg_init) ++ esw->reg_initval_fpa2 = be32_to_cpu(*reg_init); ++ ++ reg_init = of_get_property(np, "ralink,led_polarity", NULL); ++ if (reg_init) ++ esw->reg_led_polarity = be32_to_cpu(*reg_init); ++ ++ swdev = &esw->swdev; ++ swdev->of_node = pdev->dev.of_node; ++ swdev->name = "rt305x-esw"; ++ swdev->alias = "rt305x"; ++ swdev->cpu_port = RT305X_ESW_PORT6; ++ swdev->ports = RT305X_ESW_NUM_PORTS; ++ swdev->vlans = RT305X_ESW_NUM_VIDS; ++ swdev->ops = &esw_ops; ++ ++ err = register_switch(swdev, NULL); ++ if (err < 0) { ++ dev_err(&pdev->dev, "register_switch failed\n"); ++ goto unmap_base; ++ } ++ ++ platform_set_drvdata(pdev, esw); ++ ++ esw->pdata = pdata; ++ spin_lock_init(&esw->reg_rw_lock); ++ ++ esw_hw_init(esw); ++ ++ esw_w32(esw, RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_ISR); ++ esw_w32(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR); ++ request_irq(esw->irq, esw_interrupt, 0, "esw", esw); ++ ++ return 0; ++ ++unmap_base: ++ iounmap(esw->base); ++free_esw: ++ kfree(esw); ++ return err; ++} ++ ++static int esw_remove(struct platform_device *pdev) ++{ ++ struct rt305x_esw *esw; ++ ++ esw = platform_get_drvdata(pdev); ++ if (esw) { ++ unregister_switch(&esw->swdev); ++ platform_set_drvdata(pdev, NULL); ++ iounmap(esw->base); ++ kfree(esw); ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver esw_driver = { ++ .probe = esw_probe, ++ .remove = esw_remove, ++ .driver = { ++ .name = "rt305x-esw", ++ .owner = THIS_MODULE, ++ .of_match_table = ralink_esw_match, ++ }, ++}; ++ ++int __init rtesw_init(void) ++{ ++ return platform_driver_register(&esw_driver); ++} ++ ++void rtesw_exit(void) ++{ ++ platform_driver_unregister(&esw_driver); ++} +diff --git a/drivers/net/ethernet/ralink/esw_rt3052.h b/drivers/net/ethernet/ralink/esw_rt3052.h +new file mode 100644 +index 0000000..2ced3dff +--- /dev/null ++++ b/drivers/net/ethernet/ralink/esw_rt3052.h +@@ -0,0 +1,32 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#ifndef _RALINK_ESW_RT3052_H__ ++#define _RALINK_ESW_RT3052_H__ ++ ++#ifdef CONFIG_NET_RALINK_ESW_RT3052 ++ ++int __init rtesw_init(void); ++void rtesw_exit(void); ++ ++#else ++ ++static inline int __init rtesw_init(void) { return 0; } ++static inline void rtesw_exit(void) { } ++ ++#endif ++#endif +diff --git a/drivers/net/ethernet/ralink/gsw_mt7620a.c b/drivers/net/ethernet/ralink/gsw_mt7620a.c +new file mode 100644 +index 0000000..9fa6a54 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/gsw_mt7620a.c +@@ -0,0 +1,1027 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/dma-mapping.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/etherdevice.h> ++#include <linux/ethtool.h> ++#include <linux/platform_device.h> ++#include <linux/of_device.h> ++#include <linux/clk.h> ++#include <linux/of_net.h> ++#include <linux/of_mdio.h> ++#include <linux/of_irq.h> ++#include <linux/of_address.h> ++#include <linux/switch.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#include "ralink_soc_eth.h" ++ ++#include <linux/ioport.h> ++#include <linux/switch.h> ++#include <linux/mii.h> ++ ++#include <ralink_regs.h> ++#include <asm/mach-ralink/mt7620.h> ++ ++#include "ralink_soc_eth.h" ++#include "gsw_mt7620a.h" ++#include "mdio.h" ++ ++#define GSW_REG_PHY_TIMEOUT (5 * HZ) ++ ++#define MT7620A_GSW_REG_PIAC 0x7004 ++ ++#define GSW_NUM_VLANS 16 ++#define GSW_NUM_VIDS 4096 ++#define GSW_NUM_PORTS 7 ++#define GSW_PORT6 6 ++ ++#define GSW_MDIO_ACCESS BIT(31) ++#define GSW_MDIO_READ BIT(19) ++#define GSW_MDIO_WRITE BIT(18) ++#define GSW_MDIO_START BIT(16) ++#define GSW_MDIO_ADDR_SHIFT 20 ++#define GSW_MDIO_REG_SHIFT 25 ++ ++#define GSW_REG_PORT_PMCR(x) (0x3000 + (x * 0x100)) ++#define GSW_REG_PORT_STATUS(x) (0x3008 + (x * 0x100)) ++#define GSW_REG_SMACCR0 0x3fE4 ++#define GSW_REG_SMACCR1 0x3fE8 ++#define GSW_REG_CKGCR 0x3ff0 ++ ++#define GSW_REG_IMR 0x7008 ++#define GSW_REG_ISR 0x700c ++ ++#define SYSC_REG_CFG1 0x14 ++ ++#define PORT_IRQ_ST_CHG 0x7f ++ ++#define GSW_VLAN_VTCR 0x90 ++#define GSW_VLAN_VTCR_VID_M 0xfff ++#define GSW_VLAN_ID(_x) (0x100 + (4 * (_x))) ++#define GSW_VLAN_ID_VID_S 12 ++#define GSW_VLAN_ID_VID_M 0xfff ++ ++#define GSW_VAWD1 0x94 ++#define GSW_VAWD1_VTAG_EN BIT(28) ++#define GSW_VAWD1_PORTM_S 16 ++#define GSW_VAWD1_PORTM_M 0xff ++ ++#define GSW_VAWD2 0x98 ++#define GSW_VAWD2_PORTT_S 16 ++#define GSW_VAWD2_PORTT_M 0xff ++ ++#define GSW_VTIM(_x) (0x100 + (4 * (_x))) ++#define GSW_VTIM_M 0xfff ++#define GSW_VTIM_S 12 ++ ++#define GSW_REG_PCR(x) (0x2004 + (x * 0x100)) ++#define GSW_REG_PCR_EG_TAG_S 28 ++#define GSW_REG_PCR_EG_TAG_M 0x3 ++ ++#define SYSCFG1 0x14 ++ ++#define ESW_PHY_POLLING 0x7000 ++ ++#define PMCR_IPG BIT(18) ++#define PMCR_MAC_MODE BIT(16) ++#define PMCR_FORCE BIT(15) ++#define PMCR_TX_EN BIT(14) ++#define PMCR_RX_EN BIT(13) ++#define PMCR_BACKOFF BIT(9) ++#define PMCR_BACKPRES BIT(8) ++#define PMCR_RX_FC BIT(5) ++#define PMCR_TX_FC BIT(4) ++#define PMCR_SPEED(_x) (_x << 2) ++#define PMCR_DUPLEX BIT(1) ++#define PMCR_LINK BIT(0) ++ ++#define PHY_AN_EN BIT(31) ++#define PHY_PRE_EN BIT(30) ++#define PMY_MDC_CONF(_x) ((_x & 0x3f) << 24) ++ ++enum { ++ /* Global attributes. */ ++ GSW_ATTR_ENABLE_VLAN, ++ /* Port attributes. */ ++ GSW_ATTR_PORT_UNTAG, ++}; ++ ++enum { ++ PORT4_EPHY = 0, ++ PORT4_EXT, ++}; ++ ++struct gsw_port { ++ bool disable; ++ bool untag; ++ u16 pvid; ++}; ++ ++struct gsw_vlan { ++ u8 ports; ++ u16 vid; ++}; ++ ++struct mt7620_gsw { ++ struct device *dev; ++ void __iomem *base; ++ int irq; ++ ++ struct switch_dev swdev; ++ bool global_vlan_enable; ++ struct gsw_vlan vlans[GSW_NUM_VLANS]; ++ struct gsw_port ports[GSW_NUM_PORTS]; ++ long unsigned int autopoll; ++ int port4; ++}; ++ ++static inline void gsw_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg) ++{ ++ iowrite32(val, gsw->base + reg); ++} ++ ++static inline u32 gsw_r32(struct mt7620_gsw *gsw, unsigned reg) ++{ ++ return ioread32(gsw->base + reg); ++} ++ ++static int mt7620_mii_busy_wait(struct mt7620_gsw *gsw) ++{ ++ unsigned long t_start = jiffies; ++ ++ while (1) { ++ if (!(gsw_r32(gsw, MT7620A_GSW_REG_PIAC) & GSW_MDIO_ACCESS)) ++ return 0; ++ if (time_after(jiffies, t_start + GSW_REG_PHY_TIMEOUT)) { ++ break; ++ } ++ } ++ ++ printk(KERN_ERR "mdio: MDIO timeout\n"); ++ return -1; ++} ++ ++static u32 _mt7620_mii_write(struct mt7620_gsw *gsw, u32 phy_addr, u32 phy_register, ++ u32 write_data) ++{ ++ if (mt7620_mii_busy_wait(gsw)) ++ return -1; ++ ++ write_data &= 0xffff; ++ ++ gsw_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_WRITE | ++ (phy_register << GSW_MDIO_REG_SHIFT) | ++ (phy_addr << GSW_MDIO_ADDR_SHIFT) | write_data, ++ MT7620A_GSW_REG_PIAC); ++ ++ if (mt7620_mii_busy_wait(gsw)) ++ return -1; ++ ++ return 0; ++} ++ ++int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val) ++{ ++ struct fe_priv *priv = bus->priv; ++ struct mt7620_gsw *gsw = (struct mt7620_gsw *) priv->soc->swpriv; ++ ++ return _mt7620_mii_write(gsw, phy_addr, phy_reg, val); ++} ++ ++int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) ++{ ++ struct fe_priv *priv = bus->priv; ++ struct mt7620_gsw *gsw = (struct mt7620_gsw *) priv->soc->swpriv; ++ u32 d; ++ ++ if (mt7620_mii_busy_wait(gsw)) ++ return 0xffff; ++ ++ gsw_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_READ | ++ (phy_reg << GSW_MDIO_REG_SHIFT) | ++ (phy_addr << GSW_MDIO_ADDR_SHIFT), ++ MT7620A_GSW_REG_PIAC); ++ ++ if (mt7620_mii_busy_wait(gsw)) ++ return 0xffff; ++ ++ d = gsw_r32(gsw, MT7620A_GSW_REG_PIAC) & 0xffff; ++ ++ return d; ++} ++ ++static unsigned char *fe_speed_str(int speed) ++{ ++ switch (speed) { ++ case 2: ++ case SPEED_1000: ++ return "1000"; ++ case 1: ++ case SPEED_100: ++ return "100"; ++ case 0: ++ case SPEED_10: ++ return "10"; ++ } ++ ++ return "? "; ++} ++ ++int mt7620a_has_carrier(struct fe_priv *priv) ++{ ++ struct mt7620_gsw *gsw = (struct mt7620_gsw *) priv->soc->swpriv; ++ int i; ++ ++ for (i = 0; i < GSW_PORT6; i++) ++ if (gsw_r32(gsw, GSW_REG_PORT_STATUS(i)) & 0x1) ++ return 1; ++ return 0; ++} ++ ++static void mt7620a_handle_carrier(struct fe_priv *priv) ++{ ++ if (!priv->phy) ++ return; ++ ++ if (mt7620a_has_carrier(priv)) ++ netif_carrier_on(priv->netdev); ++ else ++ netif_carrier_off(priv->netdev); ++} ++ ++void mt7620_mdio_link_adjust(struct fe_priv *priv, int port) ++{ ++ if (priv->link[port]) ++ netdev_info(priv->netdev, "port %d link up (%sMbps/%s duplex)\n", ++ port, fe_speed_str(priv->phy->speed[port]), ++ (DUPLEX_FULL == priv->phy->duplex[port]) ? "Full" : "Half"); ++ else ++ netdev_info(priv->netdev, "port %d link down\n", port); ++ mt7620a_handle_carrier(priv); ++} ++ ++static irqreturn_t gsw_interrupt(int irq, void *_priv) ++{ ++ struct fe_priv *priv = (struct fe_priv *) _priv; ++ struct mt7620_gsw *gsw = (struct mt7620_gsw *) priv->soc->swpriv; ++ u32 status; ++ int i, max = (gsw->port4 == PORT4_EPHY) ? (4) : (3); ++ ++ status = gsw_r32(gsw, GSW_REG_ISR); ++ if (status & PORT_IRQ_ST_CHG) ++ for (i = 0; i <= max; i++) { ++ u32 status = gsw_r32(gsw, GSW_REG_PORT_STATUS(i)); ++ int link = status & 0x1; ++ ++ if (link != priv->link[i]) { ++ if (link) ++ netdev_info(priv->netdev, "port %d link up (%sMbps/%s duplex)\n", ++ i, fe_speed_str((status >> 2) & 3), ++ (status & 0x2) ? "Full" : "Half"); ++ else ++ netdev_info(priv->netdev, "port %d link down\n", i); ++ } ++ ++ priv->link[i] = link; ++ } ++ mt7620a_handle_carrier(priv); ++ ++ gsw_w32(gsw, status, GSW_REG_ISR); ++ ++ return IRQ_HANDLED; ++} ++ ++static int mt7620_is_bga(void) ++{ ++ u32 bga = rt_sysc_r32(0x0c); ++ ++ return (bga >> 16) & 1; ++} ++ ++static void gsw_auto_poll(struct mt7620_gsw *gsw) ++{ ++ int phy; ++ int lsb = -1, msb = 0; ++ ++ for_each_set_bit(phy, &gsw->autopoll, 32) { ++ if (lsb < 0) ++ lsb = phy; ++ msb = phy; ++ } ++ ++ gsw_w32(gsw, PHY_AN_EN | PHY_PRE_EN | PMY_MDC_CONF(5) | (msb << 8) | lsb, ESW_PHY_POLLING); ++} ++ ++void mt7620_port_init(struct fe_priv *priv, struct device_node *np) ++{ ++ struct mt7620_gsw *gsw = (struct mt7620_gsw *) priv->soc->swpriv; ++ const __be32 *_id = of_get_property(np, "reg", NULL); ++ int phy_mode, size, id; ++ int shift = 12; ++ u32 val, mask = 0; ++ int min = (gsw->port4 == PORT4_EPHY) ? (5) : (4); ++ ++ if (!_id || (be32_to_cpu(*_id) < min) || (be32_to_cpu(*_id) > 5)) { ++ if (_id) ++ pr_err("%s: invalid port id %d\n", np->name, be32_to_cpu(*_id)); ++ else ++ pr_err("%s: invalid port id\n", np->name); ++ return; ++ } ++ ++ id = be32_to_cpu(*_id); ++ ++ if (id == 4) ++ shift = 14; ++ ++ priv->phy->phy_fixed[id] = of_get_property(np, "ralink,fixed-link", &size); ++ if (priv->phy->phy_fixed[id] && (size != (4 * sizeof(*priv->phy->phy_fixed[id])))) { ++ pr_err("%s: invalid fixed link property\n", np->name); ++ priv->phy->phy_fixed[id] = NULL; ++ return; ++ } ++ ++ phy_mode = of_get_phy_mode(np); ++ switch (phy_mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ mask = 0; ++ break; ++ case PHY_INTERFACE_MODE_MII: ++ mask = 1; ++ break; ++ case PHY_INTERFACE_MODE_RMII: ++ mask = 2; ++ break; ++ default: ++ dev_err(priv->device, "port %d - invalid phy mode\n", priv->phy->speed[id]); ++ return; ++ } ++ ++ priv->phy->phy_node[id] = of_parse_phandle(np, "phy-handle", 0); ++ if (!priv->phy->phy_node[id] && !priv->phy->phy_fixed[id]) ++ return; ++ ++ val = rt_sysc_r32(SYSCFG1); ++ val &= ~(3 << shift); ++ val |= mask << shift; ++ rt_sysc_w32(val, SYSCFG1); ++ ++ if (priv->phy->phy_fixed[id]) { ++ const __be32 *link = priv->phy->phy_fixed[id]; ++ int tx_fc = be32_to_cpup(link++); ++ int rx_fc = be32_to_cpup(link++); ++ u32 val = 0; ++ ++ priv->phy->speed[id] = be32_to_cpup(link++); ++ priv->phy->duplex[id] = be32_to_cpup(link++); ++ priv->link[id] = 1; ++ ++ switch (priv->phy->speed[id]) { ++ case SPEED_10: ++ val = 0; ++ break; ++ case SPEED_100: ++ val = 1; ++ break; ++ case SPEED_1000: ++ val = 2; ++ break; ++ default: ++ dev_err(priv->device, "invalid link speed: %d\n", priv->phy->speed[id]); ++ priv->phy->phy_fixed[id] = 0; ++ return; ++ } ++ val = PMCR_SPEED(val); ++ val |= PMCR_LINK | PMCR_BACKPRES | PMCR_BACKOFF | PMCR_RX_EN | ++ PMCR_TX_EN | PMCR_FORCE | PMCR_MAC_MODE | PMCR_IPG; ++ if (tx_fc) ++ val |= PMCR_TX_FC; ++ if (rx_fc) ++ val |= PMCR_RX_FC; ++ if (priv->phy->duplex[id]) ++ val |= PMCR_DUPLEX; ++ gsw_w32(gsw, val, GSW_REG_PORT_PMCR(id)); ++ dev_info(priv->device, "using fixed link parameters\n"); ++ return; ++ } ++ ++ if (priv->phy->phy_node[id] && priv->mii_bus->phy_map[id]) { ++ u32 val = PMCR_BACKPRES | PMCR_BACKOFF | PMCR_RX_EN | ++ PMCR_TX_EN | PMCR_MAC_MODE | PMCR_IPG; ++ ++ gsw_w32(gsw, val, GSW_REG_PORT_PMCR(id)); ++ fe_connect_phy_node(priv, priv->phy->phy_node[id]); ++ gsw->autopoll |= BIT(id); ++ gsw_auto_poll(gsw); ++ return; ++ } ++} ++ ++static void gsw_hw_init(struct mt7620_gsw *gsw) ++{ ++ u32 is_BGA = mt7620_is_bga(); ++ ++ rt_sysc_w32(rt_sysc_r32(SYSC_REG_CFG1) | BIT(8), SYSC_REG_CFG1); ++ gsw_w32(gsw, gsw_r32(gsw, GSW_REG_CKGCR) & ~(0x3 << 4), GSW_REG_CKGCR); ++ ++ /*correct PHY setting L3.0 BGA*/ ++ _mt7620_mii_write(gsw, 1, 31, 0x4000); //global, page 4 ++ ++ _mt7620_mii_write(gsw, 1, 17, 0x7444); ++ if (is_BGA) ++ _mt7620_mii_write(gsw, 1, 19, 0x0114); ++ else ++ _mt7620_mii_write(gsw, 1, 19, 0x0117); ++ ++ _mt7620_mii_write(gsw, 1, 22, 0x10cf); ++ _mt7620_mii_write(gsw, 1, 25, 0x6212); ++ _mt7620_mii_write(gsw, 1, 26, 0x0777); ++ _mt7620_mii_write(gsw, 1, 29, 0x4000); ++ _mt7620_mii_write(gsw, 1, 28, 0xc077); ++ _mt7620_mii_write(gsw, 1, 24, 0x0000); ++ ++ _mt7620_mii_write(gsw, 1, 31, 0x3000); //global, page 3 ++ _mt7620_mii_write(gsw, 1, 17, 0x4838); ++ ++ _mt7620_mii_write(gsw, 1, 31, 0x2000); //global, page 2 ++ if (is_BGA) { ++ _mt7620_mii_write(gsw, 1, 21, 0x0515); ++ _mt7620_mii_write(gsw, 1, 22, 0x0053); ++ _mt7620_mii_write(gsw, 1, 23, 0x00bf); ++ _mt7620_mii_write(gsw, 1, 24, 0x0aaf); ++ _mt7620_mii_write(gsw, 1, 25, 0x0fad); ++ _mt7620_mii_write(gsw, 1, 26, 0x0fc1); ++ } else { ++ _mt7620_mii_write(gsw, 1, 21, 0x0517); ++ _mt7620_mii_write(gsw, 1, 22, 0x0fd2); ++ _mt7620_mii_write(gsw, 1, 23, 0x00bf); ++ _mt7620_mii_write(gsw, 1, 24, 0x0aab); ++ _mt7620_mii_write(gsw, 1, 25, 0x00ae); ++ _mt7620_mii_write(gsw, 1, 26, 0x0fff); ++ } ++ _mt7620_mii_write(gsw, 1, 31, 0x1000); //global, page 1 ++ _mt7620_mii_write(gsw, 1, 17, 0xe7f8); ++ ++ _mt7620_mii_write(gsw, 1, 31, 0x8000); //local, page 0 ++ _mt7620_mii_write(gsw, 0, 30, 0xa000); ++ _mt7620_mii_write(gsw, 1, 30, 0xa000); ++ _mt7620_mii_write(gsw, 2, 30, 0xa000); ++ _mt7620_mii_write(gsw, 3, 30, 0xa000); ++ ++ _mt7620_mii_write(gsw, 0, 4, 0x05e1); ++ _mt7620_mii_write(gsw, 1, 4, 0x05e1); ++ _mt7620_mii_write(gsw, 2, 4, 0x05e1); ++ _mt7620_mii_write(gsw, 3, 4, 0x05e1); ++ _mt7620_mii_write(gsw, 1, 31, 0xa000); //local, page 2 ++ _mt7620_mii_write(gsw, 0, 16, 0x1111); ++ _mt7620_mii_write(gsw, 1, 16, 0x1010); ++ _mt7620_mii_write(gsw, 2, 16, 0x1515); ++ _mt7620_mii_write(gsw, 3, 16, 0x0f0f); ++ ++ /* CPU Port6 Force Link 1G, FC ON */ ++ gsw_w32(gsw, 0x5e33b, GSW_REG_PORT_PMCR(6)); ++ /* Set Port6 CPU Port */ ++ gsw_w32(gsw, 0x7f7f7fe0, 0x0010); ++ ++// GSW_VAWD2 ++ ++ /* setup port 4 */ ++ if (gsw->port4 == PORT4_EPHY) { ++ u32 val = rt_sysc_r32(SYSCFG1); ++ val |= 3 << 14; ++ rt_sysc_w32(val, SYSCFG1); ++ _mt7620_mii_write(gsw, 4, 30, 0xa000); ++ _mt7620_mii_write(gsw, 4, 4, 0x05e1); ++ _mt7620_mii_write(gsw, 4, 16, 0x1313); ++ pr_info("gsw: setting port4 to ephy mode\n"); ++ } ++} ++ ++static int gsw_reset_switch(struct switch_dev *dev) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ ++ gsw->global_vlan_enable = 0; ++ memset(gsw->ports, 0, sizeof(gsw->ports)); ++ memset(gsw->vlans, 0, sizeof(gsw->vlans)); ++ gsw_hw_init(gsw); ++ ++ return 0; ++} ++ ++static int gsw_get_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ ++ val->value.i = gsw->global_vlan_enable; ++ ++ return 0; ++} ++ ++static int gsw_set_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ ++ gsw->global_vlan_enable = val->value.i != 0; ++ ++ return 0; ++} ++ ++static unsigned gsw_get_pvid(struct mt7620_gsw *gsw, unsigned port) ++{ ++ unsigned s, val; ++ ++ s = GSW_VTIM_S * (port % 2); ++ val = gsw_r32(gsw, GSW_VTIM(port / 2)); ++ ++ return (val >> s) & GSW_VTIM_M; ++} ++ ++static void gsw_set_pvid(struct mt7620_gsw *gsw, unsigned port, unsigned pvid) ++{ ++ unsigned s, val; ++ ++ s = GSW_VTIM_S * (port % 2); ++ val = gsw_r32(gsw, GSW_VTIM(port / 2)); ++ val &= ~(GSW_VTIM_M << s); ++ val |= (pvid && GSW_VTIM_M) << s; ++ gsw_w32(gsw, val, GSW_VTIM(port / 2)); ++} ++ ++static int gsw_get_port_bool(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ int idx = val->port_vlan; ++ ++ if (idx < 0 || idx >= GSW_NUM_PORTS) ++ return -EINVAL; ++ ++ switch (attr->id) { ++ case GSW_ATTR_PORT_UNTAG: ++ return gsw->ports[idx].untag; ++ } ++ ++ return -EINVAL; ++} ++ ++static int gsw_get_port_pvid(struct switch_dev *dev, int port, int *val) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ ++ if (port >= GSW_NUM_PORTS) ++ return -EINVAL; ++ ++ *val = gsw_get_pvid(gsw, port); ++ ++ return 0; ++} ++ ++static int gsw_set_port_pvid(struct switch_dev *dev, int port, int val) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ ++ if (port >= GSW_NUM_PORTS) ++ return -EINVAL; ++ ++ gsw->ports[port].pvid = val; ++ ++ return 0; ++} ++ ++static void gsw_set_vtcr(struct switch_dev *dev, u32 vid) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ int retry = 1000; ++ ++ gsw_w32(gsw, 0x80000000 | (BIT(vid) & GSW_VLAN_VTCR_VID_M), GSW_VLAN_VTCR); ++ while (retry-- && (gsw_r32(gsw, GSW_VLAN_VTCR) & 0x80000000)) ++ ; ++} ++ ++static void gsw_apply_vtcr(struct switch_dev *dev, u32 vid) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ int retry = 1000; ++ ++ gsw_w32(gsw, 0x80001000 | (BIT(vid) & GSW_VLAN_VTCR_VID_M), GSW_VLAN_VTCR); ++ while (retry-- && (gsw_r32(gsw, GSW_VLAN_VTCR) & 0x80000000)) ++ ; ++} ++ ++static unsigned gsw_get_vlan_id(struct mt7620_gsw *gsw, unsigned vlan) ++{ ++ unsigned s; ++ unsigned val; ++ ++ s = GSW_VLAN_ID_VID_S * (vlan % 2); ++ val = gsw_r32(gsw, GSW_VLAN_ID(vlan / 2)); ++ val = (val >> s) & GSW_VLAN_ID_VID_M; ++ ++ return val; ++} ++ ++static void gsw_set_vlan_id(struct mt7620_gsw *gsw, unsigned vlan, unsigned vid) ++{ ++ unsigned s; ++ unsigned val; ++ ++ s = GSW_VLAN_ID_VID_S * (vlan % 2); ++ val = gsw_r32(gsw, GSW_VLAN_ID(vlan / 2)); ++ val &= ~(GSW_VLAN_ID_VID_M << s); ++ val |= (vid << s); ++ gsw_w32(gsw, val, GSW_VLAN_ID(vlan / 2)); ++} ++ ++static void gsw_vlan_tagging_enable(struct mt7620_gsw *gsw, unsigned vlan, unsigned enable) ++{ ++ unsigned val; ++ ++ val = gsw_r32(gsw, GSW_VAWD1); ++ if (enable) ++ val |= GSW_VAWD1_VTAG_EN; ++ else ++ val &= ~GSW_VAWD1_VTAG_EN; ++ gsw_w32(gsw, val, GSW_VAWD1); ++} ++ ++static unsigned gsw_get_port_member(struct mt7620_gsw *gsw, unsigned vlan) ++{ ++ unsigned val; ++ ++ gsw_set_vtcr(&gsw->swdev, vlan); ++ ++ val = gsw_r32(gsw, GSW_VAWD1); ++ val = (val >> GSW_VAWD1_PORTM_S) & GSW_VAWD1_PORTM_M; ++ ++ return val; ++} ++ ++static void gsw_set_port_member(struct mt7620_gsw *gsw, unsigned vlan, unsigned member) ++{ ++ unsigned val; ++ ++ val = gsw_r32(gsw, GSW_VAWD1); ++ val = ~(GSW_VAWD1_PORTM_M << GSW_VAWD1_PORTM_S); ++ val |= (member & GSW_VAWD1_PORTM_M) << GSW_VAWD1_PORTM_S; ++ gsw_w32(gsw, val, GSW_VAWD1); ++} ++ ++static unsigned gsw_get_port_tag(struct mt7620_gsw *gsw, unsigned port) ++{ ++ unsigned val; ++ ++ val = gsw_r32(gsw, GSW_REG_PCR(port)); ++ val >>= GSW_REG_PCR_EG_TAG_S; ++ val &= GSW_REG_PCR_EG_TAG_M; ++ ++ return !!val; ++} ++ ++static void gsw_set_port_untag(struct mt7620_gsw *gsw, unsigned port, unsigned untag) ++{ ++ unsigned val; ++ ++ val = gsw_r32(gsw, GSW_REG_PCR(port)); ++ if (!untag) ++ untag = 0x2; ++ else ++ untag = 0; ++ val &= ~(GSW_REG_PCR_EG_TAG_M << GSW_REG_PCR_EG_TAG_S); ++ val |= (untag & GSW_REG_PCR_EG_TAG_M) << GSW_REG_PCR_EG_TAG_S; ++ gsw_w32(gsw, val, GSW_REG_PCR(port)); ++} ++ ++static int gsw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ int vlan_idx = -1; ++ u32 member; ++ int i; ++ ++ val->len = 0; ++ ++ if (val->port_vlan < 0 || val->port_vlan >= GSW_NUM_VIDS) ++ return -EINVAL; ++ ++ /* valid vlan? */ ++ for (i = 0; i < GSW_NUM_VLANS; i++) { ++ if (gsw_get_vlan_id(gsw, i) != val->port_vlan) ++ continue; ++ member = gsw_get_port_member(gsw, i); ++ vlan_idx = i; ++ break; ++ } ++ ++ if (vlan_idx == -1) ++ return -EINVAL; ++ ++ for (i = 0; i < GSW_NUM_PORTS; i++) { ++ struct switch_port *p; ++ int port_mask = 1 << i; ++ ++ if (!(member & port_mask)) ++ continue; ++ ++ p = &val->value.ports[val->len++]; ++ p->id = i; ++ if (gsw_get_port_tag(gsw, i)) ++ p->flags = 1 << SWITCH_PORT_FLAG_TAGGED; ++ else ++ p->flags = 0; ++ } ++ ++ return 0; ++} ++ ++static int gsw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ int ports; ++ int vlan_idx = -1; ++ int i; ++ ++ if (val->port_vlan < 0 || val->port_vlan >= GSW_NUM_VIDS || ++ val->len > GSW_NUM_PORTS) ++ return -EINVAL; ++ ++ /* one of the already defined vlans? */ ++ for (i = 0; i < GSW_NUM_VLANS; i++) { ++ if (gsw->vlans[i].vid == val->port_vlan && ++ gsw->vlans[i].ports) { ++ vlan_idx = i; ++ break; ++ } ++ } ++ ++ /* select a free slot */ ++ for (i = 0; vlan_idx == -1 && i < GSW_NUM_VLANS; i++) { ++ if (!gsw->vlans[i].ports) ++ vlan_idx = i; ++ } ++ ++ /* bail if all slots are in use */ ++ if (vlan_idx == -1) ++ return -EINVAL; ++ ++ ports = 0; ++ for (i = 0; i < val->len; i++) { ++ struct switch_port *p = &val->value.ports[i]; ++ int port_mask = 1 << p->id; ++ bool untagged = !(p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)); ++ ++ if (p->id >= GSW_NUM_PORTS) ++ return -EINVAL; ++ ++ ports |= port_mask; ++ gsw->ports[p->id].untag = untagged; ++ } ++ gsw->vlans[vlan_idx].ports = ports; ++ if (!ports) ++ gsw->vlans[vlan_idx].vid = 0xfff; ++ else ++ gsw->vlans[vlan_idx].vid = val->port_vlan; ++ ++ return 0; ++} ++ ++static int gsw_apply_config(struct switch_dev *dev) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ int i; ++ ++ for (i = 0; i < GSW_NUM_VLANS; i++) { ++ gsw_set_vtcr(&gsw->swdev, i); ++ if (gsw->global_vlan_enable) { ++ gsw_set_vlan_id(gsw, i, gsw->vlans[i].vid); ++ gsw_set_port_member(gsw, i, gsw->vlans[i].ports); ++ gsw_vlan_tagging_enable(gsw, i, 1); ++ } else { ++ gsw_set_vlan_id(gsw, i, 0xfff); ++ gsw_set_port_member(gsw, i, 0); ++ gsw_vlan_tagging_enable(gsw, i, 0); ++ } ++ gsw_apply_vtcr(&gsw->swdev, i); ++ } ++ ++ for (i = 0; i < GSW_NUM_PORTS; i++) { ++ if (gsw->global_vlan_enable) { ++ gsw_set_port_untag(gsw, i, !gsw->ports[i].untag); ++ gsw_set_pvid(gsw, i, gsw->ports[i].pvid); ++ } else { ++ gsw_set_port_untag(gsw, i, 0); ++ gsw_set_pvid(gsw, i, 0); ++ } ++ } ++ ++ if (!gsw->global_vlan_enable) ++ gsw_set_vlan_id(gsw, 0, 0); ++ ++ return 0; ++} ++ ++static int gsw_get_port_link(struct switch_dev *dev, ++ int port, ++ struct switch_port_link *link) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ u32 status; ++ ++ if (port < 0 || port >= GSW_NUM_PORTS) ++ return -EINVAL; ++ ++ status = gsw_r32(gsw, GSW_REG_PORT_STATUS(port)); ++ link->link = status & 0x1; ++ link->duplex = (status >> 1) & 1; ++ ++ switch ((status >> 2) & 0x3) { ++ case 0: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case 1: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case 2: ++ case 3: // forced gige speed can be 2 or 3 ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ } ++ ++ return 0; ++} ++ ++static int gsw_set_port_bool(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct mt7620_gsw *gsw = container_of(dev, struct mt7620_gsw, swdev); ++ int idx = val->port_vlan; ++ ++ if (idx < 0 || idx >= GSW_NUM_PORTS || ++ val->value.i < 0 || val->value.i > 1) ++ return -EINVAL; ++ ++ switch (attr->id) { ++ case GSW_ATTR_PORT_UNTAG: ++ gsw->ports[idx].untag = val->value.i; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct switch_attr gsw_global[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "VLAN mode (1:enabled)", ++ .max = 1, ++ .id = GSW_ATTR_ENABLE_VLAN, ++ .get = gsw_get_vlan_enable, ++ .set = gsw_set_vlan_enable, ++ }, ++}; ++ ++static const struct switch_attr gsw_port[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "untag", ++ .description = "Untag (1:strip outgoing vlan tag)", ++ .max = 1, ++ .id = GSW_ATTR_PORT_UNTAG, ++ .get = gsw_get_port_bool, ++ .set = gsw_set_port_bool, ++ }, ++}; ++ ++static const struct switch_attr gsw_vlan[] = { ++}; ++ ++static const struct switch_dev_ops gsw_ops = { ++ .attr_global = { ++ .attr = gsw_global, ++ .n_attr = ARRAY_SIZE(gsw_global), ++ }, ++ .attr_port = { ++ .attr = gsw_port, ++ .n_attr = ARRAY_SIZE(gsw_port), ++ }, ++ .attr_vlan = { ++ .attr = gsw_vlan, ++ .n_attr = ARRAY_SIZE(gsw_vlan), ++ }, ++ .get_vlan_ports = gsw_get_vlan_ports, ++ .set_vlan_ports = gsw_set_vlan_ports, ++ .get_port_pvid = gsw_get_port_pvid, ++ .set_port_pvid = gsw_set_port_pvid, ++ .get_port_link = gsw_get_port_link, ++ .apply_config = gsw_apply_config, ++ .reset_switch = gsw_reset_switch, ++}; ++ ++void mt7620_set_mac(struct fe_priv *priv, unsigned char *mac) ++{ ++ struct mt7620_gsw *gsw = (struct mt7620_gsw *) priv->soc->swpriv; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->page_lock, flags); ++ gsw_w32(gsw, (mac[0] << 8) | mac[1], GSW_REG_SMACCR1); ++ gsw_w32(gsw, (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], ++ GSW_REG_SMACCR0); ++ spin_unlock_irqrestore(&priv->page_lock, flags); ++} ++ ++static struct of_device_id gsw_match[] = { ++ { .compatible = "ralink,mt7620a-gsw" }, ++ {} ++}; ++ ++int mt7620_gsw_probe(struct fe_priv *priv) ++{ ++ struct mt7620_gsw *gsw; ++ struct device_node *np; ++ struct switch_dev *swdev; ++ const char *port4 = NULL; ++ ++ np = of_find_matching_node(NULL, gsw_match); ++ if (!np) { ++ dev_err(priv->device, "no gsw node found\n"); ++ return -EINVAL; ++ } ++ np = of_node_get(np); ++ ++ gsw = devm_kzalloc(priv->device, sizeof(struct mt7620_gsw), GFP_KERNEL); ++ if (!gsw) { ++ dev_err(priv->device, "no gsw memory for private data\n"); ++ return -ENOMEM; ++ } ++ ++ gsw->irq = irq_of_parse_and_map(np, 0); ++ if (!gsw->irq) { ++ dev_err(priv->device, "no gsw irq resource found\n"); ++ return -ENOMEM; ++ } ++ ++ gsw->base = of_iomap(np, 0); ++ if (!gsw->base) { ++ dev_err(priv->device, "gsw ioremap failed\n"); ++ } ++ ++ gsw->dev = priv->device; ++ priv->soc->swpriv = gsw; ++ ++ swdev = &gsw->swdev; ++ swdev->of_node = np; ++ swdev->name = "mt7620a-gsw"; ++ swdev->alias = "mt7620x"; ++ swdev->cpu_port = GSW_PORT6; ++ swdev->ports = GSW_NUM_PORTS; ++ swdev->vlans = GSW_NUM_VLANS; ++ swdev->ops = &gsw_ops; ++ ++ if (register_switch(swdev, NULL)) ++ dev_err(priv->device, "register_switch failed\n"); ++ ++ of_property_read_string(np, "ralink,port4", &port4); ++ if (port4 && !strcmp(port4, "ephy")) ++ gsw->port4 = PORT4_EPHY; ++ else if (port4 && !strcmp(port4, "gmac")) ++ gsw->port4 = PORT4_EXT; ++ else ++ WARN_ON(port4); ++ ++ gsw_hw_init(gsw); ++ ++ gsw_w32(gsw, ~PORT_IRQ_ST_CHG, GSW_REG_IMR); ++ request_irq(gsw->irq, gsw_interrupt, 0, "gsw", priv); ++ ++ return 0; ++} +diff --git a/drivers/net/ethernet/ralink/gsw_mt7620a.h b/drivers/net/ethernet/ralink/gsw_mt7620a.h +new file mode 100644 +index 0000000..fd4add5 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/gsw_mt7620a.h +@@ -0,0 +1,29 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#ifndef _RALINK_GSW_MT7620_H__ ++#define _RALINK_GSW_MT7620_H__ ++ ++extern int mt7620_gsw_probe(struct fe_priv *priv); ++extern void mt7620_set_mac(struct fe_priv *priv, unsigned char *mac); ++extern int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val); ++extern int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg); ++extern void mt7620_mdio_link_adjust(struct fe_priv *priv, int port); ++extern void mt7620_port_init(struct fe_priv *priv, struct device_node *np); ++extern int mt7620a_has_carrier(struct fe_priv *priv); ++ ++#endif +diff --git a/drivers/net/ethernet/ralink/mdio.c b/drivers/net/ethernet/ralink/mdio.c +new file mode 100644 +index 0000000..b265c75 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/mdio.c +@@ -0,0 +1,245 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/dma-mapping.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/etherdevice.h> ++#include <linux/ethtool.h> ++#include <linux/platform_device.h> ++#include <linux/phy.h> ++#include <linux/of_device.h> ++#include <linux/clk.h> ++#include <linux/of_net.h> ++#include <linux/of_mdio.h> ++ ++#include "ralink_soc_eth.h" ++#include "mdio.h" ++ ++static int fe_mdio_reset(struct mii_bus *bus) ++{ ++ /* TODO */ ++ return 0; ++} ++ ++static void fe_phy_link_adjust(struct net_device *dev) ++{ ++ struct fe_priv *priv = netdev_priv(dev); ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&priv->phy->lock, flags); ++ for (i = 0; i < 8; i++) { ++ if (priv->phy->phy_node[i]) { ++ struct phy_device *phydev = priv->phy->phy[i]; ++ int status_change = 0; ++ ++ if (phydev->link) ++ if (priv->phy->duplex[i] != phydev->duplex || ++ priv->phy->speed[i] != phydev->speed) ++ status_change = 1; ++ ++ if (phydev->link != priv->link[i]) ++ status_change = 1; ++ ++ switch (phydev->speed) { ++ case SPEED_1000: ++ case SPEED_100: ++ case SPEED_10: ++ priv->link[i] = phydev->link; ++ priv->phy->duplex[i] = phydev->duplex; ++ priv->phy->speed[i] = phydev->speed; ++ ++ if (status_change && priv->soc->mdio_adjust_link) ++ priv->soc->mdio_adjust_link(priv, i); ++ break; ++ } ++ } ++ } ++ spin_unlock_irqrestore(&priv->phy->lock, flags); ++} ++ ++int fe_connect_phy_node(struct fe_priv *priv, struct device_node *phy_node) ++{ ++ const __be32 *_port = NULL; ++ struct phy_device *phydev; ++ int phy_mode, port; ++ ++ _port = of_get_property(phy_node, "reg", NULL); ++ ++ if (!_port || (be32_to_cpu(*_port) >= 8)) { ++ pr_err("%s: invalid port id\n", phy_node->name); ++ return -EINVAL; ++ } ++ port = be32_to_cpu(*_port); ++ phy_mode = of_get_phy_mode(phy_node); ++ if (phy_mode < 0) { ++ dev_err(priv->device, "incorrect phy-mode %d\n", phy_mode); ++ priv->phy->phy_node[port] = NULL; ++ return -EINVAL; ++ } ++ ++ phydev = of_phy_connect(priv->netdev, phy_node, fe_phy_link_adjust, ++ 0, phy_mode); ++ if (IS_ERR(phydev)) { ++ dev_err(priv->device, "could not connect to PHY\n"); ++ priv->phy->phy_node[port] = NULL; ++ return PTR_ERR(phydev); ++ } ++ ++ phydev->supported &= PHY_GBIT_FEATURES; ++ phydev->advertising = phydev->supported; ++ phydev->no_auto_carrier_off = 1; ++ ++ dev_info(priv->device, ++ "connected port %d to PHY at %s [uid=%08x, driver=%s]\n", ++ port, dev_name(&phydev->dev), phydev->phy_id, ++ phydev->drv->name); ++ ++ priv->phy->phy[port] = phydev; ++ priv->link[port] = 0; ++ ++ return 0; ++} ++ ++static int fe_phy_connect(struct fe_priv *priv) ++{ ++ return 0; ++} ++ ++static void fe_phy_disconnect(struct fe_priv *priv) ++{ ++ unsigned long flags; ++ int i; ++ ++ for (i = 0; i < 8; i++) ++ if (priv->phy->phy_fixed[i]) { ++ spin_lock_irqsave(&priv->phy->lock, flags); ++ priv->link[i] = 0; ++ if (priv->soc->mdio_adjust_link) ++ priv->soc->mdio_adjust_link(priv, i); ++ spin_unlock_irqrestore(&priv->phy->lock, flags); ++ } else if (priv->phy->phy[i]) { ++ phy_disconnect(priv->phy->phy[i]); ++ } ++} ++ ++static void fe_phy_start(struct fe_priv *priv) ++{ ++ unsigned long flags; ++ int i; ++ ++ for (i = 0; i < 8; i++) { ++ if (priv->phy->phy_fixed[i]) { ++ spin_lock_irqsave(&priv->phy->lock, flags); ++ priv->link[i] = 1; ++ if (priv->soc->mdio_adjust_link) ++ priv->soc->mdio_adjust_link(priv, i); ++ spin_unlock_irqrestore(&priv->phy->lock, flags); ++ } else if (priv->phy->phy[i]) { ++ phy_start(priv->phy->phy[i]); ++ } ++ } ++} ++ ++static void fe_phy_stop(struct fe_priv *priv) ++{ ++ unsigned long flags; ++ int i; ++ ++ for (i = 0; i < 8; i++) ++ if (priv->phy->phy_fixed[i]) { ++ spin_lock_irqsave(&priv->phy->lock, flags); ++ priv->link[i] = 0; ++ if (priv->soc->mdio_adjust_link) ++ priv->soc->mdio_adjust_link(priv, i); ++ spin_unlock_irqrestore(&priv->phy->lock, flags); ++ } else if (priv->phy->phy[i]) { ++ phy_stop(priv->phy->phy[i]); ++ } ++} ++ ++static struct fe_phy phy_ralink = { ++ .connect = fe_phy_connect, ++ .disconnect = fe_phy_disconnect, ++ .start = fe_phy_start, ++ .stop = fe_phy_stop, ++}; ++ ++int fe_mdio_init(struct fe_priv *priv) ++{ ++ struct device_node *mii_np; ++ int err; ++ ++ if (!priv->soc->mdio_read || !priv->soc->mdio_write) ++ return 0; ++ ++ spin_lock_init(&phy_ralink.lock); ++ priv->phy = &phy_ralink; ++ ++ mii_np = of_get_child_by_name(priv->device->of_node, "mdio-bus"); ++ if (!mii_np) { ++ dev_err(priv->device, "no %s child node found", "mdio-bus"); ++ return -ENODEV; ++ } ++ ++ if (!of_device_is_available(mii_np)) { ++ err = 0; ++ goto err_put_node; ++ } ++ ++ priv->mii_bus = mdiobus_alloc(); ++ if (priv->mii_bus == NULL) { ++ err = -ENOMEM; ++ goto err_put_node; ++ } ++ ++ priv->mii_bus->name = "mdio"; ++ priv->mii_bus->read = priv->soc->mdio_read; ++ priv->mii_bus->write = priv->soc->mdio_write; ++ priv->mii_bus->reset = fe_mdio_reset; ++ priv->mii_bus->irq = priv->mii_irq; ++ priv->mii_bus->priv = priv; ++ priv->mii_bus->parent = priv->device; ++ ++ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name); ++ err = of_mdiobus_register(priv->mii_bus, mii_np); ++ if (err) ++ goto err_free_bus; ++ ++ return 0; ++ ++err_free_bus: ++ kfree(priv->mii_bus); ++err_put_node: ++ of_node_put(mii_np); ++ priv->mii_bus = NULL; ++ return err; ++} ++ ++void fe_mdio_cleanup(struct fe_priv *priv) ++{ ++ if (!priv->mii_bus) ++ return; ++ ++ mdiobus_unregister(priv->mii_bus); ++ of_node_put(priv->mii_bus->dev.of_node); ++ kfree(priv->mii_bus); ++} +diff --git a/drivers/net/ethernet/ralink/mdio.h b/drivers/net/ethernet/ralink/mdio.h +new file mode 100644 +index 0000000..c3910a0 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/mdio.h +@@ -0,0 +1,29 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#ifndef _RALINK_MDIO_H__ ++#define _RALINK_MDIO_H__ ++ ++#ifdef CONFIG_NET_RALINK_MDIO ++extern int fe_mdio_init(struct fe_priv *priv); ++extern void fe_mdio_cleanup(struct fe_priv *priv); ++extern int fe_connect_phy_node(struct fe_priv *priv, struct device_node *phy_node); ++#else ++static inline int fe_mdio_init(struct fe_priv *priv) { return 0; } ++static inline void fe_mdio_cleanup(struct fe_priv *priv) {} ++#endif ++#endif +diff --git a/drivers/net/ethernet/ralink/mdio_rt2880.c b/drivers/net/ethernet/ralink/mdio_rt2880.c +new file mode 100644 +index 0000000..54dbc53 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/mdio_rt2880.c +@@ -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 as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/dma-mapping.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/etherdevice.h> ++#include <linux/ethtool.h> ++#include <linux/platform_device.h> ++#include <linux/phy.h> ++#include <linux/of_device.h> ++#include <linux/clk.h> ++#include <linux/of_net.h> ++#include <linux/of_mdio.h> ++ ++#include "ralink_soc_eth.h" ++#include "mdio_rt2880.h" ++ ++#define FE_MDIO_RETRY 1000 ++ ++static unsigned char *rt2880_speed_str(struct fe_priv *priv) ++{ ++ switch (priv->phy->speed[0]) { ++ case SPEED_1000: ++ return "1000"; ++ case SPEED_100: ++ return "100"; ++ case SPEED_10: ++ return "10"; ++ } ++ ++ return "?"; ++} ++ ++void rt2880_mdio_link_adjust(struct fe_priv *priv) ++{ ++ u32 mdio_cfg; ++ ++ if (!priv->link[0]) { ++ netif_carrier_off(priv->netdev); ++ netdev_info(priv->netdev, "link down\n"); ++ return; ++ } ++ ++ mdio_cfg = FE_MDIO_CFG_TX_CLK_SKEW_200 | ++ FE_MDIO_CFG_RX_CLK_SKEW_200 | ++ FE_MDIO_CFG_GP1_FRC_EN; ++ ++ if (priv->phy->duplex[0] == DUPLEX_FULL) ++ mdio_cfg |= FE_MDIO_CFG_GP1_DUPLEX; ++ ++ if (priv->phy->tx_fc) ++ mdio_cfg |= FE_MDIO_CFG_GP1_FC_TX; ++ ++ if (priv->phy->rx_fc) ++ mdio_cfg |= FE_MDIO_CFG_GP1_FC_RX; ++ ++ switch (priv->phy->speed[0]) { ++ case SPEED_10: ++ mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_10; ++ break; ++ case SPEED_100: ++ mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_100; ++ break; ++ case SPEED_1000: ++ mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_1000; ++ break; ++ default: ++ BUG(); ++ } ++ ++ fe_w32(mdio_cfg, FE_MDIO_CFG); ++ ++ netif_carrier_on(priv->netdev); ++ netdev_info(priv->netdev, "link up (%sMbps/%s duplex)\n", ++ rt2880_speed_str(priv), ++ (DUPLEX_FULL == priv->phy->duplex[0]) ? "Full" : "Half"); ++} ++ ++static int rt2880_mdio_wait_ready(struct fe_priv *priv) ++{ ++ int retries; ++ ++ retries = FE_MDIO_RETRY; ++ while (1) { ++ u32 t; ++ ++ t = fe_r32(FE_MDIO_ACCESS); ++ if ((t & (0x1 << 31)) == 0) ++ return 0; ++ ++ if (retries-- == 0) ++ break; ++ ++ udelay(1); ++ } ++ ++ dev_err(priv->device, "MDIO operation timed out\n"); ++ return -ETIMEDOUT; ++} ++ ++int rt2880_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) ++{ ++ struct fe_priv *priv = bus->priv; ++ int err; ++ u32 t; ++ ++ err = rt2880_mdio_wait_ready(priv); ++ if (err) ++ return 0xffff; ++ ++ t = (phy_addr << 24) | (phy_reg << 16); ++ fe_w32(t, FE_MDIO_ACCESS); ++ t |= (1 << 31); ++ fe_w32(t, FE_MDIO_ACCESS); ++ ++ err = rt2880_mdio_wait_ready(priv); ++ if (err) ++ return 0xffff; ++ ++ pr_info("%s: addr=%04x, reg=%04x, value=%04x\n", __func__, ++ phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff); ++ ++ return fe_r32(FE_MDIO_ACCESS) & 0xffff; ++} ++ ++int rt2880_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val) ++{ ++ struct fe_priv *priv = bus->priv; ++ int err; ++ u32 t; ++ ++ pr_info("%s: addr=%04x, reg=%04x, value=%04x\n", __func__, ++ phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff); ++ ++ err = rt2880_mdio_wait_ready(priv); ++ if (err) ++ return err; ++ ++ t = (1 << 30) | (phy_addr << 24) | (phy_reg << 16) | val; ++ fe_w32(t, FE_MDIO_ACCESS); ++ t |= (1 << 31); ++ fe_w32(t, FE_MDIO_ACCESS); ++ ++ return rt2880_mdio_wait_ready(priv); ++} +diff --git a/drivers/net/ethernet/ralink/mdio_rt2880.h b/drivers/net/ethernet/ralink/mdio_rt2880.h +new file mode 100644 +index 0000000..c9ac0fe +--- /dev/null ++++ b/drivers/net/ethernet/ralink/mdio_rt2880.h +@@ -0,0 +1,25 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#ifndef _RALINK_MDIO_RT2880_H__ ++#define _RALINK_MDIO_RT2880_H__ ++ ++void rt2880_mdio_link_adjust(struct fe_priv *priv); ++int rt2880_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg); ++int rt2880_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val); ++ ++#endif +diff --git a/drivers/net/ethernet/ralink/ralink_soc_eth.c b/drivers/net/ethernet/ralink/ralink_soc_eth.c +new file mode 100644 +index 0000000..04e82eb +--- /dev/null ++++ b/drivers/net/ethernet/ralink/ralink_soc_eth.c +@@ -0,0 +1,759 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/dma-mapping.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/etherdevice.h> ++#include <linux/ethtool.h> ++#include <linux/platform_device.h> ++#include <linux/of_device.h> ++#include <linux/clk.h> ++#include <linux/of_net.h> ++#include <linux/of_mdio.h> ++#include <linux/if_vlan.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#include "ralink_soc_eth.h" ++#include "esw_rt3052.h" ++#include "mdio.h" ++ ++#define TX_TIMEOUT (20 * HZ / 100) ++#define MAX_RX_LENGTH 1536 ++ ++static const u32 fe_reg_table_default[FE_REG_COUNT] = { ++ [FE_REG_PDMA_GLO_CFG] = FE_PDMA_GLO_CFG, ++ [FE_REG_PDMA_RST_CFG] = FE_PDMA_RST_CFG, ++ [FE_REG_DLY_INT_CFG] = FE_DLY_INT_CFG, ++ [FE_REG_TX_BASE_PTR0] = FE_TX_BASE_PTR0, ++ [FE_REG_TX_MAX_CNT0] = FE_TX_MAX_CNT0, ++ [FE_REG_TX_CTX_IDX0] = FE_TX_CTX_IDX0, ++ [FE_REG_RX_BASE_PTR0] = FE_RX_BASE_PTR0, ++ [FE_REG_RX_MAX_CNT0] = FE_RX_MAX_CNT0, ++ [FE_REG_RX_CALC_IDX0] = FE_RX_CALC_IDX0, ++ [FE_REG_FE_INT_ENABLE] = FE_FE_INT_ENABLE, ++ [FE_REG_FE_INT_STATUS] = FE_FE_INT_STATUS, ++ [FE_REG_FE_DMA_VID_BASE] = FE_DMA_VID0, ++}; ++ ++static const u32 *fe_reg_table = fe_reg_table_default; ++ ++static void __iomem *fe_base = 0; ++ ++void fe_w32(u32 val, unsigned reg) ++{ ++ __raw_writel(val, fe_base + reg); ++} ++ ++u32 fe_r32(unsigned reg) ++{ ++ return __raw_readl(fe_base + reg); ++} ++ ++static inline void fe_reg_w32(u32 val, enum fe_reg reg) ++{ ++ fe_w32(val, fe_reg_table[reg]); ++} ++ ++static inline u32 fe_reg_r32(enum fe_reg reg) ++{ ++ return fe_r32(fe_reg_table[reg]); ++} ++ ++static inline void fe_int_disable(u32 mask) ++{ ++ fe_reg_w32(fe_reg_r32(FE_REG_FE_INT_ENABLE) & ~mask, ++ FE_REG_FE_INT_ENABLE); ++ /* flush write */ ++ fe_reg_r32(FE_REG_FE_INT_ENABLE); ++} ++ ++static inline void fe_int_enable(u32 mask) ++{ ++ fe_reg_w32(fe_reg_r32(FE_REG_FE_INT_ENABLE) | mask, ++ FE_REG_FE_INT_ENABLE); ++ /* flush write */ ++ fe_reg_r32(FE_REG_FE_INT_ENABLE); ++} ++ ++static inline void fe_hw_set_macaddr(struct fe_priv *priv, unsigned char *mac) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->page_lock, flags); ++ fe_w32((mac[0] << 8) | mac[1], FE_GDMA1_MAC_ADRH); ++ fe_w32((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], ++ FE_GDMA1_MAC_ADRL); ++ spin_unlock_irqrestore(&priv->page_lock, flags); ++} ++ ++static int fe_set_mac_address(struct net_device *dev, void *p) ++{ ++ int ret = eth_mac_addr(dev, p); ++ ++ if (!ret) { ++ struct fe_priv *priv = netdev_priv(dev); ++ ++ if (priv->soc->set_mac) ++ priv->soc->set_mac(priv, dev->dev_addr); ++ else ++ fe_hw_set_macaddr(priv, p); ++ } ++ ++ return ret; ++} ++ ++static struct sk_buff* fe_alloc_skb(struct fe_priv *priv) ++{ ++ struct sk_buff *skb; ++ ++ skb = netdev_alloc_skb(priv->netdev, MAX_RX_LENGTH + NET_IP_ALIGN); ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, NET_IP_ALIGN); ++ ++ return skb; ++} ++ ++static int fe_alloc_rx(struct fe_priv *priv) ++{ ++ int size = NUM_DMA_DESC * sizeof(struct fe_rx_dma); ++ int i; ++ ++ priv->rx_dma = dma_alloc_coherent(&priv->netdev->dev, size, ++ &priv->rx_phys, GFP_ATOMIC); ++ if (!priv->rx_dma) ++ return -ENOMEM; ++ ++ memset(priv->rx_dma, 0, size); ++ ++ for (i = 0; i < NUM_DMA_DESC; i++) { ++ priv->rx_skb[i] = fe_alloc_skb(priv); ++ if (!priv->rx_skb[i]) ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < NUM_DMA_DESC; i++) { ++ dma_addr_t dma_addr = dma_map_single(&priv->netdev->dev, ++ priv->rx_skb[i]->data, ++ MAX_RX_LENGTH, ++ DMA_FROM_DEVICE); ++ priv->rx_dma[i].rxd1 = (unsigned int) dma_addr; ++ ++ if (priv->soc->rx_dma) ++ priv->soc->rx_dma(priv, i, MAX_RX_LENGTH); ++ else ++ priv->rx_dma[i].rxd2 = RX_DMA_LSO; ++ } ++ wmb(); ++ ++ fe_reg_w32(priv->rx_phys, FE_REG_RX_BASE_PTR0); ++ fe_reg_w32(NUM_DMA_DESC, FE_REG_RX_MAX_CNT0); ++ fe_reg_w32((NUM_DMA_DESC - 1), FE_REG_RX_CALC_IDX0); ++ fe_reg_w32(FE_PST_DRX_IDX0, FE_REG_PDMA_RST_CFG); ++ ++ return 0; ++} ++ ++static int fe_alloc_tx(struct fe_priv *priv) ++{ ++ int size = NUM_DMA_DESC * sizeof(struct fe_tx_dma); ++ int i; ++ ++ priv->tx_free_idx = 0; ++ ++ priv->tx_dma = dma_alloc_coherent(&priv->netdev->dev, size, ++ &priv->tx_phys, GFP_ATOMIC); ++ if (!priv->tx_dma) ++ return -ENOMEM; ++ ++ memset(priv->tx_dma, 0, size); ++ ++ for (i = 0; i < NUM_DMA_DESC; i++) { ++ if (priv->soc->tx_dma) { ++ priv->soc->tx_dma(priv, i, 0); ++ continue; ++ } ++ ++ priv->tx_dma[i].txd2 = TX_DMA_LSO | TX_DMA_DONE; ++ priv->tx_dma[i].txd4 = TX_DMA_QN(3) | TX_DMA_PN(1); ++ } ++ ++ fe_reg_w32(priv->tx_phys, FE_REG_TX_BASE_PTR0); ++ fe_reg_w32(NUM_DMA_DESC, FE_REG_TX_MAX_CNT0); ++ fe_reg_w32(0, FE_REG_TX_CTX_IDX0); ++ fe_reg_w32(FE_PST_DTX_IDX0, FE_REG_PDMA_RST_CFG); ++ ++ return 0; ++} ++ ++static void fe_free_dma(struct fe_priv *priv) ++{ ++ int i; ++ ++ for (i = 0; i < NUM_DMA_DESC; i++) { ++ if (priv->rx_skb[i]) { ++ dma_unmap_single(&priv->netdev->dev, priv->rx_dma[i].rxd1, ++ MAX_RX_LENGTH, DMA_FROM_DEVICE); ++ dev_kfree_skb_any(priv->rx_skb[i]); ++ priv->rx_skb[i] = NULL; ++ } ++ ++ if (priv->tx_skb[i]) { ++ dev_kfree_skb_any(priv->tx_skb[i]); ++ priv->tx_skb[i] = NULL; ++ } ++ } ++ ++ if (priv->rx_dma) { ++ int size = NUM_DMA_DESC * sizeof(struct fe_rx_dma); ++ dma_free_coherent(&priv->netdev->dev, size, priv->rx_dma, ++ priv->rx_phys); ++ } ++ ++ if (priv->tx_dma) { ++ int size = NUM_DMA_DESC * sizeof(struct fe_tx_dma); ++ dma_free_coherent(&priv->netdev->dev, size, priv->tx_dma, ++ priv->tx_phys); ++ } ++ ++ netdev_reset_queue(priv->netdev); ++} ++ ++static int fe_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct fe_priv *priv = netdev_priv(dev); ++ dma_addr_t mapped_addr; ++ u32 tx_next; ++ u32 tx; ++ ++ if (priv->soc->min_pkt_len) { ++ if (skb->len < priv->soc->min_pkt_len) { ++ if (skb_padto(skb, priv->soc->min_pkt_len)) { ++ printk(KERN_ERR ++ "fe_eth: skb_padto failed\n"); ++ kfree_skb(skb); ++ return 0; ++ } ++ skb_put(skb, priv->soc->min_pkt_len - skb->len); ++ } ++ } ++ ++ dev->trans_start = jiffies; ++ mapped_addr = dma_map_single(&priv->netdev->dev, skb->data, ++ skb->len, DMA_TO_DEVICE); ++ ++ spin_lock(&priv->page_lock); ++ ++ tx = fe_reg_r32(FE_REG_TX_CTX_IDX0); ++ tx_next = (tx + 1) % NUM_DMA_DESC; ++ ++ if ((priv->tx_skb[tx]) || (priv->tx_skb[tx_next]) || ++ !(priv->tx_dma[tx].txd2 & TX_DMA_DONE) || ++ !(priv->tx_dma[tx_next].txd2 & TX_DMA_DONE)) ++ { ++ spin_unlock(&priv->page_lock); ++ dev->stats.tx_dropped++; ++ kfree_skb(skb); ++ ++ return NETDEV_TX_OK; ++ } ++ ++ priv->tx_skb[tx] = skb; ++ priv->tx_dma[tx].txd1 = (unsigned int) mapped_addr; ++ wmb(); ++ if (priv->soc->tx_dma) ++ priv->soc->tx_dma(priv, tx, skb->len); ++ else ++ priv->tx_dma[tx].txd2 = TX_DMA_LSO | TX_DMA_PLEN0(skb->len); ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ priv->tx_dma[tx].txd4 |= TX_DMA_CHKSUM; ++ else ++ priv->tx_dma[tx].txd4 &= ~TX_DMA_CHKSUM; ++ ++ if (fe_reg_table[FE_REG_FE_DMA_VID_BASE] && vlan_tx_tag_present(skb)) ++ priv->tx_dma[tx].txd4 |= 0x80 | (vlan_tx_tag_get(skb) >> 13) << 4 | (vlan_tx_tag_get(skb) & 0xF); ++ else ++ priv->tx_dma[tx].txd4 &= ~0x80; ++ ++ dev->stats.tx_packets++; ++ dev->stats.tx_bytes += skb->len; ++ ++ fe_reg_w32(tx_next, FE_REG_TX_CTX_IDX0); ++ netdev_sent_queue(dev, skb->len); ++ ++ spin_unlock(&priv->page_lock); ++ ++ return NETDEV_TX_OK; ++} ++ ++static int fe_poll_rx(struct napi_struct *napi, int budget) ++{ ++ struct fe_priv *priv = container_of(napi, struct fe_priv, rx_napi); ++ int idx = fe_reg_r32(FE_REG_RX_CALC_IDX0); ++ unsigned long flags; ++ int complete = 0; ++ int rx = 0; ++ ++ while ((rx < budget) && !complete) { ++ ++ idx = (idx + 1) % NUM_DMA_DESC; ++ ++ if (priv->rx_dma[idx].rxd2 & RX_DMA_DONE) { ++ struct sk_buff *new_skb = fe_alloc_skb(priv); ++ ++ if (new_skb) { ++ int pktlen = RX_DMA_PLEN0(priv->rx_dma[idx].rxd2); ++ dma_addr_t dma_addr; ++ ++ dma_unmap_single(&priv->netdev->dev, priv->rx_dma[idx].rxd1, ++ MAX_RX_LENGTH, DMA_FROM_DEVICE); ++ ++ skb_put(priv->rx_skb[idx], pktlen); ++ priv->rx_skb[idx]->dev = priv->netdev; ++ priv->rx_skb[idx]->protocol = eth_type_trans(priv->rx_skb[idx], priv->netdev); ++ if (priv->rx_dma[idx].rxd4 & priv->soc->checksum_bit) ++ priv->rx_skb[idx]->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ priv->rx_skb[idx]->ip_summed = CHECKSUM_NONE; ++ priv->netdev->stats.rx_packets++; ++ priv->netdev->stats.rx_bytes += pktlen; ++ netif_rx(priv->rx_skb[idx]); ++ ++ priv->rx_skb[idx] = new_skb; ++ ++ dma_addr = dma_map_single(&priv->netdev->dev, ++ new_skb->data, ++ MAX_RX_LENGTH, ++ DMA_FROM_DEVICE); ++ priv->rx_dma[idx].rxd1 = (unsigned int) dma_addr; ++ wmb(); ++ } else { ++ priv->netdev->stats.rx_dropped++; ++ } ++ ++ if (priv->soc->rx_dma) ++ priv->soc->rx_dma(priv, idx, MAX_RX_LENGTH); ++ else ++ priv->rx_dma[idx].rxd2 = RX_DMA_LSO; ++ fe_reg_w32(idx, FE_REG_RX_CALC_IDX0); ++ rx++; ++ } else { ++ complete = 1; ++ } ++ } ++ ++ if (complete || !rx) { ++ napi_complete(&priv->rx_napi); ++ spin_lock_irqsave(&priv->page_lock, flags); ++ fe_int_enable(priv->soc->rx_dly_int); ++ spin_unlock_irqrestore(&priv->page_lock, flags); ++ } ++ ++ return rx; ++} ++ ++static int fe_poll_tx(struct napi_struct *napi, int budget) ++{ ++ struct fe_priv *priv = container_of(napi, struct fe_priv, tx_napi); ++ unsigned int bytes_compl = 0; ++ unsigned int pkts_compl = 0; ++ struct netdev_queue *txq; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->page_lock, flags); ++ while (pkts_compl < budget) { ++ struct fe_tx_dma *txd; ++ ++ txd = &priv->tx_dma[priv->tx_free_idx]; ++ ++ if (!(txd->txd2 & TX_DMA_DONE) || !(priv->tx_skb[priv->tx_free_idx])) ++ break; ++ ++ bytes_compl += priv->tx_skb[priv->tx_free_idx]->len; ++ pkts_compl++; ++ ++ dev_kfree_skb_irq(priv->tx_skb[priv->tx_free_idx]); ++ priv->tx_skb[priv->tx_free_idx] = NULL; ++ priv->tx_free_idx++; ++ if (priv->tx_free_idx >= NUM_DMA_DESC) ++ priv->tx_free_idx = 0; ++ } ++ spin_unlock_irqrestore(&priv->page_lock, flags); ++ ++ txq = netdev_get_tx_queue(priv->netdev, 0); ++ if (netif_tx_queue_stopped(txq)) ++ netif_tx_start_queue(txq); ++ ++ napi_complete(napi); ++ netdev_completed_queue(priv->netdev, pkts_compl, bytes_compl); ++ ++ spin_lock_irqsave(&priv->page_lock, flags); ++ fe_int_enable(priv->soc->tx_dly_int); ++ spin_unlock_irqrestore(&priv->page_lock, flags); ++ ++ return pkts_compl; ++} ++ ++static void fe_tx_timeout(struct net_device *dev) ++{ ++ struct fe_priv *priv = netdev_priv(dev); ++ ++ priv->netdev->stats.tx_errors++; ++ netdev_err(dev, "transmit timed out, waking up the queue\n"); ++ netif_wake_queue(dev); ++} ++ ++static irqreturn_t fe_handle_irq(int irq, void *dev) ++{ ++ struct fe_priv *priv = netdev_priv(dev); ++ unsigned int status; ++ unsigned int mask; ++ ++ status = fe_reg_r32(FE_REG_FE_INT_STATUS); ++ mask = fe_reg_r32(FE_REG_FE_INT_ENABLE); ++ ++ if (!(status & mask)) ++ return IRQ_NONE; ++ ++ if (status & priv->soc->rx_dly_int) { ++ fe_int_disable(priv->soc->rx_dly_int); ++ napi_schedule(&priv->rx_napi); ++ } ++ ++ if (status & priv->soc->tx_dly_int) { ++ fe_int_disable(priv->soc->tx_dly_int); ++ napi_schedule(&priv->tx_napi); ++ } ++ ++ fe_reg_w32(status, FE_REG_FE_INT_STATUS); ++ ++ return IRQ_HANDLED; ++} ++ ++static int fe_hw_init(struct net_device *dev) ++{ ++ struct fe_priv *priv = netdev_priv(dev); ++ int err, i; ++ ++ err = devm_request_irq(priv->device, dev->irq, fe_handle_irq, 0, ++ dev_name(priv->device), dev); ++ if (err) ++ return err; ++ ++ err = fe_alloc_rx(priv); ++ if (!err) ++ err = fe_alloc_tx(priv); ++ if (err) ++ return err; ++ ++ if (priv->soc->set_mac) ++ priv->soc->set_mac(priv, dev->dev_addr); ++ else ++ fe_hw_set_macaddr(priv, dev->dev_addr); ++ ++ fe_reg_w32(FE_DELAY_INIT, FE_REG_DLY_INT_CFG); ++ ++ fe_int_disable(priv->soc->tx_dly_int | priv->soc->rx_dly_int); ++ ++ ++ if (fe_reg_table[FE_REG_FE_DMA_VID_BASE]) ++ for (i = 0; i < 16; i += 2) ++ fe_w32((i + 1) << 16 | i, fe_reg_table[FE_REG_FE_DMA_VID_BASE] + (i * 4)); ++ ++ if (priv->soc->fwd_config) { ++ priv->soc->fwd_config(priv); ++ } else { ++ unsigned long sysclk = priv->sysclk; ++ ++ if (!sysclk) { ++ netdev_err(dev, "unable to get clock\n"); ++ return -EINVAL; ++ } ++ ++ sysclk /= FE_US_CYC_CNT_DIVISOR; ++ sysclk <<= FE_US_CYC_CNT_SHIFT; ++ ++ fe_w32((fe_r32(FE_FE_GLO_CFG) & ++ ~(FE_US_CYC_CNT_MASK << FE_US_CYC_CNT_SHIFT)) | priv->sysclk, ++ FE_FE_GLO_CFG); ++ ++ fe_w32(fe_r32(FE_GDMA1_FWD_CFG) & ~0xffff, FE_GDMA1_FWD_CFG); ++ fe_w32(fe_r32(FE_GDMA1_FWD_CFG) | (FE_GDM1_ICS_EN | FE_GDM1_TCS_EN | FE_GDM1_UCS_EN), ++ FE_GDMA1_FWD_CFG); ++ fe_w32(fe_r32(FE_CDMA_CSG_CFG) | (FE_ICS_GEN_EN | FE_TCS_GEN_EN | FE_UCS_GEN_EN), ++ FE_CDMA_CSG_CFG); ++ fe_w32(FE_PSE_FQFC_CFG_INIT, FE_PSE_FQ_CFG); ++ } ++ ++ fe_w32(1, FE_FE_RST_GL); ++ fe_w32(0, FE_FE_RST_GL); ++ ++ return 0; ++} ++ ++static int fe_open(struct net_device *dev) ++{ ++ struct fe_priv *priv = netdev_priv(dev); ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&priv->page_lock, flags); ++ napi_enable(&priv->rx_napi); ++ napi_enable(&priv->tx_napi); ++ ++ val = FE_TX_WB_DDONE | FE_RX_DMA_EN | FE_TX_DMA_EN; ++ val |= priv->soc->pdma_glo_cfg; ++ fe_reg_w32(val, FE_REG_PDMA_GLO_CFG); ++ ++ spin_unlock_irqrestore(&priv->page_lock, flags); ++ ++ if (priv->phy) ++ priv->phy->start(priv); ++ ++ if (priv->soc->has_carrier && priv->soc->has_carrier(priv)) ++ netif_carrier_on(dev); ++ ++ netif_start_queue(dev); ++ fe_int_enable(priv->soc->tx_dly_int | priv->soc->rx_dly_int); ++ ++ return 0; ++} ++ ++static int fe_stop(struct net_device *dev) ++{ ++ struct fe_priv *priv = netdev_priv(dev); ++ unsigned long flags; ++ ++ fe_int_disable(priv->soc->tx_dly_int | priv->soc->rx_dly_int); ++ ++ netif_stop_queue(dev); ++ ++ if (priv->phy) ++ priv->phy->stop(priv); ++ ++ spin_lock_irqsave(&priv->page_lock, flags); ++ napi_disable(&priv->rx_napi); ++ napi_disable(&priv->tx_napi); ++ ++ fe_reg_w32(fe_reg_r32(FE_REG_PDMA_GLO_CFG) & ++ ~(FE_TX_WB_DDONE | FE_RX_DMA_EN | FE_TX_DMA_EN), ++ FE_REG_PDMA_GLO_CFG); ++ spin_unlock_irqrestore(&priv->page_lock, flags); ++ ++ return 0; ++} ++ ++static int __init fe_init(struct net_device *dev) ++{ ++ struct fe_priv *priv = netdev_priv(dev); ++ struct device_node *port; ++ int err; ++ ++ BUG_ON(!priv->soc->reset_fe); ++ priv->soc->reset_fe(); ++ ++ if (priv->soc->switch_init) ++ priv->soc->switch_init(priv); ++ ++ net_srandom(jiffies); ++ memcpy(dev->dev_addr, priv->soc->mac, ETH_ALEN); ++ of_get_mac_address_mtd(priv->device->of_node, dev->dev_addr); ++ ++ err = fe_mdio_init(priv); ++ if (err) ++ return err; ++ ++ if (priv->phy) { ++ err = priv->phy->connect(priv); ++ if (err) ++ goto err_mdio_cleanup; ++ } ++ ++ if (priv->soc->port_init) ++ for_each_child_of_node(priv->device->of_node, port) ++ if (of_device_is_compatible(port, "ralink,eth-port")) ++ priv->soc->port_init(priv, port); ++ ++ err = fe_hw_init(dev); ++ if (err) ++ goto err_phy_disconnect; ++ ++ return 0; ++ ++err_phy_disconnect: ++ if (priv->phy) ++ priv->phy->disconnect(priv); ++err_mdio_cleanup: ++ fe_mdio_cleanup(priv); ++ ++ return err; ++} ++ ++static void fe_uninit(struct net_device *dev) ++{ ++ struct fe_priv *priv = netdev_priv(dev); ++ ++ if (priv->phy) ++ priv->phy->disconnect(priv); ++ fe_mdio_cleanup(priv); ++ ++ fe_reg_w32(0, FE_REG_FE_INT_ENABLE); ++ free_irq(dev->irq, dev); ++ ++ fe_free_dma(priv); ++} ++ ++static const struct net_device_ops fe_netdev_ops = { ++ .ndo_init = fe_init, ++ .ndo_uninit = fe_uninit, ++ .ndo_open = fe_open, ++ .ndo_stop = fe_stop, ++ .ndo_start_xmit = fe_start_xmit, ++ .ndo_tx_timeout = fe_tx_timeout, ++ .ndo_set_mac_address = fe_set_mac_address, ++ .ndo_change_mtu = eth_change_mtu, ++ .ndo_validate_addr = eth_validate_addr, ++}; ++ ++static int fe_probe(struct platform_device *pdev) ++{ ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ const struct of_device_id *match; ++ struct fe_soc_data *soc = NULL; ++ struct net_device *netdev; ++ struct fe_priv *priv; ++ struct clk *sysclk; ++ int err; ++ ++ match = of_match_device(of_fe_match, &pdev->dev); ++ soc = (struct fe_soc_data *) match->data; ++ if (soc->reg_table) ++ fe_reg_table = soc->reg_table; ++ ++ fe_base = devm_request_and_ioremap(&pdev->dev, res); ++ if (!fe_base) ++ return -ENOMEM; ++ ++ netdev = alloc_etherdev(sizeof(struct fe_priv)); ++ if (!netdev) { ++ dev_err(&pdev->dev, "alloc_etherdev failed\n"); ++ return -ENOMEM; ++ } ++ ++ strcpy(netdev->name, "eth%d"); ++ netdev->netdev_ops = &fe_netdev_ops; ++ netdev->base_addr = (unsigned long) fe_base; ++ netdev->watchdog_timeo = TX_TIMEOUT; ++ netdev->features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; ++ if (fe_reg_table[FE_REG_FE_DMA_VID_BASE]) ++ netdev->features |= NETIF_F_HW_VLAN_TX; ++ ++ netdev->irq = platform_get_irq(pdev, 0); ++ if (netdev->irq < 0) { ++ dev_err(&pdev->dev, "no IRQ resource found\n"); ++ kfree(netdev); ++ return -ENXIO; ++ } ++ ++ priv = netdev_priv(netdev); ++ memset(priv, 0, sizeof(struct fe_priv)); ++ spin_lock_init(&priv->page_lock); ++ ++ sysclk = devm_clk_get(&pdev->dev, NULL); ++ if (!IS_ERR(sysclk)) ++ priv->sysclk = clk_get_rate(sysclk); ++ ++ priv->netdev = netdev; ++ priv->device = &pdev->dev; ++ priv->soc = soc; ++ ++ err = register_netdev(netdev); ++ if (err) { ++ dev_err(&pdev->dev, "error bringing up device\n"); ++ kfree(netdev); ++ return err; ++ } ++ ++ netif_napi_add(netdev, &priv->rx_napi, fe_poll_rx, 32); ++ netif_napi_add(netdev, &priv->tx_napi, fe_poll_tx, 8); ++ ++ platform_set_drvdata(pdev, netdev); ++ ++ netdev_info(netdev, "done loading\n"); ++ ++ return 0; ++} ++ ++static int fe_remove(struct platform_device *pdev) ++{ ++ struct net_device *dev = platform_get_drvdata(pdev); ++ struct fe_priv *priv = netdev_priv(dev); ++ ++ netif_stop_queue(dev); ++ netif_napi_del(&priv->rx_napi); ++ netif_napi_del(&priv->tx_napi); ++ ++ unregister_netdev(dev); ++ free_netdev(dev); ++ ++ return 0; ++} ++ ++static struct platform_driver fe_driver = { ++ .probe = fe_probe, ++ .remove = fe_remove, ++ .driver = { ++ .name = "ralink_soc_eth", ++ .owner = THIS_MODULE, ++ .of_match_table = of_fe_match, ++ }, ++}; ++ ++static int __init init_rtfe(void) ++{ ++ int ret; ++ ++ ret = rtesw_init(); ++ if (ret) ++ return ret; ++ ++ ret = platform_driver_register(&fe_driver); ++ if (ret) ++ rtesw_exit(); ++ ++ return ret; ++} ++ ++static void __exit exit_rtfe(void) ++{ ++ platform_driver_unregister(&fe_driver); ++ rtesw_exit(); ++} ++ ++module_init(init_rtfe); ++module_exit(exit_rtfe); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("Ethernet driver for Ralink SoC"); +diff --git a/drivers/net/ethernet/ralink/ralink_soc_eth.h b/drivers/net/ethernet/ralink/ralink_soc_eth.h +new file mode 100644 +index 0000000..0c769ef +--- /dev/null ++++ b/drivers/net/ethernet/ralink/ralink_soc_eth.h +@@ -0,0 +1,372 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * based on Ralink SDK3.3 ++ * Copyright (C) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#ifndef FE_ETH_H ++#define FE_ETH_H ++ ++#include <linux/mii.h> ++#include <linux/interrupt.h> ++#include <linux/netdevice.h> ++#include <linux/dma-mapping.h> ++#include <linux/phy.h> ++ ++ ++enum fe_reg { ++ FE_REG_PDMA_GLO_CFG = 0, ++ FE_REG_PDMA_RST_CFG, ++ FE_REG_DLY_INT_CFG, ++ FE_REG_TX_BASE_PTR0, ++ FE_REG_TX_MAX_CNT0, ++ FE_REG_TX_CTX_IDX0, ++ FE_REG_RX_BASE_PTR0, ++ FE_REG_RX_MAX_CNT0, ++ FE_REG_RX_CALC_IDX0, ++ FE_REG_FE_INT_ENABLE, ++ FE_REG_FE_INT_STATUS, ++ FE_REG_FE_DMA_VID_BASE, ++ FE_REG_COUNT ++}; ++ ++#define NUM_DMA_DESC 0x100 ++ ++#define FE_DELAY_EN_INT 0x80 ++#define FE_DELAY_MAX_INT 0x04 ++#define FE_DELAY_MAX_TOUT 0x04 ++#define FE_DELAY_CHAN (((FE_DELAY_EN_INT | FE_DELAY_MAX_INT) << 8) | FE_DELAY_MAX_TOUT) ++#define FE_DELAY_INIT ((FE_DELAY_CHAN << 16) | FE_DELAY_CHAN) ++#define FE_PSE_FQFC_CFG_INIT 0x80504000 ++ ++/* interrupt bits */ ++#define FE_CNT_PPE_AF BIT(31) ++#define FE_CNT_GDM_AF BIT(29) ++#define FE_PSE_P2_FC BIT(26) ++#define FE_PSE_BUF_DROP BIT(24) ++#define FE_GDM_OTHER_DROP BIT(23) ++#define FE_PSE_P1_FC BIT(22) ++#define FE_PSE_P0_FC BIT(21) ++#define FE_PSE_FQ_EMPTY BIT(20) ++#define FE_GE1_STA_CHG BIT(18) ++#define FE_TX_COHERENT BIT(17) ++#define FE_RX_COHERENT BIT(16) ++#define FE_TX_DONE_INT3 BIT(11) ++#define FE_TX_DONE_INT2 BIT(10) ++#define FE_TX_DONE_INT1 BIT(9) ++#define FE_TX_DONE_INT0 BIT(8) ++#define FE_RX_DONE_INT0 BIT(2) ++#define FE_TX_DLY_INT BIT(1) ++#define FE_RX_DLY_INT BIT(0) ++ ++#define RT5350_RX_DLY_INT BIT(30) ++#define RT5350_TX_DLY_INT BIT(28) ++ ++/* registers */ ++#define FE_FE_OFFSET 0x0000 ++#define FE_GDMA_OFFSET 0x0020 ++#define FE_PSE_OFFSET 0x0040 ++#define FE_GDMA2_OFFSET 0x0060 ++#define FE_CDMA_OFFSET 0x0080 ++#define FE_DMA_VID0 0x00a8 ++#define FE_PDMA_OFFSET 0x0100 ++#define FE_PPE_OFFSET 0x0200 ++#define FE_CMTABLE_OFFSET 0x0400 ++#define FE_POLICYTABLE_OFFSET 0x1000 ++ ++#define RT5350_PDMA_OFFSET 0x0800 ++#define RT5350_SDM_OFFSET 0x0c00 ++ ++#define FE_MDIO_ACCESS (FE_FE_OFFSET + 0x00) ++#define FE_MDIO_CFG (FE_FE_OFFSET + 0x04) ++#define FE_FE_GLO_CFG (FE_FE_OFFSET + 0x08) ++#define FE_FE_RST_GL (FE_FE_OFFSET + 0x0C) ++#define FE_FE_INT_STATUS (FE_FE_OFFSET + 0x10) ++#define FE_FE_INT_ENABLE (FE_FE_OFFSET + 0x14) ++#define FE_MDIO_CFG2 (FE_FE_OFFSET + 0x18) ++#define FE_FOC_TS_T (FE_FE_OFFSET + 0x1C) ++ ++#define FE_GDMA1_FWD_CFG (FE_GDMA_OFFSET + 0x00) ++#define FE_GDMA1_SCH_CFG (FE_GDMA_OFFSET + 0x04) ++#define FE_GDMA1_SHPR_CFG (FE_GDMA_OFFSET + 0x08) ++#define FE_GDMA1_MAC_ADRL (FE_GDMA_OFFSET + 0x0C) ++#define FE_GDMA1_MAC_ADRH (FE_GDMA_OFFSET + 0x10) ++ ++#define FE_GDMA2_FWD_CFG (FE_GDMA2_OFFSET + 0x00) ++#define FE_GDMA2_SCH_CFG (FE_GDMA2_OFFSET + 0x04) ++#define FE_GDMA2_SHPR_CFG (FE_GDMA2_OFFSET + 0x08) ++#define FE_GDMA2_MAC_ADRL (FE_GDMA2_OFFSET + 0x0C) ++#define FE_GDMA2_MAC_ADRH (FE_GDMA2_OFFSET + 0x10) ++ ++#define FE_PSE_FQ_CFG (FE_PSE_OFFSET + 0x00) ++#define FE_CDMA_FC_CFG (FE_PSE_OFFSET + 0x04) ++#define FE_GDMA1_FC_CFG (FE_PSE_OFFSET + 0x08) ++#define FE_GDMA2_FC_CFG (FE_PSE_OFFSET + 0x0C) ++ ++#define FE_CDMA_CSG_CFG (FE_CDMA_OFFSET + 0x00) ++#define FE_CDMA_SCH_CFG (FE_CDMA_OFFSET + 0x04) ++ ++#define MT7620A_GDMA_OFFSET 0x0600 ++#define MT7620A_GDMA1_FWD_CFG (MT7620A_GDMA_OFFSET + 0x00) ++#define MT7620A_FE_GDMA1_SCH_CFG (MT7620A_GDMA_OFFSET + 0x04) ++#define MT7620A_FE_GDMA1_SHPR_CFG (MT7620A_GDMA_OFFSET + 0x08) ++#define MT7620A_FE_GDMA1_MAC_ADRL (MT7620A_GDMA_OFFSET + 0x0C) ++#define MT7620A_FE_GDMA1_MAC_ADRH (MT7620A_GDMA_OFFSET + 0x10) ++ ++#define RT5350_TX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x00) ++#define RT5350_TX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x04) ++#define RT5350_TX_CTX_IDX0 (RT5350_PDMA_OFFSET + 0x08) ++#define RT5350_TX_DTX_IDX0 (RT5350_PDMA_OFFSET + 0x0C) ++#define RT5350_TX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x10) ++#define RT5350_TX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x14) ++#define RT5350_TX_CTX_IDX1 (RT5350_PDMA_OFFSET + 0x18) ++#define RT5350_TX_DTX_IDX1 (RT5350_PDMA_OFFSET + 0x1C) ++#define RT5350_TX_BASE_PTR2 (RT5350_PDMA_OFFSET + 0x20) ++#define RT5350_TX_MAX_CNT2 (RT5350_PDMA_OFFSET + 0x24) ++#define RT5350_TX_CTX_IDX2 (RT5350_PDMA_OFFSET + 0x28) ++#define RT5350_TX_DTX_IDX2 (RT5350_PDMA_OFFSET + 0x2C) ++#define RT5350_TX_BASE_PTR3 (RT5350_PDMA_OFFSET + 0x30) ++#define RT5350_TX_MAX_CNT3 (RT5350_PDMA_OFFSET + 0x34) ++#define RT5350_TX_CTX_IDX3 (RT5350_PDMA_OFFSET + 0x38) ++#define RT5350_TX_DTX_IDX3 (RT5350_PDMA_OFFSET + 0x3C) ++#define RT5350_RX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x100) ++#define RT5350_RX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x104) ++#define RT5350_RX_CALC_IDX0 (RT5350_PDMA_OFFSET + 0x108) ++#define RT5350_RX_DRX_IDX0 (RT5350_PDMA_OFFSET + 0x10C) ++#define RT5350_RX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x110) ++#define RT5350_RX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x114) ++#define RT5350_RX_CALC_IDX1 (RT5350_PDMA_OFFSET + 0x118) ++#define RT5350_RX_DRX_IDX1 (RT5350_PDMA_OFFSET + 0x11C) ++#define RT5350_PDMA_GLO_CFG (RT5350_PDMA_OFFSET + 0x204) ++#define RT5350_PDMA_RST_CFG (RT5350_PDMA_OFFSET + 0x208) ++#define RT5350_DLY_INT_CFG (RT5350_PDMA_OFFSET + 0x20c) ++#define RT5350_FE_INT_STATUS (RT5350_PDMA_OFFSET + 0x220) ++#define RT5350_FE_INT_ENABLE (RT5350_PDMA_OFFSET + 0x228) ++#define RT5350_PDMA_SCH_CFG (RT5350_PDMA_OFFSET + 0x280) ++ ++#define FE_PDMA_GLO_CFG (FE_PDMA_OFFSET + 0x00) ++#define FE_PDMA_RST_CFG (FE_PDMA_OFFSET + 0x04) ++#define FE_PDMA_SCH_CFG (FE_PDMA_OFFSET + 0x08) ++#define FE_DLY_INT_CFG (FE_PDMA_OFFSET + 0x0C) ++#define FE_TX_BASE_PTR0 (FE_PDMA_OFFSET + 0x10) ++#define FE_TX_MAX_CNT0 (FE_PDMA_OFFSET + 0x14) ++#define FE_TX_CTX_IDX0 (FE_PDMA_OFFSET + 0x18) ++#define FE_TX_DTX_IDX0 (FE_PDMA_OFFSET + 0x1C) ++#define FE_TX_BASE_PTR1 (FE_PDMA_OFFSET + 0x20) ++#define FE_TX_MAX_CNT1 (FE_PDMA_OFFSET + 0x24) ++#define FE_TX_CTX_IDX1 (FE_PDMA_OFFSET + 0x28) ++#define FE_TX_DTX_IDX1 (FE_PDMA_OFFSET + 0x2C) ++#define FE_RX_BASE_PTR0 (FE_PDMA_OFFSET + 0x30) ++#define FE_RX_MAX_CNT0 (FE_PDMA_OFFSET + 0x34) ++#define FE_RX_CALC_IDX0 (FE_PDMA_OFFSET + 0x38) ++#define FE_RX_DRX_IDX0 (FE_PDMA_OFFSET + 0x3C) ++#define FE_TX_BASE_PTR2 (FE_PDMA_OFFSET + 0x40) ++#define FE_TX_MAX_CNT2 (FE_PDMA_OFFSET + 0x44) ++#define FE_TX_CTX_IDX2 (FE_PDMA_OFFSET + 0x48) ++#define FE_TX_DTX_IDX2 (FE_PDMA_OFFSET + 0x4C) ++#define FE_TX_BASE_PTR3 (FE_PDMA_OFFSET + 0x50) ++#define FE_TX_MAX_CNT3 (FE_PDMA_OFFSET + 0x54) ++#define FE_TX_CTX_IDX3 (FE_PDMA_OFFSET + 0x58) ++#define FE_TX_DTX_IDX3 (FE_PDMA_OFFSET + 0x5C) ++#define FE_RX_BASE_PTR1 (FE_PDMA_OFFSET + 0x60) ++#define FE_RX_MAX_CNT1 (FE_PDMA_OFFSET + 0x64) ++#define FE_RX_CALC_IDX1 (FE_PDMA_OFFSET + 0x68) ++#define FE_RX_DRX_IDX1 (FE_PDMA_OFFSET + 0x6C) ++ ++#define RT5350_SDM_CFG (RT5350_SDM_OFFSET + 0x00) //Switch DMA configuration ++#define RT5350_SDM_RRING (RT5350_SDM_OFFSET + 0x04) //Switch DMA Rx Ring ++#define RT5350_SDM_TRING (RT5350_SDM_OFFSET + 0x08) //Switch DMA Tx Ring ++#define RT5350_SDM_MAC_ADRL (RT5350_SDM_OFFSET + 0x0C) //Switch MAC address LSB ++#define RT5350_SDM_MAC_ADRH (RT5350_SDM_OFFSET + 0x10) //Switch MAC Address MSB ++#define RT5350_SDM_TPCNT (RT5350_SDM_OFFSET + 0x100) //Switch DMA Tx packet count ++#define RT5350_SDM_TBCNT (RT5350_SDM_OFFSET + 0x104) //Switch DMA Tx byte count ++#define RT5350_SDM_RPCNT (RT5350_SDM_OFFSET + 0x108) //Switch DMA rx packet count ++#define RT5350_SDM_RBCNT (RT5350_SDM_OFFSET + 0x10C) //Switch DMA rx byte count ++#define RT5350_SDM_CS_ERR (RT5350_SDM_OFFSET + 0x110) //Switch DMA rx checksum error count ++ ++#define RT5350_SDM_ICS_EN BIT(16) ++#define RT5350_SDM_TCS_EN BIT(17) ++#define RT5350_SDM_UCS_EN BIT(18) ++ ++ ++/* MDIO_CFG register bits */ ++#define FE_MDIO_CFG_AUTO_POLL_EN BIT(29) ++#define FE_MDIO_CFG_GP1_BP_EN BIT(16) ++#define FE_MDIO_CFG_GP1_FRC_EN BIT(15) ++#define FE_MDIO_CFG_GP1_SPEED_10 (0 << 13) ++#define FE_MDIO_CFG_GP1_SPEED_100 (1 << 13) ++#define FE_MDIO_CFG_GP1_SPEED_1000 (2 << 13) ++#define FE_MDIO_CFG_GP1_DUPLEX BIT(12) ++#define FE_MDIO_CFG_GP1_FC_TX BIT(11) ++#define FE_MDIO_CFG_GP1_FC_RX BIT(10) ++#define FE_MDIO_CFG_GP1_LNK_DWN BIT(9) ++#define FE_MDIO_CFG_GP1_AN_FAIL BIT(8) ++#define FE_MDIO_CFG_MDC_CLK_DIV_1 (0 << 6) ++#define FE_MDIO_CFG_MDC_CLK_DIV_2 (1 << 6) ++#define FE_MDIO_CFG_MDC_CLK_DIV_4 (2 << 6) ++#define FE_MDIO_CFG_MDC_CLK_DIV_8 (3 << 6) ++#define FE_MDIO_CFG_TURBO_MII_FREQ BIT(5) ++#define FE_MDIO_CFG_TURBO_MII_MODE BIT(4) ++#define FE_MDIO_CFG_RX_CLK_SKEW_0 (0 << 2) ++#define FE_MDIO_CFG_RX_CLK_SKEW_200 (1 << 2) ++#define FE_MDIO_CFG_RX_CLK_SKEW_400 (2 << 2) ++#define FE_MDIO_CFG_RX_CLK_SKEW_INV (3 << 2) ++#define FE_MDIO_CFG_TX_CLK_SKEW_0 0 ++#define FE_MDIO_CFG_TX_CLK_SKEW_200 1 ++#define FE_MDIO_CFG_TX_CLK_SKEW_400 2 ++#define FE_MDIO_CFG_TX_CLK_SKEW_INV 3 ++ ++/* uni-cast port */ ++#define FE_GDM1_ICS_EN BIT(22) ++#define FE_GDM1_TCS_EN BIT(21) ++#define FE_GDM1_UCS_EN BIT(20) ++#define FE_GDM1_JMB_EN BIT(19) ++#define FE_GDM1_STRPCRC BIT(16) ++#define FE_GDM1_UFRC_P_CPU (0 << 12) ++#define FE_GDM1_UFRC_P_GDMA1 (1 << 12) ++#define FE_GDM1_UFRC_P_PPE (6 << 12) ++ ++/* checksums */ ++#define FE_ICS_GEN_EN BIT(2) ++#define FE_UCS_GEN_EN BIT(1) ++#define FE_TCS_GEN_EN BIT(0) ++ ++/* dma ring */ ++#define FE_PST_DRX_IDX0 BIT(16) ++#define FE_PST_DTX_IDX3 BIT(3) ++#define FE_PST_DTX_IDX2 BIT(2) ++#define FE_PST_DTX_IDX1 BIT(1) ++#define FE_PST_DTX_IDX0 BIT(0) ++ ++#define FE_TX_WB_DDONE BIT(6) ++#define FE_RX_DMA_BUSY BIT(3) ++#define FE_TX_DMA_BUSY BIT(1) ++#define FE_RX_DMA_EN BIT(2) ++#define FE_TX_DMA_EN BIT(0) ++ ++#define FE_PDMA_SIZE_4DWORDS (0 << 4) ++#define FE_PDMA_SIZE_8DWORDS (1 << 4) ++#define FE_PDMA_SIZE_16DWORDS (2 << 4) ++ ++#define FE_US_CYC_CNT_MASK 0xff ++#define FE_US_CYC_CNT_SHIFT 0x8 ++#define FE_US_CYC_CNT_DIVISOR 1000000 ++ ++#define RX_DMA_PLEN0(_x) (((_x) >> 16) & 0x3fff) ++#define RX_DMA_LSO BIT(30) ++#define RX_DMA_DONE BIT(31) ++#define RX_DMA_L4VALID BIT(30) ++ ++struct fe_rx_dma { ++ unsigned int rxd1; ++ unsigned int rxd2; ++ unsigned int rxd3; ++ unsigned int rxd4; ++} __packed __aligned(4); ++ ++#define TX_DMA_PLEN0_MASK ((0x3fff) << 16) ++#define TX_DMA_PLEN0(_x) (((_x) & 0x3fff) << 16) ++#define TX_DMA_LSO BIT(30) ++#define TX_DMA_DONE BIT(31) ++#define TX_DMA_QN(_x) ((_x) << 16) ++#define TX_DMA_PN(_x) ((_x) << 24) ++#define TX_DMA_QN_MASK TX_DMA_QN(0x7) ++#define TX_DMA_PN_MASK TX_DMA_PN(0x7) ++#define TX_DMA_CHKSUM (0x7 << 29) ++ ++struct fe_tx_dma { ++ unsigned int txd1; ++ unsigned int txd2; ++ unsigned int txd3; ++ unsigned int txd4; ++} __packed __aligned(4); ++ ++struct fe_priv; ++ ++struct fe_phy { ++ struct phy_device *phy[8]; ++ struct device_node *phy_node[8]; ++ const __be32 *phy_fixed[8]; ++ int duplex[8]; ++ int speed[8]; ++ spinlock_t lock; ++ ++ int (*connect)(struct fe_priv *priv); ++ void (*disconnect)(struct fe_priv *priv); ++ void (*start)(struct fe_priv *priv); ++ void (*stop)(struct fe_priv *priv); ++}; ++ ++struct fe_soc_data ++{ ++ unsigned char mac[6]; ++ const u32 *reg_table; ++ ++ void (*reset_fe)(void); ++ void (*set_mac)(struct fe_priv *priv, unsigned char *mac); ++ void (*fwd_config)(struct fe_priv *priv); ++ void (*tx_dma)(struct fe_priv *priv, int idx, int len); ++ void (*rx_dma)(struct fe_priv *priv, int idx, int len); ++ int (*switch_init)(struct fe_priv *priv); ++ void (*port_init)(struct fe_priv *priv, struct device_node *port); ++ int (*has_carrier)(struct fe_priv *priv); ++ int (*mdio_init)(struct fe_priv *priv); ++ void (*mdio_cleanup)(struct fe_priv *priv); ++ int (*mdio_write)(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val); ++ int (*mdio_read)(struct mii_bus *bus, int phy_addr, int phy_reg); ++ void (*mdio_adjust_link)(struct fe_priv *priv, int port); ++ ++ void *swpriv; ++ u32 pdma_glo_cfg; ++ u32 rx_dly_int; ++ u32 tx_dly_int; ++ u32 checksum_bit; ++ ++ int min_pkt_len; ++}; ++ ++struct fe_priv ++{ ++ spinlock_t page_lock; ++ ++ struct fe_soc_data *soc; ++ struct net_device *netdev; ++ struct device *device; ++ unsigned long sysclk; ++ ++ struct fe_rx_dma *rx_dma; ++ struct sk_buff *rx_skb[NUM_DMA_DESC]; ++ struct napi_struct rx_napi; ++ dma_addr_t rx_phys; ++ ++ struct fe_tx_dma *tx_dma; ++ struct sk_buff *tx_skb[NUM_DMA_DESC]; ++ struct napi_struct tx_napi; ++ dma_addr_t tx_phys; ++ unsigned int tx_free_idx; ++ ++ struct fe_phy *phy; ++ struct mii_bus *mii_bus; ++ int mii_irq[PHY_MAX_ADDR]; ++ ++ int link[8]; ++}; ++ ++extern const struct of_device_id of_fe_match[]; ++ ++void fe_w32(u32 val, unsigned reg); ++u32 fe_r32(unsigned reg); ++ ++#endif /* FE_ETH_H */ +diff --git a/drivers/net/ethernet/ralink/soc_mt7620.c b/drivers/net/ethernet/ralink/soc_mt7620.c +new file mode 100644 +index 0000000..55e303f +--- /dev/null ++++ b/drivers/net/ethernet/ralink/soc_mt7620.c +@@ -0,0 +1,111 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++#include <linux/platform_device.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#include "ralink_soc_eth.h" ++#include "gsw_mt7620a.h" ++ ++#define MT7620A_CDMA_CSG_CFG 0x400 ++#define MT7620_DMA_VID (MT7620A_CDMA_CSG_CFG | 0x30) ++#define MT7620A_DMA_2B_OFFSET BIT(31) ++#define MT7620A_RESET_FE BIT(21) ++#define MT7620A_RESET_ESW BIT(23) ++#define MT7620_L4_VALID BIT(23) ++ ++#define SYSC_REG_RESET_CTRL 0x34 ++#define MAX_RX_LENGTH 1536 ++ ++#define CDMA_ICS_EN BIT(2) ++#define CDMA_UCS_EN BIT(1) ++#define CDMA_TCS_EN BIT(0) ++ ++#define GDMA_ICS_EN BIT(22) ++#define GDMA_TCS_EN BIT(21) ++#define GDMA_UCS_EN BIT(20) ++ ++static const u32 rt5350_reg_table[FE_REG_COUNT] = { ++ [FE_REG_PDMA_GLO_CFG] = RT5350_PDMA_GLO_CFG, ++ [FE_REG_PDMA_RST_CFG] = RT5350_PDMA_RST_CFG, ++ [FE_REG_DLY_INT_CFG] = RT5350_DLY_INT_CFG, ++ [FE_REG_TX_BASE_PTR0] = RT5350_TX_BASE_PTR0, ++ [FE_REG_TX_MAX_CNT0] = RT5350_TX_MAX_CNT0, ++ [FE_REG_TX_CTX_IDX0] = RT5350_TX_CTX_IDX0, ++ [FE_REG_RX_BASE_PTR0] = RT5350_RX_BASE_PTR0, ++ [FE_REG_RX_MAX_CNT0] = RT5350_RX_MAX_CNT0, ++ [FE_REG_RX_CALC_IDX0] = RT5350_RX_CALC_IDX0, ++ [FE_REG_FE_INT_ENABLE] = RT5350_FE_INT_ENABLE, ++ [FE_REG_FE_INT_STATUS] = RT5350_FE_INT_STATUS, ++ [FE_REG_FE_DMA_VID_BASE] = MT7620_DMA_VID, ++}; ++ ++static void mt7620_fe_reset(void) ++{ ++ rt_sysc_w32(MT7620A_RESET_FE | MT7620A_RESET_ESW, SYSC_REG_RESET_CTRL); ++ rt_sysc_w32(0, SYSC_REG_RESET_CTRL); ++} ++ ++static void mt7620_fwd_config(struct fe_priv *priv) ++{ ++ fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) & ~7, MT7620A_GDMA1_FWD_CFG); ++ fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) | (GDMA_ICS_EN | GDMA_TCS_EN | GDMA_UCS_EN), MT7620A_GDMA1_FWD_CFG); ++ fe_w32(fe_r32(MT7620A_CDMA_CSG_CFG) | (CDMA_ICS_EN | CDMA_UCS_EN | CDMA_TCS_EN), MT7620A_CDMA_CSG_CFG); ++} ++ ++static void mt7620_tx_dma(struct fe_priv *priv, int idx, int len) ++{ ++ if (len) ++ priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_PLEN0(len); ++ else ++ priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_DONE; ++} ++ ++static void mt7620_rx_dma(struct fe_priv *priv, int idx, int len) ++{ ++ priv->rx_dma[idx].rxd2 = RX_DMA_PLEN0(len); ++} ++ ++static struct fe_soc_data mt7620_data = { ++ .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, ++ .reset_fe = mt7620_fe_reset, ++ .set_mac = mt7620_set_mac, ++ .fwd_config = mt7620_fwd_config, ++ .tx_dma = mt7620_tx_dma, ++ .rx_dma = mt7620_rx_dma, ++ .switch_init = mt7620_gsw_probe, ++ .port_init = mt7620_port_init, ++ .min_pkt_len = 0, ++ .reg_table = rt5350_reg_table, ++ .pdma_glo_cfg = FE_PDMA_SIZE_16DWORDS | MT7620A_DMA_2B_OFFSET, ++ .rx_dly_int = RT5350_RX_DLY_INT, ++ .tx_dly_int = RT5350_TX_DLY_INT, ++ .checksum_bit = MT7620_L4_VALID, ++ .has_carrier = mt7620a_has_carrier, ++ .mdio_read = mt7620_mdio_read, ++ .mdio_write = mt7620_mdio_write, ++ .mdio_adjust_link = mt7620_mdio_link_adjust, ++}; ++ ++const struct of_device_id of_fe_match[] = { ++ { .compatible = "ralink,mt7620a-eth", .data = &mt7620_data }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, of_fe_match); +diff --git a/drivers/net/ethernet/ralink/soc_rt2880.c b/drivers/net/ethernet/ralink/soc_rt2880.c +new file mode 100644 +index 0000000..fdbd118 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/soc_rt2880.c +@@ -0,0 +1,51 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#include "ralink_soc_eth.h" ++#include "mdio_rt2880.h" ++ ++#define SYSC_REG_RESET_CTRL 0x034 ++#define RT2880_RESET_FE BIT(18) ++ ++void rt2880_fe_reset(void) ++{ ++ rt_sysc_w32(RT2880_RESET_FE, SYSC_REG_RESET_CTRL); ++} ++ ++struct fe_soc_data rt2880_data = { ++ .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, ++ .reset_fe = rt2880_fe_reset, ++ .min_pkt_len = 64, ++ .pdma_glo_cfg = FE_PDMA_SIZE_4DWORDS, ++ .checksum_bit = RX_DMA_L4VALID, ++ .rx_dly_int = FE_RX_DLY_INT, ++ .tx_dly_int = FE_TX_DLY_INT, ++ .mdio_read = rt2880_mdio_read, ++ .mdio_write = rt2880_mdio_write, ++ .mdio_link_adjust = rt2880_mdio_link_adjust, ++}; ++ ++const struct of_device_id of_fe_match[] = { ++ { .compatible = "ralink,rt2880-eth", .data = &rt2880_data }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, of_fe_match); +diff --git a/drivers/net/ethernet/ralink/soc_rt305x.c b/drivers/net/ethernet/ralink/soc_rt305x.c +new file mode 100644 +index 0000000..c43d3f9 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/soc_rt305x.c +@@ -0,0 +1,102 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#include "ralink_soc_eth.h" ++ ++#define RT305X_RESET_FE BIT(21) ++#define RT305X_RESET_ESW BIT(23) ++#define SYSC_REG_RESET_CTRL 0x034 ++ ++static const u32 rt5350_reg_table[FE_REG_COUNT] = { ++ [FE_REG_PDMA_GLO_CFG] = RT5350_PDMA_GLO_CFG, ++ [FE_REG_PDMA_RST_CFG] = RT5350_PDMA_RST_CFG, ++ [FE_REG_DLY_INT_CFG] = RT5350_DLY_INT_CFG, ++ [FE_REG_TX_BASE_PTR0] = RT5350_TX_BASE_PTR0, ++ [FE_REG_TX_MAX_CNT0] = RT5350_TX_MAX_CNT0, ++ [FE_REG_TX_CTX_IDX0] = RT5350_TX_CTX_IDX0, ++ [FE_REG_RX_BASE_PTR0] = RT5350_RX_BASE_PTR0, ++ [FE_REG_RX_MAX_CNT0] = RT5350_RX_MAX_CNT0, ++ [FE_REG_RX_CALC_IDX0] = RT5350_RX_CALC_IDX0, ++ [FE_REG_FE_INT_ENABLE] = RT5350_FE_INT_ENABLE, ++ [FE_REG_FE_INT_STATUS] = RT5350_FE_INT_STATUS, ++ [FE_REG_FE_DMA_VID_BASE] = 0, ++}; ++ ++static void rt305x_fe_reset(void) ++{ ++ rt_sysc_w32(RT305X_RESET_FE, SYSC_REG_RESET_CTRL); ++ rt_sysc_w32(0, SYSC_REG_RESET_CTRL); ++} ++ ++static void rt5350_set_mac(struct fe_priv *priv, unsigned char *mac) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->page_lock, flags); ++ fe_w32((mac[0] << 8) | mac[1], RT5350_SDM_MAC_ADRH); ++ fe_w32((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], ++ RT5350_SDM_MAC_ADRL); ++ spin_unlock_irqrestore(&priv->page_lock, flags); ++} ++ ++static void rt5350_fwd_config(struct fe_priv *priv) ++{ ++ fe_w32(fe_r32(RT5350_SDM_CFG) & ~0xffff, RT5350_SDM_CFG); ++ fe_w32(fe_r32(RT5350_SDM_CFG) | RT5350_SDM_ICS_EN | RT5350_SDM_TCS_EN | RT5350_SDM_UCS_EN, ++ RT5350_SDM_CFG); ++} ++ ++static void rt5350_fe_reset(void) ++{ ++ rt_sysc_w32(RT305X_RESET_FE | RT305X_RESET_ESW, SYSC_REG_RESET_CTRL); ++ rt_sysc_w32(0, SYSC_REG_RESET_CTRL); ++} ++ ++static struct fe_soc_data rt3050_data = { ++ .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, ++ .reset_fe = rt305x_fe_reset, ++ .min_pkt_len = 64, ++ .pdma_glo_cfg = FE_PDMA_SIZE_4DWORDS, ++ .checksum_bit = RX_DMA_L4VALID, ++ .rx_dly_int = FE_RX_DLY_INT, ++ .tx_dly_int = FE_TX_DLY_INT, ++}; ++ ++static struct fe_soc_data rt5350_data = { ++ .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, ++ .reg_table = rt5350_reg_table, ++ .reset_fe = rt5350_fe_reset, ++ .set_mac = rt5350_set_mac, ++ .fwd_config = rt5350_fwd_config, ++ .min_pkt_len = 64, ++ .pdma_glo_cfg = FE_PDMA_SIZE_4DWORDS, ++ .checksum_bit = RX_DMA_L4VALID, ++ .rx_dly_int = RT5350_RX_DLY_INT, ++ .tx_dly_int = RT5350_TX_DLY_INT, ++}; ++ ++const struct of_device_id of_fe_match[] = { ++ { .compatible = "ralink,rt3050-eth", .data = &rt3050_data }, ++ { .compatible = "ralink,rt5350-eth", .data = &rt5350_data }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, of_fe_match); +diff --git a/drivers/net/ethernet/ralink/soc_rt3883.c b/drivers/net/ethernet/ralink/soc_rt3883.c +new file mode 100644 +index 0000000..3886be1 +--- /dev/null ++++ b/drivers/net/ethernet/ralink/soc_rt3883.c +@@ -0,0 +1,59 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public 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) 2009-2013 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#include "ralink_soc_eth.h" ++#include "mdio_rt2880.h" ++ ++#define RT3883_SYSC_REG_RSTCTRL 0x34 ++#define RT3883_RSTCTRL_FE BIT(21) ++ ++static void rt3883_fe_reset(void) ++{ ++ u32 t; ++ ++ t = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL); ++ t |= RT3883_RSTCTRL_FE; ++ rt_sysc_w32(t , RT3883_SYSC_REG_RSTCTRL); ++ ++ t &= ~RT3883_RSTCTRL_FE; ++ rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL); ++} ++ ++static struct fe_soc_data rt3883_data = { ++ .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, ++ .reset_fe = rt3883_fe_reset, ++ .min_pkt_len = 64, ++ .pdma_glo_cfg = FE_PDMA_SIZE_4DWORDS, ++ .rx_dly_int = FE_RX_DLY_INT, ++ .tx_dly_int = FE_TX_DLY_INT, ++ .checksum_bit = RX_DMA_L4VALID, ++ .mdio_read = rt2880_mdio_read, ++ .mdio_write = rt2880_mdio_write, ++ .mdio_link_adjust = rt2880_mdio_link_adjust, ++}; ++ ++const struct of_device_id of_fe_match[] = { ++ { .compatible = "ralink,rt3883-eth", .data = &rt3883_data }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, of_fe_match); ++ +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0073-USB-phy-add-ralink-SoC-driver.patch b/target/linux/ramips/patches-3.8/0073-USB-phy-add-ralink-SoC-driver.patch new file mode 100644 index 0000000..e6a63bd --- /dev/null +++ b/target/linux/ramips/patches-3.8/0073-USB-phy-add-ralink-SoC-driver.patch @@ -0,0 +1,238 @@ +From 277c29fcf17b9e3ada6ddc3bda0f7780bb8a222a Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 20 Jun 2013 19:06:09 +0200 +Subject: [PATCH 73/79] USB: phy: add ralink SoC driver + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + drivers/usb/phy/Kconfig | 8 ++ + drivers/usb/phy/Makefile | 1 + + drivers/usb/phy/ralink-phy.c | 191 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 200 insertions(+) + create mode 100644 drivers/usb/phy/ralink-phy.c + +diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig +index 5de6e7f..9b899b0 100644 +--- a/drivers/usb/phy/Kconfig ++++ b/drivers/usb/phy/Kconfig +@@ -45,3 +45,11 @@ config USB_RCAR_PHY + + To compile this driver as a module, choose M here: the + module will be called rcar-phy. ++ ++config RALINK_USBPHY ++ bool "Ralink USB PHY controller Driver" ++ depends on MIPS && RALINK ++ select USB_OTG_UTILS ++ help ++ Enable this to support ralink USB phy controller for ralink ++ SoCs. +diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile +index 1a579a8..52ba41a 100644 +--- a/drivers/usb/phy/Makefile ++++ b/drivers/usb/phy/Makefile +@@ -9,3 +9,4 @@ obj-$(CONFIG_USB_ISP1301) += isp1301.o + obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o + obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o + obj-$(CONFIG_USB_RCAR_PHY) += rcar-phy.o ++obj-$(CONFIG_RALINK_USBPHY) += ralink-phy.o +diff --git a/drivers/usb/phy/ralink-phy.c b/drivers/usb/phy/ralink-phy.c +new file mode 100644 +index 0000000..3fbabea +--- /dev/null ++++ b/drivers/usb/phy/ralink-phy.c +@@ -0,0 +1,191 @@ ++/* ++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org> ++ * ++ * based on: Renesas R-Car USB phy driver ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/io.h> ++#include <linux/usb/otg.h> ++#include <linux/of_platform.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++#include <linux/module.h> ++#include <linux/reset.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#define RT_SYSC_REG_SYSCFG1 0x014 ++#define RT_SYSC_REG_CLKCFG1 0x030 ++#define RT_SYSC_REG_USB_PHY_CFG 0x05c ++ ++#define RT_RSTCTRL_UDEV BIT(25) ++#define RT_RSTCTRL_UHST BIT(22) ++#define RT_SYSCFG1_USB0_HOST_MODE BIT(10) ++ ++#define MT7620_CLKCFG1_UPHY0_CLK_EN BIT(25) ++#define RT_CLKCFG1_UPHY1_CLK_EN BIT(20) ++#define RT_CLKCFG1_UPHY0_CLK_EN BIT(18) ++ ++#define USB_PHY_UTMI_8B60M BIT(1) ++#define UDEV_WAKEUP BIT(0) ++ ++static atomic_t usb_pwr_ref = ATOMIC_INIT(0); ++static struct reset_control *rstdev; ++static struct reset_control *rsthost; ++static u32 phy_clk; ++ ++static void usb_phy_enable(int state) ++{ ++ if (state) ++ rt_sysc_m32(0, phy_clk, RT_SYSC_REG_CLKCFG1); ++ else ++ rt_sysc_m32(phy_clk, 0, RT_SYSC_REG_CLKCFG1); ++ mdelay(100); ++} ++ ++static int usb_power_on(struct usb_phy *phy) ++{ ++ if (atomic_inc_return(&usb_pwr_ref) == 1) { ++ u32 t; ++ ++ usb_phy_enable(1); ++ ++ reset_control_assert(rstdev); ++ reset_control_assert(rsthost); ++ ++ if (OTG_STATE_B_HOST) { ++ rt_sysc_m32(0, RT_SYSCFG1_USB0_HOST_MODE, RT_SYSC_REG_SYSCFG1); ++ reset_control_deassert(rsthost); ++ } else { ++ rt_sysc_m32(RT_SYSCFG1_USB0_HOST_MODE, 0, RT_SYSC_REG_SYSCFG1); ++ reset_control_deassert(rstdev); ++ } ++ mdelay(100); ++ ++ t = rt_sysc_r32(RT_SYSC_REG_USB_PHY_CFG); ++ dev_info(phy->dev, "remote usb device wakeup %s\n", ++ (t & UDEV_WAKEUP) ? ("enabbled") : ("disabled")); ++ if (t & USB_PHY_UTMI_8B60M) ++ dev_info(phy->dev, "UTMI 8bit 60MHz\n"); ++ else ++ dev_info(phy->dev, "UTMI 16bit 30MHz\n"); ++ } ++ ++ return 0; ++} ++ ++static void usb_power_off(struct usb_phy *phy) ++{ ++ if (atomic_dec_return(&usb_pwr_ref) == 0) { ++ usb_phy_enable(0); ++ reset_control_assert(rstdev); ++ reset_control_assert(rsthost); ++ } ++} ++ ++static int usb_set_host(struct usb_otg *otg, struct usb_bus *host) ++{ ++ otg->gadget = NULL; ++ otg->host = host; ++ ++ return 0; ++} ++ ++static int usb_set_peripheral(struct usb_otg *otg, ++ struct usb_gadget *gadget) ++{ ++ otg->host = NULL; ++ otg->gadget = gadget; ++ ++ return 0; ++} ++ ++static const struct of_device_id ralink_usbphy_dt_match[] = { ++ { .compatible = "ralink,rt3xxx-usbphy", .data = (void *) (RT_CLKCFG1_UPHY1_CLK_EN | RT_CLKCFG1_UPHY0_CLK_EN) }, ++ { .compatible = "ralink,mt7620a-usbphy", .data = (void *) MT7620_CLKCFG1_UPHY0_CLK_EN }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ralink_usbphy_dt_match); ++ ++static int usb_phy_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *match; ++ struct device *dev = &pdev->dev; ++ struct usb_otg *otg; ++ struct usb_phy *phy; ++ int ret; ++ ++ match = of_match_device(ralink_usbphy_dt_match, &pdev->dev); ++ phy_clk = (int) match->data; ++ ++ rsthost = devm_reset_control_get(&pdev->dev, "host"); ++ if (IS_ERR(rsthost)) ++ return PTR_ERR(rsthost); ++ ++ rstdev = devm_reset_control_get(&pdev->dev, "device"); ++ if (IS_ERR(rstdev)) ++ return PTR_ERR(rstdev); ++ ++ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); ++ if (!phy) { ++ dev_err(&pdev->dev, "unable to allocate memory for USB PHY\n"); ++ return -ENOMEM; ++ } ++ ++ otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); ++ if (!otg) { ++ dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n"); ++ return -ENOMEM; ++ } ++ ++ phy->dev = dev; ++ phy->label = dev_name(dev); ++ phy->init = usb_power_on; ++ phy->shutdown = usb_power_off; ++ otg->set_host = usb_set_host; ++ otg->set_peripheral = usb_set_peripheral; ++ otg->phy = phy; ++ phy->otg = otg; ++ ret = usb_add_phy(phy, USB_PHY_TYPE_USB2); ++ ++ if (ret < 0) { ++ dev_err(dev, "usb phy addition error\n"); ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, phy); ++ ++ dev_info(&pdev->dev, "loaded\n"); ++ ++ return ret; ++} ++ ++static int usb_phy_remove(struct platform_device *pdev) ++{ ++ struct usb_phy *phy = platform_get_drvdata(pdev); ++ ++ usb_remove_phy(phy); ++ ++ return 0; ++} ++ ++static struct platform_driver usb_phy_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "rt3xxx-usbphy", ++ .of_match_table = of_match_ptr(ralink_usbphy_dt_match), ++ }, ++ .probe = usb_phy_probe, ++ .remove = usb_phy_remove, ++}; ++ ++module_platform_driver(usb_phy_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Ralink USB phy"); ++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0074-USB-MIPS-ralink-fix-usb-issue-on-mt7620.patch b/target/linux/ramips/patches-3.8/0074-USB-MIPS-ralink-fix-usb-issue-on-mt7620.patch new file mode 100644 index 0000000..ad8269c --- /dev/null +++ b/target/linux/ramips/patches-3.8/0074-USB-MIPS-ralink-fix-usb-issue-on-mt7620.patch @@ -0,0 +1,48 @@ +From 93bb6d731e96dc373b88a910ca9db66c560c8f4e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 24 May 2013 21:28:08 +0200 +Subject: [PATCH 74/79] USB: MIPS: ralink: fix usb issue on mt7620 + +USB fails when frequency scaling is enabled. Increase the idle cpu speed when +scaled. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/include/asm/mach-ralink/mt7620.h | 1 + + arch/mips/ralink/mt7620.c | 8 ++++++++ + 2 files changed, 9 insertions(+) + +diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h +index 9809972..d469c69 100644 +--- a/arch/mips/include/asm/mach-ralink/mt7620.h ++++ b/arch/mips/include/asm/mach-ralink/mt7620.h +@@ -20,6 +20,7 @@ + #define SYSC_REG_CHIP_REV 0x0c + #define SYSC_REG_SYSTEM_CONFIG0 0x10 + #define SYSC_REG_SYSTEM_CONFIG1 0x14 ++#define SYSC_REG_CPU_SYS_CLKCFG 0x3c + #define SYSC_REG_CPLL_CONFIG0 0x54 + #define SYSC_REG_CPLL_CONFIG1 0x58 + +diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c +index 4956d96..d76eb85 100644 +--- a/arch/mips/ralink/mt7620.c ++++ b/arch/mips/ralink/mt7620.c +@@ -186,6 +186,14 @@ void __init ralink_clk_init(void) + ralink_clk_add("10000500.uart", 40000000); + ralink_clk_add("10000b00.spi", 40000000); + ralink_clk_add("10000c00.uartlite", 40000000); ++ ++#ifdef CONFIG_USB ++ /* ++ * When the CPU goes into sleep mode, the BUS clock will be too low for ++ * USB to function properly ++ */ ++ rt_sysc_m32(0x1f1f, 0x303, SYSC_REG_CPU_SYS_CLKCFG); ++#endif + } + + void __init ralink_of_remap(void) +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0075-Kbuild-add-missing-space.patch b/target/linux/ramips/patches-3.8/0075-Kbuild-add-missing-space.patch new file mode 100644 index 0000000..b66bd85 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0075-Kbuild-add-missing-space.patch @@ -0,0 +1,38 @@ +From 5d5c270635a50b82931bb32f6fe28b84d45bdb59 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 17 May 2013 01:03:45 +0200 +Subject: [PATCH 75/79] Kbuild: add missing space + +Currently the output looks like this: +DTC arch/mips/ralink/dts/mt7620a_eval.dtb +DTB arch/mips/ralink/dts/mt7620a_eval.dtb.S +AS arch/mips/ralink/dts/mt7620a_eval.dtb.o + +Whitespace error was introduced by initial commit +commit aab94339cd85d726abeae78fc02351fc1910e6a4 +Author: Dirk Brandewie <dirk.brandewie@gmail.com> +Date: Wed Dec 22 11:57:26 2010 -0800 + +of: Add support for linking device tree blobs into vmlinux + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + scripts/Makefile.lib | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index bdf42fd..21c1359 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -246,7 +246,7 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \ + # --------------------------------------------------------------------------- + + # Generate an assembly file to wrap the output of the device tree compiler +-quiet_cmd_dt_S_dtb= DTB $@ ++quiet_cmd_dt_S_dtb= DTB $@ + cmd_dt_S_dtb= \ + ( \ + echo '\#include <asm-generic/vmlinux.lds.h>'; \ +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0076-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch b/target/linux/ramips/patches-3.8/0076-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch new file mode 100644 index 0000000..c1fe6ad --- /dev/null +++ b/target/linux/ramips/patches-3.8/0076-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch @@ -0,0 +1,3446 @@ +From 3bebf4a4400ab70ccef98c069d240dbd17dd718f Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 20 Jun 2013 19:13:25 +0200 +Subject: [PATCH 76/79] mmc: MIPS: ralink: add sdhci for mt7620a SoC + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + drivers/mmc/host/Kconfig | 11 + + drivers/mmc/host/Makefile | 1 + + drivers/mmc/host/mt6575_sd.h | 1068 ++++++++++++++++++ + drivers/mmc/host/sdhci-mt7620.c | 2314 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 3394 insertions(+) + create mode 100644 drivers/mmc/host/mt6575_sd.h + create mode 100644 drivers/mmc/host/sdhci-mt7620.c + +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 8d13c65..04085b3 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -241,6 +241,17 @@ config MMC_SDHCI_S3C_DMA + + YMMV. + ++config MMC_SDHCI_MT7620 ++ tristate "SDHCI platform support for the MT7620 SD/MMC Controller" ++ depends on SOC_MT7620 ++ depends on MMC_SDHCI_PLTFM ++ select MMC_SDHCI_IO_ACCESSORS ++ help ++ This selects the BCM2835 SD/MMC controller. If you have a BCM2835 ++ platform with SD or MMC devices, say Y or M here. ++ ++ If unsure, say N. ++ + config MMC_OMAP + tristate "TI OMAP Multimedia Card Interface support" + depends on ARCH_OMAP +diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile +index e4e218c..be79804 100644 +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -58,6 +58,7 @@ obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o + obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o + obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o + obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o ++obj-$(CONFIG_MMC_SDHCI_MT7620) += sdhci-mt7620.o + + ifeq ($(CONFIG_CB710_DEBUG),y) + CFLAGS-cb710-mmc += -DDEBUG +diff --git a/drivers/mmc/host/mt6575_sd.h b/drivers/mmc/host/mt6575_sd.h +new file mode 100644 +index 0000000..406382c +--- /dev/null ++++ b/drivers/mmc/host/mt6575_sd.h +@@ -0,0 +1,1068 @@ ++/* Copyright Statement: ++ * ++ * This software/firmware and related documentation ("MediaTek Software") are ++ * protected under relevant copyright laws. The information contained herein ++ * is confidential and proprietary to MediaTek Inc. and/or its licensors. ++ * Without the prior written permission of MediaTek inc. and/or its licensors, ++ * any reproduction, modification, use or disclosure of MediaTek Software, ++ * and information contained herein, in whole or in part, shall be strictly prohibited. ++ */ ++/* MediaTek Inc. (C) 2010. All rights reserved. ++ * ++ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES ++ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") ++ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON ++ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. ++ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE ++ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR ++ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH ++ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES ++ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES ++ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK ++ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR ++ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND ++ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, ++ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, ++ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO ++ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. ++ * ++ * The following software/firmware and/or related documentation ("MediaTek Software") ++ * have been modified by MediaTek Inc. All revisions are subject to any receiver's ++ * applicable license agreements with MediaTek Inc. ++ */ ++ ++#ifndef MT6575_SD_H ++#define MT6575_SD_H ++ ++#include <linux/bitops.h> ++#include <linux/mmc/host.h> ++ ++// #include <mach/mt6575_reg_base.h> /* --- by chhung */ ++ ++typedef void (*sdio_irq_handler_t)(void*); /* external irq handler */ ++typedef void (*pm_callback_t)(pm_message_t state, void *data); ++ ++#define MSDC_CD_PIN_EN (1 << 0) /* card detection pin is wired */ ++#define MSDC_WP_PIN_EN (1 << 1) /* write protection pin is wired */ ++#define MSDC_RST_PIN_EN (1 << 2) /* emmc reset pin is wired */ ++#define MSDC_SDIO_IRQ (1 << 3) /* use internal sdio irq (bus) */ ++#define MSDC_EXT_SDIO_IRQ (1 << 4) /* use external sdio irq */ ++#define MSDC_REMOVABLE (1 << 5) /* removable slot */ ++#define MSDC_SYS_SUSPEND (1 << 6) /* suspended by system */ ++#define MSDC_HIGHSPEED (1 << 7) /* high-speed mode support */ ++#define MSDC_UHS1 (1 << 8) /* uhs-1 mode support */ ++#define MSDC_DDR (1 << 9) /* ddr mode support */ ++#define MSDC_SPE (1 << 10) /* special support */ ++#define MSDC_INTERNAL_CLK (1 << 11) /* Force Internal clock */ ++#define MSDC_TABDRV (1 << 12) /* TABLET */ ++ ++ ++#define MSDC_SMPL_RISING (0) ++#define MSDC_SMPL_FALLING (1) ++ ++#define MSDC_CMD_PIN (0) ++#define MSDC_DAT_PIN (1) ++#define MSDC_CD_PIN (2) ++#define MSDC_WP_PIN (3) ++#define MSDC_RST_PIN (4) ++ ++enum { ++ MSDC_CLKSRC_26MHZ = 0, ++ MSDC_CLKSRC_197MHZ = 1, ++ MSDC_CLKSRC_208MHZ = 2 ++}; ++ ++struct msdc_hw { ++ unsigned char clk_src; /* host clock source */ ++ unsigned char cmd_edge; /* command latch edge */ ++ unsigned char data_edge; /* data latch edge */ ++ unsigned char clk_drv; /* clock pad driving */ ++ unsigned char cmd_drv; /* command pad driving */ ++ unsigned char dat_drv; /* data pad driving */ ++ unsigned long flags; /* hardware capability flags */ ++ unsigned long data_pins; /* data pins */ ++ unsigned long data_offset; /* data address offset */ ++ ++ /* config gpio pull mode */ ++ void (*config_gpio_pin)(int type, int pull); ++ ++ /* external power control for card */ ++ void (*ext_power_on)(void); ++ void (*ext_power_off)(void); ++ ++ /* external sdio irq operations */ ++ void (*request_sdio_eirq)(sdio_irq_handler_t sdio_irq_handler, void *data); ++ void (*enable_sdio_eirq)(void); ++ void (*disable_sdio_eirq)(void); ++ ++ /* external cd irq operations */ ++ void (*request_cd_eirq)(sdio_irq_handler_t cd_irq_handler, void *data); ++ void (*enable_cd_eirq)(void); ++ void (*disable_cd_eirq)(void); ++ int (*get_cd_status)(void); ++ ++ /* power management callback for external module */ ++ void (*register_pm)(pm_callback_t pm_cb, void *data); ++}; ++ ++extern struct msdc_hw msdc0_hw; ++extern struct msdc_hw msdc1_hw; ++extern struct msdc_hw msdc2_hw; ++extern struct msdc_hw msdc3_hw; ++ ++ ++/*--------------------------------------------------------------------------*/ ++/* Common Macro */ ++/*--------------------------------------------------------------------------*/ ++#define REG_ADDR(x) ((volatile u32*)(base + OFFSET_##x)) ++ ++/*--------------------------------------------------------------------------*/ ++/* Common Definition */ ++/*--------------------------------------------------------------------------*/ ++#define MSDC_FIFO_SZ (128) ++#define MSDC_FIFO_THD (64) // (128) ++#define MSDC_NUM (4) ++ ++#define MSDC_MS (0) ++#define MSDC_SDMMC (1) ++ ++#define MSDC_MODE_UNKNOWN (0) ++#define MSDC_MODE_PIO (1) ++#define MSDC_MODE_DMA_BASIC (2) ++#define MSDC_MODE_DMA_DESC (3) ++#define MSDC_MODE_DMA_ENHANCED (4) ++#define MSDC_MODE_MMC_STREAM (5) ++ ++#define MSDC_BUS_1BITS (0) ++#define MSDC_BUS_4BITS (1) ++#define MSDC_BUS_8BITS (2) ++ ++#define MSDC_BRUST_8B (3) ++#define MSDC_BRUST_16B (4) ++#define MSDC_BRUST_32B (5) ++#define MSDC_BRUST_64B (6) ++ ++#define MSDC_PIN_PULL_NONE (0) ++#define MSDC_PIN_PULL_DOWN (1) ++#define MSDC_PIN_PULL_UP (2) ++#define MSDC_PIN_KEEP (3) ++ ++#define MSDC_MAX_SCLK (48000000) /* +/- by chhung */ ++#define MSDC_MIN_SCLK (260000) ++ ++#define MSDC_AUTOCMD12 (0x0001) ++#define MSDC_AUTOCMD23 (0x0002) ++#define MSDC_AUTOCMD19 (0x0003) ++ ++#define MSDC_EMMC_BOOTMODE0 (0) /* Pull low CMD mode */ ++#define MSDC_EMMC_BOOTMODE1 (1) /* Reset CMD mode */ ++ ++enum { ++ RESP_NONE = 0, ++ RESP_R1, ++ RESP_R2, ++ RESP_R3, ++ RESP_R4, ++ RESP_R5, ++ RESP_R6, ++ RESP_R7, ++ RESP_R1B ++}; ++ ++/*--------------------------------------------------------------------------*/ ++/* Register Offset */ ++/*--------------------------------------------------------------------------*/ ++#define OFFSET_MSDC_CFG (0x0) ++#define OFFSET_MSDC_IOCON (0x04) ++#define OFFSET_MSDC_PS (0x08) ++#define OFFSET_MSDC_INT (0x0c) ++#define OFFSET_MSDC_INTEN (0x10) ++#define OFFSET_MSDC_FIFOCS (0x14) ++#define OFFSET_MSDC_TXDATA (0x18) ++#define OFFSET_MSDC_RXDATA (0x1c) ++#define OFFSET_SDC_CFG (0x30) ++#define OFFSET_SDC_CMD (0x34) ++#define OFFSET_SDC_ARG (0x38) ++#define OFFSET_SDC_STS (0x3c) ++#define OFFSET_SDC_RESP0 (0x40) ++#define OFFSET_SDC_RESP1 (0x44) ++#define OFFSET_SDC_RESP2 (0x48) ++#define OFFSET_SDC_RESP3 (0x4c) ++#define OFFSET_SDC_BLK_NUM (0x50) ++#define OFFSET_SDC_CSTS (0x58) ++#define OFFSET_SDC_CSTS_EN (0x5c) ++#define OFFSET_SDC_DCRC_STS (0x60) ++#define OFFSET_EMMC_CFG0 (0x70) ++#define OFFSET_EMMC_CFG1 (0x74) ++#define OFFSET_EMMC_STS (0x78) ++#define OFFSET_EMMC_IOCON (0x7c) ++#define OFFSET_SDC_ACMD_RESP (0x80) ++#define OFFSET_SDC_ACMD19_TRG (0x84) ++#define OFFSET_SDC_ACMD19_STS (0x88) ++#define OFFSET_MSDC_DMA_SA (0x90) ++#define OFFSET_MSDC_DMA_CA (0x94) ++#define OFFSET_MSDC_DMA_CTRL (0x98) ++#define OFFSET_MSDC_DMA_CFG (0x9c) ++#define OFFSET_MSDC_DBG_SEL (0xa0) ++#define OFFSET_MSDC_DBG_OUT (0xa4) ++#define OFFSET_MSDC_PATCH_BIT (0xb0) ++#define OFFSET_MSDC_PATCH_BIT1 (0xb4) ++#define OFFSET_MSDC_PAD_CTL0 (0xe0) ++#define OFFSET_MSDC_PAD_CTL1 (0xe4) ++#define OFFSET_MSDC_PAD_CTL2 (0xe8) ++#define OFFSET_MSDC_PAD_TUNE (0xec) ++#define OFFSET_MSDC_DAT_RDDLY0 (0xf0) ++#define OFFSET_MSDC_DAT_RDDLY1 (0xf4) ++#define OFFSET_MSDC_HW_DBG (0xf8) ++#define OFFSET_MSDC_VERSION (0x100) ++#define OFFSET_MSDC_ECO_VER (0x104) ++ ++/*--------------------------------------------------------------------------*/ ++/* Register Address */ ++/*--------------------------------------------------------------------------*/ ++ ++/* common register */ ++#define MSDC_CFG REG_ADDR(MSDC_CFG) ++#define MSDC_IOCON REG_ADDR(MSDC_IOCON) ++#define MSDC_PS REG_ADDR(MSDC_PS) ++#define MSDC_INT REG_ADDR(MSDC_INT) ++#define MSDC_INTEN REG_ADDR(MSDC_INTEN) ++#define MSDC_FIFOCS REG_ADDR(MSDC_FIFOCS) ++#define MSDC_TXDATA REG_ADDR(MSDC_TXDATA) ++#define MSDC_RXDATA REG_ADDR(MSDC_RXDATA) ++#define MSDC_PATCH_BIT0 REG_ADDR(MSDC_PATCH_BIT) ++ ++/* sdmmc register */ ++#define SDC_CFG REG_ADDR(SDC_CFG) ++#define SDC_CMD REG_ADDR(SDC_CMD) ++#define SDC_ARG REG_ADDR(SDC_ARG) ++#define SDC_STS REG_ADDR(SDC_STS) ++#define SDC_RESP0 REG_ADDR(SDC_RESP0) ++#define SDC_RESP1 REG_ADDR(SDC_RESP1) ++#define SDC_RESP2 REG_ADDR(SDC_RESP2) ++#define SDC_RESP3 REG_ADDR(SDC_RESP3) ++#define SDC_BLK_NUM REG_ADDR(SDC_BLK_NUM) ++#define SDC_CSTS REG_ADDR(SDC_CSTS) ++#define SDC_CSTS_EN REG_ADDR(SDC_CSTS_EN) ++#define SDC_DCRC_STS REG_ADDR(SDC_DCRC_STS) ++ ++/* emmc register*/ ++#define EMMC_CFG0 REG_ADDR(EMMC_CFG0) ++#define EMMC_CFG1 REG_ADDR(EMMC_CFG1) ++#define EMMC_STS REG_ADDR(EMMC_STS) ++#define EMMC_IOCON REG_ADDR(EMMC_IOCON) ++ ++/* auto command register */ ++#define SDC_ACMD_RESP REG_ADDR(SDC_ACMD_RESP) ++#define SDC_ACMD19_TRG REG_ADDR(SDC_ACMD19_TRG) ++#define SDC_ACMD19_STS REG_ADDR(SDC_ACMD19_STS) ++ ++/* dma register */ ++#define MSDC_DMA_SA REG_ADDR(MSDC_DMA_SA) ++#define MSDC_DMA_CA REG_ADDR(MSDC_DMA_CA) ++#define MSDC_DMA_CTRL REG_ADDR(MSDC_DMA_CTRL) ++#define MSDC_DMA_CFG REG_ADDR(MSDC_DMA_CFG) ++ ++/* pad ctrl register */ ++#define MSDC_PAD_CTL0 REG_ADDR(MSDC_PAD_CTL0) ++#define MSDC_PAD_CTL1 REG_ADDR(MSDC_PAD_CTL1) ++#define MSDC_PAD_CTL2 REG_ADDR(MSDC_PAD_CTL2) ++ ++/* data read delay */ ++#define MSDC_DAT_RDDLY0 REG_ADDR(MSDC_DAT_RDDLY0) ++#define MSDC_DAT_RDDLY1 REG_ADDR(MSDC_DAT_RDDLY1) ++ ++/* debug register */ ++#define MSDC_DBG_SEL REG_ADDR(MSDC_DBG_SEL) ++#define MSDC_DBG_OUT REG_ADDR(MSDC_DBG_OUT) ++ ++/* misc register */ ++#define MSDC_PATCH_BIT REG_ADDR(MSDC_PATCH_BIT) ++#define MSDC_PATCH_BIT1 REG_ADDR(MSDC_PATCH_BIT1) ++#define MSDC_PAD_TUNE REG_ADDR(MSDC_PAD_TUNE) ++#define MSDC_HW_DBG REG_ADDR(MSDC_HW_DBG) ++#define MSDC_VERSION REG_ADDR(MSDC_VERSION) ++#define MSDC_ECO_VER REG_ADDR(MSDC_ECO_VER) /* ECO Version */ ++ ++/*--------------------------------------------------------------------------*/ ++/* Register Mask */ ++/*--------------------------------------------------------------------------*/ ++ ++/* MSDC_CFG mask */ ++#define MSDC_CFG_MODE (0x1 << 0) /* RW */ ++#define MSDC_CFG_CKPDN (0x1 << 1) /* RW */ ++#define MSDC_CFG_RST (0x1 << 2) /* RW */ ++#define MSDC_CFG_PIO (0x1 << 3) /* RW */ ++#define MSDC_CFG_CKDRVEN (0x1 << 4) /* RW */ ++#define MSDC_CFG_BV18SDT (0x1 << 5) /* RW */ ++#define MSDC_CFG_BV18PSS (0x1 << 6) /* R */ ++#define MSDC_CFG_CKSTB (0x1 << 7) /* R */ ++#define MSDC_CFG_CKDIV (0xff << 8) /* RW */ ++#define MSDC_CFG_CKMOD (0x3 << 16) /* RW */ ++ ++/* MSDC_IOCON mask */ ++#define MSDC_IOCON_SDR104CKS (0x1 << 0) /* RW */ ++#define MSDC_IOCON_RSPL (0x1 << 1) /* RW */ ++#define MSDC_IOCON_DSPL (0x1 << 2) /* RW */ ++#define MSDC_IOCON_DDLSEL (0x1 << 3) /* RW */ ++#define MSDC_IOCON_DDR50CKD (0x1 << 4) /* RW */ ++#define MSDC_IOCON_DSPLSEL (0x1 << 5) /* RW */ ++#define MSDC_IOCON_D0SPL (0x1 << 16) /* RW */ ++#define MSDC_IOCON_D1SPL (0x1 << 17) /* RW */ ++#define MSDC_IOCON_D2SPL (0x1 << 18) /* RW */ ++#define MSDC_IOCON_D3SPL (0x1 << 19) /* RW */ ++#define MSDC_IOCON_D4SPL (0x1 << 20) /* RW */ ++#define MSDC_IOCON_D5SPL (0x1 << 21) /* RW */ ++#define MSDC_IOCON_D6SPL (0x1 << 22) /* RW */ ++#define MSDC_IOCON_D7SPL (0x1 << 23) /* RW */ ++#define MSDC_IOCON_RISCSZ (0x3 << 24) /* RW */ ++ ++/* MSDC_PS mask */ ++#define MSDC_PS_CDEN (0x1 << 0) /* RW */ ++#define MSDC_PS_CDSTS (0x1 << 1) /* R */ ++#define MSDC_PS_CDDEBOUNCE (0xf << 12) /* RW */ ++#define MSDC_PS_DAT (0xff << 16) /* R */ ++#define MSDC_PS_CMD (0x1 << 24) /* R */ ++#define MSDC_PS_WP (0x1UL<< 31) /* R */ ++ ++/* MSDC_INT mask */ ++#define MSDC_INT_MMCIRQ (0x1 << 0) /* W1C */ ++#define MSDC_INT_CDSC (0x1 << 1) /* W1C */ ++#define MSDC_INT_ACMDRDY (0x1 << 3) /* W1C */ ++#define MSDC_INT_ACMDTMO (0x1 << 4) /* W1C */ ++#define MSDC_INT_ACMDCRCERR (0x1 << 5) /* W1C */ ++#define MSDC_INT_DMAQ_EMPTY (0x1 << 6) /* W1C */ ++#define MSDC_INT_SDIOIRQ (0x1 << 7) /* W1C */ ++#define MSDC_INT_CMDRDY (0x1 << 8) /* W1C */ ++#define MSDC_INT_CMDTMO (0x1 << 9) /* W1C */ ++#define MSDC_INT_RSPCRCERR (0x1 << 10) /* W1C */ ++#define MSDC_INT_CSTA (0x1 << 11) /* R */ ++#define MSDC_INT_XFER_COMPL (0x1 << 12) /* W1C */ ++#define MSDC_INT_DXFER_DONE (0x1 << 13) /* W1C */ ++#define MSDC_INT_DATTMO (0x1 << 14) /* W1C */ ++#define MSDC_INT_DATCRCERR (0x1 << 15) /* W1C */ ++#define MSDC_INT_ACMD19_DONE (0x1 << 16) /* W1C */ ++ ++/* MSDC_INTEN mask */ ++#define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */ ++#define MSDC_INTEN_CDSC (0x1 << 1) /* RW */ ++#define MSDC_INTEN_ACMDRDY (0x1 << 3) /* RW */ ++#define MSDC_INTEN_ACMDTMO (0x1 << 4) /* RW */ ++#define MSDC_INTEN_ACMDCRCERR (0x1 << 5) /* RW */ ++#define MSDC_INTEN_DMAQ_EMPTY (0x1 << 6) /* RW */ ++#define MSDC_INTEN_SDIOIRQ (0x1 << 7) /* RW */ ++#define MSDC_INTEN_CMDRDY (0x1 << 8) /* RW */ ++#define MSDC_INTEN_CMDTMO (0x1 << 9) /* RW */ ++#define MSDC_INTEN_RSPCRCERR (0x1 << 10) /* RW */ ++#define MSDC_INTEN_CSTA (0x1 << 11) /* RW */ ++#define MSDC_INTEN_XFER_COMPL (0x1 << 12) /* RW */ ++#define MSDC_INTEN_DXFER_DONE (0x1 << 13) /* RW */ ++#define MSDC_INTEN_DATTMO (0x1 << 14) /* RW */ ++#define MSDC_INTEN_DATCRCERR (0x1 << 15) /* RW */ ++#define MSDC_INTEN_ACMD19_DONE (0x1 << 16) /* RW */ ++ ++/* MSDC_FIFOCS mask */ ++#define MSDC_FIFOCS_RXCNT (0xff << 0) /* R */ ++#define MSDC_FIFOCS_TXCNT (0xff << 16) /* R */ ++#define MSDC_FIFOCS_CLR (0x1UL<< 31) /* RW */ ++ ++/* SDC_CFG mask */ ++#define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */ ++#define SDC_CFG_INSWKUP (0x1 << 1) /* RW */ ++#define SDC_CFG_BUSWIDTH (0x3 << 16) /* RW */ ++#define SDC_CFG_SDIO (0x1 << 19) /* RW */ ++#define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */ ++#define SDC_CFG_INTATGAP (0x1 << 21) /* RW */ ++#define SDC_CFG_DTOC (0xffUL << 24) /* RW */ ++ ++/* SDC_CMD mask */ ++#define SDC_CMD_OPC (0x3f << 0) /* RW */ ++#define SDC_CMD_BRK (0x1 << 6) /* RW */ ++#define SDC_CMD_RSPTYP (0x7 << 7) /* RW */ ++#define SDC_CMD_DTYP (0x3 << 11) /* RW */ ++#define SDC_CMD_DTYP (0x3 << 11) /* RW */ ++#define SDC_CMD_RW (0x1 << 13) /* RW */ ++#define SDC_CMD_STOP (0x1 << 14) /* RW */ ++#define SDC_CMD_GOIRQ (0x1 << 15) /* RW */ ++#define SDC_CMD_BLKLEN (0xfff<< 16) /* RW */ ++#define SDC_CMD_AUTOCMD (0x3 << 28) /* RW */ ++#define SDC_CMD_VOLSWTH (0x1 << 30) /* RW */ ++ ++/* SDC_STS mask */ ++#define SDC_STS_SDCBUSY (0x1 << 0) /* RW */ ++#define SDC_STS_CMDBUSY (0x1 << 1) /* RW */ ++#define SDC_STS_SWR_COMPL (0x1 << 31) /* RW */ ++ ++/* SDC_DCRC_STS mask */ ++#define SDC_DCRC_STS_NEG (0xf << 8) /* RO */ ++#define SDC_DCRC_STS_POS (0xff << 0) /* RO */ ++ ++/* EMMC_CFG0 mask */ ++#define EMMC_CFG0_BOOTSTART (0x1 << 0) /* W */ ++#define EMMC_CFG0_BOOTSTOP (0x1 << 1) /* W */ ++#define EMMC_CFG0_BOOTMODE (0x1 << 2) /* RW */ ++#define EMMC_CFG0_BOOTACKDIS (0x1 << 3) /* RW */ ++#define EMMC_CFG0_BOOTWDLY (0x7 << 12) /* RW */ ++#define EMMC_CFG0_BOOTSUPP (0x1 << 15) /* RW */ ++ ++/* EMMC_CFG1 mask */ ++#define EMMC_CFG1_BOOTDATTMC (0xfffff << 0) /* RW */ ++#define EMMC_CFG1_BOOTACKTMC (0xfffUL << 20) /* RW */ ++ ++/* EMMC_STS mask */ ++#define EMMC_STS_BOOTCRCERR (0x1 << 0) /* W1C */ ++#define EMMC_STS_BOOTACKERR (0x1 << 1) /* W1C */ ++#define EMMC_STS_BOOTDATTMO (0x1 << 2) /* W1C */ ++#define EMMC_STS_BOOTACKTMO (0x1 << 3) /* W1C */ ++#define EMMC_STS_BOOTUPSTATE (0x1 << 4) /* R */ ++#define EMMC_STS_BOOTACKRCV (0x1 << 5) /* W1C */ ++#define EMMC_STS_BOOTDATRCV (0x1 << 6) /* R */ ++ ++/* EMMC_IOCON mask */ ++#define EMMC_IOCON_BOOTRST (0x1 << 0) /* RW */ ++ ++/* SDC_ACMD19_TRG mask */ ++#define SDC_ACMD19_TRG_TUNESEL (0xf << 0) /* RW */ ++ ++/* MSDC_DMA_CTRL mask */ ++#define MSDC_DMA_CTRL_START (0x1 << 0) /* W */ ++#define MSDC_DMA_CTRL_STOP (0x1 << 1) /* W */ ++#define MSDC_DMA_CTRL_RESUME (0x1 << 2) /* W */ ++#define MSDC_DMA_CTRL_MODE (0x1 << 8) /* RW */ ++#define MSDC_DMA_CTRL_LASTBUF (0x1 << 10) /* RW */ ++#define MSDC_DMA_CTRL_BRUSTSZ (0x7 << 12) /* RW */ ++#define MSDC_DMA_CTRL_XFERSZ (0xffffUL << 16)/* RW */ ++ ++/* MSDC_DMA_CFG mask */ ++#define MSDC_DMA_CFG_STS (0x1 << 0) /* R */ ++#define MSDC_DMA_CFG_DECSEN (0x1 << 1) /* RW */ ++#define MSDC_DMA_CFG_BDCSERR (0x1 << 4) /* R */ ++#define MSDC_DMA_CFG_GPDCSERR (0x1 << 5) /* R */ ++ ++/* MSDC_PATCH_BIT mask */ ++#define MSDC_PATCH_BIT_WFLSMODE (0x1 << 0) /* RW */ ++#define MSDC_PATCH_BIT_ODDSUPP (0x1 << 1) /* RW */ ++#define MSDC_PATCH_BIT_CKGEN_CK (0x1 << 6) /* E2: Fixed to 1 */ ++#define MSDC_PATCH_BIT_IODSSEL (0x1 << 16) /* RW */ ++#define MSDC_PATCH_BIT_IOINTSEL (0x1 << 17) /* RW */ ++#define MSDC_PATCH_BIT_BUSYDLY (0xf << 18) /* RW */ ++#define MSDC_PATCH_BIT_WDOD (0xf << 22) /* RW */ ++#define MSDC_PATCH_BIT_IDRTSEL (0x1 << 26) /* RW */ ++#define MSDC_PATCH_BIT_CMDFSEL (0x1 << 27) /* RW */ ++#define MSDC_PATCH_BIT_INTDLSEL (0x1 << 28) /* RW */ ++#define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */ ++#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */ ++ ++/* MSDC_PATCH_BIT1 mask */ ++#define MSDC_PATCH_BIT1_WRDAT_CRCS (0x7 << 3) ++#define MSDC_PATCH_BIT1_CMD_RSP (0x7 << 0) ++ ++/* MSDC_PAD_CTL0 mask */ ++#define MSDC_PAD_CTL0_CLKDRVN (0x7 << 0) /* RW */ ++#define MSDC_PAD_CTL0_CLKDRVP (0x7 << 4) /* RW */ ++#define MSDC_PAD_CTL0_CLKSR (0x1 << 8) /* RW */ ++#define MSDC_PAD_CTL0_CLKPD (0x1 << 16) /* RW */ ++#define MSDC_PAD_CTL0_CLKPU (0x1 << 17) /* RW */ ++#define MSDC_PAD_CTL0_CLKSMT (0x1 << 18) /* RW */ ++#define MSDC_PAD_CTL0_CLKIES (0x1 << 19) /* RW */ ++#define MSDC_PAD_CTL0_CLKTDSEL (0xf << 20) /* RW */ ++#define MSDC_PAD_CTL0_CLKRDSEL (0xffUL<< 24) /* RW */ ++ ++/* MSDC_PAD_CTL1 mask */ ++#define MSDC_PAD_CTL1_CMDDRVN (0x7 << 0) /* RW */ ++#define MSDC_PAD_CTL1_CMDDRVP (0x7 << 4) /* RW */ ++#define MSDC_PAD_CTL1_CMDSR (0x1 << 8) /* RW */ ++#define MSDC_PAD_CTL1_CMDPD (0x1 << 16) /* RW */ ++#define MSDC_PAD_CTL1_CMDPU (0x1 << 17) /* RW */ ++#define MSDC_PAD_CTL1_CMDSMT (0x1 << 18) /* RW */ ++#define MSDC_PAD_CTL1_CMDIES (0x1 << 19) /* RW */ ++#define MSDC_PAD_CTL1_CMDTDSEL (0xf << 20) /* RW */ ++#define MSDC_PAD_CTL1_CMDRDSEL (0xffUL<< 24) /* RW */ ++ ++/* MSDC_PAD_CTL2 mask */ ++#define MSDC_PAD_CTL2_DATDRVN (0x7 << 0) /* RW */ ++#define MSDC_PAD_CTL2_DATDRVP (0x7 << 4) /* RW */ ++#define MSDC_PAD_CTL2_DATSR (0x1 << 8) /* RW */ ++#define MSDC_PAD_CTL2_DATPD (0x1 << 16) /* RW */ ++#define MSDC_PAD_CTL2_DATPU (0x1 << 17) /* RW */ ++#define MSDC_PAD_CTL2_DATIES (0x1 << 19) /* RW */ ++#define MSDC_PAD_CTL2_DATSMT (0x1 << 18) /* RW */ ++#define MSDC_PAD_CTL2_DATTDSEL (0xf << 20) /* RW */ ++#define MSDC_PAD_CTL2_DATRDSEL (0xffUL<< 24) /* RW */ ++ ++/* MSDC_PAD_TUNE mask */ ++#define MSDC_PAD_TUNE_DATWRDLY (0x1F << 0) /* RW */ ++#define MSDC_PAD_TUNE_DATRRDLY (0x1F << 8) /* RW */ ++#define MSDC_PAD_TUNE_CMDRDLY (0x1F << 16) /* RW */ ++#define MSDC_PAD_TUNE_CMDRRDLY (0x1FUL << 22) /* RW */ ++#define MSDC_PAD_TUNE_CLKTXDLY (0x1FUL << 27) /* RW */ ++ ++/* MSDC_DAT_RDDLY0/1 mask */ ++#define MSDC_DAT_RDDLY0_D0 (0x1F << 0) /* RW */ ++#define MSDC_DAT_RDDLY0_D1 (0x1F << 8) /* RW */ ++#define MSDC_DAT_RDDLY0_D2 (0x1F << 16) /* RW */ ++#define MSDC_DAT_RDDLY0_D3 (0x1F << 24) /* RW */ ++ ++#define MSDC_DAT_RDDLY1_D4 (0x1F << 0) /* RW */ ++#define MSDC_DAT_RDDLY1_D5 (0x1F << 8) /* RW */ ++#define MSDC_DAT_RDDLY1_D6 (0x1F << 16) /* RW */ ++#define MSDC_DAT_RDDLY1_D7 (0x1F << 24) /* RW */ ++ ++#define MSDC_CKGEN_MSDC_DLY_SEL (0x1F<<10) ++#define MSDC_INT_DAT_LATCH_CK_SEL (0x7<<7) ++#define MSDC_CKGEN_MSDC_CK_SEL (0x1<<6) ++#define CARD_READY_FOR_DATA (1<<8) ++#define CARD_CURRENT_STATE(x) ((x&0x00001E00)>>9) ++ ++/*--------------------------------------------------------------------------*/ ++/* Descriptor Structure */ ++/*--------------------------------------------------------------------------*/ ++typedef struct { ++ u32 hwo:1; /* could be changed by hw */ ++ u32 bdp:1; ++ u32 rsv0:6; ++ u32 chksum:8; ++ u32 intr:1; ++ u32 rsv1:15; ++ void *next; ++ void *ptr; ++ u32 buflen:16; ++ u32 extlen:8; ++ u32 rsv2:8; ++ u32 arg; ++ u32 blknum; ++ u32 cmd; ++} gpd_t; ++ ++typedef struct { ++ u32 eol:1; ++ u32 rsv0:7; ++ u32 chksum:8; ++ u32 rsv1:1; ++ u32 blkpad:1; ++ u32 dwpad:1; ++ u32 rsv2:13; ++ void *next; ++ void *ptr; ++ u32 buflen:16; ++ u32 rsv3:16; ++} bd_t; ++ ++/*--------------------------------------------------------------------------*/ ++/* Register Debugging Structure */ ++/*--------------------------------------------------------------------------*/ ++ ++typedef struct { ++ u32 msdc:1; ++ u32 ckpwn:1; ++ u32 rst:1; ++ u32 pio:1; ++ u32 ckdrven:1; ++ u32 start18v:1; ++ u32 pass18v:1; ++ u32 ckstb:1; ++ u32 ckdiv:8; ++ u32 ckmod:2; ++ u32 pad:14; ++} msdc_cfg_reg; ++typedef struct { ++ u32 sdr104cksel:1; ++ u32 rsmpl:1; ++ u32 dsmpl:1; ++ u32 ddlysel:1; ++ u32 ddr50ckd:1; ++ u32 dsplsel:1; ++ u32 pad1:10; ++ u32 d0spl:1; ++ u32 d1spl:1; ++ u32 d2spl:1; ++ u32 d3spl:1; ++ u32 d4spl:1; ++ u32 d5spl:1; ++ u32 d6spl:1; ++ u32 d7spl:1; ++ u32 riscsz:1; ++ u32 pad2:7; ++} msdc_iocon_reg; ++typedef struct { ++ u32 cden:1; ++ u32 cdsts:1; ++ u32 pad1:10; ++ u32 cddebounce:4; ++ u32 dat:8; ++ u32 cmd:1; ++ u32 pad2:6; ++ u32 wp:1; ++} msdc_ps_reg; ++typedef struct { ++ u32 mmcirq:1; ++ u32 cdsc:1; ++ u32 pad1:1; ++ u32 atocmdrdy:1; ++ u32 atocmdtmo:1; ++ u32 atocmdcrc:1; ++ u32 dmaqempty:1; ++ u32 sdioirq:1; ++ u32 cmdrdy:1; ++ u32 cmdtmo:1; ++ u32 rspcrc:1; ++ u32 csta:1; ++ u32 xfercomp:1; ++ u32 dxferdone:1; ++ u32 dattmo:1; ++ u32 datcrc:1; ++ u32 atocmd19done:1; ++ u32 pad2:15; ++} msdc_int_reg; ++typedef struct { ++ u32 mmcirq:1; ++ u32 cdsc:1; ++ u32 pad1:1; ++ u32 atocmdrdy:1; ++ u32 atocmdtmo:1; ++ u32 atocmdcrc:1; ++ u32 dmaqempty:1; ++ u32 sdioirq:1; ++ u32 cmdrdy:1; ++ u32 cmdtmo:1; ++ u32 rspcrc:1; ++ u32 csta:1; ++ u32 xfercomp:1; ++ u32 dxferdone:1; ++ u32 dattmo:1; ++ u32 datcrc:1; ++ u32 atocmd19done:1; ++ u32 pad2:15; ++} msdc_inten_reg; ++typedef struct { ++ u32 rxcnt:8; ++ u32 pad1:8; ++ u32 txcnt:8; ++ u32 pad2:7; ++ u32 clr:1; ++} msdc_fifocs_reg; ++typedef struct { ++ u32 val; ++} msdc_txdat_reg; ++typedef struct { ++ u32 val; ++} msdc_rxdat_reg; ++typedef struct { ++ u32 sdiowkup:1; ++ u32 inswkup:1; ++ u32 pad1:14; ++ u32 buswidth:2; ++ u32 pad2:1; ++ u32 sdio:1; ++ u32 sdioide:1; ++ u32 intblkgap:1; ++ u32 pad4:2; ++ u32 dtoc:8; ++} sdc_cfg_reg; ++typedef struct { ++ u32 cmd:6; ++ u32 brk:1; ++ u32 rsptyp:3; ++ u32 pad1:1; ++ u32 dtype:2; ++ u32 rw:1; ++ u32 stop:1; ++ u32 goirq:1; ++ u32 blklen:12; ++ u32 atocmd:2; ++ u32 volswth:1; ++ u32 pad2:1; ++} sdc_cmd_reg; ++typedef struct { ++ u32 arg; ++} sdc_arg_reg; ++typedef struct { ++ u32 sdcbusy:1; ++ u32 cmdbusy:1; ++ u32 pad:29; ++ u32 swrcmpl:1; ++} sdc_sts_reg; ++typedef struct { ++ u32 val; ++} sdc_resp0_reg; ++typedef struct { ++ u32 val; ++} sdc_resp1_reg; ++typedef struct { ++ u32 val; ++} sdc_resp2_reg; ++typedef struct { ++ u32 val; ++} sdc_resp3_reg; ++typedef struct { ++ u32 num; ++} sdc_blknum_reg; ++typedef struct { ++ u32 sts; ++} sdc_csts_reg; ++typedef struct { ++ u32 sts; ++} sdc_cstsen_reg; ++typedef struct { ++ u32 datcrcsts:8; ++ u32 ddrcrcsts:4; ++ u32 pad:20; ++} sdc_datcrcsts_reg; ++typedef struct { ++ u32 bootstart:1; ++ u32 bootstop:1; ++ u32 bootmode:1; ++ u32 pad1:9; ++ u32 bootwaidly:3; ++ u32 bootsupp:1; ++ u32 pad2:16; ++} emmc_cfg0_reg; ++typedef struct { ++ u32 bootcrctmc:16; ++ u32 pad:4; ++ u32 bootacktmc:12; ++} emmc_cfg1_reg; ++typedef struct { ++ u32 bootcrcerr:1; ++ u32 bootackerr:1; ++ u32 bootdattmo:1; ++ u32 bootacktmo:1; ++ u32 bootupstate:1; ++ u32 bootackrcv:1; ++ u32 bootdatrcv:1; ++ u32 pad:25; ++} emmc_sts_reg; ++typedef struct { ++ u32 bootrst:1; ++ u32 pad:31; ++} emmc_iocon_reg; ++typedef struct { ++ u32 val; ++} msdc_acmd_resp_reg; ++typedef struct { ++ u32 tunesel:4; ++ u32 pad:28; ++} msdc_acmd19_trg_reg; ++typedef struct { ++ u32 val; ++} msdc_acmd19_sts_reg; ++typedef struct { ++ u32 addr; ++} msdc_dma_sa_reg; ++typedef struct { ++ u32 addr; ++} msdc_dma_ca_reg; ++typedef struct { ++ u32 start:1; ++ u32 stop:1; ++ u32 resume:1; ++ u32 pad1:5; ++ u32 mode:1; ++ u32 pad2:1; ++ u32 lastbuf:1; ++ u32 pad3:1; ++ u32 brustsz:3; ++ u32 pad4:1; ++ u32 xfersz:16; ++} msdc_dma_ctrl_reg; ++typedef struct { ++ u32 status:1; ++ u32 decsen:1; ++ u32 pad1:2; ++ u32 bdcsen:1; ++ u32 gpdcsen:1; ++ u32 pad2:26; ++} msdc_dma_cfg_reg; ++typedef struct { ++ u32 sel:16; ++ u32 pad2:16; ++} msdc_dbg_sel_reg; ++typedef struct { ++ u32 val; ++} msdc_dbg_out_reg; ++typedef struct { ++ u32 clkdrvn:3; ++ u32 rsv0:1; ++ u32 clkdrvp:3; ++ u32 rsv1:1; ++ u32 clksr:1; ++ u32 rsv2:7; ++ u32 clkpd:1; ++ u32 clkpu:1; ++ u32 clksmt:1; ++ u32 clkies:1; ++ u32 clktdsel:4; ++ u32 clkrdsel:8; ++} msdc_pad_ctl0_reg; ++typedef struct { ++ u32 cmddrvn:3; ++ u32 rsv0:1; ++ u32 cmddrvp:3; ++ u32 rsv1:1; ++ u32 cmdsr:1; ++ u32 rsv2:7; ++ u32 cmdpd:1; ++ u32 cmdpu:1; ++ u32 cmdsmt:1; ++ u32 cmdies:1; ++ u32 cmdtdsel:4; ++ u32 cmdrdsel:8; ++} msdc_pad_ctl1_reg; ++typedef struct { ++ u32 datdrvn:3; ++ u32 rsv0:1; ++ u32 datdrvp:3; ++ u32 rsv1:1; ++ u32 datsr:1; ++ u32 rsv2:7; ++ u32 datpd:1; ++ u32 datpu:1; ++ u32 datsmt:1; ++ u32 daties:1; ++ u32 dattdsel:4; ++ u32 datrdsel:8; ++} msdc_pad_ctl2_reg; ++typedef struct { ++ u32 wrrxdly:3; ++ u32 pad1:5; ++ u32 rdrxdly:8; ++ u32 pad2:16; ++} msdc_pad_tune_reg; ++typedef struct { ++ u32 dat0:5; ++ u32 rsv0:3; ++ u32 dat1:5; ++ u32 rsv1:3; ++ u32 dat2:5; ++ u32 rsv2:3; ++ u32 dat3:5; ++ u32 rsv3:3; ++} msdc_dat_rddly0; ++typedef struct { ++ u32 dat4:5; ++ u32 rsv4:3; ++ u32 dat5:5; ++ u32 rsv5:3; ++ u32 dat6:5; ++ u32 rsv6:3; ++ u32 dat7:5; ++ u32 rsv7:3; ++} msdc_dat_rddly1; ++typedef struct { ++ u32 dbg0sel:8; ++ u32 dbg1sel:6; ++ u32 pad1:2; ++ u32 dbg2sel:6; ++ u32 pad2:2; ++ u32 dbg3sel:6; ++ u32 pad3:2; ++} msdc_hw_dbg_reg; ++typedef struct { ++ u32 val; ++} msdc_version_reg; ++typedef struct { ++ u32 val; ++} msdc_eco_ver_reg; ++ ++struct msdc_regs { ++ msdc_cfg_reg msdc_cfg; /* base+0x00h */ ++ msdc_iocon_reg msdc_iocon; /* base+0x04h */ ++ msdc_ps_reg msdc_ps; /* base+0x08h */ ++ msdc_int_reg msdc_int; /* base+0x0ch */ ++ msdc_inten_reg msdc_inten; /* base+0x10h */ ++ msdc_fifocs_reg msdc_fifocs; /* base+0x14h */ ++ msdc_txdat_reg msdc_txdat; /* base+0x18h */ ++ msdc_rxdat_reg msdc_rxdat; /* base+0x1ch */ ++ u32 rsv1[4]; ++ sdc_cfg_reg sdc_cfg; /* base+0x30h */ ++ sdc_cmd_reg sdc_cmd; /* base+0x34h */ ++ sdc_arg_reg sdc_arg; /* base+0x38h */ ++ sdc_sts_reg sdc_sts; /* base+0x3ch */ ++ sdc_resp0_reg sdc_resp0; /* base+0x40h */ ++ sdc_resp1_reg sdc_resp1; /* base+0x44h */ ++ sdc_resp2_reg sdc_resp2; /* base+0x48h */ ++ sdc_resp3_reg sdc_resp3; /* base+0x4ch */ ++ sdc_blknum_reg sdc_blknum; /* base+0x50h */ ++ u32 rsv2[1]; ++ sdc_csts_reg sdc_csts; /* base+0x58h */ ++ sdc_cstsen_reg sdc_cstsen; /* base+0x5ch */ ++ sdc_datcrcsts_reg sdc_dcrcsta; /* base+0x60h */ ++ u32 rsv3[3]; ++ emmc_cfg0_reg emmc_cfg0; /* base+0x70h */ ++ emmc_cfg1_reg emmc_cfg1; /* base+0x74h */ ++ emmc_sts_reg emmc_sts; /* base+0x78h */ ++ emmc_iocon_reg emmc_iocon; /* base+0x7ch */ ++ msdc_acmd_resp_reg acmd_resp; /* base+0x80h */ ++ msdc_acmd19_trg_reg acmd19_trg; /* base+0x84h */ ++ msdc_acmd19_sts_reg acmd19_sts; /* base+0x88h */ ++ u32 rsv4[1]; ++ msdc_dma_sa_reg dma_sa; /* base+0x90h */ ++ msdc_dma_ca_reg dma_ca; /* base+0x94h */ ++ msdc_dma_ctrl_reg dma_ctrl; /* base+0x98h */ ++ msdc_dma_cfg_reg dma_cfg; /* base+0x9ch */ ++ msdc_dbg_sel_reg dbg_sel; /* base+0xa0h */ ++ msdc_dbg_out_reg dbg_out; /* base+0xa4h */ ++ u32 rsv5[2]; ++ u32 patch0; /* base+0xb0h */ ++ u32 patch1; /* base+0xb4h */ ++ u32 rsv6[10]; ++ msdc_pad_ctl0_reg pad_ctl0; /* base+0xe0h */ ++ msdc_pad_ctl1_reg pad_ctl1; /* base+0xe4h */ ++ msdc_pad_ctl2_reg pad_ctl2; /* base+0xe8h */ ++ msdc_pad_tune_reg pad_tune; /* base+0xech */ ++ msdc_dat_rddly0 dat_rddly0; /* base+0xf0h */ ++ msdc_dat_rddly1 dat_rddly1; /* base+0xf4h */ ++ msdc_hw_dbg_reg hw_dbg; /* base+0xf8h */ ++ u32 rsv7[1]; ++ msdc_version_reg version; /* base+0x100h */ ++ msdc_eco_ver_reg eco_ver; /* base+0x104h */ ++}; ++ ++struct scatterlist_ex { ++ u32 cmd; ++ u32 arg; ++ u32 sglen; ++ struct scatterlist *sg; ++}; ++ ++#define DMA_FLAG_NONE (0x00000000) ++#define DMA_FLAG_EN_CHKSUM (0x00000001) ++#define DMA_FLAG_PAD_BLOCK (0x00000002) ++#define DMA_FLAG_PAD_DWORD (0x00000004) ++ ++struct msdc_dma { ++ u32 flags; /* flags */ ++ u32 xfersz; /* xfer size in bytes */ ++ u32 sglen; /* size of scatter list */ ++ u32 blklen; /* block size */ ++ struct scatterlist *sg; /* I/O scatter list */ ++ struct scatterlist_ex *esg; /* extended I/O scatter list */ ++ u8 mode; /* dma mode */ ++ u8 burstsz; /* burst size */ ++ u8 intr; /* dma done interrupt */ ++ u8 padding; /* padding */ ++ u32 cmd; /* enhanced mode command */ ++ u32 arg; /* enhanced mode arg */ ++ u32 rsp; /* enhanced mode command response */ ++ u32 autorsp; /* auto command response */ ++ ++ gpd_t *gpd; /* pointer to gpd array */ ++ bd_t *bd; /* pointer to bd array */ ++ dma_addr_t gpd_addr; /* the physical address of gpd array */ ++ dma_addr_t bd_addr; /* the physical address of bd array */ ++ u32 used_gpd; /* the number of used gpd elements */ ++ u32 used_bd; /* the number of used bd elements */ ++}; ++ ++struct msdc_host ++{ ++ struct msdc_hw *hw; ++ ++ struct mmc_host *mmc; /* mmc structure */ ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ struct mmc_request *mrq; ++ int cmd_rsp; ++ int cmd_rsp_done; ++ int cmd_r1b_done; ++ ++ int error; ++ spinlock_t lock; /* mutex */ ++ struct semaphore sem; ++ ++ u32 blksz; /* host block size */ ++ u32 base; /* host base address */ ++ int id; /* host id */ ++ int pwr_ref; /* core power reference count */ ++ ++ u32 xfer_size; /* total transferred size */ ++ ++ struct msdc_dma dma; /* dma channel */ ++ u32 dma_addr; /* dma transfer address */ ++ u32 dma_left_size; /* dma transfer left size */ ++ u32 dma_xfer_size; /* dma transfer size in bytes */ ++ int dma_xfer; /* dma transfer mode */ ++ ++ u32 timeout_ns; /* data timeout ns */ ++ u32 timeout_clks; /* data timeout clks */ ++ ++ atomic_t abort; /* abort transfer */ ++ ++ int irq; /* host interrupt */ ++ ++ struct tasklet_struct card_tasklet; ++ ++ struct completion cmd_done; ++ struct completion xfer_done; ++ struct pm_message pm_state; ++ ++ u32 mclk; /* mmc subsystem clock */ ++ u32 hclk; /* host clock speed */ ++ u32 sclk; /* SD/MS clock speed */ ++ u8 core_clkon; /* Host core clock on ? */ ++ u8 card_clkon; /* Card clock on ? */ ++ u8 core_power; /* core power */ ++ u8 power_mode; /* host power mode */ ++ u8 card_inserted; /* card inserted ? */ ++ u8 suspend; /* host suspended ? */ ++ u8 reserved; ++ u8 app_cmd; /* for app command */ ++ u32 app_cmd_arg; ++ u64 starttime; ++}; ++ ++static inline unsigned int uffs(unsigned int x) ++{ ++ unsigned int r = 1; ++ ++ if (!x) ++ return 0; ++ if (!(x & 0xffff)) { ++ x >>= 16; ++ r += 16; ++ } ++ if (!(x & 0xff)) { ++ x >>= 8; ++ r += 8; ++ } ++ if (!(x & 0xf)) { ++ x >>= 4; ++ r += 4; ++ } ++ if (!(x & 3)) { ++ x >>= 2; ++ r += 2; ++ } ++ if (!(x & 1)) { ++ x >>= 1; ++ r += 1; ++ } ++ return r; ++} ++#define sdr_read8(reg) __raw_readb(reg) ++#define sdr_read16(reg) __raw_readw(reg) ++#define sdr_read32(reg) __raw_readl(reg) ++#define sdr_write8(reg,val) __raw_writeb(val,reg) ++#define sdr_write16(reg,val) __raw_writew(val,reg) ++#define sdr_write32(reg,val) __raw_writel(val,reg) ++ ++#define sdr_set_bits(reg,bs) ((*(volatile u32*)(reg)) |= (u32)(bs)) ++#define sdr_clr_bits(reg,bs) ((*(volatile u32*)(reg)) &= ~((u32)(bs))) ++ ++#define sdr_set_field(reg,field,val) \ ++ do { \ ++ volatile unsigned int tv = sdr_read32(reg); \ ++ tv &= ~(field); \ ++ tv |= ((val) << (uffs((unsigned int)field) - 1)); \ ++ sdr_write32(reg,tv); \ ++ } while(0) ++#define sdr_get_field(reg,field,val) \ ++ do { \ ++ volatile unsigned int tv = sdr_read32(reg); \ ++ val = ((tv & (field)) >> (uffs((unsigned int)field) - 1)); \ ++ } while(0) ++ ++#endif ++ +diff --git a/drivers/mmc/host/sdhci-mt7620.c b/drivers/mmc/host/sdhci-mt7620.c +new file mode 100644 +index 0000000..a3cb5e4 +--- /dev/null ++++ b/drivers/mmc/host/sdhci-mt7620.c +@@ -0,0 +1,2314 @@ ++/* Copyright Statement: ++ * ++ * This software/firmware and related documentation ("MediaTek Software") are ++ * protected under relevant copyright laws. The information contained herein ++ * is confidential and proprietary to MediaTek Inc. and/or its licensors. ++ * Without the prior written permission of MediaTek inc. and/or its licensors, ++ * any reproduction, modification, use or disclosure of MediaTek Software, ++ * and information contained herein, in whole or in part, shall be strictly prohibited. ++ * ++ * MediaTek Inc. (C) 2010. All rights reserved. ++ * ++ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES ++ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") ++ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON ++ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. ++ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE ++ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR ++ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH ++ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES ++ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES ++ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK ++ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR ++ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND ++ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, ++ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, ++ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO ++ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. ++ * ++ * The following software/firmware and/or related documentation ("MediaTek Software") ++ * have been modified by MediaTek Inc. All revisions are subject to any receiver's ++ * applicable license agreements with MediaTek Inc. ++ */ ++ ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++#include <linux/spinlock.h> ++#include <linux/timer.h> ++#include <linux/ioport.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/of_platform.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <linux/blkdev.h> ++#include <linux/slab.h> ++#include <linux/mmc/host.h> ++#include <linux/mmc/card.h> ++#include <linux/mmc/core.h> ++#include <linux/mmc/mmc.h> ++#include <linux/mmc/sd.h> ++#include <linux/mmc/sdio.h> ++#include <linux/dma-mapping.h> ++ ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/version.h> ++#include <linux/pm.h> ++ ++#define MSDC_SMPL_FALLING (1) ++#define MSDC_CD_PIN_EN (1 << 0) /* card detection pin is wired */ ++#define MSDC_WP_PIN_EN (1 << 1) /* write protection pin is wired */ ++#define MSDC_REMOVABLE (1 << 5) /* removable slot */ ++#define MSDC_SYS_SUSPEND (1 << 6) /* suspended by system */ ++#define MSDC_HIGHSPEED (1 << 7) ++ ++#define IRQ_SDC 22 ++ ++#include <asm/dma.h> ++ ++#include "mt6575_sd.h" ++ ++#define DRV_NAME "mtk-sd" ++ ++#define HOST_MAX_NUM (1) /* +/- by chhung */ ++ ++#define HOST_MAX_MCLK (48000000) /* +/- by chhung */ ++#define HOST_MIN_MCLK (260000) ++ ++#define HOST_MAX_BLKSZ (2048) ++ ++#define MSDC_OCR_AVAIL (MMC_VDD_28_29 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33) ++ ++#define GPIO_PULL_DOWN (0) ++#define GPIO_PULL_UP (1) ++ ++#define DEFAULT_DEBOUNCE (8) /* 8 cycles */ ++#define DEFAULT_DTOC (40) /* data timeout counter. 65536x40 sclk. */ ++ ++#define CMD_TIMEOUT (HZ/10) /* 100ms */ ++#define DAT_TIMEOUT (HZ/2 * 5) /* 500ms x5 */ ++ ++#define MAX_DMA_CNT (64 * 1024 - 512) /* a single transaction for WIFI may be 50K*/ ++ ++#define MAX_GPD_NUM (1 + 1) /* one null gpd */ ++#define MAX_BD_NUM (1024) ++#define MAX_BD_PER_GPD (MAX_BD_NUM) ++ ++#define MAX_HW_SGMTS (MAX_BD_NUM) ++#define MAX_PHY_SGMTS (MAX_BD_NUM) ++#define MAX_SGMT_SZ (MAX_DMA_CNT) ++#define MAX_REQ_SZ (MAX_SGMT_SZ * 8) ++ ++#ifdef MT6575_SD_DEBUG ++static struct msdc_regs *msdc_reg[HOST_MAX_NUM]; ++#endif ++ ++//================================= ++#define PERI_MSDC0_PDN (15) ++//#define PERI_MSDC1_PDN (16) ++//#define PERI_MSDC2_PDN (17) ++//#define PERI_MSDC3_PDN (18) ++ ++struct msdc_host *msdc_6575_host[] = {NULL,NULL,NULL,NULL}; ++ ++struct msdc_hw msdc0_hw = { ++ .clk_src = 0, ++ .cmd_edge = MSDC_SMPL_FALLING, ++ .data_edge = MSDC_SMPL_FALLING, ++ .clk_drv = 4, ++ .cmd_drv = 4, ++ .dat_drv = 4, ++ .data_pins = 4, ++ .data_offset = 0, ++ .flags = MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED, ++}; ++ ++static struct resource mtk_sd_resources[] = { ++ [0] = { ++ .start = 0xb0130000, ++ .end = 0xb0133fff, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_SDC, /*FIXME*/ ++ .end = IRQ_SDC, /*FIXME*/ ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device mtk_sd_device = { ++ .name = "mtk-sd", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(mtk_sd_resources), ++ .resource = mtk_sd_resources, ++}; ++/* end of +++ */ ++ ++static int msdc_rsp[] = { ++ 0, /* RESP_NONE */ ++ 1, /* RESP_R1 */ ++ 2, /* RESP_R2 */ ++ 3, /* RESP_R3 */ ++ 4, /* RESP_R4 */ ++ 1, /* RESP_R5 */ ++ 1, /* RESP_R6 */ ++ 1, /* RESP_R7 */ ++ 7, /* RESP_R1b */ ++}; ++ ++/* For Inhanced DMA */ ++#define msdc_init_gpd_ex(gpd,extlen,cmd,arg,blknum) \ ++ do { \ ++ ((gpd_t*)gpd)->extlen = extlen; \ ++ ((gpd_t*)gpd)->cmd = cmd; \ ++ ((gpd_t*)gpd)->arg = arg; \ ++ ((gpd_t*)gpd)->blknum = blknum; \ ++ }while(0) ++ ++#define msdc_init_bd(bd, blkpad, dwpad, dptr, dlen) \ ++ do { \ ++ BUG_ON(dlen > 0xFFFFUL); \ ++ ((bd_t*)bd)->blkpad = blkpad; \ ++ ((bd_t*)bd)->dwpad = dwpad; \ ++ ((bd_t*)bd)->ptr = (void*)dptr; \ ++ ((bd_t*)bd)->buflen = dlen; \ ++ }while(0) ++ ++#define msdc_txfifocnt() ((sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_TXCNT) >> 16) ++#define msdc_rxfifocnt() ((sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_RXCNT) >> 0) ++#define msdc_fifo_write32(v) sdr_write32(MSDC_TXDATA, (v)) ++#define msdc_fifo_write8(v) sdr_write8(MSDC_TXDATA, (v)) ++#define msdc_fifo_read32() sdr_read32(MSDC_RXDATA) ++#define msdc_fifo_read8() sdr_read8(MSDC_RXDATA) ++ ++ ++#define msdc_dma_on() sdr_clr_bits(MSDC_CFG, MSDC_CFG_PIO) ++#define msdc_dma_off() sdr_set_bits(MSDC_CFG, MSDC_CFG_PIO) ++ ++#define msdc_retry(expr,retry,cnt) \ ++ do { \ ++ int backup = cnt; \ ++ while (retry) { \ ++ if (!(expr)) break; \ ++ if (cnt-- == 0) { \ ++ retry--; mdelay(1); cnt = backup; \ ++ } \ ++ } \ ++ WARN_ON(retry == 0); \ ++ } while(0) ++ ++#if 0 /* +/- chhung */ ++#define msdc_reset() \ ++ do { \ ++ int retry = 3, cnt = 1000; \ ++ sdr_set_bits(MSDC_CFG, MSDC_CFG_RST); \ ++ dsb(); \ ++ msdc_retry(sdr_read32(MSDC_CFG) & MSDC_CFG_RST, retry, cnt); \ ++ } while(0) ++#else ++#define msdc_reset() \ ++ do { \ ++ int retry = 3, cnt = 1000; \ ++ sdr_set_bits(MSDC_CFG, MSDC_CFG_RST); \ ++ msdc_retry(sdr_read32(MSDC_CFG) & MSDC_CFG_RST, retry, cnt); \ ++ } while(0) ++#endif /* end of +/- */ ++ ++#define msdc_clr_int() \ ++ do { \ ++ volatile u32 val = sdr_read32(MSDC_INT); \ ++ sdr_write32(MSDC_INT, val); \ ++ } while(0) ++ ++#define msdc_clr_fifo() \ ++ do { \ ++ int retry = 3, cnt = 1000; \ ++ sdr_set_bits(MSDC_FIFOCS, MSDC_FIFOCS_CLR); \ ++ msdc_retry(sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_CLR, retry, cnt); \ ++ } while(0) ++ ++#define msdc_irq_save(val) \ ++ do { \ ++ val = sdr_read32(MSDC_INTEN); \ ++ sdr_clr_bits(MSDC_INTEN, val); \ ++ } while(0) ++ ++#define msdc_irq_restore(val) \ ++ do { \ ++ sdr_set_bits(MSDC_INTEN, val); \ ++ } while(0) ++ ++/* clock source for host: global */ ++static u32 hclks[] = {48000000}; /* +/- by chhung */ ++ ++//============================================ ++// the power for msdc host controller: global ++// always keep the VMC on. ++//============================================ ++#define msdc_vcore_on(host) \ ++ do { \ ++ printk("[+]VMC ref. count<%d>\n", ++host->pwr_ref); \ ++ (void)hwPowerOn(MT65XX_POWER_LDO_VMC, VOL_3300, "SD"); \ ++ } while (0) ++#define msdc_vcore_off(host) \ ++ do { \ ++ printk("[-]VMC ref. count<%d>\n", --host->pwr_ref); \ ++ (void)hwPowerDown(MT65XX_POWER_LDO_VMC, "SD"); \ ++ } while (0) ++ ++//==================================== ++// the vdd output for card: global ++// always keep the VMCH on. ++//==================================== ++#define msdc_vdd_on(host) \ ++ do { \ ++ (void)hwPowerOn(MT65XX_POWER_LDO_VMCH, VOL_3300, "SD"); \ ++ } while (0) ++#define msdc_vdd_off(host) \ ++ do { \ ++ (void)hwPowerDown(MT65XX_POWER_LDO_VMCH, "SD"); \ ++ } while (0) ++ ++#define sdc_is_busy() (sdr_read32(SDC_STS) & SDC_STS_SDCBUSY) ++#define sdc_is_cmd_busy() (sdr_read32(SDC_STS) & SDC_STS_CMDBUSY) ++ ++#define sdc_send_cmd(cmd,arg) \ ++ do { \ ++ sdr_write32(SDC_ARG, (arg)); \ ++ sdr_write32(SDC_CMD, (cmd)); \ ++ } while(0) ++ ++// can modify to read h/w register. ++//#define is_card_present(h) ((sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 0 : 1); ++#define is_card_present(h) (((struct msdc_host*)(h))->card_inserted) ++ ++/* +++ chhung */ ++#ifndef __ASSEMBLY__ ++#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff) ++#else ++#define PHYSADDR(a) ((a) & 0x1fffffff) ++#endif ++/* end of +++ */ ++static unsigned int msdc_do_command(struct msdc_host *host, ++ struct mmc_command *cmd, ++ int tune, ++ unsigned long timeout); ++ ++static int msdc_tune_cmdrsp(struct msdc_host*host,struct mmc_command *cmd); ++ ++#ifdef MT6575_SD_DEBUG ++static void msdc_dump_card_status(struct msdc_host *host, u32 status) ++{ ++ static char *state[] = { ++ "Idle", /* 0 */ ++ "Ready", /* 1 */ ++ "Ident", /* 2 */ ++ "Stby", /* 3 */ ++ "Tran", /* 4 */ ++ "Data", /* 5 */ ++ "Rcv", /* 6 */ ++ "Prg", /* 7 */ ++ "Dis", /* 8 */ ++ "Reserved", /* 9 */ ++ "Reserved", /* 10 */ ++ "Reserved", /* 11 */ ++ "Reserved", /* 12 */ ++ "Reserved", /* 13 */ ++ "Reserved", /* 14 */ ++ "I/O mode", /* 15 */ ++ }; ++ if (status & R1_OUT_OF_RANGE) ++ printk("[CARD_STATUS] Out of Range\n"); ++ if (status & R1_ADDRESS_ERROR) ++ printk("[CARD_STATUS] Address Error\n"); ++ if (status & R1_BLOCK_LEN_ERROR) ++ printk("[CARD_STATUS] Block Len Error\n"); ++ if (status & R1_ERASE_SEQ_ERROR) ++ printk("[CARD_STATUS] Erase Seq Error\n"); ++ if (status & R1_ERASE_PARAM) ++ printk("[CARD_STATUS] Erase Param\n"); ++ if (status & R1_WP_VIOLATION) ++ printk("[CARD_STATUS] WP Violation\n"); ++ if (status & R1_CARD_IS_LOCKED) ++ printk("[CARD_STATUS] Card is Locked\n"); ++ if (status & R1_LOCK_UNLOCK_FAILED) ++ printk("[CARD_STATUS] Lock/Unlock Failed\n"); ++ if (status & R1_COM_CRC_ERROR) ++ printk("[CARD_STATUS] Command CRC Error\n"); ++ if (status & R1_ILLEGAL_COMMAND) ++ printk("[CARD_STATUS] Illegal Command\n"); ++ if (status & R1_CARD_ECC_FAILED) ++ printk("[CARD_STATUS] Card ECC Failed\n"); ++ if (status & R1_CC_ERROR) ++ printk("[CARD_STATUS] CC Error\n"); ++ if (status & R1_ERROR) ++ printk("[CARD_STATUS] Error\n"); ++ if (status & R1_UNDERRUN) ++ printk("[CARD_STATUS] Underrun\n"); ++ if (status & R1_OVERRUN) ++ printk("[CARD_STATUS] Overrun\n"); ++ if (status & R1_CID_CSD_OVERWRITE) ++ printk("[CARD_STATUS] CID/CSD Overwrite\n"); ++ if (status & R1_WP_ERASE_SKIP) ++ printk("[CARD_STATUS] WP Eraser Skip\n"); ++ if (status & R1_CARD_ECC_DISABLED) ++ printk("[CARD_STATUS] Card ECC Disabled\n"); ++ if (status & R1_ERASE_RESET) ++ printk("[CARD_STATUS] Erase Reset\n"); ++ if (status & R1_READY_FOR_DATA) ++ printk("[CARD_STATUS] Ready for Data\n"); ++ if (status & R1_SWITCH_ERROR) ++ printk("[CARD_STATUS] Switch error\n"); ++ if (status & R1_APP_CMD) ++ printk("[CARD_STATUS] App Command\n"); ++ ++ printk("[CARD_STATUS] '%s' State\n", state[R1_CURRENT_STATE(status)]); ++} ++ ++static void msdc_dump_ocr_reg(struct msdc_host *host, u32 resp) ++{ ++ if (resp & (1 << 7)) ++ printk("[OCR] Low Voltage Range\n"); ++ if (resp & (1 << 15)) ++ printk("[OCR] 2.7-2.8 volt\n"); ++ if (resp & (1 << 16)) ++ printk("[OCR] 2.8-2.9 volt\n"); ++ if (resp & (1 << 17)) ++ printk("[OCR] 2.9-3.0 volt\n"); ++ if (resp & (1 << 18)) ++ printk("[OCR] 3.0-3.1 volt\n"); ++ if (resp & (1 << 19)) ++ printk("[OCR] 3.1-3.2 volt\n"); ++ if (resp & (1 << 20)) ++ printk("[OCR] 3.2-3.3 volt\n"); ++ if (resp & (1 << 21)) ++ printk("[OCR] 3.3-3.4 volt\n"); ++ if (resp & (1 << 22)) ++ printk("[OCR] 3.4-3.5 volt\n"); ++ if (resp & (1 << 23)) ++ printk("[OCR] 3.5-3.6 volt\n"); ++ if (resp & (1 << 24)) ++ printk("[OCR] Switching to 1.8V Accepted (S18A)\n"); ++ if (resp & (1 << 30)) ++ printk("[OCR] Card Capacity Status (CCS)\n"); ++ if (resp & (1 << 31)) ++ printk("[OCR] Card Power Up Status (Idle)\n"); ++ else ++ printk("[OCR] Card Power Up Status (Busy)\n"); ++} ++ ++static void msdc_dump_rca_resp(struct msdc_host *host, u32 resp) ++{ ++ u32 status = (((resp >> 15) & 0x1) << 23) | ++ (((resp >> 14) & 0x1) << 22) | ++ (((resp >> 13) & 0x1) << 19) | ++ (resp & 0x1fff); ++ ++ printk("[RCA] 0x%.4x\n", resp >> 16); ++ ++ msdc_dump_card_status(host, status); ++} ++ ++static void msdc_dump_io_resp(struct msdc_host *host, u32 resp) ++{ ++ u32 flags = (resp >> 8) & 0xFF; ++ char *state[] = {"DIS", "CMD", "TRN", "RFU"}; ++ ++ if (flags & (1 << 7)) ++ printk("[IO] COM_CRC_ERR\n"); ++ if (flags & (1 << 6)) ++ printk("[IO] Illgal command\n"); ++ if (flags & (1 << 3)) ++ printk("[IO] Error\n"); ++ if (flags & (1 << 2)) ++ printk("[IO] RFU\n"); ++ if (flags & (1 << 1)) ++ printk("[IO] Function number error\n"); ++ if (flags & (1 << 0)) ++ printk("[IO] Out of range\n"); ++ ++ printk("[IO] State: %s, Data:0x%x\n", state[(resp >> 12) & 0x3], resp & 0xFF); ++} ++#endif ++ ++static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) ++{ ++ u32 base = host->base; ++ u32 timeout, clk_ns; ++ ++ host->timeout_ns = ns; ++ host->timeout_clks = clks; ++ ++ clk_ns = 1000000000UL / host->sclk; ++ timeout = ns / clk_ns + clks; ++ timeout = timeout >> 16; /* in 65536 sclk cycle unit */ ++ timeout = timeout > 1 ? timeout - 1 : 0; ++ timeout = timeout > 255 ? 255 : timeout; ++ ++ sdr_set_field(SDC_CFG, SDC_CFG_DTOC, timeout); ++ ++/* printk("Set read data timeout: %dns %dclks -> %d x 65536 cycles\n", ++ ns, clks, timeout + 1);*/ ++} ++ ++static void msdc_eirq_sdio(void *data) ++{ ++ struct msdc_host *host = (struct msdc_host *)data; ++ ++// printk("SDIO EINT\n"); ++ ++ mmc_signal_sdio_irq(host->mmc); ++} ++ ++static void msdc_eirq_cd(void *data) ++{ ++ struct msdc_host *host = (struct msdc_host *)data; ++ ++// printk("CD EINT\n"); ++ ++ tasklet_hi_schedule(&host->card_tasklet); ++} ++ ++static void msdc_tasklet_card(unsigned long arg) ++{ ++ struct msdc_host *host = (struct msdc_host *)arg; ++ struct msdc_hw *hw = host->hw; ++ u32 base = host->base; ++ u32 inserted; ++ u32 status = 0; ++ ++ spin_lock(&host->lock); ++ ++ if (hw->get_cd_status) { ++ inserted = hw->get_cd_status(); ++ } else { ++ status = sdr_read32(MSDC_PS); ++ inserted = (status & MSDC_PS_CDSTS) ? 0 : 1; ++ } ++ ++ host->card_inserted = inserted; ++ ++ if (!host->suspend) { ++ host->mmc->f_max = HOST_MAX_MCLK; ++ mmc_detect_change(host->mmc, msecs_to_jiffies(20)); ++ } ++ ++// printk("card found<%s>\n", inserted ? "inserted" : "removed"); ++ ++ spin_unlock(&host->lock); ++} ++ ++static void msdc_set_mclk(struct msdc_host *host, int ddr, unsigned int hz) ++{ ++ u32 base = host->base; ++ u32 hclk = host->hclk; ++ u32 mode, flags, div, sclk; ++ ++ if (!hz) { ++// printk("set mclk to 0!!!\n"); ++ msdc_reset(); ++ return; ++ } ++ ++ msdc_irq_save(flags); ++ ++ if (ddr) { ++ mode = 0x2; ++ if (hz >= (hclk >> 2)) { ++ div = 1; ++ sclk = hclk >> 2; ++ } else { ++ div = (hclk + ((hz << 2) - 1)) / (hz << 2); ++ sclk = (hclk >> 2) / div; ++ } ++ } else if (hz >= hclk) { ++ mode = 0x1; ++ div = 0; ++ sclk = hclk; ++ } else { ++ mode = 0x0; ++ if (hz >= (hclk >> 1)) { ++ div = 0; ++ sclk = hclk >> 1; ++ } else { ++ div = (hclk + ((hz << 2) - 1)) / (hz << 2); ++ sclk = (hclk >> 2) / div; ++ } ++ } ++ ++ sdr_set_field(MSDC_CFG, MSDC_CFG_CKMOD, mode); ++ sdr_set_field(MSDC_CFG, MSDC_CFG_CKDIV, div); ++ ++ while (!(sdr_read32(MSDC_CFG) & MSDC_CFG_CKSTB)); ++ ++ host->sclk = sclk; ++ host->mclk = hz; ++ msdc_set_timeout(host, host->timeout_ns, host->timeout_clks); ++ ++/* printk("!!! Set<%dKHz> Source<%dKHz> -> sclk<%dKHz>\n", ++ hz / 1000, hclk / 1000, sclk / 1000); ++*/ ++ msdc_irq_restore(flags); ++} ++ ++static void msdc_abort_data(struct msdc_host *host) ++{ ++ u32 base = host->base; ++ struct mmc_command *stop = host->mrq->stop; ++ ++// printk("Need to Abort. dma<%d>\n", host->dma_xfer); ++ ++ msdc_reset(); ++ msdc_clr_fifo(); ++ msdc_clr_int(); ++ ++ if (stop) { ++// printk("stop when abort CMD<%d>\n", stop->opcode); ++ msdc_do_command(host, stop, 0, CMD_TIMEOUT); ++ } ++} ++ ++static unsigned int msdc_command_start(struct msdc_host *host, ++ struct mmc_command *cmd, int tune, unsigned long timeout) ++{ ++ u32 wints = MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | ++ MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | ++ MSDC_INT_ACMD19_DONE; ++ u32 base = host->base; ++ u32 opcode = cmd->opcode; ++ u32 rawcmd; ++ u32 resp; ++ unsigned long tmo; ++ ++ if (opcode == MMC_SEND_OP_COND || opcode == SD_APP_OP_COND) ++ resp = RESP_R3; ++ else if (opcode == MMC_SET_RELATIVE_ADDR || opcode == SD_SEND_RELATIVE_ADDR) ++ resp = (mmc_cmd_type(cmd) == MMC_CMD_BCR) ? RESP_R6 : RESP_R1; ++ else if (opcode == MMC_FAST_IO) ++ resp = RESP_R4; ++ else if (opcode == MMC_GO_IRQ_STATE) ++ resp = RESP_R5; ++ else if (opcode == MMC_SELECT_CARD) ++ resp = (cmd->arg != 0) ? RESP_R1B : RESP_NONE; ++ else if (opcode == SD_IO_RW_DIRECT || opcode == SD_IO_RW_EXTENDED) ++ resp = RESP_R1; ++ else if (opcode == SD_SEND_IF_COND && (mmc_cmd_type(cmd) == MMC_CMD_BCR)) ++ resp = RESP_R1; ++ else { ++ switch (mmc_resp_type(cmd)) { ++ case MMC_RSP_R1: ++ resp = RESP_R1; ++ break; ++ case MMC_RSP_R1B: ++ resp = RESP_R1B; ++ break; ++ case MMC_RSP_R2: ++ resp = RESP_R2; ++ break; ++ case MMC_RSP_R3: ++ resp = RESP_R3; ++ break; ++ case MMC_RSP_NONE: ++ default: ++ resp = RESP_NONE; ++ break; ++ } ++ } ++ ++ cmd->error = 0; ++ rawcmd = opcode | msdc_rsp[resp] << 7 | host->blksz << 16; ++ ++ if (opcode == MMC_READ_MULTIPLE_BLOCK) { ++ rawcmd |= (2 << 11); ++ } else if (opcode == MMC_READ_SINGLE_BLOCK) { ++ rawcmd |= (1 << 11); ++ } else if (opcode == MMC_WRITE_MULTIPLE_BLOCK) { ++ rawcmd |= ((2 << 11) | (1 << 13)); ++ } else if (opcode == MMC_WRITE_BLOCK) { ++ rawcmd |= ((1 << 11) | (1 << 13)); ++ } else if (opcode == SD_IO_RW_EXTENDED) { ++ if (cmd->data->flags & MMC_DATA_WRITE) ++ rawcmd |= (1 << 13); ++ if (cmd->data->blocks > 1) ++ rawcmd |= (2 << 11); ++ else ++ rawcmd |= (1 << 11); ++ } else if (opcode == SD_IO_RW_DIRECT && cmd->flags == (unsigned int)-1) { ++ rawcmd |= (1 << 14); ++ } else if ((opcode == SD_APP_SEND_SCR) || ++ (opcode == SD_APP_SEND_NUM_WR_BLKS) || ++ (opcode == SD_SWITCH && (mmc_cmd_type(cmd) == MMC_CMD_ADTC)) || ++ (opcode == SD_APP_SD_STATUS && (mmc_cmd_type(cmd) == MMC_CMD_ADTC)) || ++ (opcode == MMC_SEND_EXT_CSD && (mmc_cmd_type(cmd) == MMC_CMD_ADTC))) { ++ rawcmd |= (1 << 11); ++ } else if (opcode == MMC_STOP_TRANSMISSION) { ++ rawcmd |= (1 << 14); ++ rawcmd &= ~(0x0FFF << 16); ++ } ++ ++// printk("CMD<%d><0x%.8x> Arg<0x%.8x>\n", opcode , rawcmd, cmd->arg); ++ ++ tmo = jiffies + timeout; ++ ++ if (opcode == MMC_SEND_STATUS) { ++ for (;;) { ++ if (!sdc_is_cmd_busy()) ++ break; ++ ++ if (time_after(jiffies, tmo)) { ++ //printk("XXX cmd_busy timeout: before CMD<%d>\n", opcode); ++ cmd->error = (unsigned int)-ETIMEDOUT; ++ msdc_reset(); ++ goto end; ++ } ++ } ++ } else { ++ for (;;) { ++ if (!sdc_is_busy()) ++ break; ++ if (time_after(jiffies, tmo)) { ++ //printk("XXX sdc_busy timeout: before CMD<%d>\n", opcode); ++ cmd->error = (unsigned int)-ETIMEDOUT; ++ msdc_reset(); ++ goto end; ++ } ++ } ++ } ++ ++ //BUG_ON(in_interrupt()); ++ host->cmd = cmd; ++ host->cmd_rsp = resp; ++ init_completion(&host->cmd_done); ++ sdr_set_bits(MSDC_INTEN, wints); ++ sdc_send_cmd(rawcmd, cmd->arg); ++ ++end: ++ return cmd->error; ++} ++ ++static unsigned int msdc_command_resp(struct msdc_host *host, struct mmc_command *cmd, ++ int tune, unsigned long timeout) ++{ ++ u32 base = host->base; ++ //u32 opcode = cmd->opcode; ++ u32 resp; ++ u32 wints = MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | ++ MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | ++ MSDC_INT_ACMD19_DONE; ++ ++ resp = host->cmd_rsp; ++ ++ BUG_ON(in_interrupt()); ++ spin_unlock(&host->lock); ++ if (!wait_for_completion_timeout(&host->cmd_done, 10*timeout)) { ++ //printk("XXX CMD<%d> wait_for_completion timeout ARG<0x%.8x>\n", opcode, cmd->arg); ++ cmd->error = (unsigned int)-ETIMEDOUT; ++ msdc_reset(); ++ } ++ spin_lock(&host->lock); ++ ++ sdr_clr_bits(MSDC_INTEN, wints); ++ host->cmd = NULL; ++ ++ if (!tune) ++ return cmd->error; ++ ++ /* memory card CRC */ ++ if (host->hw->flags & MSDC_REMOVABLE && cmd->error == (unsigned int)(-EIO) ) { ++ if (sdr_read32(SDC_CMD) & 0x1800) { ++ msdc_abort_data(host); ++ } else { ++ msdc_reset(); ++ msdc_clr_fifo(); ++ msdc_clr_int(); ++ } ++ cmd->error = msdc_tune_cmdrsp(host,cmd); ++ } ++ ++ return cmd->error; ++} ++ ++static unsigned int msdc_do_command(struct msdc_host *host, struct mmc_command *cmd, ++ int tune, unsigned long timeout) ++{ ++ if (!msdc_command_start(host, cmd, tune, timeout)) ++ msdc_command_resp(host, cmd, tune, timeout); ++ ++ //printk(" return<%d> resp<0x%.8x>\n", cmd->error, cmd->resp[0]); ++ return cmd->error; ++} ++ ++static int msdc_pio_abort(struct msdc_host *host, struct mmc_data *data, unsigned long tmo) ++{ ++ u32 base = host->base; ++ int ret = 0; ++ ++ if (atomic_read(&host->abort)) ++ ret = 1; ++ ++ if (time_after(jiffies, tmo)) { ++ data->error = (unsigned int)-ETIMEDOUT; ++ //printk("XXX PIO Data Timeout: CMD<%d>\n", host->mrq->cmd->opcode); ++ ret = 1; ++ } ++ ++ if (ret) { ++ msdc_reset(); ++ msdc_clr_fifo(); ++ msdc_clr_int(); ++ //printk("msdc pio find abort\n"); ++ } ++ ++ return ret; ++} ++ ++static int msdc_pio_read(struct msdc_host *host, struct mmc_data *data) ++{ ++ struct scatterlist *sg = data->sg; ++ u32 base = host->base; ++ u32 num = data->sg_len; ++ u32 *ptr; ++ u8 *u8ptr; ++ u32 left; ++ u32 count, size = 0; ++ u32 wints = MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR; ++ unsigned long tmo = jiffies + DAT_TIMEOUT; ++ ++ sdr_set_bits(MSDC_INTEN, wints); ++ while (num) { ++ left = sg_dma_len(sg); ++ ptr = sg_virt(sg); ++ while (left) { ++ if ((left >= MSDC_FIFO_THD) && (msdc_rxfifocnt() >= MSDC_FIFO_THD)) { ++ count = MSDC_FIFO_THD >> 2; ++ do { ++ *ptr++ = msdc_fifo_read32(); ++ } while (--count); ++ left -= MSDC_FIFO_THD; ++ } else if ((left < MSDC_FIFO_THD) && msdc_rxfifocnt() >= left) { ++ while (left > 3) { ++ *ptr++ = msdc_fifo_read32(); ++ left -= 4; ++ } ++ ++ u8ptr = (u8 *)ptr; ++ while(left) { ++ * u8ptr++ = msdc_fifo_read8(); ++ left--; ++ } ++ } ++ ++ if (msdc_pio_abort(host, data, tmo)) ++ goto end; ++ } ++ size += sg_dma_len(sg); ++ sg = sg_next(sg); num--; ++ } ++end: ++ data->bytes_xfered += size; ++ //printk(" PIO Read<%d>bytes\n", size); ++ ++ sdr_clr_bits(MSDC_INTEN, wints); ++ if(data->error) ++ printk("read pio data->error<%d> left<%d> size<%d>\n", data->error, left, size); ++ ++ return data->error; ++} ++ ++static int msdc_pio_write(struct msdc_host* host, struct mmc_data *data) ++{ ++ u32 base = host->base; ++ struct scatterlist *sg = data->sg; ++ u32 num = data->sg_len; ++ u32 *ptr; ++ u8 *u8ptr; ++ u32 left; ++ u32 count, size = 0; ++ u32 wints = MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR; ++ unsigned long tmo = jiffies + DAT_TIMEOUT; ++ ++ sdr_set_bits(MSDC_INTEN, wints); ++ while (num) { ++ left = sg_dma_len(sg); ++ ptr = sg_virt(sg); ++ ++ while (left) { ++ if (left >= MSDC_FIFO_SZ && msdc_txfifocnt() == 0) { ++ count = MSDC_FIFO_SZ >> 2; ++ do { ++ msdc_fifo_write32(*ptr); ptr++; ++ } while (--count); ++ left -= MSDC_FIFO_SZ; ++ } else if (left < MSDC_FIFO_SZ && msdc_txfifocnt() == 0) { ++ while (left > 3) { ++ msdc_fifo_write32(*ptr); ptr++; ++ left -= 4; ++ } ++ ++ u8ptr = (u8*)ptr; ++ while( left) { ++ msdc_fifo_write8(*u8ptr); ++ u8ptr++; ++ left--; ++ } ++ } ++ ++ if (msdc_pio_abort(host, data, tmo)) ++ goto end; ++ } ++ size += sg_dma_len(sg); ++ sg = sg_next(sg); num--; ++ } ++end: ++ data->bytes_xfered += size; ++ //printk(" PIO Write<%d>bytes\n", size); ++ if(data->error) ++ printk("write pio data->error<%d>\n", data->error); ++ ++ sdr_clr_bits(MSDC_INTEN, wints); ++ ++ return data->error; ++} ++ ++static void msdc_dma_start(struct msdc_host *host) ++{ ++ u32 base = host->base; ++ u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR; ++ ++ sdr_set_bits(MSDC_INTEN, wints); ++ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1); ++ ++ //printk("DMA start\n"); ++} ++ ++static void msdc_dma_stop(struct msdc_host *host) ++{ ++ u32 base = host->base; ++ u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR; ++ ++ //printk("DMA status: 0x%.8x\n",sdr_read32(MSDC_DMA_CFG)); ++ ++ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1); ++ while (sdr_read32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS); ++ sdr_clr_bits(MSDC_INTEN, wints); /* Not just xfer_comp */ ++ ++ //printk("DMA stop\n"); ++} ++ ++static u8 msdc_dma_calcs(u8 *buf, u32 len) ++{ ++ u32 i, sum = 0; ++ ++ for (i = 0; i < len; i++) ++ sum += buf[i]; ++ ++ return 0xFF - (u8)sum; ++} ++ ++static int msdc_dma_config(struct msdc_host *host, struct msdc_dma *dma) ++{ ++ u32 base = host->base; ++ u32 sglen = dma->sglen; ++ u32 j, num, bdlen; ++ u8 blkpad, dwpad, chksum; ++ struct scatterlist *sg = dma->sg; ++ gpd_t *gpd; ++ bd_t *bd; ++ ++ switch (dma->mode) { ++ case MSDC_MODE_DMA_BASIC: ++ BUG_ON(dma->xfersz > 65535); ++ BUG_ON(dma->sglen != 1); ++ sdr_write32(MSDC_DMA_SA, PHYSADDR(sg_dma_address(sg))); ++ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_LASTBUF, 1); ++ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_XFERSZ, sg_dma_len(sg)); ++ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BRUSTSZ, dma->burstsz); ++ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 0); ++ break; ++ ++ case MSDC_MODE_DMA_DESC: ++ blkpad = (dma->flags & DMA_FLAG_PAD_BLOCK) ? 1 : 0; ++ dwpad = (dma->flags & DMA_FLAG_PAD_DWORD) ? 1 : 0; ++ chksum = (dma->flags & DMA_FLAG_EN_CHKSUM) ? 1 : 0; ++ ++ num = (sglen + MAX_BD_PER_GPD - 1) / MAX_BD_PER_GPD; ++ BUG_ON(num !=1 ); ++ ++ gpd = dma->gpd; ++ bd = dma->bd; ++ bdlen = sglen; ++ ++ gpd->hwo = 1; /* hw will clear it */ ++ gpd->bdp = 1; ++ gpd->chksum = 0; /* need to clear first. */ ++ gpd->chksum = (chksum ? msdc_dma_calcs((u8 *)gpd, 16) : 0); ++ ++ for (j = 0; j < bdlen; j++) { ++ msdc_init_bd(&bd[j], blkpad, dwpad, sg_dma_address(sg), sg_dma_len(sg)); ++ if( j == bdlen - 1) ++ bd[j].eol = 1; ++ else ++ bd[j].eol = 0; ++ bd[j].chksum = 0; /* checksume need to clear first */ ++ bd[j].chksum = (chksum ? msdc_dma_calcs((u8 *)(&bd[j]), 16) : 0); ++ sg++; ++ } ++ ++ dma->used_gpd += 2; ++ dma->used_bd += bdlen; ++ ++ sdr_set_field(MSDC_DMA_CFG, MSDC_DMA_CFG_DECSEN, chksum); ++ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BRUSTSZ, dma->burstsz); ++ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 1); ++ sdr_write32(MSDC_DMA_SA, PHYSADDR((u32)dma->gpd_addr)); ++ break; ++ } ++ ++// printk("DMA_CTRL = 0x%x\n", sdr_read32(MSDC_DMA_CTRL)); ++// printk("DMA_CFG = 0x%x\n", sdr_read32(MSDC_DMA_CFG)); ++// printk("DMA_SA = 0x%x\n", sdr_read32(MSDC_DMA_SA)); ++ ++ return 0; ++} ++ ++static void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, ++ struct scatterlist *sg, unsigned int sglen) ++{ ++ BUG_ON(sglen > MAX_BD_NUM); ++ ++ dma->sg = sg; ++ dma->flags = DMA_FLAG_EN_CHKSUM; ++ dma->sglen = sglen; ++ dma->xfersz = host->xfer_size; ++ dma->burstsz = MSDC_BRUST_64B; ++ ++ if (sglen == 1 && sg_dma_len(sg) <= MAX_DMA_CNT) ++ dma->mode = MSDC_MODE_DMA_BASIC; ++ else ++ dma->mode = MSDC_MODE_DMA_DESC; ++ ++// printk("DMA mode<%d> sglen<%d> xfersz<%d>\n", dma->mode, dma->sglen, dma->xfersz); ++ ++ msdc_dma_config(host, dma); ++} ++ ++static void msdc_set_blknum(struct msdc_host *host, u32 blknum) ++{ ++ u32 base = host->base; ++ ++ sdr_write32(SDC_BLK_NUM, blknum); ++} ++ ++static int msdc_do_request(struct mmc_host*mmc, struct mmc_request*mrq) ++{ ++ struct msdc_host *host = mmc_priv(mmc); ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ u32 base = host->base; ++ unsigned int left=0; ++ int dma = 0, read = 1, dir = DMA_FROM_DEVICE, send_type=0; ++ ++#define SND_DAT 0 ++#define SND_CMD 1 ++ ++ BUG_ON(mmc == NULL); ++ BUG_ON(mrq == NULL); ++ ++ host->error = 0; ++ atomic_set(&host->abort, 0); ++ ++ cmd = mrq->cmd; ++ data = mrq->cmd->data; ++ ++ if (!data) { ++ send_type = SND_CMD; ++ if (msdc_do_command(host, cmd, 1, CMD_TIMEOUT) != 0) ++ goto done; ++ } else { ++ BUG_ON(data->blksz > HOST_MAX_BLKSZ); ++ send_type=SND_DAT; ++ ++ data->error = 0; ++ read = data->flags & MMC_DATA_READ ? 1 : 0; ++ host->data = data; ++ host->xfer_size = data->blocks * data->blksz; ++ host->blksz = data->blksz; ++ ++ host->dma_xfer = dma = ((host->xfer_size >= 512) ? 1 : 0); ++ ++ if (read) ++ if ((host->timeout_ns != data->timeout_ns) || ++ (host->timeout_clks != data->timeout_clks)) ++ msdc_set_timeout(host, data->timeout_ns, data->timeout_clks); ++ ++ msdc_set_blknum(host, data->blocks); ++ ++ if (dma) { ++ msdc_dma_on(); ++ init_completion(&host->xfer_done); ++ ++ if (msdc_command_start(host, cmd, 1, CMD_TIMEOUT) != 0) ++ goto done; ++ ++ dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; ++ dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len, dir); ++ msdc_dma_setup(host, &host->dma, data->sg, data->sg_len); ++ ++ if (msdc_command_resp(host, cmd, 1, CMD_TIMEOUT) != 0) ++ goto done; ++ ++ msdc_dma_start(host); ++ ++ spin_unlock(&host->lock); ++ if (!wait_for_completion_timeout(&host->xfer_done, DAT_TIMEOUT)) { ++ /*printk("XXX CMD<%d> wait xfer_done<%d> timeout!!\n", cmd->opcode, data->blocks * data->blksz); ++ printk(" DMA_SA = 0x%x\n", sdr_read32(MSDC_DMA_SA)); ++ printk(" DMA_CA = 0x%x\n", sdr_read32(MSDC_DMA_CA)); ++ printk(" DMA_CTRL = 0x%x\n", sdr_read32(MSDC_DMA_CTRL)); ++ printk(" DMA_CFG = 0x%x\n", sdr_read32(MSDC_DMA_CFG));*/ ++ data->error = (unsigned int)-ETIMEDOUT; ++ ++ msdc_reset(); ++ msdc_clr_fifo(); ++ msdc_clr_int(); ++ } ++ spin_lock(&host->lock); ++ msdc_dma_stop(host); ++ } else { ++ if (msdc_do_command(host, cmd, 1, CMD_TIMEOUT) != 0) ++ goto done; ++ ++ if (read) { ++ if (msdc_pio_read(host, data)) ++ goto done; ++ } else { ++ if (msdc_pio_write(host, data)) ++ goto done; ++ } ++ ++ if (!read) { ++ while (1) { ++ left = msdc_txfifocnt(); ++ if (left == 0) { ++ break; ++ } ++ if (msdc_pio_abort(host, data, jiffies + DAT_TIMEOUT)) { ++ break; ++ /* Fix me: what about if data error, when stop ? how to? */ ++ } ++ } ++ } else { ++ /* Fix me: read case: need to check CRC error */ ++ } ++ ++ /* For write case: SDCBUSY and Xfer_Comp will assert when DAT0 not busy. ++ For read case : SDCBUSY and Xfer_Comp will assert when last byte read out from FIFO. ++ */ ++ ++ /* try not to wait xfer_comp interrupt. ++ the next command will check SDC_BUSY. ++ SDC_BUSY means xfer_comp assert ++ */ ++ ++ } // PIO mode ++ ++ /* Last: stop transfer */ ++ if (data->stop){ ++ if (msdc_do_command(host, data->stop, 0, CMD_TIMEOUT) != 0) { ++ goto done; ++ } ++ } ++ } ++ ++done: ++ if (data != NULL) { ++ host->data = NULL; ++ host->dma_xfer = 0; ++ if (dma != 0) { ++ msdc_dma_off(); ++ host->dma.used_bd = 0; ++ host->dma.used_gpd = 0; ++ dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len, dir); ++ } ++ host->blksz = 0; ++ ++ // printk("CMD<%d> data<%s %s> blksz<%d> block<%d> error<%d>",cmd->opcode, (dma? "dma":"pio\n"), ++ // (read ? "read ":"write") ,data->blksz, data->blocks, data->error); ++ } ++ ++ if (mrq->cmd->error) host->error = 0x001; ++ if (mrq->data && mrq->data->error) host->error |= 0x010; ++ if (mrq->stop && mrq->stop->error) host->error |= 0x100; ++ ++ //if (host->error) printk("host->error<%d>\n", host->error); ++ ++ return host->error; ++} ++ ++static int msdc_app_cmd(struct mmc_host *mmc, struct msdc_host *host) ++{ ++ struct mmc_command cmd; ++ struct mmc_request mrq; ++ u32 err; ++ ++ memset(&cmd, 0, sizeof(struct mmc_command)); ++ cmd.opcode = MMC_APP_CMD; ++#if 0 /* bug: we meet mmc->card is null when ACMD6 */ ++ cmd.arg = mmc->card->rca << 16; ++#else ++ cmd.arg = host->app_cmd_arg; ++#endif ++ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; ++ ++ memset(&mrq, 0, sizeof(struct mmc_request)); ++ mrq.cmd = &cmd; cmd.mrq = &mrq; ++ cmd.data = NULL; ++ ++ err = msdc_do_command(host, &cmd, 0, CMD_TIMEOUT); ++ return err; ++} ++ ++static int msdc_tune_cmdrsp(struct msdc_host*host, struct mmc_command *cmd) ++{ ++ int result = -1; ++ u32 base = host->base; ++ u32 rsmpl, cur_rsmpl, orig_rsmpl; ++ u32 rrdly, cur_rrdly = 0, orig_rrdly; ++ u32 skip = 1; ++ ++ /* ==== don't support 3.0 now ==== ++ 1: R_SMPL[1] ++ 2: PAD_CMD_RESP_RXDLY[26:22] ++ ==========================*/ ++ ++ // save the previous tune result ++ sdr_get_field(MSDC_IOCON, MSDC_IOCON_RSPL, orig_rsmpl); ++ sdr_get_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY, orig_rrdly); ++ ++ rrdly = 0; ++ do { ++ for (rsmpl = 0; rsmpl < 2; rsmpl++) { ++ /* Lv1: R_SMPL[1] */ ++ cur_rsmpl = (orig_rsmpl + rsmpl) % 2; ++ if (skip == 1) { ++ skip = 0; ++ continue; ++ } ++ sdr_set_field(MSDC_IOCON, MSDC_IOCON_RSPL, cur_rsmpl); ++ ++ if (host->app_cmd) { ++ result = msdc_app_cmd(host->mmc, host); ++ if (result) { ++ //printk("TUNE_CMD app_cmd<%d> failed: RESP_RXDLY<%d>,R_SMPL<%d>\n", ++ // host->mrq->cmd->opcode, cur_rrdly, cur_rsmpl); ++ continue; ++ } ++ } ++ result = msdc_do_command(host, cmd, 0, CMD_TIMEOUT); // not tune. ++ //printk("TUNE_CMD<%d> %s PAD_CMD_RESP_RXDLY[26:22]<%d> R_SMPL[1]<%d>\n", cmd->opcode, ++// (result == 0) ? "PASS" : "FAIL", cur_rrdly, cur_rsmpl); ++ ++ if (result == 0) { ++ return 0; ++ } ++ if (result != (unsigned int)(-EIO)) { ++ // printk("TUNE_CMD<%d> Error<%d> not -EIO\n", cmd->opcode, result); ++ return result; ++ } ++ ++ /* should be EIO */ ++ if (sdr_read32(SDC_CMD) & 0x1800) { /* check if has data phase */ ++ msdc_abort_data(host); ++ } ++ } ++ ++ /* Lv2: PAD_CMD_RESP_RXDLY[26:22] */ ++ cur_rrdly = (orig_rrdly + rrdly + 1) % 32; ++ sdr_set_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY, cur_rrdly); ++ }while (++rrdly < 32); ++ ++ return result; ++} ++ ++/* Support SD2.0 Only */ ++static int msdc_tune_bread(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct msdc_host *host = mmc_priv(mmc); ++ u32 base = host->base; ++ u32 ddr=0; ++ u32 dcrc = 0; ++ u32 rxdly, cur_rxdly0, cur_rxdly1; ++ u32 dsmpl, cur_dsmpl, orig_dsmpl; ++ u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3; ++ u32 cur_dat4, cur_dat5, cur_dat6, cur_dat7; ++ u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3; ++ u32 orig_dat4, orig_dat5, orig_dat6, orig_dat7; ++ int result = -1; ++ u32 skip = 1; ++ ++ sdr_get_field(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl); ++ ++ /* Tune Method 2. */ ++ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1); ++ ++ rxdly = 0; ++ do { ++ for (dsmpl = 0; dsmpl < 2; dsmpl++) { ++ cur_dsmpl = (orig_dsmpl + dsmpl) % 2; ++ if (skip == 1) { ++ skip = 0; ++ continue; ++ } ++ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl); ++ ++ if (host->app_cmd) { ++ result = msdc_app_cmd(host->mmc, host); ++ if (result) { ++ //printk("TUNE_BREAD app_cmd<%d> failed\n", host->mrq->cmd->opcode); ++ continue; ++ } ++ } ++ result = msdc_do_request(mmc,mrq); ++ ++ sdr_get_field(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc); /* RO */ ++ if (!ddr) dcrc &= ~SDC_DCRC_STS_NEG; ++ //printk("TUNE_BREAD<%s> dcrc<0x%x> DATRDDLY0/1<0x%x><0x%x> dsmpl<0x%x>\n", ++ // (result == 0 && dcrc == 0) ? "PASS" : "FAIL", dcrc, ++ // sdr_read32(MSDC_DAT_RDDLY0), sdr_read32(MSDC_DAT_RDDLY1), cur_dsmpl); ++ ++ /* Fix me: result is 0, but dcrc is still exist */ ++ if (result == 0 && dcrc == 0) { ++ goto done; ++ } else { ++ /* there is a case: command timeout, and data phase not processed */ ++ if (mrq->data->error != 0 && mrq->data->error != (unsigned int)(-EIO)) { ++ //printk("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>\n", ++ // result, mrq->cmd->error, mrq->data->error); ++ goto done; ++ } ++ } ++ } ++ ++ cur_rxdly0 = sdr_read32(MSDC_DAT_RDDLY0); ++ cur_rxdly1 = sdr_read32(MSDC_DAT_RDDLY1); ++ ++ /* E1 ECO. YD: Reverse */ ++ if (sdr_read32(MSDC_ECO_VER) >= 4) { ++ orig_dat0 = (cur_rxdly0 >> 24) & 0x1F; ++ orig_dat1 = (cur_rxdly0 >> 16) & 0x1F; ++ orig_dat2 = (cur_rxdly0 >> 8) & 0x1F; ++ orig_dat3 = (cur_rxdly0 >> 0) & 0x1F; ++ orig_dat4 = (cur_rxdly1 >> 24) & 0x1F; ++ orig_dat5 = (cur_rxdly1 >> 16) & 0x1F; ++ orig_dat6 = (cur_rxdly1 >> 8) & 0x1F; ++ orig_dat7 = (cur_rxdly1 >> 0) & 0x1F; ++ } else { ++ orig_dat0 = (cur_rxdly0 >> 0) & 0x1F; ++ orig_dat1 = (cur_rxdly0 >> 8) & 0x1F; ++ orig_dat2 = (cur_rxdly0 >> 16) & 0x1F; ++ orig_dat3 = (cur_rxdly0 >> 24) & 0x1F; ++ orig_dat4 = (cur_rxdly1 >> 0) & 0x1F; ++ orig_dat5 = (cur_rxdly1 >> 8) & 0x1F; ++ orig_dat6 = (cur_rxdly1 >> 16) & 0x1F; ++ orig_dat7 = (cur_rxdly1 >> 24) & 0x1F; ++ } ++ ++ if (ddr) { ++ cur_dat0 = (dcrc & (1 << 0) || dcrc & (1 << 8)) ? ((orig_dat0 + 1) % 32) : orig_dat0; ++ cur_dat1 = (dcrc & (1 << 1) || dcrc & (1 << 9)) ? ((orig_dat1 + 1) % 32) : orig_dat1; ++ cur_dat2 = (dcrc & (1 << 2) || dcrc & (1 << 10)) ? ((orig_dat2 + 1) % 32) : orig_dat2; ++ cur_dat3 = (dcrc & (1 << 3) || dcrc & (1 << 11)) ? ((orig_dat3 + 1) % 32) : orig_dat3; ++ } else { ++ cur_dat0 = (dcrc & (1 << 0)) ? ((orig_dat0 + 1) % 32) : orig_dat0; ++ cur_dat1 = (dcrc & (1 << 1)) ? ((orig_dat1 + 1) % 32) : orig_dat1; ++ cur_dat2 = (dcrc & (1 << 2)) ? ((orig_dat2 + 1) % 32) : orig_dat2; ++ cur_dat3 = (dcrc & (1 << 3)) ? ((orig_dat3 + 1) % 32) : orig_dat3; ++ } ++ cur_dat4 = (dcrc & (1 << 4)) ? ((orig_dat4 + 1) % 32) : orig_dat4; ++ cur_dat5 = (dcrc & (1 << 5)) ? ((orig_dat5 + 1) % 32) : orig_dat5; ++ cur_dat6 = (dcrc & (1 << 6)) ? ((orig_dat6 + 1) % 32) : orig_dat6; ++ cur_dat7 = (dcrc & (1 << 7)) ? ((orig_dat7 + 1) % 32) : orig_dat7; ++ ++ cur_rxdly0 = (cur_dat0 << 24) | (cur_dat1 << 16) | (cur_dat2 << 8) | (cur_dat3 << 0); ++ cur_rxdly1 = (cur_dat4 << 24) | (cur_dat5 << 16) | (cur_dat6 << 8) | (cur_dat7 << 0); ++ ++ sdr_write32(MSDC_DAT_RDDLY0, cur_rxdly0); ++ sdr_write32(MSDC_DAT_RDDLY1, cur_rxdly1); ++ ++ } while (++rxdly < 32); ++ ++done: ++ return result; ++} ++ ++static int msdc_tune_bwrite(struct mmc_host *mmc,struct mmc_request *mrq) ++{ ++ struct msdc_host *host = mmc_priv(mmc); ++ u32 base = host->base; ++ ++ u32 wrrdly, cur_wrrdly = 0, orig_wrrdly; ++ u32 dsmpl, cur_dsmpl, orig_dsmpl; ++ u32 rxdly, cur_rxdly0; ++ u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3; ++ u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3; ++ int result = -1; ++ u32 skip = 1; ++ ++ // MSDC_IOCON_DDR50CKD need to check. [Fix me] ++ ++ sdr_get_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, orig_wrrdly); ++ sdr_get_field(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl ); ++ ++ /* Tune Method 2. just DAT0 */ ++ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1); ++ cur_rxdly0 = sdr_read32(MSDC_DAT_RDDLY0); ++ ++ /* E1 ECO. YD: Reverse */ ++ if (sdr_read32(MSDC_ECO_VER) >= 4) { ++ orig_dat0 = (cur_rxdly0 >> 24) & 0x1F; ++ orig_dat1 = (cur_rxdly0 >> 16) & 0x1F; ++ orig_dat2 = (cur_rxdly0 >> 8) & 0x1F; ++ orig_dat3 = (cur_rxdly0 >> 0) & 0x1F; ++ } else { ++ orig_dat0 = (cur_rxdly0 >> 0) & 0x1F; ++ orig_dat1 = (cur_rxdly0 >> 8) & 0x1F; ++ orig_dat2 = (cur_rxdly0 >> 16) & 0x1F; ++ orig_dat3 = (cur_rxdly0 >> 24) & 0x1F; ++ } ++ ++ rxdly = 0; ++ do { ++ wrrdly = 0; ++ do { ++ for (dsmpl = 0; dsmpl < 2; dsmpl++) { ++ cur_dsmpl = (orig_dsmpl + dsmpl) % 2; ++ if (skip == 1) { ++ skip = 0; ++ continue; ++ } ++ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl); ++ ++ if (host->app_cmd) { ++ result = msdc_app_cmd(host->mmc, host); ++ if (result) { ++ //printk("TUNE_BWRITE app_cmd<%d> failed\n", host->mrq->cmd->opcode); ++ continue; ++ } ++ } ++ result = msdc_do_request(mmc,mrq); ++ ++ //printk("TUNE_BWRITE<%s> DSPL<%d> DATWRDLY<%d> MSDC_DAT_RDDLY0<0x%x>\n", ++ // result == 0 ? "PASS" : "FAIL", ++ // cur_dsmpl, cur_wrrdly, cur_rxdly0); ++ ++ if (result == 0) { ++ goto done; ++ } ++ else { ++ /* there is a case: command timeout, and data phase not processed */ ++ if (mrq->data->error != (unsigned int)(-EIO)) { ++ //printk("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>\n", ++ // && result, mrq->cmd->error, mrq->data->error); ++ goto done; ++ } ++ } ++ } ++ cur_wrrdly = (orig_wrrdly + wrrdly + 1) % 32; ++ sdr_set_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, cur_wrrdly); ++ } while (++wrrdly < 32); ++ ++ cur_dat0 = (orig_dat0 + rxdly) % 32; /* only adjust bit-1 for crc */ ++ cur_dat1 = orig_dat1; ++ cur_dat2 = orig_dat2; ++ cur_dat3 = orig_dat3; ++ ++ cur_rxdly0 = (cur_dat0 << 24) | (cur_dat1 << 16) | (cur_dat2 << 8) | (cur_dat3 << 0); ++ sdr_write32(MSDC_DAT_RDDLY0, cur_rxdly0); ++ } while (++rxdly < 32); ++ ++done: ++ return result; ++} ++ ++static int msdc_get_card_status(struct mmc_host *mmc, struct msdc_host *host, u32 *status) ++{ ++ struct mmc_command cmd; ++ struct mmc_request mrq; ++ u32 err; ++ ++ memset(&cmd, 0, sizeof(struct mmc_command)); ++ cmd.opcode = MMC_SEND_STATUS; ++ if (mmc->card) { ++ cmd.arg = mmc->card->rca << 16; ++ } else { ++ //printk("cmd13 mmc card is null\n"); ++ cmd.arg = host->app_cmd_arg; ++ } ++ cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; ++ ++ memset(&mrq, 0, sizeof(struct mmc_request)); ++ mrq.cmd = &cmd; cmd.mrq = &mrq; ++ cmd.data = NULL; ++ ++ err = msdc_do_command(host, &cmd, 1, CMD_TIMEOUT); ++ ++ if (status) ++ *status = cmd.resp[0]; ++ ++ return err; ++} ++ ++static int msdc_check_busy(struct mmc_host *mmc, struct msdc_host *host) ++{ ++ u32 err = 0; ++ u32 status = 0; ++ ++ do { ++ err = msdc_get_card_status(mmc, host, &status); ++ if (err) ++ return err; ++ /* need cmd12? */ ++ //printk("cmd<13> resp<0x%x>\n", status); ++ } while (R1_CURRENT_STATE(status) == 7); ++ ++ return err; ++} ++ ++static int msdc_tune_request(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct msdc_host *host = mmc_priv(mmc); ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ int ret=0, read; ++ ++ cmd = mrq->cmd; ++ data = mrq->cmd->data; ++ ++ read = data->flags & MMC_DATA_READ ? 1 : 0; ++ ++ if (read) { ++ if (data->error == (unsigned int)(-EIO)) ++ ret = msdc_tune_bread(mmc,mrq); ++ } else { ++ ret = msdc_check_busy(mmc, host); ++ if (ret){ ++ //printk("XXX cmd13 wait program done failed\n"); ++ return ret; ++ } ++ /* CRC and TO */ ++ /* Fix me: don't care card status? */ ++ ret = msdc_tune_bwrite(mmc,mrq); ++ } ++ ++ return ret; ++} ++ ++static void msdc_ops_request(struct mmc_host *mmc,struct mmc_request *mrq) ++{ ++ struct msdc_host *host = mmc_priv(mmc); ++ ++ if (host->mrq) { ++ //printk("XXX host->mrq<0x%.8x>\n", (int)host->mrq); ++ BUG(); ++ } ++ if (!is_card_present(host) || host->power_mode == MMC_POWER_OFF) { ++ //printk("cmd<%d> card<%d> power<%d>\n", mrq->cmd->opcode, is_card_present(host), host->power_mode); ++ mrq->cmd->error = (unsigned int)-ENOMEDIUM; ++ mrq->done(mrq); ++ return; ++ } ++ spin_lock(&host->lock); ++ ++ host->mrq = mrq; ++ ++ if (msdc_do_request(mmc,mrq)) ++ if(host->hw->flags & MSDC_REMOVABLE && mrq->data && mrq->data->error) ++ msdc_tune_request(mmc,mrq); ++ ++ if (mrq->cmd->opcode == MMC_APP_CMD) { ++ host->app_cmd = 1; ++ host->app_cmd_arg = mrq->cmd->arg; /* save the RCA */ ++ } else { ++ host->app_cmd = 0; ++ } ++ ++ host->mrq = NULL; ++ ++ spin_unlock(&host->lock); ++ ++ mmc_request_done(mmc, mrq); ++} ++ ++/* called by ops.set_ios */ ++static void msdc_set_buswidth(struct msdc_host *host, u32 width) ++{ ++ u32 base = host->base; ++ u32 val = sdr_read32(SDC_CFG); ++ ++ val &= ~SDC_CFG_BUSWIDTH; ++ ++ switch (width) { ++ default: ++ case MMC_BUS_WIDTH_1: ++ width = 1; ++ val |= (MSDC_BUS_1BITS << 16); ++ break; ++ case MMC_BUS_WIDTH_4: ++ val |= (MSDC_BUS_4BITS << 16); ++ break; ++ case MMC_BUS_WIDTH_8: ++ val |= (MSDC_BUS_8BITS << 16); ++ break; ++ } ++ ++ sdr_write32(SDC_CFG, val); ++ ++ //printk("Bus Width = %d\n", width); ++} ++ ++/* ops.set_ios */ ++static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct msdc_host *host = mmc_priv(mmc); ++ struct msdc_hw *hw=host->hw; ++ u32 base = host->base; ++ u32 ddr = 0; ++ ++#ifdef MT6575_SD_DEBUG ++ static char *vdd[] = { ++ "1.50v", "1.55v", "1.60v", "1.65v", "1.70v", "1.80v", "1.90v", ++ "2.00v", "2.10v", "2.20v", "2.30v", "2.40v", "2.50v", "2.60v", ++ "2.70v", "2.80v", "2.90v", "3.00v", "3.10v", "3.20v", "3.30v", ++ "3.40v", "3.50v", "3.60v" ++ }; ++ static char *power_mode[] = { ++ "OFF", "UP", "ON" ++ }; ++ static char *bus_mode[] = { ++ "UNKNOWN", "OPENDRAIN", "PUSHPULL" ++ }; ++ static char *timing[] = { ++ "LEGACY", "MMC_HS", "SD_HS" ++ }; ++ ++ /*printk("SET_IOS: CLK(%dkHz), BUS(%s), BW(%u), PWR(%s), VDD(%s), TIMING(%s)\n", ++ ios->clock / 1000, bus_mode[ios->bus_mode], ++ (ios->bus_width == MMC_BUS_WIDTH_4) ? 4 : 1, ++ power_mode[ios->power_mode], vdd[ios->vdd], timing[ios->timing]);*/ ++#endif ++ ++ msdc_set_buswidth(host, ios->bus_width); ++ ++ /* Power control ??? */ ++ switch (ios->power_mode) { ++ case MMC_POWER_OFF: ++ case MMC_POWER_UP: ++ // msdc_set_power_mode(host, ios->power_mode); /* --- by chhung */ ++ break; ++ case MMC_POWER_ON: ++ host->power_mode = MMC_POWER_ON; ++ break; ++ default: ++ break; ++ } ++ ++ /* Clock control */ ++ if (host->mclk != ios->clock) { ++ if(ios->clock > 25000000) { ++ //printk("SD data latch edge<%d>\n", hw->data_edge); ++ sdr_set_field(MSDC_IOCON, MSDC_IOCON_RSPL, hw->cmd_edge); ++ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, hw->data_edge); ++ } else { ++ sdr_write32(MSDC_IOCON, 0x00000000); ++ sdr_write32(MSDC_DAT_RDDLY0, 0x10101010); // for MT7620 E2 and afterward ++ sdr_write32(MSDC_DAT_RDDLY1, 0x00000000); ++ sdr_write32(MSDC_PAD_TUNE, 0x84101010); // for MT7620 E2 and afterward ++ } ++ msdc_set_mclk(host, ddr, ios->clock); ++ } ++} ++ ++/* ops.get_ro */ ++static int msdc_ops_get_ro(struct mmc_host *mmc) ++{ ++ struct msdc_host *host = mmc_priv(mmc); ++ u32 base = host->base; ++ unsigned long flags; ++ int ro = 0; ++ ++ if (host->hw->flags & MSDC_WP_PIN_EN) { /* set for card */ ++ spin_lock_irqsave(&host->lock, flags); ++ ro = (sdr_read32(MSDC_PS) >> 31); ++ spin_unlock_irqrestore(&host->lock, flags); ++ } ++ return ro; ++} ++ ++/* ops.get_cd */ ++static int msdc_ops_get_cd(struct mmc_host *mmc) ++{ ++ struct msdc_host *host = mmc_priv(mmc); ++ u32 base = host->base; ++ unsigned long flags; ++ int present = 1; ++ ++ /* for sdio, MSDC_REMOVABLE not set, always return 1 */ ++ if (!(host->hw->flags & MSDC_REMOVABLE)) { ++ /* For sdio, read H/W always get<1>, but may timeout some times */ ++#if 1 ++ host->card_inserted = 1; ++ return 1; ++#else ++ host->card_inserted = (host->pm_state.event == PM_EVENT_USER_RESUME) ? 1 : 0; ++ printk("sdio ops_get_cd<%d>\n", host->card_inserted); ++ return host->card_inserted; ++#endif ++ } ++ ++ /* MSDC_CD_PIN_EN set for card */ ++ if (host->hw->flags & MSDC_CD_PIN_EN) { ++ spin_lock_irqsave(&host->lock, flags); ++#if 0 ++ present = host->card_inserted; /* why not read from H/W: Fix me*/ ++#else ++ present = (sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 0 : 1; ++ host->card_inserted = present; ++#endif ++ spin_unlock_irqrestore(&host->lock, flags); ++ } else { ++ present = 0; /* TODO? Check DAT3 pins for card detection */ ++ } ++ ++ //printk("ops_get_cd return<%d>\n", present); ++ return present; ++} ++ ++/* ops.enable_sdio_irq */ ++static void msdc_ops_enable_sdio_irq(struct mmc_host *mmc, int enable) ++{ ++ struct msdc_host *host = mmc_priv(mmc); ++ struct msdc_hw *hw = host->hw; ++ u32 base = host->base; ++ u32 tmp; ++ ++ if (hw->flags & MSDC_EXT_SDIO_IRQ) { /* yes for sdio */ ++ if (enable) { ++ hw->enable_sdio_eirq(); /* combo_sdio_enable_eirq */ ++ } else { ++ hw->disable_sdio_eirq(); /* combo_sdio_disable_eirq */ ++ } ++ } else { ++ //printk("XXX \n"); /* so never enter here */ ++ tmp = sdr_read32(SDC_CFG); ++ /* FIXME. Need to interrupt gap detection */ ++ if (enable) { ++ tmp |= (SDC_CFG_SDIOIDE | SDC_CFG_SDIOINTWKUP); ++ } else { ++ tmp &= ~(SDC_CFG_SDIOIDE | SDC_CFG_SDIOINTWKUP); ++ } ++ sdr_write32(SDC_CFG, tmp); ++ } ++} ++ ++static struct mmc_host_ops mt_msdc_ops = { ++ .request = msdc_ops_request, ++ .set_ios = msdc_ops_set_ios, ++ .get_ro = msdc_ops_get_ro, ++ .get_cd = msdc_ops_get_cd, ++ .enable_sdio_irq = msdc_ops_enable_sdio_irq, ++}; ++ ++/*--------------------------------------------------------------------------*/ ++/* interrupt handler */ ++/*--------------------------------------------------------------------------*/ ++static irqreturn_t msdc_irq(int irq, void *dev_id) ++{ ++ struct msdc_host *host = (struct msdc_host *)dev_id; ++ struct mmc_data *data = host->data; ++ struct mmc_command *cmd = host->cmd; ++ u32 base = host->base; ++ ++ u32 cmdsts = MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | MSDC_INT_CMDRDY | ++ MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | MSDC_INT_ACMDRDY | ++ MSDC_INT_ACMD19_DONE; ++ u32 datsts = MSDC_INT_DATCRCERR |MSDC_INT_DATTMO; ++ ++ u32 intsts = sdr_read32(MSDC_INT); ++ u32 inten = sdr_read32(MSDC_INTEN); inten &= intsts; ++ ++ sdr_write32(MSDC_INT, intsts); /* clear interrupts */ ++ /* MSG will cause fatal error */ ++ ++ /* card change interrupt */ ++ if (intsts & MSDC_INT_CDSC){ ++ //printk("MSDC_INT_CDSC irq<0x%.8x>\n", intsts); ++ tasklet_hi_schedule(&host->card_tasklet); ++ /* tuning when plug card ? */ ++ } ++ ++ /* sdio interrupt */ ++ if (intsts & MSDC_INT_SDIOIRQ){ ++ //printk("XXX MSDC_INT_SDIOIRQ\n"); /* seems not sdio irq */ ++ //mmc_signal_sdio_irq(host->mmc); ++ } ++ ++ /* transfer complete interrupt */ ++ if (data != NULL) { ++ if (inten & MSDC_INT_XFER_COMPL) { ++ data->bytes_xfered = host->dma.xfersz; ++ complete(&host->xfer_done); ++ } ++ ++ if (intsts & datsts) { ++ /* do basic reset, or stop command will sdc_busy */ ++ msdc_reset(); ++ msdc_clr_fifo(); ++ msdc_clr_int(); ++ atomic_set(&host->abort, 1); /* For PIO mode exit */ ++ ++ if (intsts & MSDC_INT_DATTMO){ ++ //printk("XXX CMD<%d> MSDC_INT_DATTMO\n", host->mrq->cmd->opcode); ++ data->error = (unsigned int)-ETIMEDOUT; ++ } ++ else if (intsts & MSDC_INT_DATCRCERR){ ++ //printk("XXX CMD<%d> MSDC_INT_DATCRCERR, SDC_DCRC_STS<0x%x>\n", host->mrq->cmd->opcode, sdr_read32(SDC_DCRC_STS)); ++ data->error = (unsigned int)-EIO; ++ } ++ ++ //if(sdr_read32(MSDC_INTEN) & MSDC_INT_XFER_COMPL) { ++ if (host->dma_xfer) { ++ complete(&host->xfer_done); /* Read CRC come fast, XFER_COMPL not enabled */ ++ } /* PIO mode can't do complete, because not init */ ++ } ++ } ++ ++ /* command interrupts */ ++ if ((cmd != NULL) && (intsts & cmdsts)) { ++ if ((intsts & MSDC_INT_CMDRDY) || (intsts & MSDC_INT_ACMDRDY) || ++ (intsts & MSDC_INT_ACMD19_DONE)) { ++ u32 *rsp = &cmd->resp[0]; ++ ++ switch (host->cmd_rsp) { ++ case RESP_NONE: ++ break; ++ case RESP_R2: ++ *rsp++ = sdr_read32(SDC_RESP3); *rsp++ = sdr_read32(SDC_RESP2); ++ *rsp++ = sdr_read32(SDC_RESP1); *rsp++ = sdr_read32(SDC_RESP0); ++ break; ++ default: /* Response types 1, 3, 4, 5, 6, 7(1b) */ ++ if ((intsts & MSDC_INT_ACMDRDY) || (intsts & MSDC_INT_ACMD19_DONE)) { ++ *rsp = sdr_read32(SDC_ACMD_RESP); ++ } else { ++ *rsp = sdr_read32(SDC_RESP0); ++ } ++ break; ++ } ++ } else if ((intsts & MSDC_INT_RSPCRCERR) || (intsts & MSDC_INT_ACMDCRCERR)) { ++ if(intsts & MSDC_INT_ACMDCRCERR){ ++ //printk("XXX CMD<%d> MSDC_INT_ACMDCRCERR\n",cmd->opcode); ++ } ++ else { ++ //printk("XXX CMD<%d> MSDC_INT_RSPCRCERR\n",cmd->opcode); ++ } ++ cmd->error = (unsigned int)-EIO; ++ } else if ((intsts & MSDC_INT_CMDTMO) || (intsts & MSDC_INT_ACMDTMO)) { ++ if(intsts & MSDC_INT_ACMDTMO){ ++ //printk("XXX CMD<%d> MSDC_INT_ACMDTMO\n",cmd->opcode); ++ } ++ else { ++ //printk("XXX CMD<%d> MSDC_INT_CMDTMO\n",cmd->opcode); ++ } ++ cmd->error = (unsigned int)-ETIMEDOUT; ++ msdc_reset(); ++ msdc_clr_fifo(); ++ msdc_clr_int(); ++ } ++ complete(&host->cmd_done); ++ } ++ ++ /* mmc irq interrupts */ ++ if (intsts & MSDC_INT_MMCIRQ) { ++ //printk(KERN_INFO "msdc[%d] MMCIRQ: SDC_CSTS=0x%.8x\r\n", host->id, sdr_read32(SDC_CSTS)); ++ } ++ ++#ifdef MT6575_SD_DEBUG ++ { ++ msdc_int_reg *int_reg = (msdc_int_reg*)&intsts; ++ /*printk("IRQ_EVT(0x%x): MMCIRQ(%d) CDSC(%d), ACRDY(%d), ACTMO(%d), ACCRE(%d) AC19DN(%d)\n", ++ intsts, ++ int_reg->mmcirq, ++ int_reg->cdsc, ++ int_reg->atocmdrdy, ++ int_reg->atocmdtmo, ++ int_reg->atocmdcrc, ++ int_reg->atocmd19done); ++ printk("IRQ_EVT(0x%x): SDIO(%d) CMDRDY(%d), CMDTMO(%d), RSPCRC(%d), CSTA(%d)\n", ++ intsts, ++ int_reg->sdioirq, ++ int_reg->cmdrdy, ++ int_reg->cmdtmo, ++ int_reg->rspcrc, ++ int_reg->csta); ++ printk("IRQ_EVT(0x%x): XFCMP(%d) DXDONE(%d), DATTMO(%d), DATCRC(%d), DMAEMP(%d)\n", ++ intsts, ++ int_reg->xfercomp, ++ int_reg->dxferdone, ++ int_reg->dattmo, ++ int_reg->datcrc, ++ int_reg->dmaqempty);*/ ++ ++ } ++#endif ++ ++ return IRQ_HANDLED; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* platform_driver members */ ++/*--------------------------------------------------------------------------*/ ++/* called by msdc_drv_probe/remove */ ++static void msdc_enable_cd_irq(struct msdc_host *host, int enable) ++{ ++ struct msdc_hw *hw = host->hw; ++ u32 base = host->base; ++ ++ /* for sdio, not set */ ++ if ((hw->flags & MSDC_CD_PIN_EN) == 0) { ++ /* Pull down card detection pin since it is not avaiable */ ++ /* ++ if (hw->config_gpio_pin) ++ hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_DOWN); ++ */ ++ sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN); ++ sdr_clr_bits(MSDC_INTEN, MSDC_INTEN_CDSC); ++ sdr_clr_bits(SDC_CFG, SDC_CFG_INSWKUP); ++ return; ++ } ++ ++ //printk("CD IRQ Eanable(%d)\n", enable); ++ ++ if (enable) { ++ if (hw->enable_cd_eirq) { /* not set, never enter */ ++ hw->enable_cd_eirq(); ++ } else { ++ /* card detection circuit relies on the core power so that the core power ++ * shouldn't be turned off. Here adds a reference count to keep ++ * the core power alive. ++ */ ++ //msdc_vcore_on(host); //did in msdc_init_hw() ++ ++ if (hw->config_gpio_pin) /* NULL */ ++ hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_UP); ++ ++ sdr_set_field(MSDC_PS, MSDC_PS_CDDEBOUNCE, DEFAULT_DEBOUNCE); ++ sdr_set_bits(MSDC_PS, MSDC_PS_CDEN); ++ sdr_set_bits(MSDC_INTEN, MSDC_INTEN_CDSC); ++ sdr_set_bits(SDC_CFG, SDC_CFG_INSWKUP); /* not in document! Fix me */ ++ } ++ } else { ++ if (hw->disable_cd_eirq) { ++ hw->disable_cd_eirq(); ++ } else { ++ if (hw->config_gpio_pin) /* NULL */ ++ hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_DOWN); ++ ++ sdr_clr_bits(SDC_CFG, SDC_CFG_INSWKUP); ++ sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN); ++ sdr_clr_bits(MSDC_INTEN, MSDC_INTEN_CDSC); ++ ++ /* Here decreases a reference count to core power since card ++ * detection circuit is shutdown. ++ */ ++ //msdc_vcore_off(host); ++ } ++ } ++} ++ ++/* called by msdc_drv_probe */ ++static void msdc_init_hw(struct msdc_host *host) ++{ ++ u32 base = host->base; ++ struct msdc_hw *hw = host->hw; ++ ++#ifdef MT6575_SD_DEBUG ++ msdc_reg[host->id] = (struct msdc_regs *)host->base; ++#endif ++ ++ /* Power on */ ++#if 0 /* --- chhung */ ++ msdc_vcore_on(host); ++ msdc_pin_reset(host, MSDC_PIN_PULL_UP); ++ msdc_select_clksrc(host, hw->clk_src); ++ enable_clock(PERI_MSDC0_PDN + host->id, "SD"); ++ msdc_vdd_on(host); ++#endif /* end of --- */ ++ /* Configure to MMC/SD mode */ ++ sdr_set_field(MSDC_CFG, MSDC_CFG_MODE, MSDC_SDMMC); ++ ++ /* Reset */ ++ msdc_reset(); ++ msdc_clr_fifo(); ++ ++ /* Disable card detection */ ++ sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN); ++ ++ /* Disable and clear all interrupts */ ++ sdr_clr_bits(MSDC_INTEN, sdr_read32(MSDC_INTEN)); ++ sdr_write32(MSDC_INT, sdr_read32(MSDC_INT)); ++ ++#if 1 ++ /* reset tuning parameter */ ++ sdr_write32(MSDC_PAD_CTL0, 0x00090000); ++ sdr_write32(MSDC_PAD_CTL1, 0x000A0000); ++ sdr_write32(MSDC_PAD_CTL2, 0x000A0000); ++ // sdr_write32(MSDC_PAD_TUNE, 0x00000000); ++ sdr_write32(MSDC_PAD_TUNE, 0x84101010); // for MT7620 E2 and afterward ++ // sdr_write32(MSDC_DAT_RDDLY0, 0x00000000); ++ sdr_write32(MSDC_DAT_RDDLY0, 0x10101010); // for MT7620 E2 and afterward ++ sdr_write32(MSDC_DAT_RDDLY1, 0x00000000); ++ sdr_write32(MSDC_IOCON, 0x00000000); ++#if 0 // use MT7620 default value: 0x403c004f ++ sdr_write32(MSDC_PATCH_BIT0, 0x003C000F); /* bit0 modified: Rx Data Clock Source: 1 -> 2.0*/ ++#endif ++ ++ if (sdr_read32(MSDC_ECO_VER) >= 4) { ++ if (host->id == 1) { ++ sdr_set_field(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_WRDAT_CRCS, 1); ++ sdr_set_field(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMD_RSP, 1); ++ ++ /* internal clock: latch read data */ ++ sdr_set_bits(MSDC_PATCH_BIT0, MSDC_PATCH_BIT_CKGEN_CK); ++ } ++ } ++#endif ++ ++ /* for safety, should clear SDC_CFG.SDIO_INT_DET_EN & set SDC_CFG.SDIO in ++ pre-loader,uboot,kernel drivers. and SDC_CFG.SDIO_INT_DET_EN will be only ++ set when kernel driver wants to use SDIO bus interrupt */ ++ /* Configure to enable SDIO mode. it's must otherwise sdio cmd5 failed */ ++ sdr_set_bits(SDC_CFG, SDC_CFG_SDIO); ++ ++ /* disable detect SDIO device interupt function */ ++ sdr_clr_bits(SDC_CFG, SDC_CFG_SDIOIDE); ++ ++ /* eneable SMT for glitch filter */ ++ sdr_set_bits(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKSMT); ++ sdr_set_bits(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDSMT); ++ sdr_set_bits(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATSMT); ++ ++#if 1 ++ /* set clk, cmd, dat pad driving */ ++ sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVN, hw->clk_drv); ++ sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVP, hw->clk_drv); ++ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVN, hw->cmd_drv); ++ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVP, hw->cmd_drv); ++ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVN, hw->dat_drv); ++ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVP, hw->dat_drv); ++#else ++ sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVN, 0); ++ sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVP, 0); ++ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVN, 0); ++ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVP, 0); ++ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVN, 0); ++ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVP, 0); ++#endif ++ ++ /* set sampling edge */ ++ ++ /* write crc timeout detection */ ++ sdr_set_field(MSDC_PATCH_BIT0, 1 << 30, 1); ++ ++ /* Configure to default data timeout */ ++ sdr_set_field(SDC_CFG, SDC_CFG_DTOC, DEFAULT_DTOC); ++ ++ msdc_set_buswidth(host, MMC_BUS_WIDTH_1); ++ ++ //printk("init hardware done!\n"); ++} ++ ++/* called by msdc_drv_remove */ ++static void msdc_deinit_hw(struct msdc_host *host) ++{ ++ u32 base = host->base; ++ ++ /* Disable and clear all interrupts */ ++ sdr_clr_bits(MSDC_INTEN, sdr_read32(MSDC_INTEN)); ++ sdr_write32(MSDC_INT, sdr_read32(MSDC_INT)); ++ ++ /* Disable card detection */ ++ msdc_enable_cd_irq(host, 0); ++ // msdc_set_power_mode(host, MMC_POWER_OFF); /* make sure power down */ /* --- by chhung */ ++} ++ ++/* init gpd and bd list in msdc_drv_probe */ ++static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma) ++{ ++ gpd_t *gpd = dma->gpd; ++ bd_t *bd = dma->bd; ++ bd_t *ptr, *prev; ++ ++ /* we just support one gpd */ ++ int bdlen = MAX_BD_PER_GPD; ++ ++ /* init the 2 gpd */ ++ memset(gpd, 0, sizeof(gpd_t) * 2); ++ //gpd->next = (void *)virt_to_phys(gpd + 1); /* pointer to a null gpd, bug! kmalloc <-> virt_to_phys */ ++ //gpd->next = (dma->gpd_addr + 1); /* bug */ ++ gpd->next = (void *)((u32)dma->gpd_addr + sizeof(gpd_t)); ++ ++ //gpd->intr = 0; ++ gpd->bdp = 1; /* hwo, cs, bd pointer */ ++ //gpd->ptr = (void*)virt_to_phys(bd); ++ gpd->ptr = (void *)dma->bd_addr; /* physical address */ ++ ++ memset(bd, 0, sizeof(bd_t) * bdlen); ++ ptr = bd + bdlen - 1; ++ //ptr->eol = 1; /* 0 or 1 [Fix me]*/ ++ //ptr->next = 0; ++ ++ while (ptr != bd) { ++ prev = ptr - 1; ++ prev->next = (void *)(dma->bd_addr + sizeof(bd_t) *(ptr - bd)); ++ ptr = prev; ++ } ++} ++ ++static int msdc_drv_probe(struct platform_device *pdev) ++{ ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ __iomem void *base; ++ struct mmc_host *mmc; ++ struct resource *mem; ++ struct msdc_host *host; ++ struct msdc_hw *hw; ++ int ret, irq; ++ pdev->dev.platform_data = &msdc0_hw; ++ ++ /* Allocate MMC host for this device */ ++ mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev); ++ if (!mmc) return -ENOMEM; ++ ++ hw = (struct msdc_hw*)pdev->dev.platform_data; ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_irq(pdev, 0); ++ ++ //BUG_ON((!hw) || (!mem) || (irq < 0)); /* --- by chhung */ ++ ++ base = devm_request_and_ioremap(&pdev->dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++/* mem = request_mem_region(mem->start - 0xa0000000, (mem->end - mem->start + 1) - 0xa0000000, dev_name(&pdev->dev)); ++ if (mem == NULL) { ++ mmc_free_host(mmc); ++ return -EBUSY; ++ } ++*/ ++ /* Set host parameters to mmc */ ++ mmc->ops = &mt_msdc_ops; ++ mmc->f_min = HOST_MIN_MCLK; ++ mmc->f_max = HOST_MAX_MCLK; ++ mmc->ocr_avail = MSDC_OCR_AVAIL; ++ ++ /* For sd card: MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED, ++ For sdio : MSDC_EXT_SDIO_IRQ | MSDC_HIGHSPEED */ ++ if (hw->flags & MSDC_HIGHSPEED) { ++ mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; ++ } ++ if (hw->data_pins == 4) { /* current data_pins are all 4*/ ++ mmc->caps |= MMC_CAP_4_BIT_DATA; ++ } else if (hw->data_pins == 8) { ++ mmc->caps |= MMC_CAP_8_BIT_DATA; ++ } ++ if ((hw->flags & MSDC_SDIO_IRQ) || (hw->flags & MSDC_EXT_SDIO_IRQ)) ++ mmc->caps |= MMC_CAP_SDIO_IRQ; /* yes for sdio */ ++ ++ /* MMC core transfer sizes tunable parameters */ ++ // mmc->max_hw_segs = MAX_HW_SGMTS; ++// mmc->max_phys_segs = MAX_PHY_SGMTS; ++ mmc->max_seg_size = MAX_SGMT_SZ; ++ mmc->max_blk_size = HOST_MAX_BLKSZ; ++ mmc->max_req_size = MAX_REQ_SZ; ++ mmc->max_blk_count = mmc->max_req_size; ++ ++ host = mmc_priv(mmc); ++ host->hw = hw; ++ host->mmc = mmc; ++ host->id = pdev->id; ++ host->error = 0; ++ host->irq = irq; ++ host->base = (unsigned long) base; ++ host->mclk = 0; /* mclk: the request clock of mmc sub-system */ ++ host->hclk = hclks[hw->clk_src]; /* hclk: clock of clock source to msdc controller */ ++ host->sclk = 0; /* sclk: the really clock after divition */ ++ host->pm_state = PMSG_RESUME; ++ host->suspend = 0; ++ host->core_clkon = 0; ++ host->card_clkon = 0; ++ host->core_power = 0; ++ host->power_mode = MMC_POWER_OFF; ++// host->card_inserted = hw->flags & MSDC_REMOVABLE ? 0 : 1; ++ host->timeout_ns = 0; ++ host->timeout_clks = DEFAULT_DTOC * 65536; ++ ++ host->mrq = NULL; ++ //init_MUTEX(&host->sem); /* we don't need to support multiple threads access */ ++ ++ host->dma.used_gpd = 0; ++ host->dma.used_bd = 0; ++ ++ /* using dma_alloc_coherent*/ /* todo: using 1, for all 4 slots */ ++ host->dma.gpd = dma_alloc_coherent(NULL, MAX_GPD_NUM * sizeof(gpd_t), &host->dma.gpd_addr, GFP_KERNEL); ++ host->dma.bd = dma_alloc_coherent(NULL, MAX_BD_NUM * sizeof(bd_t), &host->dma.bd_addr, GFP_KERNEL); ++ BUG_ON((!host->dma.gpd) || (!host->dma.bd)); ++ msdc_init_gpd_bd(host, &host->dma); ++ /*for emmc*/ ++ msdc_6575_host[pdev->id] = host; ++ ++ tasklet_init(&host->card_tasklet, msdc_tasklet_card, (ulong)host); ++ spin_lock_init(&host->lock); ++ msdc_init_hw(host); ++ ++ ret = request_irq((unsigned int)irq, msdc_irq, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), host); ++ if (ret) goto release; ++ // mt65xx_irq_unmask(irq); /* --- by chhung */ ++ ++ if (hw->flags & MSDC_CD_PIN_EN) { /* not set for sdio */ ++ if (hw->request_cd_eirq) { /* not set for MT6575 */ ++ hw->request_cd_eirq(msdc_eirq_cd, (void*)host); /* msdc_eirq_cd will not be used! */ ++ } ++ } ++ ++ if (hw->request_sdio_eirq) /* set to combo_sdio_request_eirq() for WIFI */ ++ hw->request_sdio_eirq(msdc_eirq_sdio, (void*)host); /* msdc_eirq_sdio() will be called when EIRQ */ ++ ++ if (hw->register_pm) {/* yes for sdio */ ++ if(hw->flags & MSDC_SYS_SUSPEND) { /* will not set for WIFI */ ++ //printk("MSDC_SYS_SUSPEND and register_pm both set\n"); ++ } ++ //mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* pm not controlled by system but by client. */ /* --- by chhung */ ++ } ++ ++ platform_set_drvdata(pdev, mmc); ++ ++ ret = mmc_add_host(mmc); ++ if (ret) goto free_irq; ++ ++ /* Config card detection pin and enable interrupts */ ++ if (hw->flags & MSDC_CD_PIN_EN) { /* set for card */ ++ msdc_enable_cd_irq(host, 1); ++ } else { ++ msdc_enable_cd_irq(host, 0); ++ } ++ ++ return 0; ++ ++free_irq: ++ free_irq(irq, host); ++release: ++ platform_set_drvdata(pdev, NULL); ++ msdc_deinit_hw(host); ++ ++ tasklet_kill(&host->card_tasklet); ++ ++/* if (mem) ++ release_mem_region(mem->start, mem->end - mem->start + 1); ++*/ ++ mmc_free_host(mmc); ++ ++ return ret; ++} ++ ++/* 4 device share one driver, using "drvdata" to show difference */ ++static int msdc_drv_remove(struct platform_device *pdev) ++{ ++ struct mmc_host *mmc; ++ struct msdc_host *host; ++ struct resource *mem; ++ ++ ++ mmc = platform_get_drvdata(pdev); ++ BUG_ON(!mmc); ++ ++ host = mmc_priv(mmc); ++ BUG_ON(!host); ++ ++ //printk("removed !!!\n"); ++ ++ platform_set_drvdata(pdev, NULL); ++ mmc_remove_host(host->mmc); ++ msdc_deinit_hw(host); ++ ++ tasklet_kill(&host->card_tasklet); ++ free_irq(host->irq, host); ++ ++ dma_free_coherent(NULL, MAX_GPD_NUM * sizeof(gpd_t), host->dma.gpd, host->dma.gpd_addr); ++ dma_free_coherent(NULL, MAX_BD_NUM * sizeof(bd_t), host->dma.bd, host->dma.bd_addr); ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ if (mem) ++ release_mem_region(mem->start, mem->end - mem->start + 1); ++ ++ mmc_free_host(host->mmc); ++ ++ return 0; ++} ++ ++static const struct of_device_id mt7620a_sdhci_match[] = { ++ { .compatible = "ralink,mt7620a-sdhci" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rt288x_wdt_match); ++ ++/* Fix me: Power Flow */ ++static struct platform_driver mt_msdc_driver = { ++ .probe = msdc_drv_probe, ++ .remove = msdc_drv_remove, ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = mt7620a_sdhci_match, ++ ++ }, ++}; ++ ++static int __init mt_msdc_init(void) ++{ ++ int ret; ++/* +++ chhung */ ++ unsigned int reg; ++ ++ mtk_sd_device.dev.platform_data = &msdc0_hw; ++ printk("MTK MSDC device init.\n"); ++ reg = sdr_read32((__iomem void *) 0xb0000060) & ~(0x3<<18); ++ reg |= 0x1 << 18; ++ sdr_write32((__iomem void *) 0xb0000060, reg); ++/* end of +++ */ ++ ret = platform_driver_register(&mt_msdc_driver); ++ if (ret) { ++ printk(KERN_ERR DRV_NAME ": Can't register driver"); ++ return ret; ++ } ++ printk(KERN_INFO DRV_NAME ": MediaTek MT6575 MSDC Driver\n"); ++ ++ //msdc_debug_proc_init(); ++ return 0; ++} ++ ++static void __exit mt_msdc_exit(void) ++{ ++ platform_driver_unregister(&mt_msdc_driver); ++} ++ ++module_init(mt_msdc_init); ++module_exit(mt_msdc_exit); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MediaTek MT6575 SD/MMC Card Driver"); ++MODULE_AUTHOR("Infinity Chen <infinity.chen@mediatek.com>"); ++ ++EXPORT_SYMBOL(msdc_6575_host); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0077-clocksource-add-common-of_clksrc_init-function.patch b/target/linux/ramips/patches-3.8/0077-clocksource-add-common-of_clksrc_init-function.patch new file mode 100644 index 0000000..62f043a --- /dev/null +++ b/target/linux/ramips/patches-3.8/0077-clocksource-add-common-of_clksrc_init-function.patch @@ -0,0 +1,132 @@ +From 517d8e6ba345620c6704ec3db5b23c56fde06392 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 20 Jun 2013 19:16:03 +0200 +Subject: [PATCH 77/79] clocksource: add common of_clksrc_init() function + +It is desirable to move all clocksource drivers to drivers/clocksource, +yet each requires its own initialization function. We'd rather not +pollute <linux/> with a header for each function. Instead, create a +single of_clksrc_init() function which will determine which clocksource +driver to initialize based on device tree. + +Based on a similar patch for drivers/irqchip by Thomas Petazzoni. + +Signed-off-by: Stephen Warren <swarren@nvidia.com> +--- + drivers/clocksource/Kconfig | 3 +++ + drivers/clocksource/Makefile | 1 + + drivers/clocksource/clksrc-of.c | 35 +++++++++++++++++++++++++++++++++++ + include/asm-generic/vmlinux.lds.h | 9 +++++++++ + include/linux/clocksource.h | 9 +++++++++ + 5 files changed, 57 insertions(+) + create mode 100644 drivers/clocksource/clksrc-of.c + +diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig +index 7fdcbd3..a32b7a9 100644 +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -1,3 +1,6 @@ ++config CLKSRC_OF ++ bool ++ + config CLKSRC_I8253 + bool + +diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile +index f93453d..a33f792 100644 +--- a/drivers/clocksource/Makefile ++++ b/drivers/clocksource/Makefile +@@ -1,3 +1,4 @@ ++obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o + obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o + obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o + obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o +diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c +new file mode 100644 +index 0000000..bdabdaa +--- /dev/null ++++ b/drivers/clocksource/clksrc-of.c +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <linux/init.h> ++#include <linux/of.h> ++ ++extern struct of_device_id __clksrc_of_table[]; ++ ++static const struct of_device_id __clksrc_of_table_sentinel ++ __used __section(__clksrc_of_table_end); ++ ++void __init clocksource_of_init(void) ++{ ++ struct device_node *np; ++ const struct of_device_id *match; ++ void (*init_func)(void); ++ ++ for_each_matching_node_and_match(np, __clksrc_of_table, &match) { ++ init_func = match->data; ++ init_func(); ++ } ++} +diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h +index d1ea7ce..1e744c5 100644 +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -149,6 +149,14 @@ + #define TRACE_SYSCALLS() + #endif + ++#ifdef CONFIG_CLKSRC_OF ++#define CLKSRC_OF_TABLES() . = ALIGN(8); \ ++ VMLINUX_SYMBOL(__clksrc_of_table) = .; \ ++ *(__clksrc_of_table) \ ++ *(__clksrc_of_table_end) ++#else ++#define CLKSRC_OF_TABLES() ++#endif + + #define KERNEL_DTB() \ + STRUCT_ALIGN(); \ +@@ -493,6 +501,7 @@ + DEV_DISCARD(init.rodata) \ + CPU_DISCARD(init.rodata) \ + MEM_DISCARD(init.rodata) \ ++ CLKSRC_OF_TABLES() \ + KERNEL_DTB() + + #define INIT_TEXT \ +diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h +index 4dceaf8..7944f14 100644 +--- a/include/linux/clocksource.h ++++ b/include/linux/clocksource.h +@@ -332,4 +332,13 @@ extern int clocksource_mmio_init(void __iomem *, const char *, + + extern int clocksource_i8253_init(void); + ++#ifdef CONFIG_CLKSRC_OF ++extern void clocksource_of_init(void); ++ ++#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ ++ static const struct of_device_id __clksrc_of_table_##name \ ++ __used __section(__clksrc_of_table) \ ++ = { .compatible = compat, .data = fn }; ++#endif ++ + #endif /* _LINUX_CLOCKSOURCE_H */ +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0078-clocksource-make-clocksource_of_init-pass-a-device_n.patch b/target/linux/ramips/patches-3.8/0078-clocksource-make-clocksource_of_init-pass-a-device_n.patch new file mode 100644 index 0000000..218dfc3 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0078-clocksource-make-clocksource_of_init-pass-a-device_n.patch @@ -0,0 +1,36 @@ +From 0e00abf87d50e80b1ce5bda65a4d89adc530ba10 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 23 May 2013 16:58:12 +0200 +Subject: [PATCH 78/79] clocksource: make clocksource_of_init() pass a + device_node pointer + +If we look at the clocksources that are OF enabled we will notice, that they +all do a of_find_matching_node() when being called. This patch changes +clocksource_of_init() to always pass the struct device_node pointer to the +init function. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + drivers/clocksource/clksrc-of.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c +index bdabdaa..3ef11fb 100644 +--- a/drivers/clocksource/clksrc-of.c ++++ b/drivers/clocksource/clksrc-of.c +@@ -26,10 +26,10 @@ void __init clocksource_of_init(void) + { + struct device_node *np; + const struct of_device_id *match; +- void (*init_func)(void); ++ void (*init_func)(struct device_node *); + + for_each_matching_node_and_match(np, __clksrc_of_table, &match) { + init_func = match->data; +- init_func(); ++ init_func(np); + } + } +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0079-clocksource-MIPS-ralink-add-support-for-systick-time.patch b/target/linux/ramips/patches-3.8/0079-clocksource-MIPS-ralink-add-support-for-systick-time.patch new file mode 100644 index 0000000..32c96ec --- /dev/null +++ b/target/linux/ramips/patches-3.8/0079-clocksource-MIPS-ralink-add-support-for-systick-time.patch @@ -0,0 +1,282 @@ +From 4f3ae2a7ee1b1c9b9cab287c828f2ed7b1858495 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 20 Jun 2013 19:21:52 +0200 +Subject: [PATCH 79/79] clocksource: MIPS: ralink: add support for systick + timer found on newer ralink SoC + +Signed-off-by: John Crispin <blogic@openwrt.org +--- + arch/mips/pci/Makefile.rej | 10 +++ + arch/mips/ralink/Kconfig | 2 + + arch/mips/ralink/Kconfig.rej | 10 +++ + arch/mips/ralink/clk.c | 1 + + drivers/clocksource/Kconfig | 6 ++ + drivers/clocksource/Makefile | 1 + + drivers/clocksource/cevt-rt3352.c | 162 +++++++++++++++++++++++++++++++++++++ + 7 files changed, 192 insertions(+) + create mode 100644 arch/mips/pci/Makefile.rej + create mode 100644 arch/mips/ralink/Kconfig.rej + create mode 100644 drivers/clocksource/cevt-rt3352.c + +diff --git a/arch/mips/pci/Makefile.rej b/arch/mips/pci/Makefile.rej +new file mode 100644 +index 0000000..c5761e8 +--- /dev/null ++++ b/arch/mips/pci/Makefile.rej +@@ -0,0 +1,10 @@ ++--- arch/mips/pci/Makefile +++++ arch/mips/pci/Makefile ++@@ -43,6 +43,7 @@ ++ obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o ++ obj-$(CONFIG_SOC_RT2880) += pci-rt2880.o ++ obj-$(CONFIG_SOC_RT3883) += pci-rt3883.o +++obj-$(CONFIG_SOC_MT7620) += pci-mt7620a.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/ralink/Kconfig b/arch/mips/ralink/Kconfig +index f89fdf8..c8d5b6c 100644 +--- a/arch/mips/ralink/Kconfig ++++ b/arch/mips/ralink/Kconfig +@@ -15,6 +15,7 @@ choice + select USB_ARCH_HAS_HCD + select USB_ARCH_HAS_OHCI + select USB_ARCH_HAS_EHCI ++ select CLKEVT_RT3352 + + config SOC_RT3883 + bool "RT3883" +@@ -24,6 +25,7 @@ choice + + config SOC_MT7620 + bool "MT7620" ++ select CLKEVT_RT3352 + select HW_HAS_PCI + + endchoice +diff --git a/arch/mips/ralink/Kconfig.rej b/arch/mips/ralink/Kconfig.rej +new file mode 100644 +index 0000000..d3a804f +--- /dev/null ++++ b/arch/mips/ralink/Kconfig.rej +@@ -0,0 +1,10 @@ ++--- arch/mips/ralink/Kconfig +++++ arch/mips/ralink/Kconfig ++@@ -23,6 +24,7 @@ ++ ++ config SOC_MT7620 ++ bool "MT7620" +++ select CLKEVT_RT3352 ++ ++ endchoice ++ +diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c +index 8dfa22f..bba0cdf 100644 +--- a/arch/mips/ralink/clk.c ++++ b/arch/mips/ralink/clk.c +@@ -69,4 +69,5 @@ void __init plat_time_init(void) + pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); + mips_hpt_frequency = clk_get_rate(clk) / 2; + clk_put(clk); ++ clocksource_of_init(); + } +diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig +index a32b7a9..90bed1a 100644 +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -7,6 +7,12 @@ config CLKSRC_I8253 + config CLKEVT_I8253 + bool + ++config CLKEVT_RT3352 ++ bool ++ depends on MIPS && RALINK ++ select CLKSRC_OF ++ select CLKSRC_MMIO ++ + config I8253_LOCK + bool + +diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile +index a33f792..5031f82 100644 +--- a/drivers/clocksource/Makefile ++++ b/drivers/clocksource/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o + obj-$(CONFIG_EM_TIMER_STI) += em_sti.o + obj-$(CONFIG_CLKBLD_I8253) += i8253.o + obj-$(CONFIG_CLKSRC_MMIO) += mmio.o ++obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o + obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o + obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o + obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o +diff --git a/drivers/clocksource/cevt-rt3352.c b/drivers/clocksource/cevt-rt3352.c +new file mode 100644 +index 0000000..bd50edd +--- /dev/null ++++ b/drivers/clocksource/cevt-rt3352.c +@@ -0,0 +1,162 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2013 by John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/clockchips.h> ++#include <linux/clocksource.h> ++#include <linux/interrupt.h> ++#include <linux/reset.h> ++#include <linux/init.h> ++#include <linux/of.h> ++#include <linux/of_irq.h> ++#include <linux/of_address.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> ++#include <asm/time.h> ++ ++#define SYSTICK_FREQ (50 * 1000) ++ ++#define SYSTICK_CONFIG 0x00 ++#define SYSTICK_COMPARE 0x04 ++#define SYSTICK_COUNT 0x08 ++ ++/* route systick irq to mips irq 7 instead of the r4k-timer */ ++#define CFG_EXT_STK_EN 0x2 ++/* enable the counter */ ++#define CFG_CNT_EN 0x1 ++ ++struct systick_device { ++ void __iomem *membase; ++ struct clock_event_device dev; ++ int irq_requested; ++ int freq_scale; ++}; ++ ++static void systick_set_clock_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt); ++ ++static int systick_next_event(unsigned long delta, ++ struct clock_event_device *evt) ++{ ++ struct systick_device *sdev = container_of(evt, struct systick_device, dev); ++ u32 count; ++ ++ count = ioread32(sdev->membase + SYSTICK_COUNT); ++ count = (count + delta) % SYSTICK_FREQ; ++ iowrite32(count + delta, sdev->membase + SYSTICK_COMPARE); ++ ++ return 0; ++} ++ ++static void systick_event_handler(struct clock_event_device *dev) ++{ ++ /* noting to do here */ ++} ++ ++static irqreturn_t systick_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *dev = (struct clock_event_device *) dev_id; ++ ++ dev->event_handler(dev); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct systick_device systick = { ++ .dev = { ++ /* cevt-r4k uses 300, make sure systick gets used if available */ ++ .rating = 310, ++ .features = CLOCK_EVT_FEAT_ONESHOT, ++ .set_next_event = systick_next_event, ++ .set_mode = systick_set_clock_mode, ++ .event_handler = systick_event_handler, ++ }, ++}; ++ ++static struct irqaction systick_irqaction = { ++ .handler = systick_interrupt, ++ .flags = IRQF_PERCPU | IRQF_TIMER, ++ .dev_id = &systick.dev, ++}; ++ ++/* ugly hack */ ++#ifdef CONFIG_SOC_MT7620 ++ ++#define CLK_LUT_CFG 0x40 ++#define SLEEP_EN BIT(31) ++ ++static inline void mt7620_freq_scaling(struct systick_device *sdev, int status) ++{ ++ if (sdev->freq_scale == status) ++ return; ++ ++ sdev->freq_scale = status; ++ ++ pr_info("%s: %s autosleep mode\n", systick.dev.name, (status) ? ("enable") : ("disable")); ++ if (status) ++ rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG); ++ else ++ rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG); ++} ++#else ++static inline void mt7620_freq_scaling(struct systick_device *sdev, int status) {} ++#endif ++ ++static void systick_set_clock_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ struct systick_device *sdev = container_of(evt, struct systick_device, dev); ++ ++ switch (mode) { ++ case CLOCK_EVT_MODE_ONESHOT: ++ if (!sdev->irq_requested) ++ setup_irq(systick.dev.irq, &systick_irqaction); ++ mt7620_freq_scaling(sdev, 1); ++ sdev->irq_requested = 1; ++ iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, systick.membase + SYSTICK_CONFIG); ++ break; ++ ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ if (sdev->irq_requested) ++ free_irq(systick.dev.irq, &systick_irqaction); ++ mt7620_freq_scaling(sdev, 0); ++ sdev->irq_requested = 0; ++ iowrite32(0, systick.membase + SYSTICK_CONFIG); ++ break; ++ ++ default: ++ pr_err("%s: Unhandeled mips clock_mode\n", systick.dev.name); ++ break; ++ } ++} ++ ++static void __init ralink_systick_init(struct device_node *np) ++{ ++ systick.membase = of_iomap(np, 0); ++ if (!systick.membase) { ++ pr_err("%s: of_iomap failed", np->name); ++ return; ++ } ++ ++ clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, ++ SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up); ++ ++ systick_irqaction.name = np->name; ++ systick.dev.name = np->name; ++ clockevent_set_clock(&systick.dev, SYSTICK_FREQ); ++ systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev); ++ systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev); ++ systick.dev.irq = irq_of_parse_and_map(np, 0); ++ if (!systick.dev.irq) ++ panic("%s: request_irq failed", np->name); ++ ++ clockevents_register_device(&systick.dev); ++ ++ pr_info("%s: runing - mult: %d, shift: %d\n", np->name, systick.dev.mult, systick.dev.shift); ++} ++ ++CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0080-MIPS-add-ohci-ehci-support.patch b/target/linux/ramips/patches-3.8/0080-MIPS-add-ohci-ehci-support.patch new file mode 100644 index 0000000..0726ac8 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0080-MIPS-add-ohci-ehci-support.patch @@ -0,0 +1,227 @@ +From ec6f3aa022ef6e61f6ca80c6e30610d879654466 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 20 Jun 2013 23:33:05 +0200 +Subject: [PATCH] MIPS: add ohci/ehci support + +Signed-off-by: John Crsipin <blogic@openwrt.org> +--- + arch/mips/ralink/Kconfig | 2 ++ + drivers/usb/Makefile | 3 ++- + drivers/usb/host/ehci-platform.c | 43 ++++++++++++++++++++++++++++++++------ + drivers/usb/host/ohci-platform.c | 37 +++++++++++++++++++++++++++----- + 4 files changed, 73 insertions(+), 12 deletions(-) + +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index c8d5b6c..7cd1188 100644 +--- a/arch/mips/ralink/Kconfig ++++ b/arch/mips/ralink/Kconfig +@@ -27,6 +27,8 @@ choice + bool "MT7620" + select CLKEVT_RT3352 + select HW_HAS_PCI ++ select USB_ARCH_HAS_OHCI ++ select USB_ARCH_HAS_EHCI + + endchoice + +diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile +index f5ed3d7..41a4741 100644 +--- a/drivers/usb/Makefile ++++ b/drivers/usb/Makefile +@@ -12,6 +12,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/ + + obj-$(CONFIG_USB_MON) += mon/ + ++obj-$(CONFIG_USB_COMMON) += phy/ ++ + obj-$(CONFIG_PCI) += host/ + obj-$(CONFIG_USB_EHCI_HCD) += host/ + obj-$(CONFIG_USB_ISP116X_HCD) += host/ +@@ -46,7 +48,6 @@ obj-$(CONFIG_USB_MICROTEK) += image/ + obj-$(CONFIG_USB_SERIAL) += serial/ + + obj-$(CONFIG_USB) += misc/ +-obj-$(CONFIG_USB_COMMON) += phy/ + obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ + + obj-$(CONFIG_USB_ATM) += atm/ +diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c +index 58fa0c9..0050df7 100644 +--- a/drivers/usb/host/ehci-platform.c ++++ b/drivers/usb/host/ehci-platform.c +@@ -23,6 +23,10 @@ + #include <linux/io.h> + #include <linux/module.h> + #include <linux/platform_device.h> ++#include <linux/dma-mapping.h> ++#include <linux/of.h> ++#include <linux/usb/otg.h> ++#include <linux/usb/phy.h> + #include <linux/usb.h> + #include <linux/usb/hcd.h> + #include <linux/usb/ehci_pdriver.h> +@@ -61,22 +65,40 @@ static const struct ehci_driver_overrides platform_overrides __initdata = { + .reset = ehci_platform_reset, + }; + ++static struct usb_ehci_pdata ehci_platform_defaults; ++ + static int ehci_platform_probe(struct platform_device *dev) + { + struct usb_hcd *hcd; + struct resource *res_mem; +- struct usb_ehci_pdata *pdata = dev->dev.platform_data; ++ struct usb_ehci_pdata *pdata; + int irq; + int err = -ENOMEM; + +- if (!pdata) { +- WARN_ON(1); +- return -ENODEV; +- } +- + if (usb_disabled()) + return -ENODEV; + ++ /* ++ * use reasonable defaults so platforms don't have to provide these. ++ * with DT probing on ARM, none of these are set. ++ */ ++ if (!dev->dev.platform_data) ++ dev->dev.platform_data = &ehci_platform_defaults; ++ if (!dev->dev.dma_mask) ++ dev->dev.dma_mask = &dev->dev.coherent_dma_mask; ++ if (!dev->dev.coherent_dma_mask) ++ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); ++ ++ pdata = dev->dev.platform_data; ++ ++#ifdef CONFIG_USB_COMMON ++ hcd->phy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2); ++ if (!IS_ERR_OR_NULL(hcd->phy)) { ++ otg_set_host(hcd->phy->otg, ++ &hcd->self); ++ usb_phy_init(hcd->phy); ++ } ++#endif + irq = platform_get_irq(dev, 0); + if (irq < 0) { + dev_err(&dev->dev, "no irq provided"); +@@ -138,6 +160,9 @@ static int ehci_platform_remove(struct platform_device *dev) + if (pdata->power_off) + pdata->power_off(dev); + ++ if (pdata == &ehci_platform_defaults) ++ dev->dev.platform_data = NULL; ++ + return 0; + } + +@@ -182,6 +207,11 @@ static int ehci_platform_resume(struct device *dev) + #define ehci_platform_resume NULL + #endif /* CONFIG_PM */ + ++static const struct of_device_id ralink_ehci_ids[] = { ++ { .compatible = "ralink,rt3xxx-ehci", }, ++ {} ++}; ++ + static const struct platform_device_id ehci_platform_table[] = { + { "ehci-platform", 0 }, + { } +@@ -202,6 +232,7 @@ static struct platform_driver ehci_platform_driver = { + .owner = THIS_MODULE, + .name = "ehci-platform", + .pm = &ehci_platform_pm_ops, ++ .of_match_table = of_match_ptr(ralink_ehci_ids), + } + }; + +diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c +index 084503b..3a60f96 100644 +--- a/drivers/usb/host/ohci-platform.c ++++ b/drivers/usb/host/ohci-platform.c +@@ -15,6 +15,10 @@ + */ + #include <linux/platform_device.h> + #include <linux/usb/ohci_pdriver.h> ++#include <linux/dma-mapping.h> ++#include <linux/of.h> ++ ++static struct usb_ohci_pdata ohci_platform_defaults; + + static int ohci_platform_reset(struct usb_hcd *hcd) + { +@@ -87,14 +91,22 @@ static int ohci_platform_probe(struct platform_device *dev) + { + struct usb_hcd *hcd; + struct resource *res_mem; +- struct usb_ohci_pdata *pdata = dev->dev.platform_data; ++ struct usb_ohci_pdata *pdata; + int irq; + int err = -ENOMEM; + +- if (!pdata) { +- WARN_ON(1); +- return -ENODEV; +- } ++ /* ++ * use reasonable defaults so platforms don't have to provide these. ++ * with DT probing on ARM, none of these are set. ++ */ ++ if (!dev->dev.platform_data) ++ dev->dev.platform_data = &ohci_platform_defaults; ++ if (!dev->dev.dma_mask) ++ dev->dev.dma_mask = &dev->dev.coherent_dma_mask; ++ if (!dev->dev.coherent_dma_mask) ++ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); ++ ++ pdata = dev->dev.platform_data; + + if (usb_disabled()) + return -ENODEV; +@@ -124,6 +136,12 @@ static int ohci_platform_probe(struct platform_device *dev) + goto err_power; + } + ++#ifdef CONFIG_USB_COMMON ++ hcd->phy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2); ++ if (!IS_ERR_OR_NULL(hcd->phy)) ++ usb_phy_init(hcd->phy); ++#endif ++ + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = resource_size(res_mem); + +@@ -161,6 +179,9 @@ static int ohci_platform_remove(struct platform_device *dev) + if (pdata->power_off) + pdata->power_off(dev); + ++ if (pdata == &ohci_platform_defaults) ++ dev->dev.platform_data = NULL; ++ + return 0; + } + +@@ -200,6 +221,11 @@ static int ohci_platform_resume(struct device *dev) + #define ohci_platform_resume NULL + #endif /* CONFIG_PM */ + ++static const struct of_device_id ralink_ohci_ids[] = { ++ { .compatible = "ralink,rt3xxx-ohci", }, ++ {} ++}; ++ + static const struct platform_device_id ohci_platform_table[] = { + { "ohci-platform", 0 }, + { } +@@ -220,5 +246,6 @@ static struct platform_driver ohci_platform_driver = { + .owner = THIS_MODULE, + .name = "ohci-platform", + .pm = &ohci_platform_pm_ops, ++ .of_match_table = of_match_ptr(ralink_ohci_ids), + } + }; +-- +1.7.10.4 + diff --git a/target/linux/ramips/patches-3.8/0136-NET-MIPS-add-ralink-SoC-ethernet-driver.patch b/target/linux/ramips/patches-3.8/0136-NET-MIPS-add-ralink-SoC-ethernet-driver.patch deleted file mode 100644 index 9bb9b5f..0000000 --- a/target/linux/ramips/patches-3.8/0136-NET-MIPS-add-ralink-SoC-ethernet-driver.patch +++ /dev/null @@ -1,3137 +0,0 @@ -From 34fc7d26c01ba594be347aefcc31f55b36c06a72 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Mon, 22 Apr 2013 23:20:03 +0200 -Subject: [PATCH 136/137] NET: MIPS: add ralink SoC ethernet driver - -Add support for Ralink FE and ESW. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - .../include/asm/mach-ralink/rt305x_esw_platform.h | 27 + - arch/mips/ralink/rt305x.c | 1 + - drivers/net/ethernet/Kconfig | 1 + - drivers/net/ethernet/Makefile | 1 + - drivers/net/ethernet/ramips/Kconfig | 18 + - drivers/net/ethernet/ramips/Makefile | 9 + - drivers/net/ethernet/ramips/ramips_debugfs.c | 127 ++ - drivers/net/ethernet/ramips/ramips_esw.c | 1221 +++++++++++++++++++ - drivers/net/ethernet/ramips/ramips_eth.h | 375 ++++++ - drivers/net/ethernet/ramips/ramips_main.c | 1281 ++++++++++++++++++++ - 10 files changed, 3061 insertions(+) - create mode 100644 arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h - create mode 100644 drivers/net/ethernet/ramips/Kconfig - create mode 100644 drivers/net/ethernet/ramips/Makefile - create mode 100644 drivers/net/ethernet/ramips/ramips_debugfs.c - create mode 100644 drivers/net/ethernet/ramips/ramips_esw.c - create mode 100644 drivers/net/ethernet/ramips/ramips_eth.h - create mode 100644 drivers/net/ethernet/ramips/ramips_main.c - ---- /dev/null -+++ b/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h -@@ -0,0 +1,27 @@ -+/* -+ * Ralink RT305x SoC platform device registration -+ * -+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation. -+ */ -+ -+#ifndef _RT305X_ESW_PLATFORM_H -+#define _RT305X_ESW_PLATFORM_H -+ -+enum { -+ RT305X_ESW_VLAN_CONFIG_NONE = 0, -+ RT305X_ESW_VLAN_CONFIG_LLLLW, -+ RT305X_ESW_VLAN_CONFIG_WLLLL, -+}; -+ -+struct rt305x_esw_platform_data -+{ -+ u8 vlan_config; -+ u32 reg_initval_fct2; -+ u32 reg_initval_fpa2; -+}; -+ -+#endif /* _RT305X_ESW_PLATFORM_H */ ---- a/arch/mips/ralink/rt305x.c -+++ b/arch/mips/ralink/rt305x.c -@@ -221,6 +221,7 @@ void __init ralink_clk_init(void) - } - - ralink_clk_add("cpu", cpu_rate); -+ ralink_clk_add("sys", sys_rate); - ralink_clk_add("10000b00.spi", sys_rate); - ralink_clk_add("10000100.timer", wdt_rate); - ralink_clk_add("10000120.watchdog", wdt_rate); ---- a/drivers/net/ethernet/Kconfig -+++ b/drivers/net/ethernet/Kconfig -@@ -136,6 +136,7 @@ source "drivers/net/ethernet/packetengin - source "drivers/net/ethernet/pasemi/Kconfig" - source "drivers/net/ethernet/qlogic/Kconfig" - source "drivers/net/ethernet/racal/Kconfig" -+source "drivers/net/ethernet/ramips/Kconfig" - source "drivers/net/ethernet/realtek/Kconfig" - source "drivers/net/ethernet/renesas/Kconfig" - source "drivers/net/ethernet/rdc/Kconfig" ---- a/drivers/net/ethernet/Makefile -+++ b/drivers/net/ethernet/Makefile -@@ -54,6 +54,7 @@ obj-$(CONFIG_NET_PACKET_ENGINE) += packe - obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/ - obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/ - obj-$(CONFIG_NET_VENDOR_RACAL) += racal/ -+obj-$(CONFIG_NET_RAMIPS) += ramips/ - obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/ - obj-$(CONFIG_SH_ETH) += renesas/ - obj-$(CONFIG_NET_VENDOR_RDC) += rdc/ ---- /dev/null -+++ b/drivers/net/ethernet/ramips/Kconfig -@@ -0,0 +1,18 @@ -+config NET_RAMIPS -+ tristate "Ralink RT288X/RT3X5X/RT3662/RT3883 ethernet driver" -+ depends on RALINK -+ select PHYLIB if (SOC_RT288X || SOC_RT3883) -+ select SWCONFIG if SOC_RT305X -+ help -+ This driver supports the etehrnet mac inside the ralink wisocs -+ -+if NET_RAMIPS -+ -+config NET_RAMIPS_DEBUG -+ bool "Enable debug messages in the Ralink ethernet driver" -+ -+config NET_RAMIPS_DEBUG_FS -+ bool "Enable debugfs support for the Ralink ethernet driver" -+ depends on DEBUG_FS -+ -+endif ---- /dev/null -+++ b/drivers/net/ethernet/ramips/Makefile -@@ -0,0 +1,9 @@ -+# -+# Makefile for the Ramips SoCs built-in ethernet macs -+# -+ -+ramips-y += ramips_main.o -+ -+ramips-$(CONFIG_NET_RAMIPS_DEBUG_FS) += ramips_debugfs.o -+ -+obj-$(CONFIG_NET_RAMIPS) += ramips.o ---- /dev/null -+++ b/drivers/net/ethernet/ramips/ramips_debugfs.c -@@ -0,0 +1,127 @@ -+/* -+ * Ralink SoC ethernet driver debugfs code -+ * -+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@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/debugfs.h> -+#include <linux/module.h> -+#include <linux/phy.h> -+ -+#include "ramips_eth.h" -+ -+static struct dentry *raeth_debugfs_root; -+ -+static int raeth_debugfs_generic_open(struct inode *inode, struct file *file) -+{ -+ file->private_data = inode->i_private; -+ return 0; -+} -+ -+void raeth_debugfs_update_int_stats(struct raeth_priv *re, u32 status) -+{ -+ re->debug.int_stats.total += !!status; -+ -+ re->debug.int_stats.rx_delayed += !!(status & RAMIPS_RX_DLY_INT); -+ re->debug.int_stats.rx_done0 += !!(status & RAMIPS_RX_DONE_INT0); -+ re->debug.int_stats.rx_coherent += !!(status & RAMIPS_RX_COHERENT); -+ -+ re->debug.int_stats.tx_delayed += !!(status & RAMIPS_TX_DLY_INT); -+ re->debug.int_stats.tx_done0 += !!(status & RAMIPS_TX_DONE_INT0); -+ re->debug.int_stats.tx_done1 += !!(status & RAMIPS_TX_DONE_INT1); -+ re->debug.int_stats.tx_done2 += !!(status & RAMIPS_TX_DONE_INT2); -+ re->debug.int_stats.tx_done3 += !!(status & RAMIPS_TX_DONE_INT3); -+ re->debug.int_stats.tx_coherent += !!(status & RAMIPS_TX_COHERENT); -+ -+ re->debug.int_stats.pse_fq_empty += !!(status & RAMIPS_PSE_FQ_EMPTY); -+ re->debug.int_stats.pse_p0_fc += !!(status & RAMIPS_PSE_P0_FC); -+ re->debug.int_stats.pse_p1_fc += !!(status & RAMIPS_PSE_P1_FC); -+ re->debug.int_stats.pse_p2_fc += !!(status & RAMIPS_PSE_P2_FC); -+ re->debug.int_stats.pse_buf_drop += !!(status & RAMIPS_PSE_BUF_DROP); -+} -+ -+static ssize_t read_file_int_stats(struct file *file, char __user *user_buf, -+ size_t count, loff_t *ppos) -+{ -+#define PR_INT_STAT(_label, _field) \ -+ len += snprintf(buf + len, sizeof(buf) - len, \ -+ "%-18s: %10lu\n", _label, re->debug.int_stats._field); -+ -+ struct raeth_priv *re = file->private_data; -+ char buf[512]; -+ unsigned int len = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&re->page_lock, flags); -+ -+ PR_INT_STAT("RX Delayed", rx_delayed); -+ PR_INT_STAT("RX Done 0", rx_done0); -+ PR_INT_STAT("RX Coherent", rx_coherent); -+ -+ PR_INT_STAT("TX Delayed", tx_delayed); -+ PR_INT_STAT("TX Done 0", tx_done0); -+ PR_INT_STAT("TX Done 1", tx_done1); -+ PR_INT_STAT("TX Done 2", tx_done2); -+ PR_INT_STAT("TX Done 3", tx_done3); -+ PR_INT_STAT("TX Coherent", tx_coherent); -+ -+ PR_INT_STAT("PSE FQ empty", pse_fq_empty); -+ PR_INT_STAT("CDMA Flow control", pse_p0_fc); -+ PR_INT_STAT("GDMA1 Flow control", pse_p1_fc); -+ PR_INT_STAT("GDMA2 Flow control", pse_p2_fc); -+ PR_INT_STAT("PSE discard", pse_buf_drop); -+ -+ len += snprintf(buf + len, sizeof(buf) - len, "\n"); -+ PR_INT_STAT("Total", total); -+ -+ spin_unlock_irqrestore(&re->page_lock, flags); -+ -+ return simple_read_from_buffer(user_buf, count, ppos, buf, len); -+#undef PR_INT_STAT -+} -+ -+static const struct file_operations raeth_fops_int_stats = { -+ .open = raeth_debugfs_generic_open, -+ .read = read_file_int_stats, -+ .owner = THIS_MODULE -+}; -+ -+void raeth_debugfs_exit(struct raeth_priv *re) -+{ -+ debugfs_remove_recursive(re->debug.debugfs_dir); -+} -+ -+int raeth_debugfs_init(struct raeth_priv *re) -+{ -+ re->debug.debugfs_dir = debugfs_create_dir(re->netdev->name, -+ raeth_debugfs_root); -+ if (!re->debug.debugfs_dir) -+ return -ENOMEM; -+ -+ debugfs_create_file("int_stats", S_IRUGO, re->debug.debugfs_dir, -+ re, &raeth_fops_int_stats); -+ -+ return 0; -+} -+ -+int raeth_debugfs_root_init(void) -+{ -+ if (raeth_debugfs_root) -+ return -EBUSY; -+ -+ raeth_debugfs_root = debugfs_create_dir("raeth", NULL); -+ if (!raeth_debugfs_root) -+ return -ENOENT; -+ -+ return 0; -+} -+ -+void raeth_debugfs_root_exit(void) -+{ -+ debugfs_remove(raeth_debugfs_root); -+ raeth_debugfs_root = NULL; -+} ---- /dev/null -+++ b/drivers/net/ethernet/ramips/ramips_esw.c -@@ -0,0 +1,1221 @@ -+#include <linux/ioport.h> -+#include <linux/switch.h> -+#include <linux/mii.h> -+ -+#include <ralink_regs.h> -+#include <rt305x.h> -+#include <rt305x_esw_platform.h> -+ -+/* -+ * HW limitations for this switch: -+ * - No large frame support (PKT_MAX_LEN at most 1536) -+ * - Can't have untagged vlan and tagged vlan on one port at the same time, -+ * though this might be possible using the undocumented PPE. -+ */ -+ -+#define RT305X_ESW_REG_ISR 0x00 -+#define RT305X_ESW_REG_IMR 0x04 -+#define RT305X_ESW_REG_FCT0 0x08 -+#define RT305X_ESW_REG_PFC1 0x14 -+#define RT305X_ESW_REG_ATS 0x24 -+#define RT305X_ESW_REG_ATS0 0x28 -+#define RT305X_ESW_REG_ATS1 0x2c -+#define RT305X_ESW_REG_ATS2 0x30 -+#define RT305X_ESW_REG_PVIDC(_n) (0x40 + 4 * (_n)) -+#define RT305X_ESW_REG_VLANI(_n) (0x50 + 4 * (_n)) -+#define RT305X_ESW_REG_VMSC(_n) (0x70 + 4 * (_n)) -+#define RT305X_ESW_REG_POA 0x80 -+#define RT305X_ESW_REG_FPA 0x84 -+#define RT305X_ESW_REG_SOCPC 0x8c -+#define RT305X_ESW_REG_POC0 0x90 -+#define RT305X_ESW_REG_POC1 0x94 -+#define RT305X_ESW_REG_POC2 0x98 -+#define RT305X_ESW_REG_SGC 0x9c -+#define RT305X_ESW_REG_STRT 0xa0 -+#define RT305X_ESW_REG_PCR0 0xc0 -+#define RT305X_ESW_REG_PCR1 0xc4 -+#define RT305X_ESW_REG_FPA2 0xc8 -+#define RT305X_ESW_REG_FCT2 0xcc -+#define RT305X_ESW_REG_SGC2 0xe4 -+#define RT305X_ESW_REG_P0LED 0xa4 -+#define RT305X_ESW_REG_P1LED 0xa8 -+#define RT305X_ESW_REG_P2LED 0xac -+#define RT305X_ESW_REG_P3LED 0xb0 -+#define RT305X_ESW_REG_P4LED 0xb4 -+#define RT305X_ESW_REG_P0PC 0xe8 -+#define RT305X_ESW_REG_P1PC 0xec -+#define RT305X_ESW_REG_P2PC 0xf0 -+#define RT305X_ESW_REG_P3PC 0xf4 -+#define RT305X_ESW_REG_P4PC 0xf8 -+#define RT305X_ESW_REG_P5PC 0xfc -+ -+#define RT305X_ESW_LED_LINK 0 -+#define RT305X_ESW_LED_100M 1 -+#define RT305X_ESW_LED_DUPLEX 2 -+#define RT305X_ESW_LED_ACTIVITY 3 -+#define RT305X_ESW_LED_COLLISION 4 -+#define RT305X_ESW_LED_LINKACT 5 -+#define RT305X_ESW_LED_DUPLCOLL 6 -+#define RT305X_ESW_LED_10MACT 7 -+#define RT305X_ESW_LED_100MACT 8 -+/* Additional led states not in datasheet: */ -+#define RT305X_ESW_LED_BLINK 10 -+#define RT305X_ESW_LED_ON 12 -+ -+#define RT305X_ESW_LINK_S 25 -+#define RT305X_ESW_DUPLEX_S 9 -+#define RT305X_ESW_SPD_S 0 -+ -+#define RT305X_ESW_PCR0_WT_NWAY_DATA_S 16 -+#define RT305X_ESW_PCR0_WT_PHY_CMD BIT(13) -+#define RT305X_ESW_PCR0_CPU_PHY_REG_S 8 -+ -+#define RT305X_ESW_PCR1_WT_DONE BIT(0) -+ -+#define RT305X_ESW_ATS_TIMEOUT (5 * HZ) -+#define RT305X_ESW_PHY_TIMEOUT (5 * HZ) -+ -+#define RT305X_ESW_PVIDC_PVID_M 0xfff -+#define RT305X_ESW_PVIDC_PVID_S 12 -+ -+#define RT305X_ESW_VLANI_VID_M 0xfff -+#define RT305X_ESW_VLANI_VID_S 12 -+ -+#define RT305X_ESW_VMSC_MSC_M 0xff -+#define RT305X_ESW_VMSC_MSC_S 8 -+ -+#define RT305X_ESW_SOCPC_DISUN2CPU_S 0 -+#define RT305X_ESW_SOCPC_DISMC2CPU_S 8 -+#define RT305X_ESW_SOCPC_DISBC2CPU_S 16 -+#define RT305X_ESW_SOCPC_CRC_PADDING BIT(25) -+ -+#define RT305X_ESW_POC0_EN_BP_S 0 -+#define RT305X_ESW_POC0_EN_FC_S 8 -+#define RT305X_ESW_POC0_DIS_RMC2CPU_S 16 -+#define RT305X_ESW_POC0_DIS_PORT_M 0x7f -+#define RT305X_ESW_POC0_DIS_PORT_S 23 -+ -+#define RT305X_ESW_POC2_UNTAG_EN_M 0xff -+#define RT305X_ESW_POC2_UNTAG_EN_S 0 -+#define RT305X_ESW_POC2_ENAGING_S 8 -+#define RT305X_ESW_POC2_DIS_UC_PAUSE_S 16 -+ -+#define RT305X_ESW_SGC2_DOUBLE_TAG_M 0x7f -+#define RT305X_ESW_SGC2_DOUBLE_TAG_S 0 -+#define RT305X_ESW_SGC2_LAN_PMAP_M 0x3f -+#define RT305X_ESW_SGC2_LAN_PMAP_S 24 -+ -+#define RT305X_ESW_PFC1_EN_VLAN_M 0xff -+#define RT305X_ESW_PFC1_EN_VLAN_S 16 -+#define RT305X_ESW_PFC1_EN_TOS_S 24 -+ -+#define RT305X_ESW_VLAN_NONE 0xfff -+ -+#define RT305X_ESW_POA_LINK_MASK 0x1f -+#define RT305X_ESW_POA_LINK_SHIFT 25 -+ -+#define RT305X_ESW_PORT_ST_CHG BIT(26) -+#define RT305X_ESW_PORT0 0 -+#define RT305X_ESW_PORT1 1 -+#define RT305X_ESW_PORT2 2 -+#define RT305X_ESW_PORT3 3 -+#define RT305X_ESW_PORT4 4 -+#define RT305X_ESW_PORT5 5 -+#define RT305X_ESW_PORT6 6 -+ -+#define RT305X_ESW_PORTS_NONE 0 -+ -+#define RT305X_ESW_PMAP_LLLLLL 0x3f -+#define RT305X_ESW_PMAP_LLLLWL 0x2f -+#define RT305X_ESW_PMAP_WLLLLL 0x3e -+ -+#define RT305X_ESW_PORTS_INTERNAL \ -+ (BIT(RT305X_ESW_PORT0) | BIT(RT305X_ESW_PORT1) | \ -+ BIT(RT305X_ESW_PORT2) | BIT(RT305X_ESW_PORT3) | \ -+ BIT(RT305X_ESW_PORT4)) -+ -+#define RT305X_ESW_PORTS_NOCPU \ -+ (RT305X_ESW_PORTS_INTERNAL | BIT(RT305X_ESW_PORT5)) -+ -+#define RT305X_ESW_PORTS_CPU BIT(RT305X_ESW_PORT6) -+ -+#define RT305X_ESW_PORTS_ALL \ -+ (RT305X_ESW_PORTS_NOCPU | RT305X_ESW_PORTS_CPU) -+ -+#define RT305X_ESW_NUM_VLANS 16 -+#define RT305X_ESW_NUM_VIDS 4096 -+#define RT305X_ESW_NUM_PORTS 7 -+#define RT305X_ESW_NUM_LANWAN 6 -+#define RT305X_ESW_NUM_LEDS 5 -+ -+enum { -+ /* Global attributes. */ -+ RT305X_ESW_ATTR_ENABLE_VLAN, -+ RT305X_ESW_ATTR_ALT_VLAN_DISABLE, -+ /* Port attributes. */ -+ RT305X_ESW_ATTR_PORT_DISABLE, -+ RT305X_ESW_ATTR_PORT_DOUBLETAG, -+ RT305X_ESW_ATTR_PORT_UNTAG, -+ RT305X_ESW_ATTR_PORT_LED, -+ RT305X_ESW_ATTR_PORT_LAN, -+ RT305X_ESW_ATTR_PORT_RECV_BAD, -+ RT305X_ESW_ATTR_PORT_RECV_GOOD, -+}; -+ -+struct rt305x_esw_port { -+ bool disable; -+ bool doubletag; -+ bool untag; -+ u8 led; -+ u16 pvid; -+}; -+ -+struct rt305x_esw_vlan { -+ u8 ports; -+ u16 vid; -+}; -+ -+struct rt305x_esw { -+ struct device *dev; -+ void __iomem *base; -+ int irq; -+ const struct rt305x_esw_platform_data *pdata; -+ /* Protects against concurrent register rmw operations. */ -+ spinlock_t reg_rw_lock; -+ -+ unsigned char port_map; -+ unsigned int reg_initval_fct2; -+ unsigned int reg_initval_fpa2; -+ -+ -+ struct switch_dev swdev; -+ bool global_vlan_enable; -+ bool alt_vlan_disable; -+ struct rt305x_esw_vlan vlans[RT305X_ESW_NUM_VLANS]; -+ struct rt305x_esw_port ports[RT305X_ESW_NUM_PORTS]; -+ -+}; -+ -+static inline void -+rt305x_esw_wr(struct rt305x_esw *esw, u32 val, unsigned reg) -+{ -+ __raw_writel(val, esw->base + reg); -+} -+ -+static inline u32 -+rt305x_esw_rr(struct rt305x_esw *esw, unsigned reg) -+{ -+ return __raw_readl(esw->base + reg); -+} -+ -+static inline void -+rt305x_esw_rmw_raw(struct rt305x_esw *esw, unsigned reg, unsigned long mask, -+ unsigned long val) -+{ -+ unsigned long t; -+ -+ t = __raw_readl(esw->base + reg) & ~mask; -+ __raw_writel(t | val, esw->base + reg); -+} -+ -+static void -+rt305x_esw_rmw(struct rt305x_esw *esw, unsigned reg, unsigned long mask, -+ unsigned long val) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&esw->reg_rw_lock, flags); -+ rt305x_esw_rmw_raw(esw, reg, mask, val); -+ spin_unlock_irqrestore(&esw->reg_rw_lock, flags); -+} -+ -+static u32 -+rt305x_mii_write(struct rt305x_esw *esw, u32 phy_addr, u32 phy_register, -+ u32 write_data) -+{ -+ unsigned long t_start = jiffies; -+ int ret = 0; -+ -+ while (1) { -+ if (!(rt305x_esw_rr(esw, RT305X_ESW_REG_PCR1) & -+ RT305X_ESW_PCR1_WT_DONE)) -+ break; -+ if (time_after(jiffies, t_start + RT305X_ESW_PHY_TIMEOUT)) { -+ ret = 1; -+ goto out; -+ } -+ } -+ -+ write_data &= 0xffff; -+ rt305x_esw_wr(esw, -+ (write_data << RT305X_ESW_PCR0_WT_NWAY_DATA_S) | -+ (phy_register << RT305X_ESW_PCR0_CPU_PHY_REG_S) | -+ (phy_addr) | RT305X_ESW_PCR0_WT_PHY_CMD, -+ RT305X_ESW_REG_PCR0); -+ -+ t_start = jiffies; -+ while (1) { -+ if (rt305x_esw_rr(esw, RT305X_ESW_REG_PCR1) & -+ RT305X_ESW_PCR1_WT_DONE) -+ break; -+ -+ if (time_after(jiffies, t_start + RT305X_ESW_PHY_TIMEOUT)) { -+ ret = 1; -+ break; -+ } -+ } -+out: -+ if (ret) -+ printk(KERN_ERR "ramips_eth: MDIO timeout\n"); -+ return ret; -+} -+ -+static unsigned -+rt305x_esw_get_vlan_id(struct rt305x_esw *esw, unsigned vlan) -+{ -+ unsigned s; -+ unsigned val; -+ -+ s = RT305X_ESW_VLANI_VID_S * (vlan % 2); -+ val = rt305x_esw_rr(esw, RT305X_ESW_REG_VLANI(vlan / 2)); -+ val = (val >> s) & RT305X_ESW_VLANI_VID_M; -+ -+ return val; -+} -+ -+static void -+rt305x_esw_set_vlan_id(struct rt305x_esw *esw, unsigned vlan, unsigned vid) -+{ -+ unsigned s; -+ -+ s = RT305X_ESW_VLANI_VID_S * (vlan % 2); -+ rt305x_esw_rmw(esw, -+ RT305X_ESW_REG_VLANI(vlan / 2), -+ RT305X_ESW_VLANI_VID_M << s, -+ (vid & RT305X_ESW_VLANI_VID_M) << s); -+} -+ -+static unsigned -+rt305x_esw_get_pvid(struct rt305x_esw *esw, unsigned port) -+{ -+ unsigned s, val; -+ -+ s = RT305X_ESW_PVIDC_PVID_S * (port % 2); -+ val = rt305x_esw_rr(esw, RT305X_ESW_REG_PVIDC(port / 2)); -+ return (val >> s) & RT305X_ESW_PVIDC_PVID_M; -+} -+ -+static void -+rt305x_esw_set_pvid(struct rt305x_esw *esw, unsigned port, unsigned pvid) -+{ -+ unsigned s; -+ -+ s = RT305X_ESW_PVIDC_PVID_S * (port % 2); -+ rt305x_esw_rmw(esw, -+ RT305X_ESW_REG_PVIDC(port / 2), -+ RT305X_ESW_PVIDC_PVID_M << s, -+ (pvid & RT305X_ESW_PVIDC_PVID_M) << s); -+} -+ -+static unsigned -+rt305x_esw_get_vmsc(struct rt305x_esw *esw, unsigned vlan) -+{ -+ unsigned s, val; -+ -+ s = RT305X_ESW_VMSC_MSC_S * (vlan % 4); -+ val = rt305x_esw_rr(esw, RT305X_ESW_REG_VMSC(vlan / 4)); -+ val = (val >> s) & RT305X_ESW_VMSC_MSC_M; -+ -+ return val; -+} -+ -+static void -+rt305x_esw_set_vmsc(struct rt305x_esw *esw, unsigned vlan, unsigned msc) -+{ -+ unsigned s; -+ -+ s = RT305X_ESW_VMSC_MSC_S * (vlan % 4); -+ rt305x_esw_rmw(esw, -+ RT305X_ESW_REG_VMSC(vlan / 4), -+ RT305X_ESW_VMSC_MSC_M << s, -+ (msc & RT305X_ESW_VMSC_MSC_M) << s); -+} -+ -+static unsigned -+rt305x_esw_get_port_disable(struct rt305x_esw *esw) -+{ -+ unsigned reg; -+ reg = rt305x_esw_rr(esw, RT305X_ESW_REG_POC0); -+ return (reg >> RT305X_ESW_POC0_DIS_PORT_S) & -+ RT305X_ESW_POC0_DIS_PORT_M; -+} -+ -+static void -+rt305x_esw_set_port_disable(struct rt305x_esw *esw, unsigned disable_mask) -+{ -+ unsigned old_mask; -+ unsigned enable_mask; -+ unsigned changed; -+ int i; -+ -+ old_mask = rt305x_esw_get_port_disable(esw); -+ changed = old_mask ^ disable_mask; -+ enable_mask = old_mask & disable_mask; -+ -+ /* enable before writing to MII */ -+ rt305x_esw_rmw(esw, RT305X_ESW_REG_POC0, -+ (RT305X_ESW_POC0_DIS_PORT_M << -+ RT305X_ESW_POC0_DIS_PORT_S), -+ enable_mask << RT305X_ESW_POC0_DIS_PORT_S); -+ -+ for (i = 0; i < RT305X_ESW_NUM_LEDS; i++) { -+ if (!(changed & (1 << i))) -+ continue; -+ if (disable_mask & (1 << i)) { -+ /* disable */ -+ rt305x_mii_write(esw, i, MII_BMCR, -+ BMCR_PDOWN); -+ } else { -+ /* enable */ -+ rt305x_mii_write(esw, i, MII_BMCR, -+ BMCR_FULLDPLX | -+ BMCR_ANENABLE | -+ BMCR_ANRESTART | -+ BMCR_SPEED100); -+ } -+ } -+ -+ /* disable after writing to MII */ -+ rt305x_esw_rmw(esw, RT305X_ESW_REG_POC0, -+ (RT305X_ESW_POC0_DIS_PORT_M << -+ RT305X_ESW_POC0_DIS_PORT_S), -+ disable_mask << RT305X_ESW_POC0_DIS_PORT_S); -+} -+ -+static int -+rt305x_esw_apply_config(struct switch_dev *dev); -+ -+static void -+rt305x_esw_hw_init(struct rt305x_esw *esw) -+{ -+ int i; -+ u8 port_disable = 0; -+ u8 port_map = RT305X_ESW_PMAP_LLLLLL; -+ -+ /* vodoo from original driver */ -+ rt305x_esw_wr(esw, 0xC8A07850, RT305X_ESW_REG_FCT0); -+ rt305x_esw_wr(esw, 0x00000000, RT305X_ESW_REG_SGC2); -+ /* Port priority 1 for all ports, vlan enabled. */ -+ rt305x_esw_wr(esw, 0x00005555 | -+ (RT305X_ESW_PORTS_ALL << RT305X_ESW_PFC1_EN_VLAN_S), -+ RT305X_ESW_REG_PFC1); -+ -+ /* Enable Back Pressure, and Flow Control */ -+ rt305x_esw_wr(esw, -+ ((RT305X_ESW_PORTS_ALL << RT305X_ESW_POC0_EN_BP_S) | -+ (RT305X_ESW_PORTS_ALL << RT305X_ESW_POC0_EN_FC_S)), -+ RT305X_ESW_REG_POC0); -+ -+ /* Enable Aging, and VLAN TAG removal */ -+ rt305x_esw_wr(esw, -+ ((RT305X_ESW_PORTS_ALL << RT305X_ESW_POC2_ENAGING_S) | -+ (RT305X_ESW_PORTS_NOCPU << RT305X_ESW_POC2_UNTAG_EN_S)), -+ RT305X_ESW_REG_POC2); -+ -+ if (esw->reg_initval_fct2) -+ rt305x_esw_wr(esw, esw->reg_initval_fct2, RT305X_ESW_REG_FCT2); -+ else -+ rt305x_esw_wr(esw, esw->pdata->reg_initval_fct2, RT305X_ESW_REG_FCT2); -+ -+ /* -+ * 300s aging timer, max packet len 1536, broadcast storm prevention -+ * disabled, disable collision abort, mac xor48 hash, 10 packet back -+ * pressure jam, GMII disable was_transmit, back pressure disabled, -+ * 30ms led flash, unmatched IGMP as broadcast, rmc tb fault to all -+ * ports. -+ */ -+ rt305x_esw_wr(esw, 0x0008a301, RT305X_ESW_REG_SGC); -+ -+ /* Setup SoC Port control register */ -+ rt305x_esw_wr(esw, -+ (RT305X_ESW_SOCPC_CRC_PADDING | -+ (RT305X_ESW_PORTS_CPU << RT305X_ESW_SOCPC_DISUN2CPU_S) | -+ (RT305X_ESW_PORTS_CPU << RT305X_ESW_SOCPC_DISMC2CPU_S) | -+ (RT305X_ESW_PORTS_CPU << RT305X_ESW_SOCPC_DISBC2CPU_S)), -+ RT305X_ESW_REG_SOCPC); -+ -+ if (esw->reg_initval_fpa2) -+ rt305x_esw_wr(esw, esw->reg_initval_fpa2, RT305X_ESW_REG_FPA2); -+ else -+ rt305x_esw_wr(esw, esw->pdata->reg_initval_fpa2, RT305X_ESW_REG_FPA2); -+ rt305x_esw_wr(esw, 0x00000000, RT305X_ESW_REG_FPA); -+ -+ /* Force Link/Activity on ports */ -+ rt305x_esw_wr(esw, 0x00000005, RT305X_ESW_REG_P0LED); -+ rt305x_esw_wr(esw, 0x00000005, RT305X_ESW_REG_P1LED); -+ rt305x_esw_wr(esw, 0x00000005, RT305X_ESW_REG_P2LED); -+ rt305x_esw_wr(esw, 0x00000005, RT305X_ESW_REG_P3LED); -+ rt305x_esw_wr(esw, 0x00000005, RT305X_ESW_REG_P4LED); -+ -+ /* Copy disabled port configuration from bootloader setup */ -+ port_disable = rt305x_esw_get_port_disable(esw); -+ for (i = 0; i < 6; i++) -+ esw->ports[i].disable = (port_disable & (1 << i)) != 0; -+ -+ rt305x_mii_write(esw, 0, 31, 0x8000); -+ for (i = 0; i < 5; i++) { -+ if (esw->ports[i].disable) { -+ rt305x_mii_write(esw, i, MII_BMCR, BMCR_PDOWN); -+ } else { -+ rt305x_mii_write(esw, i, MII_BMCR, -+ BMCR_FULLDPLX | -+ BMCR_ANENABLE | -+ BMCR_SPEED100); -+ } -+ /* TX10 waveform coefficient */ -+ rt305x_mii_write(esw, i, 26, 0x1601); -+ /* TX100/TX10 AD/DA current bias */ -+ rt305x_mii_write(esw, i, 29, 0x7058); -+ /* TX100 slew rate control */ -+ rt305x_mii_write(esw, i, 30, 0x0018); -+ } -+ -+ /* PHY IOT */ -+ /* select global register */ -+ rt305x_mii_write(esw, 0, 31, 0x0); -+ /* tune TP_IDL tail and head waveform */ -+ rt305x_mii_write(esw, 0, 22, 0x052f); -+ /* set TX10 signal amplitude threshold to minimum */ -+ rt305x_mii_write(esw, 0, 17, 0x0fe0); -+ /* set squelch amplitude to higher threshold */ -+ rt305x_mii_write(esw, 0, 18, 0x40ba); -+ /* longer TP_IDL tail length */ -+ rt305x_mii_write(esw, 0, 14, 0x65); -+ /* select local register */ -+ rt305x_mii_write(esw, 0, 31, 0x8000); -+ -+ if (esw->port_map) -+ port_map = esw->port_map; -+ else -+ port_map = RT305X_ESW_PMAP_LLLLLL; -+ -+ /* -+ * Unused HW feature, but still nice to be consistent here... -+ * This is also exported to userspace ('lan' attribute) so it's -+ * conveniently usable to decide which ports go into the wan vlan by -+ * default. -+ */ -+ rt305x_esw_rmw(esw, RT305X_ESW_REG_SGC2, -+ RT305X_ESW_SGC2_LAN_PMAP_M << RT305X_ESW_SGC2_LAN_PMAP_S, -+ port_map << RT305X_ESW_SGC2_LAN_PMAP_S); -+ -+ /* make the switch leds blink */ -+ for (i = 0; i < RT305X_ESW_NUM_LEDS; i++) -+ esw->ports[i].led = 0x05; -+ -+ /* Apply the empty config. */ -+ rt305x_esw_apply_config(&esw->swdev); -+} -+ -+static irqreturn_t -+rt305x_esw_interrupt(int irq, void *_esw) -+{ -+ struct rt305x_esw *esw = (struct rt305x_esw *) _esw; -+ u32 status; -+ -+ status = rt305x_esw_rr(esw, RT305X_ESW_REG_ISR); -+ if (status & RT305X_ESW_PORT_ST_CHG) { -+ u32 link = rt305x_esw_rr(esw, RT305X_ESW_REG_POA); -+ link >>= RT305X_ESW_POA_LINK_SHIFT; -+ link &= RT305X_ESW_POA_LINK_MASK; -+ dev_info(esw->dev, "link changed 0x%02X\n", link); -+ } -+ rt305x_esw_wr(esw, RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_ISR); -+ -+ return IRQ_HANDLED; -+} -+ -+static void -+rt305x_esw_request_irq(struct rt305x_esw *esw) -+{ -+ /* Only unmask the port change interrupt */ -+ rt305x_esw_wr(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR); -+ -+ /* request the irq handler */ -+ request_irq(esw->irq, rt305x_esw_interrupt, 0, "esw", esw); -+} -+ -+static int -+rt305x_esw_apply_config(struct switch_dev *dev) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ int i; -+ u8 disable = 0; -+ u8 doubletag = 0; -+ u8 en_vlan = 0; -+ u8 untag = 0; -+ -+ for (i = 0; i < RT305X_ESW_NUM_VLANS; i++) { -+ u32 vid, vmsc; -+ if (esw->global_vlan_enable) { -+ vid = esw->vlans[i].vid; -+ vmsc = esw->vlans[i].ports; -+ } else { -+ vid = RT305X_ESW_VLAN_NONE; -+ vmsc = RT305X_ESW_PORTS_NONE; -+ } -+ rt305x_esw_set_vlan_id(esw, i, vid); -+ rt305x_esw_set_vmsc(esw, i, vmsc); -+ } -+ -+ for (i = 0; i < RT305X_ESW_NUM_PORTS; i++) { -+ u32 pvid; -+ disable |= esw->ports[i].disable << i; -+ if (esw->global_vlan_enable) { -+ doubletag |= esw->ports[i].doubletag << i; -+ en_vlan |= 1 << i; -+ untag |= esw->ports[i].untag << i; -+ pvid = esw->ports[i].pvid; -+ } else { -+ int x = esw->alt_vlan_disable ? 0 : 1; -+ doubletag |= x << i; -+ en_vlan |= x << i; -+ untag |= x << i; -+ pvid = 0; -+ } -+ rt305x_esw_set_pvid(esw, i, pvid); -+ if (i < RT305X_ESW_NUM_LEDS) -+ rt305x_esw_wr(esw, esw->ports[i].led, -+ RT305X_ESW_REG_P0LED + 4*i); -+ } -+ -+ rt305x_esw_set_port_disable(esw, disable); -+ rt305x_esw_rmw(esw, RT305X_ESW_REG_SGC2, -+ (RT305X_ESW_SGC2_DOUBLE_TAG_M << -+ RT305X_ESW_SGC2_DOUBLE_TAG_S), -+ doubletag << RT305X_ESW_SGC2_DOUBLE_TAG_S); -+ rt305x_esw_rmw(esw, RT305X_ESW_REG_PFC1, -+ RT305X_ESW_PFC1_EN_VLAN_M << RT305X_ESW_PFC1_EN_VLAN_S, -+ en_vlan << RT305X_ESW_PFC1_EN_VLAN_S); -+ rt305x_esw_rmw(esw, RT305X_ESW_REG_POC2, -+ RT305X_ESW_POC2_UNTAG_EN_M << RT305X_ESW_POC2_UNTAG_EN_S, -+ untag << RT305X_ESW_POC2_UNTAG_EN_S); -+ -+ if (!esw->global_vlan_enable) { -+ /* -+ * Still need to put all ports into vlan 0 or they'll be -+ * isolated. -+ * NOTE: vlan 0 is special, no vlan tag is prepended -+ */ -+ rt305x_esw_set_vlan_id(esw, 0, 0); -+ rt305x_esw_set_vmsc(esw, 0, RT305X_ESW_PORTS_ALL); -+ } -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_reset_switch(struct switch_dev *dev) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ esw->global_vlan_enable = 0; -+ memset(esw->ports, 0, sizeof(esw->ports)); -+ memset(esw->vlans, 0, sizeof(esw->vlans)); -+ rt305x_esw_hw_init(esw); -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_get_vlan_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ -+ val->value.i = esw->global_vlan_enable; -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_set_vlan_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ -+ esw->global_vlan_enable = val->value.i != 0; -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_get_alt_vlan_disable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ -+ val->value.i = esw->alt_vlan_disable; -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_set_alt_vlan_disable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ -+ esw->alt_vlan_disable = val->value.i != 0; -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_get_port_link(struct switch_dev *dev, -+ int port, -+ struct switch_port_link *link) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ u32 speed, poa; -+ -+ if (port < 0 || port >= RT305X_ESW_NUM_PORTS) -+ return -EINVAL; -+ -+ poa = rt305x_esw_rr(esw, RT305X_ESW_REG_POA) >> port; -+ -+ link->link = (poa >> RT305X_ESW_LINK_S) & 1; -+ link->duplex = (poa >> RT305X_ESW_DUPLEX_S) & 1; -+ if (port < RT305X_ESW_NUM_LEDS) { -+ speed = (poa >> RT305X_ESW_SPD_S) & 1; -+ } else { -+ if (port == RT305X_ESW_NUM_PORTS - 1) -+ poa >>= 1; -+ speed = (poa >> RT305X_ESW_SPD_S) & 3; -+ } -+ switch (speed) { -+ case 0: -+ link->speed = SWITCH_PORT_SPEED_10; -+ break; -+ case 1: -+ link->speed = SWITCH_PORT_SPEED_100; -+ break; -+ case 2: -+ case 3: /* forced gige speed can be 2 or 3 */ -+ link->speed = SWITCH_PORT_SPEED_1000; -+ break; -+ default: -+ link->speed = SWITCH_PORT_SPEED_UNKNOWN; -+ break; -+ } -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_get_port_bool(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ int idx = val->port_vlan; -+ u32 x, reg, shift; -+ -+ if (idx < 0 || idx >= RT305X_ESW_NUM_PORTS) -+ return -EINVAL; -+ -+ switch (attr->id) { -+ case RT305X_ESW_ATTR_PORT_DISABLE: -+ reg = RT305X_ESW_REG_POC0; -+ shift = RT305X_ESW_POC0_DIS_PORT_S; -+ break; -+ case RT305X_ESW_ATTR_PORT_DOUBLETAG: -+ reg = RT305X_ESW_REG_SGC2; -+ shift = RT305X_ESW_SGC2_DOUBLE_TAG_S; -+ break; -+ case RT305X_ESW_ATTR_PORT_UNTAG: -+ reg = RT305X_ESW_REG_POC2; -+ shift = RT305X_ESW_POC2_UNTAG_EN_S; -+ break; -+ case RT305X_ESW_ATTR_PORT_LAN: -+ reg = RT305X_ESW_REG_SGC2; -+ shift = RT305X_ESW_SGC2_LAN_PMAP_S; -+ if (idx >= RT305X_ESW_NUM_LANWAN) -+ return -EINVAL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ x = rt305x_esw_rr(esw, reg); -+ val->value.i = (x >> (idx + shift)) & 1; -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_set_port_bool(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ int idx = val->port_vlan; -+ -+ if (idx < 0 || idx >= RT305X_ESW_NUM_PORTS || -+ val->value.i < 0 || val->value.i > 1) -+ return -EINVAL; -+ -+ switch (attr->id) { -+ case RT305X_ESW_ATTR_PORT_DISABLE: -+ esw->ports[idx].disable = val->value.i; -+ break; -+ case RT305X_ESW_ATTR_PORT_DOUBLETAG: -+ esw->ports[idx].doubletag = val->value.i; -+ break; -+ case RT305X_ESW_ATTR_PORT_UNTAG: -+ esw->ports[idx].untag = val->value.i; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_get_port_recv_badgood(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ int idx = val->port_vlan; -+ int shift = attr->id == RT305X_ESW_ATTR_PORT_RECV_GOOD ? 0 : 16; -+ u32 reg; -+ -+ if (idx < 0 || idx >= RT305X_ESW_NUM_LANWAN) -+ return -EINVAL; -+ -+ reg = rt305x_esw_rr(esw, RT305X_ESW_REG_P0PC + 4*idx); -+ val->value.i = (reg >> shift) & 0xffff; -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_get_port_led(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ int idx = val->port_vlan; -+ -+ if (idx < 0 || idx >= RT305X_ESW_NUM_PORTS || -+ idx >= RT305X_ESW_NUM_LEDS) -+ return -EINVAL; -+ -+ val->value.i = rt305x_esw_rr(esw, RT305X_ESW_REG_P0LED + 4*idx); -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_set_port_led(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ int idx = val->port_vlan; -+ -+ if (idx < 0 || idx >= RT305X_ESW_NUM_LEDS) -+ return -EINVAL; -+ -+ esw->ports[idx].led = val->value.i; -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_get_port_pvid(struct switch_dev *dev, int port, int *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ -+ if (port >= RT305X_ESW_NUM_PORTS) -+ return -EINVAL; -+ -+ *val = rt305x_esw_get_pvid(esw, port); -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_set_port_pvid(struct switch_dev *dev, int port, int val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ -+ if (port >= RT305X_ESW_NUM_PORTS) -+ return -EINVAL; -+ -+ esw->ports[port].pvid = val; -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ u32 vmsc, poc2; -+ int vlan_idx = -1; -+ int i; -+ -+ val->len = 0; -+ -+ if (val->port_vlan < 0 || val->port_vlan >= RT305X_ESW_NUM_VIDS) -+ return -EINVAL; -+ -+ /* valid vlan? */ -+ for (i = 0; i < RT305X_ESW_NUM_VLANS; i++) { -+ if (rt305x_esw_get_vlan_id(esw, i) == val->port_vlan && -+ rt305x_esw_get_vmsc(esw, i) != RT305X_ESW_PORTS_NONE) { -+ vlan_idx = i; -+ break; -+ } -+ } -+ -+ if (vlan_idx == -1) -+ return -EINVAL; -+ -+ vmsc = rt305x_esw_get_vmsc(esw, vlan_idx); -+ poc2 = rt305x_esw_rr(esw, RT305X_ESW_REG_POC2); -+ -+ for (i = 0; i < RT305X_ESW_NUM_PORTS; i++) { -+ struct switch_port *p; -+ int port_mask = 1 << i; -+ -+ if (!(vmsc & port_mask)) -+ continue; -+ -+ p = &val->value.ports[val->len++]; -+ p->id = i; -+ if (poc2 & (port_mask << RT305X_ESW_POC2_UNTAG_EN_S)) -+ p->flags = 0; -+ else -+ p->flags = 1 << SWITCH_PORT_FLAG_TAGGED; -+ } -+ -+ return 0; -+} -+ -+static int -+rt305x_esw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct rt305x_esw *esw = container_of(dev, struct rt305x_esw, swdev); -+ int ports; -+ int vlan_idx = -1; -+ int i; -+ -+ if (val->port_vlan < 0 || val->port_vlan >= RT305X_ESW_NUM_VIDS || -+ val->len > RT305X_ESW_NUM_PORTS) -+ return -EINVAL; -+ -+ /* one of the already defined vlans? */ -+ for (i = 0; i < RT305X_ESW_NUM_VLANS; i++) { -+ if (esw->vlans[i].vid == val->port_vlan && -+ esw->vlans[i].ports != RT305X_ESW_PORTS_NONE) { -+ vlan_idx = i; -+ break; -+ } -+ } -+ -+ /* select a free slot */ -+ for (i = 0; vlan_idx == -1 && i < RT305X_ESW_NUM_VLANS; i++) { -+ if (esw->vlans[i].ports == RT305X_ESW_PORTS_NONE) -+ vlan_idx = i; -+ } -+ -+ /* bail if all slots are in use */ -+ if (vlan_idx == -1) -+ return -EINVAL; -+ -+ ports = RT305X_ESW_PORTS_NONE; -+ for (i = 0; i < val->len; i++) { -+ struct switch_port *p = &val->value.ports[i]; -+ int port_mask = 1 << p->id; -+ bool untagged = !(p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)); -+ -+ if (p->id >= RT305X_ESW_NUM_PORTS) -+ return -EINVAL; -+ -+ ports |= port_mask; -+ esw->ports[p->id].untag = untagged; -+ } -+ esw->vlans[vlan_idx].ports = ports; -+ if (ports == RT305X_ESW_PORTS_NONE) -+ esw->vlans[vlan_idx].vid = RT305X_ESW_VLAN_NONE; -+ else -+ esw->vlans[vlan_idx].vid = val->port_vlan; -+ -+ return 0; -+} -+ -+static const struct switch_attr rt305x_esw_global[] = { -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_vlan", -+ .description = "VLAN mode (1:enabled)", -+ .max = 1, -+ .id = RT305X_ESW_ATTR_ENABLE_VLAN, -+ .get = rt305x_esw_get_vlan_enable, -+ .set = rt305x_esw_set_vlan_enable, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "alternate_vlan_disable", -+ .description = "Use en_vlan instead of doubletag to disable" -+ " VLAN mode", -+ .max = 1, -+ .id = RT305X_ESW_ATTR_ALT_VLAN_DISABLE, -+ .get = rt305x_esw_get_alt_vlan_disable, -+ .set = rt305x_esw_set_alt_vlan_disable, -+ }, -+}; -+ -+static const struct switch_attr rt305x_esw_port[] = { -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "disable", -+ .description = "Port state (1:disabled)", -+ .max = 1, -+ .id = RT305X_ESW_ATTR_PORT_DISABLE, -+ .get = rt305x_esw_get_port_bool, -+ .set = rt305x_esw_set_port_bool, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "doubletag", -+ .description = "Double tagging for incoming vlan packets " -+ "(1:enabled)", -+ .max = 1, -+ .id = RT305X_ESW_ATTR_PORT_DOUBLETAG, -+ .get = rt305x_esw_get_port_bool, -+ .set = rt305x_esw_set_port_bool, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "untag", -+ .description = "Untag (1:strip outgoing vlan tag)", -+ .max = 1, -+ .id = RT305X_ESW_ATTR_PORT_UNTAG, -+ .get = rt305x_esw_get_port_bool, -+ .set = rt305x_esw_set_port_bool, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "led", -+ .description = "LED mode (0:link, 1:100m, 2:duplex, 3:activity," -+ " 4:collision, 5:linkact, 6:duplcoll, 7:10mact," -+ " 8:100mact, 10:blink, 12:on)", -+ .max = 15, -+ .id = RT305X_ESW_ATTR_PORT_LED, -+ .get = rt305x_esw_get_port_led, -+ .set = rt305x_esw_set_port_led, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "lan", -+ .description = "HW port group (0:wan, 1:lan)", -+ .max = 1, -+ .id = RT305X_ESW_ATTR_PORT_LAN, -+ .get = rt305x_esw_get_port_bool, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "recv_bad", -+ .description = "Receive bad packet counter", -+ .id = RT305X_ESW_ATTR_PORT_RECV_BAD, -+ .get = rt305x_esw_get_port_recv_badgood, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "recv_good", -+ .description = "Receive good packet counter", -+ .id = RT305X_ESW_ATTR_PORT_RECV_GOOD, -+ .get = rt305x_esw_get_port_recv_badgood, -+ }, -+}; -+ -+static const struct switch_attr rt305x_esw_vlan[] = { -+}; -+ -+static const struct switch_dev_ops rt305x_esw_ops = { -+ .attr_global = { -+ .attr = rt305x_esw_global, -+ .n_attr = ARRAY_SIZE(rt305x_esw_global), -+ }, -+ .attr_port = { -+ .attr = rt305x_esw_port, -+ .n_attr = ARRAY_SIZE(rt305x_esw_port), -+ }, -+ .attr_vlan = { -+ .attr = rt305x_esw_vlan, -+ .n_attr = ARRAY_SIZE(rt305x_esw_vlan), -+ }, -+ .get_vlan_ports = rt305x_esw_get_vlan_ports, -+ .set_vlan_ports = rt305x_esw_set_vlan_ports, -+ .get_port_pvid = rt305x_esw_get_port_pvid, -+ .set_port_pvid = rt305x_esw_set_port_pvid, -+ .get_port_link = rt305x_esw_get_port_link, -+ .apply_config = rt305x_esw_apply_config, -+ .reset_switch = rt305x_esw_reset_switch, -+}; -+ -+static struct rt305x_esw_platform_data rt3050_esw_data = { -+ /* All ports are LAN ports. */ -+ .vlan_config = RT305X_ESW_VLAN_CONFIG_NONE, -+ .reg_initval_fct2 = 0x00d6500c, -+ /* -+ * ext phy base addr 31, enable port 5 polling, rx/tx clock skew 1, -+ * turbo mii off, rgmi 3.3v off -+ * port5: disabled -+ * port6: enabled, gige, full-duplex, rx/tx-flow-control -+ */ -+ .reg_initval_fpa2 = 0x3f502b28, -+}; -+ -+static const struct of_device_id ralink_esw_match[] = { -+ { .compatible = "ralink,rt3050-esw", .data = &rt3050_esw_data }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, ralink_esw_match); -+ -+static int -+rt305x_esw_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ const struct rt305x_esw_platform_data *pdata; -+ const __be32 *port_map, *reg_init; -+ struct rt305x_esw *esw; -+ struct switch_dev *swdev; -+ struct resource *res, *irq; -+ int err; -+ -+ pdata = pdev->dev.platform_data; -+ if (!pdata) { -+ const struct of_device_id *match; -+ match = of_match_device(ralink_esw_match, &pdev->dev); -+ if (match) -+ pdata = (struct rt305x_esw_platform_data *) match->data; -+ } -+ if (!pdata) -+ return -EINVAL; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "no memory resource found\n"); -+ return -ENOMEM; -+ } -+ -+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -+ if (!irq) { -+ dev_err(&pdev->dev, "no irq resource found\n"); -+ return -ENOMEM; -+ } -+ -+ esw = kzalloc(sizeof(struct rt305x_esw), GFP_KERNEL); -+ if (!esw) { -+ dev_err(&pdev->dev, "no memory for private data\n"); -+ return -ENOMEM; -+ } -+ -+ esw->dev = &pdev->dev; -+ esw->irq = irq->start; -+ esw->base = ioremap(res->start, resource_size(res)); -+ if (!esw->base) { -+ dev_err(&pdev->dev, "ioremap failed\n"); -+ err = -ENOMEM; -+ goto free_esw; -+ } -+ -+ port_map = of_get_property(np, "ralink,portmap", NULL); -+ if (port_map) -+ esw->port_map = be32_to_cpu(*port_map); -+ -+ reg_init = of_get_property(np, "ralink,fct2", NULL); -+ if (reg_init) -+ esw->reg_initval_fct2 = be32_to_cpu(*reg_init); -+ -+ reg_init = of_get_property(np, "ralink,fpa2", NULL); -+ if (reg_init) -+ esw->reg_initval_fpa2 = be32_to_cpu(*reg_init); -+ -+ swdev = &esw->swdev; -+ swdev->of_node = pdev->dev.of_node; -+ swdev->name = "rt305x-esw"; -+ swdev->alias = "rt305x"; -+ swdev->cpu_port = RT305X_ESW_PORT6; -+ swdev->ports = RT305X_ESW_NUM_PORTS; -+ swdev->vlans = RT305X_ESW_NUM_VIDS; -+ swdev->ops = &rt305x_esw_ops; -+ -+ err = register_switch(swdev, NULL); -+ if (err < 0) { -+ dev_err(&pdev->dev, "register_switch failed\n"); -+ goto unmap_base; -+ } -+ -+ platform_set_drvdata(pdev, esw); -+ -+ esw->pdata = pdata; -+ spin_lock_init(&esw->reg_rw_lock); -+ rt305x_esw_hw_init(esw); -+ rt305x_esw_request_irq(esw); -+ -+ return 0; -+ -+unmap_base: -+ iounmap(esw->base); -+free_esw: -+ kfree(esw); -+ return err; -+} -+ -+static int -+rt305x_esw_remove(struct platform_device *pdev) -+{ -+ struct rt305x_esw *esw; -+ -+ esw = platform_get_drvdata(pdev); -+ if (esw) { -+ unregister_switch(&esw->swdev); -+ platform_set_drvdata(pdev, NULL); -+ iounmap(esw->base); -+ kfree(esw); -+ } -+ -+ return 0; -+} -+ -+static struct platform_driver rt305x_esw_driver = { -+ .probe = rt305x_esw_probe, -+ .remove = rt305x_esw_remove, -+ .driver = { -+ .name = "rt305x-esw", -+ .owner = THIS_MODULE, -+ .of_match_table = ralink_esw_match, -+ }, -+}; -+ -+static int __init -+rt305x_esw_init(void) -+{ -+ return platform_driver_register(&rt305x_esw_driver); -+} -+ -+static void -+rt305x_esw_exit(void) -+{ -+ platform_driver_unregister(&rt305x_esw_driver); -+} ---- /dev/null -+++ b/drivers/net/ethernet/ramips/ramips_eth.h -@@ -0,0 +1,375 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * based on Ralink SDK3.3 -+ * Copyright (C) 2009 John Crispin <blogic@openwrt.org> -+ */ -+ -+#ifndef RAMIPS_ETH_H -+#define RAMIPS_ETH_H -+ -+#include <linux/mii.h> -+#include <linux/interrupt.h> -+#include <linux/netdevice.h> -+#include <linux/dma-mapping.h> -+ -+#define NUM_RX_DESC 256 -+#define NUM_TX_DESC 256 -+ -+#define RAMIPS_DELAY_EN_INT 0x80 -+#define RAMIPS_DELAY_MAX_INT 0x04 -+#define RAMIPS_DELAY_MAX_TOUT 0x04 -+#define RAMIPS_DELAY_CHAN (((RAMIPS_DELAY_EN_INT | RAMIPS_DELAY_MAX_INT) << 8) | RAMIPS_DELAY_MAX_TOUT) -+#define RAMIPS_DELAY_INIT ((RAMIPS_DELAY_CHAN << 16) | RAMIPS_DELAY_CHAN) -+#define RAMIPS_PSE_FQFC_CFG_INIT 0x80504000 -+ -+/* interrupt bits */ -+#define RAMIPS_CNT_PPE_AF BIT(31) -+#define RAMIPS_CNT_GDM_AF BIT(29) -+#define RAMIPS_PSE_P2_FC BIT(26) -+#define RAMIPS_PSE_BUF_DROP BIT(24) -+#define RAMIPS_GDM_OTHER_DROP BIT(23) -+#define RAMIPS_PSE_P1_FC BIT(22) -+#define RAMIPS_PSE_P0_FC BIT(21) -+#define RAMIPS_PSE_FQ_EMPTY BIT(20) -+#define RAMIPS_GE1_STA_CHG BIT(18) -+#define RAMIPS_TX_COHERENT BIT(17) -+#define RAMIPS_RX_COHERENT BIT(16) -+#define RAMIPS_TX_DONE_INT3 BIT(11) -+#define RAMIPS_TX_DONE_INT2 BIT(10) -+#define RAMIPS_TX_DONE_INT1 BIT(9) -+#define RAMIPS_TX_DONE_INT0 BIT(8) -+#define RAMIPS_RX_DONE_INT0 BIT(2) -+#define RAMIPS_TX_DLY_INT BIT(1) -+#define RAMIPS_RX_DLY_INT BIT(0) -+ -+#define RT5350_RX_DLY_INT BIT(30) -+#define RT5350_TX_DLY_INT BIT(28) -+ -+/* registers */ -+#define RAMIPS_FE_OFFSET 0x0000 -+#define RAMIPS_GDMA_OFFSET 0x0020 -+#define RAMIPS_PSE_OFFSET 0x0040 -+#define RAMIPS_GDMA2_OFFSET 0x0060 -+#define RAMIPS_CDMA_OFFSET 0x0080 -+#define RAMIPS_PDMA_OFFSET 0x0100 -+#define RAMIPS_PPE_OFFSET 0x0200 -+#define RAMIPS_CMTABLE_OFFSET 0x0400 -+#define RAMIPS_POLICYTABLE_OFFSET 0x1000 -+ -+#define RT5350_PDMA_OFFSET 0x0800 -+#define RT5350_SDM_OFFSET 0x0c00 -+ -+#define RAMIPS_MDIO_ACCESS (RAMIPS_FE_OFFSET + 0x00) -+#define RAMIPS_MDIO_CFG (RAMIPS_FE_OFFSET + 0x04) -+#define RAMIPS_FE_GLO_CFG (RAMIPS_FE_OFFSET + 0x08) -+#define RAMIPS_FE_RST_GL (RAMIPS_FE_OFFSET + 0x0C) -+#define RAMIPS_FE_INT_STATUS (RAMIPS_FE_OFFSET + 0x10) -+#define RAMIPS_FE_INT_ENABLE (RAMIPS_FE_OFFSET + 0x14) -+#define RAMIPS_MDIO_CFG2 (RAMIPS_FE_OFFSET + 0x18) -+#define RAMIPS_FOC_TS_T (RAMIPS_FE_OFFSET + 0x1C) -+ -+#define RAMIPS_GDMA1_FWD_CFG (RAMIPS_GDMA_OFFSET + 0x00) -+#define RAMIPS_GDMA1_SCH_CFG (RAMIPS_GDMA_OFFSET + 0x04) -+#define RAMIPS_GDMA1_SHPR_CFG (RAMIPS_GDMA_OFFSET + 0x08) -+#define RAMIPS_GDMA1_MAC_ADRL (RAMIPS_GDMA_OFFSET + 0x0C) -+#define RAMIPS_GDMA1_MAC_ADRH (RAMIPS_GDMA_OFFSET + 0x10) -+ -+#define RAMIPS_GDMA2_FWD_CFG (RAMIPS_GDMA2_OFFSET + 0x00) -+#define RAMIPS_GDMA2_SCH_CFG (RAMIPS_GDMA2_OFFSET + 0x04) -+#define RAMIPS_GDMA2_SHPR_CFG (RAMIPS_GDMA2_OFFSET + 0x08) -+#define RAMIPS_GDMA2_MAC_ADRL (RAMIPS_GDMA2_OFFSET + 0x0C) -+#define RAMIPS_GDMA2_MAC_ADRH (RAMIPS_GDMA2_OFFSET + 0x10) -+ -+#define RAMIPS_PSE_FQ_CFG (RAMIPS_PSE_OFFSET + 0x00) -+#define RAMIPS_CDMA_FC_CFG (RAMIPS_PSE_OFFSET + 0x04) -+#define RAMIPS_GDMA1_FC_CFG (RAMIPS_PSE_OFFSET + 0x08) -+#define RAMIPS_GDMA2_FC_CFG (RAMIPS_PSE_OFFSET + 0x0C) -+ -+#define RAMIPS_CDMA_CSG_CFG (RAMIPS_CDMA_OFFSET + 0x00) -+#define RAMIPS_CDMA_SCH_CFG (RAMIPS_CDMA_OFFSET + 0x04) -+ -+#define RT5350_TX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x00) -+#define RT5350_TX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x04) -+#define RT5350_TX_CTX_IDX0 (RT5350_PDMA_OFFSET + 0x08) -+#define RT5350_TX_DTX_IDX0 (RT5350_PDMA_OFFSET + 0x0C) -+#define RT5350_TX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x10) -+#define RT5350_TX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x14) -+#define RT5350_TX_CTX_IDX1 (RT5350_PDMA_OFFSET + 0x18) -+#define RT5350_TX_DTX_IDX1 (RT5350_PDMA_OFFSET + 0x1C) -+#define RT5350_TX_BASE_PTR2 (RT5350_PDMA_OFFSET + 0x20) -+#define RT5350_TX_MAX_CNT2 (RT5350_PDMA_OFFSET + 0x24) -+#define RT5350_TX_CTX_IDX2 (RT5350_PDMA_OFFSET + 0x28) -+#define RT5350_TX_DTX_IDX2 (RT5350_PDMA_OFFSET + 0x2C) -+#define RT5350_TX_BASE_PTR3 (RT5350_PDMA_OFFSET + 0x30) -+#define RT5350_TX_MAX_CNT3 (RT5350_PDMA_OFFSET + 0x34) -+#define RT5350_TX_CTX_IDX3 (RT5350_PDMA_OFFSET + 0x38) -+#define RT5350_TX_DTX_IDX3 (RT5350_PDMA_OFFSET + 0x3C) -+#define RT5350_RX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x100) -+#define RT5350_RX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x104) -+#define RT5350_RX_CALC_IDX0 (RT5350_PDMA_OFFSET + 0x108) -+#define RT5350_RX_DRX_IDX0 (RT5350_PDMA_OFFSET + 0x10C) -+#define RT5350_RX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x110) -+#define RT5350_RX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x114) -+#define RT5350_RX_CALC_IDX1 (RT5350_PDMA_OFFSET + 0x118) -+#define RT5350_RX_DRX_IDX1 (RT5350_PDMA_OFFSET + 0x11C) -+#define RT5350_PDMA_GLO_CFG (RT5350_PDMA_OFFSET + 0x204) -+#define RT5350_PDMA_RST_CFG (RT5350_PDMA_OFFSET + 0x208) -+#define RT5350_DLY_INT_CFG (RT5350_PDMA_OFFSET + 0x20c) -+#define RT5350_FE_INT_STATUS (RT5350_PDMA_OFFSET + 0x220) -+#define RT5350_FE_INT_ENABLE (RT5350_PDMA_OFFSET + 0x228) -+#define RT5350_PDMA_SCH_CFG (RT5350_PDMA_OFFSET + 0x280) -+ -+ -+#define RAMIPS_PDMA_GLO_CFG (RAMIPS_PDMA_OFFSET + 0x00) -+#define RAMIPS_PDMA_RST_CFG (RAMIPS_PDMA_OFFSET + 0x04) -+#define RAMIPS_PDMA_SCH_CFG (RAMIPS_PDMA_OFFSET + 0x08) -+#define RAMIPS_DLY_INT_CFG (RAMIPS_PDMA_OFFSET + 0x0C) -+#define RAMIPS_TX_BASE_PTR0 (RAMIPS_PDMA_OFFSET + 0x10) -+#define RAMIPS_TX_MAX_CNT0 (RAMIPS_PDMA_OFFSET + 0x14) -+#define RAMIPS_TX_CTX_IDX0 (RAMIPS_PDMA_OFFSET + 0x18) -+#define RAMIPS_TX_DTX_IDX0 (RAMIPS_PDMA_OFFSET + 0x1C) -+#define RAMIPS_TX_BASE_PTR1 (RAMIPS_PDMA_OFFSET + 0x20) -+#define RAMIPS_TX_MAX_CNT1 (RAMIPS_PDMA_OFFSET + 0x24) -+#define RAMIPS_TX_CTX_IDX1 (RAMIPS_PDMA_OFFSET + 0x28) -+#define RAMIPS_TX_DTX_IDX1 (RAMIPS_PDMA_OFFSET + 0x2C) -+#define RAMIPS_RX_BASE_PTR0 (RAMIPS_PDMA_OFFSET + 0x30) -+#define RAMIPS_RX_MAX_CNT0 (RAMIPS_PDMA_OFFSET + 0x34) -+#define RAMIPS_RX_CALC_IDX0 (RAMIPS_PDMA_OFFSET + 0x38) -+#define RAMIPS_RX_DRX_IDX0 (RAMIPS_PDMA_OFFSET + 0x3C) -+#define RAMIPS_TX_BASE_PTR2 (RAMIPS_PDMA_OFFSET + 0x40) -+#define RAMIPS_TX_MAX_CNT2 (RAMIPS_PDMA_OFFSET + 0x44) -+#define RAMIPS_TX_CTX_IDX2 (RAMIPS_PDMA_OFFSET + 0x48) -+#define RAMIPS_TX_DTX_IDX2 (RAMIPS_PDMA_OFFSET + 0x4C) -+#define RAMIPS_TX_BASE_PTR3 (RAMIPS_PDMA_OFFSET + 0x50) -+#define RAMIPS_TX_MAX_CNT3 (RAMIPS_PDMA_OFFSET + 0x54) -+#define RAMIPS_TX_CTX_IDX3 (RAMIPS_PDMA_OFFSET + 0x58) -+#define RAMIPS_TX_DTX_IDX3 (RAMIPS_PDMA_OFFSET + 0x5C) -+#define RAMIPS_RX_BASE_PTR1 (RAMIPS_PDMA_OFFSET + 0x60) -+#define RAMIPS_RX_MAX_CNT1 (RAMIPS_PDMA_OFFSET + 0x64) -+#define RAMIPS_RX_CALC_IDX1 (RAMIPS_PDMA_OFFSET + 0x68) -+#define RAMIPS_RX_DRX_IDX1 (RAMIPS_PDMA_OFFSET + 0x6C) -+ -+#define RT5350_SDM_CFG (RT5350_SDM_OFFSET + 0x00) //Switch DMA configuration -+#define RT5350_SDM_RRING (RT5350_SDM_OFFSET + 0x04) //Switch DMA Rx Ring -+#define RT5350_SDM_TRING (RT5350_SDM_OFFSET + 0x08) //Switch DMA Tx Ring -+#define RT5350_SDM_MAC_ADRL (RT5350_SDM_OFFSET + 0x0C) //Switch MAC address LSB -+#define RT5350_SDM_MAC_ADRH (RT5350_SDM_OFFSET + 0x10) //Switch MAC Address MSB -+#define RT5350_SDM_TPCNT (RT5350_SDM_OFFSET + 0x100) //Switch DMA Tx packet count -+#define RT5350_SDM_TBCNT (RT5350_SDM_OFFSET + 0x104) //Switch DMA Tx byte count -+#define RT5350_SDM_RPCNT (RT5350_SDM_OFFSET + 0x108) //Switch DMA rx packet count -+#define RT5350_SDM_RBCNT (RT5350_SDM_OFFSET + 0x10C) //Switch DMA rx byte count -+#define RT5350_SDM_CS_ERR (RT5350_SDM_OFFSET + 0x110) //Switch DMA rx checksum error count -+ -+#define RT5350_SDM_ICS_EN BIT(16) -+#define RT5350_SDM_TCS_EN BIT(17) -+#define RT5350_SDM_UCS_EN BIT(18) -+ -+ -+/* MDIO_CFG register bits */ -+#define RAMIPS_MDIO_CFG_AUTO_POLL_EN BIT(29) -+#define RAMIPS_MDIO_CFG_GP1_BP_EN BIT(16) -+#define RAMIPS_MDIO_CFG_GP1_FRC_EN BIT(15) -+#define RAMIPS_MDIO_CFG_GP1_SPEED_10 (0 << 13) -+#define RAMIPS_MDIO_CFG_GP1_SPEED_100 (1 << 13) -+#define RAMIPS_MDIO_CFG_GP1_SPEED_1000 (2 << 13) -+#define RAMIPS_MDIO_CFG_GP1_DUPLEX BIT(12) -+#define RAMIPS_MDIO_CFG_GP1_FC_TX BIT(11) -+#define RAMIPS_MDIO_CFG_GP1_FC_RX BIT(10) -+#define RAMIPS_MDIO_CFG_GP1_LNK_DWN BIT(9) -+#define RAMIPS_MDIO_CFG_GP1_AN_FAIL BIT(8) -+#define RAMIPS_MDIO_CFG_MDC_CLK_DIV_1 (0 << 6) -+#define RAMIPS_MDIO_CFG_MDC_CLK_DIV_2 (1 << 6) -+#define RAMIPS_MDIO_CFG_MDC_CLK_DIV_4 (2 << 6) -+#define RAMIPS_MDIO_CFG_MDC_CLK_DIV_8 (3 << 6) -+#define RAMIPS_MDIO_CFG_TURBO_MII_FREQ BIT(5) -+#define RAMIPS_MDIO_CFG_TURBO_MII_MODE BIT(4) -+#define RAMIPS_MDIO_CFG_RX_CLK_SKEW_0 (0 << 2) -+#define RAMIPS_MDIO_CFG_RX_CLK_SKEW_200 (1 << 2) -+#define RAMIPS_MDIO_CFG_RX_CLK_SKEW_400 (2 << 2) -+#define RAMIPS_MDIO_CFG_RX_CLK_SKEW_INV (3 << 2) -+#define RAMIPS_MDIO_CFG_TX_CLK_SKEW_0 0 -+#define RAMIPS_MDIO_CFG_TX_CLK_SKEW_200 1 -+#define RAMIPS_MDIO_CFG_TX_CLK_SKEW_400 2 -+#define RAMIPS_MDIO_CFG_TX_CLK_SKEW_INV 3 -+ -+/* uni-cast port */ -+#define RAMIPS_GDM1_ICS_EN BIT(22) -+#define RAMIPS_GDM1_TCS_EN BIT(21) -+#define RAMIPS_GDM1_UCS_EN BIT(20) -+#define RAMIPS_GDM1_JMB_EN BIT(19) -+#define RAMIPS_GDM1_STRPCRC BIT(16) -+#define RAMIPS_GDM1_UFRC_P_CPU (0 << 12) -+#define RAMIPS_GDM1_UFRC_P_GDMA1 (1 << 12) -+#define RAMIPS_GDM1_UFRC_P_PPE (6 << 12) -+ -+/* checksums */ -+#define RAMIPS_ICS_GEN_EN BIT(2) -+#define RAMIPS_UCS_GEN_EN BIT(1) -+#define RAMIPS_TCS_GEN_EN BIT(0) -+ -+/* dma ring */ -+#define RAMIPS_PST_DRX_IDX0 BIT(16) -+#define RAMIPS_PST_DTX_IDX3 BIT(3) -+#define RAMIPS_PST_DTX_IDX2 BIT(2) -+#define RAMIPS_PST_DTX_IDX1 BIT(1) -+#define RAMIPS_PST_DTX_IDX0 BIT(0) -+ -+#define RAMIPS_TX_WB_DDONE BIT(6) -+#define RAMIPS_RX_DMA_BUSY BIT(3) -+#define RAMIPS_TX_DMA_BUSY BIT(1) -+#define RAMIPS_RX_DMA_EN BIT(2) -+#define RAMIPS_TX_DMA_EN BIT(0) -+ -+#define RAMIPS_PDMA_SIZE_4DWORDS (0 << 4) -+#define RAMIPS_PDMA_SIZE_8DWORDS (1 << 4) -+#define RAMIPS_PDMA_SIZE_16DWORDS (2 << 4) -+ -+#define RAMIPS_US_CYC_CNT_MASK 0xff -+#define RAMIPS_US_CYC_CNT_SHIFT 0x8 -+#define RAMIPS_US_CYC_CNT_DIVISOR 1000000 -+ -+#define RX_DMA_PLEN0(_x) (((_x) >> 16) & 0x3fff) -+#define RX_DMA_LSO BIT(30) -+#define RX_DMA_DONE BIT(31) -+ -+struct ramips_rx_dma { -+ unsigned int rxd1; -+ unsigned int rxd2; -+ unsigned int rxd3; -+ unsigned int rxd4; -+} __packed __aligned(4); -+ -+#define TX_DMA_PLEN0_MASK ((0x3fff) << 16) -+#define TX_DMA_PLEN0(_x) (((_x) & 0x3fff) << 16) -+#define TX_DMA_LSO BIT(30) -+#define TX_DMA_DONE BIT(31) -+#define TX_DMA_QN(_x) ((_x) << 16) -+#define TX_DMA_PN(_x) ((_x) << 24) -+#define TX_DMA_QN_MASK TX_DMA_QN(0x7) -+#define TX_DMA_PN_MASK TX_DMA_PN(0x7) -+ -+struct ramips_tx_dma { -+ unsigned int txd1; -+ unsigned int txd2; -+ unsigned int txd3; -+ unsigned int txd4; -+} __packed __aligned(4); -+ -+struct raeth_tx_info { -+ struct ramips_tx_dma *tx_desc; -+ struct sk_buff *tx_skb; -+}; -+ -+struct raeth_rx_info { -+ struct ramips_rx_dma *rx_desc; -+ struct sk_buff *rx_skb; -+ dma_addr_t rx_dma; -+ unsigned int pad; -+}; -+ -+struct raeth_int_stats { -+ unsigned long rx_delayed; -+ unsigned long tx_delayed; -+ unsigned long rx_done0; -+ unsigned long tx_done0; -+ unsigned long tx_done1; -+ unsigned long tx_done2; -+ unsigned long tx_done3; -+ unsigned long rx_coherent; -+ unsigned long tx_coherent; -+ -+ unsigned long pse_fq_empty; -+ unsigned long pse_p0_fc; -+ unsigned long pse_p1_fc; -+ unsigned long pse_p2_fc; -+ unsigned long pse_buf_drop; -+ -+ unsigned long total; -+}; -+ -+struct raeth_debug { -+ struct dentry *debugfs_dir; -+ -+ struct raeth_int_stats int_stats; -+}; -+ -+struct raeth_priv -+{ -+ struct device_node *of_node; -+ -+ struct raeth_rx_info *rx_info; -+ dma_addr_t rx_desc_dma; -+ struct tasklet_struct rx_tasklet; -+ struct ramips_rx_dma *rx; -+ -+ struct raeth_tx_info *tx_info; -+ dma_addr_t tx_desc_dma; -+ struct tasklet_struct tx_housekeeping_tasklet; -+ struct ramips_tx_dma *tx; -+ -+ unsigned int skb_free_idx; -+ -+ spinlock_t page_lock; -+ struct net_device *netdev; -+ struct device *parent; -+ -+ int link; -+ int speed; -+ int duplex; -+ int tx_fc; -+ int rx_fc; -+ -+ struct mii_bus *mii_bus; -+ int mii_irq[PHY_MAX_ADDR]; -+ struct phy_device *phy_dev; -+ spinlock_t phy_lock; -+ unsigned long sys_freq; -+ -+ unsigned char mac[6]; -+ void (*reset_fe)(void); -+ int min_pkt_len; -+ -+ u32 phy_mask; -+ phy_interface_t phy_if_mode; -+ -+#ifdef CONFIG_NET_RAMIPS_DEBUG_FS -+ struct raeth_debug debug; -+#endif -+}; -+ -+struct ramips_soc_data -+{ -+ unsigned char mac[6]; -+ void (*reset_fe)(void); -+ int min_pkt_len; -+}; -+ -+ -+#ifdef CONFIG_NET_RAMIPS_DEBUG_FS -+int raeth_debugfs_root_init(void); -+void raeth_debugfs_root_exit(void); -+int raeth_debugfs_init(struct raeth_priv *re); -+void raeth_debugfs_exit(struct raeth_priv *re); -+void raeth_debugfs_update_int_stats(struct raeth_priv *re, u32 status); -+#else -+static inline int raeth_debugfs_root_init(void) { return 0; } -+static inline void raeth_debugfs_root_exit(void) {} -+static inline int raeth_debugfs_init(struct raeth_priv *re) { return 0; } -+static inline void raeth_debugfs_exit(struct raeth_priv *re) {} -+static inline void raeth_debugfs_update_int_stats(struct raeth_priv *re, -+ u32 status) {} -+#endif /* CONFIG_NET_RAMIPS_DEBUG_FS */ -+ -+#endif /* RAMIPS_ETH_H */ ---- /dev/null -+++ b/drivers/net/ethernet/ramips/ramips_main.c -@@ -0,0 +1,1281 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public 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) 2009 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/types.h> -+#include <linux/dma-mapping.h> -+#include <linux/init.h> -+#include <linux/skbuff.h> -+#include <linux/etherdevice.h> -+#include <linux/ethtool.h> -+#include <linux/platform_device.h> -+#include <linux/phy.h> -+#include <linux/of_device.h> -+#include <linux/clk.h> -+#include <linux/of_net.h> -+#include <linux/of_mdio.h> -+ -+#include "ramips_eth.h" -+ -+#define TX_TIMEOUT (20 * HZ / 100) -+#define MAX_RX_LENGTH 1600 -+ -+#ifdef CONFIG_SOC_RT305X -+#include <rt305x.h> -+#include "ramips_esw.c" -+#else -+#include <asm/mach-ralink/ralink_regs.h> -+static inline int rt305x_esw_init(void) { return 0; } -+static inline void rt305x_esw_exit(void) { } -+static inline int soc_is_rt5350(void) { return 0; } -+#endif -+ -+#define phys_to_bus(a) (a & 0x1FFFFFFF) -+ -+#ifdef CONFIG_NET_RAMIPS_DEBUG -+#define RADEBUG(fmt, args...) printk(KERN_DEBUG fmt, ## args) -+#else -+#define RADEBUG(fmt, args...) do {} while (0) -+#endif -+ -+#define RX_DLY_INT ((soc_is_rt5350())?(RT5350_RX_DLY_INT):(RAMIPS_RX_DLY_INT)) -+#define TX_DLY_INT ((soc_is_rt5350())?(RT5350_TX_DLY_INT):(RAMIPS_TX_DLY_INT)) -+ -+enum raeth_reg { -+ RAETH_REG_PDMA_GLO_CFG = 0, -+ RAETH_REG_PDMA_RST_CFG, -+ RAETH_REG_DLY_INT_CFG, -+ RAETH_REG_TX_BASE_PTR0, -+ RAETH_REG_TX_MAX_CNT0, -+ RAETH_REG_TX_CTX_IDX0, -+ RAETH_REG_RX_BASE_PTR0, -+ RAETH_REG_RX_MAX_CNT0, -+ RAETH_REG_RX_CALC_IDX0, -+ RAETH_REG_FE_INT_ENABLE, -+ RAETH_REG_FE_INT_STATUS, -+ RAETH_REG_COUNT -+}; -+ -+static const u32 ramips_reg_table[RAETH_REG_COUNT] = { -+ [RAETH_REG_PDMA_GLO_CFG] = RAMIPS_PDMA_GLO_CFG, -+ [RAETH_REG_PDMA_RST_CFG] = RAMIPS_PDMA_RST_CFG, -+ [RAETH_REG_DLY_INT_CFG] = RAMIPS_DLY_INT_CFG, -+ [RAETH_REG_TX_BASE_PTR0] = RAMIPS_TX_BASE_PTR0, -+ [RAETH_REG_TX_MAX_CNT0] = RAMIPS_TX_MAX_CNT0, -+ [RAETH_REG_TX_CTX_IDX0] = RAMIPS_TX_CTX_IDX0, -+ [RAETH_REG_RX_BASE_PTR0] = RAMIPS_RX_BASE_PTR0, -+ [RAETH_REG_RX_MAX_CNT0] = RAMIPS_RX_MAX_CNT0, -+ [RAETH_REG_RX_CALC_IDX0] = RAMIPS_RX_CALC_IDX0, -+ [RAETH_REG_FE_INT_ENABLE] = RAMIPS_FE_INT_ENABLE, -+ [RAETH_REG_FE_INT_STATUS] = RAMIPS_FE_INT_STATUS, -+}; -+ -+static const u32 rt5350_reg_table[RAETH_REG_COUNT] = { -+ [RAETH_REG_PDMA_GLO_CFG] = RT5350_PDMA_GLO_CFG, -+ [RAETH_REG_PDMA_RST_CFG] = RT5350_PDMA_RST_CFG, -+ [RAETH_REG_DLY_INT_CFG] = RT5350_DLY_INT_CFG, -+ [RAETH_REG_TX_BASE_PTR0] = RT5350_TX_BASE_PTR0, -+ [RAETH_REG_TX_MAX_CNT0] = RT5350_TX_MAX_CNT0, -+ [RAETH_REG_TX_CTX_IDX0] = RT5350_TX_CTX_IDX0, -+ [RAETH_REG_RX_BASE_PTR0] = RT5350_RX_BASE_PTR0, -+ [RAETH_REG_RX_MAX_CNT0] = RT5350_RX_MAX_CNT0, -+ [RAETH_REG_RX_CALC_IDX0] = RT5350_RX_CALC_IDX0, -+ [RAETH_REG_FE_INT_ENABLE] = RT5350_FE_INT_ENABLE, -+ [RAETH_REG_FE_INT_STATUS] = RT5350_FE_INT_STATUS, -+}; -+ -+static struct net_device * ramips_dev; -+static void __iomem *ramips_fe_base = 0; -+ -+static inline u32 get_reg_offset(enum raeth_reg reg) -+{ -+ const u32 *table; -+ -+ if (soc_is_rt5350()) -+ table = rt5350_reg_table; -+ else -+ table = ramips_reg_table; -+ -+ return table[reg]; -+} -+ -+static inline void -+ramips_fe_wr(u32 val, unsigned reg) -+{ -+ __raw_writel(val, ramips_fe_base + reg); -+} -+ -+static inline u32 -+ramips_fe_rr(unsigned reg) -+{ -+ return __raw_readl(ramips_fe_base + reg); -+} -+ -+static inline void -+ramips_fe_twr(u32 val, enum raeth_reg reg) -+{ -+ ramips_fe_wr(val, get_reg_offset(reg)); -+} -+ -+static inline u32 -+ramips_fe_trr(enum raeth_reg reg) -+{ -+ return ramips_fe_rr(get_reg_offset(reg)); -+} -+ -+static inline void -+ramips_fe_int_disable(u32 mask) -+{ -+ ramips_fe_twr(ramips_fe_trr(RAETH_REG_FE_INT_ENABLE) & ~mask, -+ RAETH_REG_FE_INT_ENABLE); -+ /* flush write */ -+ ramips_fe_trr(RAETH_REG_FE_INT_ENABLE); -+} -+ -+static inline void -+ramips_fe_int_enable(u32 mask) -+{ -+ ramips_fe_twr(ramips_fe_trr(RAETH_REG_FE_INT_ENABLE) | mask, -+ RAETH_REG_FE_INT_ENABLE); -+ /* flush write */ -+ ramips_fe_trr(RAETH_REG_FE_INT_ENABLE); -+} -+ -+static inline void -+ramips_hw_set_macaddr(unsigned char *mac) -+{ -+ if (soc_is_rt5350()) { -+ ramips_fe_wr((mac[0] << 8) | mac[1], RT5350_SDM_MAC_ADRH); -+ ramips_fe_wr((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], -+ RT5350_SDM_MAC_ADRL); -+ } else { -+ ramips_fe_wr((mac[0] << 8) | mac[1], RAMIPS_GDMA1_MAC_ADRH); -+ ramips_fe_wr((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], -+ RAMIPS_GDMA1_MAC_ADRL); -+ } -+} -+ -+static struct sk_buff * -+ramips_alloc_skb(struct raeth_priv *re) -+{ -+ struct sk_buff *skb; -+ -+ skb = netdev_alloc_skb(re->netdev, MAX_RX_LENGTH + NET_IP_ALIGN); -+ if (!skb) -+ return NULL; -+ -+ skb_reserve(skb, NET_IP_ALIGN); -+ -+ return skb; -+} -+ -+static void -+ramips_ring_setup(struct raeth_priv *re) -+{ -+ int len; -+ int i; -+ -+ memset(re->tx_info, 0, NUM_TX_DESC * sizeof(struct raeth_tx_info)); -+ -+ len = NUM_TX_DESC * sizeof(struct ramips_tx_dma); -+ memset(re->tx, 0, len); -+ -+ for (i = 0; i < NUM_TX_DESC; i++) { -+ struct raeth_tx_info *txi; -+ struct ramips_tx_dma *txd; -+ -+ txd = &re->tx[i]; -+ txd->txd4 = TX_DMA_QN(3) | TX_DMA_PN(1); -+ txd->txd2 = TX_DMA_LSO | TX_DMA_DONE; -+ -+ txi = &re->tx_info[i]; -+ txi->tx_desc = txd; -+ if (txi->tx_skb != NULL) { -+ netdev_warn(re->netdev, -+ "dirty skb for TX desc %d\n", i); -+ txi->tx_skb = NULL; -+ } -+ } -+ -+ len = NUM_RX_DESC * sizeof(struct ramips_rx_dma); -+ memset(re->rx, 0, len); -+ -+ for (i = 0; i < NUM_RX_DESC; i++) { -+ struct raeth_rx_info *rxi; -+ struct ramips_rx_dma *rxd; -+ dma_addr_t dma_addr; -+ -+ rxd = &re->rx[i]; -+ rxi = &re->rx_info[i]; -+ BUG_ON(rxi->rx_skb == NULL); -+ dma_addr = dma_map_single(&re->netdev->dev, rxi->rx_skb->data, -+ MAX_RX_LENGTH, DMA_FROM_DEVICE); -+ rxi->rx_dma = dma_addr; -+ rxi->rx_desc = rxd; -+ -+ rxd->rxd1 = (unsigned int) dma_addr; -+ rxd->rxd2 = RX_DMA_LSO; -+ } -+ -+ /* flush descriptors */ -+ wmb(); -+} -+ -+static void -+ramips_ring_cleanup(struct raeth_priv *re) -+{ -+ int i; -+ -+ for (i = 0; i < NUM_RX_DESC; i++) { -+ struct raeth_rx_info *rxi; -+ -+ rxi = &re->rx_info[i]; -+ if (rxi->rx_skb) -+ dma_unmap_single(&re->netdev->dev, rxi->rx_dma, -+ MAX_RX_LENGTH, DMA_FROM_DEVICE); -+ } -+ -+ for (i = 0; i < NUM_TX_DESC; i++) { -+ struct raeth_tx_info *txi; -+ -+ txi = &re->tx_info[i]; -+ if (txi->tx_skb) { -+ dev_kfree_skb_any(txi->tx_skb); -+ txi->tx_skb = NULL; -+ } -+ } -+ -+ netdev_reset_queue(re->netdev); -+} -+ -+#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT3883) -+ -+#define RAMIPS_MDIO_RETRY 1000 -+ -+static unsigned char *ramips_speed_str(struct raeth_priv *re) -+{ -+ switch (re->speed) { -+ case SPEED_1000: -+ return "1000"; -+ case SPEED_100: -+ return "100"; -+ case SPEED_10: -+ return "10"; -+ } -+ -+ return "?"; -+} -+ -+static void ramips_link_adjust(struct raeth_priv *re) -+{ -+ u32 mdio_cfg; -+ -+ if (!re->link) { -+ netif_carrier_off(re->netdev); -+ netdev_info(re->netdev, "link down\n"); -+ return; -+ } -+ -+ mdio_cfg = RAMIPS_MDIO_CFG_TX_CLK_SKEW_200 | -+ RAMIPS_MDIO_CFG_RX_CLK_SKEW_200 | -+ RAMIPS_MDIO_CFG_GP1_FRC_EN; -+ -+ if (re->duplex == DUPLEX_FULL) -+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_DUPLEX; -+ -+ if (re->tx_fc) -+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_FC_TX; -+ -+ if (re->rx_fc) -+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_FC_RX; -+ -+ switch (re->speed) { -+ case SPEED_10: -+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_SPEED_10; -+ break; -+ case SPEED_100: -+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_SPEED_100; -+ break; -+ case SPEED_1000: -+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_SPEED_1000; -+ break; -+ default: -+ BUG(); -+ } -+ -+ ramips_fe_wr(mdio_cfg, RAMIPS_MDIO_CFG); -+ -+ netif_carrier_on(re->netdev); -+ netdev_info(re->netdev, "link up (%sMbps/%s duplex)\n", -+ ramips_speed_str(re), -+ (DUPLEX_FULL == re->duplex) ? "Full" : "Half"); -+} -+ -+static int -+ramips_mdio_wait_ready(struct raeth_priv *re) -+{ -+ int retries; -+ -+ retries = RAMIPS_MDIO_RETRY; -+ while (1) { -+ u32 t; -+ -+ t = ramips_fe_rr(RAMIPS_MDIO_ACCESS); -+ if ((t & (0x1 << 31)) == 0) -+ return 0; -+ -+ if (retries-- == 0) -+ break; -+ -+ udelay(1); -+ } -+ -+ dev_err(re->parent, "MDIO operation timed out\n"); -+ return -ETIMEDOUT; -+} -+ -+static int -+ramips_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) -+{ -+ struct raeth_priv *re = bus->priv; -+ int err; -+ u32 t; -+ -+ err = ramips_mdio_wait_ready(re); -+ if (err) -+ return 0xffff; -+ -+ t = (phy_addr << 24) | (phy_reg << 16); -+ ramips_fe_wr(t, RAMIPS_MDIO_ACCESS); -+ t |= (1 << 31); -+ ramips_fe_wr(t, RAMIPS_MDIO_ACCESS); -+ -+ err = ramips_mdio_wait_ready(re); -+ if (err) -+ return 0xffff; -+ -+ RADEBUG("%s: addr=%04x, reg=%04x, value=%04x\n", __func__, -+ phy_addr, phy_reg, ramips_fe_rr(RAMIPS_MDIO_ACCESS) & 0xffff); -+ -+ return ramips_fe_rr(RAMIPS_MDIO_ACCESS) & 0xffff; -+} -+ -+static int -+ramips_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val) -+{ -+ struct raeth_priv *re = bus->priv; -+ int err; -+ u32 t; -+ -+ RADEBUG("%s: addr=%04x, reg=%04x, value=%04x\n", __func__, -+ phy_addr, phy_reg, ramips_fe_rr(RAMIPS_MDIO_ACCESS) & 0xffff); -+ -+ err = ramips_mdio_wait_ready(re); -+ if (err) -+ return err; -+ -+ t = (1 << 30) | (phy_addr << 24) | (phy_reg << 16) | val; -+ ramips_fe_wr(t, RAMIPS_MDIO_ACCESS); -+ t |= (1 << 31); -+ ramips_fe_wr(t, RAMIPS_MDIO_ACCESS); -+ -+ return ramips_mdio_wait_ready(re); -+} -+ -+static int -+ramips_mdio_reset(struct mii_bus *bus) -+{ -+ /* TODO */ -+ return 0; -+} -+ -+static int -+ramips_mdio_init(struct raeth_priv *re) -+{ -+ struct device_node *mii_np; -+ int err; -+ -+ mii_np = of_get_child_by_name(re->of_node, "mdio-bus"); -+ if (!mii_np) { -+ dev_err(re->parent, "no %s child node found", "mdio-bus"); -+ return -ENODEV; -+ } -+ -+ if (!of_device_is_available(mii_np)) { -+ err = 0; -+ goto err_put_node; -+ } -+ -+ re->mii_bus = mdiobus_alloc(); -+ if (re->mii_bus == NULL) { -+ err = -ENOMEM; -+ goto err_put_node; -+ } -+ -+ re->mii_bus->name = "ramips_mdio"; -+ re->mii_bus->read = ramips_mdio_read; -+ re->mii_bus->write = ramips_mdio_write; -+ re->mii_bus->reset = ramips_mdio_reset; -+ re->mii_bus->irq = re->mii_irq; -+ re->mii_bus->priv = re; -+ re->mii_bus->parent = re->parent; -+ -+ snprintf(re->mii_bus->id, MII_BUS_ID_SIZE, "%s", "ramips_mdio"); -+ err = of_mdiobus_register(re->mii_bus, mii_np); -+ if (err) -+ goto err_free_bus; -+ -+ return 0; -+ -+err_free_bus: -+ kfree(re->mii_bus); -+err_put_node: -+ of_node_put(mii_np); -+ re->mii_bus = NULL; -+ return err; -+} -+ -+static void -+ramips_mdio_cleanup(struct raeth_priv *re) -+{ -+ if (!re->mii_bus) -+ return; -+ -+ mdiobus_unregister(re->mii_bus); -+ of_node_put(re->mii_bus->dev.of_node); -+ kfree(re->mii_bus); -+} -+ -+static void -+ramips_phy_link_adjust(struct net_device *dev) -+{ -+ struct raeth_priv *re = netdev_priv(dev); -+ struct phy_device *phydev = re->phy_dev; -+ unsigned long flags; -+ int status_change = 0; -+ -+ spin_lock_irqsave(&re->phy_lock, flags); -+ -+ if (phydev->link) -+ if (re->duplex != phydev->duplex || -+ re->speed != phydev->speed) -+ status_change = 1; -+ -+ if (phydev->link != re->link) -+ status_change = 1; -+ -+ re->link = phydev->link; -+ re->duplex = phydev->duplex; -+ re->speed = phydev->speed; -+ -+ if (status_change) -+ ramips_link_adjust(re); -+ -+ spin_unlock_irqrestore(&re->phy_lock, flags); -+} -+ -+static int -+ramips_phy_connect_by_node(struct raeth_priv *re, struct device_node *phy_node) -+{ -+ struct phy_device *phydev; -+ int phy_mode; -+ -+ phy_mode = of_get_phy_mode(re->of_node); -+ if (phy_mode < 0) { -+ dev_err(re->parent, "incorrect phy-mode\n"); -+ return -EINVAL; -+ } -+ -+ phydev = of_phy_connect(re->netdev, phy_node, ramips_phy_link_adjust, -+ 0, phy_mode); -+ if (IS_ERR(phydev)) { -+ dev_err(re->parent, "could not connect to PHY\n"); -+ return PTR_ERR(re->phy_dev); -+ } -+ -+ phydev->supported &= PHY_GBIT_FEATURES; -+ phydev->advertising = phydev->supported; -+ -+ dev_info(re->parent, -+ "connected to PHY at %s [uid=%08x, driver=%s]\n", -+ dev_name(&phydev->dev), phydev->phy_id, -+ phydev->drv->name); -+ -+ re->phy_dev = phydev; -+ re->link = 0; -+ re->speed = 0; -+ re->duplex = -1; -+ re->rx_fc = 0; -+ re->tx_fc = 0; -+ -+ return 0; -+} -+ -+static int -+ramips_phy_connect_fixed(struct raeth_priv *re, const __be32 *link, int size) -+{ -+ if (size != (4 * sizeof(*link))) { -+ dev_err(re->parent, "invalid fixed-link property\n"); -+ return -EINVAL; -+ } -+ -+ re->speed = be32_to_cpup(link++); -+ re->duplex = be32_to_cpup(link++); -+ re->tx_fc = be32_to_cpup(link++); -+ re->rx_fc = be32_to_cpup(link++); -+ -+ switch (re->speed) { -+ case SPEED_10: -+ case SPEED_100: -+ case SPEED_1000: -+ break; -+ default: -+ dev_err(re->parent, "invalid link speed: %d\n", re->speed); -+ return -EINVAL; -+ } -+ -+ dev_info(re->parent, "using fixed link parameters\n"); -+ return 0; -+} -+ -+static int -+ramips_phy_connect(struct raeth_priv *re) -+{ -+ struct device_node *phy_node; -+ const __be32 *p32; -+ int size; -+ -+ phy_node = of_parse_phandle(re->of_node, "phy-handle", 0); -+ if (phy_node) -+ return ramips_phy_connect_by_node(re, phy_node); -+ -+ p32 = of_get_property(re->of_node, "ralink,fixed-link", &size); -+ if (p32) -+ return ramips_phy_connect_fixed(re, p32, size); -+ -+ dev_err(re->parent, "unable to get connection type\n"); -+ return -EINVAL; -+} -+ -+static void -+ramips_phy_disconnect(struct raeth_priv *re) -+{ -+ if (re->phy_dev) -+ phy_disconnect(re->phy_dev); -+} -+ -+static void -+ramips_phy_start(struct raeth_priv *re) -+{ -+ unsigned long flags; -+ -+ if (re->phy_dev) { -+ phy_start(re->phy_dev); -+ } else { -+ spin_lock_irqsave(&re->phy_lock, flags); -+ re->link = 1; -+ ramips_link_adjust(re); -+ spin_unlock_irqrestore(&re->phy_lock, flags); -+ } -+} -+ -+static void -+ramips_phy_stop(struct raeth_priv *re) -+{ -+ unsigned long flags; -+ -+ if (re->phy_dev) -+ phy_stop(re->phy_dev); -+ -+ spin_lock_irqsave(&re->phy_lock, flags); -+ re->link = 0; -+ ramips_link_adjust(re); -+ spin_unlock_irqrestore(&re->phy_lock, flags); -+} -+#else -+static inline int -+ramips_mdio_init(struct raeth_priv *re) -+{ -+ return 0; -+} -+ -+static inline void -+ramips_mdio_cleanup(struct raeth_priv *re) -+{ -+} -+ -+static inline int -+ramips_phy_connect(struct raeth_priv *re) -+{ -+ return 0; -+} -+ -+static inline void -+ramips_phy_disconnect(struct raeth_priv *re) -+{ -+} -+ -+static inline void -+ramips_phy_start(struct raeth_priv *re) -+{ -+} -+ -+static inline void -+ramips_phy_stop(struct raeth_priv *re) -+{ -+} -+#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT3883 */ -+ -+static void -+ramips_ring_free(struct raeth_priv *re) -+{ -+ int len; -+ int i; -+ -+ if (re->rx_info) { -+ for (i = 0; i < NUM_RX_DESC; i++) { -+ struct raeth_rx_info *rxi; -+ -+ rxi = &re->rx_info[i]; -+ if (rxi->rx_skb) -+ dev_kfree_skb_any(rxi->rx_skb); -+ } -+ kfree(re->rx_info); -+ } -+ -+ if (re->rx) { -+ len = NUM_RX_DESC * sizeof(struct ramips_rx_dma); -+ dma_free_coherent(&re->netdev->dev, len, re->rx, -+ re->rx_desc_dma); -+ } -+ -+ if (re->tx) { -+ len = NUM_TX_DESC * sizeof(struct ramips_tx_dma); -+ dma_free_coherent(&re->netdev->dev, len, re->tx, -+ re->tx_desc_dma); -+ } -+ -+ kfree(re->tx_info); -+} -+ -+static int -+ramips_ring_alloc(struct raeth_priv *re) -+{ -+ int len; -+ int err = -ENOMEM; -+ int i; -+ -+ re->tx_info = kzalloc(NUM_TX_DESC * sizeof(struct raeth_tx_info), -+ GFP_ATOMIC); -+ if (!re->tx_info) -+ goto err_cleanup; -+ -+ re->rx_info = kzalloc(NUM_RX_DESC * sizeof(struct raeth_rx_info), -+ GFP_ATOMIC); -+ if (!re->rx_info) -+ goto err_cleanup; -+ -+ /* allocate tx ring */ -+ len = NUM_TX_DESC * sizeof(struct ramips_tx_dma); -+ re->tx = dma_alloc_coherent(&re->netdev->dev, len, -+ &re->tx_desc_dma, GFP_ATOMIC); -+ if (!re->tx) -+ goto err_cleanup; -+ -+ /* allocate rx ring */ -+ len = NUM_RX_DESC * sizeof(struct ramips_rx_dma); -+ re->rx = dma_alloc_coherent(&re->netdev->dev, len, -+ &re->rx_desc_dma, GFP_ATOMIC); -+ if (!re->rx) -+ goto err_cleanup; -+ -+ for (i = 0; i < NUM_RX_DESC; i++) { -+ struct sk_buff *skb; -+ -+ skb = ramips_alloc_skb(re); -+ if (!skb) -+ goto err_cleanup; -+ -+ re->rx_info[i].rx_skb = skb; -+ } -+ -+ return 0; -+ -+err_cleanup: -+ ramips_ring_free(re); -+ return err; -+} -+ -+static void -+ramips_setup_dma(struct raeth_priv *re) -+{ -+ ramips_fe_twr(re->tx_desc_dma, RAETH_REG_TX_BASE_PTR0); -+ ramips_fe_twr(NUM_TX_DESC, RAETH_REG_TX_MAX_CNT0); -+ ramips_fe_twr(0, RAETH_REG_TX_CTX_IDX0); -+ ramips_fe_twr(RAMIPS_PST_DTX_IDX0, RAETH_REG_PDMA_RST_CFG); -+ -+ ramips_fe_twr(re->rx_desc_dma, RAETH_REG_RX_BASE_PTR0); -+ ramips_fe_twr(NUM_RX_DESC, RAETH_REG_RX_MAX_CNT0); -+ ramips_fe_twr((NUM_RX_DESC - 1), RAETH_REG_RX_CALC_IDX0); -+ ramips_fe_twr(RAMIPS_PST_DRX_IDX0, RAETH_REG_PDMA_RST_CFG); -+} -+ -+static int -+ramips_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct raeth_priv *re = netdev_priv(dev); -+ struct raeth_tx_info *txi, *txi_next; -+ struct ramips_tx_dma *txd, *txd_next; -+ unsigned long tx; -+ unsigned int tx_next; -+ dma_addr_t mapped_addr; -+ -+ if (re->min_pkt_len) { -+ if (skb->len < re->min_pkt_len) { -+ if (skb_padto(skb, re->min_pkt_len)) { -+ printk(KERN_ERR -+ "ramips_eth: skb_padto failed\n"); -+ kfree_skb(skb); -+ return 0; -+ } -+ skb_put(skb, re->min_pkt_len - skb->len); -+ } -+ } -+ -+ dev->trans_start = jiffies; -+ mapped_addr = dma_map_single(&re->netdev->dev, skb->data, skb->len, -+ DMA_TO_DEVICE); -+ -+ spin_lock(&re->page_lock); -+ tx = ramips_fe_trr(RAETH_REG_TX_CTX_IDX0); -+ tx_next = (tx + 1) % NUM_TX_DESC; -+ -+ txi = &re->tx_info[tx]; -+ txd = txi->tx_desc; -+ txi_next = &re->tx_info[tx_next]; -+ txd_next = txi_next->tx_desc; -+ -+ if ((txi->tx_skb) || (txi_next->tx_skb) || -+ !(txd->txd2 & TX_DMA_DONE) || -+ !(txd_next->txd2 & TX_DMA_DONE)) -+ goto out; -+ -+ txi->tx_skb = skb; -+ -+ txd->txd1 = (unsigned int) mapped_addr; -+ wmb(); -+ txd->txd2 = TX_DMA_LSO | TX_DMA_PLEN0(skb->len); -+ dev->stats.tx_packets++; -+ dev->stats.tx_bytes += skb->len; -+ ramips_fe_twr(tx_next, RAETH_REG_TX_CTX_IDX0); -+ netdev_sent_queue(dev, skb->len); -+ spin_unlock(&re->page_lock); -+ return NETDEV_TX_OK; -+ -+ out: -+ spin_unlock(&re->page_lock); -+ dev->stats.tx_dropped++; -+ kfree_skb(skb); -+ return NETDEV_TX_OK; -+} -+ -+static void -+ramips_eth_rx_hw(unsigned long ptr) -+{ -+ struct net_device *dev = (struct net_device *) ptr; -+ struct raeth_priv *re = netdev_priv(dev); -+ int rx; -+ int max_rx = 16; -+ -+ rx = ramips_fe_trr(RAETH_REG_RX_CALC_IDX0); -+ -+ while (max_rx) { -+ struct raeth_rx_info *rxi; -+ struct ramips_rx_dma *rxd; -+ struct sk_buff *rx_skb, *new_skb; -+ int pktlen; -+ -+ rx = (rx + 1) % NUM_RX_DESC; -+ -+ rxi = &re->rx_info[rx]; -+ rxd = rxi->rx_desc; -+ if (!(rxd->rxd2 & RX_DMA_DONE)) -+ break; -+ -+ rx_skb = rxi->rx_skb; -+ pktlen = RX_DMA_PLEN0(rxd->rxd2); -+ -+ new_skb = ramips_alloc_skb(re); -+ /* Reuse the buffer on allocation failures */ -+ if (new_skb) { -+ dma_addr_t dma_addr; -+ -+ dma_unmap_single(&re->netdev->dev, rxi->rx_dma, -+ MAX_RX_LENGTH, DMA_FROM_DEVICE); -+ -+ skb_put(rx_skb, pktlen); -+ rx_skb->dev = dev; -+ rx_skb->protocol = eth_type_trans(rx_skb, dev); -+ rx_skb->ip_summed = CHECKSUM_NONE; -+ dev->stats.rx_packets++; -+ dev->stats.rx_bytes += pktlen; -+ netif_rx(rx_skb); -+ -+ rxi->rx_skb = new_skb; -+ -+ dma_addr = dma_map_single(&re->netdev->dev, -+ new_skb->data, -+ MAX_RX_LENGTH, -+ DMA_FROM_DEVICE); -+ rxi->rx_dma = dma_addr; -+ rxd->rxd1 = (unsigned int) dma_addr; -+ wmb(); -+ } else { -+ dev->stats.rx_dropped++; -+ } -+ -+ rxd->rxd2 = RX_DMA_LSO; -+ ramips_fe_twr(rx, RAETH_REG_RX_CALC_IDX0); -+ max_rx--; -+ } -+ -+ if (max_rx == 0) -+ tasklet_schedule(&re->rx_tasklet); -+ else -+ ramips_fe_int_enable(RX_DLY_INT); -+} -+ -+static void -+ramips_eth_tx_housekeeping(unsigned long ptr) -+{ -+ struct net_device *dev = (struct net_device*)ptr; -+ struct raeth_priv *re = netdev_priv(dev); -+ unsigned int bytes_compl = 0, pkts_compl = 0; -+ -+ spin_lock(&re->page_lock); -+ while (1) { -+ struct raeth_tx_info *txi; -+ struct ramips_tx_dma *txd; -+ -+ txi = &re->tx_info[re->skb_free_idx]; -+ txd = txi->tx_desc; -+ -+ if (!(txd->txd2 & TX_DMA_DONE) || !(txi->tx_skb)) -+ break; -+ -+ pkts_compl++; -+ bytes_compl += txi->tx_skb->len; -+ -+ dev_kfree_skb_irq(txi->tx_skb); -+ txi->tx_skb = NULL; -+ re->skb_free_idx++; -+ if (re->skb_free_idx >= NUM_TX_DESC) -+ re->skb_free_idx = 0; -+ } -+ netdev_completed_queue(dev, pkts_compl, bytes_compl); -+ spin_unlock(&re->page_lock); -+ -+ ramips_fe_int_enable(TX_DLY_INT); -+} -+ -+static void -+ramips_eth_timeout(struct net_device *dev) -+{ -+ struct raeth_priv *re = netdev_priv(dev); -+ -+ tasklet_schedule(&re->tx_housekeeping_tasklet); -+} -+ -+static irqreturn_t -+ramips_eth_irq(int irq, void *dev) -+{ -+ struct raeth_priv *re = netdev_priv(dev); -+ unsigned int status; -+ -+ status = ramips_fe_trr(RAETH_REG_FE_INT_STATUS); -+ status &= ramips_fe_trr(RAETH_REG_FE_INT_ENABLE); -+ -+ if (!status) -+ return IRQ_NONE; -+ -+ ramips_fe_twr(status, RAETH_REG_FE_INT_STATUS); -+ -+ if (status & RX_DLY_INT) { -+ ramips_fe_int_disable(RX_DLY_INT); -+ tasklet_schedule(&re->rx_tasklet); -+ } -+ -+ if (status & TX_DLY_INT) { -+ ramips_fe_int_disable(TX_DLY_INT); -+ tasklet_schedule(&re->tx_housekeeping_tasklet); -+ } -+ -+ raeth_debugfs_update_int_stats(re, status); -+ -+ return IRQ_HANDLED; -+} -+ -+static int -+ramips_eth_hw_init(struct net_device *dev) -+{ -+ struct raeth_priv *re = netdev_priv(dev); -+ int err; -+ -+ err = request_irq(dev->irq, ramips_eth_irq, IRQF_DISABLED, -+ dev_name(re->parent), dev); -+ if (err) -+ return err; -+ -+ err = ramips_ring_alloc(re); -+ if (err) -+ goto err_free_irq; -+ -+ ramips_ring_setup(re); -+ ramips_hw_set_macaddr(dev->dev_addr); -+ -+ ramips_setup_dma(re); -+ ramips_fe_wr((ramips_fe_rr(RAMIPS_FE_GLO_CFG) & -+ ~(RAMIPS_US_CYC_CNT_MASK << RAMIPS_US_CYC_CNT_SHIFT)) | -+ ((re->sys_freq / RAMIPS_US_CYC_CNT_DIVISOR) << RAMIPS_US_CYC_CNT_SHIFT), -+ RAMIPS_FE_GLO_CFG); -+ -+ tasklet_init(&re->tx_housekeeping_tasklet, ramips_eth_tx_housekeeping, -+ (unsigned long)dev); -+ tasklet_init(&re->rx_tasklet, ramips_eth_rx_hw, (unsigned long)dev); -+ -+ -+ ramips_fe_twr(RAMIPS_DELAY_INIT, RAETH_REG_DLY_INT_CFG); -+ ramips_fe_twr(TX_DLY_INT | RX_DLY_INT, RAETH_REG_FE_INT_ENABLE); -+ if (soc_is_rt5350()) { -+ ramips_fe_wr(ramips_fe_rr(RT5350_SDM_CFG) & -+ ~(RT5350_SDM_ICS_EN | RT5350_SDM_TCS_EN | RT5350_SDM_UCS_EN | 0xffff), -+ RT5350_SDM_CFG); -+ } else { -+ ramips_fe_wr(ramips_fe_rr(RAMIPS_GDMA1_FWD_CFG) & -+ ~(RAMIPS_GDM1_ICS_EN | RAMIPS_GDM1_TCS_EN | RAMIPS_GDM1_UCS_EN | 0xffff), -+ RAMIPS_GDMA1_FWD_CFG); -+ ramips_fe_wr(ramips_fe_rr(RAMIPS_CDMA_CSG_CFG) & -+ ~(RAMIPS_ICS_GEN_EN | RAMIPS_TCS_GEN_EN | RAMIPS_UCS_GEN_EN), -+ RAMIPS_CDMA_CSG_CFG); -+ ramips_fe_wr(RAMIPS_PSE_FQFC_CFG_INIT, RAMIPS_PSE_FQ_CFG); -+ } -+ ramips_fe_wr(1, RAMIPS_FE_RST_GL); -+ ramips_fe_wr(0, RAMIPS_FE_RST_GL); -+ -+ return 0; -+ -+err_free_irq: -+ free_irq(dev->irq, dev); -+ return err; -+} -+ -+static int -+ramips_eth_open(struct net_device *dev) -+{ -+ struct raeth_priv *re = netdev_priv(dev); -+ -+ ramips_fe_twr((ramips_fe_trr(RAETH_REG_PDMA_GLO_CFG) & 0xff) | -+ (RAMIPS_TX_WB_DDONE | RAMIPS_RX_DMA_EN | -+ RAMIPS_TX_DMA_EN | RAMIPS_PDMA_SIZE_4DWORDS), -+ RAETH_REG_PDMA_GLO_CFG); -+ ramips_phy_start(re); -+ netif_start_queue(dev); -+ return 0; -+} -+ -+static int -+ramips_eth_stop(struct net_device *dev) -+{ -+ struct raeth_priv *re = netdev_priv(dev); -+ -+ ramips_fe_twr(ramips_fe_trr(RAETH_REG_PDMA_GLO_CFG) & -+ ~(RAMIPS_TX_WB_DDONE | RAMIPS_RX_DMA_EN | RAMIPS_TX_DMA_EN), -+ RAETH_REG_PDMA_GLO_CFG); -+ -+ netif_stop_queue(dev); -+ ramips_phy_stop(re); -+ RADEBUG("ramips_eth: stopped\n"); -+ return 0; -+} -+ -+static int __init -+ramips_eth_probe(struct net_device *dev) -+{ -+ struct raeth_priv *re = netdev_priv(dev); -+ int err; -+ -+ BUG_ON(!re->reset_fe); -+ re->reset_fe(); -+ net_srandom(jiffies); -+ memcpy(dev->dev_addr, re->mac, ETH_ALEN); -+ of_get_mac_address_mtd(re->of_node, dev->dev_addr); -+ ether_setup(dev); -+ dev->mtu = 1500; -+ dev->watchdog_timeo = TX_TIMEOUT; -+ spin_lock_init(&re->page_lock); -+ spin_lock_init(&re->phy_lock); -+ -+ err = ramips_mdio_init(re); -+ if (err) -+ return err; -+ -+ err = ramips_phy_connect(re); -+ if (err) -+ goto err_mdio_cleanup; -+ -+ err = raeth_debugfs_init(re); -+ if (err) -+ goto err_phy_disconnect; -+ -+ err = ramips_eth_hw_init(dev); -+ if (err) -+ goto err_debugfs; -+ -+ return 0; -+ -+err_debugfs: -+ raeth_debugfs_exit(re); -+err_phy_disconnect: -+ ramips_phy_disconnect(re); -+err_mdio_cleanup: -+ ramips_mdio_cleanup(re); -+ return err; -+} -+ -+static void -+ramips_eth_uninit(struct net_device *dev) -+{ -+ struct raeth_priv *re = netdev_priv(dev); -+ -+ raeth_debugfs_exit(re); -+ ramips_phy_disconnect(re); -+ ramips_mdio_cleanup(re); -+ ramips_fe_twr(0, RAETH_REG_FE_INT_ENABLE); -+ free_irq(dev->irq, dev); -+ tasklet_kill(&re->tx_housekeeping_tasklet); -+ tasklet_kill(&re->rx_tasklet); -+ ramips_ring_cleanup(re); -+ ramips_ring_free(re); -+} -+ -+static const struct net_device_ops ramips_eth_netdev_ops = { -+ .ndo_init = ramips_eth_probe, -+ .ndo_uninit = ramips_eth_uninit, -+ .ndo_open = ramips_eth_open, -+ .ndo_stop = ramips_eth_stop, -+ .ndo_start_xmit = ramips_eth_hard_start_xmit, -+ .ndo_tx_timeout = ramips_eth_timeout, -+ .ndo_change_mtu = eth_change_mtu, -+ .ndo_set_mac_address = eth_mac_addr, -+ .ndo_validate_addr = eth_validate_addr, -+}; -+ -+#ifdef CONFIG_SOC_RT305X -+static void rt305x_fe_reset(void) -+{ -+#define RT305X_RESET_FE BIT(21) -+#define RT305X_RESET_ESW BIT(23) -+#define SYSC_REG_RESET_CTRL 0x034 -+ u32 reset_bits = RT305X_RESET_FE; -+ -+ if (soc_is_rt5350()) -+ reset_bits |= RT305X_RESET_ESW; -+ rt_sysc_w32(reset_bits, SYSC_REG_RESET_CTRL); -+ rt_sysc_w32(0, SYSC_REG_RESET_CTRL); -+} -+ -+struct ramips_soc_data rt3050_data = { -+ .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, -+ .reset_fe = rt305x_fe_reset, -+ .min_pkt_len = 64, -+}; -+ -+static const struct of_device_id ralink_eth_match[] = { -+ { .compatible = "ralink,rt3050-eth", .data = &rt3050_data }, -+ {}, -+}; -+#else -+static void rt3883_fe_reset(void) -+{ -+#define RT3883_SYSC_REG_RSTCTRL 0x34 -+#define RT3883_RSTCTRL_FE BIT(21) -+ u32 t; -+ -+ t = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL); -+ t |= RT3883_RSTCTRL_FE; -+ rt_sysc_w32(t , RT3883_SYSC_REG_RSTCTRL); -+ -+ t &= ~RT3883_RSTCTRL_FE; -+ rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL); -+} -+ -+struct ramips_soc_data rt3883_data = { -+ .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, -+ .reset_fe = rt3883_fe_reset, -+ .min_pkt_len = 64, -+}; -+ -+static const struct of_device_id ralink_eth_match[] = { -+ { .compatible = "ralink,rt3883-eth", .data = &rt3883_data }, -+ {}, -+}; -+#endif -+MODULE_DEVICE_TABLE(of, ralink_eth_match); -+ -+static int -+ramips_eth_plat_probe(struct platform_device *plat) -+{ -+ struct raeth_priv *re; -+ struct resource *res; -+ struct clk *clk; -+ int err; -+ const struct of_device_id *match; -+ const struct ramips_soc_data *soc = NULL; -+ -+ match = of_match_device(ralink_eth_match, &plat->dev); -+ if (match) -+ soc = (const struct ramips_soc_data *) match->data; -+ -+ if (!soc) { -+ dev_err(&plat->dev, "no platform data specified\n"); -+ return -EINVAL; -+ } -+ -+ res = platform_get_resource(plat, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&plat->dev, "no memory resource found\n"); -+ return -ENXIO; -+ } -+ -+ ramips_fe_base = ioremap_nocache(res->start, res->end - res->start + 1); -+ if (!ramips_fe_base) -+ return -ENOMEM; -+ -+ ramips_dev = alloc_etherdev(sizeof(struct raeth_priv)); -+ if (!ramips_dev) { -+ dev_err(&plat->dev, "alloc_etherdev failed\n"); -+ err = -ENOMEM; -+ goto err_unmap; -+ } -+ -+ strcpy(ramips_dev->name, "eth%d"); -+ ramips_dev->irq = platform_get_irq(plat, 0); -+ if (ramips_dev->irq < 0) { -+ dev_err(&plat->dev, "no IRQ resource found\n"); -+ err = -ENXIO; -+ goto err_free_dev; -+ } -+ ramips_dev->addr_len = ETH_ALEN; -+ ramips_dev->base_addr = (unsigned long)ramips_fe_base; -+ ramips_dev->netdev_ops = &ramips_eth_netdev_ops; -+ -+ re = netdev_priv(ramips_dev); -+ -+ clk = clk_get(&plat->dev, NULL); -+ if (IS_ERR(clk)) -+ panic("unable to get SYS clock, err=%ld", PTR_ERR(clk)); -+ re->sys_freq = clk_get_rate(clk); -+ -+ re->netdev = ramips_dev; -+ re->of_node = plat->dev.of_node; -+ re->parent = &plat->dev; -+ memcpy(re->mac, soc->mac, 6); -+ re->reset_fe = soc->reset_fe; -+ re->min_pkt_len = soc->min_pkt_len; -+ -+ err = register_netdev(ramips_dev); -+ if (err) { -+ dev_err(&plat->dev, "error bringing up device\n"); -+ goto err_free_dev; -+ } -+ -+ netdev_info(ramips_dev, "done loading\n"); -+ return 0; -+ -+ err_free_dev: -+ kfree(ramips_dev); -+ err_unmap: -+ iounmap(ramips_fe_base); -+ return err; -+} -+ -+static int -+ramips_eth_plat_remove(struct platform_device *plat) -+{ -+ unregister_netdev(ramips_dev); -+ free_netdev(ramips_dev); -+ RADEBUG("ramips_eth: unloaded\n"); -+ return 0; -+} -+ -+ -+ -+static struct platform_driver ramips_eth_driver = { -+ .probe = ramips_eth_plat_probe, -+ .remove = ramips_eth_plat_remove, -+ .driver = { -+ .name = "ramips_eth", -+ .owner = THIS_MODULE, -+ .of_match_table = ralink_eth_match -+ }, -+}; -+ -+static int __init -+ramips_eth_init(void) -+{ -+ int ret; -+ -+ ret = raeth_debugfs_root_init(); -+ if (ret) -+ goto err_out; -+ -+ ret = rt305x_esw_init(); -+ if (ret) -+ goto err_debugfs_exit; -+ -+ ret = platform_driver_register(&ramips_eth_driver); -+ if (ret) { -+ printk(KERN_ERR -+ "ramips_eth: Error registering platfom driver!\n"); -+ goto esw_cleanup; -+ } -+ -+ return 0; -+ -+esw_cleanup: -+ rt305x_esw_exit(); -+err_debugfs_exit: -+ raeth_debugfs_root_exit(); -+err_out: -+ return ret; -+} -+ -+static void __exit -+ramips_eth_cleanup(void) -+{ -+ platform_driver_unregister(&ramips_eth_driver); -+ rt305x_esw_exit(); -+ raeth_debugfs_root_exit(); -+} -+ -+module_init(ramips_eth_init); -+module_exit(ramips_eth_cleanup); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); -+MODULE_DESCRIPTION("ethernet driver for ramips boards"); diff --git a/target/linux/ramips/patches-3.8/0137-watchdog-adds-ralink-wdt.patch b/target/linux/ramips/patches-3.8/0137-watchdog-adds-ralink-wdt.patch deleted file mode 100644 index 3b7246f..0000000 --- a/target/linux/ramips/patches-3.8/0137-watchdog-adds-ralink-wdt.patch +++ /dev/null @@ -1,395 +0,0 @@ -From 14c1b064274d28cf88113a685c58374a515f3018 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Mon, 22 Apr 2013 23:23:07 +0200 -Subject: [PATCH 137/137] watchdog: adds ralink wdt - -Adds the watchdog driver for ralink SoC. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - drivers/watchdog/Kconfig | 6 + - drivers/watchdog/Makefile | 1 + - drivers/watchdog/ralink_wdt.c | 352 +++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 359 insertions(+) - create mode 100644 drivers/watchdog/ralink_wdt.c - ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -1077,6 +1077,12 @@ config LANTIQ_WDT - help - Hardware driver for the Lantiq SoC Watchdog Timer. - -+config RALINK_WDT -+ tristate "Ralink SoC watchdog" -+ depends on RALINK -+ help -+ Hardware driver for the Ralink SoC Watchdog Timer. -+ - # PARISC Architecture - - # POWERPC Architecture ---- a/drivers/watchdog/Makefile -+++ b/drivers/watchdog/Makefile -@@ -132,6 +132,7 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o - obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o - octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o - obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o -+obj-$(CONFIG_RALINK_WDT) += ralink_wdt.o - - # PARISC Architecture - ---- /dev/null -+++ b/drivers/watchdog/ralink_wdt.c -@@ -0,0 +1,352 @@ -+/* -+ * Ralink RT288X/RT305X built-in hardware watchdog timer -+ * -+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> -+ * -+ * This driver was based on: drivers/watchdog/ixp4xx_wdt.c -+ * Author: Deepak Saxena <dsaxena@plexity.net> -+ * Copyright 2004 (c) MontaVista, Software, Inc. -+ * -+ * which again was based on sa1100 driver, -+ * Copyright (C) 2000 Oleg Drokin <green@crimea.edu> -+ * -+ * parts of the driver are based on Ralink's 2.6.21 BSP -+ * -+ * 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/bitops.h> -+#include <linux/errno.h> -+#include <linux/fs.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/miscdevice.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/platform_device.h> -+#include <linux/types.h> -+#include <linux/watchdog.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+ -+#define DRIVER_NAME "ralink-wdt" -+ -+#define RALINK_WDT_TIMEOUT 30 /* seconds */ -+#define RALINK_WDT_PRESCALE 65536 -+ -+#define TIMER_REG_TMR1LOAD 0x00 -+#define TIMER_REG_TMR1CTL 0x08 -+ -+#define TMRSTAT_TMR1RST BIT(5) -+ -+#define TMR1CTL_ENABLE BIT(7) -+#define TMR1CTL_MODE_SHIFT 4 -+#define TMR1CTL_MODE_MASK 0x3 -+#define TMR1CTL_MODE_FREE_RUNNING 0x0 -+#define TMR1CTL_MODE_PERIODIC 0x1 -+#define TMR1CTL_MODE_TIMEOUT 0x2 -+#define TMR1CTL_MODE_WDT 0x3 -+#define TMR1CTL_PRESCALE_MASK 0xf -+#define TMR1CTL_PRESCALE_65536 0xf -+ -+static int nowayout = WATCHDOG_NOWAYOUT; -+module_param(nowayout, int, 0); -+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " -+ "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -+ -+static int ralink_wdt_timeout = RALINK_WDT_TIMEOUT; -+module_param_named(timeout, ralink_wdt_timeout, int, 0); -+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, 0 means use maximum " -+ "(default=" __MODULE_STRING(RALINK_WDT_TIMEOUT) "s)"); -+ -+static unsigned long ralink_wdt_flags; -+ -+#define WDT_FLAGS_BUSY 0 -+#define WDT_FLAGS_EXPECT_CLOSE 1 -+ -+static struct clk *ralink_wdt_clk; -+static unsigned long ralink_wdt_freq; -+static int ralink_wdt_max_timeout; -+static void __iomem *ralink_wdt_base; -+ -+static inline void rt_wdt_w32(unsigned reg, u32 val) -+{ -+ __raw_writel(val, ralink_wdt_base + reg); -+} -+ -+static inline u32 rt_wdt_r32(unsigned reg) -+{ -+ return __raw_readl(ralink_wdt_base + reg); -+} -+ -+static inline void ralink_wdt_keepalive(void) -+{ -+ rt_wdt_w32(TIMER_REG_TMR1LOAD, ralink_wdt_timeout * ralink_wdt_freq); -+} -+ -+static inline void ralink_wdt_enable(void) -+{ -+ u32 t; -+ -+ ralink_wdt_keepalive(); -+ -+ t = rt_wdt_r32(TIMER_REG_TMR1CTL); -+ t |= TMR1CTL_ENABLE; -+ rt_wdt_w32(TIMER_REG_TMR1CTL, t); -+} -+ -+static inline void ralink_wdt_disable(void) -+{ -+ u32 t; -+ -+ ralink_wdt_keepalive(); -+ -+ t = rt_wdt_r32(TIMER_REG_TMR1CTL); -+ t &= ~TMR1CTL_ENABLE; -+ rt_wdt_w32(TIMER_REG_TMR1CTL, t); -+} -+ -+static int ralink_wdt_set_timeout(int val) -+{ -+ if (val < 1 || val > ralink_wdt_max_timeout) { -+ pr_warn(DRIVER_NAME -+ ": timeout value %d must be 0 < timeout <= %d, using %d\n", -+ val, ralink_wdt_max_timeout, ralink_wdt_timeout); -+ return -EINVAL; -+ } -+ -+ ralink_wdt_timeout = val; -+ ralink_wdt_keepalive(); -+ -+ return 0; -+} -+ -+static int ralink_wdt_open(struct inode *inode, struct file *file) -+{ -+ u32 t; -+ -+ if (test_and_set_bit(WDT_FLAGS_BUSY, &ralink_wdt_flags)) -+ return -EBUSY; -+ -+ clear_bit(WDT_FLAGS_EXPECT_CLOSE, &ralink_wdt_flags); -+ -+ t = rt_wdt_r32(TIMER_REG_TMR1CTL); -+ t &= ~(TMR1CTL_MODE_MASK << TMR1CTL_MODE_SHIFT | -+ TMR1CTL_PRESCALE_MASK); -+ t |= (TMR1CTL_MODE_WDT << TMR1CTL_MODE_SHIFT | -+ TMR1CTL_PRESCALE_65536); -+ rt_wdt_w32(TIMER_REG_TMR1CTL, t); -+ -+ ralink_wdt_enable(); -+ -+ return nonseekable_open(inode, file); -+} -+ -+static int ralink_wdt_release(struct inode *inode, struct file *file) -+{ -+ if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &ralink_wdt_flags)) -+ ralink_wdt_disable(); -+ else { -+ pr_crit(DRIVER_NAME ": device closed unexpectedly, " -+ "watchdog timer will not stop!\n"); -+ ralink_wdt_keepalive(); -+ } -+ -+ clear_bit(WDT_FLAGS_BUSY, &ralink_wdt_flags); -+ clear_bit(WDT_FLAGS_EXPECT_CLOSE, &ralink_wdt_flags); -+ -+ return 0; -+} -+ -+static ssize_t rt_wdt_w32ite(struct file *file, const char *data, -+ size_t len, loff_t *ppos) -+{ -+ if (len) { -+ if (!nowayout) { -+ size_t i; -+ -+ clear_bit(WDT_FLAGS_EXPECT_CLOSE, &ralink_wdt_flags); -+ -+ for (i = 0; i != len; i++) { -+ char c; -+ -+ if (get_user(c, data + i)) -+ return -EFAULT; -+ -+ if (c == 'V') -+ set_bit(WDT_FLAGS_EXPECT_CLOSE, -+ &ralink_wdt_flags); -+ } -+ } -+ -+ ralink_wdt_keepalive(); -+ } -+ -+ return len; -+} -+ -+static const struct watchdog_info ralink_wdt_info = { -+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | -+ WDIOF_MAGICCLOSE, -+ .firmware_version = 0, -+ .identity = "RALINK watchdog", -+}; -+ -+static long ralink_wdt_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ int __user *p = argp; -+ int err; -+ int t; -+ -+ switch (cmd) { -+ case WDIOC_GETSUPPORT: -+ err = copy_to_user(argp, &ralink_wdt_info, -+ sizeof(ralink_wdt_info)) ? -EFAULT : 0; -+ break; -+ -+ case WDIOC_GETSTATUS: -+ err = put_user(0, p); -+ break; -+ -+ case WDIOC_KEEPALIVE: -+ ralink_wdt_keepalive(); -+ err = 0; -+ break; -+ -+ case WDIOC_SETTIMEOUT: -+ err = get_user(t, p); -+ if (err) -+ break; -+ -+ err = ralink_wdt_set_timeout(t); -+ if (err) -+ break; -+ -+ /* fallthrough */ -+ case WDIOC_GETTIMEOUT: -+ err = put_user(ralink_wdt_timeout, p); -+ break; -+ -+ default: -+ err = -ENOTTY; -+ break; -+ } -+ -+ return err; -+} -+ -+static const struct file_operations ralink_wdt_fops = { -+ .owner = THIS_MODULE, -+ .llseek = no_llseek, -+ .write = rt_wdt_w32ite, -+ .unlocked_ioctl = ralink_wdt_ioctl, -+ .open = ralink_wdt_open, -+ .release = ralink_wdt_release, -+}; -+ -+static struct miscdevice ralink_wdt_miscdev = { -+ .minor = WATCHDOG_MINOR, -+ .name = "watchdog", -+ .fops = &ralink_wdt_fops, -+}; -+ -+static int ralink_wdt_probe(struct platform_device *pdev) -+{ -+ struct resource *res; -+ int err; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "no memory resource found\n"); -+ return -EINVAL; -+ } -+ -+ ralink_wdt_base = ioremap(res->start, resource_size(res)); -+ if (!ralink_wdt_base) -+ return -ENOMEM; -+ -+ ralink_wdt_clk = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(ralink_wdt_clk)) { -+ err = PTR_ERR(ralink_wdt_clk); -+ goto err_unmap; -+ } -+ -+ err = clk_enable(ralink_wdt_clk); -+ if (err) -+ goto err_clk_put; -+ -+ ralink_wdt_freq = clk_get_rate(ralink_wdt_clk) / RALINK_WDT_PRESCALE; -+ if (!ralink_wdt_freq) { -+ err = -EINVAL; -+ goto err_clk_disable; -+ } -+ -+ ralink_wdt_max_timeout = (0xfffful / ralink_wdt_freq); -+ if (ralink_wdt_timeout < 1 || -+ ralink_wdt_timeout > ralink_wdt_max_timeout) { -+ ralink_wdt_timeout = ralink_wdt_max_timeout; -+ dev_info(&pdev->dev, -+ "timeout value must be 0 < timeout <= %d, using %d\n", -+ ralink_wdt_max_timeout, ralink_wdt_timeout); -+ } -+ -+ err = misc_register(&ralink_wdt_miscdev); -+ if (err) { -+ dev_err(&pdev->dev, -+ "unable to register misc device, err=%d\n", err); -+ goto err_clk_disable; -+ } -+ -+ return 0; -+ -+err_clk_disable: -+ clk_disable(ralink_wdt_clk); -+err_clk_put: -+ clk_put(ralink_wdt_clk); -+err_unmap: -+ iounmap(ralink_wdt_base); -+ return err; -+} -+ -+static int ralink_wdt_remove(struct platform_device *pdev) -+{ -+ misc_deregister(&ralink_wdt_miscdev); -+ clk_disable(ralink_wdt_clk); -+ clk_put(ralink_wdt_clk); -+ iounmap(ralink_wdt_base); -+ return 0; -+} -+ -+static void ralink_wdt_shutdown(struct platform_device *pdev) -+{ -+ ralink_wdt_disable(); -+} -+ -+static const struct of_device_id ralink_wdt_match[] = { -+ { .compatible = "ralink,rt2880-wdt" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, ralink_wdt_match); -+ -+static struct platform_driver ralink_wdt_driver = { -+ .probe = ralink_wdt_probe, -+ .remove = ralink_wdt_remove, -+ .shutdown = ralink_wdt_shutdown, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ .of_match_table = ralink_wdt_match, -+ }, -+}; -+ -+module_platform_driver(ralink_wdt_driver); -+ -+MODULE_DESCRIPTION("MediaTek/Ralink RT288X/RT305X hardware watchdog driver"); -+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:" DRIVER_NAME); -+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/target/linux/ramips/patches-3.8/0203-owrt-OF-USB-add-OF-binding-for-ehci-and-ohci-platfor.patch b/target/linux/ramips/patches-3.8/0203-owrt-OF-USB-add-OF-binding-for-ehci-and-ohci-platfor.patch deleted file mode 100644 index 13a45b2..0000000 --- a/target/linux/ramips/patches-3.8/0203-owrt-OF-USB-add-OF-binding-for-ehci-and-ohci-platfor.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 3c99a50d689cb4811b13b9810d18c9316587216f Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Mon, 18 Mar 2013 20:51:21 +0100 -Subject: [PATCH 203/208] owrt: OF: USB: add OF binding for ehci and ohci - platform driver - -Make ohci-platform and ehci-platform loadable from OF. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - drivers/usb/host/ehci-platform.c | 7 +++++++ - drivers/usb/host/ohci-platform.c | 7 +++++++ - 2 files changed, 14 insertions(+) - ---- a/drivers/usb/host/ehci-platform.c -+++ b/drivers/usb/host/ehci-platform.c -@@ -183,6 +183,12 @@ static int ehci_platform_resume(struct d - #define ehci_platform_resume NULL - #endif /* CONFIG_PM */ - -+static const struct of_device_id ehci_match_table[] = { -+ { .compatible = "ehci-platform" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, ehci_match_table); -+ - static const struct platform_device_id ehci_platform_table[] = { - { "ehci-platform", 0 }, - { } -@@ -203,6 +209,7 @@ static struct platform_driver ehci_platf - .owner = THIS_MODULE, - .name = "ehci-platform", - .pm = &ehci_platform_pm_ops, -+ .of_match_table = ehci_match_table, - } - }; - ---- a/drivers/usb/host/ohci-platform.c -+++ b/drivers/usb/host/ohci-platform.c -@@ -200,6 +200,12 @@ static int ohci_platform_resume(struct d - #define ohci_platform_resume NULL - #endif /* CONFIG_PM */ - -+static const struct of_device_id ohci_match_table[] = { -+ { .compatible = "ohci-platform" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, ohci_match_table); -+ - static const struct platform_device_id ohci_platform_table[] = { - { "ohci-platform", 0 }, - { } -@@ -220,5 +226,6 @@ static struct platform_driver ohci_platf - .owner = THIS_MODULE, - .name = "ohci-platform", - .pm = &ohci_platform_pm_ops, -+ .of_match_table = ohci_match_table, - } - }; diff --git a/target/linux/ramips/patches-3.8/0204-owrt-MIPS-ralink-add-usb-platform-support.patch b/target/linux/ramips/patches-3.8/0204-owrt-MIPS-ralink-add-usb-platform-support.patch deleted file mode 100644 index 0fedc91..0000000 --- a/target/linux/ramips/patches-3.8/0204-owrt-MIPS-ralink-add-usb-platform-support.patch +++ /dev/null @@ -1,325 +0,0 @@ -From d7e679017ec92824145b275572f6ef83d461f076 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Tue, 19 Mar 2013 09:26:22 +0100 -Subject: [PATCH 204/208] owrt: MIPS: ralink: add usb platform support - -Add code to load the platform ehci/ohci driver on Ralink SoC. For the usb core -to work we need to populate the platform_data during boot, prior to the usb -driver being loaded. - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/ralink/Makefile | 4 +- - arch/mips/ralink/common.h | 1 + - arch/mips/ralink/mt7620.c | 5 ++ - arch/mips/ralink/of.c | 1 + - arch/mips/ralink/rt305x-usb.c | 120 +++++++++++++++++++++++++++++++++++++++++ - arch/mips/ralink/rt3883-usb.c | 118 ++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 247 insertions(+), 2 deletions(-) - create mode 100644 arch/mips/ralink/rt305x-usb.c - create mode 100644 arch/mips/ralink/rt3883-usb.c - ---- a/arch/mips/ralink/Makefile -+++ b/arch/mips/ralink/Makefile -@@ -9,8 +9,8 @@ - obj-y := prom.o of.o reset.o clk.o irq.o pinmux.o timer.o - - obj-$(CONFIG_SOC_RT288X) += rt288x.o --obj-$(CONFIG_SOC_RT305X) += rt305x.o --obj-$(CONFIG_SOC_RT3883) += rt3883.o -+obj-$(CONFIG_SOC_RT305X) += rt305x.o rt305x-usb.o -+obj-$(CONFIG_SOC_RT3883) += rt3883.o rt3883-usb.o - obj-$(CONFIG_SOC_MT7620) += mt7620.o - - obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ---- a/arch/mips/ralink/common.h -+++ b/arch/mips/ralink/common.h -@@ -51,5 +51,6 @@ extern void prom_soc_init(struct ralink_ - __iomem void *plat_of_remap_node(const char *node); - - void ralink_pinmux(void); -+void ralink_usb_platform(void); - - #endif /* _RALINK_COMMON_H__ */ ---- a/arch/mips/ralink/mt7620.c -+++ b/arch/mips/ralink/mt7620.c -@@ -140,6 +140,11 @@ struct ralink_pinmux rt_gpio_pinmux = { - .uart_mask = MT7620_GPIO_MODE_GPIO, - }; - -+void ralink_usb_platform(void) -+{ -+ -+} -+ - void __init ralink_clk_init(void) - { - unsigned long cpu_rate, sys_rate; ---- a/arch/mips/ralink/of.c -+++ b/arch/mips/ralink/of.c -@@ -111,6 +111,7 @@ static int __init plat_of_setup(void) - panic("failed to populate DT\n"); - - ralink_pinmux(); -+ ralink_usb_platform(); - - return 0; - } ---- /dev/null -+++ b/arch/mips/ralink/rt305x-usb.c -@@ -0,0 +1,120 @@ -+/* -+ * 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) 2008-2011 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/module.h> -+ -+#include <linux/delay.h> -+#include <linux/of_platform.h> -+#include <linux/dma-mapping.h> -+#include <linux/usb/ehci_pdriver.h> -+#include <linux/usb/ohci_pdriver.h> -+ -+#include <asm/mach-ralink/ralink_regs.h> -+#include <asm/mach-ralink/rt305x.h> -+ -+static atomic_t rt3352_usb_pwr_ref = ATOMIC_INIT(0); -+ -+static int rt3352_usb_power_on(struct platform_device *pdev) -+{ -+ -+ if (atomic_inc_return(&rt3352_usb_pwr_ref) == 1) { -+ u32 t; -+ -+ t = rt_sysc_r32(RT3352_SYSC_REG_USB_PS); -+ -+ /* enable clock for port0's and port1's phys */ -+ t = rt_sysc_r32(RT3352_SYSC_REG_CLKCFG1); -+ t |= RT3352_CLKCFG1_UPHY0_CLK_EN | RT3352_CLKCFG1_UPHY1_CLK_EN; -+ rt_sysc_w32(t, RT3352_SYSC_REG_CLKCFG1); -+ mdelay(500); -+ -+ /* pull USBHOST and USBDEV out from reset */ -+ t = rt_sysc_r32(RT3352_SYSC_REG_RSTCTRL); -+ t &= ~(RT3352_RSTCTRL_UHST | RT3352_RSTCTRL_UDEV); -+ rt_sysc_w32(t, RT3352_SYSC_REG_RSTCTRL); -+ mdelay(500); -+ -+ /* enable host mode */ -+ t = rt_sysc_r32(RT3352_SYSC_REG_SYSCFG1); -+ t |= RT3352_SYSCFG1_USB0_HOST_MODE; -+ rt_sysc_w32(t, RT3352_SYSC_REG_SYSCFG1); -+ -+ t = rt_sysc_r32(RT3352_SYSC_REG_USB_PS); -+ } -+ -+ return 0; -+} -+ -+static void rt3352_usb_power_off(struct platform_device *pdev) -+{ -+ if (atomic_dec_return(&rt3352_usb_pwr_ref) == 0) { -+ u32 t; -+ -+ /* put USBHOST and USBDEV into reset */ -+ t = rt_sysc_r32(RT3352_SYSC_REG_RSTCTRL); -+ t |= RT3352_RSTCTRL_UHST | RT3352_RSTCTRL_UDEV; -+ rt_sysc_w32(t, RT3352_SYSC_REG_RSTCTRL); -+ udelay(10000); -+ -+ /* disable clock for port0's and port1's phys*/ -+ t = rt_sysc_r32(RT3352_SYSC_REG_CLKCFG1); -+ t &= ~(RT3352_CLKCFG1_UPHY0_CLK_EN | RT3352_CLKCFG1_UPHY1_CLK_EN); -+ rt_sysc_w32(t, RT3352_SYSC_REG_CLKCFG1); -+ udelay(10000); -+ } -+} -+ -+static struct usb_ehci_pdata rt3352_ehci_data = { -+ .power_on = rt3352_usb_power_on, -+ .power_off = rt3352_usb_power_off, -+}; -+ -+static struct usb_ohci_pdata rt3352_ohci_data = { -+ .power_on = rt3352_usb_power_on, -+ .power_off = rt3352_usb_power_off, -+}; -+ -+static void ralink_add_usb(char *name, void *pdata, u64 *mask) -+{ -+ struct device_node *node; -+ struct platform_device *pdev; -+ -+ node = of_find_compatible_node(NULL, NULL, name); -+ if (!node) -+ return; -+ -+ pdev = of_find_device_by_node(node); -+ if (!pdev) -+ goto error_out; -+ -+ if (pdata) -+ pdev->dev.platform_data = pdata; -+ if (mask) { -+ pdev->dev.dma_mask = mask; -+ pdev->dev.coherent_dma_mask = *mask; -+ } -+ -+error_out: -+ of_node_put(node); -+} -+ -+static u64 rt3352_ohci_dmamask = DMA_BIT_MASK(32); -+static u64 rt3352_ehci_dmamask = DMA_BIT_MASK(32); -+ -+void ralink_usb_platform(void) -+{ -+ if (soc_is_rt3352() || soc_is_rt5350()) { -+ ralink_add_usb("ohci-platform", -+ &rt3352_ohci_data, &rt3352_ohci_dmamask); -+ ralink_add_usb("ehci-platform", -+ &rt3352_ehci_data, &rt3352_ehci_dmamask); -+ } -+} ---- /dev/null -+++ b/arch/mips/ralink/rt3883-usb.c -@@ -0,0 +1,118 @@ -+/* -+ * 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) 2008-2011 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/module.h> -+ -+#include <linux/delay.h> -+#include <linux/of_platform.h> -+#include <linux/dma-mapping.h> -+#include <linux/usb/ehci_pdriver.h> -+#include <linux/usb/ohci_pdriver.h> -+ -+#include <asm/mach-ralink/ralink_regs.h> -+#include <asm/mach-ralink/rt3883.h> -+ -+static atomic_t rt3883_usb_pwr_ref = ATOMIC_INIT(0); -+ -+static int rt3883_usb_power_on(struct platform_device *pdev) -+{ -+ if (atomic_inc_return(&rt3883_usb_pwr_ref) == 1) { -+ u32 t; -+ -+ t = rt_sysc_r32(RT3883_SYSC_REG_USB_PS); -+ -+ /* enable clock for port0's and port1's phys */ -+ t = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1); -+ t |= RT3883_CLKCFG1_UPHY0_CLK_EN | RT3883_CLKCFG1_UPHY1_CLK_EN; -+ rt_sysc_w32(t, RT3883_SYSC_REG_CLKCFG1); -+ mdelay(500); -+ -+ /* pull USBHOST and USBDEV out from reset */ -+ t = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL); -+ t &= ~(RT3883_RSTCTRL_UHST | RT3883_RSTCTRL_UDEV); -+ rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL); -+ mdelay(500); -+ -+ /* enable host mode */ -+ t = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1); -+ t |= RT3883_SYSCFG1_USB0_HOST_MODE; -+ rt_sysc_w32(t, RT3883_SYSC_REG_SYSCFG1); -+ -+ t = rt_sysc_r32(RT3883_SYSC_REG_USB_PS); -+ } -+ -+ return 0; -+} -+ -+static void rt3883_usb_power_off(struct platform_device *pdev) -+{ -+ if (atomic_dec_return(&rt3883_usb_pwr_ref) == 0) { -+ u32 t; -+ -+ /* put USBHOST and USBDEV into reset */ -+ t = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL); -+ t |= RT3883_RSTCTRL_UHST | RT3883_RSTCTRL_UDEV; -+ rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL); -+ udelay(10000); -+ -+ /* disable clock for port0's and port1's phys*/ -+ t = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1); -+ t &= ~(RT3883_CLKCFG1_UPHY0_CLK_EN | -+ RT3883_CLKCFG1_UPHY1_CLK_EN); -+ rt_sysc_w32(t, RT3883_SYSC_REG_CLKCFG1); -+ udelay(10000); -+ } -+} -+ -+static struct usb_ohci_pdata rt3883_ohci_data = { -+ .power_on = rt3883_usb_power_on, -+ .power_off = rt3883_usb_power_off, -+}; -+ -+static struct usb_ehci_pdata rt3883_ehci_data = { -+ .power_on = rt3883_usb_power_on, -+ .power_off = rt3883_usb_power_off, -+}; -+ -+static void ralink_add_usb(char *name, void *pdata, u64 *mask) -+{ -+ struct device_node *node; -+ struct platform_device *pdev; -+ -+ node = of_find_compatible_node(NULL, NULL, name); -+ if (!node) -+ return; -+ -+ pdev = of_find_device_by_node(node); -+ if (!pdev) -+ goto error_out; -+ -+ if (pdata) -+ pdev->dev.platform_data = pdata; -+ if (mask) { -+ pdev->dev.dma_mask = mask; -+ pdev->dev.coherent_dma_mask = *mask; -+ } -+ -+error_out: -+ of_node_put(node); -+} -+ -+static u64 rt3883_ohci_dmamask = DMA_BIT_MASK(32); -+static u64 rt3883_ehci_dmamask = DMA_BIT_MASK(32); -+ -+void ralink_usb_platform(void) -+{ -+ ralink_add_usb("ohci-platform", -+ &rt3883_ohci_data, &rt3883_ohci_dmamask); -+ ralink_add_usb("ehci-platform", -+ &rt3883_ehci_data, &rt3883_ehci_dmamask); -+} ---- a/arch/mips/ralink/rt288x.c -+++ b/arch/mips/ralink/rt288x.c -@@ -74,6 +74,11 @@ struct ralink_pinmux rt_gpio_pinmux = { - .wdt_reset = rt288x_wdt_reset, - }; - -+void ralink_usb_platform(void) -+{ -+ -+} -+ - void __init ralink_clk_init(void) - { - unsigned long cpu_rate; |