[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>,
<ðsys CLK_ETHSYS_ESW>,
<ðsys CLK_ETHSYS_GP2>,
- <ðsys CLK_ETHSYS_GP1>;
- clock-names = "ethif", "esw", "gp2", "gp1";
+ <ðsys 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 = <ðsys>;
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 = <ðsys 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 = <ðsys>;
- 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 = <ð_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 = <ð_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 = <ð_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", ®);
++ 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, ð->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], ð->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], ð->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