mediatek: various fixes for v4.9
authorJohn Crispin <john@phrozen.org>
Fri, 7 Apr 2017 15:42:08 +0000 (17:42 +0200)
committerJohn Crispin <john@phrozen.org>
Fri, 7 Apr 2017 15:42:08 +0000 (17:42 +0200)
* 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@phrozen.org>
31 files changed:
target/linux/mediatek/Makefile
target/linux/mediatek/base-files/etc/board.d/02_network
target/linux/mediatek/base-files/lib/mediatek.sh [deleted file]
target/linux/mediatek/base-files/lib/preinit/01_affinity [deleted file]
target/linux/mediatek/base-files/lib/preinit/03_preinit_do_mediatek.sh [deleted file]
target/linux/mediatek/base-files/lib/preinit/05_set_preinit_iface [new file with mode: 0644]
target/linux/mediatek/config-4.9
target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi
target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts
target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts
target/linux/mediatek/files/arch/arm/boot/dts/mt7623-evb.dts [new file with mode: 0644]
target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch [deleted file]
target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch
target/linux/mediatek/patches-4.9/0083-mfd-led3.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0085-pmic-led0.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0086-pmic-led1.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0087-pmic-led2.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0088-pmic-led3.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0091-dsa1.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0092-dsa2.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0092-dsa3.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0092-dsa4.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0092-dsa5.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0093-dsa-compat.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0094-net-affinity.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch [deleted file]
target/linux/mediatek/profiles/default.mk

index 0b495ef..f183693 100644 (file)
@@ -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))
index 2549ff9..d772ab0 100755 (executable)
@@ -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@eth0" "5@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 (file)
index 490ee3e..0000000
+++ /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 (executable)
index 1141d6d..0000000
+++ /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 (file)
index 9e5a18d..0000000
+++ /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 (file)
index 0000000..eb0bed8
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+set_preinit_iface() {
+       ifconfig eth0 up
+       ifname=lan1
+}
+
+boot_hook_add preinit_main set_preinit_iface
+
index 5f959de..1d77275 100644 (file)
@@ -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
index 0f91194..7093d35 100644 (file)
        };
 
        pio: pinctrl@10005000 {
-               compatible = "mediatek,mt7623-pinctrl";
+               compatible = "mediatek,mt2701-pinctrl";
                reg = <0 0x1000b000 0 0x1000>;
                mediatek,pctl-regmap = <&syscfg_pctl_a>;
                pins-are-numbered;
        };
 
        syscfg_pctl_a: syscfg@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>;
        };
 
                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@10007000 {
                reg = <0 0x10200100 0 0x1c>;
        };
 
+       efuse: efuse@10206000 {
+               compatible = "mediatek,mt7623-efuse",
+                            "mediatek,efuse";
+               reg        = <0 0x10206000 0 0x1000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               /* Data cells */
+               thermal_calibration: calib@424 {
+                       reg = <0x424 0xc>;
+               };
+       };
+
        apmixedsys: apmixedsys@10209000 {
                compatible = "mediatek,mt7623-apmixedsys",
                             "mediatek,mt2701-apmixedsys";
                      <0 0x10216000 0 0x2000>;
        };
 
-       i2c0: i2c@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@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@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@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@11002000 {
 
        pwm: pwm@11006000 {
                compatible = "mediatek,mt7623-pwm";
-       
+
                reg = <0 0x11006000 0 0x1000>;
-               
                resets = <&pericfg MT2701_PERI_PWM_SW_RST>;
                reset-names = "pwm";
 
                         <&pericfg CLK_PERI_PWM5>;
                clock-names = "top", "main", "pwm1", "pwm2",
                              "pwm3", "pwm4", "pwm5";
-       
+
+               status = "disabled";
+       };
+
+       i2c0: i2c@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@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@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@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>;
                status = "disabled";
        };
 
