[source] mediatek: various fixes for v4.9

LEDE Commits lede-commits at lists.infradead.org
Fri Apr 7 08:42:24 PDT 2017


blogic pushed a commit to source.git, branch master:
https://git.lede-project.org/64175ffb7911f5fcd3907df09fdb9bfab53ee641

commit 64175ffb7911f5fcd3907df09fdb9bfab53ee641
Author: John Crispin <john at phrozen.org>
AuthorDate: Fri Apr 7 17:42:08 2017 +0200

    mediatek: various fixes for v4.9
    
    * adds MT7530 DSA support
    * backport latest ethernet driver
    * add PMIC leds
    * add auxadc support
    * add efuse support
    * add thermal sensor support
    * add irq affinity support for ethernet
    
    still todo
    * DSA multi cpu support
    
    Signed-off-by: John Crispin <john at phrozen.org>
---
 target/linux/mediatek/Makefile                     |    2 +-
 .../mediatek/base-files/etc/board.d/02_network     |   13 +-
 target/linux/mediatek/base-files/lib/mediatek.sh   |   39 -
 .../mediatek/base-files/lib/preinit/01_affinity    |    4 -
 .../lib/preinit/03_preinit_do_mediatek.sh          |   12 -
 .../base-files/lib/preinit/05_set_preinit_iface    |    9 +
 target/linux/mediatek/config-4.9                   |   22 +-
 .../mediatek/files/arch/arm/boot/dts/_mt7623.dtsi  |  206 +-
 .../files/arch/arm/boot/dts/mt7623-NAND.dts        |  105 +-
 .../files/arch/arm/boot/dts/mt7623-eMMC.dts        |   14 +-
 .../files/arch/arm/boot/dts/mt7623-evb.dts         |   50 +
 ...soc-mediatek-Add-MT2701-power-dt-bindings.patch |   79 +
 ...soc-mediatek-Add-MT2701-power-dt-bindings.patch |   44 -
 ...k-Refine-scpsys-to-support-multiple-platf.patch |  491 +++++
 ...015-soc-mediatek-Add-MT2701-scpsys-driver.patch |  198 ++
 .../patches-4.9/0071-pwm-add-pwm-mediatek.patch    |   44 +-
 .../linux/mediatek/patches-4.9/0083-mfd-led3.patch |   43 +
 .../mediatek/patches-4.9/0085-pmic-led0.patch      |   94 +
 .../mediatek/patches-4.9/0086-pmic-led1.patch      |   40 +
 .../mediatek/patches-4.9/0087-pmic-led2.patch      |  558 +++++
 .../mediatek/patches-4.9/0088-pmic-led3.patch      |   44 +
 target/linux/mediatek/patches-4.9/0091-dsa1.patch  |  127 ++
 .../0091-net-next-mediatek-fix-DQL-support.patch   |   95 +
 target/linux/mediatek/patches-4.9/0092-dsa2.patch  |  219 ++
 target/linux/mediatek/patches-4.9/0092-dsa3.patch  |   67 +
 target/linux/mediatek/patches-4.9/0092-dsa4.patch  |   46 +
 target/linux/mediatek/patches-4.9/0092-dsa5.patch  | 1608 ++++++++++++++
 .../mediatek/patches-4.9/0093-dsa-compat.patch     |   98 +
 .../mediatek/patches-4.9/0094-net-affinity.patch   |   40 +
 .../0101-net-mediatek-add-gsw-mt7530-driver.patch  | 2322 --------------------
 target/linux/mediatek/profiles/default.mk          |    3 -
 31 files changed, 4155 insertions(+), 2581 deletions(-)

diff --git a/target/linux/mediatek/Makefile b/target/linux/mediatek/Makefile
index 0b495ef..f183693 100644
--- a/target/linux/mediatek/Makefile
+++ b/target/linux/mediatek/Makefile
@@ -16,7 +16,7 @@ KERNELNAME:=Image dtbs zImage
 
 include $(INCLUDE_DIR)/target.mk
 DEFAULT_PACKAGES += \
-	kmod-mt76 kmod-leds-gpio kmod-gpio-button-hotplug swconfig \
+	kmod-mt76 kmod-leds-gpio kmod-gpio-button-hotplug \
 	wpad-mini
 
 $(eval $(call BuildTarget))
diff --git a/target/linux/mediatek/base-files/etc/board.d/02_network b/target/linux/mediatek/base-files/etc/board.d/02_network
index 2549ff9..d772ab0 100755
--- a/target/linux/mediatek/base-files/etc/board.d/02_network
+++ b/target/linux/mediatek/base-files/etc/board.d/02_network
@@ -1,7 +1,6 @@
 #!/bin/sh
 
 . /lib/functions.sh
-. /lib/mediatek.sh
 . /lib/functions/uci-defaults.sh
 . /lib/functions/system.sh
 
@@ -10,18 +9,16 @@ mediatek_setup_interfaces()
 	local board="$1"
 
 	case $board in
-	eMMC | \
-	NAND | \
-	mt7623_evb)
-		ucidef_set_interfaces_lan_wan "eth0.1" "eth1.2"
-		ucidef_add_switch "switch0" \
-			"0:lan" "1:lan" "2:lan" "3:lan" "4:wan" "6 at eth0" "5 at eth1"
+	'mediatek,mt7623-rfb-emmc' | \
+	'mediatek,mt7623-rfb-nand')
+		ucidef_set_interface_lan "lan1 lan2 lan3 lan4"
+		ucidef_set_interface_wan wan
 		;;
 	esac
 }
 
 board_config_update
-board=$(mediatek_board_name)
+board=$(board_name)
 mediatek_setup_interfaces $board
 board_config_flush
 
diff --git a/target/linux/mediatek/base-files/lib/mediatek.sh b/target/linux/mediatek/base-files/lib/mediatek.sh
deleted file mode 100644
index 490ee3e..0000000
--- a/target/linux/mediatek/base-files/lib/mediatek.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-# Copyright (C) 2016 OpenWrt.org
-#
-
-mediatek_board_detect() {
-	local machine
-	local name
-
-	machine=$(cat /proc/device-tree/model)
-
-	case "$machine" in
-	"MediaTek MT7623 evaluation board")
-		name="mt7623_evb"
-		;;
-	"MediaTek MT7623 eMMC evaluation board")
-		name="eMMC"
-		;;
-	"MediaTek MT7623 NAND evaluation board")
-		name="NAND"
-		;;
-	esac
-
-	[ -z "$name" ] && name="unknown"
-
-	[ -e "/tmp/sysinfo/" ] || mkdir -p "/tmp/sysinfo/"
-
-	echo "$name" > /tmp/sysinfo/board_name
-	echo "$machine" > /tmp/sysinfo/model
-}
-
-mediatek_board_name() {
-	local name
-
-	[ -f /tmp/sysinfo/board_name ] && name=$(cat /tmp/sysinfo/board_name)
-	[ -z "$name" ] && name="unknown"
-
-	echo "$name"
-}
diff --git a/target/linux/mediatek/base-files/lib/preinit/01_affinity b/target/linux/mediatek/base-files/lib/preinit/01_affinity
deleted file mode 100755
index 1141d6d..0000000
--- a/target/linux/mediatek/base-files/lib/preinit/01_affinity
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-echo 4 > /proc/irq/32/smp_affinity
-echo 8 > /proc/irq/33/smp_affinity
diff --git a/target/linux/mediatek/base-files/lib/preinit/03_preinit_do_mediatek.sh b/target/linux/mediatek/base-files/lib/preinit/03_preinit_do_mediatek.sh
deleted file mode 100644
index 9e5a18d..0000000
--- a/target/linux/mediatek/base-files/lib/preinit/03_preinit_do_mediatek.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2014 The Linux Foundation. All rights reserved.
-#
-
-do_mediatek() {
-	. /lib/mediatek.sh
-
-	mediatek_board_detect
-}
-
-boot_hook_add preinit_main do_mediatek
diff --git a/target/linux/mediatek/base-files/lib/preinit/05_set_preinit_iface b/target/linux/mediatek/base-files/lib/preinit/05_set_preinit_iface
new file mode 100644
index 0000000..eb0bed8
--- /dev/null
+++ b/target/linux/mediatek/base-files/lib/preinit/05_set_preinit_iface
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+set_preinit_iface() {
+	ifconfig eth0 up
+	ifname=lan1
+}
+
+boot_hook_add preinit_main set_preinit_iface
+
diff --git a/target/linux/mediatek/config-4.9 b/target/linux/mediatek/config-4.9
index 5f959de..1d77275 100644
--- a/target/linux/mediatek/config-4.9
+++ b/target/linux/mediatek/config-4.9
@@ -60,7 +60,7 @@ CONFIG_CLKSRC_MMIO=y
 CONFIG_CLKSRC_OF=y
 CONFIG_CLKSRC_PROBE=y
 CONFIG_CLONE_BACKWARDS=y
-CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 block2mtd.block2mtd=/dev/mmcblk0,65536,eMMC,5 mtdparts=eMMC:256k(mbr)ro,512k(uboot)ro,256k(config)ro,256k(factory)ro,32M(kernel),32M(recovery),1024M(rootfs),2048M(usrdata),-(bmtpool) rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 rootfstype=squashfs,jffs2"
 CONFIG_CMDLINE_FORCE=y
 CONFIG_COMMON_CLK=y
 CONFIG_COMMON_CLK_MEDIATEK=y
@@ -95,6 +95,7 @@ CONFIG_CPU_HAS_ASID=y
 CONFIG_CPU_PABRT_V7=y
 CONFIG_CPU_PM=y
 CONFIG_CPU_RMAP=y
+# CONFIG_CPU_THERMAL is not set
 CONFIG_CPU_TLB_V7=y
 CONFIG_CPU_V7=y
 CONFIG_CRC16=y
@@ -217,6 +218,9 @@ CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MT65XX=y
+CONFIG_IIO=y
+# CONFIG_IIO_BUFFER is not set
+# CONFIG_IIO_TRIGGER is not set
 CONFIG_INITRAMFS_ROOT_GID=1000
 CONFIG_INITRAMFS_ROOT_UID=1000
 CONFIG_INITRAMFS_SOURCE="/openwrt/trunk/build_dir/target-arm_cortex-a7_musl-1.1.14_eabi/root-mediatek /openwrt/trunk/target/linux/generic/image/initramfs-base-files.txt"
@@ -230,6 +234,7 @@ CONFIG_IRQ_DOMAIN_HIERARCHY=y
 CONFIG_IRQ_FORCED_THREADING=y
 CONFIG_IRQ_WORK=y
 CONFIG_KALLSYMS=y
+CONFIG_LEDS_MT6323=y
 CONFIG_LIBFDT=y
 CONFIG_LOCKUP_DETECTOR=y
 CONFIG_LOCK_SPIN_ON_OWNER=y
@@ -245,8 +250,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_MDIO_BITBANG=y
 CONFIG_MDIO_BOARDINFO=y
 CONFIG_MDIO_GPIO=y
-# CONFIG_MTK_EFUSE is not set
-# CONFIG_MEDIATEK_MT6577_AUXADC is not set
+CONFIG_MEDIATEK_MT6577_AUXADC=y
 CONFIG_MEDIATEK_WATCHDOG=y
 CONFIG_MFD_CORE=y
 # CONFIG_MFD_MAX77620 is not set
@@ -278,18 +282,25 @@ CONFIG_MTD_UBI_BLOCK=y
 # CONFIG_MTD_UBI_FASTMAP is not set
 # CONFIG_MTD_UBI_GLUEBI is not set
 CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTK_EFUSE=y
 CONFIG_MTK_INFRACFG=y
 # CONFIG_MTK_IOMMU is not set
 # CONFIG_MTK_IOMMU_V1 is not set
 CONFIG_MTK_PMIC_WRAP=y
 CONFIG_MTK_SCPSYS=y
+CONFIG_MTK_THERMAL=y
 CONFIG_MTK_TIMER=y
 CONFIG_MULTI_IRQ_HANDLER=y
 CONFIG_MUTEX_SPIN_ON_OWNER=y
 CONFIG_NEED_DMA_MAP_STATE=y
 # CONFIG_NEON is not set
+CONFIG_NET_DSA=y
+# CONFIG_NET_DSA_HWMON is not set
+CONFIG_NET_DSA_MT7530=y
+CONFIG_NET_DSA_TAG_MTK=y
 CONFIG_NET_FLOW_LIMIT=y
 CONFIG_NET_MEDIATEK_SOC=y
+CONFIG_NET_SWITCHDEV=y
 # CONFIG_NET_VENDOR_AURORA is not set
 CONFIG_NET_VENDOR_MEDIATEK=y
 # CONFIG_NET_VENDOR_WIZNET is not set
@@ -299,6 +310,7 @@ CONFIG_NO_HZ=y
 CONFIG_NO_HZ_COMMON=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_NR_CPUS=4
+CONFIG_NVMEM=y
 CONFIG_OF=y
 CONFIG_OF_ADDRESS=y
 CONFIG_OF_ADDRESS_PCI=y
@@ -403,6 +415,10 @@ CONFIG_SWIOTLB=y
 CONFIG_SWPHY=y
 CONFIG_SWP_EMULATE=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_OF=y
 # CONFIG_THUMB2_KERNEL is not set
 CONFIG_TICK_CPU_ACCOUNTING=y
 CONFIG_TIMER_STATS=y
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi b/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi
index 0f91194..7093d35 100644
--- a/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi
+++ b/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi
@@ -151,7 +151,7 @@
 	};
 
 	pio: pinctrl at 10005000 {
-		compatible = "mediatek,mt7623-pinctrl";
+		compatible = "mediatek,mt2701-pinctrl";
 		reg = <0 0x1000b000 0 0x1000>;
 		mediatek,pctl-regmap = <&syscfg_pctl_a>;
 		pins-are-numbered;
@@ -165,7 +165,9 @@
 	};
 
 	syscfg_pctl_a: syscfg at 10005000 {
-		compatible = "mediatek,mt7623-pctl-a-syscfg", "syscon";
+		compatible = "mediatek,mt7623-pctl-a-syscfg",
+			     "mediatek,mt2701-pctl-a-syscfg",
+			     "syscon";
 		reg = <0 0x10005000 0 0x1000>;
 	};
 
@@ -176,8 +178,9 @@
 		reg = <0 0x10006000 0 0x1000>;
 		infracfg = <&infracfg>;
 		clocks = <&clk26m>,
-			 <&topckgen CLK_TOP_MM_SEL>;
-		clock-names = "mfg", "mm";
+			 <&topckgen CLK_TOP_MM_SEL>,
+			 <&topckgen CLK_TOP_ETHIF_SEL>;
+		clock-names = "mfg", "mm", "ethif";
 	};
 
 	watchdog: watchdog at 10007000 {
@@ -217,6 +220,19 @@
 		reg = <0 0x10200100 0 0x1c>;
 	};
 
+	efuse: efuse at 10206000 {
+		compatible = "mediatek,mt7623-efuse",
+			     "mediatek,efuse";
+		reg	   = <0 0x10206000 0 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		/* Data cells */
+		thermal_calibration: calib at 424 {
+			reg = <0x424 0xc>;
+		};
+	};
+
 	apmixedsys: apmixedsys at 10209000 {
 		compatible = "mediatek,mt7623-apmixedsys",
 			     "mediatek,mt2701-apmixedsys";
@@ -235,49 +251,13 @@
 		      <0 0x10216000 0 0x2000>;
 	};
 