+       thermal: thermal@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@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>;
        };
 
        bch: ecc@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>;
        };
 
        usb1: usb@1a1c0000 {
-               compatible = "mediatek,mt2701-xhci",
+               compatible = "mediatek,mt7623-xhci",
                             "mediatek,mt8173-xhci";
                reg = <0 0x1a1c0000 0 0x1000>,
                      <0 0x1a1c4700 0 0x0100>;
        };
 
        ethsys: syscon@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@1b100000 {
-               compatible = "mediatek,mt2701-eth";
+               compatible = "mediatek,mt7623-eth",
+                            "mediatek,mt2701-eth",
+                            "syscon";
                reg = <0 0x1b100000 0 0x20000>;
-       
+
                clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
                         <&ethsys CLK_ETHSYS_ESW>,
                         <&ethsys CLK_ETHSYS_GP2>,
-                        <&ethsys CLK_ETHSYS_GP1>;
-               clock-names = "ethif", "esw", "gp2", "gp1";
+                        <&ethsys CLK_ETHSYS_GP1>,
+                        <&apmixedsys CLK_APMIXED_TRGPLL>;
+               clock-names = "ethif", "esw", "gp2", "gp1", "trgpll";
                interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW
                              GIC_SPI 199 IRQ_TYPE_LEVEL_LOW
                              GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>;
                mediatek,ethsys = <&ethsys>;
                mediatek,pctl = <&syscfg_pctl_a>;
 
-               mediatek,switch = <&gsw>;
-
                #address-cells = <1>;
                #size-cells = <0>;
-       
+
                status = "disabled";
 
                gmac1: mac@0 {
                        reg = <0>;
 
                        status = "disabled";
-                       
-                       phy-mode = "rgmii";
-                       
+
+                       phy-mode = "trgmii";
+
                        fixed-link {
                                speed = <1000>;
                                full-duplex;
 
                        status = "disabled";
                };
-       
-               mdio-bus {
+
+               mdio0: mdio-bus {
                        #address-cells = <1>;
                        #size-cells = <0>;
-
-                       phy5: ethernet-phy@5 {
-                               reg = <5>;
-                               phy-mode = "rgmii-rxid";
-                       };
-
-                       phy1f: ethernet-phy@1f {
-                               reg = <0x1f>;
-                               phy-mode = "rgmii";
-                       };
                };
        };
-
-       gsw: switch@1b100000 {
-               compatible = "mediatek,mt7623-gsw";
-               interrupt-parent = <&pio>;
-               interrupts = <168 IRQ_TYPE_EDGE_RISING>;
-               resets = <&ethsys 2>;
-               reset-names = "eth";
-               clocks = <&apmixedsys CLK_APMIXED_TRGPLL>;
-               clock-names = "trgpll";
-               mt7530-supply = <&mt6323_vpa_reg>;
-               mediatek,pctl-regmap = <&syscfg_pctl_a>;
-               mediatek,ethsys = <&ethsys>;
-               status = "disabled";
-       };
 };
index 15b7da9..d90e0fb 100644 (file)
@@ -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;
                                regulator-enable-ramp-delay = <216>;
                        };
                };
+
+               mt6323led: leds {
+                       compatible = "mediatek,mt6323-led";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       led@0 {
+                               reg = <0>;
+                               label = "LED0";
+                               linux,default-trigger = "timer";
+                               default-state = "on";
+                       };
+                       led@1 {
+                               reg = <1>;
+                               label = "LED1";
+                               default-state = "off";
+                       };
+                       led@2 {
+                               reg = <2>;
+                               label = "LED2";
+                               default-state = "on";
+                       };
+                       led@3 {
+                               reg = <3>;
+                               label = "LED3";
+                               default-state = "on";
+                       };
+               };
        };
 };
 
                                 <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;
        mac-address = [00 11 22 33 44 55];
        status = "okay";
 
-       phy-mode = "rgmii";
+       phy-mode = "trgmii";
 
        fixed-link {
                speed = <1000>;
        };
 };
 
-&gsw {
-       pinctrl-names = "default";
-       pinctrl-0 = <&eth_default>;
-       mediatek,reset-pin = <&pio 15 0>;
-       status = "okay";
+&mdio0 {
+       switch@0 {
+               compatible = "mediatek,mt7530";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&eth_default>;
+
+               core-supply = <&mt6323_vpa_reg>;
+               io-supply = <&mt6323_vemc3v3_reg>;
+               reset-gpios = <&pio 33 0>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+                       port@0 {
+                               reg = <0>;
+                               label = "lan0";
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               label = "lan1";
+                       };
+
+                       port@2 {
+                               reg = <2>;
+                               label = "lan2";
+                       };
+
+                       port@3 {
+                               reg = <3>;
+                               label = "lan3";
+                       };
+
+                       port@4 {
+                               reg = <4>;
+                               label = "wan";
+                       };
+
+                       port@6 {
+                               reg = <6>;
+                               label = "cpu";
+                               ethernet = <&gmac1>;
+                               phy-mode = "trgmii";
+                               fixed-link {
+                                       speed = <1000>;
+                                       full-duplex;
+                               };
+                       };
+               };
+       };
 };
 
+
 &pwm {
        pinctrl-names = "default";
        pinctrl-0 = <&pwm_pins>;
index 630240c..86c4dd5 100644 (file)
@@ -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;
                                 <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;
 &gmac2 {
        mac-address = [00 11 22 33 44 55];
        status = "okay";
-       phy-handle = <&phy5>;
-};
-
-&gsw {
-       pinctrl-names = "default";
-       pinctrl-0 = <&eth_default>;
-       mediatek,reset-pin = <&pio 15 0>;
-       status = "okay";
 };
 
 &pwm {
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-evb.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-evb.dts
new file mode 100644 (file)
index 0000000..ad2a38b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 (file)
index 0000000..28b3d7f
--- /dev/null
@@ -0,0 +1,79 @@
+From 3e96c653372d8852c45dcd3bd856975157a0fd6a Mon Sep 17 00:00:00 2001
+From: Shunli Wang <shunli.wang@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@mediatek.com>
+Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Reviewed-by: Kevin Hilman <khilman@baylibre.com>
+Signed-off-by: Matthias Brugger <matthias.bgg@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 (file)
index 132d6c8..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-From 7c5b29de78f1b15c5bde40a6ca4510fc09588457 Mon Sep 17 00:00:00 2001
-From: Shunli Wang <shunli.wang@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@mediatek.com>
-Signed-off-by: James Liao <jamesjj.liao@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 (file)
index 0000000..4c9e790
--- /dev/null
@@ -0,0 +1,491 @@
+From 6078c651947a148c1de543b54fe55af43a63043a Mon Sep 17 00:00:00 2001
+From: James Liao <jamesjj.liao@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@mediatek.com>
+Reviewed-by: Kevin Hilman <khilman@baylibre.com>
+Signed-off-by: Matthias Brugger <matthias.bgg@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 (file)
index 0000000..c56a8a9
--- /dev/null
@@ -0,0 +1,198 @@
+From 112ef1882e12094c823937f9d72f2f598db02df7 Mon Sep 17 00:00:00 2001
+From: Shunli Wang <shunli.wang@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@mediatek.com>
+Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
+Reviewed-by: Kevin Hilman <khilman@baylibre.com>
+Signed-off-by: Matthias Brugger <matthias.bgg@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,
+       }, {
index 24437cf..cf604f4 100644 (file)
@@ -13,36 +13,10 @@ Signed-off-by: John Crispin <john@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@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@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 (file)
index 0000000..a72da69
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9591021
+Message-Id: <1487962041-6548-5-git-send-email-sean.wang@mediatek.com>
+To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
+ <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
+ <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
+ Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
+ linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
+ linux-arm-kernel@lists.infradead.org
+Date: Sat, 25 Feb 2017 02:47:21 +0800
+
+From: Sean Wang <sean.wang@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@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 (file)
index 0000000..96662dd
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9633073
+Message-Id: <1489992447-13007-2-git-send-email-sean.wang@mediatek.com>
+To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
+ <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
+ <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
+ Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
+ linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
+ linux-arm-kernel@lists.infradead.org
+Date: Mon, 20 Mar 2017 14:47:24 +0800
+
+From: Sean Wang <sean.wang@mediatek.com>
+
+This patch adds documentation for devicetree bindings for LED support on
+MT6323 PMIC.
+
+Signed-off-by: Sean Wang <sean.wang@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@0 {
++                              reg = <0>;
++                              label = "LED0";
++                              linux,default-trigger = "timer";
++                              default-state = "on";
++                      };
++                      led@1 {
++                              reg = <1>;
++                              label = "LED1";
++                              default-state = "off";
++                      };
++                      led@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 (file)
index 0000000..215b1b0
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9633089
+Message-Id: <1489992447-13007-3-git-send-email-sean.wang@mediatek.com>
+To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
+ <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
+ <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
+ Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
+ linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
+ linux-arm-kernel@lists.infradead.org
+Date: Mon, 20 Mar 2017 14:47:25 +0800
+
+From: Sean Wang <sean.wang@mediatek.com>
+
+This patch adds description for LED as the sub-module on MT6397/MT6323
+multifunction device.
+
+Signed-off-by: Sean Wang <sean.wang@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 (file)
index 0000000..f3bc921
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9633081
+Message-Id: <1489992447-13007-4-git-send-email-sean.wang@mediatek.com>
+To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
+ <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
+ <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
+ Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
+ linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
+ linux-arm-kernel@lists.infradead.org
+Date: Mon, 20 Mar 2017 14:47:26 +0800
+
+From: Sean Wang <sean.wang@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@mediatek.com>
+Reviewed-by: Jacek Anaszewski <jacek.anaszewski@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@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++#include <linux/kernel.h>
++#include <linux/leds.h>
++#include <linux/mfd/mt6323/registers.h>
++#include <linux/mfd/mt6397/core.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++
++/*
++ * Register field for MT6323_TOP_CKPDN0 to enable
++ * 32K clock common for LED device.
++ */
++#define MT6323_RG_DRV_32K_CK_PDN      BIT(11)
++#define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11)
++
++/*
++ * Register field for MT6323_TOP_CKPDN2 to enable
++ * individual clock for LED device.
++ */
++#define MT6323_RG_ISINK_CK_PDN(i)     BIT(i)
++#define MT6323_RG_ISINK_CK_PDN_MASK(i)        BIT(i)
++
++/*
++ * Register field for MT6323_TOP_CKCON1 to select
++ * clock source.
++ */
++#define MT6323_RG_ISINK_CK_SEL_MASK(i)        (BIT(10) << (i))
++
++/*
++ * Register for MT6323_ISINK_CON0 to setup the
++ * duty cycle of the blink.
++ */
++#define MT6323_ISINK_CON0(i)          (MT6323_ISINK0_CON0 + 0x8 * (i))
++#define MT6323_ISINK_DIM_DUTY_MASK    (0x1f << 8)
++#define MT6323_ISINK_DIM_DUTY(i)      (((i) << 8) & \
++                                      MT6323_ISINK_DIM_DUTY_MASK)
++
++/* Register to setup the period of the blink. */
++#define MT6323_ISINK_CON1(i)          (MT6323_ISINK0_CON1 + 0x8 * (i))
++#define MT6323_ISINK_DIM_FSEL_MASK    (0xffff)
++#define MT6323_ISINK_DIM_FSEL(i)      ((i) & MT6323_ISINK_DIM_FSEL_MASK)
++
++/* Register to control the brightness. */
++#define MT6323_ISINK_CON2(i)          (MT6323_ISINK0_CON2 + 0x8 * (i))
++#define MT6323_ISINK_CH_STEP_SHIFT    12
++#define MT6323_ISINK_CH_STEP_MASK     (0x7 << 12)
++#define MT6323_ISINK_CH_STEP(i)               (((i) << 12) & \
++                                      MT6323_ISINK_CH_STEP_MASK)
++#define MT6323_ISINK_SFSTR0_TC_MASK   (0x3 << 1)
++#define MT6323_ISINK_SFSTR0_TC(i)     (((i) << 1) & \
++                                      MT6323_ISINK_SFSTR0_TC_MASK)
++#define MT6323_ISINK_SFSTR0_EN_MASK   BIT(0)
++#define MT6323_ISINK_SFSTR0_EN                BIT(0)
++
++/* Register to LED channel enablement. */
++#define MT6323_ISINK_CH_EN_MASK(i)    BIT(i)
++#define MT6323_ISINK_CH_EN(i)         BIT(i)
++
++#define MT6323_MAX_PERIOD             10000
++#define MT6323_MAX_LEDS                       4
++#define MT6323_MAX_BRIGHTNESS         6
++#define MT6323_UNIT_DUTY              3125
++#define MT6323_CAL_HW_DUTY(o, p)      DIV_ROUND_CLOSEST((o) * 100000ul,\
++                                      (p) * MT6323_UNIT_DUTY)
++
++struct mt6323_leds;
++
++/**
++ * struct mt6323_led - state container for the LED device
++ * @id:                       the identifier in MT6323 LED device
++ * @parent:           the pointer to MT6323 LED controller
++ * @cdev:             LED class device for this LED device
++ * @current_brightness: current state of the LED device
++ */
++struct mt6323_led {
++      int                     id;
++      struct mt6323_leds      *parent;
++      struct led_classdev     cdev;
++      enum led_brightness     current_brightness;
++};
++
++/**
++ * struct mt6323_leds -       state container for holding LED controller
++ *                    of the driver
++ * @dev:              the device pointer
++ * @hw:                       the underlying hardware providing shared
++ *                    bus for the register operations
++ * @lock:             the lock among process context
++ * @led:              the array that contains the state of individual
++ *                    LED device
++ */
++struct mt6323_leds {
++      struct device           *dev;
++      struct mt6397_chip      *hw;
++      /* protect among process context */
++      struct mutex            lock;
++      struct mt6323_led       *led[MT6323_MAX_LEDS];
++};
++
++static int mt6323_led_hw_brightness(struct led_classdev *cdev,
++                                  enum led_brightness brightness)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      u32 con2_mask = 0, con2_val = 0;
++      int ret;
++
++      /*
++       * Setup current output for the corresponding
++       * brightness level.
++       */
++      con2_mask |= MT6323_ISINK_CH_STEP_MASK |
++                   MT6323_ISINK_SFSTR0_TC_MASK |
++                   MT6323_ISINK_SFSTR0_EN_MASK;
++      con2_val |=  MT6323_ISINK_CH_STEP(brightness - 1) |
++                   MT6323_ISINK_SFSTR0_TC(2) |
++                   MT6323_ISINK_SFSTR0_EN;
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id),
++                               con2_mask, con2_val);
++      return ret;
++}
++
++static int mt6323_led_hw_off(struct led_classdev *cdev)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      unsigned int status;
++      int ret;
++
++      status = MT6323_ISINK_CH_EN(led->id);
++      ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
++                               MT6323_ISINK_CH_EN_MASK(led->id), ~status);
++      if (ret < 0)
++              return ret;
++
++      usleep_range(100, 300);
++      ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
++                               MT6323_RG_ISINK_CK_PDN_MASK(led->id),
++                               MT6323_RG_ISINK_CK_PDN(led->id));
++      if (ret < 0)
++              return ret;
++
++      return 0;
++}
++
++static enum led_brightness
++mt6323_get_led_hw_brightness(struct led_classdev *cdev)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      unsigned int status;
++      int ret;
++
++      ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status);
++      if (ret < 0)
++              return ret;
++
++      if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id))
++              return 0;
++
++      ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status);
++      if (ret < 0)
++              return ret;
++
++      if (!(status & MT6323_ISINK_CH_EN(led->id)))
++              return 0;
++
++      ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status);
++      if (ret < 0)
++              return ret;
++
++      return  ((status & MT6323_ISINK_CH_STEP_MASK)
++                >> MT6323_ISINK_CH_STEP_SHIFT) + 1;
++}
++
++static int mt6323_led_hw_on(struct led_classdev *cdev,
++                          enum led_brightness brightness)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      unsigned int status;
++      int ret;
++
++      /*
++       * Setup required clock source, enable the corresponding
++       * clock and channel and let work with continuous blink as
++       * the default.
++       */
++      ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1,
++                               MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0);
++      if (ret < 0)
++              return ret;
++
++      status = MT6323_RG_ISINK_CK_PDN(led->id);
++      ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
++                               MT6323_RG_ISINK_CK_PDN_MASK(led->id),
++                               ~status);
++      if (ret < 0)
++              return ret;
++
++      usleep_range(100, 300);
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
++                               MT6323_ISINK_CH_EN_MASK(led->id),
++                               MT6323_ISINK_CH_EN(led->id));
++      if (ret < 0)
++              return ret;
++
++      ret = mt6323_led_hw_brightness(cdev, brightness);
++      if (ret < 0)
++              return ret;
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
++                               MT6323_ISINK_DIM_DUTY_MASK,
++                               MT6323_ISINK_DIM_DUTY(31));
++      if (ret < 0)
++              return ret;
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
++                               MT6323_ISINK_DIM_FSEL_MASK,
++                               MT6323_ISINK_DIM_FSEL(1000));
++      if (ret < 0)
++              return ret;
++
++      return 0;
++}
++
++static int mt6323_led_set_blink(struct led_classdev *cdev,
++                              unsigned long *delay_on,
++                              unsigned long *delay_off)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      unsigned long period;
++      u8 duty_hw;
++      int ret;
++
++      /*
++       * Units are in ms, if over the hardware able
++       * to support, fallback into software blink
++       */
++      period = *delay_on + *delay_off;
++
++      if (period > MT6323_MAX_PERIOD)
++              return -EINVAL;
++
++      /*
++       * LED subsystem requires a default user
++       * friendly blink pattern for the LED so using
++       * 1Hz duty cycle 50% here if without specific
++       * value delay_on and delay off being assigned.
++       */
++      if (!*delay_on && !*delay_off) {
++              *delay_on = 500;
++              *delay_off = 500;
++      }
++
++      /*
++       * Calculate duty_hw based on the percentage of period during
++       * which the led is ON.
++       */
++      duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period);
++
++      /* hardware doesn't support zero duty cycle. */
++      if (!duty_hw)
++              return -EINVAL;
++
++      mutex_lock(&leds->lock);
++      /*
++       * Set max_brightness as the software blink behavior
++       * when no blink brightness.
++       */
++      if (!led->current_brightness) {
++              ret = mt6323_led_hw_on(cdev, cdev->max_brightness);
++              if (ret < 0)
++                      goto out;
++              led->current_brightness = cdev->max_brightness;
++      }
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
++                               MT6323_ISINK_DIM_DUTY_MASK,
++                               MT6323_ISINK_DIM_DUTY(duty_hw - 1));
++      if (ret < 0)
++              goto out;
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
++                               MT6323_ISINK_DIM_FSEL_MASK,
++                               MT6323_ISINK_DIM_FSEL(period - 1));
++out:
++      mutex_unlock(&leds->lock);
++
++      return ret;
++}
++
++static int mt6323_led_set_brightness(struct led_classdev *cdev,
++                                   enum led_brightness brightness)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      int ret;
++
++      mutex_lock(&leds->lock);
++
++      if (!led->current_brightness && brightness) {
++              ret = mt6323_led_hw_on(cdev, brightness);
++              if (ret < 0)
++                      goto out;
++      } else if (brightness) {
++              ret = mt6323_led_hw_brightness(cdev, brightness);
++              if (ret < 0)
++                      goto out;
++      } else {
++              ret = mt6323_led_hw_off(cdev);
++              if (ret < 0)
++                      goto out;
++      }
++
++      led->current_brightness = brightness;
++out:
++      mutex_unlock(&leds->lock);
++
++      return ret;
++}
++
++static int mt6323_led_set_dt_default(struct led_classdev *cdev,
++                                   struct device_node *np)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      const char *state;
++      int ret = 0;
++
++      led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
++      led->cdev.default_trigger = of_get_property(np,
++                                                  "linux,default-trigger",
++                                                  NULL);
++
++      state = of_get_property(np, "default-state", NULL);
++      if (state) {
++              if (!strcmp(state, "keep")) {
++                      ret = mt6323_get_led_hw_brightness(cdev);
++                      if (ret < 0)
++                              return ret;
++                      led->current_brightness = ret;
++                      ret = 0;
++              } else if (!strcmp(state, "on")) {
++                      ret =
++                      mt6323_led_set_brightness(cdev, cdev->max_brightness);
++              } else  {
++                      ret = mt6323_led_set_brightness(cdev, LED_OFF);
++              }
++      }
++
++      return ret;
++}
++
++static int mt6323_led_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct device_node *np = pdev->dev.of_node;
++      struct device_node *child;
++      struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent);
++      struct mt6323_leds *leds;
++      struct mt6323_led *led;
++      int ret;
++      unsigned int status;
++      u32 reg;
++
++      leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
++      if (!leds)
++              return -ENOMEM;
++
++      platform_set_drvdata(pdev, leds);
++      leds->dev = dev;
++
++      /*
++       * leds->hw points to the underlying bus for the register
++       * controlled.
++       */
++      leds->hw = hw;
++      mutex_init(&leds->lock);
++
++      status = MT6323_RG_DRV_32K_CK_PDN;
++      ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
++                               MT6323_RG_DRV_32K_CK_PDN_MASK, ~status);
++      if (ret < 0) {
++              dev_err(leds->dev,
++                      "Failed to update MT6323_TOP_CKPDN0 Register\n");
++              return ret;
++      }
++
++      for_each_available_child_of_node(np, child) {
++              ret = of_property_read_u32(child, "reg", &reg);
++              if (ret) {
++                      dev_err(dev, "Failed to read led 'reg' property\n");
++                      goto put_child_node;
++              }
++
++              if (reg < 0 || reg > MT6323_MAX_LEDS || leds->led[reg]) {
++                      dev_err(dev, "Invalid led reg %u\n", reg);
++                      ret = -EINVAL;
++                      goto put_child_node;
++              }
++
++              led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
++              if (!led) {
++                      ret = -ENOMEM;
++                      goto put_child_node;
++              }
++
++              leds->led[reg] = led;
++              leds->led[reg]->id = reg;
++              leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS;
++              leds->led[reg]->cdev.brightness_set_blocking =
++                                      mt6323_led_set_brightness;
++              leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
++              leds->led[reg]->cdev.brightness_get =
++                                      mt6323_get_led_hw_brightness;
++              leds->led[reg]->parent = leds;
++
++              ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child);
++              if (ret < 0) {
++                      dev_err(leds->dev,
++                              "Failed to LED set default from devicetree\n");
++                      goto put_child_node;
++              }
++
++              ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev);
++              if (ret) {
++                      dev_err(&pdev->dev, "Failed to register LED: %d\n",
++                              ret);
++                      goto put_child_node;
++              }
++              leds->led[reg]->cdev.dev->of_node = child;
++      }
++
++      return 0;
++
++put_child_node:
++      of_node_put(child);
++      return ret;
++}
++
++static int mt6323_led_remove(struct platform_device *pdev)
++{
++      struct mt6323_leds *leds = platform_get_drvdata(pdev);
++      int i;
++
++      /* Turn the LEDs off on driver removal. */
++      for (i = 0 ; leds->led[i] ; i++)
++              mt6323_led_hw_off(&leds->led[i]->cdev);
++
++      regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
++                         MT6323_RG_DRV_32K_CK_PDN_MASK,
++                         MT6323_RG_DRV_32K_CK_PDN);
++
++      mutex_destroy(&leds->lock);
++
++      return 0;
++}
++
++static const struct of_device_id mt6323_led_dt_match[] = {
++      { .compatible = "mediatek,mt6323-led" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);
++
++static struct platform_driver mt6323_led_driver = {
++      .probe          = mt6323_led_probe,
++      .remove         = mt6323_led_remove,
++      .driver         = {
++              .name   = "mt6323-led",
++              .of_match_table = mt6323_led_dt_match,
++      },
++};
++
++module_platform_driver(mt6323_led_driver);
++
++MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC");
++MODULE_AUTHOR("Sean Wang <sean.wang@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 (file)
index 0000000..701dcec
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9633079
+Message-Id: <1489992447-13007-5-git-send-email-sean.wang@mediatek.com>
+To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
+ <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
+ <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
+ Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
+ linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
+ linux-arm-kernel@lists.infradead.org
+Date: Mon, 20 Mar 2017 14:47:27 +0800
+
+From: Sean Wang <sean.wang@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@mediatek.com>
+Acked-by: Lee Jones <lee.jones@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 (file)
index 0000000..c9bad93
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9651093
+Message-Id: <1490780303-18598-2-git-send-email-sean.wang@mediatek.com>
+To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
+ <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
+ <robh+dt@kernel.org>, <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
+ netdev@vger.kernel.org, sean.wang@mediatek.com,
+ linux-kernel@vger.kernel.org, 
+ linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
+Date: Wed, 29 Mar 2017 17:38:19 +0800
+
+From: Sean Wang <sean.wang@mediatek.com>
+
+Add device-tree binding for Mediatek MT7530 switch.
+
+Cc: devicetree@vger.kernel.org
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+Acked-by: Rob Herring <robh@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@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@0 {
++                                      reg = <0>;
++                                      label = "lan0";
++                              };
++
++                              port@1 {
++                                      reg = <1>;
++                                      label = "lan1";
++                              };
++
++                              port@2 {
++                                      reg = <2>;
++                                      label = "lan2";
++                              };
++
++                              port@3 {
++                                      reg = <3>;
++                                      label = "lan3";
++                              };
++
++                              port@4 {
++                                      reg = <4>;
++                                      label = "wan";
++                              };
++
++                              port@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 (file)
index 0000000..5ae90e3
--- /dev/null
@@ -0,0 +1,95 @@
+From 81cdbda2a08375b9d5915567d2210bf2433e7332 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@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@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 (file)
index 0000000..84e5cb4
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9651099
+Message-Id: <1490780303-18598-3-git-send-email-sean.wang@mediatek.com>
+To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
+ <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
+ <robh+dt@kernel.org>, <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
+ netdev@vger.kernel.org, sean.wang@mediatek.com,
+ linux-kernel@vger.kernel.org, 
+ linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
+Date: Wed, 29 Mar 2017 17:38:20 +0800
+
+From: Sean Wang <sean.wang@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@mediatek.com>
+Signed-off-by: Landen Chao <Landen.Chao@mediatek.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@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@mediatek.com>
++ *                  Sean Wang <sean.wang@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 (file)
index 0000000..7c4dc4f
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9651091
+Message-Id: <1490780303-18598-4-git-send-email-sean.wang@mediatek.com>
+To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
+ <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
+ <robh+dt@kernel.org>, <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
+ netdev@vger.kernel.org, sean.wang@mediatek.com,
+ linux-kernel@vger.kernel.org, 
+ linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
+Date: Wed, 29 Mar 2017 17:38:21 +0800
+
+From: Sean Wang <sean.wang@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@mediatek.com>
+Signed-off-by: Landen Chao <Landen.Chao@mediatek.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@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 (file)
index 0000000..d67b4a9
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9651097
+Message-Id: <1490780303-18598-5-git-send-email-sean.wang@mediatek.com>
+To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
+ <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
+ <robh+dt@kernel.org>, <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
+ netdev@vger.kernel.org, sean.wang@mediatek.com,
+ linux-kernel@vger.kernel.org, 
+ linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
+Date: Wed, 29 Mar 2017 17:38:22 +0800
+
+From: Sean Wang <sean.wang@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@mediatek.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@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 (file)
index 0000000..6c10137
--- /dev/null
@@ -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@mediatek.com
+X-Patchwork-Id: 9651095
+Message-Id: <1490780303-18598-6-git-send-email-sean.wang@mediatek.com>
+To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
+ <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
+ <robh+dt@kernel.org>, <mark.rutland@arm.com>
+Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
+ netdev@vger.kernel.org, sean.wang@mediatek.com,
+ linux-kernel@vger.kernel.org, 
+ linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
+Date: Wed, 29 Mar 2017 17:38:23 +0800
+
+From: Sean Wang <sean.wang@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@mediatek.com>
+Signed-off-by: Landen Chao <Landen.Chao@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@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@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@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 (file)
index 0000000..ca36d4c
--- /dev/null
@@ -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 (file)
index 0000000..8e51bdd
--- /dev/null
@@ -0,0 +1,40 @@
+Index: linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+===================================================================
+--- linux-4.9.17.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -2459,15 +2459,23 @@ static int mtk_probe(struct platform_dev
+                       goto err_deinit_hw;
+       }
++      for (i = 0; i < 3; i++) {
++              int cpu = i % num_online_cpus();
++
++              cpumask_set_cpu(cpu, &eth->affinity_mask[i]);
++      }
++
+       err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
+                              dev_name(eth->dev), eth);
+       if (err)
+               goto err_free_dev;
++      irq_set_affinity_hint(eth->irq[1], &eth->affinity_mask[1]);
+       err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
+                              dev_name(eth->dev), eth);
+       if (err)
+               goto err_free_dev;
++      irq_set_affinity_hint(eth->irq[2], &eth->affinity_mask[2]);
+       err = mtk_mdio_init(eth);
+       if (err)
+Index: linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+===================================================================
+--- linux-4.9.17.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -539,6 +539,7 @@ struct mtk_eth {
+       struct net_device               *netdev[MTK_MAX_DEVS];
+       struct mtk_mac                  *mac[MTK_MAX_DEVS];
+       int                             irq[3];
++      cpumask_t                       affinity_mask[3];
+       u32                             msg_enable;
+       unsigned long                   sysclk;
+       struct regmap                   *ethsys;
diff --git a/target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch b/target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch
deleted file mode 100644 (file)
index d351192..0000000
+++ /dev/null
@@ -1,2322 +0,0 @@
-From 6b8a7257e7bcb56782c3f8048311670fe6a80209 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@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@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@openwrt.org>
-+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@nbd.name>
-+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@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@openwrt.org>
-+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@nbd.name>
-+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@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@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@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@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 */
index c713ba0..2ef570b 100644 (file)
@@ -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