-	i2c0: i2c at 11007000 {
-		compatible = "mediatek,mt7623-i2c",
-			     "mediatek,mt6577-i2c";
-		reg = <0 0x11007000 0 0x70>,
-		      <0 0x11000200 0 0x80>;
-		interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_LOW>;
-		clock-div = <16>;
-		clocks = <&pericfg CLK_PERI_I2C0>,
-			 <&pericfg CLK_PERI_AP_DMA>;
-		clock-names = "main", "dma";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
-
-	i2c1: i2c at 11008000 {
-		compatible = "mediatek,mt7623-i2c",
-			     "mediatek,mt6577-i2c";
-		reg = <0 0x11008000 0 0x70>,
-		      <0 0x11000280 0 0x80>;
-		interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_LOW>;
-		clock-div = <16>;
-		clocks = <&pericfg CLK_PERI_I2C1>,
-			 <&pericfg CLK_PERI_AP_DMA>;
-		clock-names = "main", "dma";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
-
-	i2c2: i2c at 11009000 {
-		compatible = "mediatek,mt7623-i2c",
-			     "mediatek,mt6577-i2c";
-		reg = <0 0x11009000 0 0x70>,
-		      <0 0x11000300 0 0x80>;
-		interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_LOW>;
-		clock-div = <16>;
-		clocks = <&pericfg CLK_PERI_I2C2>,
-			 <&pericfg CLK_PERI_AP_DMA>;
-		clock-names = "main", "dma";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
+	auxadc: adc at 11001000 {
+		compatible = "mediatek,mt7623-auxadc",
+			     "mediatek,mt2701-auxadc";
+		reg = <0 0x11001000 0 0x1000>;
+		clocks = <&pericfg CLK_PERI_AUXADC>;
+		clock-names = "main";
+		#io-channel-cells = <1>;
 	};
 
 	uart0: serial at 11002000 {
@@ -326,9 +306,8 @@
 
 	pwm: pwm at 11006000 {
 		compatible = "mediatek,mt7623-pwm";
-	
+
 		reg = <0 0x11006000 0 0x1000>;
-		
 		resets = <&pericfg MT2701_PERI_PWM_SW_RST>;
 		reset-names = "pwm";
 
@@ -342,12 +321,58 @@
 			 <&pericfg CLK_PERI_PWM5>;
 		clock-names = "top", "main", "pwm1", "pwm2",
 			      "pwm3", "pwm4", "pwm5";
-	
+
+		status = "disabled";
+	};
+
+	i2c0: i2c at 11007000 {
+		compatible = "mediatek,mt7623-i2c",
+			     "mediatek,mt6577-i2c";
+		reg = <0 0x11007000 0 0x70>,
+		      <0 0x11000200 0 0x80>;
+		interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_LOW>;
+		clock-div = <16>;
+		clocks = <&pericfg CLK_PERI_I2C0>,
+			 <&pericfg CLK_PERI_AP_DMA>;
+		clock-names = "main", "dma";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c1: i2c at 11008000 {
+		compatible = "mediatek,mt7623-i2c",
+			     "mediatek,mt6577-i2c";
+		reg = <0 0x11008000 0 0x70>,
+		      <0 0x11000280 0 0x80>;
+		interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_LOW>;
+		clock-div = <16>;
+		clocks = <&pericfg CLK_PERI_I2C1>,
+			 <&pericfg CLK_PERI_AP_DMA>;
+		clock-names = "main", "dma";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c2: i2c at 11009000 {
+		compatible = "mediatek,mt7623-i2c",
+			     "mediatek,mt6577-i2c";
+		reg = <0 0x11009000 0 0x70>,
+		      <0 0x11000300 0 0x80>;
+		interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_LOW>;
+		clock-div = <16>;
+		clocks = <&pericfg CLK_PERI_I2C2>,
+			 <&pericfg CLK_PERI_AP_DMA>;
+		clock-names = "main", "dma";
+		#address-cells = <1>;
+		#size-cells = <0>;
 		status = "disabled";
 	};
 
 	spi: spi at 1100a000 {
-		compatible = "mediatek,mt7623-spi", "mediatek,mt6589-spi";
+		compatible = "mediatek,mt7623-spi",
+			     "mediatek,mt6589-spi";
 		reg = <0 0x1100a000 0 0x1000>;
 		interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&pericfg CLK_PERI_SPI0>;
@@ -356,8 +381,27 @@
 		status = "disabled";
 	};
 
+	thermal: thermal at 1100b000 {
+		#thermal-sensor-cells = <1>;
+		compatible = "mediatek,mt2701-thermal",
+			     "mediatek,mt2701-thermal";
+		reg = <0 0x1100b000 0 0x1000>;
+		interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&pericfg CLK_PERI_THERM>,
+			 <&pericfg CLK_PERI_AUXADC>;
+		clock-names = "therm", "auxadc";
+		resets = <&pericfg MT2701_PERI_THERM_SW_RST>;
+		reset-names = "therm";
+		mediatek,auxadc = <&auxadc>;
+		mediatek,apmixedsys = <&apmixedsys>;
+
+		nvmem-cells = <&thermal_calibration>;
+		nvmem-cell-names = "calibration-data";
+	};
+
 	nandc: nfi at 1100d000 {
-		compatible = "mediatek,mt2701-nfc";
+		compatible = "mediatek,mt7623-nfc",
+			     "mediatek,mt2701-nfc";
 		reg = <0 0x1100d000 0 0x1000>;
 		power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
 		interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>;
@@ -371,7 +415,8 @@
 	};
 
 	bch: ecc at 1100e000 {
-		compatible = "mediatek,mt2701-ecc";
+		compatible = "mediatek,mt7623-ecc",
+			     "mediatek,mt2701-ecc";
 		reg = <0 0x1100e000 0 0x1000>;
 		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&pericfg CLK_PERI_NFI_ECC>;
@@ -402,7 +447,7 @@
 	};
 
 	usb1: usb at 1a1c0000 {
-		compatible = "mediatek,mt2701-xhci",
+		compatible = "mediatek,mt7623-xhci",
 			     "mediatek,mt8173-xhci";
 		reg = <0 0x1a1c0000 0 0x1000>,
 		      <0 0x1a1c4700 0 0x0100>;
@@ -528,21 +573,26 @@
 	};
 
 	ethsys: syscon at 1b000000 {
-		compatible = "mediatek,mt2701-ethsys", "syscon";
+		compatible = "mediatek,mt7623-ethsys",
+			     "mediatek,mt2701-ethsys",
+			     "syscon";
 		reg = <0 0x1b000000 0 0x1000>;
 		#reset-cells = <1>;
 		#clock-cells = <1>;
 	};
 
 	eth: ethernet at 1b100000 {
-		compatible = "mediatek,mt2701-eth";
+		compatible = "mediatek,mt7623-eth",
+			     "mediatek,mt2701-eth",
+			     "syscon";
 		reg = <0 0x1b100000 0 0x20000>;
-	
+
 		clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
 			 <&ethsys CLK_ETHSYS_ESW>,
 			 <&ethsys CLK_ETHSYS_GP2>,
-			 <&ethsys CLK_ETHSYS_GP1>;
-		clock-names = "ethif", "esw", "gp2", "gp1";
+			 <&ethsys CLK_ETHSYS_GP1>,
+			 <&apmixedsys CLK_APMIXED_TRGPLL>;
+		clock-names = "ethif", "esw", "gp2", "gp1", "trgpll";
 		interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW
 			      GIC_SPI 199 IRQ_TYPE_LEVEL_LOW
 			      GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>;
@@ -554,11 +604,9 @@
 		mediatek,ethsys = <&ethsys>;
 		mediatek,pctl = <&syscfg_pctl_a>;
 
-		mediatek,switch = <&gsw>;
-
 		#address-cells = <1>;
 		#size-cells = <0>;
-	
+
 		status = "disabled";
 
 		gmac1: mac at 0 {
@@ -566,9 +614,9 @@
 			reg = <0>;
 
 			status = "disabled";
-			
-			phy-mode = "rgmii";
-			
+
+			phy-mode = "trgmii";
+
 			fixed-link {
 				speed = <1000>;
 				full-duplex;
@@ -582,34 +630,10 @@
 
 			status = "disabled";
 		};
-	
-		mdio-bus {
+
+		mdio0: mdio-bus {
 			#address-cells = <1>;
 			#size-cells = <0>;
-
-			phy5: ethernet-phy at 5 {
-				reg = <5>;
-				phy-mode = "rgmii-rxid";
-			};
-
-			phy1f: ethernet-phy at 1f {
-				reg = <0x1f>;
-				phy-mode = "rgmii";
-			};
 		};
 	};
-
-	gsw: switch at 1b100000 {
-		compatible = "mediatek,mt7623-gsw";
-		interrupt-parent = <&pio>;
-		interrupts = <168 IRQ_TYPE_EDGE_RISING>;
-		resets = <&ethsys 2>;
-		reset-names = "eth";
-		clocks = <&apmixedsys CLK_APMIXED_TRGPLL>;
-		clock-names = "trgpll";
-		mt7530-supply = <&mt6323_vpa_reg>;
-		mediatek,pctl-regmap = <&syscfg_pctl_a>;
-		mediatek,ethsys = <&ethsys>;
-		status = "disabled";
-	};
 };
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts
index 15b7da9..d90e0fb 100644
--- a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts
+++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts
@@ -18,8 +18,8 @@
 #include <dt-bindings/gpio/gpio.h>
 
 / {
-	model = "MediaTek MT7623 NAND evaluation board";
-	compatible = "mediatek,mt7623-evb", "mediatek,mt7623";
+	model = "MediaTek MT7623 NAND reference board";
+	compatible = "mediatek,mt7623-rfb-nand", "mediatek,mt7623";
 
 	chosen {
 		stdout-path = &uart2;
@@ -280,6 +280,34 @@
 				regulator-enable-ramp-delay = <216>;
 			};
 		};
+
+		mt6323led: leds {
+			compatible = "mediatek,mt6323-led";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led at 0 {
+				reg = <0>;
+				label = "LED0";
+				linux,default-trigger = "timer";
+				default-state = "on";
+			};
+			led at 1 {
+				reg = <1>;
+				label = "LED1";
+				default-state = "off";
+			};
+			led at 2 {
+				reg = <2>;
+				label = "LED2";
+				default-state = "on";
+			};
+			led at 3 {
+				reg = <3>;
+				label = "LED3";
+				default-state = "on";
+			};
+		};
 	};
 };
 
@@ -332,10 +360,16 @@
 				 <MT7623_PIN_270_G2_RXD1_FUNC_G2_RXD1>,
 				 <MT7623_PIN_271_G2_RXD2_FUNC_G2_RXD2>,
 				 <MT7623_PIN_272_G2_RXD3_FUNC_G2_RXD3>,
-				 <MT7623_PIN_273_ESW_INT_FUNC_ESW_INT>,
 				 <MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV>;
 		};
-		
+
+		pins_eth_esw {
+			pinmux = <MT7623_PIN_273_ESW_INT_FUNC_ESW_INT>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up;
+		};
+
 		pins_eth_rst {
 			pinmux = <MT7623_PIN_15_GPIO15_FUNC_GPIO15>;
 			output-low;
@@ -426,7 +460,7 @@
 	mac-address = [00 11 22 33 44 55];
 	status = "okay";
 
-	phy-mode = "rgmii";
+	phy-mode = "trgmii";
 
 	fixed-link {
 		speed = <1000>;
@@ -435,13 +469,64 @@
 	};
 };
 
-&gsw {
-	pinctrl-names = "default";
-	pinctrl-0 = <&eth_default>;
-	mediatek,reset-pin = <&pio 15 0>;
-	status = "okay";
+&mdio0 {
+	switch at 0 {
+		compatible = "mediatek,mt7530";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&eth_default>;
+
+		core-supply = <&mt6323_vpa_reg>;
+		io-supply = <&mt6323_vemc3v3_reg>;
+		reset-gpios = <&pio 33 0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			port at 0 {
+				reg = <0>;
+				label = "lan0";
+			};
+
+			port at 1 {
+				reg = <1>;
+				label = "lan1";
+			};
+
+			port at 2 {
+				reg = <2>;
+				label = "lan2";
+			};
+
+			port at 3 {
+				reg = <3>;
+				label = "lan3";
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "wan";
+			};
+
+			port at 6 {
+				reg = <6>;
+				label = "cpu";
+				ethernet = <&gmac1>;
+				phy-mode = "trgmii";
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
 };
 
+
 &pwm {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pwm_pins>;
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts
index 630240c..86c4dd5 100644
--- a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts
+++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts
@@ -18,8 +18,8 @@
 #include <dt-bindings/gpio/gpio.h>
 
 / {
-	model = "MediaTek MT7623 eMMC evaluation board";
-	compatible = "mediatek,mt7623-evb", "mediatek,mt7623";
+	model = "MediaTek MT7623 eMMC reference board";
+	compatible = "mediatek,mt7623-rfb-emmc", "mediatek,mt7623";
 
 	chosen {
 		stdout-path = &uart2;
@@ -430,7 +430,7 @@
 				 <MT7623_PIN_273_ESW_INT_FUNC_ESW_INT>,
 				 <MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV>;
 		};
-		
+
 		pins_eth_rst {
 			pinmux = <MT7623_PIN_15_GPIO15_FUNC_GPIO15>;
 			output-low;
@@ -474,14 +474,6 @@
 &gmac2 {
 	mac-address = [00 11 22 33 44 55];
 	status = "okay";
-	phy-handle = <&phy5>;
-};
-
-&gsw {
-	pinctrl-names = "default";
-	pinctrl-0 = <&eth_default>;
-	mediatek,reset-pin = <&pio 15 0>;
-	status = "okay";
 };
 
 &pwm {
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-evb.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-evb.dts
new file mode 100644
index 0000000..ad2a38b
--- /dev/null
+++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-evb.dts
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: John Crispin <blogic at 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+#include "mt7623.dtsi"
+
+/ {
+	model = "MediaTek MT7623 evaluation board";
+	compatible = "mediatek,mt7623-evb", "mediatek,mt7623";
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	memory {
+		reg = <0 0x80000000 0 0x40000000>;
+	};
+/*
+	pwm_pins: pwm {
+		pins_pwm1 {
+			pinmux = <MT7623_PIN_204_PWM1_FUNC_PWM1>;
+		};
+
+		pins_pwm2 {
+			pinmux = <MT7623_PIN_205_PWM2_FUNC_PWM2>;
+		};
+	};*/
+
+};
+
+&uart2 {
+	status = "okay";
+};
+
+/*&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm_pins>;
+	status = "okay";
+};*/
diff --git a/target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch b/target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch
new file mode 100644
index 0000000..28b3d7f
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch
@@ -0,0 +1,79 @@
+From 3e96c653372d8852c45dcd3bd856975157a0fd6a Mon Sep 17 00:00:00 2001
+From: Shunli Wang <shunli.wang at mediatek.com>
+Date: Thu, 20 Oct 2016 16:56:37 +0800
+Subject: [PATCH] soc: mediatek: Add MT2701 power dt-bindings
+
+Add power dt-bindings for MT2701.
+
+Signed-off-by: Shunli Wang <shunli.wang at mediatek.com>
+Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
+Acked-by: Rob Herring <robh at kernel.org>
+Reviewed-by: Kevin Hilman <khilman at baylibre.com>
+Signed-off-by: Matthias Brugger <matthias.bgg at gmail.com>
+---
+ .../devicetree/bindings/soc/mediatek/scpsys.txt    | 13 +++++++----
+ include/dt-bindings/power/mt2701-power.h           | 27 ++++++++++++++++++++++
+ 2 files changed, 35 insertions(+), 5 deletions(-)
+ create mode 100644 include/dt-bindings/power/mt2701-power.h
+
+Index: linux-4.9.14/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+===================================================================
+--- linux-4.9.14.orig/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
++++ linux-4.9.14/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+@@ -9,17 +9,20 @@ domain control.
+ 
+ The driver implements the Generic PM domain bindings described in
+ power/power_domain.txt. It provides the power domains defined in
+-include/dt-bindings/power/mt8173-power.h.
++include/dt-bindings/power/mt8173-power.h and mt2701-power.h.
+ 
+ Required properties:
+-- compatible: Must be "mediatek,mt8173-scpsys"
++- compatible: Should be one of:
++	- "mediatek,mt2701-scpsys"
++	- "mediatek,mt8173-scpsys"
+ - #power-domain-cells: Must be 1
+ - reg: Address range of the SCPSYS unit
+ - infracfg: must contain a phandle to the infracfg controller
+ - clock, clock-names: clocks according to the common clock binding.
+-                      The clocks needed "mm", "mfg", "venc" and "venc_lt".
+-		      These are the clocks which hardware needs to be enabled
+-		      before enabling certain power domains.
++                      These are clocks which hardware needs to be
++                      enabled before enabling certain power domains.
++	Required clocks for MT2701: "mm", "mfg", "ethif"
++	Required clocks for MT8173: "mm", "mfg", "venc", "venc_lt"
+ 
+ Optional properties:
+ - vdec-supply: Power supply for the vdec power domain
+Index: linux-4.9.14/include/dt-bindings/power/mt2701-power.h
+===================================================================
+--- /dev/null
++++ linux-4.9.14/include/dt-bindings/power/mt2701-power.h
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) 2015 MediaTek Inc.
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _DT_BINDINGS_POWER_MT2701_POWER_H
++#define _DT_BINDINGS_POWER_MT2701_POWER_H
++
++#define MT2701_POWER_DOMAIN_CONN	0
++#define MT2701_POWER_DOMAIN_DISP	1
++#define MT2701_POWER_DOMAIN_IFR_MSC	2
++#define MT2701_POWER_DOMAIN_VDEC	3
++#define MT2701_POWER_DOMAIN_ISP		4
++#define MT2701_POWER_DOMAIN_BDP		5
++#define MT2701_POWER_DOMAIN_ETH		6
++#define MT2701_POWER_DOMAIN_HIF		7
++
++#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */
diff --git a/target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch b/target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
deleted file mode 100644
index 132d6c8..0000000
--- a/target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 7c5b29de78f1b15c5bde40a6ca4510fc09588457 Mon Sep 17 00:00:00 2001
-From: Shunli Wang <shunli.wang at mediatek.com>
-Date: Wed, 30 Dec 2015 14:41:45 +0800
-Subject: [PATCH 004/102] soc: mediatek: Add MT2701 power dt-bindings
-
-Add power dt-bindings for MT2701.
-
-Signed-off-by: Shunli Wang <shunli.wang at mediatek.com>
-Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
----
- include/dt-bindings/power/mt2701-power.h |   27 +++++++++++++++++++++++++++
- 1 file changed, 27 insertions(+)
- create mode 100644 include/dt-bindings/power/mt2701-power.h
-
---- /dev/null
-+++ b/include/dt-bindings/power/mt2701-power.h
-@@ -0,0 +1,27 @@
-+/*
-+ * Copyright (C) 2015 MediaTek Inc.
-+ *
-+ * This program is free software: you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef _DT_BINDINGS_POWER_MT2701_POWER_H
-+#define _DT_BINDINGS_POWER_MT2701_POWER_H
-+
-+#define MT2701_POWER_DOMAIN_CONN	0
-+#define MT2701_POWER_DOMAIN_DISP	1
-+#define MT2701_POWER_DOMAIN_MFG		2
-+#define MT2701_POWER_DOMAIN_VDEC	3
-+#define MT2701_POWER_DOMAIN_ISP		4
-+#define MT2701_POWER_DOMAIN_BDP		5
-+#define MT2701_POWER_DOMAIN_ETH		6
-+#define MT2701_POWER_DOMAIN_HIF		7
-+#define MT2701_POWER_DOMAIN_IFR_MSC	8
-+
-+#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */
diff --git a/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch b/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch
new file mode 100644
index 0000000..4c9e790
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch
@@ -0,0 +1,491 @@
+From 6078c651947a148c1de543b54fe55af43a63043a Mon Sep 17 00:00:00 2001
+From: James Liao <jamesjj.liao at mediatek.com>
+Date: Thu, 20 Oct 2016 16:56:35 +0800
+Subject: [PATCH 1/2] soc: mediatek: Refine scpsys to support multiple platform
+
+Refine scpsys driver common code to support multiple SoC / platform.
+
+Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
+Reviewed-by: Kevin Hilman <khilman at baylibre.com>
+Signed-off-by: Matthias Brugger <matthias.bgg at gmail.com>
+---
+ drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++---------------
+ 1 file changed, 210 insertions(+), 138 deletions(-)
+
+diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
+index 837effe19907..722aac80e611 100644
+--- a/drivers/soc/mediatek/mtk-scpsys.c
++++ b/drivers/soc/mediatek/mtk-scpsys.c
+@@ -11,17 +11,15 @@
+  * GNU General Public License for more details.
+  */
+ #include <linux/clk.h>
+-#include <linux/delay.h>
++#include <linux/init.h>
+ #include <linux/io.h>
+-#include <linux/kernel.h>
+ #include <linux/mfd/syscon.h>
+-#include <linux/init.h>
+ #include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_domain.h>
+-#include <linux/regmap.h>
+-#include <linux/soc/mediatek/infracfg.h>
+ #include <linux/regulator/consumer.h>
++#include <linux/soc/mediatek/infracfg.h>
++
+ #include <dt-bindings/power/mt8173-power.h>
+ 
+ #define SPM_VDE_PWR_CON			0x0210
+@@ -34,6 +32,7 @@
+ #define SPM_MFG_2D_PWR_CON		0x02c0
+ #define SPM_MFG_ASYNC_PWR_CON		0x02c4
+ #define SPM_USB_PWR_CON			0x02cc
++
+ #define SPM_PWR_STATUS			0x060c
+ #define SPM_PWR_STATUS_2ND		0x0610
+ 
+@@ -55,12 +54,21 @@
+ #define PWR_STATUS_USB			BIT(25)
+ 
+ enum clk_id {
+-	MT8173_CLK_NONE,
+-	MT8173_CLK_MM,
+-	MT8173_CLK_MFG,
+-	MT8173_CLK_VENC,
+-	MT8173_CLK_VENC_LT,
+-	MT8173_CLK_MAX,
++	CLK_NONE,
++	CLK_MM,
++	CLK_MFG,
++	CLK_VENC,
++	CLK_VENC_LT,
++	CLK_MAX,
++};
++
++static const char * const clk_names[] = {
++	NULL,
++	"mm",
++	"mfg",
++	"venc",
++	"venc_lt",
++	NULL,
+ };
+ 
+ #define MAX_CLKS	2
+@@ -76,98 +84,6 @@ struct scp_domain_data {
+ 	bool active_wakeup;
+ };
+ 
+-static const struct scp_domain_data scp_domain_data[] = {
+-	[MT8173_POWER_DOMAIN_VDEC] = {
+-		.name = "vdec",
+-		.sta_mask = PWR_STATUS_VDEC,
+-		.ctl_offs = SPM_VDE_PWR_CON,
+-		.sram_pdn_bits = GENMASK(11, 8),
+-		.sram_pdn_ack_bits = GENMASK(12, 12),
+-		.clk_id = {MT8173_CLK_MM},
+-	},
+-	[MT8173_POWER_DOMAIN_VENC] = {
+-		.name = "venc",
+-		.sta_mask = PWR_STATUS_VENC,
+-		.ctl_offs = SPM_VEN_PWR_CON,
+-		.sram_pdn_bits = GENMASK(11, 8),
+-		.sram_pdn_ack_bits = GENMASK(15, 12),
+-		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
+-	},
+-	[MT8173_POWER_DOMAIN_ISP] = {
+-		.name = "isp",
+-		.sta_mask = PWR_STATUS_ISP,
+-		.ctl_offs = SPM_ISP_PWR_CON,
+-		.sram_pdn_bits = GENMASK(11, 8),
+-		.sram_pdn_ack_bits = GENMASK(13, 12),
+-		.clk_id = {MT8173_CLK_MM},
+-	},
+-	[MT8173_POWER_DOMAIN_MM] = {
+-		.name = "mm",
+-		.sta_mask = PWR_STATUS_DISP,
+-		.ctl_offs = SPM_DIS_PWR_CON,
+-		.sram_pdn_bits = GENMASK(11, 8),
+-		.sram_pdn_ack_bits = GENMASK(12, 12),
+-		.clk_id = {MT8173_CLK_MM},
+-		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
+-			MT8173_TOP_AXI_PROT_EN_MM_M1,
+-	},
+-	[MT8173_POWER_DOMAIN_VENC_LT] = {
+-		.name = "venc_lt",
+-		.sta_mask = PWR_STATUS_VENC_LT,
+-		.ctl_offs = SPM_VEN2_PWR_CON,
+-		.sram_pdn_bits = GENMASK(11, 8),
+-		.sram_pdn_ack_bits = GENMASK(15, 12),
+-		.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
+-	},
+-	[MT8173_POWER_DOMAIN_AUDIO] = {
+-		.name = "audio",
+-		.sta_mask = PWR_STATUS_AUDIO,
+-		.ctl_offs = SPM_AUDIO_PWR_CON,
+-		.sram_pdn_bits = GENMASK(11, 8),
+-		.sram_pdn_ack_bits = GENMASK(15, 12),
+-		.clk_id = {MT8173_CLK_NONE},
+-	},
+-	[MT8173_POWER_DOMAIN_USB] = {
+-		.name = "usb",
+-		.sta_mask = PWR_STATUS_USB,
+-		.ctl_offs = SPM_USB_PWR_CON,
+-		.sram_pdn_bits = GENMASK(11, 8),
+-		.sram_pdn_ack_bits = GENMASK(15, 12),
+-		.clk_id = {MT8173_CLK_NONE},
+-		.active_wakeup = true,
+-	},
+-	[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
+-		.name = "mfg_async",
+-		.sta_mask = PWR_STATUS_MFG_ASYNC,
+-		.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
+-		.sram_pdn_bits = GENMASK(11, 8),
+-		.sram_pdn_ack_bits = 0,
+-		.clk_id = {MT8173_CLK_MFG},
+-	},
+-	[MT8173_POWER_DOMAIN_MFG_2D] = {
+-		.name = "mfg_2d",
+-		.sta_mask = PWR_STATUS_MFG_2D,
+-		.ctl_offs = SPM_MFG_2D_PWR_CON,
+-		.sram_pdn_bits = GENMASK(11, 8),
+-		.sram_pdn_ack_bits = GENMASK(13, 12),
+-		.clk_id = {MT8173_CLK_NONE},
+-	},
+-	[MT8173_POWER_DOMAIN_MFG] = {
+-		.name = "mfg",
+-		.sta_mask = PWR_STATUS_MFG,
+-		.ctl_offs = SPM_MFG_PWR_CON,
+-		.sram_pdn_bits = GENMASK(13, 8),
+-		.sram_pdn_ack_bits = GENMASK(21, 16),
+-		.clk_id = {MT8173_CLK_NONE},
+-		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
+-			MT8173_TOP_AXI_PROT_EN_MFG_M0 |
+-			MT8173_TOP_AXI_PROT_EN_MFG_M1 |
+-			MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
+-	},
+-};
+-
+-#define NUM_DOMAINS	ARRAY_SIZE(scp_domain_data)
+-
+ struct scp;
+ 
+ struct scp_domain {
+@@ -179,7 +95,7 @@ struct scp_domain {
+ };
+ 
+ struct scp {
+-	struct scp_domain domains[NUM_DOMAINS];
++	struct scp_domain *domains;
+ 	struct genpd_onecell_data pd_data;
+ 	struct device *dev;
+ 	void __iomem *base;
+@@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct device *dev)
+ 	return scpd->data->active_wakeup;
+ }
+ 
+-static int scpsys_probe(struct platform_device *pdev)
++static void init_clks(struct platform_device *pdev, struct clk **clk)
++{
++	int i;
++
++	for (i = CLK_NONE + 1; i < CLK_MAX; i++)
++		clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
++}
++
++static struct scp *init_scp(struct platform_device *pdev,
++			const struct scp_domain_data *scp_domain_data, int num)
+ {
+ 	struct genpd_onecell_data *pd_data;
+ 	struct resource *res;
+-	int i, j, ret;
++	int i, j;
+ 	struct scp *scp;
+-	struct clk *clk[MT8173_CLK_MAX];
++	struct clk *clk[CLK_MAX];
+ 
+ 	scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
+ 	if (!scp)
+-		return -ENOMEM;
++		return ERR_PTR(-ENOMEM);
+ 
+ 	scp->dev = &pdev->dev;
+ 
+ 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ 	scp->base = devm_ioremap_resource(&pdev->dev, res);
+ 	if (IS_ERR(scp->base))
+-		return PTR_ERR(scp->base);
++		return ERR_CAST(scp->base);
++
++	scp->domains = devm_kzalloc(&pdev->dev,
++				sizeof(*scp->domains) * num, GFP_KERNEL);
++	if (!scp->domains)
++		return ERR_PTR(-ENOMEM);
+ 
+ 	pd_data = &scp->pd_data;
+ 
+ 	pd_data->domains = devm_kzalloc(&pdev->dev,
+-			sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
++			sizeof(*pd_data->domains) * num, GFP_KERNEL);
+ 	if (!pd_data->domains)
+-		return -ENOMEM;
+-
+-	clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
+-	if (IS_ERR(clk[MT8173_CLK_MM]))
+-		return PTR_ERR(clk[MT8173_CLK_MM]);
+-
+-	clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
+-	if (IS_ERR(clk[MT8173_CLK_MFG]))
+-		return PTR_ERR(clk[MT8173_CLK_MFG]);
+-
+-	clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
+-	if (IS_ERR(clk[MT8173_CLK_VENC]))
+-		return PTR_ERR(clk[MT8173_CLK_VENC]);
+-
+-	clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
+-	if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
+-		return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
++		return ERR_PTR(-ENOMEM);
+ 
+ 	scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ 			"infracfg");
+ 	if (IS_ERR(scp->infracfg)) {
+ 		dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
+ 				PTR_ERR(scp->infracfg));
+-		return PTR_ERR(scp->infracfg);
++		return ERR_CAST(scp->infracfg);
+ 	}
+ 
+-	for (i = 0; i < NUM_DOMAINS; i++) {
++	for (i = 0; i < num; i++) {
+ 		struct scp_domain *scpd = &scp->domains[i];
+ 		const struct scp_domain_data *data = &scp_domain_data[i];
+ 
+@@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_device *pdev)
+ 			if (PTR_ERR(scpd->supply) == -ENODEV)
+ 				scpd->supply = NULL;
+ 			else
+-				return PTR_ERR(scpd->supply);
++				return ERR_CAST(scpd->supply);
+ 		}
+ 	}
+ 
+-	pd_data->num_domains = NUM_DOMAINS;
++	pd_data->num_domains = num;
+ 
+-	for (i = 0; i < NUM_DOMAINS; i++) {
++	init_clks(pdev, clk);
++
++	for (i = 0; i < num; i++) {
+ 		struct scp_domain *scpd = &scp->domains[i];
+ 		struct generic_pm_domain *genpd = &scpd->genpd;
+ 		const struct scp_domain_data *data = &scp_domain_data[i];
+@@ -482,13 +398,37 @@ static int scpsys_probe(struct platform_device *pdev)
+ 		scpd->scp = scp;
+ 
+ 		scpd->data = data;
+-		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
+-			scpd->clk[j] = clk[data->clk_id[j]];
++
++		for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
++			struct clk *c = clk[data->clk_id[j]];
++
++			if (IS_ERR(c)) {
++				dev_err(&pdev->dev, "%s: clk unavailable\n",
++					data->name);
++				return ERR_CAST(c);
++			}
++
++			scpd->clk[j] = c;
++		}
+ 
+ 		genpd->name = data->name;
+ 		genpd->power_off = scpsys_power_off;
+ 		genpd->power_on = scpsys_power_on;
+ 		genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
++	}
++
++	return scp;
++}
++
++static void mtk_register_power_domains(struct platform_device *pdev,
++				struct scp *scp, int num)
++{
++	struct genpd_onecell_data *pd_data;
++	int i, ret;
++
++	for (i = 0; i < num; i++) {
++		struct scp_domain *scpd = &scp->domains[i];
++		struct generic_pm_domain *genpd = &scpd->genpd;
+ 
+ 		/*
+ 		 * Initially turn on all domains to make the domains usable
+@@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_device *pdev)
+ 	 * valid.
+ 	 */
+ 
++	pd_data = &scp->pd_data;
++
++	ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
++	if (ret)
++		dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
++}
++
++/*
++ * MT8173 power domain support
++ */
++
++static const struct scp_domain_data scp_domain_data_mt8173[] = {
++	[MT8173_POWER_DOMAIN_VDEC] = {
++		.name = "vdec",
++		.sta_mask = PWR_STATUS_VDEC,
++		.ctl_offs = SPM_VDE_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(12, 12),
++		.clk_id = {CLK_MM},
++	},
++	[MT8173_POWER_DOMAIN_VENC] = {
++		.name = "venc",
++		.sta_mask = PWR_STATUS_VENC,
++		.ctl_offs = SPM_VEN_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(15, 12),
++		.clk_id = {CLK_MM, CLK_VENC},
++	},
++	[MT8173_POWER_DOMAIN_ISP] = {
++		.name = "isp",
++		.sta_mask = PWR_STATUS_ISP,
++		.ctl_offs = SPM_ISP_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(13, 12),
++		.clk_id = {CLK_MM},
++	},
++	[MT8173_POWER_DOMAIN_MM] = {
++		.name = "mm",
++		.sta_mask = PWR_STATUS_DISP,
++		.ctl_offs = SPM_DIS_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(12, 12),
++		.clk_id = {CLK_MM},
++		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
++			MT8173_TOP_AXI_PROT_EN_MM_M1,
++	},
++	[MT8173_POWER_DOMAIN_VENC_LT] = {
++		.name = "venc_lt",
++		.sta_mask = PWR_STATUS_VENC_LT,
++		.ctl_offs = SPM_VEN2_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(15, 12),
++		.clk_id = {CLK_MM, CLK_VENC_LT},
++	},
++	[MT8173_POWER_DOMAIN_AUDIO] = {
++		.name = "audio",
++		.sta_mask = PWR_STATUS_AUDIO,
++		.ctl_offs = SPM_AUDIO_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(15, 12),
++		.clk_id = {CLK_NONE},
++	},
++	[MT8173_POWER_DOMAIN_USB] = {
++		.name = "usb",
++		.sta_mask = PWR_STATUS_USB,
++		.ctl_offs = SPM_USB_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(15, 12),
++		.clk_id = {CLK_NONE},
++		.active_wakeup = true,
++	},
++	[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
++		.name = "mfg_async",
++		.sta_mask = PWR_STATUS_MFG_ASYNC,
++		.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = 0,
++		.clk_id = {CLK_MFG},
++	},
++	[MT8173_POWER_DOMAIN_MFG_2D] = {
++		.name = "mfg_2d",
++		.sta_mask = PWR_STATUS_MFG_2D,
++		.ctl_offs = SPM_MFG_2D_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(13, 12),
++		.clk_id = {CLK_NONE},
++	},
++	[MT8173_POWER_DOMAIN_MFG] = {
++		.name = "mfg",
++		.sta_mask = PWR_STATUS_MFG,
++		.ctl_offs = SPM_MFG_PWR_CON,
++		.sram_pdn_bits = GENMASK(13, 8),
++		.sram_pdn_ack_bits = GENMASK(21, 16),
++		.clk_id = {CLK_NONE},
++		.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
++			MT8173_TOP_AXI_PROT_EN_MFG_M0 |
++			MT8173_TOP_AXI_PROT_EN_MFG_M1 |
++			MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
++	},
++};
++
++#define NUM_DOMAINS_MT8173	ARRAY_SIZE(scp_domain_data_mt8173)
++
++static int __init scpsys_probe_mt8173(struct platform_device *pdev)
++{
++	struct scp *scp;
++	struct genpd_onecell_data *pd_data;
++	int ret;
++
++	scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173);
++	if (IS_ERR(scp))
++		return PTR_ERR(scp);
++
++	mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173);
++
++	pd_data = &scp->pd_data;
++
+ 	ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC],
+ 		pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]);
+ 	if (ret && IS_ENABLED(CONFIG_PM))
+@@ -517,21 +574,36 @@ static int scpsys_probe(struct platform_device *pdev)
+ 	if (ret && IS_ENABLED(CONFIG_PM))
+ 		dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
+ 
+-	ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
+-	if (ret)
+-		dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
+-
+ 	return 0;
+ }
+ 
++/*
++ * scpsys driver init
++ */
++
+ static const struct of_device_id of_scpsys_match_tbl[] = {
+ 	{
+ 		.compatible = "mediatek,mt8173-scpsys",
++		.data = scpsys_probe_mt8173,
+ 	}, {
+ 		/* sentinel */
+ 	}
+ };
+ 
++static int scpsys_probe(struct platform_device *pdev)
++{
++	int (*probe)(struct platform_device *);
++	const struct of_device_id *of_id;
++
++	of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node);
++	if (!of_id || !of_id->data)
++		return -EINVAL;
++
++	probe = of_id->data;
++
++	return probe(pdev);
++}
++
+ static struct platform_driver scpsys_drv = {
+ 	.probe = scpsys_probe,
+ 	.driver = {
+-- 
+2.11.0
+
diff --git a/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch b/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch
new file mode 100644
index 0000000..c56a8a9
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch
@@ -0,0 +1,198 @@
+From 112ef1882e12094c823937f9d72f2f598db02df7 Mon Sep 17 00:00:00 2001
+From: Shunli Wang <shunli.wang at mediatek.com>
+Date: Thu, 20 Oct 2016 16:56:38 +0800
+Subject: [PATCH 2/2] soc: mediatek: Add MT2701 scpsys driver
+
+Add scpsys driver for MT2701.
+
+mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should
+be enabled on both arm64 and arm platforms.
+
+Signed-off-by: Shunli Wang <shunli.wang at mediatek.com>
+Signed-off-by: James Liao <jamesjj.liao at mediatek.com>
+Reviewed-by: Kevin Hilman <khilman at baylibre.com>
+Signed-off-by: Matthias Brugger <matthias.bgg at gmail.com>
+---
+ drivers/soc/mediatek/Kconfig      |   2 +-
+ drivers/soc/mediatek/mtk-scpsys.c | 117 +++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 117 insertions(+), 2 deletions(-)
+
+Index: linux-4.9.14/drivers/soc/mediatek/Kconfig
+===================================================================
+--- linux-4.9.14.orig/drivers/soc/mediatek/Kconfig
++++ linux-4.9.14/drivers/soc/mediatek/Kconfig
+@@ -23,7 +23,7 @@ config MTK_PMIC_WRAP
+ config MTK_SCPSYS
+ 	bool "MediaTek SCPSYS Support"
+ 	depends on ARCH_MEDIATEK || COMPILE_TEST
+-	default ARM64 && ARCH_MEDIATEK
++	default ARCH_MEDIATEK
+ 	select REGMAP
+ 	select MTK_INFRACFG
+ 	select PM_GENERIC_DOMAINS if PM
+Index: linux-4.9.14/drivers/soc/mediatek/mtk-scpsys.c
+===================================================================
+--- linux-4.9.14.orig/drivers/soc/mediatek/mtk-scpsys.c
++++ linux-4.9.14/drivers/soc/mediatek/mtk-scpsys.c
+@@ -20,6 +20,7 @@
+ #include <linux/regulator/consumer.h>
+ #include <linux/soc/mediatek/infracfg.h>
+ 
++#include <dt-bindings/power/mt2701-power.h>
+ #include <dt-bindings/power/mt8173-power.h>
+ 
+ #define SPM_VDE_PWR_CON			0x0210
+@@ -27,8 +28,13 @@
+ #define SPM_VEN_PWR_CON			0x0230
+ #define SPM_ISP_PWR_CON			0x0238
+ #define SPM_DIS_PWR_CON			0x023c
++#define SPM_CONN_PWR_CON		0x0280
+ #define SPM_VEN2_PWR_CON		0x0298
+-#define SPM_AUDIO_PWR_CON		0x029c
++#define SPM_AUDIO_PWR_CON		0x029c	/* MT8173 */
++#define SPM_BDP_PWR_CON			0x029c	/* MT2701 */
++#define SPM_ETH_PWR_CON			0x02a0
++#define SPM_HIF_PWR_CON			0x02a4
++#define SPM_IFR_MSC_PWR_CON		0x02a8
+ #define SPM_MFG_2D_PWR_CON		0x02c0
+ #define SPM_MFG_ASYNC_PWR_CON		0x02c4
+ #define SPM_USB_PWR_CON			0x02cc
+@@ -42,10 +48,15 @@
+ #define PWR_ON_2ND_BIT			BIT(3)
+ #define PWR_CLK_DIS_BIT			BIT(4)
+ 
++#define PWR_STATUS_CONN			BIT(1)
+ #define PWR_STATUS_DISP			BIT(3)
+ #define PWR_STATUS_MFG			BIT(4)
+ #define PWR_STATUS_ISP			BIT(5)
+ #define PWR_STATUS_VDEC			BIT(7)
++#define PWR_STATUS_BDP			BIT(14)
++#define PWR_STATUS_ETH			BIT(15)
++#define PWR_STATUS_HIF			BIT(16)
++#define PWR_STATUS_IFR_MSC		BIT(17)
+ #define PWR_STATUS_VENC_LT		BIT(20)
+ #define PWR_STATUS_VENC			BIT(21)
+ #define PWR_STATUS_MFG_2D		BIT(22)
+@@ -59,6 +70,7 @@ enum clk_id {
+ 	CLK_MFG,
+ 	CLK_VENC,
+ 	CLK_VENC_LT,
++	CLK_ETHIF,
+ 	CLK_MAX,
+ };
+ 
+@@ -68,6 +80,7 @@ static const char * const clk_names[] =
+ 	"mfg",
+ 	"venc",
+ 	"venc_lt",
++	"ethif",
+ 	NULL,
+ };
+ 
+@@ -455,6 +468,96 @@ static void mtk_register_power_domains(s
+ }
+ 
+ /*
++ * MT2701 power domain support
++ */
++
++static const struct scp_domain_data scp_domain_data_mt2701[] = {
++	[MT2701_POWER_DOMAIN_CONN] = {
++		.name = "conn",
++		.sta_mask = PWR_STATUS_CONN,
++		.ctl_offs = SPM_CONN_PWR_CON,
++		.bus_prot_mask = 0x0104,
++		.clk_id = {CLK_NONE},
++		.active_wakeup = true,
++	},
++	[MT2701_POWER_DOMAIN_DISP] = {
++		.name = "disp",
++		.sta_mask = PWR_STATUS_DISP,
++		.ctl_offs = SPM_DIS_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.clk_id = {CLK_MM},
++		.bus_prot_mask = 0x0002,
++		.active_wakeup = true,
++	},
++	[MT2701_POWER_DOMAIN_VDEC] = {
++		.name = "vdec",
++		.sta_mask = PWR_STATUS_VDEC,
++		.ctl_offs = SPM_VDE_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(12, 12),
++		.clk_id = {CLK_MM},
++		.active_wakeup = true,
++	},
++	[MT2701_POWER_DOMAIN_ISP] = {
++		.name = "isp",
++		.sta_mask = PWR_STATUS_ISP,
++		.ctl_offs = SPM_ISP_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(13, 12),
++		.clk_id = {CLK_MM},
++		.active_wakeup = true,
++	},
++	[MT2701_POWER_DOMAIN_BDP] = {
++		.name = "bdp",
++		.sta_mask = PWR_STATUS_BDP,
++		.ctl_offs = SPM_BDP_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.clk_id = {CLK_NONE},
++		.active_wakeup = true,
++	},
++	[MT2701_POWER_DOMAIN_ETH] = {
++		.name = "eth",
++		.sta_mask = PWR_STATUS_ETH,
++		.ctl_offs = SPM_ETH_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(15, 12),
++		.clk_id = {CLK_ETHIF},
++		.active_wakeup = true,
++	},
++	[MT2701_POWER_DOMAIN_HIF] = {
++		.name = "hif",
++		.sta_mask = PWR_STATUS_HIF,
++		.ctl_offs = SPM_HIF_PWR_CON,
++		.sram_pdn_bits = GENMASK(11, 8),
++		.sram_pdn_ack_bits = GENMASK(15, 12),
++		.clk_id = {CLK_ETHIF},
++		.active_wakeup = true,
++	},
++	[MT2701_POWER_DOMAIN_IFR_MSC] = {
++		.name = "ifr_msc",
++		.sta_mask = PWR_STATUS_IFR_MSC,
++		.ctl_offs = SPM_IFR_MSC_PWR_CON,
++		.clk_id = {CLK_NONE},
++		.active_wakeup = true,
++	},
++};
++
++#define NUM_DOMAINS_MT2701	ARRAY_SIZE(scp_domain_data_mt2701)
++
++static int __init scpsys_probe_mt2701(struct platform_device *pdev)
++{
++	struct scp *scp;
++
++	scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701);
++	if (IS_ERR(scp))
++		return PTR_ERR(scp);
++
++	mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701);
++
++	return 0;
++}
++
++/*
+  * MT8173 power domain support
+  */
+ 
+@@ -583,6 +686,9 @@ static int __init scpsys_probe_mt8173(st
+ 
+ static const struct of_device_id of_scpsys_match_tbl[] = {
+ 	{
++		.compatible = "mediatek,mt2701-scpsys",
++		.data = scpsys_probe_mt2701,
++	}, {
+ 		.compatible = "mediatek,mt8173-scpsys",
+ 		.data = scpsys_probe_mt8173,
+ 	}, {
diff --git a/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch b/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch
index 24437cf..cf604f4 100644
--- a/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch
+++ b/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch
@@ -13,36 +13,10 @@ Signed-off-by: John Crispin <john at phrozen.org>
  5 files changed, 279 insertions(+)
  create mode 100644 drivers/pwm/pwm-mediatek.c
 
---- a/arch/arm/boot/dts/mt7623-evb.dts
-+++ b/arch/arm/boot/dts/mt7623-evb.dts
-@@ -26,8 +26,25 @@
- 	memory {
- 		reg = <0 0x80000000 0 0x40000000>;
- 	};
-+/*
-+	pwm_pins: pwm {
-+		pins_pwm1 {
-+			pinmux = <MT7623_PIN_204_PWM1_FUNC_PWM1>;
-+		};
-+
-+		pins_pwm2 {
-+			pinmux = <MT7623_PIN_205_PWM2_FUNC_PWM2>;
-+		};
-+	};*/
-+
- };
- 
- &uart2 {
- 	status = "okay";
- };
-+
-+/*&pwm {
-+	pinctrl-names = "default";
-+	pinctrl-0 = <&pwm_pins>;
-+	status = "okay";
-+};*/
---- a/drivers/pwm/Kconfig
-+++ b/drivers/pwm/Kconfig
+Index: linux-4.9.17/drivers/pwm/Kconfig
+===================================================================
+--- linux-4.9.17.orig/drivers/pwm/Kconfig
++++ linux-4.9.17/drivers/pwm/Kconfig
 @@ -282,6 +282,15 @@ config PWM_MTK_DISP
  	  To compile this driver as a module, choose M here: the module
  	  will be called pwm-mtk-disp.
@@ -59,8 +33,10 @@ Signed-off-by: John Crispin <john at phrozen.org>
  config PWM_MXS
  	tristate "Freescale MXS PWM support"
  	depends on ARCH_MXS && OF
---- a/drivers/pwm/Makefile
-+++ b/drivers/pwm/Makefile
+Index: linux-4.9.17/drivers/pwm/Makefile
+===================================================================
+--- linux-4.9.17.orig/drivers/pwm/Makefile
++++ linux-4.9.17/drivers/pwm/Makefile
 @@ -25,6 +25,7 @@ obj-$(CONFIG_PWM_LPSS)		+= pwm-lpss.o
  obj-$(CONFIG_PWM_LPSS_PCI)	+= pwm-lpss-pci.o
  obj-$(CONFIG_PWM_LPSS_PLATFORM)	+= pwm-lpss-platform.o
@@ -69,8 +45,10 @@ Signed-off-by: John Crispin <john at phrozen.org>
  obj-$(CONFIG_PWM_MTK_DISP)	+= pwm-mtk-disp.o
  obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o
  obj-$(CONFIG_PWM_OMAP_DMTIMER)	+= pwm-omap-dmtimer.o
+Index: linux-4.9.17/drivers/pwm/pwm-mediatek.c
+===================================================================
 --- /dev/null
-+++ b/drivers/pwm/pwm-mediatek.c
++++ linux-4.9.17/drivers/pwm/pwm-mediatek.c
 @@ -0,0 +1,230 @@
 +/*
 + * Mediatek Pulse Width Modulator driver
diff --git a/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch b/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch
new file mode 100644
index 0000000..a72da69
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch
@@ -0,0 +1,43 @@
+From patchwork Fri Feb 24 18:47:21 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,4/4] mfd: mt6397: Add MT6323 LED support into MT6397 driver
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9591021
+Message-Id: <1487962041-6548-5-git-send-email-sean.wang at mediatek.com>
+To: <rpurdie at rpsys.net>, <jacek.anaszewski at gmail.com>, <lee.jones at linaro.org>, 
+ <matthias.bgg at gmail.com>, <pavel at ucw.cz>, <robh+dt at kernel.org>,
+ <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, keyhaede at gmail.com,
+ Sean Wang <sean.wang at mediatek.com>, linux-kernel at vger.kernel.org,
+ linux-mediatek at lists.infradead.org, linux-leds at vger.kernel.org,
+ linux-arm-kernel at lists.infradead.org
+Date: Sat, 25 Feb 2017 02:47:21 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+Add compatible string as "mt6323-led" that will make
+the OF core spawn child devices for the LED subnode
+of that MT6323 MFD device.
+
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+---
+ drivers/mfd/mt6397-core.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
+index e14d8b0..8e601c8 100644
+--- a/drivers/mfd/mt6397-core.c
++++ b/drivers/mfd/mt6397-core.c
+@@ -48,6 +48,10 @@
+ 		.name = "mt6323-regulator",
+ 		.of_compatible = "mediatek,mt6323-regulator"
+ 	},
++	{
++		.name = "mt6323-led",
++		.of_compatible = "mediatek,mt6323-led"
++	},
+ };
+ 
+ static const struct mfd_cell mt6397_devs[] = {
diff --git a/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch b/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch
new file mode 100644
index 0000000..96662dd
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch
@@ -0,0 +1,94 @@
+From patchwork Mon Mar 20 06:47:24 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v6,1/4] dt-bindings: leds: Add document bindings for leds-mt6323
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9633073
+Message-Id: <1489992447-13007-2-git-send-email-sean.wang at mediatek.com>
+To: <rpurdie at rpsys.net>, <jacek.anaszewski at gmail.com>, <lee.jones at linaro.org>, 
+ <matthias.bgg at gmail.com>, <pavel at ucw.cz>, <robh+dt at kernel.org>,
+ <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, keyhaede at gmail.com,
+ Sean Wang <sean.wang at mediatek.com>, linux-kernel at vger.kernel.org,
+ linux-mediatek at lists.infradead.org, linux-leds at vger.kernel.org,
+ linux-arm-kernel at lists.infradead.org
+Date: Mon, 20 Mar 2017 14:47:24 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+This patch adds documentation for devicetree bindings for LED support on
+MT6323 PMIC.
+
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+---
+ .../devicetree/bindings/leds/leds-mt6323.txt       | 60 ++++++++++++++++++++++
+ 1 file changed, 60 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/leds/leds-mt6323.txt
+
+diff --git a/Documentation/devicetree/bindings/leds/leds-mt6323.txt b/Documentation/devicetree/bindings/leds/leds-mt6323.txt
+new file mode 100644
+index 0000000..ac38472
+--- /dev/null
++++ b/Documentation/devicetree/bindings/leds/leds-mt6323.txt
+@@ -0,0 +1,60 @@
++Device Tree Bindings for LED support on MT6323 PMIC
++
++MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED
++controllers are defined as the subnode of the function node provided by MT6323
++PMIC controller that is being defined as one kind of Muti-Function Device (MFD)
++using shared bus called PMIC wrapper for each subfunction to access remote
++MT6323 PMIC hardware.
++
++For MT6323 MFD bindings see:
++Documentation/devicetree/bindings/mfd/mt6397.txt
++For MediaTek PMIC wrapper bindings see:
++Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
++
++Required properties:
++- compatible : Must be "mediatek,mt6323-led"
++- address-cells : Must be 1
++- size-cells : Must be 0
++
++Each led is represented as a child node of the mediatek,mt6323-led that
++describes the initial behavior for each LED physically and currently only four
++LED child nodes can be supported.
++
++Required properties for the LED child node:
++- reg : LED channel number (0..3)
++
++Optional properties for the LED child node:
++- label : See Documentation/devicetree/bindings/leds/common.txt
++- linux,default-trigger : See Documentation/devicetree/bindings/leds/common.txt
++- default-state: See Documentation/devicetree/bindings/leds/common.txt
++
++Example:
++
++	mt6323: pmic {
++		compatible = "mediatek,mt6323";
++
++		...
++
++		mt6323led: leds {
++			compatible = "mediatek,mt6323-led";
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			led at 0 {
++				reg = <0>;
++				label = "LED0";
++				linux,default-trigger = "timer";
++				default-state = "on";
++			};
++			led at 1 {
++				reg = <1>;
++				label = "LED1";
++				default-state = "off";
++			};
++			led at 2 {
++				reg = <2>;
++				label = "LED2";
++				default-state = "on";
++			};
++		};
++	};
diff --git a/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch b/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch
new file mode 100644
index 0000000..215b1b0
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch
@@ -0,0 +1,40 @@
+From patchwork Mon Mar 20 06:47:25 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v6,
+ 2/4] dt-bindings: mfd: Add the description for LED as the sub module
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9633089
+Message-Id: <1489992447-13007-3-git-send-email-sean.wang at mediatek.com>
+To: <rpurdie at rpsys.net>, <jacek.anaszewski at gmail.com>, <lee.jones at linaro.org>, 
+ <matthias.bgg at gmail.com>, <pavel at ucw.cz>, <robh+dt at kernel.org>,
+ <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, keyhaede at gmail.com,
+ Sean Wang <sean.wang at mediatek.com>, linux-kernel at vger.kernel.org,
+ linux-mediatek at lists.infradead.org, linux-leds at vger.kernel.org,
+ linux-arm-kernel at lists.infradead.org
+Date: Mon, 20 Mar 2017 14:47:25 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+This patch adds description for LED as the sub-module on MT6397/MT6323
+multifunction device.
+
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+---
+ Documentation/devicetree/bindings/mfd/mt6397.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt
+index c568d52..522a3bb 100644
+--- a/Documentation/devicetree/bindings/mfd/mt6397.txt
++++ b/Documentation/devicetree/bindings/mfd/mt6397.txt
+@@ -6,6 +6,7 @@ MT6397/MT6323 is a multifunction device with the following sub modules:
+ - Audio codec
+ - GPIO
+ - Clock
++- LED
+ 
+ It is interfaced to host controller using SPI interface by a proprietary hardware
+ called PMIC wrapper or pwrap. MT6397/MT6323 MFD is a child device of pwrap.
diff --git a/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch b/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch
new file mode 100644
index 0000000..f3bc921
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch
@@ -0,0 +1,558 @@
+From patchwork Mon Mar 20 06:47:26 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v6,3/4] leds: Add LED support for MT6323 PMIC
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9633081
+Message-Id: <1489992447-13007-4-git-send-email-sean.wang at mediatek.com>
+To: <rpurdie at rpsys.net>, <jacek.anaszewski at gmail.com>, <lee.jones at linaro.org>, 
+ <matthias.bgg at gmail.com>, <pavel at ucw.cz>, <robh+dt at kernel.org>,
+ <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, keyhaede at gmail.com,
+ Sean Wang <sean.wang at mediatek.com>, linux-kernel at vger.kernel.org,
+ linux-mediatek at lists.infradead.org, linux-leds at vger.kernel.org,
+ linux-arm-kernel at lists.infradead.org
+Date: Mon, 20 Mar 2017 14:47:26 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+MT6323 PMIC is a multi-function device that includes LED function.
+It allows attaching up to 4 LEDs which can either be on, off or dimmed
+and/or blinked with the controller.
+
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+Reviewed-by: Jacek Anaszewski <jacek.anaszewski at gmail.com>
+---
+ drivers/leds/Kconfig       |   8 +
+ drivers/leds/Makefile      |   1 +
+ drivers/leds/leds-mt6323.c | 502 +++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 511 insertions(+)
+ create mode 100644 drivers/leds/leds-mt6323.c
+
+Index: linux-4.9.17/drivers/leds/Kconfig
+===================================================================
+--- linux-4.9.17.orig/drivers/leds/Kconfig
++++ linux-4.9.17/drivers/leds/Kconfig
+@@ -117,6 +117,14 @@ config LEDS_MIKROTIK_RB532
+ 	  This option enables support for the so called "User LED" of
+ 	  Mikrotik's Routerboard 532.
+ 
++config LEDS_MT6323
++	tristate "LED Support for Mediatek MT6323 PMIC"
++	depends on LEDS_CLASS
++	depends on MFD_MT6397
++	help
++	  This option enables support for on-chip LED drivers found on
++	  Mediatek MT6323 PMIC.
++
+ config LEDS_S3C24XX
+ 	tristate "LED Support for Samsung S3C24XX GPIO LEDs"
+ 	depends on LEDS_CLASS
+Index: linux-4.9.17/drivers/leds/leds-mt6323.c
+===================================================================
+--- /dev/null
++++ linux-4.9.17/drivers/leds/leds-mt6323.c
+@@ -0,0 +1,502 @@
++/*
++ * LED driver for Mediatek MT6323 PMIC
++ *
++ * Copyright (C) 2017 Sean Wang <sean.wang at mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++#include <linux/kernel.h>
++#include <linux/leds.h>
++#include <linux/mfd/mt6323/registers.h>
++#include <linux/mfd/mt6397/core.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++
++/*
++ * Register field for MT6323_TOP_CKPDN0 to enable
++ * 32K clock common for LED device.
++ */
++#define MT6323_RG_DRV_32K_CK_PDN	BIT(11)
++#define MT6323_RG_DRV_32K_CK_PDN_MASK	BIT(11)
++
++/*
++ * Register field for MT6323_TOP_CKPDN2 to enable
++ * individual clock for LED device.
++ */
++#define MT6323_RG_ISINK_CK_PDN(i)	BIT(i)
++#define MT6323_RG_ISINK_CK_PDN_MASK(i)	BIT(i)
++
++/*
++ * Register field for MT6323_TOP_CKCON1 to select
++ * clock source.
++ */
++#define MT6323_RG_ISINK_CK_SEL_MASK(i)	(BIT(10) << (i))
++
++/*
++ * Register for MT6323_ISINK_CON0 to setup the
++ * duty cycle of the blink.
++ */
++#define MT6323_ISINK_CON0(i)		(MT6323_ISINK0_CON0 + 0x8 * (i))
++#define MT6323_ISINK_DIM_DUTY_MASK	(0x1f << 8)
++#define MT6323_ISINK_DIM_DUTY(i)	(((i) << 8) & \
++					MT6323_ISINK_DIM_DUTY_MASK)
++
++/* Register to setup the period of the blink. */
++#define MT6323_ISINK_CON1(i)		(MT6323_ISINK0_CON1 + 0x8 * (i))
++#define MT6323_ISINK_DIM_FSEL_MASK	(0xffff)
++#define MT6323_ISINK_DIM_FSEL(i)	((i) & MT6323_ISINK_DIM_FSEL_MASK)
++
++/* Register to control the brightness. */
++#define MT6323_ISINK_CON2(i)		(MT6323_ISINK0_CON2 + 0x8 * (i))
++#define MT6323_ISINK_CH_STEP_SHIFT	12
++#define MT6323_ISINK_CH_STEP_MASK	(0x7 << 12)
++#define MT6323_ISINK_CH_STEP(i)		(((i) << 12) & \
++					MT6323_ISINK_CH_STEP_MASK)
++#define MT6323_ISINK_SFSTR0_TC_MASK	(0x3 << 1)
++#define MT6323_ISINK_SFSTR0_TC(i)	(((i) << 1) & \
++					MT6323_ISINK_SFSTR0_TC_MASK)
++#define MT6323_ISINK_SFSTR0_EN_MASK	BIT(0)
++#define MT6323_ISINK_SFSTR0_EN		BIT(0)
++
++/* Register to LED channel enablement. */
++#define MT6323_ISINK_CH_EN_MASK(i)	BIT(i)
++#define MT6323_ISINK_CH_EN(i)		BIT(i)
++
++#define MT6323_MAX_PERIOD		10000
++#define MT6323_MAX_LEDS			4
++#define MT6323_MAX_BRIGHTNESS		6
++#define MT6323_UNIT_DUTY		3125
++#define MT6323_CAL_HW_DUTY(o, p)	DIV_ROUND_CLOSEST((o) * 100000ul,\
++					(p) * MT6323_UNIT_DUTY)
++
++struct mt6323_leds;
++
++/**
++ * struct mt6323_led - state container for the LED device
++ * @id:			the identifier in MT6323 LED device
++ * @parent:		the pointer to MT6323 LED controller
++ * @cdev:		LED class device for this LED device
++ * @current_brightness: current state of the LED device
++ */
++struct mt6323_led {
++	int			id;
++	struct mt6323_leds	*parent;
++	struct led_classdev	cdev;
++	enum led_brightness	current_brightness;
++};
++
++/**
++ * struct mt6323_leds -	state container for holding LED controller
++ *			of the driver
++ * @dev:		the device pointer
++ * @hw:			the underlying hardware providing shared
++ *			bus for the register operations
++ * @lock:		the lock among process context
++ * @led:		the array that contains the state of individual
++ *			LED device
++ */
++struct mt6323_leds {
++	struct device		*dev;
++	struct mt6397_chip	*hw;
++	/* protect among process context */
++	struct mutex		lock;
++	struct mt6323_led	*led[MT6323_MAX_LEDS];
++};
++
++static int mt6323_led_hw_brightness(struct led_classdev *cdev,
++				    enum led_brightness brightness)
++{
++	struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++	struct mt6323_leds *leds = led->parent;
++	struct regmap *regmap = leds->hw->regmap;
++	u32 con2_mask = 0, con2_val = 0;
++	int ret;
++
++	/*
++	 * Setup current output for the corresponding
++	 * brightness level.
++	 */
++	con2_mask |= MT6323_ISINK_CH_STEP_MASK |
++		     MT6323_ISINK_SFSTR0_TC_MASK |
++		     MT6323_ISINK_SFSTR0_EN_MASK;
++	con2_val |=  MT6323_ISINK_CH_STEP(brightness - 1) |
++		     MT6323_ISINK_SFSTR0_TC(2) |
++		     MT6323_ISINK_SFSTR0_EN;
++
++	ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id),
++				 con2_mask, con2_val);
++	return ret;
++}
++
++static int mt6323_led_hw_off(struct led_classdev *cdev)
++{
++	struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++	struct mt6323_leds *leds = led->parent;
++	struct regmap *regmap = leds->hw->regmap;
++	unsigned int status;
++	int ret;
++
++	status = MT6323_ISINK_CH_EN(led->id);
++	ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
++				 MT6323_ISINK_CH_EN_MASK(led->id), ~status);
++	if (ret < 0)
++		return ret;
++
++	usleep_range(100, 300);
++	ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
++				 MT6323_RG_ISINK_CK_PDN_MASK(led->id),
++				 MT6323_RG_ISINK_CK_PDN(led->id));
++	if (ret < 0)
++		return ret;
++
++	return 0;
++}
++
++static enum led_brightness
++mt6323_get_led_hw_brightness(struct led_classdev *cdev)
++{
++	struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++	struct mt6323_leds *leds = led->parent;
++	struct regmap *regmap = leds->hw->regmap;
++	unsigned int status;
++	int ret;
++
++	ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status);
++	if (ret < 0)
++		return ret;
++
++	if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id))
++		return 0;
++
++	ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status);
++	if (ret < 0)
++		return ret;
++
++	if (!(status & MT6323_ISINK_CH_EN(led->id)))
++		return 0;
++
++	ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status);
++	if (ret < 0)
++		return ret;
++
++	return  ((status & MT6323_ISINK_CH_STEP_MASK)
++		  >> MT6323_ISINK_CH_STEP_SHIFT) + 1;
++}
++
++static int mt6323_led_hw_on(struct led_classdev *cdev,
++			    enum led_brightness brightness)
++{
++	struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++	struct mt6323_leds *leds = led->parent;
++	struct regmap *regmap = leds->hw->regmap;
++	unsigned int status;
++	int ret;
++
++	/*
++	 * Setup required clock source, enable the corresponding
++	 * clock and channel and let work with continuous blink as
++	 * the default.
++	 */
++	ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1,
++				 MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0);
++	if (ret < 0)
++		return ret;
++
++	status = MT6323_RG_ISINK_CK_PDN(led->id);
++	ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
++				 MT6323_RG_ISINK_CK_PDN_MASK(led->id),
++				 ~status);
++	if (ret < 0)
++		return ret;
++
++	usleep_range(100, 300);
++
++	ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
++				 MT6323_ISINK_CH_EN_MASK(led->id),
++				 MT6323_ISINK_CH_EN(led->id));
++	if (ret < 0)
++		return ret;
++
++	ret = mt6323_led_hw_brightness(cdev, brightness);
++	if (ret < 0)
++		return ret;
++
++	ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
++				 MT6323_ISINK_DIM_DUTY_MASK,
++				 MT6323_ISINK_DIM_DUTY(31));
++	if (ret < 0)
++		return ret;
++
++	ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
++				 MT6323_ISINK_DIM_FSEL_MASK,
++				 MT6323_ISINK_DIM_FSEL(1000));
++	if (ret < 0)
++		return ret;
++
++	return 0;
++}
++
++static int mt6323_led_set_blink(struct led_classdev *cdev,
++				unsigned long *delay_on,
++				unsigned long *delay_off)
++{
++	struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++	struct mt6323_leds *leds = led->parent;
++	struct regmap *regmap = leds->hw->regmap;
++	unsigned long period;
++	u8 duty_hw;
++	int ret;
++
++	/*
++	 * Units are in ms, if over the hardware able
++	 * to support, fallback into software blink
++	 */
++	period = *delay_on + *delay_off;
++
++	if (period > MT6323_MAX_PERIOD)
++		return -EINVAL;
++
++	/*
++	 * LED subsystem requires a default user
++	 * friendly blink pattern for the LED so using
++	 * 1Hz duty cycle 50% here if without specific
++	 * value delay_on and delay off being assigned.
++	 */
++	if (!*delay_on && !*delay_off) {
++		*delay_on = 500;
++		*delay_off = 500;
++	}
++
++	/*
++	 * Calculate duty_hw based on the percentage of period during
++	 * which the led is ON.
++	 */
++	duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period);
++
++	/* hardware doesn't support zero duty cycle. */
++	if (!duty_hw)
++		return -EINVAL;
++
++	mutex_lock(&leds->lock);
++	/*
++	 * Set max_brightness as the software blink behavior
++	 * when no blink brightness.
++	 */
++	if (!led->current_brightness) {
++		ret = mt6323_led_hw_on(cdev, cdev->max_brightness);
++		if (ret < 0)
++			goto out;
++		led->current_brightness = cdev->max_brightness;
++	}
++
++	ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
++				 MT6323_ISINK_DIM_DUTY_MASK,
++				 MT6323_ISINK_DIM_DUTY(duty_hw - 1));
++	if (ret < 0)
++		goto out;
++
++	ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
++				 MT6323_ISINK_DIM_FSEL_MASK,
++				 MT6323_ISINK_DIM_FSEL(period - 1));
++out:
++	mutex_unlock(&leds->lock);
++
++	return ret;
++}
++
++static int mt6323_led_set_brightness(struct led_classdev *cdev,
++				     enum led_brightness brightness)
++{
++	struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++	struct mt6323_leds *leds = led->parent;
++	int ret;
++
++	mutex_lock(&leds->lock);
++
++	if (!led->current_brightness && brightness) {
++		ret = mt6323_led_hw_on(cdev, brightness);
++		if (ret < 0)
++			goto out;
++	} else if (brightness) {
++		ret = mt6323_led_hw_brightness(cdev, brightness);
++		if (ret < 0)
++			goto out;
++	} else {
++		ret = mt6323_led_hw_off(cdev);
++		if (ret < 0)
++			goto out;
++	}
++
++	led->current_brightness = brightness;
++out:
++	mutex_unlock(&leds->lock);
++
++	return ret;
++}
++
++static int mt6323_led_set_dt_default(struct led_classdev *cdev,
++				     struct device_node *np)
++{
++	struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++	const char *state;
++	int ret = 0;
++
++	led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
++	led->cdev.default_trigger = of_get_property(np,
++						    "linux,default-trigger",
++						    NULL);
++
++	state = of_get_property(np, "default-state", NULL);
++	if (state) {
++		if (!strcmp(state, "keep")) {
++			ret = mt6323_get_led_hw_brightness(cdev);
++			if (ret < 0)
++				return ret;
++			led->current_brightness = ret;
++			ret = 0;
++		} else if (!strcmp(state, "on")) {
++			ret =
++			mt6323_led_set_brightness(cdev, cdev->max_brightness);
++		} else  {
++			ret = mt6323_led_set_brightness(cdev, LED_OFF);
++		}
++	}
++
++	return ret;
++}
++
++static int mt6323_led_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *np = pdev->dev.of_node;
++	struct device_node *child;
++	struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent);
++	struct mt6323_leds *leds;
++	struct mt6323_led *led;
++	int ret;
++	unsigned int status;
++	u32 reg;
++
++	leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
++	if (!leds)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, leds);
++	leds->dev = dev;
++
++	/*
++	 * leds->hw points to the underlying bus for the register
++	 * controlled.
++	 */
++	leds->hw = hw;
++	mutex_init(&leds->lock);
++
++	status = MT6323_RG_DRV_32K_CK_PDN;
++	ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
++				 MT6323_RG_DRV_32K_CK_PDN_MASK, ~status);
++	if (ret < 0) {
++		dev_err(leds->dev,
++			"Failed to update MT6323_TOP_CKPDN0 Register\n");
++		return ret;
++	}
++
++	for_each_available_child_of_node(np, child) {
++		ret = of_property_read_u32(child, "reg", &reg);
++		if (ret) {
++			dev_err(dev, "Failed to read led 'reg' property\n");
++			goto put_child_node;
++		}
++
++		if (reg < 0 || reg > MT6323_MAX_LEDS || leds->led[reg]) {
++			dev_err(dev, "Invalid led reg %u\n", reg);
++			ret = -EINVAL;
++			goto put_child_node;
++		}
++
++		led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
++		if (!led) {
++			ret = -ENOMEM;
++			goto put_child_node;
++		}
++
++		leds->led[reg] = led;
++		leds->led[reg]->id = reg;
++		leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS;
++		leds->led[reg]->cdev.brightness_set_blocking =
++					mt6323_led_set_brightness;
++		leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
++		leds->led[reg]->cdev.brightness_get =
++					mt6323_get_led_hw_brightness;
++		leds->led[reg]->parent = leds;
++
++		ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child);
++		if (ret < 0) {
++			dev_err(leds->dev,
++				"Failed to LED set default from devicetree\n");
++			goto put_child_node;
++		}
++
++		ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev);
++		if (ret) {
++			dev_err(&pdev->dev, "Failed to register LED: %d\n",
++				ret);
++			goto put_child_node;
++		}
++		leds->led[reg]->cdev.dev->of_node = child;
++	}
++
++	return 0;
++
++put_child_node:
++	of_node_put(child);
++	return ret;
++}
++
++static int mt6323_led_remove(struct platform_device *pdev)
++{
++	struct mt6323_leds *leds = platform_get_drvdata(pdev);
++	int i;
++
++	/* Turn the LEDs off on driver removal. */
++	for (i = 0 ; leds->led[i] ; i++)
++		mt6323_led_hw_off(&leds->led[i]->cdev);
++
++	regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
++			   MT6323_RG_DRV_32K_CK_PDN_MASK,
++			   MT6323_RG_DRV_32K_CK_PDN);
++
++	mutex_destroy(&leds->lock);
++
++	return 0;
++}
++
++static const struct of_device_id mt6323_led_dt_match[] = {
++	{ .compatible = "mediatek,mt6323-led" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);
++
++static struct platform_driver mt6323_led_driver = {
++	.probe		= mt6323_led_probe,
++	.remove		= mt6323_led_remove,
++	.driver		= {
++		.name	= "mt6323-led",
++		.of_match_table = mt6323_led_dt_match,
++	},
++};
++
++module_platform_driver(mt6323_led_driver);
++
++MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC");
++MODULE_AUTHOR("Sean Wang <sean.wang at mediatek.com>");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch b/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch
new file mode 100644
index 0000000..701dcec
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch
@@ -0,0 +1,44 @@
+From patchwork Mon Mar 20 06:47:27 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v6,
+ 4/4] mfd: mt6397: Align the placement at which the mfd_cell of LED is
+ defined
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9633079
+Message-Id: <1489992447-13007-5-git-send-email-sean.wang at mediatek.com>
+To: <rpurdie at rpsys.net>, <jacek.anaszewski at gmail.com>, <lee.jones at linaro.org>, 
+ <matthias.bgg at gmail.com>, <pavel at ucw.cz>, <robh+dt at kernel.org>,
+ <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, keyhaede at gmail.com,
+ Sean Wang <sean.wang at mediatek.com>, linux-kernel at vger.kernel.org,
+ linux-mediatek at lists.infradead.org, linux-leds at vger.kernel.org,
+ linux-arm-kernel at lists.infradead.org
+Date: Mon, 20 Mar 2017 14:47:27 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+Align the placement as which the mfd_cell of LED is defined as the other
+members done on the structure.
+
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+Acked-by: Lee Jones <lee.jones at linaro.org>
+---
+ drivers/mfd/mt6397-core.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
+index 8e601c8..04a601f 100644
+--- a/drivers/mfd/mt6397-core.c
++++ b/drivers/mfd/mt6397-core.c
+@@ -47,8 +47,7 @@
+ 	{
+ 		.name = "mt6323-regulator",
+ 		.of_compatible = "mediatek,mt6323-regulator"
+-	},
+-	{
++	}, {
+ 		.name = "mt6323-led",
+ 		.of_compatible = "mediatek,mt6323-led"
+ 	},
diff --git a/target/linux/mediatek/patches-4.9/0091-dsa1.patch b/target/linux/mediatek/patches-4.9/0091-dsa1.patch
new file mode 100644
index 0000000..c9bad93
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0091-dsa1.patch
@@ -0,0 +1,127 @@
+From patchwork Wed Mar 29 09:38:19 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net-next,v3,1/5] dt-bindings: net: dsa: add Mediatek MT7530 binding
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9651093
+Message-Id: <1490780303-18598-2-git-send-email-sean.wang at mediatek.com>
+To: <andrew at lunn.ch>, <f.fainelli at gmail.com>,
+ <vivien.didelot at savoirfairelinux.com>, <matthias.bgg at gmail.com>,
+ <robh+dt at kernel.org>, <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, Landen.Chao at mediatek.com, keyhaede at gmail.com, 
+ netdev at vger.kernel.org, sean.wang at mediatek.com,
+ linux-kernel at vger.kernel.org, 
+ linux-mediatek at lists.infradead.org, objelf at gmail.com, davem at davemloft.net
+Date: Wed, 29 Mar 2017 17:38:19 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+Add device-tree binding for Mediatek MT7530 switch.
+
+Cc: devicetree at vger.kernel.org
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+Acked-by: Rob Herring <robh at kernel.org>
+---
+ .../devicetree/bindings/net/dsa/mt7530.txt         | 92 ++++++++++++++++++++++
+ 1 file changed, 92 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/net/dsa/mt7530.txt
+
+diff --git a/Documentation/devicetree/bindings/net/dsa/mt7530.txt b/Documentation/devicetree/bindings/net/dsa/mt7530.txt
+new file mode 100644
+index 0000000..a9bc27b
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/dsa/mt7530.txt
+@@ -0,0 +1,92 @@
++Mediatek MT7530 Ethernet switch
++================================
++
++Required properties:
++
++- compatible: Must be compatible = "mediatek,mt7530";
++- #address-cells: Must be 1.
++- #size-cells: Must be 0.
++- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part
++	on multi-chip module belong to MT7623A has or the remotely standalone
++	chip as the function MT7623N reference board provided for.
++- core-supply: Phandle to the regulator node necessary for the core power.
++- io-supply: Phandle to the regulator node necessary for the I/O power.
++	See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
++	for details for the regulator setup on these boards.
++
++If the property mediatek,mcm isn't defined, following property is required
++
++- reset-gpios: Should be a gpio specifier for a reset line.
++
++Else, following properties are required
++
++- resets : Phandle pointing to the system reset controller with
++	line index for the ethsys.
++- reset-names : Should be set to "mcm".
++
++Required properties for the child nodes within ports container:
++
++- reg: Port address described must be 6 for CPU port and from 0 to 5 for
++	user ports.
++- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled
++	 "cpu".
++
++See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional
++required, optional properties and how the integrated switch subnodes must
++be specified.
++
++Example:
++
++	&mdio0 {
++		switch at 0 {
++			compatible = "mediatek,mt7530";
++			#address-cells = <1>;
++			#size-cells = <0>;
++			reg = <0>;
++
++			core-supply = <&mt6323_vpa_reg>;
++			io-supply = <&mt6323_vemc3v3_reg>;
++			reset-gpios = <&pio 33 0>;
++
++			ports {
++				#address-cells = <1>;
++				#size-cells = <0>;
++				reg = <0>;
++				port at 0 {
++					reg = <0>;
++					label = "lan0";
++				};
++
++				port at 1 {
++					reg = <1>;
++					label = "lan1";
++				};
++
++				port at 2 {
++					reg = <2>;
++					label = "lan2";
++				};
++
++				port at 3 {
++					reg = <3>;
++					label = "lan3";
++				};
++
++				port at 4 {
++					reg = <4>;
++					label = "wan";
++				};
++
++				port at 6 {
++					reg = <6>;
++					label = "cpu";
++					ethernet = <&gmac0>;
++					phy-mode = "trgmii";
++					fixed-link {
++						speed = <1000>;
++						full-duplex;
++					};
++				};
++			};
++		};
++	};
diff --git a/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch b/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch
new file mode 100644
index 0000000..5ae90e3
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch
@@ -0,0 +1,95 @@
+From 81cdbda2a08375b9d5915567d2210bf2433e7332 Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Sat, 23 Apr 2016 11:57:21 +0200
+Subject: [PATCH 081/102] net-next: mediatek: fix DQL support
+
+The MTK ethernet core has 2 MACs both sitting on the same DMA ring. The
+current code will assign the TX traffic of each MAC to its own DQL. This
+results in the amount of data, that DQL says is in the queue incorrect. As
+the data from multiple devices is infact enqueued. This makes any decision
+based on these value non deterministic. Fix this by tracking all TX
+traffic, regardless of the MAC it belongs to in the DQL of all devices
+using the DMA.
+
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c |   33 ++++++++++++++++-----------
+ 1 file changed, 20 insertions(+), 13 deletions(-)
+
+Index: linux-4.9.14/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+===================================================================
+--- linux-4.9.14.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ linux-4.9.14/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -706,7 +706,16 @@ static int mtk_tx_map(struct sk_buff *sk
+ 	WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
+ 				(!nr_frags * TX_DMA_LS0)));
+ 
+-	netdev_sent_queue(dev, skb->len);
++	/* we have a single DMA ring so BQL needs to be updated for all devices
++	 * sitting on this ring
++	 */
++	for (i = 0; i < MTK_MAC_COUNT; i++) {
++		if (!eth->netdev[i])
++			continue;
++
++		netdev_sent_queue(eth->netdev[i], skb->len);
++	}
++
+ 	skb_tx_timestamp(skb);
+ 
+ 	ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
+@@ -998,21 +1007,18 @@ static int mtk_poll_tx(struct mtk_eth *e
+ 	struct mtk_tx_dma *desc;
+ 	struct sk_buff *skb;
+ 	struct mtk_tx_buf *tx_buf;
+-	unsigned int done[MTK_MAX_DEVS];
+-	unsigned int bytes[MTK_MAX_DEVS];
++	int total = 0, done = 0;
++	unsigned int bytes = 0;
+ 	u32 cpu, dma;
+ 	static int condition;
+-	int total = 0, i;
+-
+-	memset(done, 0, sizeof(done));
+-	memset(bytes, 0, sizeof(bytes));
++	int i;
+ 
+ 	cpu = mtk_r32(eth, MTK_QTX_CRX_PTR);
+ 	dma = mtk_r32(eth, MTK_QTX_DRX_PTR);
+ 
+ 	desc = mtk_qdma_phys_to_virt(ring, cpu);
+ 
+-	while ((cpu != dma) && budget) {
++	while ((cpu != dma) && done < budget) {
+ 		u32 next_cpu = desc->txd2;
+ 		int mac;
+ 
+@@ -1032,9 +1038,8 @@ static int mtk_poll_tx(struct mtk_eth *e
+ 		}
+ 
+ 		if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
+-			bytes[mac] += skb->len;
+-			done[mac]++;
+-			budget--;
++			bytes += skb->len;
++			done++;
+ 		}
+ 		mtk_tx_unmap(eth, tx_buf);
+ 
+@@ -1046,11 +1051,13 @@ static int mtk_poll_tx(struct mtk_eth *e
+ 
+ 	mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
+ 
++	/* we have a single DMA ring so BQL needs to be updated for all devices
++	 * sitting on this ring
++	 */
+ 	for (i = 0; i < MTK_MAC_COUNT; i++) {
+-		if (!eth->netdev[i] || !done[i])
++		if (!eth->netdev[i])
+ 			continue;
+-		netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
+-		total += done[i];
++		netdev_completed_queue(eth->netdev[i], done, bytes);
+ 	}
+ 
+ 	if (mtk_queue_stopped(eth) &&
diff --git a/target/linux/mediatek/patches-4.9/0092-dsa2.patch b/target/linux/mediatek/patches-4.9/0092-dsa2.patch
new file mode 100644
index 0000000..84e5cb4
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0092-dsa2.patch
@@ -0,0 +1,219 @@
+From patchwork Wed Mar 29 09:38:20 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net-next,v3,2/5] net-next: dsa: add Mediatek tag RX/TX handler
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9651099
+Message-Id: <1490780303-18598-3-git-send-email-sean.wang at mediatek.com>
+To: <andrew at lunn.ch>, <f.fainelli at gmail.com>,
+ <vivien.didelot at savoirfairelinux.com>, <matthias.bgg at gmail.com>,
+ <robh+dt at kernel.org>, <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, Landen.Chao at mediatek.com, keyhaede at gmail.com, 
+ netdev at vger.kernel.org, sean.wang at mediatek.com,
+ linux-kernel at vger.kernel.org, 
+ linux-mediatek at lists.infradead.org, objelf at gmail.com, davem at davemloft.net
+Date: Wed, 29 Mar 2017 17:38:20 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+Add the support for the 4-bytes tag for DSA port distinguishing inserted
+allowing receiving and transmitting the packet via the particular port.
+The tag is being added after the source MAC address in the ethernet
+header.
+
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+Signed-off-by: Landen Chao <Landen.Chao at mediatek.com>
+Reviewed-by: Andrew Lunn <andrew at lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli at gmail.com>
+---
+ include/net/dsa.h  |   1 +
+ net/dsa/Kconfig    |   2 +
+ net/dsa/Makefile   |   1 +
+ net/dsa/dsa.c      |   3 ++
+ net/dsa/dsa_priv.h |   3 ++
+ net/dsa/tag_mtk.c  | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 127 insertions(+)
+ create mode 100644 net/dsa/tag_mtk.c
+
+diff --git a/include/net/dsa.h b/include/net/dsa.h
+index 4e13e69..3276547 100644
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -31,6 +31,7 @@ enum dsa_tag_protocol {
+ 	DSA_TAG_PROTO_EDSA,
+ 	DSA_TAG_PROTO_BRCM,
+ 	DSA_TAG_PROTO_QCA,
++	DSA_TAG_PROTO_MTK,
+ 	DSA_TAG_LAST,		/* MUST BE LAST */
+ };
+ 
+diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
+index 9649238..d78789b 100644
+--- a/net/dsa/Kconfig
++++ b/net/dsa/Kconfig
+@@ -31,4 +31,6 @@ config NET_DSA_TAG_TRAILER
+ config NET_DSA_TAG_QCA
+ 	bool
+ 
++config NET_DSA_TAG_MTK
++	bool
+ endif
+diff --git a/net/dsa/Makefile b/net/dsa/Makefile
+index 31d3437..9b1d478 100644
+--- a/net/dsa/Makefile
++++ b/net/dsa/Makefile
+@@ -8,3 +8,4 @@ dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
+ dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
+ dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
+ dsa_core-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
++dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
+diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
+index b6d4f6a..617f736 100644
+--- a/net/dsa/dsa.c
++++ b/net/dsa/dsa.c
+@@ -53,6 +53,9 @@ static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
+ #ifdef CONFIG_NET_DSA_TAG_QCA
+ 	[DSA_TAG_PROTO_QCA] = &qca_netdev_ops,
+ #endif
++#ifdef CONFIG_NET_DSA_TAG_MTK
++	[DSA_TAG_PROTO_MTK] = &mtk_netdev_ops,
++#endif
+ 	[DSA_TAG_PROTO_NONE] = &none_ops,
+ };
+ 
+diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
+index 0706a51..2a31399 100644
+--- a/net/dsa/dsa_priv.h
++++ b/net/dsa/dsa_priv.h
+@@ -85,4 +85,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
+ /* tag_qca.c */
+ extern const struct dsa_device_ops qca_netdev_ops;
+ 
++/* tag_mtk.c */
++extern const struct dsa_device_ops mtk_netdev_ops;
++
+ #endif
+diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c
+new file mode 100644
+index 0000000..833a9d6
+--- /dev/null
++++ b/net/dsa/tag_mtk.c
+@@ -0,0 +1,117 @@
++/*
++ * Mediatek DSA Tag support
++ * Copyright (C) 2017 Landen Chao <landen.chao at mediatek.com>
++ *		      Sean Wang <sean.wang at mediatek.com>
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/etherdevice.h>
++#include "dsa_priv.h"
++
++#define MTK_HDR_LEN		4
++#define MTK_HDR_RECV_SOURCE_PORT_MASK	GENMASK(2, 0)
++#define MTK_HDR_XMIT_DP_BIT_MASK	GENMASK(5, 0)
++
++static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
++				    struct net_device *dev)
++{
++	struct dsa_slave_priv *p = netdev_priv(dev);
++	u8 *mtk_tag;
++
++	if (skb_cow_head(skb, MTK_HDR_LEN) < 0)
++		goto out_free;
++
++	skb_push(skb, MTK_HDR_LEN);
++
++	memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
++
++	/* Build the tag after the MAC Source Address */
++	mtk_tag = skb->data + 2 * ETH_ALEN;
++	mtk_tag[0] = 0;
++	mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
++	mtk_tag[2] = 0;
++	mtk_tag[3] = 0;
++
++	return skb;
++
++out_free:
++	kfree_skb(skb);
++	return NULL;
++}
++
++static int mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
++		       struct packet_type *pt, struct net_device *orig_dev)
++{
++	struct dsa_switch_tree *dst = dev->dsa_ptr;
++	struct dsa_switch *ds;
++	int port;
++	__be16 *phdr, hdr;
++
++	if (unlikely(!dst))
++		goto out_drop;
++
++	skb = skb_unshare(skb, GFP_ATOMIC);
++	if (!skb)
++		goto out;
++
++	if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
++		goto out_drop;
++
++	/* The MTK header is added by the switch between src addr
++	 * and ethertype at this point, skb->data points to 2 bytes
++	 * after src addr so header should be 2 bytes right before.
++	 */
++	phdr = (__be16 *)(skb->data - 2);
++	hdr = ntohs(*phdr);
++
++	/* Remove MTK tag and recalculate checksum. */
++	skb_pull_rcsum(skb, MTK_HDR_LEN);
++
++	memmove(skb->data - ETH_HLEN,
++		skb->data - ETH_HLEN - MTK_HDR_LEN,
++		2 * ETH_ALEN);
++
++	/* This protocol doesn't support cascading multiple
++	 * switches so it's safe to assume the switch is first
++	 * in the tree.
++	 */
++	ds = dst->ds[0];
++	if (!ds)
++		goto out_drop;
++
++	/* Get source port information */
++	port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
++	if (!ds->ports[port].netdev)
++		goto out_drop;
++
++	/* Update skb & forward the frame accordingly */
++	skb_push(skb, ETH_HLEN);
++
++	skb->pkt_type = PACKET_HOST;
++	skb->dev = ds->ports[port].netdev;
++	skb->protocol = eth_type_trans(skb, skb->dev);
++
++	skb->dev->stats.rx_packets++;
++	skb->dev->stats.rx_bytes += skb->len;
++
++	netif_receive_skb(skb);
++
++	return 0;
++
++out_drop:
++	kfree_skb(skb);
++out:
++	return 0;
++}
++
++const struct dsa_device_ops mtk_netdev_ops = {
++	.xmit	= mtk_tag_xmit,
++	.rcv	= mtk_tag_rcv,
++};
diff --git a/target/linux/mediatek/patches-4.9/0092-dsa3.patch b/target/linux/mediatek/patches-4.9/0092-dsa3.patch
new file mode 100644
index 0000000..7c4dc4f
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0092-dsa3.patch
@@ -0,0 +1,67 @@
+From patchwork Wed Mar 29 09:38:21 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net-next, v3,
+ 3/5] net-next: ethernet: mediatek: add CDM able to recognize the tag
+ for DSA
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9651091
+Message-Id: <1490780303-18598-4-git-send-email-sean.wang at mediatek.com>
+To: <andrew at lunn.ch>, <f.fainelli at gmail.com>,
+ <vivien.didelot at savoirfairelinux.com>, <matthias.bgg at gmail.com>,
+ <robh+dt at kernel.org>, <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, Landen.Chao at mediatek.com, keyhaede at gmail.com, 
+ netdev at vger.kernel.org, sean.wang at mediatek.com,
+ linux-kernel at vger.kernel.org, 
+ linux-mediatek at lists.infradead.org, objelf at gmail.com, davem at davemloft.net
+Date: Wed, 29 Mar 2017 17:38:21 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+The patch adds the setup for allowing CDM can recognize these packets with
+carrying port-distinguishing tag. Otherwise, these tagging packets will be
+handled incorrectly by CDM. The setup is also working out for general
+untag packets as well.
+
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+Signed-off-by: Landen Chao <Landen.Chao at mediatek.com>
+Reviewed-by: Andrew Lunn <andrew at lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli at gmail.com>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++++
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++
+ 2 files changed, 10 insertions(+)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+index 9e75768..c21ed99 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1846,6 +1846,12 @@ static int mtk_hw_init(struct mtk_eth *eth)
+ 	/* GE2, Force 1000M/FD, FC ON */
+ 	mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(1));
+ 
++	/* Indicates CDM to parse the MTK special tag from CPU
++	 * which also is working out for untag packets.
++	 */
++	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
++	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
++
+ 	/* Enable RX VLan Offloading */
+ 	mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+index 99b1c8e..996024d 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -70,6 +70,10 @@
+ /* Frame Engine Interrupt Grouping Register */
+ #define MTK_FE_INT_GRP		0x20
+ 
++/* CDMP Ingress Control Register */
++#define MTK_CDMQ_IG_CTRL	0x1400
++#define MTK_CDMQ_STAG_EN	BIT(0)
++
+ /* CDMP Exgress Control Register */
+ #define MTK_CDMP_EG_CTRL	0x404
+ 
diff --git a/target/linux/mediatek/patches-4.9/0092-dsa4.patch b/target/linux/mediatek/patches-4.9/0092-dsa4.patch
new file mode 100644
index 0000000..d67b4a9
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0092-dsa4.patch
@@ -0,0 +1,46 @@
+From patchwork Wed Mar 29 09:38:22 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net-next, v3,
+ 4/5] net-next: ethernet: mediatek: add device_node of GMAC pointing
+ into the netdev instance
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9651097
+Message-Id: <1490780303-18598-5-git-send-email-sean.wang at mediatek.com>
+To: <andrew at lunn.ch>, <f.fainelli at gmail.com>,
+ <vivien.didelot at savoirfairelinux.com>, <matthias.bgg at gmail.com>,
+ <robh+dt at kernel.org>, <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, Landen.Chao at mediatek.com, keyhaede at gmail.com, 
+ netdev at vger.kernel.org, sean.wang at mediatek.com,
+ linux-kernel at vger.kernel.org, 
+ linux-mediatek at lists.infradead.org, objelf at gmail.com, davem at davemloft.net
+Date: Wed, 29 Mar 2017 17:38:22 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+the patch adds the setup of the corresponding device node of GMAC into the
+netdev instance which could allow other modules such as DSA to find the
+instance through the node in dt-bindings using of_find_net_device_by_node()
+call.
+
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+Reviewed-by: Andrew Lunn <andrew at lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli at gmail.com>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+index c21ed99..84b09a4 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -2323,6 +2323,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+ 	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
+ 
+ 	eth->netdev[id]->irq = eth->irq[0];
++	eth->netdev[id]->dev.of_node = np;
++
+ 	return 0;
+ 
+ free_netdev:
diff --git a/target/linux/mediatek/patches-4.9/0092-dsa5.patch b/target/linux/mediatek/patches-4.9/0092-dsa5.patch
new file mode 100644
index 0000000..6c10137
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0092-dsa5.patch
@@ -0,0 +1,1608 @@
+From patchwork Wed Mar 29 09:38:23 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net-next, v3,
+ 5/5] net-next: dsa: add dsa support for Mediatek MT7530 switch
+From: sean.wang at mediatek.com
+X-Patchwork-Id: 9651095
+Message-Id: <1490780303-18598-6-git-send-email-sean.wang at mediatek.com>
+To: <andrew at lunn.ch>, <f.fainelli at gmail.com>,
+ <vivien.didelot at savoirfairelinux.com>, <matthias.bgg at gmail.com>,
+ <robh+dt at kernel.org>, <mark.rutland at arm.com>
+Cc: devicetree at vger.kernel.org, Landen.Chao at mediatek.com, keyhaede at gmail.com, 
+ netdev at vger.kernel.org, sean.wang at mediatek.com,
+ linux-kernel at vger.kernel.org, 
+ linux-mediatek at lists.infradead.org, objelf at gmail.com, davem at davemloft.net
+Date: Wed, 29 Mar 2017 17:38:23 +0800
+
+From: Sean Wang <sean.wang at mediatek.com>
+
+MT7530 is a 7-ports Gigabit Ethernet Switch that could be found on
+Mediatek router platforms such as MT7623A or MT7623N platform which
+includes 7-port Gigabit Ethernet MAC and 5-port Gigabit Ethernet PHY.
+Among these ports, The port from 0 to 4 are the user ports connecting
+with the remote devices while the port 5 and 6 are the CPU ports
+connecting into Mediatek Ethernet GMAC.
+
+For port 6, it can communicate with the CPU via Mediatek Ethernet GMAC
+through either the TRGMII or RGMII which could be controlled by phy-mode
+in the dt-bindings to specify which mode is preferred to use. And for
+port 5, only RGMII can be specified. However, currently, only port 6 is
+being supported in this DSA driver.
+
+The driver is made with the reference to qca8k and other existing DSA
+driver. The most of the essential callbacks of the DSA are already
+support in the driver, including tag insert for user port distinguishing,
+port control, bridge offloading, STP setup and ethtool operation to allow
+DSA to model each user port into a standalone netdevice as the other DSA
+driver had done.
+
+Signed-off-by: Sean Wang <sean.wang at mediatek.com>
+Signed-off-by: Landen Chao <Landen.Chao at mediatek.com>
+---
+ drivers/net/dsa/Kconfig  |    8 +
+ drivers/net/dsa/Makefile |    2 +-
+ drivers/net/dsa/mt7530.c | 1126 ++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/dsa/mt7530.h |  390 ++++++++++++++++
+ 4 files changed, 1525 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/dsa/mt7530.c
+ create mode 100644 drivers/net/dsa/mt7530.h
+
+diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
+index 0659846..5b322b4 100644
+--- a/drivers/net/dsa/Kconfig
++++ b/drivers/net/dsa/Kconfig
+@@ -34,4 +34,12 @@ config NET_DSA_QCA8K
+ 	  This enables support for the Qualcomm Atheros QCA8K Ethernet
+ 	  switch chips.
+ 
++config NET_DSA_MT7530
++	tristate "Mediatek MT7530 Ethernet switch support"
++	depends on NET_DSA
++	select NET_DSA_TAG_MTK
++	---help---
++	  This enables support for the Mediatek MT7530 Ethernet switch
++	  chip.
++
+ endmenu
+diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
+index a3c9416..8e629c1 100644
+--- a/drivers/net/dsa/Makefile
++++ b/drivers/net/dsa/Makefile
+@@ -2,6 +2,6 @@ obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
+ obj-$(CONFIG_NET_DSA_BCM_SF2)	+= bcm-sf2.o
+ bcm-sf2-objs			:= bcm_sf2.o bcm_sf2_cfp.o
+ obj-$(CONFIG_NET_DSA_QCA8K)	+= qca8k.o
+-
++obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
+ obj-y				+= b53/
+ obj-y				+= mv88e6xxx/
+diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
+new file mode 100644
+index 0000000..ad2e6f8
+--- /dev/null
++++ b/drivers/net/dsa/mt7530.c
+@@ -0,0 +1,1126 @@
++/*
++ * Mediatek MT7530 DSA Switch driver
++ * Copyright (C) 2017 Sean Wang <sean.wang at mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT 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/etherdevice.h>
++#include <linux/if_bridge.h>
++#include <linux/iopoll.h>
++#include <linux/mdio.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/of_gpio.h>
++#include <linux/of_mdio.h>
++#include <linux/of_net.h>
++#include <linux/of_platform.h>
++#include <linux/phy.h>
++#include <linux/regmap.h>
++#include <linux/regulator/consumer.h>
++#include <linux/reset.h>
++#include <net/dsa.h>
++#include <net/switchdev.h>
++
++#include "mt7530.h"
++
++/* String, offset, and register size in bytes if different from 4 bytes */
++static const struct mt7530_mib_desc mt7530_mib[] = {
++	MIB_DESC(1, 0x00, "TxDrop"),
++	MIB_DESC(1, 0x04, "TxCrcErr"),
++	MIB_DESC(1, 0x08, "TxUnicast"),
++	MIB_DESC(1, 0x0c, "TxMulticast"),
++	MIB_DESC(1, 0x10, "TxBroadcast"),
++	MIB_DESC(1, 0x14, "TxCollision"),
++	MIB_DESC(1, 0x18, "TxSingleCollision"),
++	MIB_DESC(1, 0x1c, "TxMultipleCollision"),
++	MIB_DESC(1, 0x20, "TxDeferred"),
++	MIB_DESC(1, 0x24, "TxLateCollision"),
++	MIB_DESC(1, 0x28, "TxExcessiveCollistion"),
++	MIB_DESC(1, 0x2c, "TxPause"),
++	MIB_DESC(1, 0x30, "TxPktSz64"),
++	MIB_DESC(1, 0x34, "TxPktSz65To127"),
++	MIB_DESC(1, 0x38, "TxPktSz128To255"),
++	MIB_DESC(1, 0x3c, "TxPktSz256To511"),
++	MIB_DESC(1, 0x40, "TxPktSz512To1023"),
++	MIB_DESC(1, 0x44, "Tx1024ToMax"),
++	MIB_DESC(2, 0x48, "TxBytes"),
++	MIB_DESC(1, 0x60, "RxDrop"),
++	MIB_DESC(1, 0x64, "RxFiltering"),
++	MIB_DESC(1, 0x6c, "RxMulticast"),
++	MIB_DESC(1, 0x70, "RxBroadcast"),
++	MIB_DESC(1, 0x74, "RxAlignErr"),
++	MIB_DESC(1, 0x78, "RxCrcErr"),
++	MIB_DESC(1, 0x7c, "RxUnderSizeErr"),
++	MIB_DESC(1, 0x80, "RxFragErr"),
++	MIB_DESC(1, 0x84, "RxOverSzErr"),
++	MIB_DESC(1, 0x88, "RxJabberErr"),
++	MIB_DESC(1, 0x8c, "RxPause"),
++	MIB_DESC(1, 0x90, "RxPktSz64"),
++	MIB_DESC(1, 0x94, "RxPktSz65To127"),
++	MIB_DESC(1, 0x98, "RxPktSz128To255"),
++	MIB_DESC(1, 0x9c, "RxPktSz256To511"),
++	MIB_DESC(1, 0xa0, "RxPktSz512To1023"),
++	MIB_DESC(1, 0xa4, "RxPktSz1024ToMax"),
++	MIB_DESC(2, 0xa8, "RxBytes"),
++	MIB_DESC(1, 0xb0, "RxCtrlDrop"),
++	MIB_DESC(1, 0xb4, "RxIngressDrop"),
++	MIB_DESC(1, 0xb8, "RxArlDrop"),
++};
++
++static struct mt7530_priv *lpriv;
++static void mt7530_port_disable(struct dsa_switch *ds, int port,
++				struct phy_device *phy);
++static int mt7530_cpu_port_enable(struct mt7530_priv *priv,
++				  int port);
++
++static int
++mt7623_trgmii_write(struct mt7530_priv *priv,  u32 reg, u32 val)
++{
++	int ret;
++
++	ret =  regmap_write(priv->ethernet, TRGMII_BASE(reg), val);
++	if (ret < 0)
++		dev_err(priv->dev,
++			"failed to priv write register\n");
++	return ret;
++}
++
++static u32
++mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg)
++{
++	int ret;
++	u32 val;
++
++	ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val);
++	if (ret < 0) {
++		dev_err(priv->dev,
++			"failed to priv read register\n");
++		return ret;
++	}
++
++	return val;
++}
++
++static void
++mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg,
++		  u32 mask, u32 set)
++{
++	u32 val;
++
++	val = mt7623_trgmii_read(priv, reg);
++	val &= ~mask;
++	val |= set;
++	mt7623_trgmii_write(priv, reg, val);
++}
++
++static void
++mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++	mt7623_trgmii_rmw(priv, reg, 0, val);
++}
++
++static void
++mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++	mt7623_trgmii_rmw(priv, reg, val, 0);
++}
++
++static int
++core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)
++{
++	struct mii_bus *bus = priv->bus;
++	int value, ret;
++
++	/* Write the desired MMD Devad */
++	ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
++	if (ret < 0)
++		goto err;
++
++	/* Write the desired MMD register address */
++	ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
++	if (ret < 0)
++		goto err;
++
++	/* Select the Function : DATA with no post increment */
++	ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
++	if (ret < 0)
++		goto err;
++
++	/* Read the content of the MMD's selected register */
++	value = bus->read(bus, 0, MII_MMD_DATA);
++
++	return value;
++err:
++	dev_err(&bus->dev,  "failed to read mmd register\n");
++
++	return ret;
++}
++
++static int
++core_write_mmd_indirect(struct mt7530_priv *priv, int prtad,
++			int devad, u32 data)
++{
++	struct mii_bus *bus = priv->bus;
++	int ret;
++
++	/* Write the desired MMD Devad */
++	ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
++	if (ret < 0)
++		goto err;
++
++	/* Write the desired MMD register address */
++	ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
++	if (ret < 0)
++		goto err;
++
++	/* Select the Function : DATA with no post increment */
++	ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
++	if (ret < 0)
++		goto err;
++
++	/* Write the data into MMD's selected register */
++	ret = bus->write(bus, 0, MII_MMD_DATA, data);
++err:
++	if (ret < 0)
++		dev_err(&bus->dev,
++			"failed to write mmd register\n");
++	return ret;
++}
++
++static void
++core_write(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++	struct mii_bus *bus = priv->bus;
++
++	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
++
++	mutex_unlock(&bus->mdio_lock);
++}
++
++static void
++core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
++{
++	struct mii_bus *bus = priv->bus;
++	u32 val;
++
++	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2);
++	val &= ~mask;
++	val |= set;
++	core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
++
++	mutex_unlock(&bus->mdio_lock);
++}
++
++static void
++core_set(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++	core_rmw(priv, reg, 0, val);
++}
++
++static void
++core_clear(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++	core_rmw(priv, reg, val, 0);
++}
++
++static int
++mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++	struct mii_bus *bus = priv->bus;
++	u16 page, r, lo, hi;
++	int ret;
++
++	page = (reg >> 6) & 0x3ff;
++	r  = (reg >> 2) & 0xf;
++	lo = val & 0xffff;
++	hi = val >> 16;
++
++	/* MT7530 uses 31 as the pseudo port */
++	ret = bus->write(bus, 0x1f, 0x1f, page);
++	if (ret < 0)
++		goto err;
++
++	ret = bus->write(bus, 0x1f, r,  lo);
++	if (ret < 0)
++		goto err;
++
++	ret = bus->write(bus, 0x1f, 0x10, hi);
++err:
++	if (ret < 0)
++		dev_err(&bus->dev,
++			"failed to write mt7530 register\n");
++	return ret;
++}
++
++static u32
++mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
++{
++	struct mii_bus *bus = priv->bus;
++	u16 page, r, lo, hi;
++	int ret;
++
++	page = (reg >> 6) & 0x3ff;
++	r = (reg >> 2) & 0xf;
++
++	/* MT7530 uses 31 as the pseudo port */
++	ret = bus->write(bus, 0x1f, 0x1f, page);
++	if (ret < 0) {
++		dev_err(&bus->dev,
++			"failed to read mt7530 register\n");
++		return ret;
++	}
++
++	lo = bus->read(bus, 0x1f, r);
++	hi = bus->read(bus, 0x1f, 0x10);
++
++	return (hi << 16) | (lo & 0xffff);
++}
++
++static void
++mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++	struct mii_bus *bus = priv->bus;
++
++	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	mt7530_mii_write(priv, reg, val);
++
++	mutex_unlock(&bus->mdio_lock);
++}
++
++static u32
++_mt7530_read(u32 reg)
++{
++	struct mt7530_priv	*priv = lpriv;
++	struct mii_bus		*bus = priv->bus;
++	u32 val;
++
++	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	val = mt7530_mii_read(priv, reg);
++
++	mutex_unlock(&bus->mdio_lock);
++
++	return val;
++}
++
++static u32
++mt7530_read(struct mt7530_priv *priv, u32 reg)
++{
++	return _mt7530_read(reg);
++}
++
++static void
++mt7530_rmw(struct mt7530_priv *priv, u32 reg,
++	   u32 mask, u32 set)
++{
++	struct mii_bus *bus = priv->bus;
++	u32 val;
++
++	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	val = mt7530_mii_read(priv, reg);
++	val &= ~mask;
++	val |= set;
++	mt7530_mii_write(priv, reg, val);
++
++	mutex_unlock(&bus->mdio_lock);
++}
++
++static void
++mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++	mt7530_rmw(priv, reg, 0, val);
++}
++
++static void
++mt7530_clear(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++	mt7530_rmw(priv, reg, val, 0);
++}
++
++static int
++mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
++{
++	u32 val;
++	int ret;
++
++	/* Set the command operating upon the MAC address entries */
++	val = ATC_BUSY | ATC_MAT(0) | cmd;
++	mt7530_write(priv, MT7530_ATC, val);
++
++	ret = readx_poll_timeout(_mt7530_read, MT7530_ATC, val,
++				 !(val & ATC_BUSY), 20, 20000);
++	if (ret < 0) {
++		dev_err(priv->dev, "reset timeout\n");
++		return ret;
++	}
++
++	/* Additional sanity for read command if the specified
++	 * entry is invalid
++	 */
++	val = mt7530_read(priv, MT7530_ATC);
++	if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID))
++		return -EINVAL;
++
++	if (rsp)
++		*rsp = val;
++
++	return 0;
++}
++
++static void
++mt7530_fdb_read(struct mt7530_priv *priv, struct mt7530_fdb *fdb)
++{
++	u32 reg[3];
++	int i;
++
++	/* Read from ARL table into an array */
++	for (i = 0; i < 3; i++) {
++		reg[i] = mt7530_read(priv, MT7530_TSRA1 + (i * 4));
++
++		dev_dbg(priv->dev, "%s(%d) reg[%d]=0x%x\n",
++			__func__, __LINE__, i, reg[i]);
++	}
++
++	fdb->vid = (reg[1] >> CVID) & CVID_MASK;
++	fdb->aging = (reg[2] >> AGE_TIMER) & AGE_TIMER_MASK;
++	fdb->port_mask = (reg[2] >> PORT_MAP) & PORT_MAP_MASK;
++	fdb->mac[0] = (reg[0] >> MAC_BYTE_0) & MAC_BYTE_MASK;
++	fdb->mac[1] = (reg[0] >> MAC_BYTE_1) & MAC_BYTE_MASK;
++	fdb->mac[2] = (reg[0] >> MAC_BYTE_2) & MAC_BYTE_MASK;
++	fdb->mac[3] = (reg[0] >> MAC_BYTE_3) & MAC_BYTE_MASK;
++	fdb->mac[4] = (reg[1] >> MAC_BYTE_4) & MAC_BYTE_MASK;
++	fdb->mac[5] = (reg[1] >> MAC_BYTE_5) & MAC_BYTE_MASK;
++	fdb->noarp = ((reg[2] >> ENT_STATUS) & ENT_STATUS_MASK) == STATIC_ENT;
++}
++
++static void
++mt7530_fdb_write(struct mt7530_priv *priv, u16 vid,
++		 u8 port_mask, const u8 *mac,
++		 u8 aging, u8 type)
++{
++	u32 reg[3] = { 0 };
++	int i;
++
++	reg[1] |= vid & CVID_MASK;
++	reg[2] |= (aging & AGE_TIMER_MASK) << AGE_TIMER;
++	reg[2] |= (port_mask & PORT_MAP_MASK) << PORT_MAP;
++	/* STATIC_ENT indicate that entry is static wouldn't
++	 * be aged out and STATIC_EMP specified as erasing an
++	 * entry
++	 */
++	reg[2] |= (type & ENT_STATUS_MASK) << ENT_STATUS;
++	reg[1] |= mac[5] << MAC_BYTE_5;
++	reg[1] |= mac[4] << MAC_BYTE_4;
++	reg[0] |= mac[3] << MAC_BYTE_3;
++	reg[0] |= mac[2] << MAC_BYTE_2;
++	reg[0] |= mac[1] << MAC_BYTE_1;
++	reg[0] |= mac[0] << MAC_BYTE_0;
++
++	/* Write array into the ARL table */
++	for (i = 0; i < 3; i++)
++		mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]);
++}
++
++static int
++mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 ncpo1, ssc_delta, trgint, i;
++
++	switch (mode) {
++	case PHY_INTERFACE_MODE_RGMII:
++		trgint = 0;
++		ncpo1 = 0x0c80;
++		ssc_delta = 0x87;
++		break;
++	case PHY_INTERFACE_MODE_TRGMII:
++		trgint = 1;
++		ncpo1 = 0x1400;
++		ssc_delta = 0x57;
++		break;
++	default:
++		dev_err(priv->dev, "xMII mode %d not supported\n", mode);
++		return -EINVAL;
++	}
++
++	mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
++		   P6_INTF_MODE(trgint));
++
++	/* Lower Tx Driving for TRGMII path */
++	for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
++		mt7530_write(priv, MT7530_TRGMII_TD_ODT(i),
++			     TD_DM_DRVP(8) | TD_DM_DRVN(8));
++
++	/* Setup core clock for MT7530 */
++	if (!trgint) {
++		/* Disable MT7530 core clock */
++		core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
++
++		/* Disable PLL, since phy_device has not yet been created
++		 * provided for phy_[read,write]_mmd_indirect is called, we
++		 * provide our own core_write_mmd_indirect to complete this
++		 * function.
++		 */
++		core_write_mmd_indirect(priv,
++					CORE_GSWPLL_GRP1,
++					MDIO_MMD_VEND2,
++					0);
++
++		/* Set core clock into 500Mhz */
++		core_write(priv, CORE_GSWPLL_GRP2,
++			   RG_GSWPLL_POSDIV_500M(1) |
++			   RG_GSWPLL_FBKDIV_500M(25));
++
++		/* Enable PLL */
++		core_write(priv, CORE_GSWPLL_GRP1,
++			   RG_GSWPLL_EN_PRE |
++			   RG_GSWPLL_POSDIV_200M(2) |
++			   RG_GSWPLL_FBKDIV_200M(32));
++
++		/* Enable MT7530 core clock */
++		core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
++	}
++
++	/* Setup the MT7530 TRGMII Tx Clock */
++	core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
++	core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));
++	core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));
++	core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta));
++	core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta));
++	core_write(priv, CORE_PLL_GROUP4,
++		   RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN |
++		   RG_SYSPLL_BIAS_LPF_EN);
++	core_write(priv, CORE_PLL_GROUP2,
++		   RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
++		   RG_SYSPLL_POSDIV(1));
++	core_write(priv, CORE_PLL_GROUP7,
++		   RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) |
++		   RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
++	core_set(priv, CORE_TRGMII_GSW_CLK_CG,
++		 REG_GSWCK_EN | REG_TRGMIICK_EN);
++
++	if (!trgint)
++		for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
++			mt7530_rmw(priv, MT7530_TRGMII_RD(i),
++				   RD_TAP_MASK, RD_TAP(16));
++	else
++		mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII);
++
++	return 0;
++}
++
++static int
++mt7623_pad_clk_setup(struct dsa_switch *ds)
++{
++	struct mt7530_priv *priv = ds->priv;
++	int i;
++
++	for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
++		mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i),
++				    TD_DM_DRVP(8) | TD_DM_DRVN(8));
++
++	mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL);
++	mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST);
++
++	return 0;
++}
++
++static void
++mt7530_mib_reset(struct dsa_switch *ds)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_FLUSH);
++	mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE);
++}
++
++static void
++mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable)
++{
++	u32 mask = PMCR_TX_EN | PMCR_RX_EN;
++
++	if (enable)
++		mt7530_set(priv, MT7530_PMCR_P(port), mask);
++	else
++		mt7530_clear(priv, MT7530_PMCR_P(port), mask);
++}
++
++static int
++mt7530_setup(struct dsa_switch *ds)
++{
++	struct mt7530_priv *priv = ds->priv;
++	int ret, i;
++	u32 id, val;
++	struct device_node *dn;
++
++	/* The parent node of master_netdev which holds the common system
++	 * controller also is the container for two GMACs nodes representing
++	 * as two netdev instances.
++	 */
++	dn = ds->master_netdev->dev.of_node->parent;
++	priv->ethernet = syscon_node_to_regmap(dn);
++	if (IS_ERR(priv->ethernet))
++		return PTR_ERR(priv->ethernet);
++
++	regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
++	ret = regulator_enable(priv->core_pwr);
++	if (ret < 0) {
++		dev_err(priv->dev,
++			"Failed to enable core power: %d\n", ret);
++		return ret;
++	}
++
++	regulator_set_voltage(priv->io_pwr, 3300000, 3300000);
++	ret = regulator_enable(priv->io_pwr);
++	if (ret < 0) {
++		dev_err(priv->dev, "Failed to enable io pwr: %d\n",
++			ret);
++		return ret;
++	}
++
++	/* Reset whole chip through gpio pin or memory-mapped registers for
++	 * different type of hardware
++	 */
++	if (priv->mcm) {
++		reset_control_assert(priv->rstc);
++		usleep_range(1000, 1100);
++		reset_control_deassert(priv->rstc);
++	} else {
++		gpiod_set_value_cansleep(priv->reset, 0);
++		usleep_range(1000, 1100);
++		gpiod_set_value_cansleep(priv->reset, 1);
++	}
++
++	/* Waiting for MT7530 got to stable */
++	ret = readx_poll_timeout(_mt7530_read, MT7530_HWTRAP, val, val != 0,
++				 20, 1000000);
++	if (ret < 0) {
++		dev_err(priv->dev, "reset timeout\n");
++		return ret;
++	}
++
++	id = mt7530_read(priv, MT7530_CREV);
++	id >>= CHIP_NAME_SHIFT;
++	if (id != MT7530_ID) {
++		dev_err(priv->dev, "chip %x can't be supported\n", id);
++		return -ENODEV;
++	}
++
++	/* Reset the switch through internal reset */
++	mt7530_write(priv, MT7530_SYS_CTRL,
++		     SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
++		     SYS_CTRL_REG_RST);
++
++	/* Enable Port 6 only; P5 as GMAC5 which currently is not supported */
++	val = mt7530_read(priv, MT7530_MHWTRAP);
++	val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
++	val |= MHWTRAP_MANUAL;
++	mt7530_write(priv, MT7530_MHWTRAP, val);
++
++	/* Enable and reset MIB counters */
++	mt7530_mib_reset(ds);
++
++	mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK);
++
++	for (i = 0; i < MT7530_NUM_PORTS; i++) {
++		/* Disable forwarding by default on all ports */
++		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
++			   PCR_MATRIX_CLR);
++
++		if (dsa_is_cpu_port(ds, i))
++			mt7530_cpu_port_enable(priv, i);
++		else
++			mt7530_port_disable(ds, i, NULL);
++	}
++
++	/* Flush the FDB table */
++	ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0);
++	if (ret < 0)
++		return ret;
++
++	return 0;
++}
++
++static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	return mdiobus_read_nested(priv->bus, port, regnum);
++}
++
++int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	return mdiobus_write_nested(priv->bus, port, regnum, val);
++}
++
++static void
++mt7530_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++)
++		strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name,
++			ETH_GSTRING_LEN);
++}
++
++static void
++mt7530_get_ethtool_stats(struct dsa_switch *ds, int port,
++			 uint64_t *data)
++{
++	struct mt7530_priv *priv = ds->priv;
++	const struct mt7530_mib_desc *mib;
++	u32 reg, i;
++	u64 hi;
++
++	for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) {
++		mib = &mt7530_mib[i];
++		reg = MT7530_PORT_MIB_COUNTER(port) + mib->offset;
++
++		data[i] = mt7530_read(priv, reg);
++		if (mib->size == 2) {
++			hi = mt7530_read(priv, reg + 4);
++			data[i] |= hi << 32;
++		}
++	}
++}
++
++static int
++mt7530_get_sset_count(struct dsa_switch *ds)
++{
++	return ARRAY_SIZE(mt7530_mib);
++}
++
++static void mt7530_adjust_link(struct dsa_switch *ds, int port,
++			       struct phy_device *phydev)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	if (phy_is_pseudo_fixed_link(phydev)) {
++		dev_dbg(priv->dev, "phy-mode for master device = %x\n",
++			phydev->interface);
++
++		/* Setup TX circuit incluing relevant PAD and driving */
++		mt7530_pad_clk_setup(ds, phydev->interface);
++
++		/* Setup RX circuit, relevant PAD and driving on the host
++		 * which must be placed after the setup on the device side is
++		 * all finished.
++		 */
++		mt7623_pad_clk_setup(ds);
++	}
++}
++
++static int
++mt7530_cpu_port_enable(struct mt7530_priv *priv,
++		       int port)
++{
++	/* Enable Mediatek header mode on the cpu port */
++	mt7530_write(priv, MT7530_PVC_P(port),
++		     PORT_SPEC_TAG);
++
++	/* Setup the MAC by default for the cpu port */
++	mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK);
++
++	/* Disable auto learning on the cpu port */
++	mt7530_set(priv, MT7530_PSC_P(port), SA_DIS);
++
++	/* Unknown unicast frame fordwarding to the cpu port */
++	mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port)));
++
++	/* CPU port gets connected to all user ports of
++	 * the switch
++	 */
++	mt7530_write(priv, MT7530_PCR_P(port),
++		     PCR_MATRIX(priv->ds->enabled_port_mask));
++
++	return 0;
++}
++
++static int
++mt7530_port_enable(struct dsa_switch *ds, int port,
++		   struct phy_device *phy)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	mutex_lock(&priv->reg_mutex);
++
++	/* Setup the MAC for the user port */
++	mt7530_write(priv, MT7530_PMCR_P(port), PMCR_USERP_LINK);
++
++	/* Allow the user port gets connected to the cpu port and also
++	 * restore the port matrix if the port is the member of a certain
++	 * bridge.
++	 */
++	priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT));
++	priv->ports[port].enable = true;
++	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
++		   priv->ports[port].pm);
++	mt7530_port_set_status(priv, port, 1);
++
++	mutex_unlock(&priv->reg_mutex);
++
++	return 0;
++}
++
++static void
++mt7530_port_disable(struct dsa_switch *ds, int port,
++		    struct phy_device *phy)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	mutex_lock(&priv->reg_mutex);
++
++	/* Clear up all port matrix which could be restored in the next
++	 * enablement for the port.
++	 */
++	priv->ports[port].enable = false;
++	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
++		   PCR_MATRIX_CLR);
++	mt7530_port_set_status(priv, port, 0);
++
++	mutex_unlock(&priv->reg_mutex);
++}
++
++static void
++mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 stp_state;
++
++	switch (state) {
++	case BR_STATE_DISABLED:
++		stp_state = MT7530_STP_DISABLED;
++		break;
++	case BR_STATE_BLOCKING:
++		stp_state = MT7530_STP_BLOCKING;
++		break;
++	case BR_STATE_LISTENING:
++		stp_state = MT7530_STP_LISTENING;
++		break;
++	case BR_STATE_LEARNING:
++		stp_state = MT7530_STP_LEARNING;
++		break;
++	case BR_STATE_FORWARDING:
++	default:
++		stp_state = MT7530_STP_FORWARDING;
++		break;
++	}
++
++	mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK, stp_state);
++}
++
++static int
++mt7530_port_bridge_join(struct dsa_switch *ds, int port,
++			struct net_device *bridge)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 port_bitmap = BIT(MT7530_CPU_PORT);
++	int i;
++
++	mutex_lock(&priv->reg_mutex);
++
++	for (i = 0; i < MT7530_NUM_PORTS; i++) {
++		/* Add this port to the port matrix of the other ports in the
++		 * same bridge. If the port is disabled, port matrix is kept
++		 * and not being setup until the port becomes enabled.
++		 */
++		if (ds->enabled_port_mask & BIT(i) && i != port) {
++			if (ds->ports[i].bridge_dev != bridge)
++				continue;
++			if (priv->ports[i].enable)
++				mt7530_set(priv, MT7530_PCR_P(i),
++					   PCR_MATRIX(BIT(port)));
++			priv->ports[i].pm |= PCR_MATRIX(BIT(port));
++
++			port_bitmap |= BIT(i);
++		}
++	}
++
++	/* Add the all other ports to this port matrix. */
++	if (priv->ports[port].enable)
++		mt7530_rmw(priv, MT7530_PCR_P(port),
++			   PCR_MATRIX_MASK, PCR_MATRIX(port_bitmap));
++	priv->ports[port].pm |= PCR_MATRIX(port_bitmap);
++
++	mutex_unlock(&priv->reg_mutex);
++
++	return 0;
++}
++
++static void
++mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
++			 struct net_device *bridge)
++{
++	struct mt7530_priv *priv = ds->priv;
++	int i;
++
++	mutex_lock(&priv->reg_mutex);
++
++	for (i = 0; i < MT7530_NUM_PORTS; i++) {
++		/* Remove this port from the port matrix of the other ports
++		 * in the same bridge. If the port is disabled, port matrix
++		 * is kept and not being setup until the port becomes enabled.
++		 */
++		if (ds->enabled_port_mask & BIT(i) && i != port) {
++			if (ds->ports[i].bridge_dev != bridge)
++				continue;
++			if (priv->ports[i].enable)
++				mt7530_clear(priv, MT7530_PCR_P(i),
++					     PCR_MATRIX(BIT(port)));
++			priv->ports[i].pm &= ~PCR_MATRIX(BIT(port));
++		}
++	}
++
++	/* Set the cpu port to be the only one in the port matrix of
++	 * this port.
++	 */
++	if (priv->ports[port].enable)
++		mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
++			   PCR_MATRIX(BIT(MT7530_CPU_PORT)));
++	priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
++
++	mutex_unlock(&priv->reg_mutex);
++}
++
++static int
++mt7530_port_fdb_prepare(struct dsa_switch *ds, int port,
++			const struct switchdev_obj_port_fdb *fdb,
++			struct switchdev_trans *trans)
++{
++	struct mt7530_priv *priv = ds->priv;
++	int ret;
++
++	/* Because auto-learned entrie shares the same FDB table.
++	 * an entry is reserved with no port_mask to make sure fdb_add
++	 * is called while the entry is still available.
++	 */
++	mutex_lock(&priv->reg_mutex);
++	mt7530_fdb_write(priv, fdb->vid, 0, fdb->addr, -1, STATIC_ENT);
++	ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
++	mutex_unlock(&priv->reg_mutex);
++
++	return ret;
++}
++
++static void
++mt7530_port_fdb_add(struct dsa_switch *ds, int port,
++		    const struct switchdev_obj_port_fdb *fdb,
++		    struct switchdev_trans *trans)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u8 port_mask = BIT(port);
++
++	mutex_lock(&priv->reg_mutex);
++	mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_ENT);
++	mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
++	mutex_unlock(&priv->reg_mutex);
++}
++
++static int
++mt7530_port_fdb_del(struct dsa_switch *ds, int port,
++		    const struct switchdev_obj_port_fdb *fdb)
++{
++	struct mt7530_priv *priv = ds->priv;
++	int ret;
++	u8 port_mask = BIT(port);
++
++	mutex_lock(&priv->reg_mutex);
++	mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_EMP);
++	ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
++	mutex_unlock(&priv->reg_mutex);
++
++	return ret;
++}
++
++static int
++mt7530_port_fdb_dump(struct dsa_switch *ds, int port,
++		     struct switchdev_obj_port_fdb *fdb,
++		     int (*cb)(struct switchdev_obj *obj))
++{
++	struct mt7530_priv *priv = ds->priv;
++	struct mt7530_fdb _fdb = { 0 };
++	int cnt = MT7530_NUM_FDB_RECORDS;
++	int ret = 0;
++	u32 rsp = 0;
++
++	mutex_lock(&priv->reg_mutex);
++
++	ret = mt7530_fdb_cmd(priv, MT7530_FDB_START, &rsp);
++	if (ret < 0)
++		goto err;
++
++	do {
++		if (rsp & ATC_SRCH_HIT) {
++			mt7530_fdb_read(priv, &_fdb);
++			if (_fdb.port_mask & BIT(port)) {
++				ether_addr_copy(fdb->addr, _fdb.mac);
++				fdb->vid = _fdb.vid;
++				fdb->ndm_state = _fdb.noarp ?
++						NUD_NOARP : NUD_REACHABLE;
++				ret = cb(&fdb->obj);
++				if (ret < 0)
++					break;
++			}
++		}
++	} while (--cnt &&
++		 !(rsp & ATC_SRCH_END) &&
++		 !mt7530_fdb_cmd(priv, MT7530_FDB_NEXT, &rsp));
++err:
++	mutex_unlock(&priv->reg_mutex);
++
++	return 0;
++}
++
++static enum dsa_tag_protocol
++mtk_get_tag_protocol(struct dsa_switch *ds)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) {
++		dev_warn(priv->dev,
++			 "port not matched with tagging CPU port\n");
++		return DSA_TAG_PROTO_NONE;
++	} else {
++		return DSA_TAG_PROTO_MTK;
++	}
++}
++
++static struct dsa_switch_ops mt7530_switch_ops = {
++	.get_tag_protocol	= mtk_get_tag_protocol,
++	.setup			= mt7530_setup,
++	.get_strings		= mt7530_get_strings,
++	.phy_read		= mt7530_phy_read,
++	.phy_write		= mt7530_phy_write,
++	.get_ethtool_stats	= mt7530_get_ethtool_stats,
++	.get_sset_count		= mt7530_get_sset_count,
++	.adjust_link		= mt7530_adjust_link,
++	.port_enable		= mt7530_port_enable,
++	.port_disable		= mt7530_port_disable,
++	.port_stp_state_set	= mt7530_stp_state_set,
++	.port_bridge_join	= mt7530_port_bridge_join,
++	.port_bridge_leave	= mt7530_port_bridge_leave,
++	.port_fdb_prepare	= mt7530_port_fdb_prepare,
++	.port_fdb_add		= mt7530_port_fdb_add,
++	.port_fdb_del		= mt7530_port_fdb_del,
++	.port_fdb_dump		= mt7530_port_fdb_dump,
++};
++
++static int
++mt7530_probe(struct mdio_device *mdiodev)
++{
++	struct mt7530_priv *priv;
++	struct device_node *dn;
++
++	dn = mdiodev->dev.of_node;
++
++	priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS);
++	if (!priv->ds)
++		return -ENOMEM;
++
++	/* Use medatek,mcm property to distinguish hardware type that would
++	 * casues a little bit differences on power-on sequence.
++	 */
++	priv->mcm = of_property_read_bool(dn, "mediatek,mcm");
++	if (priv->mcm) {
++		dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n");
++
++		priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm");
++		if (IS_ERR(priv->rstc)) {
++			dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
++			return PTR_ERR(priv->rstc);
++		}
++	}
++
++	priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
++	if (IS_ERR(priv->core_pwr))
++		return PTR_ERR(priv->core_pwr);
++
++	priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
++	if (IS_ERR(priv->io_pwr))
++		return PTR_ERR(priv->io_pwr);
++
++	/* Not MCM that indicates switch works as the remote standalone
++	 * integrated circuit so the GPIO pin would be used to complete
++	 * the reset, otherwise memory-mapped register accessing used
++	 * through syscon provides in the case of MCM.
++	 */
++	if (!priv->mcm) {
++		priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
++						      GPIOD_OUT_LOW);
++		if (IS_ERR(priv->reset)) {
++			dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
++			return PTR_ERR(priv->reset);
++		}
++	}
++
++	priv->bus = mdiodev->bus;
++	priv->dev = &mdiodev->dev;
++	priv->ds->priv = priv;
++	priv->ds->ops = &mt7530_switch_ops;
++	mutex_init(&priv->reg_mutex);
++	lpriv = priv;
++	dev_set_drvdata(&mdiodev->dev, priv);
++
++	return dsa_register_switch(priv->ds, &mdiodev->dev);
++}
++
++static void
++mt7530_remove(struct mdio_device *mdiodev)
++{
++	struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
++	int ret = 0;
++
++	ret = regulator_disable(priv->core_pwr);
++	if (ret < 0)
++		dev_err(priv->dev,
++			"Failed to disable core power: %d\n", ret);
++
++	ret = regulator_disable(priv->io_pwr);
++	if (ret < 0)
++		dev_err(priv->dev, "Failed to disable io pwr: %d\n",
++			ret);
++
++	dsa_unregister_switch(priv->ds);
++	mutex_destroy(&priv->reg_mutex);
++}
++
++static const struct of_device_id mt7530_of_match[] = {
++	{ .compatible = "mediatek,mt7530" },
++	{ /* sentinel */ },
++};
++
++static struct mdio_driver mt7530_mdio_driver = {
++	.probe  = mt7530_probe,
++	.remove = mt7530_remove,
++	.mdiodrv.driver = {
++		.name = "mt7530",
++		.of_match_table = mt7530_of_match,
++	},
++};
++
++mdio_module_driver(mt7530_mdio_driver);
++
++MODULE_AUTHOR("Sean Wang <sean.wang at mediatek.com>");
++MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:mediatek-mt7530");
+diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
+new file mode 100644
+index 0000000..05a612f
+--- /dev/null
++++ b/drivers/net/dsa/mt7530.h
+@@ -0,0 +1,390 @@
++/*
++ * Copyright (C) 2017 Sean Wang <sean.wang at mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __MT7530_H
++#define __MT7530_H
++
++#define MT7530_NUM_PORTS		7
++#define MT7530_CPU_PORT			6
++#define MT7530_NUM_FDB_RECORDS		2048
++
++#define	NUM_TRGMII_CTRL			5
++
++#define TRGMII_BASE(x)			(0x10000 + (x))
++
++/* Registers to ethsys access */
++#define ETHSYS_CLKCFG0			0x2c
++#define  ETHSYS_TRGMII_CLK_SEL362_5	BIT(11)
++
++#define SYSC_REG_RSTCTRL		0x34
++#define  RESET_MCM			BIT(2)
++
++/* Registers to mac forward control for unknown frames */
++#define MT7530_MFC			0x10
++#define  BC_FFP(x)			(((x) & 0xff) << 24)
++#define  UNM_FFP(x)			(((x) & 0xff) << 16)
++#define  UNU_FFP(x)			(((x) & 0xff) << 8)
++#define  UNU_FFP_MASK			UNU_FFP(~0)
++
++/* Registers for address table access */
++#define MT7530_ATA1			0x74
++#define  STATIC_EMP			0
++#define  STATIC_ENT			3
++#define MT7530_ATA2			0x78
++
++/* Register for address table write data */
++#define MT7530_ATWD			0x7c
++
++/* Register for address table control */
++#define MT7530_ATC			0x80
++#define  ATC_HASH			(((x) & 0xfff) << 16)
++#define  ATC_BUSY			BIT(15)
++#define  ATC_SRCH_END			BIT(14)
++#define  ATC_SRCH_HIT			BIT(13)
++#define  ATC_INVALID			BIT(12)
++#define  ATC_MAT(x)			(((x) & 0xf) << 8)
++#define  ATC_MAT_MACTAB			ATC_MAT(0)
++
++enum mt7530_fdb_cmd {
++	MT7530_FDB_READ	= 0,
++	MT7530_FDB_WRITE = 1,
++	MT7530_FDB_FLUSH = 2,
++	MT7530_FDB_START = 4,
++	MT7530_FDB_NEXT = 5,
++};
++
++/* Registers for table search read address */
++#define MT7530_TSRA1			0x84
++#define  MAC_BYTE_0			24
++#define  MAC_BYTE_1			16
++#define  MAC_BYTE_2			8
++#define  MAC_BYTE_3			0
++#define  MAC_BYTE_MASK			0xff
++
++#define MT7530_TSRA2			0x88
++#define  MAC_BYTE_4			24
++#define  MAC_BYTE_5			16
++#define  CVID				0
++#define  CVID_MASK			0xfff
++
++#define MT7530_ATRD			0x8C
++#define	 AGE_TIMER			24
++#define  AGE_TIMER_MASK			0xff
++#define  PORT_MAP			4
++#define  PORT_MAP_MASK			0xff
++#define  ENT_STATUS			2
++#define  ENT_STATUS_MASK		0x3
++
++/* Register for vlan table control */
++#define MT7530_VTCR			0x90
++#define  VTCR_BUSY			BIT(31)
++#define  VTCR_FUNC			(((x) & 0xf) << 12)
++#define  VTCR_FUNC_RD_VID		0x1
++#define  VTCR_FUNC_WR_VID		0x2
++#define  VTCR_FUNC_INV_VID		0x3
++#define  VTCR_FUNC_VAL_VID		0x4
++#define  VTCR_VID			((x) & 0xfff)
++
++/* Register for setup vlan and acl write data */
++#define MT7530_VAWD1			0x94
++#define  PORT_STAG			BIT(31)
++#define  IVL_MAC			BIT(30)
++#define  PORT_MEM(x)			(((x) & 0xff) << 16)
++#define  VALID				BIT(1)
++
++#define MT7530_VAWD2			0x98
++
++/* Register for port STP state control */
++#define MT7530_SSP_P(x)			(0x2000 + ((x) * 0x100))
++#define  FID_PST(x)			((x) & 0x3)
++#define  FID_PST_MASK			FID_PST(0x3)
++
++enum mt7530_stp_state {
++	MT7530_STP_DISABLED = 0,
++	MT7530_STP_BLOCKING = 1,
++	MT7530_STP_LISTENING = 1,
++	MT7530_STP_LEARNING = 2,
++	MT7530_STP_FORWARDING  = 3
++};
++
++/* Register for port control */
++#define MT7530_PCR_P(x)			(0x2004 + ((x) * 0x100))
++#define  PORT_VLAN(x)			((x) & 0x3)
++#define  PCR_MATRIX(x)			(((x) & 0xff) << 16)
++#define  PORT_PRI(x)			(((x) & 0x7) << 24)
++#define  EG_TAG(x)			(((x) & 0x3) << 28)
++#define  PCR_MATRIX_MASK		PCR_MATRIX(0xff)
++#define  PCR_MATRIX_CLR			PCR_MATRIX(0)
++
++/* Register for port security control */
++#define MT7530_PSC_P(x)			(0x200c + ((x) * 0x100))
++#define  SA_DIS				BIT(4)
++
++/* Register for port vlan control */
++#define MT7530_PVC_P(x)			(0x2010 + ((x) * 0x100))
++#define  PORT_SPEC_TAG			BIT(5)
++#define  VLAN_ATTR(x)			(((x) & 0x3) << 6)
++#define  STAG_VPID			(((x) & 0xffff) << 16)
++
++/* Register for port port-and-protocol based vlan 1 control */
++#define MT7530_PPBV1_P(x)		(0x2014 + ((x) * 0x100))
++
++/* Register for port MAC control register */
++#define MT7530_PMCR_P(x)		(0x3000 + ((x) * 0x100))
++#define  PMCR_IFG_XMIT(x)		(((x) & 0x3) << 18)
++#define  PMCR_MAC_MODE			BIT(16)
++#define  PMCR_FORCE_MODE		BIT(15)
++#define  PMCR_TX_EN			BIT(14)
++#define  PMCR_RX_EN			BIT(13)
++#define  PMCR_BACKOFF_EN		BIT(9)
++#define  PMCR_BACKPR_EN			BIT(8)
++#define  PMCR_TX_FC_EN			BIT(5)
++#define  PMCR_RX_FC_EN			BIT(4)
++#define  PMCR_FORCE_SPEED_1000		BIT(3)
++#define  PMCR_FORCE_FDX			BIT(1)
++#define  PMCR_FORCE_LNK			BIT(0)
++#define  PMCR_COMMON_LINK		(PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
++					 PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
++					 PMCR_TX_EN | PMCR_RX_EN | \
++					 PMCR_TX_FC_EN | PMCR_RX_FC_EN)
++#define  PMCR_CPUP_LINK			(PMCR_COMMON_LINK | PMCR_FORCE_MODE | \
++					 PMCR_FORCE_SPEED_1000 | \
++					 PMCR_FORCE_FDX | \
++					 PMCR_FORCE_LNK)
++#define  PMCR_USERP_LINK		PMCR_COMMON_LINK
++#define  PMCR_FIXED_LINK		(PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
++					 PMCR_FORCE_MODE | PMCR_TX_EN | \
++					 PMCR_RX_EN | PMCR_BACKPR_EN | \
++					 PMCR_BACKOFF_EN | \
++					 PMCR_FORCE_SPEED_1000 | \
++					 PMCR_FORCE_FDX | \
++					 PMCR_FORCE_LNK)
++#define PMCR_FIXED_LINK_FC		(PMCR_FIXED_LINK | \
++					 PMCR_TX_FC_EN | PMCR_RX_FC_EN)
++
++#define MT7530_PMSR_P(x)		(0x3008 + (x) * 0x100)
++
++/* Register for MIB */
++#define MT7530_PORT_MIB_COUNTER(x)	(0x4000 + (x) * 0x100)
++#define MT7530_MIB_CCR			0x4fe0
++#define  CCR_MIB_ENABLE			BIT(31)
++#define  CCR_RX_OCT_CNT_GOOD		BIT(7)
++#define  CCR_RX_OCT_CNT_BAD		BIT(6)
++#define  CCR_TX_OCT_CNT_GOOD		BIT(5)
++#define  CCR_TX_OCT_CNT_BAD		BIT(4)
++#define  CCR_MIB_FLUSH			(CCR_RX_OCT_CNT_GOOD | \
++					 CCR_RX_OCT_CNT_BAD | \
++					 CCR_TX_OCT_CNT_GOOD | \
++					 CCR_TX_OCT_CNT_BAD)
++#define  CCR_MIB_ACTIVATE		(CCR_MIB_ENABLE | \
++					 CCR_RX_OCT_CNT_GOOD | \
++					 CCR_RX_OCT_CNT_BAD | \
++					 CCR_TX_OCT_CNT_GOOD | \
++					 CCR_TX_OCT_CNT_BAD)
++/* Register for system reset */
++#define MT7530_SYS_CTRL			0x7000
++#define  SYS_CTRL_PHY_RST		BIT(2)
++#define  SYS_CTRL_SW_RST		BIT(1)
++#define  SYS_CTRL_REG_RST		BIT(0)
++
++/* Register for hw trap status */
++#define MT7530_HWTRAP			0x7800
++
++/* Register for hw trap modification */
++#define MT7530_MHWTRAP			0x7804
++#define  MHWTRAP_MANUAL			BIT(16)
++#define  MHWTRAP_P5_MAC_SEL		BIT(13)
++#define  MHWTRAP_P6_DIS			BIT(8)
++#define  MHWTRAP_P5_RGMII_MODE		BIT(7)
++#define  MHWTRAP_P5_DIS			BIT(6)
++#define  MHWTRAP_PHY_ACCESS		BIT(5)
++
++/* Register for TOP signal control */
++#define MT7530_TOP_SIG_CTRL		0x7808
++#define  TOP_SIG_CTRL_NORMAL		(BIT(17) | BIT(16))
++
++#define MT7530_IO_DRV_CR		0x7810
++#define  P5_IO_CLK_DRV(x)		((x) & 0x3)
++#define  P5_IO_DATA_DRV(x)		(((x) & 0x3) << 4)
++
++#define MT7530_P6ECR			0x7830
++#define  P6_INTF_MODE_MASK		0x3
++#define  P6_INTF_MODE(x)		((x) & 0x3)
++
++/* Registers for TRGMII on the both side */
++#define MT7530_TRGMII_RCK_CTRL		0x7a00
++#define GSW_TRGMII_RCK_CTRL		0x300
++#define  RX_RST				BIT(31)
++#define  RXC_DQSISEL			BIT(30)
++#define  DQSI1_TAP_MASK			(0x7f << 8)
++#define  DQSI0_TAP_MASK			0x7f
++#define  DQSI1_TAP(x)			(((x) & 0x7f) << 8)
++#define  DQSI0_TAP(x)			((x) & 0x7f)
++
++#define MT7530_TRGMII_RCK_RTT		0x7a04
++#define GSW_TRGMII_RCK_RTT		0x304
++#define  DQS1_GATE			BIT(31)
++#define  DQS0_GATE			BIT(30)
++
++#define MT7530_TRGMII_RD(x)		(0x7a10 + (x) * 8)
++#define GSW_TRGMII_RD(x)		(0x310 + (x) * 8)
++#define  BSLIP_EN			BIT(31)
++#define  EDGE_CHK			BIT(30)
++#define  RD_TAP_MASK			0x7f
++#define  RD_TAP(x)			((x) & 0x7f)
++
++#define GSW_TRGMII_TXCTRL		0x340
++#define MT7530_TRGMII_TXCTRL		0x7a40
++#define  TRAIN_TXEN			BIT(31)
++#define  TXC_INV			BIT(30)
++#define  TX_RST				BIT(28)
++
++#define MT7530_TRGMII_TD_ODT(i)		(0x7a54 + 8 * (i))
++#define GSW_TRGMII_TD_ODT(i)		(0x354 + 8 * (i))
++#define  TD_DM_DRVP(x)			((x) & 0xf)
++#define  TD_DM_DRVN(x)			(((x) & 0xf) << 4)
++
++#define GSW_INTF_MODE			0x390
++#define  INTF_MODE_TRGMII		BIT(1)
++
++#define MT7530_TRGMII_TCK_CTRL		0x7a78
++#define  TCK_TAP(x)			(((x) & 0xf) << 8)
++
++#define MT7530_P5RGMIIRXCR		0x7b00
++#define  CSR_RGMII_EDGE_ALIGN		BIT(8)
++#define  CSR_RGMII_RXC_0DEG_CFG(x)	((x) & 0xf)
++
++#define MT7530_P5RGMIITXCR		0x7b04
++#define  CSR_RGMII_TXC_CFG(x)		((x) & 0x1f)
++
++#define MT7530_CREV			0x7ffc
++#define  CHIP_NAME_SHIFT		16
++#define  MT7530_ID			0x7530
++
++/* Registers for core PLL access through mmd indirect */
++#define CORE_PLL_GROUP2			0x401
++#define  RG_SYSPLL_EN_NORMAL		BIT(15)
++#define  RG_SYSPLL_VODEN		BIT(14)
++#define  RG_SYSPLL_LF			BIT(13)
++#define  RG_SYSPLL_RST_DLY(x)		(((x) & 0x3) << 12)
++#define  RG_SYSPLL_LVROD_EN		BIT(10)
++#define  RG_SYSPLL_PREDIV(x)		(((x) & 0x3) << 8)
++#define  RG_SYSPLL_POSDIV(x)		(((x) & 0x3) << 5)
++#define  RG_SYSPLL_FBKSEL		BIT(4)
++#define  RT_SYSPLL_EN_AFE_OLT		BIT(0)
++
++#define CORE_PLL_GROUP4			0x403
++#define  RG_SYSPLL_DDSFBK_EN		BIT(12)
++#define  RG_SYSPLL_BIAS_EN		BIT(11)
++#define  RG_SYSPLL_BIAS_LPF_EN		BIT(10)
++
++#define CORE_PLL_GROUP5			0x404
++#define  RG_LCDDS_PCW_NCPO1(x)		((x) & 0xffff)
++
++#define CORE_PLL_GROUP6			0x405
++#define  RG_LCDDS_PCW_NCPO0(x)		((x) & 0xffff)
++
++#define CORE_PLL_GROUP7			0x406
++#define  RG_LCDDS_PWDB			BIT(15)
++#define  RG_LCDDS_ISO_EN		BIT(13)
++#define  RG_LCCDS_C(x)			(((x) & 0x7) << 4)
++#define  RG_LCDDS_PCW_NCPO_CHG		BIT(3)
++
++#define CORE_PLL_GROUP10		0x409
++#define  RG_LCDDS_SSC_DELTA(x)		((x) & 0xfff)
++
++#define CORE_PLL_GROUP11		0x40a
++#define  RG_LCDDS_SSC_DELTA1(x)		((x) & 0xfff)
++
++#define CORE_GSWPLL_GRP1		0x40d
++#define  RG_GSWPLL_PREDIV(x)		(((x) & 0x3) << 14)
++#define  RG_GSWPLL_POSDIV_200M(x)	(((x) & 0x3) << 12)
++#define  RG_GSWPLL_EN_PRE		BIT(11)
++#define  RG_GSWPLL_FBKSEL		BIT(10)
++#define  RG_GSWPLL_BP			BIT(9)
++#define  RG_GSWPLL_BR			BIT(8)
++#define  RG_GSWPLL_FBKDIV_200M(x)	((x) & 0xff)
++
++#define CORE_GSWPLL_GRP2		0x40e
++#define  RG_GSWPLL_POSDIV_500M(x)	(((x) & 0x3) << 8)
++#define  RG_GSWPLL_FBKDIV_500M(x)	((x) & 0xff)
++
++#define CORE_TRGMII_GSW_CLK_CG		0x410
++#define  REG_GSWCK_EN			BIT(0)
++#define  REG_TRGMIICK_EN		BIT(1)
++
++#define MIB_DESC(_s, _o, _n)	\
++	{			\
++		.size = (_s),	\
++		.offset = (_o),	\
++		.name = (_n),	\
++	}
++
++struct mt7530_mib_desc {
++	unsigned int size;
++	unsigned int offset;
++	const char *name;
++};
++
++struct mt7530_fdb {
++	u16 vid;
++	u8 port_mask;
++	u8 aging;
++	u8 mac[6];
++	bool noarp;
++};
++
++struct mt7530_port {
++	bool enable;
++	u32 pm;
++};
++
++/* struct mt7530_priv -	This is the main data structure for holding the state
++ *			of the driver
++ * @dev:		The device pointer
++ * @ds:			The pointer to the dsa core structure
++ * @bus:		The bus used for the device and built-in PHY
++ * @rstc:		The pointer to reset control used by MCM
++ * @ethernet:		The regmap used for access TRGMII-based registers
++ * @core_pwr:		The power supplied into the core
++ * @io_pwr:		The power supplied into the I/O
++ * @reset:		The descriptor for GPIO line tied to its reset pin
++ * @mcm:		Flag for distinguishing if standalone IC or module
++ *			coupling
++ * @ports:		Holding the state among ports
++ * @reg_mutex:		The lock for protecting among process accessing
++ *			registers
++ */
++struct mt7530_priv {
++	struct device		*dev;
++	struct dsa_switch	*ds;
++	struct mii_bus		*bus;
++	struct reset_control	*rstc;
++	struct regmap		*ethernet;
++	struct regulator	*core_pwr;
++	struct regulator	*io_pwr;
++	struct gpio_desc	*reset;
++	bool			mcm;
++
++	struct mt7530_port	ports[MT7530_NUM_PORTS];
++	/* protect among processes for registers access*/
++	struct mutex reg_mutex;
++};
++
++struct mt7530_hw_stats {
++	const char	*string;
++	u16		reg;
++	u8		sizeof_stat;
++};
++
++#endif /* __MT7530_H */
diff --git a/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch b/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch
new file mode 100644
index 0000000..ca36d4c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch
@@ -0,0 +1,98 @@
+Index: linux-4.9.17/drivers/net/dsa/mt7530.c
+===================================================================
+--- linux-4.9.17.orig/drivers/net/dsa/mt7530.c
++++ linux-4.9.17/drivers/net/dsa/mt7530.c
+@@ -834,6 +834,7 @@ mt7530_port_bridge_join(struct dsa_switc
+ 	int i;
+ 
+ 	mutex_lock(&priv->reg_mutex);
++	priv->bridge_dev[port] = bridge;
+ 
+ 	for (i = 0; i < MT7530_NUM_PORTS; i++) {
+ 		/* Add this port to the port matrix of the other ports in the
+@@ -841,7 +842,7 @@ mt7530_port_bridge_join(struct dsa_switc
+ 		 * and not being setup until the port becomes enabled.
+ 		 */
+ 		if (ds->enabled_port_mask & BIT(i) && i != port) {
+-			if (ds->ports[i].bridge_dev != bridge)
++			if (priv->bridge_dev[i] != bridge)
+ 				continue;
+ 			if (priv->ports[i].enable)
+ 				mt7530_set(priv, MT7530_PCR_P(i),
+@@ -864,8 +865,7 @@ mt7530_port_bridge_join(struct dsa_switc
+ }
+ 
+ static void
+-mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
+-			 struct net_device *bridge)
++mt7530_port_bridge_leave(struct dsa_switch *ds, int port)
+ {
+ 	struct mt7530_priv *priv = ds->priv;
+ 	int i;
+@@ -878,7 +878,7 @@ mt7530_port_bridge_leave(struct dsa_swit
+ 		 * is kept and not being setup until the port becomes enabled.
+ 		 */
+ 		if (ds->enabled_port_mask & BIT(i) && i != port) {
+-			if (ds->ports[i].bridge_dev != bridge)
++			if (priv->bridge_dev[i] != priv->bridge_dev[port])
+ 				continue;
+ 			if (priv->ports[i].enable)
+ 				mt7530_clear(priv, MT7530_PCR_P(i),
+@@ -890,6 +890,7 @@ mt7530_port_bridge_leave(struct dsa_swit
+ 	/* Set the cpu port to be the only one in the port matrix of
+ 	 * this port.
+ 	 */
++	priv->bridge_dev[port] = NULL;
+ 	if (priv->ports[port].enable)
+ 		mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+ 			   PCR_MATRIX(BIT(MT7530_CPU_PORT)));
+@@ -1033,7 +1034,7 @@ mt7530_probe(struct mdio_device *mdiodev
+ 	if (!priv)
+ 		return -ENOMEM;
+ 
+-	priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS);
++	priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
+ 	if (!priv->ds)
+ 		return -ENOMEM;
+ 
+@@ -1076,12 +1077,13 @@ mt7530_probe(struct mdio_device *mdiodev
+ 	priv->bus = mdiodev->bus;
+ 	priv->dev = &mdiodev->dev;
+ 	priv->ds->priv = priv;
++	priv->ds->dev = &mdiodev->dev;
+ 	priv->ds->ops = &mt7530_switch_ops;
+ 	mutex_init(&priv->reg_mutex);
+ 	lpriv = priv;
+ 	dev_set_drvdata(&mdiodev->dev, priv);
+ 
+-	return dsa_register_switch(priv->ds, &mdiodev->dev);
++	return dsa_register_switch(priv->ds, priv->ds->dev->of_node);
+ }
+ 
+ static void
+Index: linux-4.9.17/drivers/net/dsa/mt7530.h
+===================================================================
+--- linux-4.9.17.orig/drivers/net/dsa/mt7530.h
++++ linux-4.9.17/drivers/net/dsa/mt7530.h
+@@ -379,6 +379,8 @@ struct mt7530_priv {
+ 	struct mt7530_port	ports[MT7530_NUM_PORTS];
+ 	/* protect among processes for registers access*/
+ 	struct mutex reg_mutex;
++
++	struct net_device *bridge_dev[MT7530_NUM_PORTS];
+ };
+ 
+ struct mt7530_hw_stats {
+Index: linux-4.9.17/net/dsa/tag_mtk.c
+===================================================================
+--- linux-4.9.17.orig/net/dsa/tag_mtk.c
++++ linux-4.9.17/net/dsa/tag_mtk.c
+@@ -35,7 +35,7 @@ static struct sk_buff *mtk_tag_xmit(stru
+ 	/* Build the tag after the MAC Source Address */
+ 	mtk_tag = skb->data + 2 * ETH_ALEN;
+ 	mtk_tag[0] = 0;
+-	mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
++	mtk_tag[1] = (1 << p->port) & MTK_HDR_XMIT_DP_BIT_MASK;
+ 	mtk_tag[2] = 0;
+ 	mtk_tag[3] = 0;
+ 
diff --git a/target/linux/mediatek/patches-4.9/0094-net-affinity.patch b/target/linux/mediatek/patches-4.9/0094-net-affinity.patch
new file mode 100644
index 0000000..8e51bdd
--- /dev/null
+++ b/target/linux/mediatek/patches-4.9/0094-net-affinity.patch
@@ -0,0 +1,40 @@
+Index: linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+===================================================================
+--- linux-4.9.17.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -2459,15 +2459,23 @@ static int mtk_probe(struct platform_dev
+ 			goto err_deinit_hw;
+ 	}
+ 
++	for (i = 0; i < 3; i++) {
++		int cpu = i % num_online_cpus();
++
++		cpumask_set_cpu(cpu, &eth->affinity_mask[i]);
++	}
++
+ 	err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
+ 			       dev_name(eth->dev), eth);
+ 	if (err)
+ 		goto err_free_dev;
++	irq_set_affinity_hint(eth->irq[1], &eth->affinity_mask[1]);
+ 
+ 	err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
+ 			       dev_name(eth->dev), eth);
+ 	if (err)
+ 		goto err_free_dev;
++	irq_set_affinity_hint(eth->irq[2], &eth->affinity_mask[2]);
+ 
+ 	err = mtk_mdio_init(eth);
+ 	if (err)
+Index: linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+===================================================================
+--- linux-4.9.17.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -539,6 +539,7 @@ struct mtk_eth {
+ 	struct net_device		*netdev[MTK_MAX_DEVS];
+ 	struct mtk_mac			*mac[MTK_MAX_DEVS];
+ 	int				irq[3];
++	cpumask_t			affinity_mask[3];
+ 	u32				msg_enable;
+ 	unsigned long			sysclk;
+ 	struct regmap			*ethsys;
diff --git a/target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch b/target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch
deleted file mode 100644
index d351192..0000000
--- a/target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch
+++ /dev/null
@@ -1,2322 +0,0 @@
-From 6b8a7257e7bcb56782c3f8048311670fe6a80209 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic at openwrt.org>
-Date: Mon, 11 Apr 2016 03:11:54 +0200
-Subject: [PATCH 101/102] net: mediatek add gsw/mt7530 driver
-
-Signed-off-by: John Crispin <blogic at openwrt.org>
----
- drivers/net/ethernet/mediatek/Makefile      |    2 +-
- drivers/net/ethernet/mediatek/gsw_mt7620.h  |  251 +++++++
- drivers/net/ethernet/mediatek/gsw_mt7623.c  | 1084 +++++++++++++++++++++++++++
- drivers/net/ethernet/mediatek/mt7530.c      |  808 ++++++++++++++++++++
- drivers/net/ethernet/mediatek/mt7530.h      |   20 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c |   59 +-
- drivers/net/ethernet/mediatek/mtk_eth_soc.h |    5 +
- 7 files changed, 2199 insertions(+), 30 deletions(-)
- create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7620.h
- create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7623.c
- create mode 100644 drivers/net/ethernet/mediatek/mt7530.c
- create mode 100644 drivers/net/ethernet/mediatek/mt7530.h
-
---- a/drivers/net/ethernet/mediatek/Makefile
-+++ b/drivers/net/ethernet/mediatek/Makefile
-@@ -2,4 +2,4 @@
- # Makefile for the Mediatek SoCs built-in ethernet macs
- #
- 
--obj-$(CONFIG_NET_MEDIATEK_SOC)			+= mtk_eth_soc.o
-+obj-$(CONFIG_NET_MEDIATEK_SOC)			+= mt7530.o gsw_mt7623.o mtk_eth_soc.o
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/gsw_mt7620.h
-@@ -0,0 +1,251 @@
-+/*   This program is free software; 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.
-+ *
-+ *   Copyright (C) 2009-2016 John Crispin <blogic at openwrt.org>
-+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd at nbd.name>
-+ *   Copyright (C) 2013-2016 Michael Lee <igvtee at gmail.com>
-+ */
-+
-+#ifndef _RALINK_GSW_MT7620_H__
-+#define _RALINK_GSW_MT7620_H__
-+
-+#define GSW_REG_PHY_TIMEOUT	(5 * HZ)
-+
-+#define MT7620_GSW_REG_PIAC	0x0004
-+
-+#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 GSW_REG_GPC1		0x7014
-+
-+#define SYSC_REG_CHIP_REV_ID	0x0c
-+#define SYSC_REG_CFG		0x10
-+#define SYSC_REG_CFG1		0x14
-+#define RST_CTRL_MCM		BIT(2)
-+#define SYSC_PAD_RGMII2_MDIO	0x58
-+#define SYSC_GPIO_MODE		0x60
-+
-+#define PORT_IRQ_ST_CHG		0x7f
-+
-+#define MT7621_ESW_PHY_POLLING	0x0000
-+#define MT7620_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)
-+
-+/* ethernet subsystem config register */
-+#define ETHSYS_SYSCFG0		0x14
-+/* ethernet subsystem clock register */
-+#define ETHSYS_CLKCFG0		0x2c
-+#define ETHSYS_TRGMII_CLK_SEL362_5	BIT(11)
-+
-+/* p5 RGMII wrapper TX clock control register */
-+#define MT7530_P5RGMIITXCR	0x7b04
-+/* p5 RGMII wrapper RX clock control register */
-+#define MT7530_P5RGMIIRXCR	0x7b00
-+/* TRGMII TDX ODT registers */
-+#define MT7530_TRGMII_TD0_ODT	0x7a54
-+#define MT7530_TRGMII_TD1_ODT	0x7a5c
-+#define MT7530_TRGMII_TD2_ODT	0x7a64
-+#define MT7530_TRGMII_TD3_ODT	0x7a6c
-+#define MT7530_TRGMII_TD4_ODT	0x7a74
-+#define MT7530_TRGMII_TD5_ODT	0x7a7c
-+/* TRGMII TCK ctrl register */
-+#define MT7530_TRGMII_TCK_CTRL	0x7a78
-+/* TRGMII Tx ctrl register */
-+#define MT7530_TRGMII_TXCTRL	0x7a40
-+/* port 6 extended control register */
-+#define MT7530_P6ECR            0x7830
-+/* IO driver control register */
-+#define MT7530_IO_DRV_CR	0x7810
-+/* top signal control register */
-+#define MT7530_TOP_SIG_CTRL	0x7808
-+/* modified hwtrap register */
-+#define MT7530_MHWTRAP		0x7804
-+/* hwtrap status register */
-+#define MT7530_HWTRAP		0x7800
-+/* status interrupt register */
-+#define MT7530_SYS_INT_STS	0x700c
-+/* system nterrupt register */
-+#define MT7530_SYS_INT_EN	0x7008
-+/* system control register */
-+#define MT7530_SYS_CTRL		0x7000
-+/* port MAC status register */
-+#define MT7530_PMSR_P(x)	(0x3008 + (x * 0x100))
-+/* port MAC control register */
-+#define MT7530_PMCR_P(x)	(0x3000 + (x * 0x100))
-+
-+#define MT7621_XTAL_SHIFT	6
-+#define MT7621_XTAL_MASK	0x7
-+#define MT7621_XTAL_25		6
-+#define MT7621_XTAL_40		3
-+#define MT7621_MDIO_DRV_MASK	(3 << 4)
-+#define MT7621_GE1_MODE_MASK	(3 << 12)
-+
-+#define TRGMII_TXCTRL_TXC_INV	BIT(30)
-+#define P6ECR_INTF_MODE_RGMII	BIT(1)
-+#define P5RGMIIRXCR_C_ALIGN	BIT(8)
-+#define P5RGMIIRXCR_DELAY_2	BIT(1)
-+#define P5RGMIITXCR_DELAY_2	(BIT(8) | BIT(2))
-+
-+/* TOP_SIG_CTRL bits */
-+#define TOP_SIG_CTRL_NORMAL	(BIT(17) | BIT(16))
-+
-+/* MHWTRAP bits */
-+#define MHWTRAP_MANUAL		BIT(16)
-+#define MHWTRAP_P5_MAC_SEL	BIT(13)
-+#define MHWTRAP_P6_DIS		BIT(8)
-+#define MHWTRAP_P5_RGMII_MODE	BIT(7)
-+#define MHWTRAP_P5_DIS		BIT(6)
-+#define MHWTRAP_PHY_ACCESS	BIT(5)
-+
-+/* HWTRAP bits */
-+#define HWTRAP_XTAL_SHIFT	9
-+#define HWTRAP_XTAL_MASK	0x3
-+
-+/* SYS_CTRL bits */
-+#define SYS_CTRL_SW_RST		BIT(1)
-+#define SYS_CTRL_REG_RST	BIT(0)
-+
-+/* PMCR bits */
-+#define PMCR_IFG_XMIT_96	BIT(18)
-+#define PMCR_MAC_MODE		BIT(16)
-+#define PMCR_FORCE_MODE		BIT(15)
-+#define PMCR_TX_EN		BIT(14)
-+#define PMCR_RX_EN		BIT(13)
-+#define PMCR_BACK_PRES_EN	BIT(9)
-+#define PMCR_BACKOFF_EN		BIT(8)
-+#define PMCR_TX_FC_EN		BIT(5)
-+#define PMCR_RX_FC_EN		BIT(4)
-+#define PMCR_FORCE_SPEED_1000	BIT(3)
-+#define PMCR_FORCE_FDX		BIT(1)
-+#define PMCR_FORCE_LNK		BIT(0)
-+#define PMCR_FIXED_LINK		(PMCR_IFG_XMIT_96 | PMCR_MAC_MODE | \
-+				 PMCR_FORCE_MODE | PMCR_TX_EN | PMCR_RX_EN | \
-+				 PMCR_BACK_PRES_EN | PMCR_BACKOFF_EN | \
-+				 PMCR_FORCE_SPEED_1000 | PMCR_FORCE_FDX | \
-+				 PMCR_FORCE_LNK)
-+
-+#define PMCR_FIXED_LINK_FC	(PMCR_FIXED_LINK | \
-+				 PMCR_TX_FC_EN | PMCR_RX_FC_EN)
-+
-+/* TRGMII control registers */
-+#define GSW_INTF_MODE		0x390
-+#define GSW_TRGMII_TD0_ODT	0x354
-+#define GSW_TRGMII_TD1_ODT	0x35c
-+#define GSW_TRGMII_TD2_ODT	0x364
-+#define GSW_TRGMII_TD3_ODT	0x36c
-+#define GSW_TRGMII_TXCTL_ODT	0x374
-+#define GSW_TRGMII_TCK_ODT	0x37c
-+#define GSW_TRGMII_RCK_CTRL	0x300
-+
-+#define INTF_MODE_TRGMII	BIT(1)
-+#define TRGMII_RCK_CTRL_RX_RST	BIT(31)
-+
-+
-+/* possible XTAL speed */
-+#define	MT7623_XTAL_40		0
-+#define MT7623_XTAL_20		1
-+#define MT7623_XTAL_25		3
-+
-+/* GPIO port control registers */
-+#define	GPIO_OD33_CTRL8		0x4c0
-+#define	GPIO_BIAS_CTRL		0xed0
-+#define GPIO_DRV_SEL10		0xf00
-+
-+/* on MT7620 the functio of port 4 can be software configured */
-+enum {
-+	PORT4_EPHY = 0,
-+	PORT4_EXT,
-+};
-+
-+/* struct mt7620_gsw -	the structure that holds the SoC specific data
-+ * @dev:		The Device struct
-+ * @base:		The base address
-+ * @piac_offset:	The PIAC base may change depending on SoC
-+ * @irq:		The IRQ we are using
-+ * @port4:		The port4 mode on MT7620
-+ * @autopoll:		Is MDIO autopolling enabled
-+ * @ethsys:		The ethsys register map
-+ * @pctl:		The pin control register map
-+ * @clk_trgpll:		The trgmii pll clock
-+ */
-+struct mt7620_gsw {
-+	struct mtk_eth		*eth;
-+	struct device		*dev;
-+	void __iomem		*base;
-+	u32			piac_offset;
-+	int			irq;
-+	int			port4;
-+	unsigned long int	autopoll;
-+
-+	struct regmap		*ethsys;
-+	struct regmap		*pctl;
-+
-+	struct clk		*clk_trgpll;
-+
-+	int			trgmii_force;
-+	bool			wllll;
-+};
-+
-+/* switch register I/O wrappers */
-+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg);
-+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg);
-+
-+/* the callback used by the driver core to bringup the switch */
-+int mtk_gsw_init(struct mtk_eth *eth);
-+
-+/* MDIO access wrappers */
-+int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val);
-+int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg);
-+void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port);
-+int mt7620_has_carrier(struct mtk_eth *eth);
-+void mt7620_print_link_state(struct mtk_eth *eth, int port, int link,
-+			     int speed, int duplex);
-+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val);
-+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg);
-+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg);
-+
-+u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr,
-+		      u32 phy_register, u32 write_data);
-+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg);
-+void mt7620_handle_carrier(struct mtk_eth *eth);
-+
-+#endif
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/gsw_mt7623.c
-@@ -0,0 +1,1084 @@
-+/*   This program is free software; 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.
-+ *
-+ *   Copyright (C) 2009-2016 John Crispin <blogic at openwrt.org>
-+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd at nbd.name>
-+ *   Copyright (C) 2013-2016 Michael Lee <igvtee at gmail.com>
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/platform_device.h>
-+#include <linux/of_device.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_gpio.h>
-+#include <linux/of_mdio.h>
-+#include <linux/clk.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regmap.h>
-+#include <linux/reset.h>
-+#include <linux/mii.h>
-+#include <linux/interrupt.h>
-+#include <linux/netdevice.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/phy.h>
-+#include <linux/ethtool.h>
-+#include <linux/version.h>
-+#include <linux/atomic.h>
-+
-+#include "mtk_eth_soc.h"
-+#include "gsw_mt7620.h"
-+#include "mt7530.h"
-+
-+#define ETHSYS_CLKCFG0			0x2c
-+#define ETHSYS_TRGMII_CLK_SEL362_5	BIT(11)
-+
-+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val)
-+{
-+	_mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
-+	_mtk_mdio_write(gsw->eth, 0x1f, (reg >> 2) & 0xf,  val & 0xffff);
-+	_mtk_mdio_write(gsw->eth, 0x1f, 0x10, val >> 16);
-+}
-+
-+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg)
-+{
-+	u16 high, low;
-+
-+	_mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
-+	low = _mtk_mdio_read(gsw->eth, 0x1f, (reg >> 2) & 0xf);
-+	high = _mtk_mdio_read(gsw->eth, 0x1f, 0x10);
-+
-+	return (high << 16) | (low & 0xffff);
-+}
-+
-+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg)
-+{
-+	u32 val = mt7530_mdio_r32(gsw, reg);
-+
-+	val &= mask;
-+	val |= set;
-+	mt7530_mdio_w32(gsw, reg, val);
-+}
-+
-+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg)
-+{
-+	mtk_w32(gsw->eth, val, reg + 0x10000);
-+}
-+
-+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg)
-+{
-+	return mtk_r32(gsw->eth, reg + 0x10000);
-+}
-+
-+void mtk_switch_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, unsigned reg)
-+{
-+	u32 val = mtk_switch_r32(gsw, reg);
-+
-+	val &= mask;
-+	val |= set;
-+
-+	mtk_switch_w32(gsw, val, reg);
-+}
-+
-+int mt7623_gsw_config(struct mtk_eth *eth)
-+{
-+	if (eth->mii_bus && mdiobus_get_phy(eth->mii_bus, 0x1f))
-+		mt7530_probe(eth->dev, NULL, eth->mii_bus, 1);
-+
-+	return 0;
-+}
-+
-+static irqreturn_t gsw_interrupt_mt7623(int irq, void *_eth)
-+{
-+	struct mtk_eth *eth = (struct mtk_eth *)_eth;
-+	struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
-+	u32 reg, i;
-+
-+	reg = mt7530_mdio_r32(gsw, 0x700c);
-+
-+	for (i = 0; i < 5; i++)
-+		if (reg & BIT(i)) {
-+			unsigned int link;
-+
-+			link = mt7530_mdio_r32(gsw,
-+					       0x3008 + (i * 0x100)) & 0x1;
-+
-+			if (link)
-+				dev_info(gsw->dev,
-+					 "port %d link up\n", i);
-+			else
-+				dev_info(gsw->dev,
-+					 "port %d link down\n", i);
-+		}
-+
-+//	mt7620_handle_carrier(eth);
-+	mt7530_mdio_w32(gsw, 0x700c, 0x1f);
-+
-+	return IRQ_HANDLED;
-+}
-+
-+static void wait_loop(struct mt7620_gsw *gsw)
-+{
-+	int i;
-+	int read_data;
-+
-+	for (i = 0; i < 320; i = i + 1)
-+		read_data = mtk_switch_r32(gsw, 0x610);
-+}
-+
-+static void trgmii_calibration_7623(struct mt7620_gsw *gsw)
-+{
-+
-+	unsigned int tap_a[5] = { 0, 0, 0, 0, 0 };	/* minumum delay for all correct */
-+	unsigned int tap_b[5] = { 0, 0, 0, 0, 0 };	/* maximum delay for all correct */
-+	unsigned int final_tap[5];
-+	unsigned int rxc_step_size;
-+	unsigned int rxd_step_size;
-+	unsigned int read_data;
-+	unsigned int tmp;
-+	unsigned int rd_wd;
-+	int i;
-+	unsigned int err_cnt[5];
-+	unsigned int init_toggle_data;
-+	unsigned int err_flag[5];
-+	unsigned int err_total_flag;
-+	unsigned int training_word;
-+	unsigned int rd_tap;
-+	u32 val;
-+
-+	u32 TRGMII_7623_base;
-+	u32 TRGMII_7623_RD_0;
-+	u32 TRGMII_RCK_CTRL;
-+
-+	TRGMII_7623_base = 0x300;	/* 0xFB110300 */
-+	TRGMII_7623_RD_0 = TRGMII_7623_base + 0x10;
-+	TRGMII_RCK_CTRL = TRGMII_7623_base;
-+	rxd_step_size = 0x1;
-+	rxc_step_size = 0x4;
-+	init_toggle_data = 0x00000055;
-+	training_word = 0x000000AC;
-+
-+	/* RX clock gating in MT7623 */
-+	mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04);
-+
-+	/* Assert RX  reset in MT7623 */
-+	mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_base + 0x00);
-+
-+	/* Set TX OE edge in  MT7623 */
-+	mtk_switch_m32(gsw, 0, 0x00002000, TRGMII_7623_base + 0x78);
-+
-+	/* Disable RX clock gating in MT7623 */
-+	mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04);
-+
-+	/* Release RX reset in MT7623 */
-+	mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base);
-+
-+	for (i = 0; i < 5; i++)
-+		mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8);
-+
-+	pr_err("Enable Training Mode in MT7530\n");
-+	read_data = mt7530_mdio_r32(gsw, 0x7A40);
-+	read_data |= 0xC0000000;
-+	mt7530_mdio_w32(gsw, 0x7A40, read_data);	/* Enable Training Mode in MT7530 */
-+	err_total_flag = 0;
-+	pr_err("Adjust RXC delay in MT7623\n");
-+	read_data = 0x0;
-+	while (err_total_flag == 0 && read_data != 0x68) {
-+		pr_err("2nd Enable EDGE CHK in MT7623\n");
-+		/* Enable EDGE CHK in MT7623 */
-+		for (i = 0; i < 5; i++)
-+			    mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+
-+		wait_loop(gsw);
-+		err_total_flag = 1;
-+		for (i = 0; i < 5; i++) {
-+			err_cnt[i] =
-+			    mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 8;
-+			err_cnt[i] &= 0x0000000f;
-+			rd_wd = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 16;
-+			rd_wd &= 0x000000ff;
-+			val = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
-+			pr_err("ERR_CNT = %d, RD_WD =%x, TRGMII_7623_RD_0=%x\n",
-+			       err_cnt[i], rd_wd, val);
-+			if (err_cnt[i] != 0) {
-+				err_flag[i] = 1;
-+			} else if (rd_wd != 0x55) {
-+				err_flag[i] = 1;
-+			} else {
-+				err_flag[i] = 0;
-+			}
-+			err_total_flag = err_flag[i] & err_total_flag;
-+		}
-+
-+		pr_err("2nd Disable EDGE CHK in MT7623\n");
-+		/* Disable EDGE CHK in MT7623 */
-+		for (i = 0; i < 5; i++)
-+			    mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+		wait_loop(gsw);
-+		pr_err("2nd Disable EDGE CHK in MT7623\n");
-+		/* Adjust RXC delay */
-+		/* RX clock gating in MT7623 */
-+		mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04);
-+		read_data = mtk_switch_r32(gsw, TRGMII_7623_base);
-+		if (err_total_flag == 0) {
-+			tmp = (read_data & 0x0000007f) + rxc_step_size;
-+			pr_err(" RXC delay = %d\n", tmp); 
-+			read_data >>= 8;
-+			read_data &= 0xffffff80;
-+			read_data |= tmp;
-+			read_data <<= 8;
-+			read_data &= 0xffffff80;
-+			read_data |= tmp;
-+			mtk_switch_w32(gsw, read_data, TRGMII_7623_base);
-+		} else {
-+			tmp = (read_data & 0x0000007f) + 16;
-+			pr_err(" RXC delay = %d\n", tmp); 
-+			read_data >>= 8;
-+			read_data &= 0xffffff80;
-+			read_data |= tmp;
-+			read_data <<= 8;
-+			read_data &= 0xffffff80;
-+			read_data |= tmp;
-+			mtk_switch_w32(gsw, read_data, TRGMII_7623_base);
-+		}
-+		read_data &= 0x000000ff;
-+
-+		/* Disable RX clock gating in MT7623 */
-+		mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04);
-+		for (i = 0; i < 5; i++)
-+			mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8);
-+	}
-+
-+	/* Read RD_WD MT7623 */
-+	for (i = 0; i < 5; i++) {
-+		rd_tap = 0;
-+		while (err_flag[i] != 0 && rd_tap != 128) {
-+			/* Enable EDGE CHK in MT7623 */
-+			mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+			wait_loop(gsw);
-+
-+			read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
-+			err_cnt[i] = (read_data >> 8) & 0x0000000f;	/* Read MT7623 Errcnt */
-+			rd_wd = (read_data >> 16) & 0x000000ff;
-+			if (err_cnt[i] != 0 || rd_wd != 0x55) {
-+				err_flag[i] = 1;
-+			} else {
-+				err_flag[i] = 0;
-+			}
-+			/* Disable EDGE CHK in MT7623 */
-+			mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+			wait_loop(gsw);
-+			if (err_flag[i] != 0) {
-+				rd_tap = (read_data & 0x0000007f) + rxd_step_size;	/* Add RXD delay in MT7623 */
-+				read_data = (read_data & 0xffffff80) | rd_tap;
-+				mtk_switch_w32(gsw, read_data,
-+					TRGMII_7623_RD_0 + i * 8);
-+				tap_a[i] = rd_tap;
-+			} else {
-+				rd_tap = (read_data & 0x0000007f) + 48;
-+				read_data = (read_data & 0xffffff80) | rd_tap;
-+				mtk_switch_w32(gsw, read_data,
-+					TRGMII_7623_RD_0 + i * 8);
-+			}
-+
-+		}
-+		pr_err("MT7623 %dth bit  Tap_a = %d\n", i, tap_a[i]);
-+	}
-+	/* pr_err("Last While Loop\n"); */
-+	for (i = 0; i < 5; i++) {
-+		while ((err_flag[i] == 0) && (rd_tap != 128)) {
-+			read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
-+			rd_tap = (read_data & 0x0000007f) + rxd_step_size;	/* Add RXD delay in MT7623 */
-+			read_data = (read_data & 0xffffff80) | rd_tap;
-+			mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8);
-+			/* Enable EDGE CHK in MT7623 */
-+			val =
-+			    mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) | 0x40000000;
-+			val &= 0x4fffffff;
-+			mtk_switch_w32(gsw, val, TRGMII_7623_RD_0 + i * 8);
-+			wait_loop(gsw);
-+			read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8);
-+			err_cnt[i] = (read_data >> 8) & 0x0000000f;	/* Read MT7623 Errcnt */
-+			rd_wd = (read_data >> 16) & 0x000000ff;
-+			if (err_cnt[i] != 0 || rd_wd != 0x55) {
-+				err_flag[i] = 1;
-+			} else {
-+				err_flag[i] = 0;
-+			}
-+
-+			/* Disable EDGE CHK in MT7623 */
-+			mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8);
-+			wait_loop(gsw);
-+
-+		}
-+
-+		tap_b[i] = rd_tap;	/* -rxd_step_size; */
-+		pr_err("MT7623 %dth bit  Tap_b = %d\n", i, tap_b[i]);
-+		final_tap[i] = (tap_a[i] + tap_b[i]) / 2;	/* Calculate RXD delay = (TAP_A + TAP_B)/2 */
-+		read_data = (read_data & 0xffffff80) | final_tap[i];
-+		mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8);
-+	}
-+
-+	read_data = mt7530_mdio_r32(gsw, 0x7A40);
-+	read_data &= 0x3fffffff;
-+	mt7530_mdio_w32(gsw, 0x7A40, read_data);
-+}
-+
-+static void trgmii_calibration_7530(struct mt7620_gsw *gsw)
-+{
-+
-+	unsigned int tap_a[5] = { 0, 0, 0, 0, 0 };
-+	unsigned int tap_b[5] = { 0, 0, 0, 0, 0 };
-+	unsigned int final_tap[5];
-+	unsigned int rxc_step_size;
-+	unsigned int rxd_step_size;
-+	unsigned int read_data;
-+	unsigned int tmp = 0;
-+	int i;
-+	unsigned int err_cnt[5];
-+	unsigned int rd_wd;
-+	unsigned int init_toggle_data;
-+	unsigned int err_flag[5];
-+	unsigned int err_total_flag;
-+	unsigned int training_word;
-+	unsigned int rd_tap;
-+
-+	u32 TRGMII_7623_base;
-+	u32 TRGMII_7530_RD_0;
-+	u32 TRGMII_RCK_CTRL;
-+	u32 TRGMII_7530_base;
-+	u32 TRGMII_7530_TX_base;
-+	u32 val;
-+
-+	TRGMII_7623_base = 0x300;
-+	TRGMII_7530_base = 0x7A00;
-+	TRGMII_7530_RD_0 = TRGMII_7530_base + 0x10;
-+	TRGMII_RCK_CTRL = TRGMII_7623_base;
-+	rxd_step_size = 0x1;
-+	rxc_step_size = 0x8;
-+	init_toggle_data = 0x00000055;
-+	training_word = 0x000000AC;
-+
-+	TRGMII_7530_TX_base = TRGMII_7530_base + 0x50;
-+
-+	/* pr_err("Calibration begin ........\n"); */
-+	val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000;
-+	mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
-+	read_data = mt7530_mdio_r32(gsw, 0x7a10);
-+	/* pr_err("TRGMII_7530_RD_0 is %x\n", read_data); */
-+
-+	read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
-+	read_data &= 0x3fffffff;
-+	mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data);	/* RX clock gating in MT7530 */
-+
-+	read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x78);
-+	read_data |= 0x00002000;
-+	mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x78, read_data);	/* Set TX OE edge in  MT7530 */
-+
-+	read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+	read_data |= 0x80000000;
-+	mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data);	/* Assert RX  reset in MT7530 */
-+
-+	read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+	read_data &= 0x7fffffff;
-+	mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data);	/* Release RX reset in MT7530 */
-+
-+	read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
-+	read_data |= 0xC0000000;
-+	mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data);	/* Disable RX clock gating in MT7530 */
-+
-+	/* pr_err("Enable Training Mode in MT7623\n"); */
-+	/*Enable Training Mode in MT7623 */
-+	val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000;
-+	mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
-+	if (gsw->trgmii_force == 2000) {
-+		val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0xC0000000;
-+		mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
-+	} else {
-+		val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000;
-+		mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40);
-+	}
-+	val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x078) & 0xfffff0ff;
-+	mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x078);
-+	val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x50) & 0xfffff0ff;
-+	mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x50);
-+	val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x58) & 0xfffff0ff;
-+	mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x58);
-+	val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x60) & 0xfffff0ff;
-+	mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x60);
-+	val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x68) & 0xfffff0ff;
-+	mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x68);
-+	val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x70) & 0xfffff0ff;
-+	mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x70);
-+	val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x78) & 0x00000800;
-+	mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x78);
-+	err_total_flag = 0;
-+	/* pr_err("Adjust RXC delay in MT7530\n"); */
-+	read_data = 0x0;
-+	while (err_total_flag == 0 && (read_data != 0x68)) {
-+		/* pr_err("2nd Enable EDGE CHK in MT7530\n"); */
-+		/* Enable EDGE CHK in MT7530 */
-+		for (i = 0; i < 5; i++) {
-+			read_data =
-+			    mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+			read_data |= 0x40000000;
-+			read_data &= 0x4fffffff;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+					read_data);
-+			wait_loop(gsw);
-+			/* pr_err("2nd Disable EDGE CHK in MT7530\n"); */
-+			err_cnt[i] =
-+			    mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+			/* pr_err("***** MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */
-+			/* pr_err("MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */
-+			err_cnt[i] >>= 8;
-+			err_cnt[i] &= 0x0000ff0f;
-+			rd_wd = err_cnt[i] >> 8;
-+			rd_wd &= 0x000000ff;
-+			err_cnt[i] &= 0x0000000f;
-+			/* read_data = mt7530_mdio_r32(gsw,0x7a10,&read_data); */
-+			if (err_cnt[i] != 0) {
-+				err_flag[i] = 1;
-+			} else if (rd_wd != 0x55) {
-+				err_flag[i] = 1;
-+			} else {
-+				err_flag[i] = 0;
-+			}
-+			if (i == 0) {
-+				err_total_flag = err_flag[i];
-+			} else {
-+				err_total_flag = err_flag[i] & err_total_flag;
-+			}
-+			/* Disable EDGE CHK in MT7530 */
-+			read_data =
-+			    mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+			read_data |= 0x40000000;
-+			read_data &= 0x4fffffff;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+					read_data);
-+			wait_loop(gsw);
-+		}
-+		/*Adjust RXC delay */
-+		if (err_total_flag == 0) {
-+			read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+			read_data |= 0x80000000;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data);	/* Assert RX  reset in MT7530 */
-+
-+			read_data =
-+			    mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
-+			read_data &= 0x3fffffff;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data);	/* RX clock gating in MT7530 */
-+
-+			read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+			tmp = read_data;
-+			tmp &= 0x0000007f;
-+			tmp += rxc_step_size;
-+			/* pr_err("Current rxc delay = %d\n", tmp); */
-+			read_data &= 0xffffff80;
-+			read_data |= tmp;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data);
-+			read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+			/* pr_err("Current RXC delay = %x\n", read_data); */
-+
-+			read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base);
-+			read_data &= 0x7fffffff;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data);	/* Release RX reset in MT7530 */
-+
-+			read_data =
-+			    mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04);
-+			read_data |= 0xc0000000;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data);	/* Disable RX clock gating in MT7530 */
-+			pr_err("####### MT7530 RXC delay is %d\n", tmp);
-+		}
-+		read_data = tmp;
-+	}
-+	pr_err("Finish RXC Adjustment while loop\n");
-+
-+	/* pr_err("Read RD_WD MT7530\n"); */
-+	/* Read RD_WD MT7530 */
-+	for (i = 0; i < 5; i++) {
-+		rd_tap = 0;
-+		while (err_flag[i] != 0 && rd_tap != 128) {
-+			/* Enable EDGE CHK in MT7530 */
-+			read_data =
-+			    mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+			read_data |= 0x40000000;
-+			read_data &= 0x4fffffff;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+					read_data);
-+			wait_loop(gsw);
-+			err_cnt[i] = (read_data >> 8) & 0x0000000f;
-+			rd_wd = (read_data >> 16) & 0x000000ff;
-+			if (err_cnt[i] != 0 || rd_wd != 0x55) {
-+				err_flag[i] = 1;
-+			} else {
-+				err_flag[i] = 0;
-+			}
-+			if (err_flag[i] != 0) {
-+				rd_tap = (read_data & 0x0000007f) + rxd_step_size;	/* Add RXD delay in MT7530 */
-+				read_data = (read_data & 0xffffff80) | rd_tap;
-+				mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+						read_data);
-+				tap_a[i] = rd_tap;
-+			} else {
-+				tap_a[i] = (read_data & 0x0000007f);	/* Record the min delay TAP_A */
-+				rd_tap = tap_a[i] + 0x4;
-+				read_data = (read_data & 0xffffff80) | rd_tap;
-+				mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+						read_data);
-+			}
-+
-+			/* Disable EDGE CHK in MT7530 */
-+			read_data =
-+			    mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+			read_data |= 0x40000000;
-+			read_data &= 0x4fffffff;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+					read_data);
-+			wait_loop(gsw);
-+
-+		}
-+		pr_err("MT7530 %dth bit  Tap_a = %d\n", i, tap_a[i]);
-+	}
-+
-+	/* pr_err("Last While Loop\n"); */
-+	for (i = 0; i < 5; i++) {
-+		rd_tap = 0;
-+		while (err_flag[i] == 0 && (rd_tap != 128)) {
-+			/* Enable EDGE CHK in MT7530 */
-+			read_data = mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+			read_data |= 0x40000000;
-+			read_data &= 0x4fffffff;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+					read_data);
-+			wait_loop(gsw);
-+			err_cnt[i] = (read_data >> 8) & 0x0000000f;
-+			rd_wd = (read_data >> 16) & 0x000000ff;
-+			if (err_cnt[i] != 0 || rd_wd != 0x55)
-+				err_flag[i] = 1;
-+			else
-+				err_flag[i] = 0;
-+
-+			if (err_flag[i] == 0 && (rd_tap != 128)) {
-+				/* Add RXD delay in MT7530 */
-+				rd_tap = (read_data & 0x0000007f) + rxd_step_size;
-+				read_data = (read_data & 0xffffff80) | rd_tap;
-+				mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+						read_data);
-+			}
-+			/* Disable EDGE CHK in MT7530 */
-+			read_data =
-+			    mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+			read_data |= 0x40000000;
-+			read_data &= 0x4fffffff;
-+			mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8,
-+					read_data);
-+			wait_loop(gsw);
-+		}
-+		tap_b[i] = rd_tap;	/* - rxd_step_size; */
-+		pr_err("MT7530 %dth bit  Tap_b = %d\n", i, tap_b[i]);
-+		/* Calculate RXD delay = (TAP_A + TAP_B)/2 */
-+		final_tap[i] = (tap_a[i] + tap_b[i]) / 2;	
-+		/* pr_err("########****** MT7530 %dth bit Final Tap = %d\n", i, final_tap[i]); */
-+
-+		read_data = (read_data & 0xffffff80) | final_tap[i];
-+		mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, read_data);
-+	}
-+
-+	if (gsw->trgmii_force == 2000)
-+		mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base + 0x40);
-+	else
-+		mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x40);
-+
-+}
-+
-+static void mt7530_trgmii_clock_setting(struct mt7620_gsw *gsw, u32 xtal_mode)
-+{
-+
-+	u32 regValue;
-+
-+	/* TRGMII Clock */
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x410);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x1);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x404);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+
-+	if (xtal_mode == 1) {
-+		/* 25MHz */
-+		if (gsw->trgmii_force == 2600)
-+			/* 325MHz */
-+			_mtk_mdio_write(gsw->eth, 0, 14, 0x1a00);
-+		else if (gsw->trgmii_force == 2000)
-+			/* 250MHz */
-+			_mtk_mdio_write(gsw->eth, 0, 14, 0x1400);
-+	} else if (xtal_mode == 2) {
-+		/* 40MHz */
-+		if (gsw->trgmii_force == 2600)
-+			/* 325MHz */
-+			_mtk_mdio_write(gsw->eth, 0, 14, 0x1040);
-+		else if (gsw->trgmii_force == 2000)
-+			/* 250MHz */
-+			_mtk_mdio_write(gsw->eth, 0, 14, 0x0c80);
-+	}
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x405);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x0);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x409);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	if (xtal_mode == 1)
-+		/* 25MHz */
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x0057);
-+	else
-+		/* 40MHz */
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x0087);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x40a);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	if (xtal_mode == 1)
-+		/* 25MHz */
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x0057);
-+	else
-+		/* 40MHz */
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x0087);
-+
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x403);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x1800);
-+
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x403);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x1c00);
-+
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x401);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0xc020);
-+
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x406);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0xa030);
-+
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x406);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0xa038);
-+
-+//	udelay(120);		/* for MT7623 bring up test */
-+
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x410);
-+	_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x3);
-+
-+	regValue = mt7530_mdio_r32(gsw, 0x7830);
-+	regValue &= 0xFFFFFFFC;
-+	regValue |= 0x00000001;
-+	mt7530_mdio_w32(gsw, 0x7830, regValue);
-+
-+	regValue = mt7530_mdio_r32(gsw, 0x7a40);
-+	regValue &= ~(0x1 << 30);
-+	regValue &= ~(0x1 << 28);
-+	mt7530_mdio_w32(gsw, 0x7a40, regValue);
-+
-+	mt7530_mdio_w32(gsw, 0x7a78, 0x55);
-+//	udelay(100);		/* for mt7623 bring up test */
-+
-+	mtk_switch_m32(gsw, 0x7fffffff, 0, 0x300);
-+
-+	trgmii_calibration_7623(gsw);
-+	trgmii_calibration_7530(gsw);
-+
-+	mtk_switch_m32(gsw, 0, 0x80000000, 0x300);
-+	mtk_switch_m32(gsw, 0, 0x7fffffff, 0x300);
-+
-+	/*MT7530 RXC reset */
-+	regValue = mt7530_mdio_r32(gsw, 0x7a00);
-+	regValue |= (0x1 << 31);
-+	mt7530_mdio_w32(gsw, 0x7a00, regValue);
-+	mdelay(1);
-+	regValue &= ~(0x1 << 31);
-+	mt7530_mdio_w32(gsw, 0x7a00, regValue);
-+	mdelay(100);
-+}
-+
-+static void mt7623_hw_init(struct mtk_eth *eth, struct mt7620_gsw *gsw, struct device_node *np)
-+{
-+       u32     i;
-+       u32     val;
-+       u32     xtal_mode;
-+
-+	regmap_update_bits(gsw->ethsys, ETHSYS_CLKCFG0,
-+			   ETHSYS_TRGMII_CLK_SEL362_5,
-+			   ETHSYS_TRGMII_CLK_SEL362_5);
-+
-+	/* reset the TRGMII core */
-+	mtk_switch_m32(gsw, 0, INTF_MODE_TRGMII, GSW_INTF_MODE);
-+	/* Assert MT7623 RXC reset */
-+	mtk_switch_m32(gsw, 0, TRGMII_RCK_CTRL_RX_RST, GSW_TRGMII_RCK_CTRL);
-+
-+	/* Hardware reset Switch */
-+	device_reset(eth->dev);
-+
-+	/* Wait for Switch Reset Completed*/
-+	for (i = 0; i < 100; i++) {
-+		mdelay(10);
-+		if (mt7530_mdio_r32(gsw, MT7530_HWTRAP))
-+			break;
-+	}
-+
-+	/* turn off all PHYs */
-+	for (i = 0; i <= 4; i++) {
-+		val = _mtk_mdio_read(gsw->eth, i, 0x0);
-+		val |= BIT(11);
-+		_mtk_mdio_write(gsw->eth, i, 0x0, val);
-+	}
-+
-+	/* reset the switch */
-+	mt7530_mdio_w32(gsw, MT7530_SYS_CTRL,
-+			SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
-+	udelay(100);
-+
-+	/* GE1, Force 1000M/FD, FC ON */
-+	mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK_FC);
-+
-+	/* GE2, Force 1000M/FD, FC ON */
-+	mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), PMCR_FIXED_LINK_FC);
-+
-+	/* Enable Port 6, P5 as GMAC5, P5 disable */
-+	val = mt7530_mdio_r32(gsw, MT7530_MHWTRAP);
-+	if (gsw->eth->mac[0] &&
-+	    of_phy_is_fixed_link(gsw->eth->mac[0]->of_node))
-+		/* Enable Port 6 */
-+		val &= ~MHWTRAP_P6_DIS;
-+	else
-+		/* Disable Port 6 */
-+		val |= MHWTRAP_P6_DIS;
-+	if (gsw->eth->mac[1] &&
-+	    of_phy_is_fixed_link(gsw->eth->mac[1]->of_node)) {
-+		/* Enable Port 5 */
-+		val &= ~MHWTRAP_P5_DIS;
-+		/* Port 5 as PHY */
-+		val &= ~MHWTRAP_P5_MAC_SEL;
-+	} else {
-+		/* Disable Port 5 */
-+		val |= MHWTRAP_P5_DIS;
-+		/* Port 5 as GMAC */
-+		val |= MHWTRAP_P5_MAC_SEL;
-+		val |= BIT(7);
-+		mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), 0x8000);
-+	}
-+	/* gphy to port 0/4 */
-+	if (gsw->wllll)
-+		val |= BIT(20);
-+	else
-+		val &= ~BIT(20);
-+
-+	/* Set MT7530 phy direct access mode**/
-+	val &= ~MHWTRAP_PHY_ACCESS;
-+	/* manual override of HW-Trap */
-+	val |= MHWTRAP_MANUAL;
-+	mt7530_mdio_w32(gsw, MT7530_MHWTRAP, val);
-+	dev_info(gsw->dev, "Setting MHWTRAP to 0x%08x\n", val);
-+
-+	val = mt7530_mdio_r32(gsw, 0x7800);
-+	val = (val >> 9) & 0x3;
-+	if (val == 0x3) {
-+		xtal_mode = 1;
-+		/* 25Mhz Xtal - do nothing */
-+	} else if (val == 0x2) {
-+		/* 40Mhz */
-+		xtal_mode = 2;
-+
-+		/* disable MT7530 core clock */
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x410);
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x0);
-+
-+		/* disable MT7530 PLL */
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x40d);
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x2020);
-+
-+		/* for MT7530 core clock = 500Mhz */
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x40e);
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x119);
-+
-+		/* enable MT7530 PLL */
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x40d);
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x2820);
-+
-+		udelay(20);
-+
-+		/* enable MT7530 core clock */
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x1f);
-+		_mtk_mdio_write(gsw->eth, 0, 14, 0x410);
-+		_mtk_mdio_write(gsw->eth, 0, 13, 0x401f);
-+	} else {
-+		xtal_mode = 3;
-+		/* 20Mhz Xtal - TODO */
-+	}
-+
-+	/* RGMII */
-+	_mtk_mdio_write(gsw->eth, 0, 14, 0x1);
-+
-+	/* set MT7530 central align */
-+	val = mt7530_mdio_r32(gsw, 0x7830);
-+	val &= ~1;
-+	val |= 1<<1;
-+	mt7530_mdio_w32(gsw, 0x7830, val);
-+
-+	val = mt7530_mdio_r32(gsw, 0x7a40);
-+	val &= ~(1<<30);
-+	mt7530_mdio_w32(gsw, 0x7a40, val);
-+
-+	mt7530_mdio_w32(gsw, 0x7a78, 0x855);
-+
-+	/* delay setting for 10/1000M */
-+	mt7530_mdio_w32(gsw, 0x7b00, 0x104);
-+	mt7530_mdio_w32(gsw, 0x7b04, 0x10);
-+
-+	/* lower Tx Driving */
-+	mt7530_mdio_w32(gsw, 0x7a54, 0x88);
-+	mt7530_mdio_w32(gsw, 0x7a5c, 0x88);
-+	mt7530_mdio_w32(gsw, 0x7a64, 0x88);
-+	mt7530_mdio_w32(gsw, 0x7a6c, 0x88);
-+	mt7530_mdio_w32(gsw, 0x7a74, 0x88);
-+	mt7530_mdio_w32(gsw, 0x7a7c, 0x88);
-+	mt7530_mdio_w32(gsw, 0x7810, 0x11);
-+
-+	/* Set MT7623/MT7683 TX Driving */
-+	mtk_switch_w32(gsw, 0x88, 0x354);
-+	mtk_switch_w32(gsw, 0x88, 0x35c);
-+	mtk_switch_w32(gsw, 0x88, 0x364);
-+	mtk_switch_w32(gsw, 0x88, 0x36c);
-+	mtk_switch_w32(gsw, 0x88, 0x374);
-+	mtk_switch_w32(gsw, 0x88, 0x37c);
-+
-+	/* Set GE2 driving and slew rate */
-+	regmap_write(gsw->pctl, 0xF00, 0xe00);
-+	/* set GE2 TDSEL */
-+	regmap_write(gsw->pctl, 0x4C0, 0x5);
-+	/* set GE2 TUNE */
-+	regmap_write(gsw->pctl, 0xED0, 0x0);
-+
-+	regmap_write(gsw->pctl, 0xb70, 0);
-+	regmap_write(gsw->pctl, 0x250, 0xffff);
-+	regmap_write(gsw->pctl, 0x260, 0xff);
-+	regmap_write(gsw->pctl, 0x380, 0x37);
-+	regmap_write(gsw->pctl, 0x390, 0x40);
-+
-+	mt7530_trgmii_clock_setting(gsw, xtal_mode);
-+
-+	//LANWANPartition(gsw);
-+
-+	/* disable EEE */
-+	for (i = 0; i <= 4; i++) {
-+		_mtk_mdio_write(gsw->eth, i, 13, 0x7);
-+		_mtk_mdio_write(gsw->eth, i, 14, 0x3C);
-+		_mtk_mdio_write(gsw->eth, i, 13, 0x4007);
-+		_mtk_mdio_write(gsw->eth, i, 14, 0x0);
-+
-+		/* Increase SlvDPSready time */
-+		_mtk_mdio_write(gsw->eth, i, 31, 0x52b5);
-+		_mtk_mdio_write(gsw->eth, i, 16, 0xafae);
-+		_mtk_mdio_write(gsw->eth, i, 18, 0x2f);
-+		_mtk_mdio_write(gsw->eth, i, 16, 0x8fae);
-+
-+		/* Incease post_update_timer */
-+		_mtk_mdio_write(gsw->eth, i, 31, 0x3);
-+		_mtk_mdio_write(gsw->eth, i, 17, 0x4b);
-+
-+		/* Adjust 100_mse_threshold */
-+		_mtk_mdio_write(gsw->eth, i, 13, 0x1e);
-+		_mtk_mdio_write(gsw->eth, i, 14, 0x123);
-+		_mtk_mdio_write(gsw->eth, i, 13, 0x401e);
-+		_mtk_mdio_write(gsw->eth, i, 14, 0xffff);
-+
-+		/* Disable mcc */
-+		_mtk_mdio_write(gsw->eth, i, 13, 0x1e);
-+		_mtk_mdio_write(gsw->eth, i, 14, 0xa6);
-+		_mtk_mdio_write(gsw->eth, i, 13, 0x401e);
-+		_mtk_mdio_write(gsw->eth, i, 14, 0x300);
-+
-+		/* Disable HW auto downshift*/
-+		_mtk_mdio_write(gsw->eth, i, 31, 0x1);
-+		val = _mtk_mdio_read(gsw->eth, i, 0x14);
-+		val &= ~(1<<4);
-+		_mtk_mdio_write(gsw->eth, i, 0x14, val);
-+	}
-+
-+	/* turn on all PHYs */
-+	for (i = 0; i <= 4; i++) {
-+		val = _mtk_mdio_read(gsw->eth, i, 0);
-+		val &= ~BIT(11);
-+		_mtk_mdio_write(gsw->eth, i, 0, val);
-+	}
-+
-+	/* enable irq */
-+	mt7530_mdio_m32(gsw, 0, TOP_SIG_CTRL_NORMAL, MT7530_TOP_SIG_CTRL);
-+}
-+
-+static const struct of_device_id mediatek_gsw_match[] = {
-+	{ .compatible = "mediatek,mt7623-gsw" },
-+	{},
-+};
-+MODULE_DEVICE_TABLE(of, mediatek_gsw_match);
-+
-+int mtk_gsw_init(struct mtk_eth *eth)
-+{
-+	struct device_node *np = eth->switch_np;
-+	struct platform_device *pdev = of_find_device_by_node(np);
-+	struct mt7620_gsw *gsw;
-+
-+	if (!pdev)
-+		return -ENODEV;
-+
-+	if (!of_device_is_compatible(np, mediatek_gsw_match->compatible))
-+		return -EINVAL;
-+
-+	gsw = platform_get_drvdata(pdev);
-+	if (!gsw)
-+		return -ENODEV;
-+	gsw->eth = eth;
-+	eth->sw_priv = gsw;
-+
-+	mt7623_hw_init(eth, gsw, np);
-+
-+	if (request_threaded_irq(gsw->irq, gsw_interrupt_mt7623, NULL, 0,
-+				 "gsw", eth))
-+		pr_err("fail to request irq\n");
-+	mt7530_mdio_w32(gsw, 0x7008, 0x1f);
-+
-+	return 0;
-+}
-+
-+static int mt7623_gsw_probe(struct platform_device *pdev)
-+{
-+	struct device_node *np = pdev->dev.of_node;
-+	struct device_node *pctl;
-+	int reset_pin, ret;
-+	struct mt7620_gsw *gsw;
-+	struct regulator *supply;
-+
-+	gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL);
-+	if (!gsw)
-+		return -ENOMEM;
-+
-+	gsw->dev = &pdev->dev;
-+	gsw->trgmii_force = 2000;
-+	gsw->irq = irq_of_parse_and_map(np, 0);
-+	if (gsw->irq < 0)
-+		return -EINVAL;
-+
-+	gsw->ethsys = syscon_regmap_lookup_by_phandle(np, "mediatek,ethsys");
-+	if (IS_ERR(gsw->ethsys))
-+		return PTR_ERR(gsw->ethsys);
-+
-+	reset_pin = of_get_named_gpio(np, "mediatek,reset-pin", 0);
-+	if (reset_pin < 0)
-+		return reset_pin;
-+
-+	pctl = of_parse_phandle(np, "mediatek,pctl-regmap", 0);
-+	if (IS_ERR(pctl))
-+		return PTR_ERR(pctl);
-+
-+	gsw->pctl = syscon_node_to_regmap(pctl);
-+	if (IS_ERR(pctl))
-+		return PTR_ERR(pctl);
-+
-+	ret = devm_gpio_request(&pdev->dev, reset_pin, "mt7530-reset");
-+	if (ret)
-+		return ret;
-+
-+	gsw->clk_trgpll = devm_clk_get(&pdev->dev, "trgpll");
-+
-+	if (IS_ERR(gsw->clk_trgpll))
-+		return -ENODEV;
-+
-+	supply = devm_regulator_get(&pdev->dev, "mt7530");
-+	if (IS_ERR(supply))
-+		return PTR_ERR(supply);
-+
-+	regulator_set_voltage(supply, 1000000, 1000000);
-+	ret = regulator_enable(supply);
-+	if (ret) {
-+		dev_err(&pdev->dev, "Failed to enable reg-7530: %d\n", ret);
-+		return ret;
-+	}
-+
-+	gsw->wllll = of_property_read_bool(np, "mediatek,wllll");
-+
-+	pm_runtime_enable(&pdev->dev);
-+	pm_runtime_get_sync(&pdev->dev);
-+
-+	ret = clk_set_rate(gsw->clk_trgpll, 500000000);
-+	if (ret)
-+		return ret;
-+
-+	regmap_write(gsw->ethsys, 0x34, 0x800000);
-+	regmap_write(gsw->ethsys, 0x34, 0x0);
-+
-+	clk_prepare_enable(gsw->clk_trgpll);
-+
-+	gpio_direction_output(reset_pin, 0);
-+	udelay(1000);
-+	gpio_set_value(reset_pin, 1);
-+	mdelay(100);
-+
-+	platform_set_drvdata(pdev, gsw);
-+
-+	return 0;
-+}
-+
-+static int mt7623_gsw_remove(struct platform_device *pdev)
-+{
-+	struct mt7620_gsw *gsw = platform_get_drvdata(pdev);
-+
-+	clk_disable_unprepare(gsw->clk_trgpll);
-+
-+	pm_runtime_put_sync(&pdev->dev);
-+        pm_runtime_disable(&pdev->dev);
-+
-+	platform_set_drvdata(pdev, NULL);
-+
-+	return 0;
-+}
-+
-+static struct platform_driver gsw_driver = {
-+	.probe = mt7623_gsw_probe,
-+	.remove = mt7623_gsw_remove,
-+	.driver = {
-+		.name = "mt7623-gsw",
-+		.owner = THIS_MODULE,
-+		.of_match_table = mediatek_gsw_match,
-+	},
-+};
-+
-+module_platform_driver(gsw_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("John Crispin <blogic at openwrt.org>");
-+MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7623 SoC");
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mt7530.c
-@@ -0,0 +1,808 @@
-+/*
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * Copyright (C) 2013 John Crispin <blogic at openwrt.org>
-+ */
-+
-+#include <linux/if.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/if_ether.h>
-+#include <linux/skbuff.h>
-+#include <linux/netdevice.h>
-+#include <linux/netlink.h>
-+#include <linux/bitops.h>
-+#include <net/genetlink.h>
-+#include <linux/switch.h>
-+#include <linux/delay.h>
-+#include <linux/phy.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/lockdep.h>
-+#include <linux/workqueue.h>
-+#include <linux/of_device.h>
-+
-+#include "mt7530.h"
-+
-+#define MT7530_CPU_PORT		6
-+#define MT7530_NUM_PORTS	8
-+#define MT7530_NUM_VLANS	16
-+#define MT7530_MAX_VID		4095
-+#define MT7530_MIN_VID		0
-+
-+/* registers */
-+#define REG_ESW_VLAN_VTCR		0x90
-+#define REG_ESW_VLAN_VAWD1		0x94
-+#define REG_ESW_VLAN_VAWD2		0x98
-+#define REG_ESW_VLAN_VTIM(x)	(0x100 + 4 * ((x) / 2))
-+
-+#define REG_ESW_VLAN_VAWD1_IVL_MAC	BIT(30)
-+#define REG_ESW_VLAN_VAWD1_VTAG_EN	BIT(28)
-+#define REG_ESW_VLAN_VAWD1_VALID	BIT(0)
-+
-+/* vlan egress mode */
-+enum {
-+	ETAG_CTRL_UNTAG	= 0,
-+	ETAG_CTRL_TAG	= 2,
-+	ETAG_CTRL_SWAP	= 1,
-+	ETAG_CTRL_STACK	= 3,
-+};
-+
-+#define REG_ESW_PORT_PCR(x)	(0x2004 | ((x) << 8))
-+#define REG_ESW_PORT_PVC(x)	(0x2010 | ((x) << 8))
-+#define REG_ESW_PORT_PPBV1(x)	(0x2014 | ((x) << 8))
-+
-+#define REG_HWTRAP		0x7804
-+
-+#define MIB_DESC(_s , _o, _n)   \
-+	{                       \
-+		.size = (_s),   \
-+		.offset = (_o), \
-+		.name = (_n),   \
-+	}
-+
-+struct mt7xxx_mib_desc {
-+	unsigned int size;
-+	unsigned int offset;
-+	const char *name;
-+};
-+
-+#define MT7621_MIB_COUNTER_BASE	0x4000
-+#define MT7621_MIB_COUNTER_PORT_OFFSET	0x100
-+#define MT7621_STATS_TDPC	0x00
-+#define MT7621_STATS_TCRC	0x04
-+#define MT7621_STATS_TUPC	0x08
-+#define MT7621_STATS_TMPC	0x0C
-+#define MT7621_STATS_TBPC	0x10
-+#define MT7621_STATS_TCEC	0x14
-+#define MT7621_STATS_TSCEC	0x18
-+#define MT7621_STATS_TMCEC	0x1C
-+#define MT7621_STATS_TDEC	0x20
-+#define MT7621_STATS_TLCEC	0x24
-+#define MT7621_STATS_TXCEC	0x28
-+#define MT7621_STATS_TPPC	0x2C
-+#define MT7621_STATS_TL64PC	0x30
-+#define MT7621_STATS_TL65PC	0x34
-+#define MT7621_STATS_TL128PC	0x38
-+#define MT7621_STATS_TL256PC	0x3C
-+#define MT7621_STATS_TL512PC	0x40
-+#define MT7621_STATS_TL1024PC	0x44
-+#define MT7621_STATS_TOC	0x48
-+#define MT7621_STATS_RDPC	0x60
-+#define MT7621_STATS_RFPC	0x64
-+#define MT7621_STATS_RUPC	0x68
-+#define MT7621_STATS_RMPC	0x6C
-+#define MT7621_STATS_RBPC	0x70
-+#define MT7621_STATS_RAEPC	0x74
-+#define MT7621_STATS_RCEPC	0x78
-+#define MT7621_STATS_RUSPC	0x7C
-+#define MT7621_STATS_RFEPC	0x80
-+#define MT7621_STATS_ROSPC	0x84
-+#define MT7621_STATS_RJEPC	0x88
-+#define MT7621_STATS_RPPC	0x8C
-+#define MT7621_STATS_RL64PC	0x90
-+#define MT7621_STATS_RL65PC	0x94
-+#define MT7621_STATS_RL128PC	0x98
-+#define MT7621_STATS_RL256PC	0x9C
-+#define MT7621_STATS_RL512PC	0xA0
-+#define MT7621_STATS_RL1024PC	0xA4
-+#define MT7621_STATS_ROC	0xA8
-+#define MT7621_STATS_RDPC_CTRL	0xB0
-+#define MT7621_STATS_RDPC_ING	0xB4
-+#define MT7621_STATS_RDPC_ARL	0xB8
-+
-+static const struct mt7xxx_mib_desc mt7621_mibs[] = {
-+	MIB_DESC(1, MT7621_STATS_TDPC, "TxDrop"),
-+	MIB_DESC(1, MT7621_STATS_TCRC, "TxCRC"),
-+	MIB_DESC(1, MT7621_STATS_TUPC, "TxUni"),
-+	MIB_DESC(1, MT7621_STATS_TMPC, "TxMulti"),
-+	MIB_DESC(1, MT7621_STATS_TBPC, "TxBroad"),
-+	MIB_DESC(1, MT7621_STATS_TCEC, "TxCollision"),
-+	MIB_DESC(1, MT7621_STATS_TSCEC, "TxSingleCol"),
-+	MIB_DESC(1, MT7621_STATS_TMCEC, "TxMultiCol"),
-+	MIB_DESC(1, MT7621_STATS_TDEC, "TxDefer"),
-+	MIB_DESC(1, MT7621_STATS_TLCEC, "TxLateCol"),
-+	MIB_DESC(1, MT7621_STATS_TXCEC, "TxExcCol"),
-+	MIB_DESC(1, MT7621_STATS_TPPC, "TxPause"),
-+	MIB_DESC(1, MT7621_STATS_TL64PC, "Tx64Byte"),
-+	MIB_DESC(1, MT7621_STATS_TL65PC, "Tx65Byte"),
-+	MIB_DESC(1, MT7621_STATS_TL128PC, "Tx128Byte"),
-+	MIB_DESC(1, MT7621_STATS_TL256PC, "Tx256Byte"),
-+	MIB_DESC(1, MT7621_STATS_TL512PC, "Tx512Byte"),
-+	MIB_DESC(1, MT7621_STATS_TL1024PC, "Tx1024Byte"),
-+	MIB_DESC(2, MT7621_STATS_TOC, "TxByte"),
-+	MIB_DESC(1, MT7621_STATS_RDPC, "RxDrop"),
-+	MIB_DESC(1, MT7621_STATS_RFPC, "RxFiltered"),
-+	MIB_DESC(1, MT7621_STATS_RUPC, "RxUni"),
-+	MIB_DESC(1, MT7621_STATS_RMPC, "RxMulti"),
-+	MIB_DESC(1, MT7621_STATS_RBPC, "RxBroad"),
-+	MIB_DESC(1, MT7621_STATS_RAEPC, "RxAlignErr"),
-+	MIB_DESC(1, MT7621_STATS_RCEPC, "RxCRC"),
-+	MIB_DESC(1, MT7621_STATS_RUSPC, "RxUnderSize"),
-+	MIB_DESC(1, MT7621_STATS_RFEPC, "RxFragment"),
-+	MIB_DESC(1, MT7621_STATS_ROSPC, "RxOverSize"),
-+	MIB_DESC(1, MT7621_STATS_RJEPC, "RxJabber"),
-+	MIB_DESC(1, MT7621_STATS_RPPC, "RxPause"),
-+	MIB_DESC(1, MT7621_STATS_RL64PC, "Rx64Byte"),
-+	MIB_DESC(1, MT7621_STATS_RL65PC, "Rx65Byte"),
-+	MIB_DESC(1, MT7621_STATS_RL128PC, "Rx128Byte"),
-+	MIB_DESC(1, MT7621_STATS_RL256PC, "Rx256Byte"),
-+	MIB_DESC(1, MT7621_STATS_RL512PC, "Rx512Byte"),
-+	MIB_DESC(1, MT7621_STATS_RL1024PC, "Rx1024Byte"),
-+	MIB_DESC(2, MT7621_STATS_ROC, "RxByte"),
-+	MIB_DESC(1, MT7621_STATS_RDPC_CTRL, "RxCtrlDrop"),
-+	MIB_DESC(1, MT7621_STATS_RDPC_ING, "RxIngDrop"),
-+	MIB_DESC(1, MT7621_STATS_RDPC_ARL, "RxARLDrop")
-+};
-+
-+enum {
-+	/* Global attributes. */
-+	MT7530_ATTR_ENABLE_VLAN,
-+};
-+
-+struct mt7530_port_entry {
-+	u16	pvid;
-+};
-+
-+struct mt7530_vlan_entry {
-+	u16	vid;
-+	u8	member;
-+	u8	etags;
-+};
-+
-+struct mt7530_priv {
-+	void __iomem		*base;
-+	struct mii_bus		*bus;
-+	struct switch_dev	swdev;
-+
-+	bool			global_vlan_enable;
-+	struct mt7530_vlan_entry	vlan_entries[MT7530_NUM_VLANS];
-+	struct mt7530_port_entry	port_entries[MT7530_NUM_PORTS];
-+};
-+
-+struct mt7530_mapping {
-+	char	*name;
-+	u16	pvids[MT7530_NUM_PORTS];
-+	u8	members[MT7530_NUM_VLANS];
-+	u8	etags[MT7530_NUM_VLANS];
-+	u16	vids[MT7530_NUM_VLANS];
-+} mt7530_defaults[] = {
-+	{
-+		.name = "llllw",
-+		.pvids = { 1, 1, 1, 1, 2, 1, 1 },
-+		.members = { 0, 0x6f, 0x50 },
-+		.etags = { 0, 0x40, 0x40 },
-+		.vids = { 0, 1, 2 },
-+	}, {
-+		.name = "wllll",
-+		.pvids = { 2, 1, 1, 1, 1, 1, 1 },
-+		.members = { 0, 0x7e, 0x41 },
-+		.etags = { 0, 0x40, 0x40 },
-+		.vids = { 0, 1, 2 },
-+	},
-+};
-+
-+struct mt7530_mapping*
-+mt7530_find_mapping(struct device_node *np)
-+{
-+	const char *map;
-+	int i;
-+
-+	if (of_property_read_string(np, "mediatek,portmap", &map))
-+		return NULL;
-+
-+	for (i = 0; i < ARRAY_SIZE(mt7530_defaults); i++)
-+		if (!strcmp(map, mt7530_defaults[i].name))
-+			return &mt7530_defaults[i];
-+
-+	return NULL;
-+}
-+
-+static void
-+mt7530_apply_mapping(struct mt7530_priv *mt7530, struct mt7530_mapping *map)
-+{
-+	int i = 0;
-+
-+	for (i = 0; i < MT7530_NUM_PORTS; i++)
-+		mt7530->port_entries[i].pvid = map->pvids[i];
-+
-+	for (i = 0; i < MT7530_NUM_VLANS; i++) {
-+		mt7530->vlan_entries[i].member = map->members[i];
-+		mt7530->vlan_entries[i].etags = map->etags[i];
-+		mt7530->vlan_entries[i].vid = map->vids[i];
-+	}
-+}
-+
-+static int
-+mt7530_reset_switch(struct switch_dev *dev)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+	int i;
-+
-+	memset(eth->port_entries, 0, sizeof(eth->port_entries));
-+	memset(eth->vlan_entries, 0, sizeof(eth->vlan_entries));
-+
-+	/* set default vid of each vlan to the same number of vlan, so the vid
-+	 * won't need be set explicitly.
-+	 */
-+	for (i = 0; i < MT7530_NUM_VLANS; i++) {
-+		eth->vlan_entries[i].vid = i;
-+	}
-+
-+	return 0;
-+}
-+
-+static int
-+mt7530_get_vlan_enable(struct switch_dev *dev,
-+			   const struct switch_attr *attr,
-+			   struct switch_val *val)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+
-+	val->value.i = eth->global_vlan_enable;
-+
-+	return 0;
-+}
-+
-+static int
-+mt7530_set_vlan_enable(struct switch_dev *dev,
-+			   const struct switch_attr *attr,
-+			   struct switch_val *val)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+
-+	eth->global_vlan_enable = val->value.i != 0;
-+
-+	return 0;
-+}
-+
-+static u32
-+mt7530_r32(struct mt7530_priv *eth, u32 reg)
-+{
-+	u32 val;
-+	if (eth->bus) {
-+		u16 high, low;
-+
-+		mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
-+		low = mdiobus_read(eth->bus, 0x1f, (reg >> 2) & 0xf);
-+		high = mdiobus_read(eth->bus, 0x1f, 0x10);
-+
-+		return (high << 16) | (low & 0xffff);
-+	}
-+
-+	val = ioread32(eth->base + reg);
-+	pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val);
-+
-+	return val;
-+}
-+
-+static void
-+mt7530_w32(struct mt7530_priv *eth, u32 reg, u32 val)
-+{
-+	if (eth->bus) {
-+		mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
-+		mdiobus_write(eth->bus, 0x1f, (reg >> 2) & 0xf,  val & 0xffff);
-+		mdiobus_write(eth->bus, 0x1f, 0x10, val >> 16);
-+		return;
-+	}
-+
-+	pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val);
-+	iowrite32(val, eth->base + reg);
-+}
-+
-+static void
-+mt7530_vtcr(struct mt7530_priv *eth, u32 cmd, u32 val)
-+{
-+	int i;
-+
-+	mt7530_w32(eth, REG_ESW_VLAN_VTCR, BIT(31) | (cmd << 12) | val);
-+
-+	for (i = 0; i < 20; i++) {
-+		u32 val = mt7530_r32(eth, REG_ESW_VLAN_VTCR);
-+
-+		if ((val & BIT(31)) == 0)
-+			break;
-+
-+		udelay(1000);
-+	}
-+	if (i == 20)
-+		printk("mt7530: vtcr timeout\n");
-+}
-+
-+static int
-+mt7530_get_port_pvid(struct switch_dev *dev, int port, int *val)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+
-+	if (port >= MT7530_NUM_PORTS)
-+		return -EINVAL;
-+
-+	*val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(port));
-+	*val &= 0xfff;
-+
-+	return 0;
-+}
-+
-+static int
-+mt7530_set_port_pvid(struct switch_dev *dev, int port, int pvid)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+
-+	if (port >= MT7530_NUM_PORTS)
-+		return -EINVAL;
-+
-+	if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID)
-+		return -EINVAL;
-+
-+	eth->port_entries[port].pvid = pvid;
-+
-+	return 0;
-+}
-+
-+static int
-+mt7530_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+	u32 member;
-+	u32 etags;
-+	int i;
-+
-+	val->len = 0;
-+
-+	if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS)
-+		return -EINVAL;
-+
-+	mt7530_vtcr(eth, 0, val->port_vlan);
-+
-+	member = mt7530_r32(eth, REG_ESW_VLAN_VAWD1);
-+	member >>= 16;
-+	member &= 0xff;
-+
-+	etags = mt7530_r32(eth, REG_ESW_VLAN_VAWD2);
-+
-+	for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+		struct switch_port *p;
-+		int etag;
-+
-+		if (!(member & BIT(i)))
-+			continue;
-+
-+		p = &val->value.ports[val->len++];
-+		p->id = i;
-+
-+		etag = (etags >> (i * 2)) & 0x3;
-+
-+		if (etag == ETAG_CTRL_TAG)
-+			p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED);
-+		else if (etag != ETAG_CTRL_UNTAG)
-+			printk("vlan egress tag control neither untag nor tag.\n");
-+	}
-+
-+	return 0;
-+}
-+
-+static int
-+mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+	u8 member = 0;
-+	u8 etags = 0;
-+	int i;
-+
-+	if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS ||
-+			val->len > MT7530_NUM_PORTS)
-+		return -EINVAL;
-+
-+	for (i = 0; i < val->len; i++) {
-+		struct switch_port *p = &val->value.ports[i];
-+
-+		if (p->id >= MT7530_NUM_PORTS)
-+			return -EINVAL;
-+
-+		member |= BIT(p->id);
-+
-+		if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED))
-+			etags |= BIT(p->id);
-+	}
-+	eth->vlan_entries[val->port_vlan].member = member;
-+	eth->vlan_entries[val->port_vlan].etags = etags;
-+
-+	return 0;
-+}
-+
-+static int
-+mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
-+		struct switch_val *val)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+	int vlan;
-+	u16 vid;
-+
-+	vlan = val->port_vlan;
-+	vid = (u16)val->value.i;
-+
-+	if (vlan < 0 || vlan >= MT7530_NUM_VLANS)
-+		return -EINVAL;
-+
-+	if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID)
-+		return -EINVAL;
-+
-+	eth->vlan_entries[vlan].vid = vid;
-+	return 0;
-+}
-+
-+static int
-+mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
-+		struct switch_val *val)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+	u32 vid;
-+	int vlan;
-+
-+	vlan = val->port_vlan;
-+
-+	vid = mt7530_r32(eth, REG_ESW_VLAN_VTIM(vlan));
-+	if (vlan & 1)
-+		vid = vid >> 12;
-+	vid &= 0xfff;
-+
-+	val->value.i = vid;
-+	return 0;
-+}
-+
-+static int
-+mt7530_apply_config(struct switch_dev *dev)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+	int i, j;
-+	u8 tag_ports;
-+	u8 untag_ports;
-+
-+	if (!eth->global_vlan_enable) {
-+		for (i = 0; i < MT7530_NUM_PORTS; i++)
-+			mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0000);
-+
-+		for (i = 0; i < MT7530_NUM_PORTS; i++)
-+			mt7530_w32(eth, REG_ESW_PORT_PVC(i), 0x810000c0);
-+
-+		return 0;
-+	}
-+
-+	/* set all ports as security mode */
-+	for (i = 0; i < MT7530_NUM_PORTS; i++)
-+		mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0003);
-+
-+	/* check if a port is used in tag/untag vlan egress mode */
-+	tag_ports = 0;
-+	untag_ports = 0;
-+
-+	for (i = 0; i < MT7530_NUM_VLANS; i++) {
-+		u8 member = eth->vlan_entries[i].member;
-+		u8 etags = eth->vlan_entries[i].etags;
-+
-+		if (!member)
-+			continue;
-+
-+		for (j = 0; j < MT7530_NUM_PORTS; j++) {
-+			if (!(member & BIT(j)))
-+				continue;
-+
-+			if (etags & BIT(j))
-+				tag_ports |= 1u << j;
-+			else
-+				untag_ports |= 1u << j;
-+		}
-+	}
-+
-+	/* set all untag-only ports as transparent and the rest as user port */
-+	for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+		u32 pvc_mode = 0x81000000;
-+
-+		if (untag_ports & BIT(i) && !(tag_ports & BIT(i)))
-+			pvc_mode = 0x810000c0;
-+
-+		mt7530_w32(eth, REG_ESW_PORT_PVC(i), pvc_mode);
-+	}
-+
-+	for (i = 0; i < MT7530_NUM_VLANS; i++) {
-+		u16 vid = eth->vlan_entries[i].vid;
-+		u8 member = eth->vlan_entries[i].member;
-+		u8 etags = eth->vlan_entries[i].etags;
-+		u32 val;
-+
-+		/* vid of vlan */
-+		val = mt7530_r32(eth, REG_ESW_VLAN_VTIM(i));
-+		if (i % 2 == 0) {
-+			val &= 0xfff000;
-+			val |= vid;
-+		} else {
-+			val &= 0xfff;
-+			val |= (vid << 12);
-+		}
-+		mt7530_w32(eth, REG_ESW_VLAN_VTIM(i), val);
-+
-+		/* vlan port membership */
-+		if (member)
-+			mt7530_w32(eth, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |
-+				REG_ESW_VLAN_VAWD1_VTAG_EN | (member << 16) |
-+				REG_ESW_VLAN_VAWD1_VALID);
-+		else
-+			mt7530_w32(eth, REG_ESW_VLAN_VAWD1, 0);
-+
-+		/* egress mode */
-+		val = 0;
-+		for (j = 0; j < MT7530_NUM_PORTS; j++) {
-+			if (etags & BIT(j))
-+				val |= ETAG_CTRL_TAG << (j * 2);
-+			else
-+				val |= ETAG_CTRL_UNTAG << (j * 2);
-+		}
-+		mt7530_w32(eth, REG_ESW_VLAN_VAWD2, val);
-+
-+		/* write to vlan table */
-+		mt7530_vtcr(eth, 1, i);
-+	}
-+
-+	/* Port Default PVID */
-+	for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+		u32 val;
-+		val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(i));
-+		val &= ~0xfff;
-+		val |= eth->port_entries[i].pvid;
-+		mt7530_w32(eth, REG_ESW_PORT_PPBV1(i), val);
-+	}
-+
-+	return 0;
-+}
-+
-+static int
-+mt7530_get_port_link(struct switch_dev *dev,  int port,
-+			struct switch_port_link *link)
-+{
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+	u32 speed, pmsr;
-+
-+	if (port < 0 || port >= MT7530_NUM_PORTS)
-+		return -EINVAL;
-+
-+	pmsr = mt7530_r32(eth, 0x3008 + (0x100 * port));
-+
-+	link->link = pmsr & 1;
-+	link->duplex = (pmsr >> 1) & 1;
-+	speed = (pmsr >> 2) & 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 const struct switch_attr mt7530_global[] = {
-+	{
-+		.type = SWITCH_TYPE_INT,
-+		.name = "enable_vlan",
-+		.description = "VLAN mode (1:enabled)",
-+		.max = 1,
-+		.id = MT7530_ATTR_ENABLE_VLAN,
-+		.get = mt7530_get_vlan_enable,
-+		.set = mt7530_set_vlan_enable,
-+	},
-+};
-+
-+static u64 get_mib_counter(struct mt7530_priv *eth, int i, int port)
-+{
-+	unsigned int port_base;
-+	u64 t;
-+
-+	port_base = MT7621_MIB_COUNTER_BASE +
-+		    MT7621_MIB_COUNTER_PORT_OFFSET * port;
-+
-+	t = mt7530_r32(eth, port_base + mt7621_mibs[i].offset);
-+	if (mt7621_mibs[i].size == 2) {
-+		u64 hi;
-+
-+		hi = mt7530_r32(eth, port_base + mt7621_mibs[i].offset + 4);
-+		t |= hi << 32;
-+	}
-+
-+	return t;
-+}
-+
-+static int mt7621_sw_get_port_mib(struct switch_dev *dev,
-+				  const struct switch_attr *attr,
-+				  struct switch_val *val)
-+{
-+	static char buf[4096];
-+	struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev);
-+	int i, len = 0;
-+
-+	if (val->port_vlan >= MT7530_NUM_PORTS)
-+		return -EINVAL;
-+
-+	len += snprintf(buf + len, sizeof(buf) - len,
-+			"Port %d MIB counters\n", val->port_vlan);
-+
-+	for (i = 0; i < sizeof(mt7621_mibs) / sizeof(*mt7621_mibs); ++i) {
-+		u64 counter;
-+		len += snprintf(buf + len, sizeof(buf) - len,
-+				"%-11s: ", mt7621_mibs[i].name);
-+		counter = get_mib_counter(eth, i, val->port_vlan);
-+		len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
-+				counter);
-+	}
-+
-+	val->value.s = buf;
-+	val->len = len;
-+	return 0;
-+}
-+
-+static const struct switch_attr mt7621_port[] = {
-+	{
-+		.type = SWITCH_TYPE_STRING,
-+		.name = "mib",
-+		.description = "Get MIB counters for port",
-+		.get = mt7621_sw_get_port_mib,
-+		.set = NULL,
-+	},
-+};
-+
-+static const struct switch_attr mt7530_port[] = {
-+};
-+
-+static const struct switch_attr mt7530_vlan[] = {
-+	{
-+		.type = SWITCH_TYPE_INT,
-+		.name = "vid",
-+		.description = "VLAN ID (0-4094)",
-+		.set = mt7530_set_vid,
-+		.get = mt7530_get_vid,
-+		.max = 4094,
-+	},
-+};
-+
-+static const struct switch_dev_ops mt7621_ops = {
-+	.attr_global = {
-+		.attr = mt7530_global,
-+		.n_attr = ARRAY_SIZE(mt7530_global),
-+	},
-+/*	.attr_port = {
-+		.attr = mt7621_port,
-+		.n_attr = ARRAY_SIZE(mt7621_port),
-+	},*/
-+	.attr_vlan = {
-+		.attr = mt7530_vlan,
-+		.n_attr = ARRAY_SIZE(mt7530_vlan),
-+	},
-+	.get_vlan_ports = mt7530_get_vlan_ports,
-+	.set_vlan_ports = mt7530_set_vlan_ports,
-+	.get_port_pvid = mt7530_get_port_pvid,
-+	.set_port_pvid = mt7530_set_port_pvid,
-+	.get_port_link = mt7530_get_port_link,
-+	.apply_config = mt7530_apply_config,
-+	.reset_switch = mt7530_reset_switch,
-+};
-+
-+static const struct switch_dev_ops mt7530_ops = {
-+	.attr_global = {
-+		.attr = mt7530_global,
-+		.n_attr = ARRAY_SIZE(mt7530_global),
-+	},
-+	.attr_port = {
-+		.attr = mt7530_port,
-+		.n_attr = ARRAY_SIZE(mt7530_port),
-+	},
-+	.attr_vlan = {
-+		.attr = mt7530_vlan,
-+		.n_attr = ARRAY_SIZE(mt7530_vlan),
-+	},
-+	.get_vlan_ports = mt7530_get_vlan_ports,
-+	.set_vlan_ports = mt7530_set_vlan_ports,
-+	.get_port_pvid = mt7530_get_port_pvid,
-+	.set_port_pvid = mt7530_set_port_pvid,
-+	.get_port_link = mt7530_get_port_link,
-+	.apply_config = mt7530_apply_config,
-+	.reset_switch = mt7530_reset_switch,
-+};
-+
-+int
-+mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan)
-+{
-+	struct switch_dev *swdev;
-+	struct mt7530_priv *mt7530;
-+	struct mt7530_mapping *map;
-+	int ret;
-+
-+	mt7530 = devm_kzalloc(dev, sizeof(struct mt7530_priv), GFP_KERNEL);
-+	if (!mt7530)
-+		return -ENOMEM;
-+
-+	mt7530->base = base;
-+	mt7530->bus = bus;
-+	mt7530->global_vlan_enable = vlan;
-+
-+	swdev = &mt7530->swdev;
-+	if (bus) {
-+		swdev->alias = "mt7530";
-+		swdev->name = "mt7530";
-+	} else if (IS_ENABLED(CONFIG_MACH_MT7623)) {
-+		swdev->alias = "mt7623";
-+		swdev->name = "mt7623";
-+	} else if (IS_ENABLED(CONFIG_SOC_MT7621)) {
-+		swdev->alias = "mt7621";
-+		swdev->name = "mt7621";
-+	} else {
-+		swdev->alias = "mt7620";
-+		swdev->name = "mt7620";
-+	}
-+	swdev->cpu_port = MT7530_CPU_PORT;
-+	swdev->ports = MT7530_NUM_PORTS;
-+	swdev->vlans = MT7530_NUM_VLANS;
-+	if (IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623))
-+		swdev->ops = &mt7621_ops;
-+	else
-+		swdev->ops = &mt7530_ops;
-+
-+	ret = register_switch(swdev, NULL);
-+	if (ret) {
-+		dev_err(dev, "failed to register mt7530\n");
-+		return ret;
-+	}
-+
-+	mt7530_reset_switch(swdev);
-+
-+	map = mt7530_find_mapping(dev->of_node);
-+	if (map)
-+		mt7530_apply_mapping(mt7530, map);
-+	mt7530_apply_config(swdev);
-+
-+	/* magic vodoo */
-+	if (!(IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623)) && bus && mt7530_r32(mt7530, REG_HWTRAP) !=  0x1117edf) {
-+	        dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n");
-+		mt7530_w32(mt7530, REG_HWTRAP, 0x1117edf);
-+	}
-+	dev_info(dev, "loaded %s driver\n", swdev->name);
-+
-+	return 0;
-+}
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mt7530.h
-@@ -0,0 +1,20 @@
-+/*
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * Copyright (C) 2013 John Crispin <blogic at openwrt.org>
-+ */
-+
-+#ifndef _MT7530_H__
-+#define _MT7530_H__
-+
-+int mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan);
-+
-+#endif
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -25,6 +25,9 @@
- 
- #include "mtk_eth_soc.h"
- 
-+/* the callback used by the driver core to bringup the switch */
-+int mtk_gsw_init(struct mtk_eth *eth);
-+
- static int mtk_msg_level = -1;
- module_param_named(msg_level, mtk_msg_level, int, 0);
- MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
-@@ -74,14 +77,14 @@ static int mtk_mdio_busy_wait(struct mtk
- 			return 0;
- 		if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT))
- 			break;
--		usleep_range(10, 20);
-+//		usleep_range(10, 20);
- 	}
- 
- 	dev_err(eth->dev, "mdio: MDIO timeout\n");
- 	return -1;
- }
- 
--static u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr,
-+u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr,
- 			   u32 phy_register, u32 write_data)
- {
- 	if (mtk_mdio_busy_wait(eth))
-@@ -100,7 +103,7 @@ static u32 _mtk_mdio_write(struct mtk_et
- 	return 0;
- }
- 
--static u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg)
-+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg)
- {
- 	u32 d;
- 
-@@ -155,7 +158,7 @@ static void mtk_gmac0_rgmii_adjust(struc
- 
- 	val = (speed == SPEED_1000) ?
- 		RCK_CTRL_RGMII_1000 : RCK_CTRL_RGMII_10_100;
--	mtk_w32(eth, val, TRGMII_RCK_CTRL);
-+	mtk_w32(eth, val, _TRGMII_RCK_CTRL);
- 
- 	val = (speed == SPEED_1000) ?
- 		TCK_CTRL_RGMII_1000 : TCK_CTRL_RGMII_10_100;
-@@ -1833,15 +1836,6 @@ static int mtk_hw_init(struct mtk_eth *e
- 	}
- 	regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
- 
--	/* Set GE2 driving and slew rate */
--	regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
--
--	/* set GE2 TDSEL */
--	regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5);
--
--	/* set GE2 TUNE */
--	regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0);
--
- 	/* GE1, Force 1000M/FD, FC ON */
- 	mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(0));
- 
-@@ -1851,6 +1845,8 @@ static int mtk_hw_init(struct mtk_eth *e
- 	/* Enable RX VLan Offloading */
- 	mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
- 
-+	mtk_gsw_init(eth);
-+
- 	/* disable delay and normal interrupt */
- 	mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
- 	mtk_w32(eth, 0, MTK_PDMA_DELAY_INT);
-@@ -1879,6 +1875,8 @@ static int mtk_hw_init(struct mtk_eth *e
- 		mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
- 	}
- 
-+	mt7623_gsw_config(eth);
-+
- 	return 0;
- }
- 
-@@ -2379,6 +2377,9 @@ static int mtk_probe(struct platform_dev
- 	if (!eth)
- 		return -ENOMEM;
- 
-+	eth->switch_np = of_parse_phandle(pdev->dev.of_node,
-+					  "mediatek,switch", 0);
-+
- 	eth->dev = &pdev->dev;
- 	eth->base = devm_ioremap_resource(&pdev->dev, res);
- 	if (IS_ERR(eth->base))
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -314,7 +314,7 @@
- 				 MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_LINK)
- 
- /* TRGMII RXC control register */
--#define TRGMII_RCK_CTRL		0x10300
-+#define _TRGMII_RCK_CTRL		0x10300
- #define DQSI0(x)		((x << 0) & GENMASK(6, 0))
- #define DQSI1(x)		((x << 8) & GENMASK(14, 8))
- #define RXCTL_DMWTLAT(x)	((x << 16) & GENMASK(18, 16))
-@@ -554,6 +554,9 @@ struct mtk_eth {
- 	struct mii_bus			*mii_bus;
- 	struct work_struct		pending_work;
- 	unsigned long			state;
-+
-+	struct device_node		*switch_np;
-+	void				*sw_priv;
- };
- 
- /* struct mtk_mac -	the structure that holds the info about the MACs of the
-@@ -586,4 +589,6 @@ void mtk_stats_update_mac(struct mtk_mac
- void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
- u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
- 
-+int mt7623_gsw_config(struct mtk_eth *eth);
-+
- #endif /* MTK_ETH_H */
diff --git a/target/linux/mediatek/profiles/default.mk b/target/linux/mediatek/profiles/default.mk
index c713ba0..2ef570b 100644
--- a/target/linux/mediatek/profiles/default.mk
+++ b/target/linux/mediatek/profiles/default.mk
@@ -7,9 +7,6 @@
 
 define Profile/Default
 	NAME:=Default Profile (minimum package set)
-	PACKAGES:= \
-		kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport \
-		kmod-usb3
 endef
 
 define Profile/Default/Description



More information about the lede-commits mailing list