uboot-mediatek: backport mtk_eth fixes from u-boot next
authorShiji Yang <yangshiji66@qq.com>
Thu, 9 Jan 2025 10:10:28 +0000 (18:10 +0800)
committerDaniel Golle <daniel@makrotopia.org>
Sun, 9 Feb 2025 21:50:58 +0000 (21:50 +0000)
This patch series will provide better support for Mediatek
ethernet and add support for Airoha AN8855.

Signed-off-by: Shiji Yang <yangshiji66@qq.com>
13 files changed:
package/boot/uboot-mediatek/patches/060-01-clk-mediatek-mt7629-fix-parent-clock-of-some-top-clo.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/060-02-arm-dts-mt7629-fix-sgmii-clock-selection-for-etherne.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/060-03-net-mediatek-use-correct-register-field-for-SGMII-sp.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/060-04-net-mediatek-correct-register-name-of-ethsys-syscfg1.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/060-05-net-mediatek-fix-sgmii-selection-for-mt7622.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/060-06-net-mediatek-fix-gmac2-usability-for-mt7629.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/060-07-net-mediatek-add-support-for-10GBASE-R.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/060-08-net-mediatek-make-sgmii-usxgmii-optional.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/060-09-net-mediatek-don-t-enable-GDMA-cpu-bridge-unconditio.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/060-10-net-mediatek-fix-usability-with-wget-command.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/061-01-net-mediatek-split-ethernet-switch-code-from-mtk_eth.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/061-02-net-mediatek-add-support-for-MediaTek-MT7987-SoC.patch [new file with mode: 0644]
package/boot/uboot-mediatek/patches/061-03-net-mediatek-add-support-for-Airoha-AN8855-ethernet-.patch [new file with mode: 0644]

diff --git a/package/boot/uboot-mediatek/patches/060-01-clk-mediatek-mt7629-fix-parent-clock-of-some-top-clo.patch b/package/boot/uboot-mediatek/patches/060-01-clk-mediatek-mt7629-fix-parent-clock-of-some-top-clo.patch
new file mode 100644 (file)
index 0000000..387cf90
--- /dev/null
@@ -0,0 +1,45 @@
+From 6e45549f4dac42748d66462e04f940ef6737289d Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:39:16 +0800
+Subject: [PATCH 01/10] clk: mediatek: mt7629: fix parent clock of some top
+ clock muxes
+
+According to the mt7629 programming guide, the CLK_TOP_F10M_REF_SEL
+shares the same parent selection with CLK_TOP_IRRX_SEL, while the
+present parent selection for CLK_TOP_F10M_REF_SEL is actually used
+for CLK_TOP_SGMII_REF_1_SEL.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/clk/mediatek/clk-mt7629.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt7629.c
++++ b/drivers/clk/mediatek/clk-mt7629.c
+@@ -186,7 +186,7 @@ static const int pwm_parents[] = {
+       CLK_TOP_UNIVPLL2_D4
+ };
+-static const int f10m_ref_parents[] = {
++static const int sgmii_ref_1_parents[] = {
+       CLK_XTAL,
+       CLK_TOP_SGMIIPLL_D2
+ };
+@@ -369,7 +369,7 @@ static const struct mtk_composite top_mu
+       /* CLK_CFG_1 */
+       MUX_GATE(CLK_TOP_PWM_SEL, pwm_parents, 0x50, 0, 2, 7),
+-      MUX_GATE(CLK_TOP_F10M_REF_SEL, f10m_ref_parents, 0x50, 8, 1, 15),
++      MUX_GATE(CLK_TOP_F10M_REF_SEL, irrx_parents, 0x50, 8, 1, 15),
+       MUX_GATE(CLK_TOP_NFI_INFRA_SEL, nfi_infra_parents, 0x50, 16, 4, 23),
+       MUX_GATE(CLK_TOP_FLASH_SEL, flash_parents, 0x50, 24, 3, 31),
+@@ -412,7 +412,7 @@ static const struct mtk_composite top_mu
+       /* CLK_CFG_8 */
+       MUX_GATE(CLK_TOP_CRYPTO_SEL, crypto_parents, 0xC0, 0, 3, 7),
+-      MUX_GATE(CLK_TOP_SGMII_REF_1_SEL, f10m_ref_parents, 0xC0, 8, 1, 15),
++      MUX_GATE(CLK_TOP_SGMII_REF_1_SEL, sgmii_ref_1_parents, 0xC0, 8, 1, 15),
+       MUX_GATE(CLK_TOP_10M_SEL, gpt10m_parents, 0xC0, 16, 1, 23),
+ };
diff --git a/package/boot/uboot-mediatek/patches/060-02-arm-dts-mt7629-fix-sgmii-clock-selection-for-etherne.patch b/package/boot/uboot-mediatek/patches/060-02-arm-dts-mt7629-fix-sgmii-clock-selection-for-etherne.patch
new file mode 100644 (file)
index 0000000..c96490e
--- /dev/null
@@ -0,0 +1,28 @@
+From ba365c3d23411620d86b5baf621c8f5a4000ab33 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:39:20 +0800
+Subject: [PATCH 02/10] arm: dts: mt7629: fix sgmii clock selection for
+ ethernet
+
+Setup correct parent of clock CLK_TOP_SGMII_REF_1_SEL to allow
+sgmiisys1 work correctly.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ arch/arm/dts/mt7629.dtsi | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/dts/mt7629.dtsi
++++ b/arch/arm/dts/mt7629.dtsi
+@@ -314,8 +314,10 @@
+                               "sgmii2_cdr_ref", "sgmii2_cdr_fb",
+                               "sgmii_ck", "eth2pll";
+               assigned-clocks = <&topckgen CLK_TOP_ETH_SEL>,
+-                                <&topckgen CLK_TOP_F10M_REF_SEL>;
++                                <&topckgen CLK_TOP_F10M_REF_SEL>,
++                                <&topckgen CLK_TOP_SGMII_REF_1_SEL>;
+               assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>,
++                                       <&topckgen CLK_TOP_SYSPLL4_D16>,
+                                        <&topckgen CLK_TOP_SGMIIPLL_D2>;
+               power-domains = <&scpsys MT7629_POWER_DOMAIN_ETHSYS>;
+               resets = <&ethsys ETHSYS_FE_RST>;
diff --git a/package/boot/uboot-mediatek/patches/060-03-net-mediatek-use-correct-register-field-for-SGMII-sp.patch b/package/boot/uboot-mediatek/patches/060-03-net-mediatek-use-correct-register-field-for-SGMII-sp.patch
new file mode 100644 (file)
index 0000000..ba3fbf6
--- /dev/null
@@ -0,0 +1,64 @@
+From 0d4d8e6f47ef22ea6b3041b4c0cb27b4ed4bf188 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:39:23 +0800
+Subject: [PATCH 03/10] net: mediatek: use correct register field for SGMII
+ speed selection
+
+The register field for SGMII speed selection is a 2-bit field with
+value 0 for 1Gbps and 1 for 2.5Gbps (2/3 are reserved).
+So it's necessary to set both bits instead of just setting/clearing
+only the lower bit.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 12 ++++++------
+ drivers/net/mtk_eth.h |  3 ++-
+ 2 files changed, 8 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -835,8 +835,8 @@ static int mt7531_port_sgmii_init(struct
+       }
+       /* Set SGMII GEN2 speed(2.5G) */
+-      mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port),
+-                     SGMSYS_SPEED_2500, SGMSYS_SPEED_2500);
++      mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK,
++                     FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
+       /* Disable SGMII AN */
+       mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port),
+@@ -1281,8 +1281,7 @@ static int mtk_phy_probe(struct udevice
+ static void mtk_sgmii_an_init(struct mtk_eth_priv *priv)
+ {
+       /* Set SGMII GEN1 speed(1G) */
+-      clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
+-                      SGMSYS_SPEED_2500, 0);
++      clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK);
+       /* Enable SGMII AN */
+       setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
+@@ -1305,8 +1304,9 @@ static void mtk_sgmii_an_init(struct mtk
+ static void mtk_sgmii_force_init(struct mtk_eth_priv *priv)
+ {
+       /* Set SGMII GEN2 speed(2.5G) */
+-      setbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
+-                   SGMSYS_SPEED_2500);
++      clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
++                      SGMSYS_SPEED_MASK,
++                      FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
+       /* Disable SGMII AN */
+       clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
+--- a/drivers/net/mtk_eth.h
++++ b/drivers/net/mtk_eth.h
+@@ -108,7 +108,8 @@ enum mkt_eth_capabilities {
+ #define SGMSYS_GEN2_SPEED             0x2028
+ #define SGMSYS_GEN2_SPEED_V2          0x128
+-#define SGMSYS_SPEED_2500             BIT(2)
++#define SGMSYS_SPEED_MASK             GENMASK(3, 2)
++#define SGMSYS_SPEED_2500             1
+ /* USXGMII subsystem config registers */
+ /* Register to control USXGMII XFI PLL digital */
diff --git a/package/boot/uboot-mediatek/patches/060-04-net-mediatek-correct-register-name-of-ethsys-syscfg1.patch b/package/boot/uboot-mediatek/patches/060-04-net-mediatek-correct-register-name-of-ethsys-syscfg1.patch
new file mode 100644 (file)
index 0000000..8c549e7
--- /dev/null
@@ -0,0 +1,78 @@
+From 7562da9454c1a6eff3db3b41c183e03039e855e6 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:39:27 +0800
+Subject: [PATCH 04/10] net: mediatek: correct register name of ethsys syscfg1
+
+The SYSCFG0 should be SYSCFG1 according to the programming guide.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 14 +++++++-------
+ drivers/net/mtk_eth.h | 12 ++++++------
+ 2 files changed, 13 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -1450,8 +1450,8 @@ static void mtk_mac_init(struct mtk_eth_
+               }
+               ge_mode = GE_MODE_RGMII;
+-              mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG, SYSCFG0_SGMII_SEL_M,
+-                             SYSCFG0_SGMII_SEL(priv->gmac_id));
++              mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, SYSCFG1_SGMII_SEL_M,
++                             SYSCFG1_SGMII_SEL(priv->gmac_id));
+               if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
+                       mtk_sgmii_an_init(priv);
+               else
+@@ -1469,9 +1469,9 @@ static void mtk_mac_init(struct mtk_eth_
+       }
+       /* set the gmac to the right mode */
+-      mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG,
+-                     SYSCFG0_GE_MODE_M << SYSCFG0_GE_MODE_S(priv->gmac_id),
+-                     ge_mode << SYSCFG0_GE_MODE_S(priv->gmac_id));
++      mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
++                     SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
++                     ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id));
+       if (priv->force_mode) {
+               mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+@@ -1527,8 +1527,8 @@ static void mtk_xmac_init(struct mtk_eth
+       }
+       /* Set GMAC to the correct mode */
+-      mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG,
+-                     SYSCFG0_GE_MODE_M << SYSCFG0_GE_MODE_S(priv->gmac_id),
++      mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
++                     SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
+                      0);
+       if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII &&
+--- a/drivers/net/mtk_eth.h
++++ b/drivers/net/mtk_eth.h
+@@ -65,11 +65,11 @@ enum mkt_eth_capabilities {
+ /* Ethernet subsystem registers */
+-#define ETHSYS_SYSCFG0_REG            0x14
+-#define SYSCFG0_GE_MODE_S(n)          (12 + ((n) * 2))
+-#define SYSCFG0_GE_MODE_M             0x3
+-#define SYSCFG0_SGMII_SEL_M           (0x3 << 8)
+-#define SYSCFG0_SGMII_SEL(gmac)               ((!(gmac)) ? BIT(9) : BIT(8))
++#define ETHSYS_SYSCFG1_REG            0x14
++#define SYSCFG1_GE_MODE_S(n)          (12 + ((n) * 2))
++#define SYSCFG1_GE_MODE_M             0x3
++#define SYSCFG1_SGMII_SEL_M           (0x3 << 8)
++#define SYSCFG1_SGMII_SEL(gmac)               ((!(gmac)) ? BIT(9) : BIT(8))
+ #define ETHSYS_CLKCFG0_REG            0x2c
+ #define ETHSYS_TRGMII_CLK_SEL362_5    BIT(11)
+@@ -84,7 +84,7 @@ enum mkt_eth_capabilities {
+ #define QPHY_SEL_MASK                 0x3
+ #define SGMII_QPHY_SEL                        0x2
+-/* SYSCFG0_GE_MODE: GE Modes */
++/* SYSCFG1_GE_MODE: GE Modes */
+ #define GE_MODE_RGMII                 0
+ #define GE_MODE_MII                   1
+ #define GE_MODE_MII_PHY                       2
diff --git a/package/boot/uboot-mediatek/patches/060-05-net-mediatek-fix-sgmii-selection-for-mt7622.patch b/package/boot/uboot-mediatek/patches/060-05-net-mediatek-fix-sgmii-selection-for-mt7622.patch
new file mode 100644 (file)
index 0000000..a45e878
--- /dev/null
@@ -0,0 +1,90 @@
+From 82f05bc48821f3709f22f3d1f6e45290547f74be Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:39:41 +0800
+Subject: [PATCH 05/10] net: mediatek: fix sgmii selection for mt7622
+
+Unlike other platforms, mt7622 has only one SGMII and it can be
+attached to either gmac1 or gmac2. So the register field of the
+sgmii selection differs from other platforms as newer platforms can
+control each sgmii individually.
+
+This patch adds a new capability for mt7622 to handle this case.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 10 ++++++++--
+ drivers/net/mtk_eth.h |  8 ++++++--
+ 2 files changed, 14 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -1434,7 +1434,7 @@ static void mtk_usxgmii_an_init(struct m
+ static void mtk_mac_init(struct mtk_eth_priv *priv)
+ {
+-      int i, ge_mode = 0;
++      int i, sgmii_sel_mask = 0, ge_mode = 0;
+       u32 mcr;
+       switch (priv->phy_interface) {
+@@ -1450,8 +1450,13 @@ static void mtk_mac_init(struct mtk_eth_
+               }
+               ge_mode = GE_MODE_RGMII;
+-              mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, SYSCFG1_SGMII_SEL_M,
++
++              if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII))
++                      sgmii_sel_mask = SYSCFG1_SGMII_SEL_M;
++
++              mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask,
+                              SYSCFG1_SGMII_SEL(priv->gmac_id));
++
+               if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
+                       mtk_sgmii_an_init(priv);
+               else
+@@ -2112,6 +2117,7 @@ static const struct mtk_soc_data mt7623_
+ };
+ static const struct mtk_soc_data mt7622_data = {
++      .caps = MT7622_CAPS,
+       .ana_rgc3 = 0x2028,
+       .gdma_count = 2,
+       .pdma_base = PDMA_V1_BASE,
+--- a/drivers/net/mtk_eth.h
++++ b/drivers/net/mtk_eth.h
+@@ -23,6 +23,7 @@ enum mkt_eth_capabilities {
+       /* PATH BITS */
+       MTK_ETH_PATH_GMAC1_TRGMII_BIT,
+       MTK_ETH_PATH_GMAC2_SGMII_BIT,
++      MTK_ETH_PATH_MT7622_SGMII_BIT,
+ };
+ #define MTK_TRGMII                    BIT(MTK_TRGMII_BIT)
+@@ -36,6 +37,7 @@ enum mkt_eth_capabilities {
+ #define MTK_ETH_PATH_GMAC1_TRGMII     BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
+ #define MTK_ETH_PATH_GMAC2_SGMII      BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
++#define MTK_ETH_PATH_MT7622_SGMII     BIT(MTK_ETH_PATH_MT7622_SGMII_BIT)
+ #define MTK_GMAC1_TRGMII      (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
+@@ -45,6 +47,8 @@ enum mkt_eth_capabilities {
+ #define MT7621_CAPS  (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK)
++#define MT7622_CAPS  (MTK_ETH_PATH_MT7622_SGMII)
++
+ #define MT7623_CAPS  (MTK_GMAC1_TRGMII)
+ #define MT7981_CAPS  (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2)
+@@ -68,8 +72,8 @@ enum mkt_eth_capabilities {
+ #define ETHSYS_SYSCFG1_REG            0x14
+ #define SYSCFG1_GE_MODE_S(n)          (12 + ((n) * 2))
+ #define SYSCFG1_GE_MODE_M             0x3
+-#define SYSCFG1_SGMII_SEL_M           (0x3 << 8)
+-#define SYSCFG1_SGMII_SEL(gmac)               ((!(gmac)) ? BIT(9) : BIT(8))
++#define SYSCFG1_SGMII_SEL_M           GENMASK(9, 8)
++#define SYSCFG1_SGMII_SEL(gmac)               BIT(9 - (gmac))
+ #define ETHSYS_CLKCFG0_REG            0x2c
+ #define ETHSYS_TRGMII_CLK_SEL362_5    BIT(11)
diff --git a/package/boot/uboot-mediatek/patches/060-06-net-mediatek-fix-gmac2-usability-for-mt7629.patch b/package/boot/uboot-mediatek/patches/060-06-net-mediatek-fix-gmac2-usability-for-mt7629.patch
new file mode 100644 (file)
index 0000000..5bc6e70
--- /dev/null
@@ -0,0 +1,73 @@
+From d8d7e566545f836dd49611cafbf44eef56434e08 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:39:46 +0800
+Subject: [PATCH 06/10] net: mediatek: fix gmac2 usability for mt7629
+
+MT7629 need extra setting for gmac2 to work. So additional
+capability is added for mt7629 to handle this case.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 6 ++++++
+ drivers/net/mtk_eth.h | 7 +++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -1437,6 +1437,11 @@ static void mtk_mac_init(struct mtk_eth_
+       int i, sgmii_sel_mask = 0, ge_mode = 0;
+       u32 mcr;
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) {
++              mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG,
++                            INFRA_MISC2_BONDING_OPTION, priv->gmac_id);
++      }
++
+       switch (priv->phy_interface) {
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+       case PHY_INTERFACE_MODE_RGMII:
+@@ -2101,6 +2106,7 @@ static const struct mtk_soc_data mt7981_
+ };
+ static const struct mtk_soc_data mt7629_data = {
++      .caps = MT7629_CAPS,
+       .ana_rgc3 = 0x128,
+       .gdma_count = 2,
+       .pdma_base = PDMA_V1_BASE,
+--- a/drivers/net/mtk_eth.h
++++ b/drivers/net/mtk_eth.h
+@@ -24,6 +24,7 @@ enum mkt_eth_capabilities {
+       MTK_ETH_PATH_GMAC1_TRGMII_BIT,
+       MTK_ETH_PATH_GMAC2_SGMII_BIT,
+       MTK_ETH_PATH_MT7622_SGMII_BIT,
++      MTK_ETH_PATH_MT7629_GMAC2_BIT,
+ };
+ #define MTK_TRGMII                    BIT(MTK_TRGMII_BIT)
+@@ -38,6 +39,7 @@ enum mkt_eth_capabilities {
+ #define MTK_ETH_PATH_GMAC2_SGMII      BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
+ #define MTK_ETH_PATH_MT7622_SGMII     BIT(MTK_ETH_PATH_MT7622_SGMII_BIT)
++#define MTK_ETH_PATH_MT7629_GMAC2     BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT)
+ #define MTK_GMAC1_TRGMII      (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
+@@ -51,6 +53,8 @@ enum mkt_eth_capabilities {
+ #define MT7623_CAPS  (MTK_GMAC1_TRGMII)
++#define MT7629_CAPS  (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA)
++
+ #define MT7981_CAPS  (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2)
+ #define MT7986_CAPS  (MTK_NETSYS_V2)
+@@ -88,6 +92,9 @@ enum mkt_eth_capabilities {
+ #define QPHY_SEL_MASK                 0x3
+ #define SGMII_QPHY_SEL                        0x2
++#define MT7629_INFRA_MISC2_REG                0x70c
++#define INFRA_MISC2_BONDING_OPTION    GENMASK(15, 0)
++
+ /* SYSCFG1_GE_MODE: GE Modes */
+ #define GE_MODE_RGMII                 0
+ #define GE_MODE_MII                   1
diff --git a/package/boot/uboot-mediatek/patches/060-07-net-mediatek-add-support-for-10GBASE-R.patch b/package/boot/uboot-mediatek/patches/060-07-net-mediatek-add-support-for-10GBASE-R.patch
new file mode 100644 (file)
index 0000000..f7a63a5
--- /dev/null
@@ -0,0 +1,147 @@
+From ad0c47109e4c9f6297aa247d8bbf7131438bc435 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:39:50 +0800
+Subject: [PATCH 07/10] net: mediatek: add support for 10GBASE-R
+
+This patch adds support for 10GBASE-R interface mode
+
+Signed-off-by: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 83 +++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 81 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -1246,6 +1246,7 @@ static int mtk_phy_start(struct mtk_eth_
+       if (!priv->force_mode) {
+               if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++                  priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
+                   priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
+                       mtk_xphy_link_adjust(priv);
+               else
+@@ -1425,6 +1426,71 @@ static void mtk_usxgmii_setup_phya_an_10
+       udelay(400);
+ }
++static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv)
++{
++      regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C);
++      regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
++      regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000);
++      ndelay(1020);
++      regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000);
++      ndelay(1020);
++
++      regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
++      regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
++      regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
++      regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
++      regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
++      regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
++      regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
++      regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
++      regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
++      regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
++      regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
++      regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
++      regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
++      regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
++      regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
++      regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
++      regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
++      regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
++      regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
++      regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
++      regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
++      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
++      regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
++      ndelay(1020);
++      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
++      regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
++      regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
++      regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
++      regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
++      regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
++      regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
++      regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100);
++      regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000);
++      regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000);
++      regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
++      if (priv->gmac_id == 2)
++              regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400);
++      regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
++      regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
++      udelay(150);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
++      ndelay(1020);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
++      udelay(15);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
++      ndelay(1020);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
++      udelay(100);
++      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
++      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
++      regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
++      udelay(400);
++}
++
+ static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv)
+ {
+       mtk_xfi_pll_enable(priv);
+@@ -1432,6 +1498,13 @@ static void mtk_usxgmii_an_init(struct m
+       mtk_usxgmii_setup_phya_an_10000(priv);
+ }
++static void mtk_10gbaser_init(struct mtk_eth_priv *priv)
++{
++      mtk_xfi_pll_enable(priv);
++      mtk_usxgmii_reset(priv);
++      mtk_usxgmii_setup_phya_force_10000(priv);
++}
++
+ static void mtk_mac_init(struct mtk_eth_priv *priv)
+ {
+       int i, sgmii_sel_mask = 0, ge_mode = 0;
+@@ -1532,6 +1605,9 @@ static void mtk_xmac_init(struct mtk_eth
+       case PHY_INTERFACE_MODE_USXGMII:
+               mtk_usxgmii_an_init(priv);
+               break;
++      case PHY_INTERFACE_MODE_10GBASER:
++              mtk_10gbaser_init(priv);
++              break;
+       default:
+               break;
+       }
+@@ -1541,7 +1617,8 @@ static void mtk_xmac_init(struct mtk_eth
+                      SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
+                      0);
+-      if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII &&
++      if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++           priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
+           priv->gmac_id == 1) {
+               mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX,
+                             NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL);
+@@ -1843,6 +1920,7 @@ static int mtk_eth_probe(struct udevice
+       /* Set MAC mode */
+       if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++          priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
+           priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
+               mtk_xmac_init(priv);
+       else
+@@ -1977,7 +2055,8 @@ static int mtk_eth_of_to_plat(struct ude
+               /* Upstream linux use mediatek,pnswap instead of pn_swap */
+               priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") ||
+                               ofnode_read_bool(args.node, "mediatek,pnswap");
+-      } else if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII) {
++      } else if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++                 priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) {
+               /* get corresponding usxgmii phandle */
+               ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys",
+                                                NULL, 0, 0, &args);
diff --git a/package/boot/uboot-mediatek/patches/060-08-net-mediatek-make-sgmii-usxgmii-optional.patch b/package/boot/uboot-mediatek/patches/060-08-net-mediatek-make-sgmii-usxgmii-optional.patch
new file mode 100644 (file)
index 0000000..d6a885f
--- /dev/null
@@ -0,0 +1,144 @@
+From 5ac929fd1ab1d0dc77b9167952aea7cafdb8619f Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:39:55 +0800
+Subject: [PATCH 08/10] net: mediatek: make sgmii/usxgmii optional
+
+Not all platforms supports sgmii and/or usxgmii. So we add Kconfig
+options for these features and enable them only for supported
+platforms.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/Kconfig   | 12 ++++++++++++
+ drivers/net/mtk_eth.c | 39 +++++++++++++++++++++++++++++----------
+ 2 files changed, 41 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -975,6 +975,18 @@ config MEDIATEK_ETH
+         This Driver support MediaTek Ethernet GMAC
+         Say Y to enable support for the MediaTek Ethernet GMAC.
++if MEDIATEK_ETH
++
++config MTK_ETH_SGMII
++      bool
++      default y if ARCH_MEDIATEK && !TARGET_MT7623
++
++config MTK_ETH_XGMII
++      bool
++      default y if TARGET_MT7987 || TARGET_MT7988
++
++endif # MEDIATEK_ETH
++
+ config HIFEMAC_ETH
+       bool "HiSilicon Fast Ethernet Controller"
+       select DM_CLK
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -1505,7 +1505,7 @@ static void mtk_10gbaser_init(struct mtk
+       mtk_usxgmii_setup_phya_force_10000(priv);
+ }
+-static void mtk_mac_init(struct mtk_eth_priv *priv)
++static int mtk_mac_init(struct mtk_eth_priv *priv)
+ {
+       int i, sgmii_sel_mask = 0, ge_mode = 0;
+       u32 mcr;
+@@ -1522,13 +1522,16 @@ static void mtk_mac_init(struct mtk_eth_
+               break;
+       case PHY_INTERFACE_MODE_SGMII:
+       case PHY_INTERFACE_MODE_2500BASEX:
++              if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
++                      printf("Error: SGMII is not supported on this platform\n");
++                      return -ENOTSUPP;
++              }
++
+               if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) {
+                       mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK,
+                                     SGMII_QPHY_SEL);
+               }
+-              ge_mode = GE_MODE_RGMII;
+-
+               if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII))
+                       sgmii_sel_mask = SYSCFG1_SGMII_SEL_M;
+@@ -1539,6 +1542,8 @@ static void mtk_mac_init(struct mtk_eth_
+                       mtk_sgmii_an_init(priv);
+               else
+                       mtk_sgmii_force_init(priv);
++
++              ge_mode = GE_MODE_RGMII;
+               break;
+       case PHY_INTERFACE_MODE_MII:
+       case PHY_INTERFACE_MODE_GMII:
+@@ -1595,12 +1600,19 @@ static void mtk_mac_init(struct mtk_eth_
+                            RX_RST | RXC_DQSISEL);
+               mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0);
+       }
++
++      return 0;
+ }
+-static void mtk_xmac_init(struct mtk_eth_priv *priv)
++static int mtk_xmac_init(struct mtk_eth_priv *priv)
+ {
+       u32 force_link = 0;
++      if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
++              printf("Error: 10Gb interface is not supported on this platform\n");
++              return -ENOTSUPP;
++      }
++
+       switch (priv->phy_interface) {
+       case PHY_INTERFACE_MODE_USXGMII:
+               mtk_usxgmii_an_init(priv);
+@@ -1633,6 +1645,8 @@ static void mtk_xmac_init(struct mtk_eth
+       /* Force GMAC link down */
+       mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE);
++
++      return 0;
+ }
+ static void mtk_eth_fifo_init(struct mtk_eth_priv *priv)
+@@ -1922,9 +1936,12 @@ static int mtk_eth_probe(struct udevice
+       if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+           priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
+           priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
+-              mtk_xmac_init(priv);
++              ret = mtk_xmac_init(priv);
+       else
+-              mtk_mac_init(priv);
++              ret = mtk_mac_init(priv);
++
++      if (ret)
++              return ret;
+       /* Probe phy if switch is not specified */
+       if (priv->sw == SW_NONE)
+@@ -2032,8 +2049,9 @@ static int mtk_eth_of_to_plat(struct ude
+               }
+       }
+-      if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII ||
+-          priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) {
++      if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII ||
++           priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) &&
++          IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
+               /* get corresponding sgmii phandle */
+               ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys",
+                                                NULL, 0, 0, &args);
+@@ -2055,8 +2073,9 @@ static int mtk_eth_of_to_plat(struct ude
+               /* Upstream linux use mediatek,pnswap instead of pn_swap */
+               priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") ||
+                               ofnode_read_bool(args.node, "mediatek,pnswap");
+-      } else if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+-                 priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) {
++      } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++                  priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
++                 IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
+               /* get corresponding usxgmii phandle */
+               ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys",
+                                                NULL, 0, 0, &args);
diff --git a/package/boot/uboot-mediatek/patches/060-09-net-mediatek-don-t-enable-GDMA-cpu-bridge-unconditio.patch b/package/boot/uboot-mediatek/patches/060-09-net-mediatek-don-t-enable-GDMA-cpu-bridge-unconditio.patch
new file mode 100644 (file)
index 0000000..c9ea8f4
--- /dev/null
@@ -0,0 +1,36 @@
+From b9dfb5636bc5eb9b783b88b8388dc7d1f41d6498 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:39:59 +0800
+Subject: [PATCH 09/10] net: mediatek: don't enable GDMA cpu bridge
+ unconditionally for NETSYSv3
+
+Enable GDMA cpu bridge only when 10Gb interface is enabled for GMAC other
+than GMAC0, or when MT7988 internal switch is used.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -1762,10 +1762,16 @@ static int mtk_eth_start(struct udevice
+               if (priv->sw == SW_MT7988 && priv->gmac_id == 0) {
+                       mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG,
+                                      GDMA_BRIDGE_TO_CPU);
+-              }
+-              mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
+-                             GDMA_CPU_BRIDGE_EN);
++                      mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
++                                     GDMA_CPU_BRIDGE_EN);
++              } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++                          priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
++                          priv->phy_interface == PHY_INTERFACE_MODE_XGMII) &&
++                         priv->gmac_id != 0) {
++                      mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
++                                     GDMA_CPU_BRIDGE_EN);
++              }
+       }
+       udelay(500);
diff --git a/package/boot/uboot-mediatek/patches/060-10-net-mediatek-fix-usability-with-wget-command.patch b/package/boot/uboot-mediatek/patches/060-10-net-mediatek-fix-usability-with-wget-command.patch
new file mode 100644 (file)
index 0000000..a20d790
--- /dev/null
@@ -0,0 +1,37 @@
+From c949686e558e00cbb8c38f7c060701006d70cea8 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 17 Dec 2024 16:40:03 +0800
+Subject: [PATCH 10/10] net: mediatek: fix usability with wget command
+
+The wget command currently cannot work correctly with mtk_eth driver.
+This patch fixed this by increase DMA ring size and invalidate ring data
+after use.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/mtk_eth.c
++++ b/drivers/net/mtk_eth.c
+@@ -29,8 +29,8 @@
+ #include "mtk_eth.h"
+-#define NUM_TX_DESC           24
+-#define NUM_RX_DESC           24
++#define NUM_TX_DESC           32
++#define NUM_RX_DESC           32
+ #define TX_TOTAL_BUF_SIZE     (NUM_TX_DESC * PKTSIZE_ALIGN)
+ #define RX_TOTAL_BUF_SIZE     (NUM_RX_DESC * PKTSIZE_ALIGN)
+ #define TOTAL_PKT_BUF_SIZE    (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE)
+@@ -1897,6 +1897,9 @@ static int mtk_eth_free_pkt(struct udevi
+       rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
++      invalidate_dcache_range((ulong)rxd->rxd1,
++                              (ulong)rxd->rxd1 + PKTSIZE_ALIGN);
++
+       if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+           MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+               rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
diff --git a/package/boot/uboot-mediatek/patches/061-01-net-mediatek-split-ethernet-switch-code-from-mtk_eth.patch b/package/boot/uboot-mediatek/patches/061-01-net-mediatek-split-ethernet-switch-code-from-mtk_eth.patch
new file mode 100644 (file)
index 0000000..b212c6c
--- /dev/null
@@ -0,0 +1,6311 @@
+From 626cdca5b68acdc72d2533e2ed2306c06f296725 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 10 Jan 2025 16:41:13 +0800
+Subject: [PATCH 1/3] net: mediatek: split ethernet switch code from mtk_eth.c
+
+mtk_eth.c contains not only the ethernet GMAC/DMA driver, but also
+some ethernet switch initialization code. As we may add more switch
+support in the future, it's better to move them out of mtk_eth.c to
+avoid increasing the code complexity.
+
+Since not all switches are supported for a particular board, Kconfig
+options are added to allow user to select which switch should be
+built into u-boot. If multiple switches are selected, auto-detecting
+can also be enabled.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/Kconfig                 |  21 +-
+ drivers/net/Makefile                |   2 +-
+ drivers/net/mtk_eth/Kconfig         |  35 +
+ drivers/net/mtk_eth/Makefile        |   9 +
+ drivers/net/mtk_eth/mt7530.c        | 281 ++++++++
+ drivers/net/mtk_eth/mt7531.c        | 293 +++++++++
+ drivers/net/mtk_eth/mt753x.c        | 262 ++++++++
+ drivers/net/mtk_eth/mt753x.h        | 286 ++++++++
+ drivers/net/mtk_eth/mt7988.c        | 160 +++++
+ drivers/net/{ => mtk_eth}/mtk_eth.c | 971 ++++------------------------
+ drivers/net/{ => mtk_eth}/mtk_eth.h | 301 ++-------
+ 11 files changed, 1520 insertions(+), 1101 deletions(-)
+ create mode 100644 drivers/net/mtk_eth/Kconfig
+ create mode 100644 drivers/net/mtk_eth/Makefile
+ create mode 100644 drivers/net/mtk_eth/mt7530.c
+ create mode 100644 drivers/net/mtk_eth/mt7531.c
+ create mode 100644 drivers/net/mtk_eth/mt753x.c
+ create mode 100644 drivers/net/mtk_eth/mt753x.h
+ create mode 100644 drivers/net/mtk_eth/mt7988.c
+ rename drivers/net/{ => mtk_eth}/mtk_eth.c (62%)
+ rename drivers/net/{ => mtk_eth}/mtk_eth.h (59%)
+
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -966,26 +966,7 @@ config TSEC_ENET
+         This driver implements support for the (Enhanced) Three-Speed
+         Ethernet Controller found on Freescale SoCs.
+-config MEDIATEK_ETH
+-      bool "MediaTek Ethernet GMAC Driver"
+-      select PHYLIB
+-      select DM_GPIO
+-      select DM_RESET
+-      help
+-        This Driver support MediaTek Ethernet GMAC
+-        Say Y to enable support for the MediaTek Ethernet GMAC.
+-
+-if MEDIATEK_ETH
+-
+-config MTK_ETH_SGMII
+-      bool
+-      default y if ARCH_MEDIATEK && !TARGET_MT7623
+-
+-config MTK_ETH_XGMII
+-      bool
+-      default y if TARGET_MT7987 || TARGET_MT7988
+-
+-endif # MEDIATEK_ETH
++source "drivers/net/mtk_eth/Kconfig"
+ config HIFEMAC_ETH
+       bool "HiSilicon Fast Ethernet Controller"
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -67,7 +67,7 @@ obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio
+ obj-$(CONFIG_MDIO_MUX_MMIOREG) += mdio_mux_mmioreg.o
+ obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o
+ obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
+-obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
++obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth/
+ obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
+ obj-$(CONFIG_MT7620_ETH) += mt7620-eth.o
+ obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o
+--- /dev/null
++++ b/drivers/net/mtk_eth/Kconfig
+@@ -0,0 +1,35 @@
++
++config MEDIATEK_ETH
++      bool "MediaTek Ethernet GMAC Driver"
++      select PHYLIB
++      select DM_GPIO
++      select DM_RESET
++      help
++        This Driver support MediaTek Ethernet GMAC
++        Say Y to enable support for the MediaTek Ethernet GMAC.
++
++if MEDIATEK_ETH
++
++config MTK_ETH_SGMII
++      bool
++      default y if ARCH_MEDIATEK && !TARGET_MT7623
++
++config MTK_ETH_XGMII
++      bool
++      default y if TARGET_MT7988
++
++config MTK_ETH_SWITCH_MT7530
++      bool "Support for MediaTek MT7530 ethernet switch"
++      default y if TARGET_MT7623 || SOC_MT7621
++
++config MTK_ETH_SWITCH_MT7531
++      bool "Support for MediaTek MT7531 ethernet switch"
++      default y if TARGET_MT7622 || TARGET_MT7629 || TARGET_MT7981 || \
++                   TARGET_MT7986
++
++config MTK_ETH_SWITCH_MT7988
++      bool "Support for MediaTek MT7988 built-in ethernet switch"
++      depends on TARGET_MT7988
++      default y
++
++endif # MEDIATEK_ETH
+--- /dev/null
++++ b/drivers/net/mtk_eth/Makefile
+@@ -0,0 +1,9 @@
++# SPDX-License-Identifier: GPL-2.0+
++#
++# Copyright (C) 2025 MediaTek Inc.
++# Author: Weijie Gao <weijie.gao@mediatek.com>
++
++obj-y += mtk_eth.o
++obj-$(CONFIG_MTK_ETH_SWITCH_MT7530) += mt753x.o mt7530.o
++obj-$(CONFIG_MTK_ETH_SWITCH_MT7531) += mt753x.o mt7531.o
++obj-$(CONFIG_MTK_ETH_SWITCH_MT7988) += mt753x.o mt7988.o
+--- /dev/null
++++ b/drivers/net/mtk_eth/mt7530.c
+@@ -0,0 +1,281 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2025 MediaTek Inc.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ * Author: Mark Lee <mark-mc.lee@mediatek.com>
++ */
++
++#include <miiphy.h>
++#include <linux/delay.h>
++#include <linux/mdio.h>
++#include <linux/mii.h>
++#include "mtk_eth.h"
++#include "mt753x.h"
++
++#define CHIP_REV                      0x7ffc
++#define CHIP_NAME_S                   16
++#define CHIP_NAME_M                   0xffff0000
++#define CHIP_REV_S                    0
++#define CHIP_REV_M                    0x0f
++
++static void mt7530_core_reg_write(struct mt753x_switch_priv *priv, u32 reg,
++                                u32 val)
++{
++      u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
++
++      mtk_mmd_ind_write(priv->epriv.eth, phy_addr, 0x1f, reg, val);
++}
++
++static int mt7530_pad_clk_setup(struct mt753x_switch_priv *priv, int mode)
++{
++      u32 ncpo1, ssc_delta;
++
++      switch (mode) {
++      case PHY_INTERFACE_MODE_RGMII:
++              ncpo1 = 0x0c80;
++              ssc_delta = 0x87;
++              break;
++
++      default:
++              printf("error: xMII mode %d is not supported\n", mode);
++              return -EINVAL;
++      }
++
++      /* Disable MT7530 core clock */
++      mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0);
++
++      /* Disable MT7530 PLL */
++      mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1,
++                            (2 << RG_GSWPLL_POSDIV_200M_S) |
++                            (32 << RG_GSWPLL_FBKDIV_200M_S));
++
++      /* For MT7530 core clock = 500Mhz */
++      mt7530_core_reg_write(priv, CORE_GSWPLL_GRP2,
++                            (1 << RG_GSWPLL_POSDIV_500M_S) |
++                            (25 << RG_GSWPLL_FBKDIV_500M_S));
++
++      /* Enable MT7530 PLL */
++      mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1,
++                            (2 << RG_GSWPLL_POSDIV_200M_S) |
++                            (32 << RG_GSWPLL_FBKDIV_200M_S) |
++                            RG_GSWPLL_EN_PRE);
++
++      udelay(20);
++
++      mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
++
++      /* Setup the MT7530 TRGMII Tx Clock */
++      mt7530_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1);
++      mt7530_core_reg_write(priv, CORE_PLL_GROUP6, 0);
++      mt7530_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta);
++      mt7530_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta);
++      mt7530_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
++                            RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
++
++      mt7530_core_reg_write(priv, CORE_PLL_GROUP2,
++                            RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
++                            (1 << RG_SYSPLL_POSDIV_S));
++
++      mt7530_core_reg_write(priv, CORE_PLL_GROUP7,
++                            RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) |
++                            RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
++
++      /* Enable MT7530 core clock */
++      mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG,
++                            REG_GSWCK_EN | REG_TRGMIICK_EN);
++
++      return 0;
++}
++
++static void mt7530_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
++{
++      struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
++      u32 pmcr = FORCE_MODE;
++
++      if (enable)
++              pmcr = priv->pmcr;
++
++      mt753x_reg_write(priv, PMCR_REG(6), pmcr);
++}
++
++static int mt7530_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
++{
++      struct mt753x_switch_priv *priv = bus->priv;
++
++      if (devad < 0)
++              return mtk_mii_read(priv->epriv.eth, addr, reg);
++
++      return mtk_mmd_ind_read(priv->epriv.eth, addr, devad, reg);
++}
++
++static int mt7530_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
++                           u16 val)
++{
++      struct mt753x_switch_priv *priv = bus->priv;
++
++      if (devad < 0)
++              return mtk_mii_write(priv->epriv.eth, addr, reg, val);
++
++      return mtk_mmd_ind_write(priv->epriv.eth, addr, devad, reg, val);
++}
++
++static int mt7530_mdio_register(struct mt753x_switch_priv *priv)
++{
++      struct mii_dev *mdio_bus = mdio_alloc();
++      int ret;
++
++      if (!mdio_bus)
++              return -ENOMEM;
++
++      mdio_bus->read = mt7530_mdio_read;
++      mdio_bus->write = mt7530_mdio_write;
++      snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
++
++      mdio_bus->priv = priv;
++
++      ret = mdio_register(mdio_bus);
++      if (ret) {
++              mdio_free(mdio_bus);
++              return ret;
++      }
++
++      priv->mdio_bus = mdio_bus;
++
++      return 0;
++}
++
++static int mt7530_setup(struct mtk_eth_switch_priv *swpriv)
++{
++      struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
++      u16 phy_addr, phy_val;
++      u32 i, val, txdrv;
++
++      priv->smi_addr = MT753X_DFL_SMI_ADDR;
++      priv->reg_read = mt753x_mdio_reg_read;
++      priv->reg_write = mt753x_mdio_reg_write;
++
++      if (!MTK_HAS_CAPS(priv->epriv.soc->caps, MTK_TRGMII_MT7621_CLK)) {
++              /* Select 250MHz clk for RGMII mode */
++              mtk_ethsys_rmw(priv->epriv.eth, ETHSYS_CLKCFG0_REG,
++                             ETHSYS_TRGMII_CLK_SEL362_5, 0);
++
++              txdrv = 8;
++      } else {
++              txdrv = 4;
++      }
++
++      /* Modify HWTRAP first to allow direct access to internal PHYs */
++      mt753x_reg_read(priv, HWTRAP_REG, &val);
++      val |= CHG_TRAP;
++      val &= ~C_MDIO_BPS;
++      mt753x_reg_write(priv, MHWTRAP_REG, val);
++
++      /* Calculate the phy base address */
++      val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3;
++      priv->phy_base = (val | 0x7) + 1;
++
++      /* Turn off PHYs */
++      for (i = 0; i < MT753X_NUM_PHYS; i++) {
++              phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
++              phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
++              phy_val |= BMCR_PDOWN;
++              mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
++      }
++
++      /* Force MAC link down before reset */
++      mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
++      mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
++
++      /* MT7530 reset */
++      mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
++      udelay(100);
++
++      val = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
++            MAC_MODE | FORCE_MODE |
++            MAC_TX_EN | MAC_RX_EN |
++            BKOFF_EN | BACKPR_EN |
++            (SPEED_1000M << FORCE_SPD_S) |
++            FORCE_DPX | FORCE_LINK;
++
++      /* MT7530 Port6: Forced 1000M/FD, FC disabled */
++      priv->pmcr = val;
++
++      /* MT7530 Port5: Forced link down */
++      mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
++
++      /* Keep MAC link down before starting eth */
++      mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
++
++      /* MT7530 Port6: Set to RGMII */
++      mt753x_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII);
++
++      /* Hardware Trap: Enable Port6, Disable Port5 */
++      mt753x_reg_read(priv, HWTRAP_REG, &val);
++      val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS |
++             (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) |
++             (P5_INTF_MODE_RGMII << P5_INTF_MODE_S);
++      val &= ~(C_MDIO_BPS | P6_INTF_DIS);
++      mt753x_reg_write(priv, MHWTRAP_REG, val);
++
++      /* Setup switch core pll */
++      mt7530_pad_clk_setup(priv, priv->epriv.phy_interface);
++
++      /* Lower Tx Driving for TRGMII path */
++      for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
++              mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i),
++                               (txdrv << TD_DM_DRVP_S) |
++                               (txdrv << TD_DM_DRVN_S));
++
++      for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
++              mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16);
++
++      /* Enable port isolation to block inter-port communication */
++      mt753x_port_isolation(priv);
++
++      /* Turn on PHYs */
++      for (i = 0; i < MT753X_NUM_PHYS; i++) {
++              phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
++              phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
++              phy_val &= ~BMCR_PDOWN;
++              mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
++      }
++
++      return mt7530_mdio_register(priv);
++}
++
++static int mt7530_cleanup(struct mtk_eth_switch_priv *swpriv)
++{
++      struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
++
++      mdio_unregister(priv->mdio_bus);
++
++      return 0;
++}
++
++static int mt7530_detect(struct mtk_eth_priv *priv)
++{
++      int ret;
++      u32 rev;
++
++      ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev);
++      if (ret)
++              return ret;
++
++      if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7530)
++              return 0;
++
++      return -ENODEV;
++}
++
++MTK_ETH_SWITCH(mt7530) = {
++      .name = "mt7530",
++      .desc = "MediaTek MT7530",
++      .priv_size = sizeof(struct mt753x_switch_priv),
++      .reset_wait_time = 1000,
++
++      .detect = mt7530_detect,
++      .setup = mt7530_setup,
++      .cleanup = mt7530_cleanup,
++      .mac_control = mt7530_mac_control,
++};
+--- /dev/null
++++ b/drivers/net/mtk_eth/mt7531.c
+@@ -0,0 +1,293 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2025 MediaTek Inc.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ * Author: Mark Lee <mark-mc.lee@mediatek.com>
++ */
++
++#include <miiphy.h>
++#include <linux/delay.h>
++#include <linux/mdio.h>
++#include <linux/mii.h>
++#include "mtk_eth.h"
++#include "mt753x.h"
++
++#define CHIP_REV                      0x781C
++#define CHIP_NAME_S                   16
++#define CHIP_NAME_M                   0xffff0000
++#define CHIP_REV_S                    0
++#define CHIP_REV_M                    0x0f
++#define CHIP_REV_E1                   0x0
++
++static int mt7531_core_reg_read(struct mt753x_switch_priv *priv, u32 reg)
++{
++      u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
++
++      return mt7531_mmd_read(priv, phy_addr, 0x1f, reg);
++}
++
++static void mt7531_core_reg_write(struct mt753x_switch_priv *priv, u32 reg,
++                                u32 val)
++{
++      u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
++
++      mt7531_mmd_write(priv, phy_addr, 0x1f, reg, val);
++}
++
++static void mt7531_core_pll_setup(struct mt753x_switch_priv *priv)
++{
++      /* Step 1 : Disable MT7531 COREPLL */
++      mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, 0);
++
++      /* Step 2: switch to XTAL output */
++      mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_CLKSW, SW_CLKSW);
++
++      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, 0);
++
++      /* Step 3: disable PLLGP and enable program PLLGP */
++      mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_PLLGP, SW_PLLGP);
++
++      /* Step 4: program COREPLL output frequency to 500MHz */
++      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_POSDIV_M,
++                     2 << RG_COREPLL_POSDIV_S);
++      udelay(25);
++
++      /* Currently, support XTAL 25Mhz only */
++      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_M,
++                     0x140000 << RG_COREPLL_SDM_PCW_S);
++
++      /* Set feedback divide ratio update signal to high */
++      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG,
++                     RG_COREPLL_SDM_PCW_CHG);
++
++      /* Wait for at least 16 XTAL clocks */
++      udelay(10);
++
++      /* Step 5: set feedback divide ratio update signal to low */
++      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, 0);
++
++      /* add enable 325M clock for SGMII */
++      mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
++
++      /* add enable 250SSC clock for RGMII */
++      mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
++
++      /*Step 6: Enable MT7531 PLL */
++      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, RG_COREPLL_EN);
++
++      mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, EN_COREPLL);
++
++      udelay(25);
++}
++
++static int mt7531_port_sgmii_init(struct mt753x_switch_priv *priv, u32 port)
++{
++      if (port != 5 && port != 6) {
++              printf("mt7531: port %d is not a SGMII port\n", port);
++              return -EINVAL;
++      }
++
++      /* Set SGMII GEN2 speed(2.5G) */
++      mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK,
++                     FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
++
++      /* Disable SGMII AN */
++      mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port),
++                     SGMII_AN_ENABLE, 0);
++
++      /* SGMII force mode setting */
++      mt753x_reg_write(priv, MT7531_SGMII_MODE(port), SGMII_FORCE_MODE);
++
++      /* Release PHYA power down state */
++      mt753x_reg_rmw(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
++                     SGMII_PHYA_PWD, 0);
++
++      return 0;
++}
++
++static int mt7531_port_rgmii_init(struct mt753x_switch_priv *priv, u32 port)
++{
++      u32 val;
++
++      if (port != 5) {
++              printf("error: RGMII mode is not available for port %d\n",
++                     port);
++              return -EINVAL;
++      }
++
++      mt753x_reg_read(priv, MT7531_CLKGEN_CTRL, &val);
++      val |= GP_CLK_EN;
++      val &= ~GP_MODE_M;
++      val |= GP_MODE_RGMII << GP_MODE_S;
++      val |= TXCLK_NO_REVERSE;
++      val |= RXCLK_NO_DELAY;
++      val &= ~CLK_SKEW_IN_M;
++      val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S;
++      val &= ~CLK_SKEW_OUT_M;
++      val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S;
++      mt753x_reg_write(priv, MT7531_CLKGEN_CTRL, val);
++
++      return 0;
++}
++
++static void mt7531_phy_setting(struct mt753x_switch_priv *priv)
++{
++      int i;
++      u32 val;
++
++      for (i = 0; i < MT753X_NUM_PHYS; i++) {
++              /* Enable HW auto downshift */
++              mt7531_mii_write(priv, i, 0x1f, 0x1);
++              val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
++              val |= PHY_EN_DOWN_SHFIT;
++              mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
++
++              /* PHY link down power saving enable */
++              val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
++              val |= PHY_LINKDOWN_POWER_SAVING_EN;
++              mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
++
++              val = mt7531_mmd_read(priv, i, 0x1e, PHY_DEV1E_REG_0C6);
++              val &= ~PHY_POWER_SAVING_M;
++              val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
++              mt7531_mmd_write(priv, i, 0x1e, PHY_DEV1E_REG_0C6, val);
++      }
++}
++
++static void mt7531_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
++{
++      struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
++      u32 pmcr = FORCE_MODE_LNK;
++
++      if (enable)
++              pmcr = priv->pmcr;
++
++      mt753x_reg_write(priv, PMCR_REG(5), pmcr);
++      mt753x_reg_write(priv, PMCR_REG(6), pmcr);
++}
++
++static int mt7531_setup(struct mtk_eth_switch_priv *swpriv)
++{
++      struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
++      u32 i, val, pmcr, port5_sgmii;
++      u16 phy_addr, phy_val;
++
++      priv->smi_addr = MT753X_DFL_SMI_ADDR;
++      priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
++      priv->reg_read = mt753x_mdio_reg_read;
++      priv->reg_write = mt753x_mdio_reg_write;
++
++      /* Turn off PHYs */
++      for (i = 0; i < MT753X_NUM_PHYS; i++) {
++              phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
++              phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
++              phy_val |= BMCR_PDOWN;
++              mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
++      }
++
++      /* Force MAC link down before reset */
++      mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
++      mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
++
++      /* Switch soft reset */
++      mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
++      udelay(100);
++
++      /* Enable MDC input Schmitt Trigger */
++      mt753x_reg_rmw(priv, MT7531_SMT0_IOLB, SMT_IOLB_5_SMI_MDC_EN,
++                     SMT_IOLB_5_SMI_MDC_EN);
++
++      mt7531_core_pll_setup(priv);
++
++      mt753x_reg_read(priv, MT7531_TOP_SIG_SR, &val);
++      port5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
++
++      /* port5 support either RGMII or SGMII, port6 only support SGMII. */
++      switch (priv->epriv.phy_interface) {
++      case PHY_INTERFACE_MODE_RGMII:
++              if (!port5_sgmii)
++                      mt7531_port_rgmii_init(priv, 5);
++              break;
++
++      case PHY_INTERFACE_MODE_2500BASEX:
++              mt7531_port_sgmii_init(priv, 6);
++              if (port5_sgmii)
++                      mt7531_port_sgmii_init(priv, 5);
++              break;
++
++      default:
++              break;
++      }
++
++      pmcr = MT7531_FORCE_MODE |
++             (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
++             MAC_MODE | MAC_TX_EN | MAC_RX_EN |
++             BKOFF_EN | BACKPR_EN |
++             FORCE_RX_FC | FORCE_TX_FC |
++             (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
++             FORCE_LINK;
++
++      priv->pmcr = pmcr;
++
++      /* Keep MAC link down before starting eth */
++      mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
++      mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
++
++      /* Enable port isolation to block inter-port communication */
++      mt753x_port_isolation(priv);
++
++      /* Turn on PHYs */
++      for (i = 0; i < MT753X_NUM_PHYS; i++) {
++              phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
++              phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
++              phy_val &= ~BMCR_PDOWN;
++              mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
++      }
++
++      mt7531_phy_setting(priv);
++
++      /* Enable Internal PHYs */
++      val = mt7531_core_reg_read(priv, CORE_PLL_GROUP4);
++      val |= MT7531_BYPASS_MODE;
++      val &= ~MT7531_POWER_ON_OFF;
++      mt7531_core_reg_write(priv, CORE_PLL_GROUP4, val);
++
++      return mt7531_mdio_register(priv);
++}
++
++static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
++{
++      struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
++
++      mdio_unregister(priv->mdio_bus);
++
++      return 0;
++}
++
++static int mt7531_detect(struct mtk_eth_priv *priv)
++{
++      int ret;
++      u32 rev;
++
++      ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev);
++      if (ret)
++              return ret;
++
++      if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7531)
++              return 0;
++
++      return -ENODEV;
++}
++
++MTK_ETH_SWITCH(mt7531) = {
++      .name = "mt7531",
++      .desc = "MediaTek MT7531",
++      .priv_size = sizeof(struct mt753x_switch_priv),
++      .reset_wait_time = 200,
++
++      .detect = mt7531_detect,
++      .setup = mt7531_setup,
++      .cleanup = mt7531_cleanup,
++      .mac_control = mt7531_mac_control,
++};
+--- /dev/null
++++ b/drivers/net/mtk_eth/mt753x.c
+@@ -0,0 +1,262 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2025 MediaTek Inc.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ * Author: Mark Lee <mark-mc.lee@mediatek.com>
++ */
++
++#include <errno.h>
++#include <time.h>
++#include "mtk_eth.h"
++#include "mt753x.h"
++
++/*
++ * MT753x Internal Register Address Bits
++ * -------------------------------------------------------------------
++ * | 15  14  13  12  11  10   9   8   7   6 | 5   4   3   2 | 1   0  |
++ * |----------------------------------------|---------------|--------|
++ * |              Page Address              |  Reg Address  | Unused |
++ * -------------------------------------------------------------------
++ */
++
++int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg,
++                         u32 *data)
++{
++      int ret, low_word, high_word;
++
++      /* Write page address */
++      ret = mtk_mii_write(priv, smi_addr, 0x1f, reg >> 6);
++      if (ret)
++              return ret;
++
++      /* Read low word */
++      low_word = mtk_mii_read(priv, smi_addr, (reg >> 2) & 0xf);
++      if (low_word < 0)
++              return low_word;
++
++      /* Read high word */
++      high_word = mtk_mii_read(priv, smi_addr, 0x10);
++      if (high_word < 0)
++              return high_word;
++
++      if (data)
++              *data = ((u32)high_word << 16) | (low_word & 0xffff);
++
++      return 0;
++}
++
++int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
++{
++      return __mt753x_mdio_reg_read(priv->epriv.eth, priv->smi_addr, reg,
++                                    data);
++}
++
++int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
++{
++      int ret;
++
++      /* Write page address */
++      ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x1f, reg >> 6);
++      if (ret)
++              return ret;
++
++      /* Write low word */
++      ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, (reg >> 2) & 0xf,
++                          data & 0xffff);
++      if (ret)
++              return ret;
++
++      /* Write high word */
++      return mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x10, data >> 16);
++}
++
++int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
++{
++      return priv->reg_read(priv, reg, data);
++}
++
++int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
++{
++      return priv->reg_write(priv, reg, data);
++}
++
++void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set)
++{
++      u32 val;
++
++      priv->reg_read(priv, reg, &val);
++      val &= ~clr;
++      val |= set;
++      priv->reg_write(priv, reg, val);
++}
++
++/* Indirect MDIO clause 22/45 access */
++static int mt7531_mii_rw(struct mt753x_switch_priv *priv, int phy, int reg,
++                       u16 data, u32 cmd, u32 st)
++{
++      u32 val, timeout_ms;
++      ulong timeout;
++      int ret = 0;
++
++      val = (st << MDIO_ST_S) |
++            ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
++            ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
++            ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
++
++      if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
++              val |= data & MDIO_RW_DATA_M;
++
++      mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST);
++
++      timeout_ms = 100;
++      timeout = get_timer(0);
++      while (1) {
++              mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
++
++              if ((val & PHY_ACS_ST) == 0)
++                      break;
++
++              if (get_timer(timeout) > timeout_ms)
++                      return -ETIMEDOUT;
++      }
++
++      if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
++              mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
++              ret = val & MDIO_RW_DATA_M;
++      }
++
++      return ret;
++}
++
++int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg)
++{
++      u8 phy_addr;
++
++      if (phy >= MT753X_NUM_PHYS)
++              return -EINVAL;
++
++      phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
++
++      return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ,
++                           MDIO_ST_C22);
++}
++
++int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val)
++{
++      u8 phy_addr;
++
++      if (phy >= MT753X_NUM_PHYS)
++              return -EINVAL;
++
++      phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
++
++      return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE,
++                           MDIO_ST_C22);
++}
++
++int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
++                  u16 reg)
++{
++      u8 phy_addr;
++      int ret;
++
++      if (addr >= MT753X_NUM_PHYS)
++              return -EINVAL;
++
++      phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
++
++      ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
++                          MDIO_ST_C45);
++      if (ret)
++              return ret;
++
++      return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45,
++                           MDIO_ST_C45);
++}
++
++int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
++                   u16 reg, u16 val)
++{
++      u8 phy_addr;
++      int ret;
++
++      if (addr >= MT753X_NUM_PHYS)
++              return 0;
++
++      phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
++
++      ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
++                          MDIO_ST_C45);
++      if (ret)
++              return ret;
++
++      return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE,
++                           MDIO_ST_C45);
++}
++
++static int mt7531_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
++{
++      struct mt753x_switch_priv *priv = bus->priv;
++
++      if (devad < 0)
++              return mt7531_mii_read(priv, addr, reg);
++
++      return mt7531_mmd_read(priv, addr, devad, reg);
++}
++
++static int mt7531_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
++                           u16 val)
++{
++      struct mt753x_switch_priv *priv = bus->priv;
++
++      if (devad < 0)
++              return mt7531_mii_write(priv, addr, reg, val);
++
++      return mt7531_mmd_write(priv, addr, devad, reg, val);
++}
++
++int mt7531_mdio_register(struct mt753x_switch_priv *priv)
++{
++      struct mii_dev *mdio_bus = mdio_alloc();
++      int ret;
++
++      if (!mdio_bus)
++              return -ENOMEM;
++
++      mdio_bus->read = mt7531_mdio_read;
++      mdio_bus->write = mt7531_mdio_write;
++      snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
++
++      mdio_bus->priv = priv;
++
++      ret = mdio_register(mdio_bus);
++      if (ret) {
++              mdio_free(mdio_bus);
++              return ret;
++      }
++
++      priv->mdio_bus = mdio_bus;
++
++      return 0;
++}
++
++void mt753x_port_isolation(struct mt753x_switch_priv *priv)
++{
++      u32 i;
++
++      for (i = 0; i < MT753X_NUM_PORTS; i++) {
++              /* Set port matrix mode */
++              if (i != 6)
++                      mt753x_reg_write(priv, PCR_REG(i),
++                                       (0x40 << PORT_MATRIX_S));
++              else
++                      mt753x_reg_write(priv, PCR_REG(i),
++                                       (0x3f << PORT_MATRIX_S));
++
++              /* Set port mode to user port */
++              mt753x_reg_write(priv, PVC_REG(i),
++                               (0x8100 << STAG_VPID_S) |
++                               (VLAN_ATTR_USER << VLAN_ATTR_S));
++      }
++}
+--- /dev/null
++++ b/drivers/net/mtk_eth/mt753x.h
+@@ -0,0 +1,286 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2025 MediaTek Inc.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ * Author: Mark Lee <mark-mc.lee@mediatek.com>
++ */
++
++#ifndef _MTK_ETH_MT753X_H_
++#define _MTK_ETH_MT753X_H_
++
++#include <phy.h>
++#include <miiphy.h>
++#include <linux/bitops.h>
++#include <linux/bitfield.h>
++
++struct mtk_eth_priv;
++
++#define MT753X_NUM_PHYS               5
++#define MT753X_NUM_PORTS      7
++#define MT753X_DFL_SMI_ADDR   31
++#define MT753X_SMI_ADDR_MASK  0x1f
++
++#define MT753X_PHY_ADDR(base, addr) \
++      (((base) + (addr)) & 0x1f)
++
++/* MT7530 Registers */
++#define PCR_REG(p)                    (0x2004 + (p) * 0x100)
++#define PORT_MATRIX_S                 16
++#define PORT_MATRIX_M                 0xff0000
++
++#define PVC_REG(p)                    (0x2010 + (p) * 0x100)
++#define STAG_VPID_S                   16
++#define STAG_VPID_M                   0xffff0000
++#define VLAN_ATTR_S                   6
++#define VLAN_ATTR_M                   0xc0
++
++/* VLAN_ATTR: VLAN attributes */
++#define VLAN_ATTR_USER                        0
++#define VLAN_ATTR_STACK                       1
++#define VLAN_ATTR_TRANSLATION         2
++#define VLAN_ATTR_TRANSPARENT         3
++
++#define PMCR_REG(p)                   (0x3000 + (p) * 0x100)
++/* XXX: all fields of MT7530 are defined under GMAC_PORT_MCR
++ * MT7531 specific fields are defined below
++ */
++#define FORCE_MODE_EEE1G              BIT(25)
++#define FORCE_MODE_EEE100             BIT(26)
++#define FORCE_MODE_TX_FC              BIT(27)
++#define FORCE_MODE_RX_FC              BIT(28)
++#define FORCE_MODE_DPX                        BIT(29)
++#define FORCE_MODE_SPD                        BIT(30)
++#define FORCE_MODE_LNK                        BIT(31)
++#define MT7531_FORCE_MODE             FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
++                                      FORCE_MODE_DPX   | FORCE_MODE_SPD | \
++                                      FORCE_MODE_LNK
++#define MT7988_FORCE_MODE             FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
++                                      FORCE_MODE_DPX   | FORCE_MODE_SPD | \
++                                      FORCE_MODE_LNK
++
++/* MT7531 SGMII Registers */
++#define MT7531_SGMII_REG_BASE         0x5000
++#define MT7531_SGMII_REG_PORT_BASE    0x1000
++#define MT7531_SGMII_REG(p, r)                (MT7531_SGMII_REG_BASE + \
++                                      (p) * MT7531_SGMII_REG_PORT_BASE + (r))
++#define MT7531_PCS_CONTROL_1(p)               MT7531_SGMII_REG(((p) - 5), 0x00)
++#define MT7531_SGMII_MODE(p)          MT7531_SGMII_REG(((p) - 5), 0x20)
++#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(((p) - 5), 0xe8)
++#define MT7531_PHYA_CTRL_SIGNAL3(p)   MT7531_SGMII_REG(((p) - 5), 0x128)
++#define MT7531_PHYA_ANA_SYSPLL(p)     MT7531_SGMII_REG(((p) - 5), 0x158)
++/* XXX: all fields of MT7531 SGMII  are defined under SGMSYS */
++
++/* MT753x System Control Register */
++#define SYS_CTRL_REG                  0x7000
++#define SW_PHY_RST                    BIT(2)
++#define SW_SYS_RST                    BIT(1)
++#define SW_REG_RST                    BIT(0)
++
++/* MT7531  */
++#define MT7531_PHY_IAC                        0x701c
++/* XXX: all fields are defined under GMAC_PIAC_REG */
++
++#define MT7531_CLKGEN_CTRL            0x7500
++#define CLK_SKEW_OUT_S                        8
++#define CLK_SKEW_OUT_M                        0x300
++#define CLK_SKEW_IN_S                 6
++#define CLK_SKEW_IN_M                 0xc0
++#define RXCLK_NO_DELAY                        BIT(5)
++#define TXCLK_NO_REVERSE              BIT(4)
++#define GP_MODE_S                     1
++#define GP_MODE_M                     0x06
++#define GP_CLK_EN                     BIT(0)
++
++/* Values of GP_MODE */
++#define GP_MODE_RGMII                 0
++#define GP_MODE_MII                   1
++#define GP_MODE_REV_MII                       2
++
++/* Values of CLK_SKEW_IN */
++#define CLK_SKEW_IN_NO_CHANGE         0
++#define CLK_SKEW_IN_DELAY_100PPS      1
++#define CLK_SKEW_IN_DELAY_200PPS      2
++#define CLK_SKEW_IN_REVERSE           3
++
++/* Values of CLK_SKEW_OUT */
++#define CLK_SKEW_OUT_NO_CHANGE                0
++#define CLK_SKEW_OUT_DELAY_100PPS     1
++#define CLK_SKEW_OUT_DELAY_200PPS     2
++#define CLK_SKEW_OUT_REVERSE          3
++
++#define HWTRAP_REG                    0x7800
++/* MT7530 Modified Hardware Trap Status Registers */
++#define MHWTRAP_REG                   0x7804
++#define CHG_TRAP                      BIT(16)
++#define LOOPDET_DIS                   BIT(14)
++#define P5_INTF_SEL_S                 13
++#define P5_INTF_SEL_M                 0x2000
++#define SMI_ADDR_S                    11
++#define SMI_ADDR_M                    0x1800
++#define XTAL_FSEL_S                   9
++#define XTAL_FSEL_M                   0x600
++#define P6_INTF_DIS                   BIT(8)
++#define P5_INTF_MODE_S                        7
++#define P5_INTF_MODE_M                        0x80
++#define P5_INTF_DIS                   BIT(6)
++#define C_MDIO_BPS                    BIT(5)
++#define CHIP_MODE_S                   0
++#define CHIP_MODE_M                   0x0f
++
++/* P5_INTF_SEL: Interface type of Port5 */
++#define P5_INTF_SEL_GPHY              0
++#define P5_INTF_SEL_GMAC5             1
++
++/* P5_INTF_MODE: Interface mode of Port5 */
++#define P5_INTF_MODE_GMII_MII         0
++#define P5_INTF_MODE_RGMII            1
++
++#define MT7530_P6ECR                  0x7830
++#define P6_INTF_MODE_M                        0x3
++#define P6_INTF_MODE_S                        0
++
++/* P6_INTF_MODE: Interface mode of Port6 */
++#define P6_INTF_MODE_RGMII            0
++#define P6_INTF_MODE_TRGMII           1
++
++#define MT7530_TRGMII_RD(n)           (0x7a10 + (n) * 8)
++#define RD_TAP_S                      0
++#define RD_TAP_M                      0x7f
++
++#define MT7530_TRGMII_TD_ODT(n)               (0x7a54 + (n) * 8)
++/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */
++
++/* TOP Signals Status Register */
++#define MT7531_TOP_SIG_SR             0x780c
++#define PAD_MCM_SMI_EN                        BIT(0)
++#define PAD_DUAL_SGMII_EN             BIT(1)
++
++/* MT7531 PLLGP Registers */
++#define MT7531_PLLGP_EN                       0x7820
++#define EN_COREPLL                    BIT(2)
++#define SW_CLKSW                      BIT(1)
++#define SW_PLLGP                      BIT(0)
++
++#define MT7531_PLLGP_CR0              0x78a8
++#define RG_COREPLL_EN                 BIT(22)
++#define RG_COREPLL_POSDIV_S           23
++#define RG_COREPLL_POSDIV_M           0x3800000
++#define RG_COREPLL_SDM_PCW_S          1
++#define RG_COREPLL_SDM_PCW_M          0x3ffffe
++#define RG_COREPLL_SDM_PCW_CHG                BIT(0)
++
++/* MT7531 RGMII and SGMII PLL clock */
++#define MT7531_ANA_PLLGP_CR2          0x78b0
++#define MT7531_ANA_PLLGP_CR5          0x78bc
++
++/* MT7531 GPIO GROUP IOLB SMT0 Control */
++#define MT7531_SMT0_IOLB              0x7f04
++#define SMT_IOLB_5_SMI_MDC_EN         BIT(5)
++
++/* MT7530 GPHY MDIO MMD Registers */
++#define CORE_PLL_GROUP2                       0x401
++#define RG_SYSPLL_EN_NORMAL           BIT(15)
++#define RG_SYSPLL_VODEN                       BIT(14)
++#define RG_SYSPLL_POSDIV_S            5
++#define RG_SYSPLL_POSDIV_M            0x60
++
++#define CORE_PLL_GROUP4                       0x403
++#define MT7531_BYPASS_MODE            BIT(4)
++#define MT7531_POWER_ON_OFF           BIT(5)
++#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_S          0
++#define RG_LCDDS_PCW_NCPO1_M          0xffff
++
++#define CORE_PLL_GROUP6                       0x405
++#define RG_LCDDS_PCW_NCPO0_S          0
++#define RG_LCDDS_PCW_NCPO0_M          0xffff
++
++#define CORE_PLL_GROUP7                       0x406
++#define RG_LCDDS_PWDB                 BIT(15)
++#define RG_LCDDS_ISO_EN                       BIT(13)
++#define RG_LCCDS_C_S                  4
++#define RG_LCCDS_C_M                  0x70
++#define RG_LCDDS_PCW_NCPO_CHG         BIT(3)
++
++#define CORE_PLL_GROUP10              0x409
++#define RG_LCDDS_SSC_DELTA_S          0
++#define RG_LCDDS_SSC_DELTA_M          0xfff
++
++#define CORE_PLL_GROUP11              0x40a
++#define RG_LCDDS_SSC_DELTA1_S         0
++#define RG_LCDDS_SSC_DELTA1_M         0xfff
++
++#define CORE_GSWPLL_GRP1              0x40d
++#define RG_GSWPLL_POSDIV_200M_S               12
++#define RG_GSWPLL_POSDIV_200M_M               0x3000
++#define RG_GSWPLL_EN_PRE              BIT(11)
++#define RG_GSWPLL_FBKDIV_200M_S               0
++#define RG_GSWPLL_FBKDIV_200M_M               0xff
++
++#define CORE_GSWPLL_GRP2              0x40e
++#define RG_GSWPLL_POSDIV_500M_S               8
++#define RG_GSWPLL_POSDIV_500M_M               0x300
++#define RG_GSWPLL_FBKDIV_500M_S               0
++#define RG_GSWPLL_FBKDIV_500M_M               0xff
++
++#define CORE_TRGMII_GSW_CLK_CG                0x410
++#define REG_GSWCK_EN                  BIT(0)
++#define REG_TRGMIICK_EN                       BIT(1)
++
++/* Extend PHY Control Register 3 */
++#define PHY_EXT_REG_14                        0x14
++
++/* Fields of PHY_EXT_REG_14 */
++#define PHY_EN_DOWN_SHFIT             BIT(4)
++
++/* Extend PHY Control Register 4 */
++#define PHY_EXT_REG_17                        0x17
++
++/* Fields of PHY_EXT_REG_17 */
++#define PHY_LINKDOWN_POWER_SAVING_EN  BIT(4)
++
++/* PHY RXADC Control Register 7 */
++#define PHY_DEV1E_REG_0C6             0x0c6
++
++/* Fields of PHY_DEV1E_REG_0C6 */
++#define PHY_POWER_SAVING_S            8
++#define PHY_POWER_SAVING_M            0x300
++#define PHY_POWER_SAVING_TX           0x0
++
++struct mt753x_switch_priv {
++      struct mtk_eth_switch_priv epriv;
++      struct mii_dev *mdio_bus;
++      u32 smi_addr;
++      u32 phy_base;
++      u32 pmcr;
++
++      int (*reg_read)(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
++      int (*reg_write)(struct mt753x_switch_priv *priv, u32 reg, u32 data);
++};
++
++int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg,
++                         u32 *data);
++int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
++int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data);
++
++int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
++int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data);
++void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set);
++
++int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg);
++int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val);
++int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
++                  u16 reg);
++int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
++                   u16 reg, u16 val);
++
++int mt7531_mdio_register(struct mt753x_switch_priv *priv);
++
++void mt753x_port_isolation(struct mt753x_switch_priv *priv);
++
++#endif /* _MTK_ETH_MT753X_H_ */
+--- /dev/null
++++ b/drivers/net/mtk_eth/mt7988.c
+@@ -0,0 +1,160 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2025 MediaTek Inc.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ * Author: Mark Lee <mark-mc.lee@mediatek.com>
++ */
++
++#include <miiphy.h>
++#include <linux/delay.h>
++#include <linux/mdio.h>
++#include <linux/mii.h>
++#include <linux/io.h>
++#include "mtk_eth.h"
++#include "mt753x.h"
++
++static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
++{
++      *data = readl(priv->epriv.ethsys_base + GSW_BASE + reg);
++
++      return 0;
++}
++
++static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
++{
++      writel(data, priv->epriv.ethsys_base + GSW_BASE + reg);
++
++      return 0;
++}
++
++static void mt7988_phy_setting(struct mt753x_switch_priv *priv)
++{
++      u16 val;
++      u32 i;
++
++      for (i = 0; i < MT753X_NUM_PHYS; i++) {
++              /* Enable HW auto downshift */
++              mt7531_mii_write(priv, i, 0x1f, 0x1);
++              val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
++              val |= PHY_EN_DOWN_SHFIT;
++              mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
++
++              /* PHY link down power saving enable */
++              val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
++              val |= PHY_LINKDOWN_POWER_SAVING_EN;
++              mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
++      }
++}
++
++static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
++{
++      struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
++      u32 pmcr = FORCE_MODE_LNK;
++
++      if (enable)
++              pmcr = priv->pmcr;
++
++      mt7988_reg_write(priv, PMCR_REG(6), pmcr);
++}
++
++static int mt7988_setup(struct mtk_eth_switch_priv *swpriv)
++{
++      struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
++      u16 phy_addr, phy_val;
++      u32 pmcr;
++      int i;
++
++      priv->smi_addr = MT753X_DFL_SMI_ADDR;
++      priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
++      priv->reg_read = mt7988_reg_read;
++      priv->reg_write = mt7988_reg_write;
++
++      /* Turn off PHYs */
++      for (i = 0; i < MT753X_NUM_PHYS; i++) {
++              phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
++              phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
++              phy_val |= BMCR_PDOWN;
++              mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
++      }
++
++      switch (priv->epriv.phy_interface) {
++      case PHY_INTERFACE_MODE_USXGMII:
++              /* Use CPU bridge instead of actual USXGMII path */
++
++              /* Disable GDM1 RX CRC stripping */
++              /* mtk_fe_rmw(priv, 0x500, BIT(16), 0); */
++
++              /* Set GDM1 no drop */
++              mtk_fe_rmw(priv->epriv.eth, PSE_NO_DROP_CFG_REG, 0,
++                         PSE_NO_DROP_GDM1);
++
++              /* Enable GSW CPU bridge as USXGMII */
++              /* mtk_fe_rmw(priv, 0x504, BIT(31), BIT(31)); */
++
++              /* Enable GDM1 to GSW CPU bridge */
++              mtk_gmac_rmw(priv->epriv.eth, GMAC_MAC_MISC_REG, 0, BIT(0));
++
++              /* XGMAC force link up */
++              mtk_gmac_rmw(priv->epriv.eth, GMAC_XGMAC_STS_REG, 0,
++                           P1_XGMAC_FORCE_LINK);
++
++              /* Setup GSW CPU bridge IPG */
++              mtk_gmac_rmw(priv->epriv.eth, GMAC_GSW_CFG_REG,
++                           GSWTX_IPG_M | GSWRX_IPG_M,
++                           (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S));
++              break;
++      default:
++              printf("Error: MT7988 GSW does not support %s interface\n",
++                     phy_string_for_interface(priv->epriv.phy_interface));
++              break;
++      }
++
++      pmcr = MT7988_FORCE_MODE |
++             (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
++             MAC_MODE | MAC_TX_EN | MAC_RX_EN |
++             BKOFF_EN | BACKPR_EN |
++             FORCE_RX_FC | FORCE_TX_FC |
++             (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
++             FORCE_LINK;
++
++      priv->pmcr = pmcr;
++
++      /* Keep MAC link down before starting eth */
++      mt7988_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
++
++      /* Enable port isolation to block inter-port communication */
++      mt753x_port_isolation(priv);
++
++      /* Turn on PHYs */
++      for (i = 0; i < MT753X_NUM_PHYS; i++) {
++              phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
++              phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
++              phy_val &= ~BMCR_PDOWN;
++              mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
++      }
++
++      mt7988_phy_setting(priv);
++
++      return mt7531_mdio_register(priv);
++}
++
++static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
++{
++      struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
++
++      mdio_unregister(priv->mdio_bus);
++
++      return 0;
++}
++
++MTK_ETH_SWITCH(mt7988) = {
++      .name = "mt7988",
++      .desc = "MediaTek MT7988 built-in switch",
++      .priv_size = sizeof(struct mt753x_switch_priv),
++      .reset_wait_time = 50,
++
++      .setup = mt7988_setup,
++      .cleanup = mt7531_cleanup,
++      .mac_control = mt7988_mac_control,
++};
+--- a/drivers/net/mtk_eth.c
++++ /dev/null
+@@ -1,2280 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/*
+- * Copyright (C) 2018 MediaTek Inc.
+- *
+- * Author: Weijie Gao <weijie.gao@mediatek.com>
+- * Author: Mark Lee <mark-mc.lee@mediatek.com>
+- */
+-
+-#include <cpu_func.h>
+-#include <dm.h>
+-#include <log.h>
+-#include <malloc.h>
+-#include <miiphy.h>
+-#include <net.h>
+-#include <regmap.h>
+-#include <reset.h>
+-#include <syscon.h>
+-#include <wait_bit.h>
+-#include <asm/cache.h>
+-#include <asm/gpio.h>
+-#include <asm/io.h>
+-#include <dm/device_compat.h>
+-#include <linux/delay.h>
+-#include <linux/err.h>
+-#include <linux/ioport.h>
+-#include <linux/mdio.h>
+-#include <linux/mii.h>
+-#include <linux/printk.h>
+-
+-#include "mtk_eth.h"
+-
+-#define NUM_TX_DESC           32
+-#define NUM_RX_DESC           32
+-#define TX_TOTAL_BUF_SIZE     (NUM_TX_DESC * PKTSIZE_ALIGN)
+-#define RX_TOTAL_BUF_SIZE     (NUM_RX_DESC * PKTSIZE_ALIGN)
+-#define TOTAL_PKT_BUF_SIZE    (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE)
+-
+-#define MT753X_NUM_PHYS               5
+-#define MT753X_NUM_PORTS      7
+-#define MT753X_DFL_SMI_ADDR   31
+-#define MT753X_SMI_ADDR_MASK  0x1f
+-
+-#define MT753X_PHY_ADDR(base, addr) \
+-      (((base) + (addr)) & 0x1f)
+-
+-#define GDMA_FWD_TO_CPU \
+-      (0x20000000 | \
+-      GDM_ICS_EN | \
+-      GDM_TCS_EN | \
+-      GDM_UCS_EN | \
+-      STRP_CRC | \
+-      (DP_PDMA << MYMAC_DP_S) | \
+-      (DP_PDMA << BC_DP_S) | \
+-      (DP_PDMA << MC_DP_S) | \
+-      (DP_PDMA << UN_DP_S))
+-
+-#define GDMA_BRIDGE_TO_CPU \
+-      (0xC0000000 | \
+-      GDM_ICS_EN | \
+-      GDM_TCS_EN | \
+-      GDM_UCS_EN | \
+-      (DP_PDMA << MYMAC_DP_S) | \
+-      (DP_PDMA << BC_DP_S) | \
+-      (DP_PDMA << MC_DP_S) | \
+-      (DP_PDMA << UN_DP_S))
+-
+-#define GDMA_FWD_DISCARD \
+-      (0x20000000 | \
+-      GDM_ICS_EN | \
+-      GDM_TCS_EN | \
+-      GDM_UCS_EN | \
+-      STRP_CRC | \
+-      (DP_DISCARD << MYMAC_DP_S) | \
+-      (DP_DISCARD << BC_DP_S) | \
+-      (DP_DISCARD << MC_DP_S) | \
+-      (DP_DISCARD << UN_DP_S))
+-
+-enum mtk_switch {
+-      SW_NONE,
+-      SW_MT7530,
+-      SW_MT7531,
+-      SW_MT7988,
+-};
+-
+-/* struct mtk_soc_data -      This is the structure holding all differences
+- *                            among various plaforms
+- * @caps                      Flags shown the extra capability for the SoC
+- * @ana_rgc3:                 The offset for register ANA_RGC3 related to
+- *                            sgmiisys syscon
+- * @gdma_count:                       Number of GDMAs
+- * @pdma_base:                        Register base of PDMA block
+- * @txd_size:                 Tx DMA descriptor size.
+- * @rxd_size:                 Rx DMA descriptor size.
+- */
+-struct mtk_soc_data {
+-      u32 caps;
+-      u32 ana_rgc3;
+-      u32 gdma_count;
+-      u32 pdma_base;
+-      u32 txd_size;
+-      u32 rxd_size;
+-};
+-
+-struct mtk_eth_priv {
+-      char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
+-
+-      void *tx_ring_noc;
+-      void *rx_ring_noc;
+-
+-      int rx_dma_owner_idx0;
+-      int tx_cpu_owner_idx0;
+-
+-      void __iomem *fe_base;
+-      void __iomem *gmac_base;
+-      void __iomem *sgmii_base;
+-      void __iomem *gsw_base;
+-
+-      struct regmap *ethsys_regmap;
+-
+-      struct regmap *infra_regmap;
+-
+-      struct regmap *usxgmii_regmap;
+-      struct regmap *xfi_pextp_regmap;
+-      struct regmap *xfi_pll_regmap;
+-      struct regmap *toprgu_regmap;
+-
+-      struct mii_dev *mdio_bus;
+-      int (*mii_read)(struct mtk_eth_priv *priv, u8 phy, u8 reg);
+-      int (*mii_write)(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 val);
+-      int (*mmd_read)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg);
+-      int (*mmd_write)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
+-                       u16 val);
+-
+-      const struct mtk_soc_data *soc;
+-      int gmac_id;
+-      int force_mode;
+-      int speed;
+-      int duplex;
+-      int mdc;
+-      bool pn_swap;
+-
+-      struct phy_device *phydev;
+-      int phy_interface;
+-      int phy_addr;
+-
+-      enum mtk_switch sw;
+-      int (*switch_init)(struct mtk_eth_priv *priv);
+-      void (*switch_mac_control)(struct mtk_eth_priv *priv, bool enable);
+-      u32 mt753x_smi_addr;
+-      u32 mt753x_phy_base;
+-      u32 mt753x_pmcr;
+-      u32 mt753x_reset_wait_time;
+-
+-      struct gpio_desc rst_gpio;
+-      int mcm;
+-
+-      struct reset_ctl rst_fe;
+-      struct reset_ctl rst_mcm;
+-};
+-
+-static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
+-{
+-      writel(val, priv->fe_base + priv->soc->pdma_base + reg);
+-}
+-
+-static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
+-                       u32 set)
+-{
+-      clrsetbits_le32(priv->fe_base + priv->soc->pdma_base + reg, clr, set);
+-}
+-
+-static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg,
+-                         u32 val)
+-{
+-      u32 gdma_base;
+-
+-      if (no == 2)
+-              gdma_base = GDMA3_BASE;
+-      else if (no == 1)
+-              gdma_base = GDMA2_BASE;
+-      else
+-              gdma_base = GDMA1_BASE;
+-
+-      writel(val, priv->fe_base + gdma_base + reg);
+-}
+-
+-static void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
+-{
+-      clrsetbits_le32(priv->fe_base + reg, clr, set);
+-}
+-
+-static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg)
+-{
+-      return readl(priv->gmac_base + reg);
+-}
+-
+-static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
+-{
+-      writel(val, priv->gmac_base + reg);
+-}
+-
+-static void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
+-{
+-      clrsetbits_le32(priv->gmac_base + reg, clr, set);
+-}
+-
+-static void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
+-                         u32 set)
+-{
+-      uint val;
+-
+-      regmap_read(priv->ethsys_regmap, reg, &val);
+-      val &= ~clr;
+-      val |= set;
+-      regmap_write(priv->ethsys_regmap, reg, val);
+-}
+-
+-static void mtk_infra_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
+-                        u32 set)
+-{
+-      uint val;
+-
+-      regmap_read(priv->infra_regmap, reg, &val);
+-      val &= ~clr;
+-      val |= set;
+-      regmap_write(priv->infra_regmap, reg, val);
+-}
+-
+-static u32 mtk_gsw_read(struct mtk_eth_priv *priv, u32 reg)
+-{
+-      return readl(priv->gsw_base + reg);
+-}
+-
+-static void mtk_gsw_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
+-{
+-      writel(val, priv->gsw_base + reg);
+-}
+-
+-/* Direct MDIO clause 22/45 access via SoC */
+-static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data,
+-                    u32 cmd, u32 st)
+-{
+-      int ret;
+-      u32 val;
+-
+-      val = (st << MDIO_ST_S) |
+-            ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
+-            (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
+-            (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
+-
+-      if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
+-              val |= data & MDIO_RW_DATA_M;
+-
+-      mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST);
+-
+-      ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG,
+-                              PHY_ACS_ST, 0, 5000, 0);
+-      if (ret) {
+-              pr_warn("MDIO access timeout\n");
+-              return ret;
+-      }
+-
+-      if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
+-              val = mtk_gmac_read(priv, GMAC_PIAC_REG);
+-              return val & MDIO_RW_DATA_M;
+-      }
+-
+-      return 0;
+-}
+-
+-/* Direct MDIO clause 22 read via SoC */
+-static int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg)
+-{
+-      return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22);
+-}
+-
+-/* Direct MDIO clause 22 write via SoC */
+-static int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data)
+-{
+-      return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22);
+-}
+-
+-/* Direct MDIO clause 45 read via SoC */
+-static int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg)
+-{
+-      int ret;
+-
+-      ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
+-      if (ret)
+-              return ret;
+-
+-      return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45,
+-                        MDIO_ST_C45);
+-}
+-
+-/* Direct MDIO clause 45 write via SoC */
+-static int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad,
+-                       u16 reg, u16 val)
+-{
+-      int ret;
+-
+-      ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
+-      if (ret)
+-              return ret;
+-
+-      return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE,
+-                        MDIO_ST_C45);
+-}
+-
+-/* Indirect MDIO clause 45 read via MII registers */
+-static int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad,
+-                          u16 reg)
+-{
+-      int ret;
+-
+-      ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
+-                            (MMD_ADDR << MMD_CMD_S) |
+-                            ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+-      if (ret)
+-              return ret;
+-
+-      ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
+-      if (ret)
+-              return ret;
+-
+-      ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
+-                            (MMD_DATA << MMD_CMD_S) |
+-                            ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+-      if (ret)
+-              return ret;
+-
+-      return priv->mii_read(priv, addr, MII_MMD_ADDR_DATA_REG);
+-}
+-
+-/* Indirect MDIO clause 45 write via MII registers */
+-static int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad,
+-                           u16 reg, u16 val)
+-{
+-      int ret;
+-
+-      ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
+-                            (MMD_ADDR << MMD_CMD_S) |
+-                            ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+-      if (ret)
+-              return ret;
+-
+-      ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
+-      if (ret)
+-              return ret;
+-
+-      ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
+-                            (MMD_DATA << MMD_CMD_S) |
+-                            ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+-      if (ret)
+-              return ret;
+-
+-      return priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val);
+-}
+-
+-/*
+- * MT7530 Internal Register Address Bits
+- * -------------------------------------------------------------------
+- * | 15  14  13  12  11  10   9   8   7   6 | 5   4   3   2 | 1   0  |
+- * |----------------------------------------|---------------|--------|
+- * |              Page Address              |  Reg Address  | Unused |
+- * -------------------------------------------------------------------
+- */
+-
+-static int mt753x_reg_read(struct mtk_eth_priv *priv, u32 reg, u32 *data)
+-{
+-      int ret, low_word, high_word;
+-
+-      if (priv->sw == SW_MT7988) {
+-              *data = mtk_gsw_read(priv, reg);
+-              return 0;
+-      }
+-
+-      /* Write page address */
+-      ret = mtk_mii_write(priv, priv->mt753x_smi_addr, 0x1f, reg >> 6);
+-      if (ret)
+-              return ret;
+-
+-      /* Read low word */
+-      low_word = mtk_mii_read(priv, priv->mt753x_smi_addr, (reg >> 2) & 0xf);
+-      if (low_word < 0)
+-              return low_word;
+-
+-      /* Read high word */
+-      high_word = mtk_mii_read(priv, priv->mt753x_smi_addr, 0x10);
+-      if (high_word < 0)
+-              return high_word;
+-
+-      if (data)
+-              *data = ((u32)high_word << 16) | (low_word & 0xffff);
+-
+-      return 0;
+-}
+-
+-static int mt753x_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 data)
+-{
+-      int ret;
+-
+-      if (priv->sw == SW_MT7988) {
+-              mtk_gsw_write(priv, reg, data);
+-              return 0;
+-      }
+-
+-      /* Write page address */
+-      ret = mtk_mii_write(priv, priv->mt753x_smi_addr, 0x1f, reg >> 6);
+-      if (ret)
+-              return ret;
+-
+-      /* Write low word */
+-      ret = mtk_mii_write(priv, priv->mt753x_smi_addr, (reg >> 2) & 0xf,
+-                          data & 0xffff);
+-      if (ret)
+-              return ret;
+-
+-      /* Write high word */
+-      return mtk_mii_write(priv, priv->mt753x_smi_addr, 0x10, data >> 16);
+-}
+-
+-static void mt753x_reg_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
+-                         u32 set)
+-{
+-      u32 val;
+-
+-      mt753x_reg_read(priv, reg, &val);
+-      val &= ~clr;
+-      val |= set;
+-      mt753x_reg_write(priv, reg, val);
+-}
+-
+-/* Indirect MDIO clause 22/45 access */
+-static int mt7531_mii_rw(struct mtk_eth_priv *priv, int phy, int reg, u16 data,
+-                       u32 cmd, u32 st)
+-{
+-      ulong timeout;
+-      u32 val, timeout_ms;
+-      int ret = 0;
+-
+-      val = (st << MDIO_ST_S) |
+-            ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
+-            ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
+-            ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
+-
+-      if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
+-              val |= data & MDIO_RW_DATA_M;
+-
+-      mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST);
+-
+-      timeout_ms = 100;
+-      timeout = get_timer(0);
+-      while (1) {
+-              mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
+-
+-              if ((val & PHY_ACS_ST) == 0)
+-                      break;
+-
+-              if (get_timer(timeout) > timeout_ms)
+-                      return -ETIMEDOUT;
+-      }
+-
+-      if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
+-              mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
+-              ret = val & MDIO_RW_DATA_M;
+-      }
+-
+-      return ret;
+-}
+-
+-static int mt7531_mii_ind_read(struct mtk_eth_priv *priv, u8 phy, u8 reg)
+-{
+-      u8 phy_addr;
+-
+-      if (phy >= MT753X_NUM_PHYS)
+-              return -EINVAL;
+-
+-      phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, phy);
+-
+-      return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ,
+-                           MDIO_ST_C22);
+-}
+-
+-static int mt7531_mii_ind_write(struct mtk_eth_priv *priv, u8 phy, u8 reg,
+-                              u16 val)
+-{
+-      u8 phy_addr;
+-
+-      if (phy >= MT753X_NUM_PHYS)
+-              return -EINVAL;
+-
+-      phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, phy);
+-
+-      return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE,
+-                           MDIO_ST_C22);
+-}
+-
+-static int mt7531_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad,
+-                             u16 reg)
+-{
+-      u8 phy_addr;
+-      int ret;
+-
+-      if (addr >= MT753X_NUM_PHYS)
+-              return -EINVAL;
+-
+-      phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, addr);
+-
+-      ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
+-                          MDIO_ST_C45);
+-      if (ret)
+-              return ret;
+-
+-      return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45,
+-                           MDIO_ST_C45);
+-}
+-
+-static int mt7531_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad,
+-                              u16 reg, u16 val)
+-{
+-      u8 phy_addr;
+-      int ret;
+-
+-      if (addr >= MT753X_NUM_PHYS)
+-              return 0;
+-
+-      phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, addr);
+-
+-      ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
+-                          MDIO_ST_C45);
+-      if (ret)
+-              return ret;
+-
+-      return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE,
+-                           MDIO_ST_C45);
+-}
+-
+-static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+-{
+-      struct mtk_eth_priv *priv = bus->priv;
+-
+-      if (devad < 0)
+-              return priv->mii_read(priv, addr, reg);
+-      else
+-              return priv->mmd_read(priv, addr, devad, reg);
+-}
+-
+-static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+-                        u16 val)
+-{
+-      struct mtk_eth_priv *priv = bus->priv;
+-
+-      if (devad < 0)
+-              return priv->mii_write(priv, addr, reg, val);
+-      else
+-              return priv->mmd_write(priv, addr, devad, reg, val);
+-}
+-
+-static int mtk_mdio_register(struct udevice *dev)
+-{
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-      struct mii_dev *mdio_bus = mdio_alloc();
+-      int ret;
+-
+-      if (!mdio_bus)
+-              return -ENOMEM;
+-
+-      /* Assign MDIO access APIs according to the switch/phy */
+-      switch (priv->sw) {
+-      case SW_MT7530:
+-              priv->mii_read = mtk_mii_read;
+-              priv->mii_write = mtk_mii_write;
+-              priv->mmd_read = mtk_mmd_ind_read;
+-              priv->mmd_write = mtk_mmd_ind_write;
+-              break;
+-      case SW_MT7531:
+-      case SW_MT7988:
+-              priv->mii_read = mt7531_mii_ind_read;
+-              priv->mii_write = mt7531_mii_ind_write;
+-              priv->mmd_read = mt7531_mmd_ind_read;
+-              priv->mmd_write = mt7531_mmd_ind_write;
+-              break;
+-      default:
+-              priv->mii_read = mtk_mii_read;
+-              priv->mii_write = mtk_mii_write;
+-              priv->mmd_read = mtk_mmd_read;
+-              priv->mmd_write = mtk_mmd_write;
+-      }
+-
+-      mdio_bus->read = mtk_mdio_read;
+-      mdio_bus->write = mtk_mdio_write;
+-      snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
+-
+-      mdio_bus->priv = (void *)priv;
+-
+-      ret = mdio_register(mdio_bus);
+-
+-      if (ret)
+-              return ret;
+-
+-      priv->mdio_bus = mdio_bus;
+-
+-      return 0;
+-}
+-
+-static int mt753x_core_reg_read(struct mtk_eth_priv *priv, u32 reg)
+-{
+-      u8 phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, 0);
+-
+-      return priv->mmd_read(priv, phy_addr, 0x1f, reg);
+-}
+-
+-static void mt753x_core_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
+-{
+-      u8 phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, 0);
+-
+-      priv->mmd_write(priv, phy_addr, 0x1f, reg, val);
+-}
+-
+-static int mt7530_pad_clk_setup(struct mtk_eth_priv *priv, int mode)
+-{
+-      u32 ncpo1, ssc_delta;
+-
+-      switch (mode) {
+-      case PHY_INTERFACE_MODE_RGMII:
+-              ncpo1 = 0x0c80;
+-              ssc_delta = 0x87;
+-              break;
+-      default:
+-              printf("error: xMII mode %d not supported\n", mode);
+-              return -EINVAL;
+-      }
+-
+-      /* Disable MT7530 core clock */
+-      mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0);
+-
+-      /* Disable MT7530 PLL */
+-      mt753x_core_reg_write(priv, CORE_GSWPLL_GRP1,
+-                            (2 << RG_GSWPLL_POSDIV_200M_S) |
+-                            (32 << RG_GSWPLL_FBKDIV_200M_S));
+-
+-      /* For MT7530 core clock = 500Mhz */
+-      mt753x_core_reg_write(priv, CORE_GSWPLL_GRP2,
+-                            (1 << RG_GSWPLL_POSDIV_500M_S) |
+-                            (25 << RG_GSWPLL_FBKDIV_500M_S));
+-
+-      /* Enable MT7530 PLL */
+-      mt753x_core_reg_write(priv, CORE_GSWPLL_GRP1,
+-                            (2 << RG_GSWPLL_POSDIV_200M_S) |
+-                            (32 << RG_GSWPLL_FBKDIV_200M_S) |
+-                            RG_GSWPLL_EN_PRE);
+-
+-      udelay(20);
+-
+-      mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
+-
+-      /* Setup the MT7530 TRGMII Tx Clock */
+-      mt753x_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1);
+-      mt753x_core_reg_write(priv, CORE_PLL_GROUP6, 0);
+-      mt753x_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta);
+-      mt753x_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta);
+-      mt753x_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
+-                            RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
+-
+-      mt753x_core_reg_write(priv, CORE_PLL_GROUP2,
+-                            RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
+-                            (1 << RG_SYSPLL_POSDIV_S));
+-
+-      mt753x_core_reg_write(priv, CORE_PLL_GROUP7,
+-                            RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) |
+-                            RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
+-
+-      /* Enable MT7530 core clock */
+-      mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG,
+-                            REG_GSWCK_EN | REG_TRGMIICK_EN);
+-
+-      return 0;
+-}
+-
+-static void mt7530_mac_control(struct mtk_eth_priv *priv, bool enable)
+-{
+-      u32 pmcr = FORCE_MODE;
+-
+-      if (enable)
+-              pmcr = priv->mt753x_pmcr;
+-
+-      mt753x_reg_write(priv, PMCR_REG(6), pmcr);
+-}
+-
+-static int mt7530_setup(struct mtk_eth_priv *priv)
+-{
+-      u16 phy_addr, phy_val;
+-      u32 val, txdrv;
+-      int i;
+-
+-      if (!MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
+-              /* Select 250MHz clk for RGMII mode */
+-              mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG,
+-                             ETHSYS_TRGMII_CLK_SEL362_5, 0);
+-
+-              txdrv = 8;
+-      } else {
+-              txdrv = 4;
+-      }
+-
+-      /* Modify HWTRAP first to allow direct access to internal PHYs */
+-      mt753x_reg_read(priv, HWTRAP_REG, &val);
+-      val |= CHG_TRAP;
+-      val &= ~C_MDIO_BPS;
+-      mt753x_reg_write(priv, MHWTRAP_REG, val);
+-
+-      /* Calculate the phy base address */
+-      val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3;
+-      priv->mt753x_phy_base = (val | 0x7) + 1;
+-
+-      /* Turn off PHYs */
+-      for (i = 0; i < MT753X_NUM_PHYS; i++) {
+-              phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
+-              phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
+-              phy_val |= BMCR_PDOWN;
+-              priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
+-      }
+-
+-      /* Force MAC link down before reset */
+-      mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
+-      mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
+-
+-      /* MT7530 reset */
+-      mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
+-      udelay(100);
+-
+-      val = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+-            MAC_MODE | FORCE_MODE |
+-            MAC_TX_EN | MAC_RX_EN |
+-            BKOFF_EN | BACKPR_EN |
+-            (SPEED_1000M << FORCE_SPD_S) |
+-            FORCE_DPX | FORCE_LINK;
+-
+-      /* MT7530 Port6: Forced 1000M/FD, FC disabled */
+-      priv->mt753x_pmcr = val;
+-
+-      /* MT7530 Port5: Forced link down */
+-      mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
+-
+-      /* Keep MAC link down before starting eth */
+-      mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
+-
+-      /* MT7530 Port6: Set to RGMII */
+-      mt753x_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII);
+-
+-      /* Hardware Trap: Enable Port6, Disable Port5 */
+-      mt753x_reg_read(priv, HWTRAP_REG, &val);
+-      val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS |
+-             (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) |
+-             (P5_INTF_MODE_RGMII << P5_INTF_MODE_S);
+-      val &= ~(C_MDIO_BPS | P6_INTF_DIS);
+-      mt753x_reg_write(priv, MHWTRAP_REG, val);
+-
+-      /* Setup switch core pll */
+-      mt7530_pad_clk_setup(priv, priv->phy_interface);
+-
+-      /* Lower Tx Driving for TRGMII path */
+-      for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
+-              mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i),
+-                               (txdrv << TD_DM_DRVP_S) |
+-                               (txdrv << TD_DM_DRVN_S));
+-
+-      for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
+-              mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16);
+-
+-      /* Turn on PHYs */
+-      for (i = 0; i < MT753X_NUM_PHYS; i++) {
+-              phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
+-              phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
+-              phy_val &= ~BMCR_PDOWN;
+-              priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
+-      }
+-
+-      return 0;
+-}
+-
+-static void mt7531_core_pll_setup(struct mtk_eth_priv *priv, int mcm)
+-{
+-      /* Step 1 : Disable MT7531 COREPLL */
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, 0);
+-
+-      /* Step 2: switch to XTAL output */
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_CLKSW, SW_CLKSW);
+-
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, 0);
+-
+-      /* Step 3: disable PLLGP and enable program PLLGP */
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_PLLGP, SW_PLLGP);
+-
+-      /* Step 4: program COREPLL output frequency to 500MHz */
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_POSDIV_M,
+-                     2 << RG_COREPLL_POSDIV_S);
+-      udelay(25);
+-
+-      /* Currently, support XTAL 25Mhz only */
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_M,
+-                     0x140000 << RG_COREPLL_SDM_PCW_S);
+-
+-      /* Set feedback divide ratio update signal to high */
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG,
+-                     RG_COREPLL_SDM_PCW_CHG);
+-
+-      /* Wait for at least 16 XTAL clocks */
+-      udelay(10);
+-
+-      /* Step 5: set feedback divide ratio update signal to low */
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, 0);
+-
+-      /* add enable 325M clock for SGMII */
+-      mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
+-
+-      /* add enable 250SSC clock for RGMII */
+-      mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
+-
+-      /*Step 6: Enable MT7531 PLL */
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, RG_COREPLL_EN);
+-
+-      mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, EN_COREPLL);
+-
+-      udelay(25);
+-}
+-
+-static int mt7531_port_sgmii_init(struct mtk_eth_priv *priv,
+-                                u32 port)
+-{
+-      if (port != 5 && port != 6) {
+-              printf("mt7531: port %d is not a SGMII port\n", port);
+-              return -EINVAL;
+-      }
+-
+-      /* Set SGMII GEN2 speed(2.5G) */
+-      mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK,
+-                     FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
+-
+-      /* Disable SGMII AN */
+-      mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port),
+-                     SGMII_AN_ENABLE, 0);
+-
+-      /* SGMII force mode setting */
+-      mt753x_reg_write(priv, MT7531_SGMII_MODE(port), SGMII_FORCE_MODE);
+-
+-      /* Release PHYA power down state */
+-      mt753x_reg_rmw(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
+-                     SGMII_PHYA_PWD, 0);
+-
+-      return 0;
+-}
+-
+-static int mt7531_port_rgmii_init(struct mtk_eth_priv *priv, u32 port)
+-{
+-      u32 val;
+-
+-      if (port != 5) {
+-              printf("error: RGMII mode is not available for port %d\n",
+-                     port);
+-              return -EINVAL;
+-      }
+-
+-      mt753x_reg_read(priv, MT7531_CLKGEN_CTRL, &val);
+-      val |= GP_CLK_EN;
+-      val &= ~GP_MODE_M;
+-      val |= GP_MODE_RGMII << GP_MODE_S;
+-      val |= TXCLK_NO_REVERSE;
+-      val |= RXCLK_NO_DELAY;
+-      val &= ~CLK_SKEW_IN_M;
+-      val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S;
+-      val &= ~CLK_SKEW_OUT_M;
+-      val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S;
+-      mt753x_reg_write(priv, MT7531_CLKGEN_CTRL, val);
+-
+-      return 0;
+-}
+-
+-static void mt7531_phy_setting(struct mtk_eth_priv *priv)
+-{
+-      int i;
+-      u32 val;
+-
+-      for (i = 0; i < MT753X_NUM_PHYS; i++) {
+-              /* Enable HW auto downshift */
+-              priv->mii_write(priv, i, 0x1f, 0x1);
+-              val = priv->mii_read(priv, i, PHY_EXT_REG_14);
+-              val |= PHY_EN_DOWN_SHFIT;
+-              priv->mii_write(priv, i, PHY_EXT_REG_14, val);
+-
+-              /* PHY link down power saving enable */
+-              val = priv->mii_read(priv, i, PHY_EXT_REG_17);
+-              val |= PHY_LINKDOWN_POWER_SAVING_EN;
+-              priv->mii_write(priv, i, PHY_EXT_REG_17, val);
+-
+-              val = priv->mmd_read(priv, i, 0x1e, PHY_DEV1E_REG_0C6);
+-              val &= ~PHY_POWER_SAVING_M;
+-              val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
+-              priv->mmd_write(priv, i, 0x1e, PHY_DEV1E_REG_0C6, val);
+-      }
+-}
+-
+-static void mt7531_mac_control(struct mtk_eth_priv *priv, bool enable)
+-{
+-      u32 pmcr = FORCE_MODE_LNK;
+-
+-      if (enable)
+-              pmcr = priv->mt753x_pmcr;
+-
+-      mt753x_reg_write(priv, PMCR_REG(5), pmcr);
+-      mt753x_reg_write(priv, PMCR_REG(6), pmcr);
+-}
+-
+-static int mt7531_setup(struct mtk_eth_priv *priv)
+-{
+-      u16 phy_addr, phy_val;
+-      u32 val;
+-      u32 pmcr;
+-      u32 port5_sgmii;
+-      int i;
+-
+-      priv->mt753x_phy_base = (priv->mt753x_smi_addr + 1) &
+-                              MT753X_SMI_ADDR_MASK;
+-
+-      /* Turn off PHYs */
+-      for (i = 0; i < MT753X_NUM_PHYS; i++) {
+-              phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
+-              phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
+-              phy_val |= BMCR_PDOWN;
+-              priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
+-      }
+-
+-      /* Force MAC link down before reset */
+-      mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
+-      mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
+-
+-      /* Switch soft reset */
+-      mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
+-      udelay(100);
+-
+-      /* Enable MDC input Schmitt Trigger */
+-      mt753x_reg_rmw(priv, MT7531_SMT0_IOLB, SMT_IOLB_5_SMI_MDC_EN,
+-                     SMT_IOLB_5_SMI_MDC_EN);
+-
+-      mt7531_core_pll_setup(priv, priv->mcm);
+-
+-      mt753x_reg_read(priv, MT7531_TOP_SIG_SR, &val);
+-      port5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
+-
+-      /* port5 support either RGMII or SGMII, port6 only support SGMII. */
+-      switch (priv->phy_interface) {
+-      case PHY_INTERFACE_MODE_RGMII:
+-              if (!port5_sgmii)
+-                      mt7531_port_rgmii_init(priv, 5);
+-              break;
+-      case PHY_INTERFACE_MODE_2500BASEX:
+-              mt7531_port_sgmii_init(priv, 6);
+-              if (port5_sgmii)
+-                      mt7531_port_sgmii_init(priv, 5);
+-              break;
+-      default:
+-              break;
+-      }
+-
+-      pmcr = MT7531_FORCE_MODE |
+-             (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+-             MAC_MODE | MAC_TX_EN | MAC_RX_EN |
+-             BKOFF_EN | BACKPR_EN |
+-             FORCE_RX_FC | FORCE_TX_FC |
+-             (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
+-             FORCE_LINK;
+-
+-      priv->mt753x_pmcr = pmcr;
+-
+-      /* Keep MAC link down before starting eth */
+-      mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
+-      mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
+-
+-      /* Turn on PHYs */
+-      for (i = 0; i < MT753X_NUM_PHYS; i++) {
+-              phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
+-              phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
+-              phy_val &= ~BMCR_PDOWN;
+-              priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
+-      }
+-
+-      mt7531_phy_setting(priv);
+-
+-      /* Enable Internal PHYs */
+-      val = mt753x_core_reg_read(priv, CORE_PLL_GROUP4);
+-      val |= MT7531_BYPASS_MODE;
+-      val &= ~MT7531_POWER_ON_OFF;
+-      mt753x_core_reg_write(priv, CORE_PLL_GROUP4, val);
+-
+-      return 0;
+-}
+-
+-static void mt7988_phy_setting(struct mtk_eth_priv *priv)
+-{
+-      u16 val;
+-      u32 i;
+-
+-      for (i = 0; i < MT753X_NUM_PHYS; i++) {
+-              /* Enable HW auto downshift */
+-              priv->mii_write(priv, i, 0x1f, 0x1);
+-              val = priv->mii_read(priv, i, PHY_EXT_REG_14);
+-              val |= PHY_EN_DOWN_SHFIT;
+-              priv->mii_write(priv, i, PHY_EXT_REG_14, val);
+-
+-              /* PHY link down power saving enable */
+-              val = priv->mii_read(priv, i, PHY_EXT_REG_17);
+-              val |= PHY_LINKDOWN_POWER_SAVING_EN;
+-              priv->mii_write(priv, i, PHY_EXT_REG_17, val);
+-      }
+-}
+-
+-static void mt7988_mac_control(struct mtk_eth_priv *priv, bool enable)
+-{
+-      u32 pmcr = FORCE_MODE_LNK;
+-
+-      if (enable)
+-              pmcr = priv->mt753x_pmcr;
+-
+-      mt753x_reg_write(priv, PMCR_REG(6), pmcr);
+-}
+-
+-static int mt7988_setup(struct mtk_eth_priv *priv)
+-{
+-      u16 phy_addr, phy_val;
+-      u32 pmcr;
+-      int i;
+-
+-      priv->gsw_base = regmap_get_range(priv->ethsys_regmap, 0) + GSW_BASE;
+-
+-      priv->mt753x_phy_base = (priv->mt753x_smi_addr + 1) &
+-                              MT753X_SMI_ADDR_MASK;
+-
+-      /* Turn off PHYs */
+-      for (i = 0; i < MT753X_NUM_PHYS; i++) {
+-              phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
+-              phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
+-              phy_val |= BMCR_PDOWN;
+-              priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
+-      }
+-
+-      switch (priv->phy_interface) {
+-      case PHY_INTERFACE_MODE_USXGMII:
+-              /* Use CPU bridge instead of actual USXGMII path */
+-
+-              /* Set GDM1 no drop */
+-              mtk_fe_rmw(priv, PSE_NO_DROP_CFG_REG, 0, PSE_NO_DROP_GDM1);
+-
+-              /* Enable GDM1 to GSW CPU bridge */
+-              mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, BIT(0));
+-
+-              /* XGMAC force link up */
+-              mtk_gmac_rmw(priv, GMAC_XGMAC_STS_REG, 0, P1_XGMAC_FORCE_LINK);
+-
+-              /* Setup GSW CPU bridge IPG */
+-              mtk_gmac_rmw(priv, GMAC_GSW_CFG_REG, GSWTX_IPG_M | GSWRX_IPG_M,
+-                           (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S));
+-              break;
+-      default:
+-              printf("Error: MT7988 GSW does not support %s interface\n",
+-                     phy_string_for_interface(priv->phy_interface));
+-              break;
+-      }
+-
+-      pmcr = MT7988_FORCE_MODE |
+-             (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+-             MAC_MODE | MAC_TX_EN | MAC_RX_EN |
+-             BKOFF_EN | BACKPR_EN |
+-             FORCE_RX_FC | FORCE_TX_FC |
+-             (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
+-             FORCE_LINK;
+-
+-      priv->mt753x_pmcr = pmcr;
+-
+-      /* Keep MAC link down before starting eth */
+-      mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
+-
+-      /* Turn on PHYs */
+-      for (i = 0; i < MT753X_NUM_PHYS; i++) {
+-              phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
+-              phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
+-              phy_val &= ~BMCR_PDOWN;
+-              priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
+-      }
+-
+-      mt7988_phy_setting(priv);
+-
+-      return 0;
+-}
+-
+-static int mt753x_switch_init(struct mtk_eth_priv *priv)
+-{
+-      int ret;
+-      int i;
+-
+-      /* Global reset switch */
+-      if (priv->mcm) {
+-              reset_assert(&priv->rst_mcm);
+-              udelay(1000);
+-              reset_deassert(&priv->rst_mcm);
+-              mdelay(priv->mt753x_reset_wait_time);
+-      } else if (dm_gpio_is_valid(&priv->rst_gpio)) {
+-              dm_gpio_set_value(&priv->rst_gpio, 0);
+-              udelay(1000);
+-              dm_gpio_set_value(&priv->rst_gpio, 1);
+-              mdelay(priv->mt753x_reset_wait_time);
+-      }
+-
+-      ret = priv->switch_init(priv);
+-      if (ret)
+-              return ret;
+-
+-      /* Set port isolation */
+-      for (i = 0; i < MT753X_NUM_PORTS; i++) {
+-              /* Set port matrix mode */
+-              if (i != 6)
+-                      mt753x_reg_write(priv, PCR_REG(i),
+-                                       (0x40 << PORT_MATRIX_S));
+-              else
+-                      mt753x_reg_write(priv, PCR_REG(i),
+-                                       (0x3f << PORT_MATRIX_S));
+-
+-              /* Set port mode to user port */
+-              mt753x_reg_write(priv, PVC_REG(i),
+-                               (0x8100 << STAG_VPID_S) |
+-                               (VLAN_ATTR_USER << VLAN_ATTR_S));
+-      }
+-
+-      return 0;
+-}
+-
+-static void mtk_xphy_link_adjust(struct mtk_eth_priv *priv)
+-{
+-      u16 lcl_adv = 0, rmt_adv = 0;
+-      u8 flowctrl;
+-      u32 mcr;
+-
+-      mcr = mtk_gmac_read(priv, XGMAC_PORT_MCR(priv->gmac_id));
+-      mcr &= ~(XGMAC_FORCE_TX_FC | XGMAC_FORCE_RX_FC);
+-
+-      if (priv->phydev->duplex) {
+-              if (priv->phydev->pause)
+-                      rmt_adv = LPA_PAUSE_CAP;
+-              if (priv->phydev->asym_pause)
+-                      rmt_adv |= LPA_PAUSE_ASYM;
+-
+-              if (priv->phydev->advertising & ADVERTISED_Pause)
+-                      lcl_adv |= ADVERTISE_PAUSE_CAP;
+-              if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
+-                      lcl_adv |= ADVERTISE_PAUSE_ASYM;
+-
+-              flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+-
+-              if (flowctrl & FLOW_CTRL_TX)
+-                      mcr |= XGMAC_FORCE_TX_FC;
+-              if (flowctrl & FLOW_CTRL_RX)
+-                      mcr |= XGMAC_FORCE_RX_FC;
+-
+-              debug("rx pause %s, tx pause %s\n",
+-                    flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
+-                    flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
+-      }
+-
+-      mcr &= ~(XGMAC_TRX_DISABLE);
+-      mtk_gmac_write(priv, XGMAC_PORT_MCR(priv->gmac_id), mcr);
+-}
+-
+-static void mtk_phy_link_adjust(struct mtk_eth_priv *priv)
+-{
+-      u16 lcl_adv = 0, rmt_adv = 0;
+-      u8 flowctrl;
+-      u32 mcr;
+-
+-      mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+-            (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
+-            MAC_MODE | FORCE_MODE |
+-            MAC_TX_EN | MAC_RX_EN |
+-            DEL_RXFIFO_CLR |
+-            BKOFF_EN | BACKPR_EN;
+-
+-      switch (priv->phydev->speed) {
+-      case SPEED_10:
+-              mcr |= (SPEED_10M << FORCE_SPD_S);
+-              break;
+-      case SPEED_100:
+-              mcr |= (SPEED_100M << FORCE_SPD_S);
+-              break;
+-      case SPEED_1000:
+-      case SPEED_2500:
+-              mcr |= (SPEED_1000M << FORCE_SPD_S);
+-              break;
+-      };
+-
+-      if (priv->phydev->link)
+-              mcr |= FORCE_LINK;
+-
+-      if (priv->phydev->duplex) {
+-              mcr |= FORCE_DPX;
+-
+-              if (priv->phydev->pause)
+-                      rmt_adv = LPA_PAUSE_CAP;
+-              if (priv->phydev->asym_pause)
+-                      rmt_adv |= LPA_PAUSE_ASYM;
+-
+-              if (priv->phydev->advertising & ADVERTISED_Pause)
+-                      lcl_adv |= ADVERTISE_PAUSE_CAP;
+-              if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
+-                      lcl_adv |= ADVERTISE_PAUSE_ASYM;
+-
+-              flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+-
+-              if (flowctrl & FLOW_CTRL_TX)
+-                      mcr |= FORCE_TX_FC;
+-              if (flowctrl & FLOW_CTRL_RX)
+-                      mcr |= FORCE_RX_FC;
+-
+-              debug("rx pause %s, tx pause %s\n",
+-                    flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
+-                    flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
+-      }
+-
+-      mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
+-}
+-
+-static int mtk_phy_start(struct mtk_eth_priv *priv)
+-{
+-      struct phy_device *phydev = priv->phydev;
+-      int ret;
+-
+-      ret = phy_startup(phydev);
+-
+-      if (ret) {
+-              debug("Could not initialize PHY %s\n", phydev->dev->name);
+-              return ret;
+-      }
+-
+-      if (!phydev->link) {
+-              debug("%s: link down.\n", phydev->dev->name);
+-              return 0;
+-      }
+-
+-      if (!priv->force_mode) {
+-              if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+-                  priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
+-                  priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
+-                      mtk_xphy_link_adjust(priv);
+-              else
+-                      mtk_phy_link_adjust(priv);
+-      }
+-
+-      debug("Speed: %d, %s duplex%s\n", phydev->speed,
+-            (phydev->duplex) ? "full" : "half",
+-            (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
+-
+-      return 0;
+-}
+-
+-static int mtk_phy_probe(struct udevice *dev)
+-{
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-      struct phy_device *phydev;
+-
+-      phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev,
+-                           priv->phy_interface);
+-      if (!phydev)
+-              return -ENODEV;
+-
+-      phydev->supported &= PHY_GBIT_FEATURES;
+-      phydev->advertising = phydev->supported;
+-
+-      priv->phydev = phydev;
+-      phy_config(phydev);
+-
+-      return 0;
+-}
+-
+-static void mtk_sgmii_an_init(struct mtk_eth_priv *priv)
+-{
+-      /* Set SGMII GEN1 speed(1G) */
+-      clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK);
+-
+-      /* Enable SGMII AN */
+-      setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
+-                   SGMII_AN_ENABLE);
+-
+-      /* SGMII AN mode setting */
+-      writel(SGMII_AN_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
+-
+-      /* SGMII PN SWAP setting */
+-      if (priv->pn_swap) {
+-              setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
+-                           SGMII_PN_SWAP_TX_RX);
+-      }
+-
+-      /* Release PHYA power down state */
+-      clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
+-                      SGMII_PHYA_PWD, 0);
+-}
+-
+-static void mtk_sgmii_force_init(struct mtk_eth_priv *priv)
+-{
+-      /* Set SGMII GEN2 speed(2.5G) */
+-      clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
+-                      SGMSYS_SPEED_MASK,
+-                      FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
+-
+-      /* Disable SGMII AN */
+-      clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
+-                      SGMII_AN_ENABLE, 0);
+-
+-      /* SGMII force mode setting */
+-      writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
+-
+-      /* SGMII PN SWAP setting */
+-      if (priv->pn_swap) {
+-              setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
+-                           SGMII_PN_SWAP_TX_RX);
+-      }
+-
+-      /* Release PHYA power down state */
+-      clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
+-                      SGMII_PHYA_PWD, 0);
+-}
+-
+-static void mtk_xfi_pll_enable(struct mtk_eth_priv *priv)
+-{
+-      u32 val = 0;
+-
+-      /* Add software workaround for USXGMII PLL TCL issue */
+-      regmap_write(priv->xfi_pll_regmap, XFI_PLL_ANA_GLB8,
+-                   RG_XFI_PLL_ANA_SWWA);
+-
+-      regmap_read(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, &val);
+-      val |= RG_XFI_PLL_EN;
+-      regmap_write(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, val);
+-}
+-
+-static void mtk_usxgmii_reset(struct mtk_eth_priv *priv)
+-{
+-      switch (priv->gmac_id) {
+-      case 1:
+-              regmap_write(priv->toprgu_regmap, 0xFC, 0x0000A004);
+-              regmap_write(priv->toprgu_regmap, 0x18, 0x88F0A004);
+-              regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
+-              regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
+-              regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
+-              break;
+-      case 2:
+-              regmap_write(priv->toprgu_regmap, 0xFC, 0x00005002);
+-              regmap_write(priv->toprgu_regmap, 0x18, 0x88F05002);
+-              regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
+-              regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
+-              regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
+-              break;
+-      }
+-
+-      mdelay(10);
+-}
+-
+-static void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth_priv *priv)
+-{
+-      regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6D);
+-      regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
+-      regmap_write(priv->usxgmii_regmap, 0x80C, 0x30000000);
+-      ndelay(1020);
+-      regmap_write(priv->usxgmii_regmap, 0x80C, 0x10000000);
+-      ndelay(1020);
+-      regmap_write(priv->usxgmii_regmap, 0x80C, 0x00000000);
+-
+-      regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
+-      regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
+-      regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
+-      regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
+-      regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
+-      regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
+-      regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
+-      regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
+-      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
+-      ndelay(1020);
+-      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
+-      regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x40704000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3050, 0xA8000000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x000000AA);
+-      regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
+-      regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
+-      udelay(150);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
+-      ndelay(1020);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
+-      udelay(15);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
+-      ndelay(1020);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
+-      udelay(100);
+-      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
+-      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
+-      udelay(400);
+-}
+-
+-static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv)
+-{
+-      regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C);
+-      regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
+-      regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000);
+-      ndelay(1020);
+-      regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000);
+-      ndelay(1020);
+-
+-      regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
+-      regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
+-      regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
+-      regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
+-      regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
+-      regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
+-      regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
+-      regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
+-      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
+-      ndelay(1020);
+-      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
+-      regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
+-      regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
+-      regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
+-      if (priv->gmac_id == 2)
+-              regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400);
+-      regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
+-      regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
+-      udelay(150);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
+-      ndelay(1020);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
+-      udelay(15);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
+-      ndelay(1020);
+-      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
+-      udelay(100);
+-      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
+-      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
+-      regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
+-      udelay(400);
+-}
+-
+-static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv)
+-{
+-      mtk_xfi_pll_enable(priv);
+-      mtk_usxgmii_reset(priv);
+-      mtk_usxgmii_setup_phya_an_10000(priv);
+-}
+-
+-static void mtk_10gbaser_init(struct mtk_eth_priv *priv)
+-{
+-      mtk_xfi_pll_enable(priv);
+-      mtk_usxgmii_reset(priv);
+-      mtk_usxgmii_setup_phya_force_10000(priv);
+-}
+-
+-static int mtk_mac_init(struct mtk_eth_priv *priv)
+-{
+-      int i, sgmii_sel_mask = 0, ge_mode = 0;
+-      u32 mcr;
+-
+-      if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) {
+-              mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG,
+-                            INFRA_MISC2_BONDING_OPTION, priv->gmac_id);
+-      }
+-
+-      switch (priv->phy_interface) {
+-      case PHY_INTERFACE_MODE_RGMII_RXID:
+-      case PHY_INTERFACE_MODE_RGMII:
+-              ge_mode = GE_MODE_RGMII;
+-              break;
+-      case PHY_INTERFACE_MODE_SGMII:
+-      case PHY_INTERFACE_MODE_2500BASEX:
+-              if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
+-                      printf("Error: SGMII is not supported on this platform\n");
+-                      return -ENOTSUPP;
+-              }
+-
+-              if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) {
+-                      mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK,
+-                                    SGMII_QPHY_SEL);
+-              }
+-
+-              if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII))
+-                      sgmii_sel_mask = SYSCFG1_SGMII_SEL_M;
+-
+-              mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask,
+-                             SYSCFG1_SGMII_SEL(priv->gmac_id));
+-
+-              if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
+-                      mtk_sgmii_an_init(priv);
+-              else
+-                      mtk_sgmii_force_init(priv);
+-
+-              ge_mode = GE_MODE_RGMII;
+-              break;
+-      case PHY_INTERFACE_MODE_MII:
+-      case PHY_INTERFACE_MODE_GMII:
+-              ge_mode = GE_MODE_MII;
+-              break;
+-      case PHY_INTERFACE_MODE_RMII:
+-              ge_mode = GE_MODE_RMII;
+-              break;
+-      default:
+-              break;
+-      }
+-
+-      /* set the gmac to the right mode */
+-      mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
+-                     SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
+-                     ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id));
+-
+-      if (priv->force_mode) {
+-              mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+-                    (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
+-                    MAC_MODE | FORCE_MODE |
+-                    MAC_TX_EN | MAC_RX_EN |
+-                    BKOFF_EN | BACKPR_EN |
+-                    FORCE_LINK;
+-
+-              switch (priv->speed) {
+-              case SPEED_10:
+-                      mcr |= SPEED_10M << FORCE_SPD_S;
+-                      break;
+-              case SPEED_100:
+-                      mcr |= SPEED_100M << FORCE_SPD_S;
+-                      break;
+-              case SPEED_1000:
+-              case SPEED_2500:
+-                      mcr |= SPEED_1000M << FORCE_SPD_S;
+-                      break;
+-              }
+-
+-              if (priv->duplex)
+-                      mcr |= FORCE_DPX;
+-
+-              mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
+-      }
+-
+-      if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC1_TRGMII) &&
+-          !MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
+-              /* Lower Tx Driving for TRGMII path */
+-              for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
+-                      mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i),
+-                                     (8 << TD_DM_DRVP_S) |
+-                                     (8 << TD_DM_DRVN_S));
+-
+-              mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0,
+-                           RX_RST | RXC_DQSISEL);
+-              mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0);
+-      }
+-
+-      return 0;
+-}
+-
+-static int mtk_xmac_init(struct mtk_eth_priv *priv)
+-{
+-      u32 force_link = 0;
+-
+-      if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
+-              printf("Error: 10Gb interface is not supported on this platform\n");
+-              return -ENOTSUPP;
+-      }
+-
+-      switch (priv->phy_interface) {
+-      case PHY_INTERFACE_MODE_USXGMII:
+-              mtk_usxgmii_an_init(priv);
+-              break;
+-      case PHY_INTERFACE_MODE_10GBASER:
+-              mtk_10gbaser_init(priv);
+-              break;
+-      default:
+-              break;
+-      }
+-
+-      /* Set GMAC to the correct mode */
+-      mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
+-                     SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
+-                     0);
+-
+-      if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+-           priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
+-          priv->gmac_id == 1) {
+-              mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX,
+-                            NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL);
+-      }
+-
+-      if (priv->phy_interface == PHY_INTERFACE_MODE_XGMII ||
+-          priv->gmac_id == 2)
+-              force_link = XGMAC_FORCE_LINK(priv->gmac_id);
+-
+-      mtk_gmac_rmw(priv, XGMAC_STS(priv->gmac_id),
+-                   XGMAC_FORCE_LINK(priv->gmac_id), force_link);
+-
+-      /* Force GMAC link down */
+-      mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE);
+-
+-      return 0;
+-}
+-
+-static void mtk_eth_fifo_init(struct mtk_eth_priv *priv)
+-{
+-      char *pkt_base = priv->pkt_pool;
+-      struct mtk_tx_dma_v2 *txd;
+-      struct mtk_rx_dma_v2 *rxd;
+-      int i;
+-
+-      mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0);
+-      udelay(500);
+-
+-      memset(priv->tx_ring_noc, 0, NUM_TX_DESC * priv->soc->txd_size);
+-      memset(priv->rx_ring_noc, 0, NUM_RX_DESC * priv->soc->rxd_size);
+-      memset(priv->pkt_pool, 0xff, TOTAL_PKT_BUF_SIZE);
+-
+-      flush_dcache_range((ulong)pkt_base,
+-                         (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE));
+-
+-      priv->rx_dma_owner_idx0 = 0;
+-      priv->tx_cpu_owner_idx0 = 0;
+-
+-      for (i = 0; i < NUM_TX_DESC; i++) {
+-              txd = priv->tx_ring_noc + i * priv->soc->txd_size;
+-
+-              txd->txd1 = virt_to_phys(pkt_base);
+-              txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0;
+-
+-              if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+-                      txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id == 2 ?
+-                                                         15 : priv->gmac_id + 1);
+-              else if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
+-                      txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id + 1);
+-              else
+-                      txd->txd4 = PDMA_V1_TXD4_FPORT_SET(priv->gmac_id + 1);
+-
+-              pkt_base += PKTSIZE_ALIGN;
+-      }
+-
+-      for (i = 0; i < NUM_RX_DESC; i++) {
+-              rxd = priv->rx_ring_noc + i * priv->soc->rxd_size;
+-
+-              rxd->rxd1 = virt_to_phys(pkt_base);
+-
+-              if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+-                  MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+-                      rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+-              else
+-                      rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+-
+-              pkt_base += PKTSIZE_ALIGN;
+-      }
+-
+-      mtk_pdma_write(priv, TX_BASE_PTR_REG(0),
+-                     virt_to_phys(priv->tx_ring_noc));
+-      mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC);
+-      mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
+-
+-      mtk_pdma_write(priv, RX_BASE_PTR_REG(0),
+-                     virt_to_phys(priv->rx_ring_noc));
+-      mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC);
+-      mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1);
+-
+-      mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0);
+-}
+-
+-static void mtk_eth_mdc_init(struct mtk_eth_priv *priv)
+-{
+-      u32 divider;
+-
+-      if (priv->mdc == 0)
+-              return;
+-
+-      divider = min_t(u32, DIV_ROUND_UP(MDC_MAX_FREQ, priv->mdc), MDC_MAX_DIVIDER);
+-
+-      /* Configure MDC turbo mode */
+-      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+-              mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, MISC_MDC_TURBO);
+-      else
+-              mtk_gmac_rmw(priv, GMAC_PPSC_REG, 0, MISC_MDC_TURBO);
+-
+-      /* Configure MDC divider */
+-      mtk_gmac_rmw(priv, GMAC_PPSC_REG, PHY_MDC_CFG,
+-                   FIELD_PREP(PHY_MDC_CFG, divider));
+-}
+-
+-static int mtk_eth_start(struct udevice *dev)
+-{
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-      int i, ret;
+-
+-      /* Reset FE */
+-      reset_assert(&priv->rst_fe);
+-      udelay(1000);
+-      reset_deassert(&priv->rst_fe);
+-      mdelay(10);
+-
+-      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+-          MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+-              setbits_le32(priv->fe_base + FE_GLO_MISC_REG, PDMA_VER_V2);
+-
+-      /* Packets forward to PDMA */
+-      mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU);
+-
+-      for (i = 0; i < priv->soc->gdma_count; i++) {
+-              if (i == priv->gmac_id)
+-                      continue;
+-
+-              mtk_gdma_write(priv, i, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD);
+-      }
+-
+-      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) {
+-              if (priv->sw == SW_MT7988 && priv->gmac_id == 0) {
+-                      mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG,
+-                                     GDMA_BRIDGE_TO_CPU);
+-
+-                      mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
+-                                     GDMA_CPU_BRIDGE_EN);
+-              } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+-                          priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
+-                          priv->phy_interface == PHY_INTERFACE_MODE_XGMII) &&
+-                         priv->gmac_id != 0) {
+-                      mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
+-                                     GDMA_CPU_BRIDGE_EN);
+-              }
+-      }
+-
+-      udelay(500);
+-
+-      mtk_eth_fifo_init(priv);
+-
+-      if (priv->switch_mac_control)
+-              priv->switch_mac_control(priv, true);
+-
+-      /* Start PHY */
+-      if (priv->sw == SW_NONE) {
+-              ret = mtk_phy_start(priv);
+-              if (ret)
+-                      return ret;
+-      }
+-
+-      mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0,
+-                   TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN);
+-      udelay(500);
+-
+-      return 0;
+-}
+-
+-static void mtk_eth_stop(struct udevice *dev)
+-{
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-
+-      if (priv->switch_mac_control)
+-              priv->switch_mac_control(priv, false);
+-
+-      mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG,
+-                   TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0);
+-      udelay(500);
+-
+-      wait_for_bit_le32(priv->fe_base + priv->soc->pdma_base + PDMA_GLO_CFG_REG,
+-                        RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0);
+-}
+-
+-static int mtk_eth_write_hwaddr(struct udevice *dev)
+-{
+-      struct eth_pdata *pdata = dev_get_plat(dev);
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-      unsigned char *mac = pdata->enetaddr;
+-      u32 macaddr_lsb, macaddr_msb;
+-
+-      macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1];
+-      macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) |
+-                    ((u32)mac[4] << 8) | (u32)mac[5];
+-
+-      mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb);
+-      mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb);
+-
+-      return 0;
+-}
+-
+-static int mtk_eth_send(struct udevice *dev, void *packet, int length)
+-{
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-      u32 idx = priv->tx_cpu_owner_idx0;
+-      struct mtk_tx_dma_v2 *txd;
+-      void *pkt_base;
+-
+-      txd = priv->tx_ring_noc + idx * priv->soc->txd_size;
+-
+-      if (!(txd->txd2 & PDMA_TXD2_DDONE)) {
+-              debug("mtk-eth: TX DMA descriptor ring is full\n");
+-              return -EPERM;
+-      }
+-
+-      pkt_base = (void *)phys_to_virt(txd->txd1);
+-      memcpy(pkt_base, packet, length);
+-      flush_dcache_range((ulong)pkt_base, (ulong)pkt_base +
+-                         roundup(length, ARCH_DMA_MINALIGN));
+-
+-      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+-          MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+-              txd->txd2 = PDMA_TXD2_LS0 | PDMA_V2_TXD2_SDL0_SET(length);
+-      else
+-              txd->txd2 = PDMA_TXD2_LS0 | PDMA_V1_TXD2_SDL0_SET(length);
+-
+-      priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC;
+-      mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
+-
+-      return 0;
+-}
+-
+-static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+-{
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-      u32 idx = priv->rx_dma_owner_idx0;
+-      struct mtk_rx_dma_v2 *rxd;
+-      uchar *pkt_base;
+-      u32 length;
+-
+-      rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
+-
+-      if (!(rxd->rxd2 & PDMA_RXD2_DDONE)) {
+-              debug("mtk-eth: RX DMA descriptor ring is empty\n");
+-              return -EAGAIN;
+-      }
+-
+-      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+-          MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+-              length = PDMA_V2_RXD2_PLEN0_GET(rxd->rxd2);
+-      else
+-              length = PDMA_V1_RXD2_PLEN0_GET(rxd->rxd2);
+-
+-      pkt_base = (void *)phys_to_virt(rxd->rxd1);
+-      invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base +
+-                              roundup(length, ARCH_DMA_MINALIGN));
+-
+-      if (packetp)
+-              *packetp = pkt_base;
+-
+-      return length;
+-}
+-
+-static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
+-{
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-      u32 idx = priv->rx_dma_owner_idx0;
+-      struct mtk_rx_dma_v2 *rxd;
+-
+-      rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
+-
+-      invalidate_dcache_range((ulong)rxd->rxd1,
+-                              (ulong)rxd->rxd1 + PKTSIZE_ALIGN);
+-
+-      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+-          MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+-              rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+-      else
+-              rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+-
+-      mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx);
+-      priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC;
+-
+-      return 0;
+-}
+-
+-static int mtk_eth_probe(struct udevice *dev)
+-{
+-      struct eth_pdata *pdata = dev_get_plat(dev);
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-      ulong iobase = pdata->iobase;
+-      int ret;
+-
+-      /* Frame Engine Register Base */
+-      priv->fe_base = (void *)iobase;
+-
+-      /* GMAC Register Base */
+-      priv->gmac_base = (void *)(iobase + GMAC_BASE);
+-
+-      /* MDIO register */
+-      ret = mtk_mdio_register(dev);
+-      if (ret)
+-              return ret;
+-
+-      /* Prepare for tx/rx rings */
+-      priv->tx_ring_noc = (void *)
+-              noncached_alloc(priv->soc->txd_size * NUM_TX_DESC,
+-                              ARCH_DMA_MINALIGN);
+-      priv->rx_ring_noc = (void *)
+-              noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC,
+-                              ARCH_DMA_MINALIGN);
+-
+-      /* Set MDC divider */
+-      mtk_eth_mdc_init(priv);
+-
+-      /* Set MAC mode */
+-      if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+-          priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
+-          priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
+-              ret = mtk_xmac_init(priv);
+-      else
+-              ret = mtk_mac_init(priv);
+-
+-      if (ret)
+-              return ret;
+-
+-      /* Probe phy if switch is not specified */
+-      if (priv->sw == SW_NONE)
+-              return mtk_phy_probe(dev);
+-
+-      /* Initialize switch */
+-      return mt753x_switch_init(priv);
+-}
+-
+-static int mtk_eth_remove(struct udevice *dev)
+-{
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-
+-      /* MDIO unregister */
+-      mdio_unregister(priv->mdio_bus);
+-      mdio_free(priv->mdio_bus);
+-
+-      /* Stop possibly started DMA */
+-      mtk_eth_stop(dev);
+-
+-      return 0;
+-}
+-
+-static int mtk_eth_of_to_plat(struct udevice *dev)
+-{
+-      struct eth_pdata *pdata = dev_get_plat(dev);
+-      struct mtk_eth_priv *priv = dev_get_priv(dev);
+-      struct ofnode_phandle_args args;
+-      struct regmap *regmap;
+-      const char *str;
+-      ofnode subnode;
+-      int ret;
+-
+-      priv->soc = (const struct mtk_soc_data *)dev_get_driver_data(dev);
+-      if (!priv->soc) {
+-              dev_err(dev, "missing soc compatible data\n");
+-              return -EINVAL;
+-      }
+-
+-      pdata->iobase = (phys_addr_t)dev_remap_addr(dev);
+-
+-      /* get corresponding ethsys phandle */
+-      ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0,
+-                                       &args);
+-      if (ret)
+-              return ret;
+-
+-      priv->ethsys_regmap = syscon_node_to_regmap(args.node);
+-      if (IS_ERR(priv->ethsys_regmap))
+-              return PTR_ERR(priv->ethsys_regmap);
+-
+-      if (MTK_HAS_CAPS(priv->soc->caps, MTK_INFRA)) {
+-              /* get corresponding infracfg phandle */
+-              ret = dev_read_phandle_with_args(dev, "mediatek,infracfg",
+-                                               NULL, 0, 0, &args);
+-
+-              if (ret)
+-                      return ret;
+-
+-              priv->infra_regmap = syscon_node_to_regmap(args.node);
+-              if (IS_ERR(priv->infra_regmap))
+-                      return PTR_ERR(priv->infra_regmap);
+-      }
+-
+-      /* Reset controllers */
+-      ret = reset_get_by_name(dev, "fe", &priv->rst_fe);
+-      if (ret) {
+-              printf("error: Unable to get reset ctrl for frame engine\n");
+-              return ret;
+-      }
+-
+-      priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0);
+-
+-      priv->mdc = 0;
+-      subnode = ofnode_find_subnode(dev_ofnode(dev), "mdio");
+-      if (ofnode_valid(subnode)) {
+-              priv->mdc = ofnode_read_u32_default(subnode, "clock-frequency", 2500000);
+-              if (priv->mdc > MDC_MAX_FREQ ||
+-                  priv->mdc < MDC_MAX_FREQ / MDC_MAX_DIVIDER) {
+-                      printf("error: MDIO clock frequency out of range\n");
+-                      return -EINVAL;
+-              }
+-      }
+-
+-      /* Interface mode is required */
+-      pdata->phy_interface = dev_read_phy_mode(dev);
+-      priv->phy_interface = pdata->phy_interface;
+-      if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
+-              printf("error: phy-mode is not set\n");
+-              return -EINVAL;
+-      }
+-
+-      /* Force mode or autoneg */
+-      subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link");
+-      if (ofnode_valid(subnode)) {
+-              priv->force_mode = 1;
+-              priv->speed = ofnode_read_u32_default(subnode, "speed", 0);
+-              priv->duplex = ofnode_read_bool(subnode, "full-duplex");
+-
+-              if (priv->speed != SPEED_10 && priv->speed != SPEED_100 &&
+-                  priv->speed != SPEED_1000 && priv->speed != SPEED_2500 &&
+-                  priv->speed != SPEED_10000) {
+-                      printf("error: no valid speed set in fixed-link\n");
+-                      return -EINVAL;
+-              }
+-      }
+-
+-      if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII ||
+-           priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) &&
+-          IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
+-              /* get corresponding sgmii phandle */
+-              ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys",
+-                                               NULL, 0, 0, &args);
+-              if (ret)
+-                      return ret;
+-
+-              regmap = syscon_node_to_regmap(args.node);
+-
+-              if (IS_ERR(regmap))
+-                      return PTR_ERR(regmap);
+-
+-              priv->sgmii_base = regmap_get_range(regmap, 0);
+-
+-              if (!priv->sgmii_base) {
+-                      dev_err(dev, "Unable to find sgmii\n");
+-                      return -ENODEV;
+-              }
+-
+-              /* Upstream linux use mediatek,pnswap instead of pn_swap */
+-              priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") ||
+-                              ofnode_read_bool(args.node, "mediatek,pnswap");
+-      } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+-                  priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
+-                 IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
+-              /* get corresponding usxgmii phandle */
+-              ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys",
+-                                               NULL, 0, 0, &args);
+-              if (ret)
+-                      return ret;
+-
+-              priv->usxgmii_regmap = syscon_node_to_regmap(args.node);
+-              if (IS_ERR(priv->usxgmii_regmap))
+-                      return PTR_ERR(priv->usxgmii_regmap);
+-
+-              /* get corresponding xfi_pextp phandle */
+-              ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pextp",
+-                                               NULL, 0, 0, &args);
+-              if (ret)
+-                      return ret;
+-
+-              priv->xfi_pextp_regmap = syscon_node_to_regmap(args.node);
+-              if (IS_ERR(priv->xfi_pextp_regmap))
+-                      return PTR_ERR(priv->xfi_pextp_regmap);
+-
+-              /* get corresponding xfi_pll phandle */
+-              ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pll",
+-                                               NULL, 0, 0, &args);
+-              if (ret)
+-                      return ret;
+-
+-              priv->xfi_pll_regmap = syscon_node_to_regmap(args.node);
+-              if (IS_ERR(priv->xfi_pll_regmap))
+-                      return PTR_ERR(priv->xfi_pll_regmap);
+-
+-              /* get corresponding toprgu phandle */
+-              ret = dev_read_phandle_with_args(dev, "mediatek,toprgu",
+-                                               NULL, 0, 0, &args);
+-              if (ret)
+-                      return ret;
+-
+-              priv->toprgu_regmap = syscon_node_to_regmap(args.node);
+-              if (IS_ERR(priv->toprgu_regmap))
+-                      return PTR_ERR(priv->toprgu_regmap);
+-      }
+-
+-      /* check for switch first, otherwise phy will be used */
+-      priv->sw = SW_NONE;
+-      priv->switch_init = NULL;
+-      priv->switch_mac_control = NULL;
+-      str = dev_read_string(dev, "mediatek,switch");
+-
+-      if (str) {
+-              if (!strcmp(str, "mt7530")) {
+-                      priv->sw = SW_MT7530;
+-                      priv->switch_init = mt7530_setup;
+-                      priv->switch_mac_control = mt7530_mac_control;
+-                      priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR;
+-                      priv->mt753x_reset_wait_time = 1000;
+-              } else if (!strcmp(str, "mt7531")) {
+-                      priv->sw = SW_MT7531;
+-                      priv->switch_init = mt7531_setup;
+-                      priv->switch_mac_control = mt7531_mac_control;
+-                      priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR;
+-                      priv->mt753x_reset_wait_time = 200;
+-              } else if (!strcmp(str, "mt7988")) {
+-                      priv->sw = SW_MT7988;
+-                      priv->switch_init = mt7988_setup;
+-                      priv->switch_mac_control = mt7988_mac_control;
+-                      priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR;
+-                      priv->mt753x_reset_wait_time = 50;
+-              } else {
+-                      printf("error: unsupported switch\n");
+-                      return -EINVAL;
+-              }
+-
+-              priv->mcm = dev_read_bool(dev, "mediatek,mcm");
+-              if (priv->mcm) {
+-                      ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm);
+-                      if (ret) {
+-                              printf("error: no reset ctrl for mcm\n");
+-                              return ret;
+-                      }
+-              } else {
+-                      gpio_request_by_name(dev, "reset-gpios", 0,
+-                                           &priv->rst_gpio, GPIOD_IS_OUT);
+-              }
+-      } else {
+-              ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0,
+-                                               0, &args);
+-              if (ret) {
+-                      printf("error: phy-handle is not specified\n");
+-                      return ret;
+-              }
+-
+-              priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1);
+-              if (priv->phy_addr < 0) {
+-                      printf("error: phy address is not specified\n");
+-                      return ret;
+-              }
+-      }
+-
+-      return 0;
+-}
+-
+-static const struct mtk_soc_data mt7988_data = {
+-      .caps = MT7988_CAPS,
+-      .ana_rgc3 = 0x128,
+-      .gdma_count = 3,
+-      .pdma_base = PDMA_V3_BASE,
+-      .txd_size = sizeof(struct mtk_tx_dma_v2),
+-      .rxd_size = sizeof(struct mtk_rx_dma_v2),
+-};
+-
+-static const struct mtk_soc_data mt7986_data = {
+-      .caps = MT7986_CAPS,
+-      .ana_rgc3 = 0x128,
+-      .gdma_count = 2,
+-      .pdma_base = PDMA_V2_BASE,
+-      .txd_size = sizeof(struct mtk_tx_dma_v2),
+-      .rxd_size = sizeof(struct mtk_rx_dma_v2),
+-};
+-
+-static const struct mtk_soc_data mt7981_data = {
+-      .caps = MT7981_CAPS,
+-      .ana_rgc3 = 0x128,
+-      .gdma_count = 2,
+-      .pdma_base = PDMA_V2_BASE,
+-      .txd_size = sizeof(struct mtk_tx_dma_v2),
+-      .rxd_size = sizeof(struct mtk_rx_dma_v2),
+-};
+-
+-static const struct mtk_soc_data mt7629_data = {
+-      .caps = MT7629_CAPS,
+-      .ana_rgc3 = 0x128,
+-      .gdma_count = 2,
+-      .pdma_base = PDMA_V1_BASE,
+-      .txd_size = sizeof(struct mtk_tx_dma),
+-      .rxd_size = sizeof(struct mtk_rx_dma),
+-};
+-
+-static const struct mtk_soc_data mt7623_data = {
+-      .caps = MT7623_CAPS,
+-      .gdma_count = 2,
+-      .pdma_base = PDMA_V1_BASE,
+-      .txd_size = sizeof(struct mtk_tx_dma),
+-      .rxd_size = sizeof(struct mtk_rx_dma),
+-};
+-
+-static const struct mtk_soc_data mt7622_data = {
+-      .caps = MT7622_CAPS,
+-      .ana_rgc3 = 0x2028,
+-      .gdma_count = 2,
+-      .pdma_base = PDMA_V1_BASE,
+-      .txd_size = sizeof(struct mtk_tx_dma),
+-      .rxd_size = sizeof(struct mtk_rx_dma),
+-};
+-
+-static const struct mtk_soc_data mt7621_data = {
+-      .caps = MT7621_CAPS,
+-      .gdma_count = 2,
+-      .pdma_base = PDMA_V1_BASE,
+-      .txd_size = sizeof(struct mtk_tx_dma),
+-      .rxd_size = sizeof(struct mtk_rx_dma),
+-};
+-
+-static const struct udevice_id mtk_eth_ids[] = {
+-      { .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data },
+-      { .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data },
+-      { .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data },
+-      { .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data },
+-      { .compatible = "mediatek,mt7623-eth", .data = (ulong)&mt7623_data },
+-      { .compatible = "mediatek,mt7622-eth", .data = (ulong)&mt7622_data },
+-      { .compatible = "mediatek,mt7621-eth", .data = (ulong)&mt7621_data },
+-      {}
+-};
+-
+-static const struct eth_ops mtk_eth_ops = {
+-      .start = mtk_eth_start,
+-      .stop = mtk_eth_stop,
+-      .send = mtk_eth_send,
+-      .recv = mtk_eth_recv,
+-      .free_pkt = mtk_eth_free_pkt,
+-      .write_hwaddr = mtk_eth_write_hwaddr,
+-};
+-
+-U_BOOT_DRIVER(mtk_eth) = {
+-      .name = "mtk-eth",
+-      .id = UCLASS_ETH,
+-      .of_match = mtk_eth_ids,
+-      .of_to_plat = mtk_eth_of_to_plat,
+-      .plat_auto      = sizeof(struct eth_pdata),
+-      .probe = mtk_eth_probe,
+-      .remove = mtk_eth_remove,
+-      .ops = &mtk_eth_ops,
+-      .priv_auto      = sizeof(struct mtk_eth_priv),
+-      .flags = DM_FLAG_ALLOC_PRIV_DMA,
+-};
+--- /dev/null
++++ b/drivers/net/mtk_eth/mtk_eth.c
+@@ -0,0 +1,1563 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2025 MediaTek Inc.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ * Author: Mark Lee <mark-mc.lee@mediatek.com>
++ */
++
++#include <cpu_func.h>
++#include <dm.h>
++#include <log.h>
++#include <malloc.h>
++#include <miiphy.h>
++#include <net.h>
++#include <regmap.h>
++#include <reset.h>
++#include <syscon.h>
++#include <wait_bit.h>
++#include <asm/cache.h>
++#include <asm/gpio.h>
++#include <asm/io.h>
++#include <dm/device_compat.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/ioport.h>
++#include <linux/mdio.h>
++#include <linux/mii.h>
++#include <linux/printk.h>
++
++#include "mtk_eth.h"
++
++#define NUM_TX_DESC           32
++#define NUM_RX_DESC           32
++#define TX_TOTAL_BUF_SIZE     (NUM_TX_DESC * PKTSIZE_ALIGN)
++#define RX_TOTAL_BUF_SIZE     (NUM_RX_DESC * PKTSIZE_ALIGN)
++#define TOTAL_PKT_BUF_SIZE    (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE)
++
++#define GDMA_FWD_TO_CPU \
++      (0x20000000 | \
++      GDM_ICS_EN | \
++      GDM_TCS_EN | \
++      GDM_UCS_EN | \
++      STRP_CRC | \
++      (DP_PDMA << MYMAC_DP_S) | \
++      (DP_PDMA << BC_DP_S) | \
++      (DP_PDMA << MC_DP_S) | \
++      (DP_PDMA << UN_DP_S))
++
++#define GDMA_BRIDGE_TO_CPU \
++      (0xC0000000 | \
++      GDM_ICS_EN | \
++      GDM_TCS_EN | \
++      GDM_UCS_EN | \
++      (DP_PDMA << MYMAC_DP_S) | \
++      (DP_PDMA << BC_DP_S) | \
++      (DP_PDMA << MC_DP_S) | \
++      (DP_PDMA << UN_DP_S))
++
++#define GDMA_FWD_DISCARD \
++      (0x20000000 | \
++      GDM_ICS_EN | \
++      GDM_TCS_EN | \
++      GDM_UCS_EN | \
++      STRP_CRC | \
++      (DP_DISCARD << MYMAC_DP_S) | \
++      (DP_DISCARD << BC_DP_S) | \
++      (DP_DISCARD << MC_DP_S) | \
++      (DP_DISCARD << UN_DP_S))
++
++struct mtk_eth_priv {
++      char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
++
++      void *tx_ring_noc;
++      void *rx_ring_noc;
++
++      int rx_dma_owner_idx0;
++      int tx_cpu_owner_idx0;
++
++      void __iomem *fe_base;
++      void __iomem *gmac_base;
++      void __iomem *sgmii_base;
++
++      struct regmap *ethsys_regmap;
++
++      struct regmap *infra_regmap;
++
++      struct regmap *usxgmii_regmap;
++      struct regmap *xfi_pextp_regmap;
++      struct regmap *xfi_pll_regmap;
++      struct regmap *toprgu_regmap;
++
++      struct mii_dev *mdio_bus;
++
++      const struct mtk_soc_data *soc;
++      int gmac_id;
++      int force_mode;
++      int speed;
++      int duplex;
++      int mdc;
++      bool pn_swap;
++
++      struct phy_device *phydev;
++      int phy_interface;
++      int phy_addr;
++
++      struct mtk_eth_switch_priv *swpriv;
++      const char *swname;
++
++      struct gpio_desc rst_gpio;
++      int mcm;
++
++      struct reset_ctl rst_fe;
++      struct reset_ctl rst_mcm;
++};
++
++static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
++{
++      writel(val, priv->fe_base + priv->soc->pdma_base + reg);
++}
++
++static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
++                       u32 set)
++{
++      clrsetbits_le32(priv->fe_base + priv->soc->pdma_base + reg, clr, set);
++}
++
++static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg,
++                         u32 val)
++{
++      u32 gdma_base;
++
++      if (no == 2)
++              gdma_base = GDMA3_BASE;
++      else if (no == 1)
++              gdma_base = GDMA2_BASE;
++      else
++              gdma_base = GDMA1_BASE;
++
++      writel(val, priv->fe_base + gdma_base + reg);
++}
++
++void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
++{
++      clrsetbits_le32(priv->fe_base + reg, clr, set);
++}
++
++static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg)
++{
++      return readl(priv->gmac_base + reg);
++}
++
++static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
++{
++      writel(val, priv->gmac_base + reg);
++}
++
++void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
++{
++      clrsetbits_le32(priv->gmac_base + reg, clr, set);
++}
++
++void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
++{
++      uint val;
++
++      regmap_read(priv->ethsys_regmap, reg, &val);
++      val &= ~clr;
++      val |= set;
++      regmap_write(priv->ethsys_regmap, reg, val);
++}
++
++static void mtk_infra_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
++                        u32 set)
++{
++      uint val;
++
++      regmap_read(priv->infra_regmap, reg, &val);
++      val &= ~clr;
++      val |= set;
++      regmap_write(priv->infra_regmap, reg, val);
++}
++
++/* Direct MDIO clause 22/45 access via SoC */
++static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data,
++                    u32 cmd, u32 st)
++{
++      int ret;
++      u32 val;
++
++      val = (st << MDIO_ST_S) |
++            ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
++            (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
++            (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
++
++      if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
++              val |= data & MDIO_RW_DATA_M;
++
++      mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST);
++
++      ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG,
++                              PHY_ACS_ST, 0, 5000, 0);
++      if (ret) {
++              pr_warn("MDIO access timeout\n");
++              return ret;
++      }
++
++      if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
++              val = mtk_gmac_read(priv, GMAC_PIAC_REG);
++              return val & MDIO_RW_DATA_M;
++      }
++
++      return 0;
++}
++
++/* Direct MDIO clause 22 read via SoC */
++int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg)
++{
++      return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22);
++}
++
++/* Direct MDIO clause 22 write via SoC */
++int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data)
++{
++      return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22);
++}
++
++/* Direct MDIO clause 45 read via SoC */
++int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg)
++{
++      int ret;
++
++      ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
++      if (ret)
++              return ret;
++
++      return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45,
++                        MDIO_ST_C45);
++}
++
++/* Direct MDIO clause 45 write via SoC */
++int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
++                u16 val)
++{
++      int ret;
++
++      ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
++      if (ret)
++              return ret;
++
++      return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE,
++                        MDIO_ST_C45);
++}
++
++/* Indirect MDIO clause 45 read via MII registers */
++int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg)
++{
++      int ret;
++
++      ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
++                          (MMD_ADDR << MMD_CMD_S) |
++                          ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
++                          (MMD_DATA << MMD_CMD_S) |
++                          ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
++      if (ret)
++              return ret;
++
++      return mtk_mii_read(priv, addr, MII_MMD_ADDR_DATA_REG);
++}
++
++/* Indirect MDIO clause 45 write via MII registers */
++int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
++                    u16 val)
++{
++      int ret;
++
++      ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
++                          (MMD_ADDR << MMD_CMD_S) |
++                          ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
++                          (MMD_DATA << MMD_CMD_S) |
++                          ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
++      if (ret)
++              return ret;
++
++      return mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val);
++}
++
++static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
++{
++      struct mtk_eth_priv *priv = bus->priv;
++
++      if (devad < 0)
++              return mtk_mii_read(priv, addr, reg);
++
++      return mtk_mmd_read(priv, addr, devad, reg);
++}
++
++static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
++                        u16 val)
++{
++      struct mtk_eth_priv *priv = bus->priv;
++
++      if (devad < 0)
++              return mtk_mii_write(priv, addr, reg, val);
++
++      return mtk_mmd_write(priv, addr, devad, reg, val);
++}
++
++static int mtk_mdio_register(struct udevice *dev)
++{
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++      struct mii_dev *mdio_bus = mdio_alloc();
++      int ret;
++
++      if (!mdio_bus)
++              return -ENOMEM;
++
++      mdio_bus->read = mtk_mdio_read;
++      mdio_bus->write = mtk_mdio_write;
++      snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
++
++      mdio_bus->priv = (void *)priv;
++
++      ret = mdio_register(mdio_bus);
++
++      if (ret)
++              return ret;
++
++      priv->mdio_bus = mdio_bus;
++
++      return 0;
++}
++
++static int mtk_switch_init(struct mtk_eth_priv *priv)
++{
++      struct mtk_eth_switch *swdrvs = ll_entry_start(struct mtk_eth_switch,
++                                                     mtk_eth_switch);
++      const u32 n_swdrvs = ll_entry_count(struct mtk_eth_switch,
++                                          mtk_eth_switch);
++      struct mtk_eth_switch *tmp, *swdrv = NULL;
++      u32 reset_wait_time = 500;
++      size_t priv_size;
++      int ret;
++
++      if (strcmp(priv->swname, "auto")) {
++              for (tmp = swdrvs; tmp < swdrvs + n_swdrvs; tmp++) {
++                      if (!strcmp(tmp->name, priv->swname)) {
++                              swdrv = tmp;
++                              break;
++                      }
++              }
++      }
++
++      if (swdrv)
++              reset_wait_time = swdrv->reset_wait_time;
++
++      /* Global reset switch */
++      if (priv->mcm) {
++              reset_assert(&priv->rst_mcm);
++              udelay(1000);
++              reset_deassert(&priv->rst_mcm);
++              mdelay(reset_wait_time);
++      } else if (dm_gpio_is_valid(&priv->rst_gpio)) {
++              dm_gpio_set_value(&priv->rst_gpio, 0);
++              udelay(1000);
++              dm_gpio_set_value(&priv->rst_gpio, 1);
++              mdelay(reset_wait_time);
++      }
++
++      if (!swdrv) {
++              for (tmp = swdrvs; tmp < swdrvs + n_swdrvs; tmp++) {
++                      if (!tmp->detect)
++                              continue;
++
++                      ret = tmp->detect(priv);
++                      if (!ret) {
++                              swdrv = tmp;
++                              break;
++                      }
++              }
++
++              if (!swdrv) {
++                      printf("Error: unable to detect switch\n");
++                      return -ENODEV;
++              }
++      } else {
++              if (swdrv->detect) {
++                      ret = swdrv->detect(priv);
++                      if (ret) {
++                              printf("Error: switch probing failed\n");
++                              return -ENODEV;
++                      }
++              }
++      }
++
++      printf("%s\n", swdrv->desc);
++
++      priv_size = swdrv->priv_size;
++      if (priv_size < sizeof(struct mtk_eth_switch_priv))
++              priv_size = sizeof(struct mtk_eth_switch_priv);
++
++      priv->swpriv = calloc(1, priv_size);
++      if (!priv->swpriv) {
++              printf("Error: no memory for switch data\n");
++              return -ENOMEM;
++      }
++
++      priv->swpriv->eth = priv;
++      priv->swpriv->soc = priv->soc;
++      priv->swpriv->phy_interface = priv->phy_interface;
++      priv->swpriv->sw = swdrv;
++      priv->swpriv->ethsys_base = regmap_get_range(priv->ethsys_regmap, 0);
++
++      ret = swdrv->setup(priv->swpriv);
++      if (ret) {
++              free(priv->swpriv);
++              priv->swpriv = NULL;
++              return ret;
++      }
++
++      return 0;
++}
++
++static void mtk_xphy_link_adjust(struct mtk_eth_priv *priv)
++{
++      u16 lcl_adv = 0, rmt_adv = 0;
++      u8 flowctrl;
++      u32 mcr;
++
++      mcr = mtk_gmac_read(priv, XGMAC_PORT_MCR(priv->gmac_id));
++      mcr &= ~(XGMAC_FORCE_TX_FC | XGMAC_FORCE_RX_FC);
++
++      if (priv->phydev->duplex) {
++              if (priv->phydev->pause)
++                      rmt_adv = LPA_PAUSE_CAP;
++              if (priv->phydev->asym_pause)
++                      rmt_adv |= LPA_PAUSE_ASYM;
++
++              if (priv->phydev->advertising & ADVERTISED_Pause)
++                      lcl_adv |= ADVERTISE_PAUSE_CAP;
++              if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
++                      lcl_adv |= ADVERTISE_PAUSE_ASYM;
++
++              flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
++
++              if (flowctrl & FLOW_CTRL_TX)
++                      mcr |= XGMAC_FORCE_TX_FC;
++              if (flowctrl & FLOW_CTRL_RX)
++                      mcr |= XGMAC_FORCE_RX_FC;
++
++              debug("rx pause %s, tx pause %s\n",
++                    flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
++                    flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
++      }
++
++      mcr &= ~(XGMAC_TRX_DISABLE);
++      mtk_gmac_write(priv, XGMAC_PORT_MCR(priv->gmac_id), mcr);
++}
++
++static void mtk_phy_link_adjust(struct mtk_eth_priv *priv)
++{
++      u16 lcl_adv = 0, rmt_adv = 0;
++      u8 flowctrl;
++      u32 mcr;
++
++      mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
++            (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
++            MAC_MODE | FORCE_MODE |
++            MAC_TX_EN | MAC_RX_EN |
++            DEL_RXFIFO_CLR |
++            BKOFF_EN | BACKPR_EN;
++
++      switch (priv->phydev->speed) {
++      case SPEED_10:
++              mcr |= (SPEED_10M << FORCE_SPD_S);
++              break;
++      case SPEED_100:
++              mcr |= (SPEED_100M << FORCE_SPD_S);
++              break;
++      case SPEED_1000:
++      case SPEED_2500:
++              mcr |= (SPEED_1000M << FORCE_SPD_S);
++              break;
++      };
++
++      if (priv->phydev->link)
++              mcr |= FORCE_LINK;
++
++      if (priv->phydev->duplex) {
++              mcr |= FORCE_DPX;
++
++              if (priv->phydev->pause)
++                      rmt_adv = LPA_PAUSE_CAP;
++              if (priv->phydev->asym_pause)
++                      rmt_adv |= LPA_PAUSE_ASYM;
++
++              if (priv->phydev->advertising & ADVERTISED_Pause)
++                      lcl_adv |= ADVERTISE_PAUSE_CAP;
++              if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
++                      lcl_adv |= ADVERTISE_PAUSE_ASYM;
++
++              flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
++
++              if (flowctrl & FLOW_CTRL_TX)
++                      mcr |= FORCE_TX_FC;
++              if (flowctrl & FLOW_CTRL_RX)
++                      mcr |= FORCE_RX_FC;
++
++              debug("rx pause %s, tx pause %s\n",
++                    flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
++                    flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
++      }
++
++      mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
++}
++
++static int mtk_phy_start(struct mtk_eth_priv *priv)
++{
++      struct phy_device *phydev = priv->phydev;
++      int ret;
++
++      ret = phy_startup(phydev);
++
++      if (ret) {
++              debug("Could not initialize PHY %s\n", phydev->dev->name);
++              return ret;
++      }
++
++      if (!phydev->link) {
++              debug("%s: link down.\n", phydev->dev->name);
++              return 0;
++      }
++
++      if (!priv->force_mode) {
++              if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++                  priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
++                  priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
++                      mtk_xphy_link_adjust(priv);
++              else
++                      mtk_phy_link_adjust(priv);
++      }
++
++      debug("Speed: %d, %s duplex%s\n", phydev->speed,
++            (phydev->duplex) ? "full" : "half",
++            (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
++
++      return 0;
++}
++
++static int mtk_phy_probe(struct udevice *dev)
++{
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++      struct phy_device *phydev;
++
++      phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev,
++                           priv->phy_interface);
++      if (!phydev)
++              return -ENODEV;
++
++      phydev->supported &= PHY_GBIT_FEATURES;
++      phydev->advertising = phydev->supported;
++
++      priv->phydev = phydev;
++      phy_config(phydev);
++
++      return 0;
++}
++
++static void mtk_sgmii_an_init(struct mtk_eth_priv *priv)
++{
++      /* Set SGMII GEN1 speed(1G) */
++      clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK);
++
++      /* Enable SGMII AN */
++      setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
++                   SGMII_AN_ENABLE);
++
++      /* SGMII AN mode setting */
++      writel(SGMII_AN_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
++
++      /* SGMII PN SWAP setting */
++      if (priv->pn_swap) {
++              setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
++                           SGMII_PN_SWAP_TX_RX);
++      }
++
++      /* Release PHYA power down state */
++      clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
++                      SGMII_PHYA_PWD, 0);
++}
++
++static void mtk_sgmii_force_init(struct mtk_eth_priv *priv)
++{
++      /* Set SGMII GEN2 speed(2.5G) */
++      clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
++                      SGMSYS_SPEED_MASK,
++                      FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
++
++      /* Disable SGMII AN */
++      clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
++                      SGMII_AN_ENABLE, 0);
++
++      /* SGMII force mode setting */
++      writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
++
++      /* SGMII PN SWAP setting */
++      if (priv->pn_swap) {
++              setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
++                           SGMII_PN_SWAP_TX_RX);
++      }
++
++      /* Release PHYA power down state */
++      clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
++                      SGMII_PHYA_PWD, 0);
++}
++
++static void mtk_xfi_pll_enable(struct mtk_eth_priv *priv)
++{
++      u32 val = 0;
++
++      /* Add software workaround for USXGMII PLL TCL issue */
++      regmap_write(priv->xfi_pll_regmap, XFI_PLL_ANA_GLB8,
++                   RG_XFI_PLL_ANA_SWWA);
++
++      regmap_read(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, &val);
++      val |= RG_XFI_PLL_EN;
++      regmap_write(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, val);
++}
++
++static void mtk_usxgmii_reset(struct mtk_eth_priv *priv)
++{
++      switch (priv->gmac_id) {
++      case 1:
++              regmap_write(priv->toprgu_regmap, 0xFC, 0x0000A004);
++              regmap_write(priv->toprgu_regmap, 0x18, 0x88F0A004);
++              regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
++              regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
++              regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
++              break;
++      case 2:
++              regmap_write(priv->toprgu_regmap, 0xFC, 0x00005002);
++              regmap_write(priv->toprgu_regmap, 0x18, 0x88F05002);
++              regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
++              regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
++              regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
++              break;
++      }
++
++      mdelay(10);
++}
++
++static void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth_priv *priv)
++{
++      regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6D);
++      regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
++      regmap_write(priv->usxgmii_regmap, 0x80C, 0x30000000);
++      ndelay(1020);
++      regmap_write(priv->usxgmii_regmap, 0x80C, 0x10000000);
++      ndelay(1020);
++      regmap_write(priv->usxgmii_regmap, 0x80C, 0x00000000);
++
++      regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
++      regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
++      regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
++      regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
++      regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
++      regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
++      regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
++      regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
++      regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
++      regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
++      regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
++      regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
++      regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
++      regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
++      regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
++      regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
++      regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
++      regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
++      regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
++      regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
++      regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
++      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
++      regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
++      ndelay(1020);
++      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
++      regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
++      regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
++      regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
++      regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
++      regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
++      regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
++      regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x40704000);
++      regmap_write(priv->xfi_pextp_regmap, 0x3050, 0xA8000000);
++      regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x000000AA);
++      regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
++      regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
++      regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
++      udelay(150);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
++      ndelay(1020);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
++      udelay(15);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
++      ndelay(1020);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
++      udelay(100);
++      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
++      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
++      regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
++      udelay(400);
++}
++
++static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv)
++{
++      regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C);
++      regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
++      regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000);
++      ndelay(1020);
++      regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000);
++      ndelay(1020);
++
++      regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
++      regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
++      regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
++      regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
++      regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
++      regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
++      regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
++      regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
++      regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
++      regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
++      regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
++      regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
++      regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
++      regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
++      regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
++      regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
++      regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
++      regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
++      regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
++      regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
++      regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
++      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
++      regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
++      ndelay(1020);
++      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
++      regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
++      regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
++      regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
++      regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
++      regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
++      regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
++      regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100);
++      regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000);
++      regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000);
++      regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
++      if (priv->gmac_id == 2)
++              regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400);
++      regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
++      regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
++      udelay(150);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
++      ndelay(1020);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
++      udelay(15);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
++      ndelay(1020);
++      regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
++      udelay(100);
++      regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
++      regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
++      regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
++      udelay(400);
++}
++
++static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv)
++{
++      mtk_xfi_pll_enable(priv);
++      mtk_usxgmii_reset(priv);
++      mtk_usxgmii_setup_phya_an_10000(priv);
++}
++
++static void mtk_10gbaser_init(struct mtk_eth_priv *priv)
++{
++      mtk_xfi_pll_enable(priv);
++      mtk_usxgmii_reset(priv);
++      mtk_usxgmii_setup_phya_force_10000(priv);
++}
++
++static int mtk_mac_init(struct mtk_eth_priv *priv)
++{
++      int i, sgmii_sel_mask = 0, ge_mode = 0;
++      u32 mcr;
++
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) {
++              mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG,
++                            INFRA_MISC2_BONDING_OPTION, priv->gmac_id);
++      }
++
++      switch (priv->phy_interface) {
++      case PHY_INTERFACE_MODE_RGMII_RXID:
++      case PHY_INTERFACE_MODE_RGMII:
++              ge_mode = GE_MODE_RGMII;
++              break;
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_2500BASEX:
++              if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
++                      printf("Error: SGMII is not supported on this platform\n");
++                      return -ENOTSUPP;
++              }
++
++              if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) {
++                      mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK,
++                                    SGMII_QPHY_SEL);
++              }
++
++              if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII))
++                      sgmii_sel_mask = SYSCFG1_SGMII_SEL_M;
++
++              mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask,
++                             SYSCFG1_SGMII_SEL(priv->gmac_id));
++
++              if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
++                      mtk_sgmii_an_init(priv);
++              else
++                      mtk_sgmii_force_init(priv);
++
++              ge_mode = GE_MODE_RGMII;
++              break;
++      case PHY_INTERFACE_MODE_MII:
++      case PHY_INTERFACE_MODE_GMII:
++              ge_mode = GE_MODE_MII;
++              break;
++      case PHY_INTERFACE_MODE_RMII:
++              ge_mode = GE_MODE_RMII;
++              break;
++      default:
++              break;
++      }
++
++      /* set the gmac to the right mode */
++      mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
++                     SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
++                     ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id));
++
++      if (priv->force_mode) {
++              mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
++                    (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
++                    MAC_MODE | FORCE_MODE |
++                    MAC_TX_EN | MAC_RX_EN |
++                    BKOFF_EN | BACKPR_EN |
++                    FORCE_LINK;
++
++              switch (priv->speed) {
++              case SPEED_10:
++                      mcr |= SPEED_10M << FORCE_SPD_S;
++                      break;
++              case SPEED_100:
++                      mcr |= SPEED_100M << FORCE_SPD_S;
++                      break;
++              case SPEED_1000:
++              case SPEED_2500:
++                      mcr |= SPEED_1000M << FORCE_SPD_S;
++                      break;
++              }
++
++              if (priv->duplex)
++                      mcr |= FORCE_DPX;
++
++              mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
++      }
++
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC1_TRGMII) &&
++          !MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
++              /* Lower Tx Driving for TRGMII path */
++              for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
++                      mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i),
++                                     (8 << TD_DM_DRVP_S) |
++                                     (8 << TD_DM_DRVN_S));
++
++              mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0,
++                           RX_RST | RXC_DQSISEL);
++              mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0);
++      }
++
++      return 0;
++}
++
++static int mtk_xmac_init(struct mtk_eth_priv *priv)
++{
++      u32 force_link = 0;
++
++      if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
++              printf("Error: 10Gb interface is not supported on this platform\n");
++              return -ENOTSUPP;
++      }
++
++      switch (priv->phy_interface) {
++      case PHY_INTERFACE_MODE_USXGMII:
++              mtk_usxgmii_an_init(priv);
++              break;
++      case PHY_INTERFACE_MODE_10GBASER:
++              mtk_10gbaser_init(priv);
++              break;
++      default:
++              break;
++      }
++
++      /* Set GMAC to the correct mode */
++      mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
++                     SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
++                     0);
++
++      if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++           priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
++          priv->gmac_id == 1) {
++              mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX,
++                            NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL);
++      }
++
++      if (priv->phy_interface == PHY_INTERFACE_MODE_XGMII ||
++          priv->gmac_id == 2)
++              force_link = XGMAC_FORCE_LINK(priv->gmac_id);
++
++      mtk_gmac_rmw(priv, XGMAC_STS(priv->gmac_id),
++                   XGMAC_FORCE_LINK(priv->gmac_id), force_link);
++
++      /* Force GMAC link down */
++      mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE);
++
++      return 0;
++}
++
++static void mtk_eth_fifo_init(struct mtk_eth_priv *priv)
++{
++      char *pkt_base = priv->pkt_pool;
++      struct mtk_tx_dma_v2 *txd;
++      struct mtk_rx_dma_v2 *rxd;
++      int i;
++
++      mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0);
++      udelay(500);
++
++      memset(priv->tx_ring_noc, 0, NUM_TX_DESC * priv->soc->txd_size);
++      memset(priv->rx_ring_noc, 0, NUM_RX_DESC * priv->soc->rxd_size);
++      memset(priv->pkt_pool, 0xff, TOTAL_PKT_BUF_SIZE);
++
++      flush_dcache_range((ulong)pkt_base,
++                         (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE));
++
++      priv->rx_dma_owner_idx0 = 0;
++      priv->tx_cpu_owner_idx0 = 0;
++
++      for (i = 0; i < NUM_TX_DESC; i++) {
++              txd = priv->tx_ring_noc + i * priv->soc->txd_size;
++
++              txd->txd1 = virt_to_phys(pkt_base);
++              txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0;
++
++              if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
++                      txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id == 2 ?
++                                                         15 : priv->gmac_id + 1);
++              else if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
++                      txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id + 1);
++              else
++                      txd->txd4 = PDMA_V1_TXD4_FPORT_SET(priv->gmac_id + 1);
++
++              pkt_base += PKTSIZE_ALIGN;
++      }
++
++      for (i = 0; i < NUM_RX_DESC; i++) {
++              rxd = priv->rx_ring_noc + i * priv->soc->rxd_size;
++
++              rxd->rxd1 = virt_to_phys(pkt_base);
++
++              if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
++                  MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
++                      rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
++              else
++                      rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
++
++              pkt_base += PKTSIZE_ALIGN;
++      }
++
++      mtk_pdma_write(priv, TX_BASE_PTR_REG(0),
++                     virt_to_phys(priv->tx_ring_noc));
++      mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC);
++      mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
++
++      mtk_pdma_write(priv, RX_BASE_PTR_REG(0),
++                     virt_to_phys(priv->rx_ring_noc));
++      mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC);
++      mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1);
++
++      mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0);
++}
++
++static void mtk_eth_mdc_init(struct mtk_eth_priv *priv)
++{
++      u32 divider;
++
++      if (priv->mdc == 0)
++              return;
++
++      divider = min_t(u32, DIV_ROUND_UP(MDC_MAX_FREQ, priv->mdc), MDC_MAX_DIVIDER);
++
++      /* Configure MDC turbo mode */
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
++              mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, MISC_MDC_TURBO);
++      else
++              mtk_gmac_rmw(priv, GMAC_PPSC_REG, 0, MISC_MDC_TURBO);
++
++      /* Configure MDC divider */
++      mtk_gmac_rmw(priv, GMAC_PPSC_REG, PHY_MDC_CFG,
++                   FIELD_PREP(PHY_MDC_CFG, divider));
++}
++
++static int mtk_eth_start(struct udevice *dev)
++{
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++      int i, ret;
++
++      /* Reset FE */
++      reset_assert(&priv->rst_fe);
++      udelay(1000);
++      reset_deassert(&priv->rst_fe);
++      mdelay(10);
++
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
++          MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
++              setbits_le32(priv->fe_base + FE_GLO_MISC_REG, PDMA_VER_V2);
++
++      /* Packets forward to PDMA */
++      mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU);
++
++      for (i = 0; i < priv->soc->gdma_count; i++) {
++              if (i == priv->gmac_id)
++                      continue;
++
++              mtk_gdma_write(priv, i, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD);
++      }
++
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) {
++              if (priv->swpriv && !strcmp(priv->swpriv->sw->name, "mt7988") &&
++                  priv->gmac_id == 0) {
++                      mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG,
++                                     GDMA_BRIDGE_TO_CPU);
++
++                      mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
++                                     GDMA_CPU_BRIDGE_EN);
++              } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++                          priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
++                          priv->phy_interface == PHY_INTERFACE_MODE_XGMII) &&
++                         priv->gmac_id != 0) {
++                      mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
++                                     GDMA_CPU_BRIDGE_EN);
++              }
++      }
++
++      udelay(500);
++
++      mtk_eth_fifo_init(priv);
++
++      if (priv->swpriv) {
++              /* Enable communication with switch */
++              if (priv->swpriv->sw->mac_control)
++                      priv->swpriv->sw->mac_control(priv->swpriv, true);
++      } else {
++              /* Start PHY */
++              ret = mtk_phy_start(priv);
++              if (ret)
++                      return ret;
++      }
++
++      mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0,
++                   TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN);
++      udelay(500);
++
++      return 0;
++}
++
++static void mtk_eth_stop(struct udevice *dev)
++{
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++
++      if (priv->swpriv) {
++              if (priv->swpriv->sw->mac_control)
++                      priv->swpriv->sw->mac_control(priv->swpriv, false);
++      }
++
++      mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG,
++                   TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0);
++      udelay(500);
++
++      wait_for_bit_le32(priv->fe_base + priv->soc->pdma_base + PDMA_GLO_CFG_REG,
++                        RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0);
++}
++
++static int mtk_eth_write_hwaddr(struct udevice *dev)
++{
++      struct eth_pdata *pdata = dev_get_plat(dev);
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++      unsigned char *mac = pdata->enetaddr;
++      u32 macaddr_lsb, macaddr_msb;
++
++      macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1];
++      macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) |
++                    ((u32)mac[4] << 8) | (u32)mac[5];
++
++      mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb);
++      mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb);
++
++      return 0;
++}
++
++static int mtk_eth_send(struct udevice *dev, void *packet, int length)
++{
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++      u32 idx = priv->tx_cpu_owner_idx0;
++      struct mtk_tx_dma_v2 *txd;
++      void *pkt_base;
++
++      txd = priv->tx_ring_noc + idx * priv->soc->txd_size;
++
++      if (!(txd->txd2 & PDMA_TXD2_DDONE)) {
++              debug("mtk-eth: TX DMA descriptor ring is full\n");
++              return -EPERM;
++      }
++
++      pkt_base = (void *)phys_to_virt(txd->txd1);
++      memcpy(pkt_base, packet, length);
++      flush_dcache_range((ulong)pkt_base, (ulong)pkt_base +
++                         roundup(length, ARCH_DMA_MINALIGN));
++
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
++          MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
++              txd->txd2 = PDMA_TXD2_LS0 | PDMA_V2_TXD2_SDL0_SET(length);
++      else
++              txd->txd2 = PDMA_TXD2_LS0 | PDMA_V1_TXD2_SDL0_SET(length);
++
++      priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC;
++      mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
++
++      return 0;
++}
++
++static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp)
++{
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++      u32 idx = priv->rx_dma_owner_idx0;
++      struct mtk_rx_dma_v2 *rxd;
++      uchar *pkt_base;
++      u32 length;
++
++      rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
++
++      if (!(rxd->rxd2 & PDMA_RXD2_DDONE)) {
++              debug("mtk-eth: RX DMA descriptor ring is empty\n");
++              return -EAGAIN;
++      }
++
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
++          MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
++              length = PDMA_V2_RXD2_PLEN0_GET(rxd->rxd2);
++      else
++              length = PDMA_V1_RXD2_PLEN0_GET(rxd->rxd2);
++
++      pkt_base = (void *)phys_to_virt(rxd->rxd1);
++      invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base +
++                              roundup(length, ARCH_DMA_MINALIGN));
++
++      if (packetp)
++              *packetp = pkt_base;
++
++      return length;
++}
++
++static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
++{
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++      u32 idx = priv->rx_dma_owner_idx0;
++      struct mtk_rx_dma_v2 *rxd;
++
++      rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
++
++      invalidate_dcache_range((ulong)rxd->rxd1,
++                              (ulong)rxd->rxd1 + PKTSIZE_ALIGN);
++
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
++          MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
++              rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
++      else
++              rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
++
++      mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx);
++      priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC;
++
++      return 0;
++}
++
++static int mtk_eth_probe(struct udevice *dev)
++{
++      struct eth_pdata *pdata = dev_get_plat(dev);
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++      ulong iobase = pdata->iobase;
++      int ret;
++
++      /* Frame Engine Register Base */
++      priv->fe_base = (void *)iobase;
++
++      /* GMAC Register Base */
++      priv->gmac_base = (void *)(iobase + GMAC_BASE);
++
++      /* MDIO register */
++      ret = mtk_mdio_register(dev);
++      if (ret)
++              return ret;
++
++      /* Prepare for tx/rx rings */
++      priv->tx_ring_noc = (void *)
++              noncached_alloc(priv->soc->txd_size * NUM_TX_DESC,
++                              ARCH_DMA_MINALIGN);
++      priv->rx_ring_noc = (void *)
++              noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC,
++                              ARCH_DMA_MINALIGN);
++
++      /* Set MDC divider */
++      mtk_eth_mdc_init(priv);
++
++      /* Set MAC mode */
++      if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++          priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
++          priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
++              ret = mtk_xmac_init(priv);
++      else
++              ret = mtk_mac_init(priv);
++
++      if (ret)
++              return ret;
++
++      /* Probe phy if switch is not specified */
++      if (!priv->swname)
++              return mtk_phy_probe(dev);
++
++      /* Initialize switch */
++      return mtk_switch_init(priv);
++}
++
++static int mtk_eth_remove(struct udevice *dev)
++{
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++
++      /* MDIO unregister */
++      mdio_unregister(priv->mdio_bus);
++      mdio_free(priv->mdio_bus);
++
++      /* Stop possibly started DMA */
++      mtk_eth_stop(dev);
++
++      if (priv->swpriv) {
++              if (priv->swpriv->sw->cleanup)
++                      priv->swpriv->sw->cleanup(priv->swpriv);
++              free(priv->swpriv);
++      }
++
++      return 0;
++}
++
++static int mtk_eth_of_to_plat(struct udevice *dev)
++{
++      struct eth_pdata *pdata = dev_get_plat(dev);
++      struct mtk_eth_priv *priv = dev_get_priv(dev);
++      struct ofnode_phandle_args args;
++      struct regmap *regmap;
++      ofnode subnode;
++      int ret;
++
++      priv->soc = (const struct mtk_soc_data *)dev_get_driver_data(dev);
++      if (!priv->soc) {
++              dev_err(dev, "missing soc compatible data\n");
++              return -EINVAL;
++      }
++
++      pdata->iobase = (phys_addr_t)dev_remap_addr(dev);
++
++      /* get corresponding ethsys phandle */
++      ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0,
++                                       &args);
++      if (ret)
++              return ret;
++
++      priv->ethsys_regmap = syscon_node_to_regmap(args.node);
++      if (IS_ERR(priv->ethsys_regmap))
++              return PTR_ERR(priv->ethsys_regmap);
++
++      if (MTK_HAS_CAPS(priv->soc->caps, MTK_INFRA)) {
++              /* get corresponding infracfg phandle */
++              ret = dev_read_phandle_with_args(dev, "mediatek,infracfg",
++                                               NULL, 0, 0, &args);
++
++              if (ret)
++                      return ret;
++
++              priv->infra_regmap = syscon_node_to_regmap(args.node);
++              if (IS_ERR(priv->infra_regmap))
++                      return PTR_ERR(priv->infra_regmap);
++      }
++
++      /* Reset controllers */
++      ret = reset_get_by_name(dev, "fe", &priv->rst_fe);
++      if (ret) {
++              printf("error: Unable to get reset ctrl for frame engine\n");
++              return ret;
++      }
++
++      priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0);
++
++      priv->mdc = 0;
++      subnode = ofnode_find_subnode(dev_ofnode(dev), "mdio");
++      if (ofnode_valid(subnode)) {
++              priv->mdc = ofnode_read_u32_default(subnode, "clock-frequency", 2500000);
++              if (priv->mdc > MDC_MAX_FREQ ||
++                  priv->mdc < MDC_MAX_FREQ / MDC_MAX_DIVIDER) {
++                      printf("error: MDIO clock frequency out of range\n");
++                      return -EINVAL;
++              }
++      }
++
++      /* Interface mode is required */
++      pdata->phy_interface = dev_read_phy_mode(dev);
++      priv->phy_interface = pdata->phy_interface;
++      if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
++              printf("error: phy-mode is not set\n");
++              return -EINVAL;
++      }
++
++      /* Force mode or autoneg */
++      subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link");
++      if (ofnode_valid(subnode)) {
++              priv->force_mode = 1;
++              priv->speed = ofnode_read_u32_default(subnode, "speed", 0);
++              priv->duplex = ofnode_read_bool(subnode, "full-duplex");
++
++              if (priv->speed != SPEED_10 && priv->speed != SPEED_100 &&
++                  priv->speed != SPEED_1000 && priv->speed != SPEED_2500 &&
++                  priv->speed != SPEED_10000) {
++                      printf("error: no valid speed set in fixed-link\n");
++                      return -EINVAL;
++              }
++      }
++
++      if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII ||
++           priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) &&
++          IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
++              /* get corresponding sgmii phandle */
++              ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys",
++                                               NULL, 0, 0, &args);
++              if (ret)
++                      return ret;
++
++              regmap = syscon_node_to_regmap(args.node);
++
++              if (IS_ERR(regmap))
++                      return PTR_ERR(regmap);
++
++              priv->sgmii_base = regmap_get_range(regmap, 0);
++
++              if (!priv->sgmii_base) {
++                      dev_err(dev, "Unable to find sgmii\n");
++                      return -ENODEV;
++              }
++
++              /* Upstream linux use mediatek,pnswap instead of pn_swap */
++              priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") ||
++                              ofnode_read_bool(args.node, "mediatek,pnswap");
++      } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
++                  priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
++                 IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
++              /* get corresponding usxgmii phandle */
++              ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys",
++                                               NULL, 0, 0, &args);
++              if (ret)
++                      return ret;
++
++              priv->usxgmii_regmap = syscon_node_to_regmap(args.node);
++              if (IS_ERR(priv->usxgmii_regmap))
++                      return PTR_ERR(priv->usxgmii_regmap);
++
++              /* get corresponding xfi_pextp phandle */
++              ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pextp",
++                                               NULL, 0, 0, &args);
++              if (ret)
++                      return ret;
++
++              priv->xfi_pextp_regmap = syscon_node_to_regmap(args.node);
++              if (IS_ERR(priv->xfi_pextp_regmap))
++                      return PTR_ERR(priv->xfi_pextp_regmap);
++
++              /* get corresponding xfi_pll phandle */
++              ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pll",
++                                               NULL, 0, 0, &args);
++              if (ret)
++                      return ret;
++
++              priv->xfi_pll_regmap = syscon_node_to_regmap(args.node);
++              if (IS_ERR(priv->xfi_pll_regmap))
++                      return PTR_ERR(priv->xfi_pll_regmap);
++
++              /* get corresponding toprgu phandle */
++              ret = dev_read_phandle_with_args(dev, "mediatek,toprgu",
++                                               NULL, 0, 0, &args);
++              if (ret)
++                      return ret;
++
++              priv->toprgu_regmap = syscon_node_to_regmap(args.node);
++              if (IS_ERR(priv->toprgu_regmap))
++                      return PTR_ERR(priv->toprgu_regmap);
++      }
++
++      priv->swname = dev_read_string(dev, "mediatek,switch");
++      if (priv->swname) {
++              priv->mcm = dev_read_bool(dev, "mediatek,mcm");
++              if (priv->mcm) {
++                      ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm);
++                      if (ret) {
++                              printf("error: no reset ctrl for mcm\n");
++                              return ret;
++                      }
++              } else {
++                      gpio_request_by_name(dev, "reset-gpios", 0,
++                                           &priv->rst_gpio, GPIOD_IS_OUT);
++              }
++      } else {
++              ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0,
++                                               0, &args);
++              if (ret) {
++                      printf("error: phy-handle is not specified\n");
++                      return ret;
++              }
++
++              priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1);
++              if (priv->phy_addr < 0) {
++                      printf("error: phy address is not specified\n");
++                      return ret;
++              }
++      }
++
++      return 0;
++}
++
++static const struct mtk_soc_data mt7988_data = {
++      .caps = MT7988_CAPS,
++      .ana_rgc3 = 0x128,
++      .gdma_count = 3,
++      .pdma_base = PDMA_V3_BASE,
++      .txd_size = sizeof(struct mtk_tx_dma_v2),
++      .rxd_size = sizeof(struct mtk_rx_dma_v2),
++};
++
++static const struct mtk_soc_data mt7986_data = {
++      .caps = MT7986_CAPS,
++      .ana_rgc3 = 0x128,
++      .gdma_count = 2,
++      .pdma_base = PDMA_V2_BASE,
++      .txd_size = sizeof(struct mtk_tx_dma_v2),
++      .rxd_size = sizeof(struct mtk_rx_dma_v2),
++};
++
++static const struct mtk_soc_data mt7981_data = {
++      .caps = MT7981_CAPS,
++      .ana_rgc3 = 0x128,
++      .gdma_count = 2,
++      .pdma_base = PDMA_V2_BASE,
++      .txd_size = sizeof(struct mtk_tx_dma_v2),
++      .rxd_size = sizeof(struct mtk_rx_dma_v2),
++};
++
++static const struct mtk_soc_data mt7629_data = {
++      .caps = MT7629_CAPS,
++      .ana_rgc3 = 0x128,
++      .gdma_count = 2,
++      .pdma_base = PDMA_V1_BASE,
++      .txd_size = sizeof(struct mtk_tx_dma),
++      .rxd_size = sizeof(struct mtk_rx_dma),
++};
++
++static const struct mtk_soc_data mt7623_data = {
++      .caps = MT7623_CAPS,
++      .gdma_count = 2,
++      .pdma_base = PDMA_V1_BASE,
++      .txd_size = sizeof(struct mtk_tx_dma),
++      .rxd_size = sizeof(struct mtk_rx_dma),
++};
++
++static const struct mtk_soc_data mt7622_data = {
++      .caps = MT7622_CAPS,
++      .ana_rgc3 = 0x2028,
++      .gdma_count = 2,
++      .pdma_base = PDMA_V1_BASE,
++      .txd_size = sizeof(struct mtk_tx_dma),
++      .rxd_size = sizeof(struct mtk_rx_dma),
++};
++
++static const struct mtk_soc_data mt7621_data = {
++      .caps = MT7621_CAPS,
++      .gdma_count = 2,
++      .pdma_base = PDMA_V1_BASE,
++      .txd_size = sizeof(struct mtk_tx_dma),
++      .rxd_size = sizeof(struct mtk_rx_dma),
++};
++
++static const struct udevice_id mtk_eth_ids[] = {
++      { .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data },
++      { .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data },
++      { .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data },
++      { .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data },
++      { .compatible = "mediatek,mt7623-eth", .data = (ulong)&mt7623_data },
++      { .compatible = "mediatek,mt7622-eth", .data = (ulong)&mt7622_data },
++      { .compatible = "mediatek,mt7621-eth", .data = (ulong)&mt7621_data },
++      {}
++};
++
++static const struct eth_ops mtk_eth_ops = {
++      .start = mtk_eth_start,
++      .stop = mtk_eth_stop,
++      .send = mtk_eth_send,
++      .recv = mtk_eth_recv,
++      .free_pkt = mtk_eth_free_pkt,
++      .write_hwaddr = mtk_eth_write_hwaddr,
++};
++
++U_BOOT_DRIVER(mtk_eth) = {
++      .name = "mtk-eth",
++      .id = UCLASS_ETH,
++      .of_match = mtk_eth_ids,
++      .of_to_plat = mtk_eth_of_to_plat,
++      .plat_auto = sizeof(struct eth_pdata),
++      .probe = mtk_eth_probe,
++      .remove = mtk_eth_remove,
++      .ops = &mtk_eth_ops,
++      .priv_auto = sizeof(struct mtk_eth_priv),
++      .flags = DM_FLAG_ALLOC_PRIV_DMA,
++};
+--- a/drivers/net/mtk_eth.h
++++ /dev/null
+@@ -1,600 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Copyright (C) 2018 MediaTek Inc.
+- *
+- * Author: Weijie Gao <weijie.gao@mediatek.com>
+- * Author: Mark Lee <mark-mc.lee@mediatek.com>
+- */
+-
+-#ifndef _MTK_ETH_H_
+-#define _MTK_ETH_H_
+-
+-#include <linux/bitops.h>
+-#include <linux/bitfield.h>
+-
+-enum mkt_eth_capabilities {
+-      MTK_TRGMII_BIT,
+-      MTK_TRGMII_MT7621_CLK_BIT,
+-      MTK_U3_COPHY_V2_BIT,
+-      MTK_INFRA_BIT,
+-      MTK_NETSYS_V2_BIT,
+-      MTK_NETSYS_V3_BIT,
+-
+-      /* PATH BITS */
+-      MTK_ETH_PATH_GMAC1_TRGMII_BIT,
+-      MTK_ETH_PATH_GMAC2_SGMII_BIT,
+-      MTK_ETH_PATH_MT7622_SGMII_BIT,
+-      MTK_ETH_PATH_MT7629_GMAC2_BIT,
+-};
+-
+-#define MTK_TRGMII                    BIT(MTK_TRGMII_BIT)
+-#define MTK_TRGMII_MT7621_CLK         BIT(MTK_TRGMII_MT7621_CLK_BIT)
+-#define MTK_U3_COPHY_V2                       BIT(MTK_U3_COPHY_V2_BIT)
+-#define MTK_INFRA                     BIT(MTK_INFRA_BIT)
+-#define MTK_NETSYS_V2                 BIT(MTK_NETSYS_V2_BIT)
+-#define MTK_NETSYS_V3                 BIT(MTK_NETSYS_V3_BIT)
+-
+-/* Supported path present on SoCs */
+-#define MTK_ETH_PATH_GMAC1_TRGMII     BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
+-
+-#define MTK_ETH_PATH_GMAC2_SGMII      BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
+-#define MTK_ETH_PATH_MT7622_SGMII     BIT(MTK_ETH_PATH_MT7622_SGMII_BIT)
+-#define MTK_ETH_PATH_MT7629_GMAC2     BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT)
+-
+-#define MTK_GMAC1_TRGMII      (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
+-
+-#define MTK_GMAC2_U3_QPHY     (MTK_ETH_PATH_GMAC2_SGMII | MTK_U3_COPHY_V2 | MTK_INFRA)
+-
+-#define MTK_HAS_CAPS(caps, _x)                (((caps) & (_x)) == (_x))
+-
+-#define MT7621_CAPS  (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK)
+-
+-#define MT7622_CAPS  (MTK_ETH_PATH_MT7622_SGMII)
+-
+-#define MT7623_CAPS  (MTK_GMAC1_TRGMII)
+-
+-#define MT7629_CAPS  (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA)
+-
+-#define MT7981_CAPS  (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2)
+-
+-#define MT7986_CAPS  (MTK_NETSYS_V2)
+-
+-#define MT7988_CAPS  (MTK_NETSYS_V3 | MTK_INFRA)
+-
+-/* Frame Engine Register Bases */
+-#define PDMA_V1_BASE                  0x0800
+-#define PDMA_V2_BASE                  0x6000
+-#define PDMA_V3_BASE                  0x6800
+-#define GDMA1_BASE                    0x0500
+-#define GDMA2_BASE                    0x1500
+-#define GDMA3_BASE                    0x0540
+-#define GMAC_BASE                     0x10000
+-#define GSW_BASE                      0x20000
+-
+-/* Ethernet subsystem registers */
+-
+-#define ETHSYS_SYSCFG1_REG            0x14
+-#define SYSCFG1_GE_MODE_S(n)          (12 + ((n) * 2))
+-#define SYSCFG1_GE_MODE_M             0x3
+-#define SYSCFG1_SGMII_SEL_M           GENMASK(9, 8)
+-#define SYSCFG1_SGMII_SEL(gmac)               BIT(9 - (gmac))
+-
+-#define ETHSYS_CLKCFG0_REG            0x2c
+-#define ETHSYS_TRGMII_CLK_SEL362_5    BIT(11)
+-
+-/* Top misc registers */
+-#define TOPMISC_NETSYS_PCS_MUX                0x84
+-#define NETSYS_PCS_MUX_MASK           GENMASK(1, 0)
+-#define MUX_G2_USXGMII_SEL            BIT(1)
+-#define MUX_HSGMII1_G1_SEL            BIT(0)
+-
+-#define USB_PHY_SWITCH_REG            0x218
+-#define QPHY_SEL_MASK                 0x3
+-#define SGMII_QPHY_SEL                        0x2
+-
+-#define MT7629_INFRA_MISC2_REG                0x70c
+-#define INFRA_MISC2_BONDING_OPTION    GENMASK(15, 0)
+-
+-/* SYSCFG1_GE_MODE: GE Modes */
+-#define GE_MODE_RGMII                 0
+-#define GE_MODE_MII                   1
+-#define GE_MODE_MII_PHY                       2
+-#define GE_MODE_RMII                  3
+-
+-/* SGMII subsystem config registers */
+-#define SGMSYS_PCS_CONTROL_1          0x0
+-#define SGMII_LINK_STATUS             BIT(18)
+-#define SGMII_AN_ENABLE                       BIT(12)
+-#define SGMII_AN_RESTART              BIT(9)
+-
+-#define SGMSYS_SGMII_MODE             0x20
+-#define SGMII_AN_MODE                 0x31120103
+-#define SGMII_FORCE_MODE              0x31120019
+-
+-#define SGMSYS_QPHY_PWR_STATE_CTRL    0xe8
+-#define SGMII_PHYA_PWD                        BIT(4)
+-
+-#define SGMSYS_QPHY_WRAP_CTRL         0xec
+-#define SGMII_PN_SWAP_TX_RX           0x03
+-
+-#define SGMSYS_GEN2_SPEED             0x2028
+-#define SGMSYS_GEN2_SPEED_V2          0x128
+-#define SGMSYS_SPEED_MASK             GENMASK(3, 2)
+-#define SGMSYS_SPEED_2500             1
+-
+-/* USXGMII subsystem config registers */
+-/* Register to control USXGMII XFI PLL digital */
+-#define XFI_PLL_DIG_GLB8              0x08
+-#define RG_XFI_PLL_EN                 BIT(31)
+-
+-/* Register to control USXGMII XFI PLL analog */
+-#define XFI_PLL_ANA_GLB8              0x108
+-#define RG_XFI_PLL_ANA_SWWA           0x02283248
+-
+-/* Frame Engine Registers */
+-#define PSE_NO_DROP_CFG_REG           0x108
+-#define PSE_NO_DROP_GDM1              BIT(1)
+-
+-#define FE_GLO_MISC_REG                       0x124
+-#define PDMA_VER_V2                   BIT(4)
+-
+-/* PDMA */
+-#define TX_BASE_PTR_REG(n)            (0x000 + (n) * 0x10)
+-#define TX_MAX_CNT_REG(n)             (0x004 + (n) * 0x10)
+-#define TX_CTX_IDX_REG(n)             (0x008 + (n) * 0x10)
+-#define TX_DTX_IDX_REG(n)             (0x00c + (n) * 0x10)
+-
+-#define RX_BASE_PTR_REG(n)            (0x100 + (n) * 0x10)
+-#define RX_MAX_CNT_REG(n)             (0x104 + (n) * 0x10)
+-#define RX_CRX_IDX_REG(n)             (0x108 + (n) * 0x10)
+-#define RX_DRX_IDX_REG(n)             (0x10c + (n) * 0x10)
+-
+-#define PDMA_GLO_CFG_REG              0x204
+-#define TX_WB_DDONE                   BIT(6)
+-#define RX_DMA_BUSY                   BIT(3)
+-#define RX_DMA_EN                     BIT(2)
+-#define TX_DMA_BUSY                   BIT(1)
+-#define TX_DMA_EN                     BIT(0)
+-
+-#define PDMA_RST_IDX_REG              0x208
+-#define RST_DRX_IDX0                  BIT(16)
+-#define RST_DTX_IDX0                  BIT(0)
+-
+-/* GDMA */
+-#define GDMA_IG_CTRL_REG              0x000
+-#define GDM_ICS_EN                    BIT(22)
+-#define GDM_TCS_EN                    BIT(21)
+-#define GDM_UCS_EN                    BIT(20)
+-#define STRP_CRC                      BIT(16)
+-#define MYMAC_DP_S                    12
+-#define MYMAC_DP_M                    0xf000
+-#define BC_DP_S                               8
+-#define BC_DP_M                               0xf00
+-#define MC_DP_S                               4
+-#define MC_DP_M                               0xf0
+-#define UN_DP_S                               0
+-#define UN_DP_M                               0x0f
+-
+-#define GDMA_EG_CTRL_REG              0x004
+-#define GDMA_CPU_BRIDGE_EN            BIT(31)
+-
+-#define GDMA_MAC_LSB_REG              0x008
+-
+-#define GDMA_MAC_MSB_REG              0x00c
+-
+-/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */
+-#define DP_PDMA                               0
+-#define DP_GDMA1                      1
+-#define DP_GDMA2                      2
+-#define DP_PPE                                4
+-#define DP_QDMA                               5
+-#define DP_DISCARD                    7
+-
+-/* GMAC Registers */
+-
+-#define GMAC_PPSC_REG                 0x0000
+-#define PHY_MDC_CFG                   GENMASK(29, 24)
+-#define MDC_TURBO                     BIT(20)
+-#define MDC_MAX_FREQ                  25000000
+-#define MDC_MAX_DIVIDER                       63
+-
+-#define GMAC_PIAC_REG                 0x0004
+-#define PHY_ACS_ST                    BIT(31)
+-#define MDIO_REG_ADDR_S                       25
+-#define MDIO_REG_ADDR_M                       0x3e000000
+-#define MDIO_PHY_ADDR_S                       20
+-#define MDIO_PHY_ADDR_M                       0x1f00000
+-#define MDIO_CMD_S                    18
+-#define MDIO_CMD_M                    0xc0000
+-#define MDIO_ST_S                     16
+-#define MDIO_ST_M                     0x30000
+-#define MDIO_RW_DATA_S                        0
+-#define MDIO_RW_DATA_M                        0xffff
+-
+-#define GMAC_XGMAC_STS_REG            0x000c
+-#define P1_XGMAC_FORCE_LINK           BIT(15)
+-
+-#define GMAC_MAC_MISC_REG             0x0010
+-#define MISC_MDC_TURBO                        BIT(4)
+-
+-#define GMAC_GSW_CFG_REG              0x0080
+-#define GSWTX_IPG_M                   0xF0000
+-#define GSWTX_IPG_S                   16
+-#define GSWRX_IPG_M                   0xF
+-#define GSWRX_IPG_S                   0
+-
+-/* MDIO_CMD: MDIO commands */
+-#define MDIO_CMD_ADDR                 0
+-#define MDIO_CMD_WRITE                        1
+-#define MDIO_CMD_READ                 2
+-#define MDIO_CMD_READ_C45             3
+-
+-/* MDIO_ST: MDIO start field */
+-#define MDIO_ST_C45                   0
+-#define MDIO_ST_C22                   1
+-
+-#define GMAC_PORT_MCR(p)              (0x0100 + (p) * 0x100)
+-#define MAC_RX_PKT_LEN_S              24
+-#define MAC_RX_PKT_LEN_M              0x3000000
+-#define IPG_CFG_S                     18
+-#define IPG_CFG_M                     0xc0000
+-#define MAC_MODE                      BIT(16)
+-#define FORCE_MODE                    BIT(15)
+-#define MAC_TX_EN                     BIT(14)
+-#define MAC_RX_EN                     BIT(13)
+-#define DEL_RXFIFO_CLR                        BIT(12)
+-#define BKOFF_EN                      BIT(9)
+-#define BACKPR_EN                     BIT(8)
+-#define FORCE_RX_FC                   BIT(5)
+-#define FORCE_TX_FC                   BIT(4)
+-#define FORCE_SPD_S                   2
+-#define FORCE_SPD_M                   0x0c
+-#define FORCE_DPX                     BIT(1)
+-#define FORCE_LINK                    BIT(0)
+-
+-/* Values of IPG_CFG */
+-#define IPG_96BIT                     0
+-#define IPG_96BIT_WITH_SHORT_IPG      1
+-#define IPG_64BIT                     2
+-
+-/* MAC_RX_PKT_LEN: Max RX packet length */
+-#define MAC_RX_PKT_LEN_1518           0
+-#define MAC_RX_PKT_LEN_1536           1
+-#define MAC_RX_PKT_LEN_1552           2
+-#define MAC_RX_PKT_LEN_JUMBO          3
+-
+-/* FORCE_SPD: Forced link speed */
+-#define SPEED_10M                     0
+-#define SPEED_100M                    1
+-#define SPEED_1000M                   2
+-
+-#define GMAC_TRGMII_RCK_CTRL          0x300
+-#define RX_RST                                BIT(31)
+-#define RXC_DQSISEL                   BIT(30)
+-
+-#define GMAC_TRGMII_TD_ODT(n)         (0x354 + (n) * 8)
+-#define TD_DM_DRVN_S                  4
+-#define TD_DM_DRVN_M                  0xf0
+-#define TD_DM_DRVP_S                  0
+-#define TD_DM_DRVP_M                  0x0f
+-
+-/* XGMAC Status Registers */
+-#define XGMAC_STS(x)                  (((x) == 2) ? 0x001C : 0x000C)
+-#define XGMAC_FORCE_LINK(x)           (((x) == 1) ? BIT(31) : BIT(15))
+-
+-/* XGMAC Registers */
+-#define XGMAC_PORT_MCR(x)             (0x2000 + (((x) - 1) * 0x1000))
+-#define XGMAC_TRX_DISABLE             0xf
+-#define XGMAC_FORCE_TX_FC             BIT(5)
+-#define XGMAC_FORCE_RX_FC             BIT(4)
+-
+-/* MT7530 Registers */
+-
+-#define PCR_REG(p)                    (0x2004 + (p) * 0x100)
+-#define PORT_MATRIX_S                 16
+-#define PORT_MATRIX_M                 0xff0000
+-
+-#define PVC_REG(p)                    (0x2010 + (p) * 0x100)
+-#define STAG_VPID_S                   16
+-#define STAG_VPID_M                   0xffff0000
+-#define VLAN_ATTR_S                   6
+-#define VLAN_ATTR_M                   0xc0
+-
+-/* VLAN_ATTR: VLAN attributes */
+-#define VLAN_ATTR_USER                        0
+-#define VLAN_ATTR_STACK                       1
+-#define VLAN_ATTR_TRANSLATION         2
+-#define VLAN_ATTR_TRANSPARENT         3
+-
+-#define PMCR_REG(p)                   (0x3000 + (p) * 0x100)
+-/* XXX: all fields of MT7530 are defined under GMAC_PORT_MCR
+- * MT7531 specific fields are defined below
+- */
+-#define FORCE_MODE_EEE1G              BIT(25)
+-#define FORCE_MODE_EEE100             BIT(26)
+-#define FORCE_MODE_TX_FC              BIT(27)
+-#define FORCE_MODE_RX_FC              BIT(28)
+-#define FORCE_MODE_DPX                        BIT(29)
+-#define FORCE_MODE_SPD                        BIT(30)
+-#define FORCE_MODE_LNK                        BIT(31)
+-#define MT7531_FORCE_MODE             FORCE_MODE_EEE1G | FORCE_MODE_EEE100 |\
+-                                      FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
+-                                      FORCE_MODE_DPX   | FORCE_MODE_SPD | \
+-                                      FORCE_MODE_LNK
+-#define MT7988_FORCE_MODE             FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
+-                                      FORCE_MODE_DPX   | FORCE_MODE_SPD | \
+-                                      FORCE_MODE_LNK
+-
+-/* MT7531 SGMII Registers */
+-#define MT7531_SGMII_REG_BASE         0x5000
+-#define MT7531_SGMII_REG_PORT_BASE    0x1000
+-#define MT7531_SGMII_REG(p, r)                (MT7531_SGMII_REG_BASE + \
+-                                      (p) * MT7531_SGMII_REG_PORT_BASE + (r))
+-#define MT7531_PCS_CONTROL_1(p)               MT7531_SGMII_REG(((p) - 5), 0x00)
+-#define MT7531_SGMII_MODE(p)          MT7531_SGMII_REG(((p) - 5), 0x20)
+-#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(((p) - 5), 0xe8)
+-#define MT7531_PHYA_CTRL_SIGNAL3(p)   MT7531_SGMII_REG(((p) - 5), 0x128)
+-/* XXX: all fields of MT7531 SGMII  are defined under SGMSYS */
+-
+-/* MT753x System Control Register */
+-#define SYS_CTRL_REG                  0x7000
+-#define SW_PHY_RST                    BIT(2)
+-#define SW_SYS_RST                    BIT(1)
+-#define SW_REG_RST                    BIT(0)
+-
+-/* MT7531  */
+-#define MT7531_PHY_IAC                        0x701c
+-/* XXX: all fields are defined under GMAC_PIAC_REG */
+-
+-#define MT7531_CLKGEN_CTRL            0x7500
+-#define CLK_SKEW_OUT_S                        8
+-#define CLK_SKEW_OUT_M                        0x300
+-#define CLK_SKEW_IN_S                 6
+-#define CLK_SKEW_IN_M                 0xc0
+-#define RXCLK_NO_DELAY                        BIT(5)
+-#define TXCLK_NO_REVERSE              BIT(4)
+-#define GP_MODE_S                     1
+-#define GP_MODE_M                     0x06
+-#define GP_CLK_EN                     BIT(0)
+-
+-/* Values of GP_MODE */
+-#define GP_MODE_RGMII                 0
+-#define GP_MODE_MII                   1
+-#define GP_MODE_REV_MII                       2
+-
+-/* Values of CLK_SKEW_IN */
+-#define CLK_SKEW_IN_NO_CHANGE         0
+-#define CLK_SKEW_IN_DELAY_100PPS      1
+-#define CLK_SKEW_IN_DELAY_200PPS      2
+-#define CLK_SKEW_IN_REVERSE           3
+-
+-/* Values of CLK_SKEW_OUT */
+-#define CLK_SKEW_OUT_NO_CHANGE                0
+-#define CLK_SKEW_OUT_DELAY_100PPS     1
+-#define CLK_SKEW_OUT_DELAY_200PPS     2
+-#define CLK_SKEW_OUT_REVERSE          3
+-
+-#define HWTRAP_REG                    0x7800
+-/* MT7530 Modified Hardware Trap Status Registers */
+-#define MHWTRAP_REG                   0x7804
+-#define CHG_TRAP                      BIT(16)
+-#define LOOPDET_DIS                   BIT(14)
+-#define P5_INTF_SEL_S                 13
+-#define P5_INTF_SEL_M                 0x2000
+-#define SMI_ADDR_S                    11
+-#define SMI_ADDR_M                    0x1800
+-#define XTAL_FSEL_S                   9
+-#define XTAL_FSEL_M                   0x600
+-#define P6_INTF_DIS                   BIT(8)
+-#define P5_INTF_MODE_S                        7
+-#define P5_INTF_MODE_M                        0x80
+-#define P5_INTF_DIS                   BIT(6)
+-#define C_MDIO_BPS                    BIT(5)
+-#define CHIP_MODE_S                   0
+-#define CHIP_MODE_M                   0x0f
+-
+-/* P5_INTF_SEL: Interface type of Port5 */
+-#define P5_INTF_SEL_GPHY              0
+-#define P5_INTF_SEL_GMAC5             1
+-
+-/* P5_INTF_MODE: Interface mode of Port5 */
+-#define P5_INTF_MODE_GMII_MII         0
+-#define P5_INTF_MODE_RGMII            1
+-
+-#define MT7530_P6ECR                  0x7830
+-#define P6_INTF_MODE_M                        0x3
+-#define P6_INTF_MODE_S                        0
+-
+-/* P6_INTF_MODE: Interface mode of Port6 */
+-#define P6_INTF_MODE_RGMII            0
+-#define P6_INTF_MODE_TRGMII           1
+-
+-#define NUM_TRGMII_CTRL                       5
+-
+-#define MT7530_TRGMII_RD(n)           (0x7a10 + (n) * 8)
+-#define RD_TAP_S                      0
+-#define RD_TAP_M                      0x7f
+-
+-#define MT7530_TRGMII_TD_ODT(n)               (0x7a54 + (n) * 8)
+-/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */
+-
+-/* TOP Signals Status Register */
+-#define MT7531_TOP_SIG_SR             0x780c
+-#define PAD_MCM_SMI_EN                        BIT(0)
+-#define PAD_DUAL_SGMII_EN             BIT(1)
+-
+-/* MT7531 PLLGP Registers */
+-#define MT7531_PLLGP_EN                       0x7820
+-#define EN_COREPLL                    BIT(2)
+-#define SW_CLKSW                      BIT(1)
+-#define SW_PLLGP                      BIT(0)
+-
+-#define MT7531_PLLGP_CR0              0x78a8
+-#define RG_COREPLL_EN                 BIT(22)
+-#define RG_COREPLL_POSDIV_S           23
+-#define RG_COREPLL_POSDIV_M           0x3800000
+-#define RG_COREPLL_SDM_PCW_S          1
+-#define RG_COREPLL_SDM_PCW_M          0x3ffffe
+-#define RG_COREPLL_SDM_PCW_CHG                BIT(0)
+-
+-/* MT7531 RGMII and SGMII PLL clock */
+-#define MT7531_ANA_PLLGP_CR2          0x78b0
+-#define MT7531_ANA_PLLGP_CR5          0x78bc
+-
+-/* MT7531 GPIO GROUP IOLB SMT0 Control */
+-#define MT7531_SMT0_IOLB              0x7f04
+-#define SMT_IOLB_5_SMI_MDC_EN         BIT(5)
+-
+-/* MT7530 GPHY MDIO Indirect Access Registers */
+-#define MII_MMD_ACC_CTL_REG           0x0d
+-#define MMD_CMD_S                     14
+-#define MMD_CMD_M                     0xc000
+-#define MMD_DEVAD_S                   0
+-#define MMD_DEVAD_M                   0x1f
+-
+-/* MMD_CMD: MMD commands */
+-#define MMD_ADDR                      0
+-#define MMD_DATA                      1
+-#define MMD_DATA_RW_POST_INC          2
+-#define MMD_DATA_W_POST_INC           3
+-
+-#define MII_MMD_ADDR_DATA_REG         0x0e
+-
+-/* MT7530 GPHY MDIO MMD Registers */
+-#define CORE_PLL_GROUP2                       0x401
+-#define RG_SYSPLL_EN_NORMAL           BIT(15)
+-#define RG_SYSPLL_VODEN                       BIT(14)
+-#define RG_SYSPLL_POSDIV_S            5
+-#define RG_SYSPLL_POSDIV_M            0x60
+-
+-#define CORE_PLL_GROUP4                       0x403
+-#define MT7531_BYPASS_MODE            BIT(4)
+-#define MT7531_POWER_ON_OFF           BIT(5)
+-#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_S          0
+-#define RG_LCDDS_PCW_NCPO1_M          0xffff
+-
+-#define CORE_PLL_GROUP6                       0x405
+-#define RG_LCDDS_PCW_NCPO0_S          0
+-#define RG_LCDDS_PCW_NCPO0_M          0xffff
+-
+-#define CORE_PLL_GROUP7                       0x406
+-#define RG_LCDDS_PWDB                 BIT(15)
+-#define RG_LCDDS_ISO_EN                       BIT(13)
+-#define RG_LCCDS_C_S                  4
+-#define RG_LCCDS_C_M                  0x70
+-#define RG_LCDDS_PCW_NCPO_CHG         BIT(3)
+-
+-#define CORE_PLL_GROUP10              0x409
+-#define RG_LCDDS_SSC_DELTA_S          0
+-#define RG_LCDDS_SSC_DELTA_M          0xfff
+-
+-#define CORE_PLL_GROUP11              0x40a
+-#define RG_LCDDS_SSC_DELTA1_S         0
+-#define RG_LCDDS_SSC_DELTA1_M         0xfff
+-
+-#define CORE_GSWPLL_GRP1              0x40d
+-#define RG_GSWPLL_POSDIV_200M_S               12
+-#define RG_GSWPLL_POSDIV_200M_M               0x3000
+-#define RG_GSWPLL_EN_PRE              BIT(11)
+-#define RG_GSWPLL_FBKDIV_200M_S               0
+-#define RG_GSWPLL_FBKDIV_200M_M               0xff
+-
+-#define CORE_GSWPLL_GRP2              0x40e
+-#define RG_GSWPLL_POSDIV_500M_S               8
+-#define RG_GSWPLL_POSDIV_500M_M               0x300
+-#define RG_GSWPLL_FBKDIV_500M_S               0
+-#define RG_GSWPLL_FBKDIV_500M_M               0xff
+-
+-#define CORE_TRGMII_GSW_CLK_CG                0x410
+-#define REG_GSWCK_EN                  BIT(0)
+-#define REG_TRGMIICK_EN                       BIT(1)
+-
+-/* Extend PHY Control Register 3 */
+-#define PHY_EXT_REG_14                        0x14
+-
+-/* Fields of PHY_EXT_REG_14 */
+-#define PHY_EN_DOWN_SHFIT             BIT(4)
+-
+-/* Extend PHY Control Register 4 */
+-#define PHY_EXT_REG_17                        0x17
+-
+-/* Fields of PHY_EXT_REG_17 */
+-#define PHY_LINKDOWN_POWER_SAVING_EN  BIT(4)
+-
+-/* PHY RXADC Control Register 7 */
+-#define PHY_DEV1E_REG_0C6             0x0c6
+-
+-/* Fields of PHY_DEV1E_REG_0C6 */
+-#define PHY_POWER_SAVING_S            8
+-#define PHY_POWER_SAVING_M            0x300
+-#define PHY_POWER_SAVING_TX           0x0
+-
+-/* PDMA descriptors */
+-struct mtk_rx_dma {
+-      unsigned int rxd1;
+-      unsigned int rxd2;
+-      unsigned int rxd3;
+-      unsigned int rxd4;
+-} __packed __aligned(4);
+-
+-struct mtk_rx_dma_v2 {
+-      unsigned int rxd1;
+-      unsigned int rxd2;
+-      unsigned int rxd3;
+-      unsigned int rxd4;
+-      unsigned int rxd5;
+-      unsigned int rxd6;
+-      unsigned int rxd7;
+-      unsigned int rxd8;
+-} __packed __aligned(4);
+-
+-struct mtk_tx_dma {
+-      unsigned int txd1;
+-      unsigned int txd2;
+-      unsigned int txd3;
+-      unsigned int txd4;
+-} __packed __aligned(4);
+-
+-struct mtk_tx_dma_v2 {
+-      unsigned int txd1;
+-      unsigned int txd2;
+-      unsigned int txd3;
+-      unsigned int txd4;
+-      unsigned int txd5;
+-      unsigned int txd6;
+-      unsigned int txd7;
+-      unsigned int txd8;
+-} __packed __aligned(4);
+-
+-/* PDMA TXD fields */
+-#define PDMA_TXD2_DDONE                       BIT(31)
+-#define PDMA_TXD2_LS0                 BIT(30)
+-#define PDMA_V1_TXD2_SDL0_M           GENMASK(29, 16)
+-#define PDMA_V1_TXD2_SDL0_SET(_v)     FIELD_PREP(PDMA_V1_TXD2_SDL0_M, (_v))
+-#define PDMA_V2_TXD2_SDL0_M           GENMASK(23, 8)
+-#define PDMA_V2_TXD2_SDL0_SET(_v)     FIELD_PREP(PDMA_V2_TXD2_SDL0_M, (_v))
+-
+-#define PDMA_V1_TXD4_FPORT_M          GENMASK(27, 25)
+-#define PDMA_V1_TXD4_FPORT_SET(_v)    FIELD_PREP(PDMA_V1_TXD4_FPORT_M, (_v))
+-#define PDMA_V2_TXD4_FPORT_M          GENMASK(27, 24)
+-#define PDMA_V2_TXD4_FPORT_SET(_v)    FIELD_PREP(PDMA_V2_TXD4_FPORT_M, (_v))
+-
+-#define PDMA_V2_TXD5_FPORT_M          GENMASK(19, 16)
+-#define PDMA_V2_TXD5_FPORT_SET(_v)    FIELD_PREP(PDMA_V2_TXD5_FPORT_M, (_v))
+-
+-/* PDMA RXD fields */
+-#define PDMA_RXD2_DDONE                       BIT(31)
+-#define PDMA_RXD2_LS0                 BIT(30)
+-#define PDMA_V1_RXD2_PLEN0_M          GENMASK(29, 16)
+-#define PDMA_V1_RXD2_PLEN0_GET(_v)    FIELD_GET(PDMA_V1_RXD2_PLEN0_M, (_v))
+-#define PDMA_V1_RXD2_PLEN0_SET(_v)    FIELD_PREP(PDMA_V1_RXD2_PLEN0_M, (_v))
+-#define PDMA_V2_RXD2_PLEN0_M          GENMASK(23, 8)
+-#define PDMA_V2_RXD2_PLEN0_GET(_v)    FIELD_GET(PDMA_V2_RXD2_PLEN0_M, (_v))
+-#define PDMA_V2_RXD2_PLEN0_SET(_v)    FIELD_PREP(PDMA_V2_RXD2_PLEN0_M, (_v))
+-
+-#endif /* _MTK_ETH_H_ */
+--- /dev/null
++++ b/drivers/net/mtk_eth/mtk_eth.h
+@@ -0,0 +1,429 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2025 MediaTek Inc.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ * Author: Mark Lee <mark-mc.lee@mediatek.com>
++ */
++
++#ifndef _MTK_ETH_H_
++#define _MTK_ETH_H_
++
++#include <linker_lists.h>
++#include <linux/bitops.h>
++#include <linux/bitfield.h>
++
++struct mtk_eth_priv;
++struct mtk_eth_switch_priv;
++
++/* struct mtk_soc_data -      This is the structure holding all differences
++ *                            among various plaforms
++ * @caps                      Flags shown the extra capability for the SoC
++ * @ana_rgc3:                 The offset for register ANA_RGC3 related to
++ *                            sgmiisys syscon
++ * @gdma_count:                       Number of GDMAs
++ * @pdma_base:                        Register base of PDMA block
++ * @txd_size:                 Tx DMA descriptor size.
++ * @rxd_size:                 Rx DMA descriptor size.
++ */
++struct mtk_soc_data {
++      u32 caps;
++      u32 ana_rgc3;
++      u32 gdma_count;
++      u32 pdma_base;
++      u32 txd_size;
++      u32 rxd_size;
++};
++
++struct mtk_eth_switch {
++      const char *name;
++      const char *desc;
++      size_t priv_size;
++      u32 reset_wait_time;
++
++      int (*detect)(struct mtk_eth_priv *priv);
++      int (*setup)(struct mtk_eth_switch_priv *priv);
++      int (*cleanup)(struct mtk_eth_switch_priv *priv);
++      void (*mac_control)(struct mtk_eth_switch_priv *priv, bool enable);
++};
++
++#define MTK_ETH_SWITCH(__name)        \
++      ll_entry_declare(struct mtk_eth_switch, __name, mtk_eth_switch)
++
++struct mtk_eth_switch_priv {
++      struct mtk_eth_priv *eth;
++      const struct mtk_eth_switch *sw;
++      const struct mtk_soc_data *soc;
++      void *ethsys_base;
++      int phy_interface;
++};
++
++enum mkt_eth_capabilities {
++      MTK_TRGMII_BIT,
++      MTK_TRGMII_MT7621_CLK_BIT,
++      MTK_U3_COPHY_V2_BIT,
++      MTK_INFRA_BIT,
++      MTK_NETSYS_V2_BIT,
++      MTK_NETSYS_V3_BIT,
++
++      /* PATH BITS */
++      MTK_ETH_PATH_GMAC1_TRGMII_BIT,
++      MTK_ETH_PATH_GMAC2_SGMII_BIT,
++      MTK_ETH_PATH_MT7622_SGMII_BIT,
++      MTK_ETH_PATH_MT7629_GMAC2_BIT,
++};
++
++#define MTK_TRGMII                    BIT(MTK_TRGMII_BIT)
++#define MTK_TRGMII_MT7621_CLK         BIT(MTK_TRGMII_MT7621_CLK_BIT)
++#define MTK_U3_COPHY_V2                       BIT(MTK_U3_COPHY_V2_BIT)
++#define MTK_INFRA                     BIT(MTK_INFRA_BIT)
++#define MTK_NETSYS_V2                 BIT(MTK_NETSYS_V2_BIT)
++#define MTK_NETSYS_V3                 BIT(MTK_NETSYS_V3_BIT)
++
++/* Supported path present on SoCs */
++#define MTK_ETH_PATH_GMAC1_TRGMII     BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
++#define MTK_ETH_PATH_GMAC2_SGMII      BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
++#define MTK_ETH_PATH_MT7622_SGMII     BIT(MTK_ETH_PATH_MT7622_SGMII_BIT)
++#define MTK_ETH_PATH_MT7629_GMAC2     BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT)
++
++#define MTK_GMAC1_TRGMII      (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
++
++#define MTK_GMAC2_U3_QPHY     (MTK_ETH_PATH_GMAC2_SGMII | MTK_U3_COPHY_V2 | MTK_INFRA)
++
++#define MTK_HAS_CAPS(caps, _x)                (((caps) & (_x)) == (_x))
++
++#define MT7621_CAPS  (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK)
++
++#define MT7622_CAPS  (MTK_ETH_PATH_MT7622_SGMII)
++
++#define MT7623_CAPS  (MTK_GMAC1_TRGMII)
++
++#define MT7629_CAPS  (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA)
++
++#define MT7981_CAPS  (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2)
++
++#define MT7986_CAPS  (MTK_NETSYS_V2)
++
++#define MT7987_CAPS  (MTK_NETSYS_V3 | MTK_GMAC2_U3_QPHY | MTK_INFRA)
++
++#define MT7988_CAPS  (MTK_NETSYS_V3 | MTK_INFRA)
++
++/* Frame Engine Register Bases */
++#define PDMA_V1_BASE                  0x0800
++#define PDMA_V2_BASE                  0x6000
++#define PDMA_V3_BASE                  0x6800
++#define GDMA1_BASE                    0x0500
++#define GDMA2_BASE                    0x1500
++#define GDMA3_BASE                    0x0540
++#define GMAC_BASE                     0x10000
++#define GSW_BASE                      0x20000
++
++/* Ethernet subsystem registers */
++#define ETHSYS_SYSCFG1_REG            0x14
++#define SYSCFG1_GE_MODE_S(n)          (12 + ((n) * 2))
++#define SYSCFG1_GE_MODE_M             0x3
++#define SYSCFG1_SGMII_SEL_M           GENMASK(9, 8)
++#define SYSCFG1_SGMII_SEL(gmac)               BIT(9 - (gmac))
++
++#define ETHSYS_CLKCFG0_REG            0x2c
++#define ETHSYS_TRGMII_CLK_SEL362_5    BIT(11)
++
++/* Top misc registers */
++#define TOPMISC_NETSYS_PCS_MUX                0x84
++#define NETSYS_PCS_MUX_MASK           GENMASK(1, 0)
++#define MUX_G2_USXGMII_SEL            BIT(1)
++#define MUX_HSGMII1_G1_SEL            BIT(0)
++
++#define USB_PHY_SWITCH_REG            0x218
++#define QPHY_SEL_MASK                 0x3
++#define SGMII_QPHY_SEL                        0x2
++
++#define MT7629_INFRA_MISC2_REG                0x70c
++#define INFRA_MISC2_BONDING_OPTION    GENMASK(15, 0)
++
++/* SYSCFG1_GE_MODE: GE Modes */
++#define GE_MODE_RGMII                 0
++#define GE_MODE_MII                   1
++#define GE_MODE_MII_PHY                       2
++#define GE_MODE_RMII                  3
++
++/* SGMII subsystem config registers */
++#define SGMSYS_PCS_CONTROL_1          0x0
++#define SGMII_LINK_STATUS             BIT(18)
++#define SGMII_AN_ENABLE                       BIT(12)
++#define SGMII_AN_RESTART              BIT(9)
++
++#define SGMSYS_SGMII_MODE             0x20
++#define SGMII_AN_MODE                 0x31120103
++#define SGMII_FORCE_MODE              0x31120019
++
++#define SGMSYS_QPHY_PWR_STATE_CTRL    0xe8
++#define SGMII_PHYA_PWD                        BIT(4)
++
++#define SGMSYS_QPHY_WRAP_CTRL         0xec
++#define SGMII_PN_SWAP_TX_RX           0x03
++
++#define SGMSYS_GEN2_SPEED             0x2028
++#define SGMSYS_GEN2_SPEED_V2          0x128
++#define SGMSYS_SPEED_MASK             GENMASK(3, 2)
++#define SGMSYS_SPEED_2500             1
++
++/* USXGMII subsystem config registers */
++/* Register to control USXGMII XFI PLL digital */
++#define XFI_PLL_DIG_GLB8              0x08
++#define RG_XFI_PLL_EN                 BIT(31)
++
++/* Register to control USXGMII XFI PLL analog */
++#define XFI_PLL_ANA_GLB8              0x108
++#define RG_XFI_PLL_ANA_SWWA           0x02283248
++
++/* Frame Engine Registers */
++#define PSE_NO_DROP_CFG_REG           0x108
++#define PSE_NO_DROP_GDM1              BIT(1)
++
++#define FE_GLO_MISC_REG                       0x124
++#define PDMA_VER_V2                   BIT(4)
++
++/* PDMA */
++#define TX_BASE_PTR_REG(n)            (0x000 + (n) * 0x10)
++#define TX_MAX_CNT_REG(n)             (0x004 + (n) * 0x10)
++#define TX_CTX_IDX_REG(n)             (0x008 + (n) * 0x10)
++#define TX_DTX_IDX_REG(n)             (0x00c + (n) * 0x10)
++
++#define RX_BASE_PTR_REG(n)            (0x100 + (n) * 0x10)
++#define RX_MAX_CNT_REG(n)             (0x104 + (n) * 0x10)
++#define RX_CRX_IDX_REG(n)             (0x108 + (n) * 0x10)
++#define RX_DRX_IDX_REG(n)             (0x10c + (n) * 0x10)
++
++#define PDMA_GLO_CFG_REG              0x204
++#define TX_WB_DDONE                   BIT(6)
++#define RX_DMA_BUSY                   BIT(3)
++#define RX_DMA_EN                     BIT(2)
++#define TX_DMA_BUSY                   BIT(1)
++#define TX_DMA_EN                     BIT(0)
++
++#define PDMA_RST_IDX_REG              0x208
++#define RST_DRX_IDX0                  BIT(16)
++#define RST_DTX_IDX0                  BIT(0)
++
++/* GDMA */
++#define GDMA_IG_CTRL_REG              0x000
++#define GDM_ICS_EN                    BIT(22)
++#define GDM_TCS_EN                    BIT(21)
++#define GDM_UCS_EN                    BIT(20)
++#define STRP_CRC                      BIT(16)
++#define MYMAC_DP_S                    12
++#define MYMAC_DP_M                    0xf000
++#define BC_DP_S                               8
++#define BC_DP_M                               0xf00
++#define MC_DP_S                               4
++#define MC_DP_M                               0xf0
++#define UN_DP_S                               0
++#define UN_DP_M                               0x0f
++
++#define GDMA_EG_CTRL_REG              0x004
++#define GDMA_CPU_BRIDGE_EN            BIT(31)
++
++#define GDMA_MAC_LSB_REG              0x008
++
++#define GDMA_MAC_MSB_REG              0x00c
++
++/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */
++#define DP_PDMA                               0
++#define DP_GDMA1                      1
++#define DP_GDMA2                      2
++#define DP_PPE                                4
++#define DP_QDMA                               5
++#define DP_DISCARD                    7
++
++/* GMAC Registers */
++#define GMAC_PPSC_REG                 0x0000
++#define PHY_MDC_CFG                   GENMASK(29, 24)
++#define MDC_TURBO                     BIT(20)
++#define MDC_MAX_FREQ                  25000000
++#define MDC_MAX_DIVIDER                       63
++
++#define GMAC_PIAC_REG                 0x0004
++#define PHY_ACS_ST                    BIT(31)
++#define MDIO_REG_ADDR_S                       25
++#define MDIO_REG_ADDR_M                       0x3e000000
++#define MDIO_PHY_ADDR_S                       20
++#define MDIO_PHY_ADDR_M                       0x1f00000
++#define MDIO_CMD_S                    18
++#define MDIO_CMD_M                    0xc0000
++#define MDIO_ST_S                     16
++#define MDIO_ST_M                     0x30000
++#define MDIO_RW_DATA_S                        0
++#define MDIO_RW_DATA_M                        0xffff
++
++#define GMAC_XGMAC_STS_REG            0x000c
++#define P1_XGMAC_FORCE_LINK           BIT(15)
++
++#define GMAC_MAC_MISC_REG             0x0010
++#define MISC_MDC_TURBO                        BIT(4)
++
++#define GMAC_GSW_CFG_REG              0x0080
++#define GSWTX_IPG_M                   0xF0000
++#define GSWTX_IPG_S                   16
++#define GSWRX_IPG_M                   0xF
++#define GSWRX_IPG_S                   0
++
++/* MDIO_CMD: MDIO commands */
++#define MDIO_CMD_ADDR                 0
++#define MDIO_CMD_WRITE                        1
++#define MDIO_CMD_READ                 2
++#define MDIO_CMD_READ_C45             3
++
++/* MDIO_ST: MDIO start field */
++#define MDIO_ST_C45                   0
++#define MDIO_ST_C22                   1
++
++#define GMAC_PORT_MCR(p)              (0x0100 + (p) * 0x100)
++#define MAC_RX_PKT_LEN_S              24
++#define MAC_RX_PKT_LEN_M              0x3000000
++#define IPG_CFG_S                     18
++#define IPG_CFG_M                     0xc0000
++#define MAC_MODE                      BIT(16)
++#define FORCE_MODE                    BIT(15)
++#define MAC_TX_EN                     BIT(14)
++#define MAC_RX_EN                     BIT(13)
++#define DEL_RXFIFO_CLR                        BIT(12)
++#define BKOFF_EN                      BIT(9)
++#define BACKPR_EN                     BIT(8)
++#define FORCE_RX_FC                   BIT(5)
++#define FORCE_TX_FC                   BIT(4)
++#define FORCE_SPD_S                   2
++#define FORCE_SPD_M                   0x0c
++#define FORCE_DPX                     BIT(1)
++#define FORCE_LINK                    BIT(0)
++
++/* Values of IPG_CFG */
++#define IPG_96BIT                     0
++#define IPG_96BIT_WITH_SHORT_IPG      1
++#define IPG_64BIT                     2
++
++/* MAC_RX_PKT_LEN: Max RX packet length */
++#define MAC_RX_PKT_LEN_1518           0
++#define MAC_RX_PKT_LEN_1536           1
++#define MAC_RX_PKT_LEN_1552           2
++#define MAC_RX_PKT_LEN_JUMBO          3
++
++/* FORCE_SPD: Forced link speed */
++#define SPEED_10M                     0
++#define SPEED_100M                    1
++#define SPEED_1000M                   2
++
++#define GMAC_TRGMII_RCK_CTRL          0x300
++#define RX_RST                                BIT(31)
++#define RXC_DQSISEL                   BIT(30)
++
++#define NUM_TRGMII_CTRL                       5
++
++#define GMAC_TRGMII_TD_ODT(n)         (0x354 + (n) * 8)
++#define TD_DM_DRVN_S                  4
++#define TD_DM_DRVN_M                  0xf0
++#define TD_DM_DRVP_S                  0
++#define TD_DM_DRVP_M                  0x0f
++
++/* XGMAC Status Registers */
++#define XGMAC_STS(x)                  (((x) == 2) ? 0x001C : 0x000C)
++#define XGMAC_FORCE_LINK(x)           (((x) == 1) ? BIT(31) : BIT(15))
++
++/* XGMAC Registers */
++#define XGMAC_PORT_MCR(x)             (0x2000 + (((x) - 1) * 0x1000))
++#define XGMAC_TRX_DISABLE             0xf
++#define XGMAC_FORCE_TX_FC             BIT(5)
++#define XGMAC_FORCE_RX_FC             BIT(4)
++
++/* MDIO Indirect Access Registers */
++#define MII_MMD_ACC_CTL_REG           0x0d
++#define MMD_CMD_S                     14
++#define MMD_CMD_M                     0xc000
++#define MMD_DEVAD_S                   0
++#define MMD_DEVAD_M                   0x1f
++
++/* MMD_CMD: MMD commands */
++#define MMD_ADDR                      0
++#define MMD_DATA                      1
++#define MMD_DATA_RW_POST_INC          2
++#define MMD_DATA_W_POST_INC           3
++
++#define MII_MMD_ADDR_DATA_REG         0x0e
++
++/* PDMA descriptors */
++struct mtk_rx_dma {
++      unsigned int rxd1;
++      unsigned int rxd2;
++      unsigned int rxd3;
++      unsigned int rxd4;
++} __packed __aligned(4);
++
++struct mtk_rx_dma_v2 {
++      unsigned int rxd1;
++      unsigned int rxd2;
++      unsigned int rxd3;
++      unsigned int rxd4;
++      unsigned int rxd5;
++      unsigned int rxd6;
++      unsigned int rxd7;
++      unsigned int rxd8;
++} __packed __aligned(4);
++
++struct mtk_tx_dma {
++      unsigned int txd1;
++      unsigned int txd2;
++      unsigned int txd3;
++      unsigned int txd4;
++} __packed __aligned(4);
++
++struct mtk_tx_dma_v2 {
++      unsigned int txd1;
++      unsigned int txd2;
++      unsigned int txd3;
++      unsigned int txd4;
++      unsigned int txd5;
++      unsigned int txd6;
++      unsigned int txd7;
++      unsigned int txd8;
++} __packed __aligned(4);
++
++/* PDMA TXD fields */
++#define PDMA_TXD2_DDONE                       BIT(31)
++#define PDMA_TXD2_LS0                 BIT(30)
++#define PDMA_V1_TXD2_SDL0_M           GENMASK(29, 16)
++#define PDMA_V1_TXD2_SDL0_SET(_v)     FIELD_PREP(PDMA_V1_TXD2_SDL0_M, (_v))
++#define PDMA_V2_TXD2_SDL0_M           GENMASK(23, 8)
++#define PDMA_V2_TXD2_SDL0_SET(_v)     FIELD_PREP(PDMA_V2_TXD2_SDL0_M, (_v))
++
++#define PDMA_V1_TXD4_FPORT_M          GENMASK(27, 25)
++#define PDMA_V1_TXD4_FPORT_SET(_v)    FIELD_PREP(PDMA_V1_TXD4_FPORT_M, (_v))
++#define PDMA_V2_TXD4_FPORT_M          GENMASK(27, 24)
++#define PDMA_V2_TXD4_FPORT_SET(_v)    FIELD_PREP(PDMA_V2_TXD4_FPORT_M, (_v))
++
++#define PDMA_V2_TXD5_FPORT_M          GENMASK(19, 16)
++#define PDMA_V2_TXD5_FPORT_SET(_v)    FIELD_PREP(PDMA_V2_TXD5_FPORT_M, (_v))
++
++/* PDMA RXD fields */
++#define PDMA_RXD2_DDONE                       BIT(31)
++#define PDMA_RXD2_LS0                 BIT(30)
++#define PDMA_V1_RXD2_PLEN0_M          GENMASK(29, 16)
++#define PDMA_V1_RXD2_PLEN0_GET(_v)    FIELD_GET(PDMA_V1_RXD2_PLEN0_M, (_v))
++#define PDMA_V1_RXD2_PLEN0_SET(_v)    FIELD_PREP(PDMA_V1_RXD2_PLEN0_M, (_v))
++#define PDMA_V2_RXD2_PLEN0_M          GENMASK(23, 8)
++#define PDMA_V2_RXD2_PLEN0_GET(_v)    FIELD_GET(PDMA_V2_RXD2_PLEN0_M, (_v))
++#define PDMA_V2_RXD2_PLEN0_SET(_v)    FIELD_PREP(PDMA_V2_RXD2_PLEN0_M, (_v))
++
++void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set);
++void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set);
++void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set);
++
++int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg);
++int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data);
++int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg);
++int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
++                u16 val);
++int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg);
++int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
++                    u16 val);
++
++#endif /* _MTK_ETH_H_ */
diff --git a/package/boot/uboot-mediatek/patches/061-02-net-mediatek-add-support-for-MediaTek-MT7987-SoC.patch b/package/boot/uboot-mediatek/patches/061-02-net-mediatek-add-support-for-MediaTek-MT7987-SoC.patch
new file mode 100644 (file)
index 0000000..183c712
--- /dev/null
@@ -0,0 +1,63 @@
+From fe106f2093733b8bd61946372945dfea552b4755 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 10 Jan 2025 16:41:20 +0800
+Subject: [PATCH 2/3] net: mediatek: add support for MediaTek MT7987 SoC
+
+This patch adds support for MediaTek MT7987.
+
+MT7987 features MediaTek NETSYS v3, similar to MT7988, features three GMACs
+which support 2.5Gb HSGMII. One 2.5Gb PHY is also embedded an can be
+connected to a dedicated GMAC.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth/Kconfig   |  4 ++--
+ drivers/net/mtk_eth/mtk_eth.c | 10 ++++++++++
+ 2 files changed, 12 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/mtk_eth/Kconfig
++++ b/drivers/net/mtk_eth/Kconfig
+@@ -16,7 +16,7 @@ config MTK_ETH_SGMII
+ config MTK_ETH_XGMII
+       bool
+-      default y if TARGET_MT7988
++      default y if TARGET_MT7987 || TARGET_MT7988
+ config MTK_ETH_SWITCH_MT7530
+       bool "Support for MediaTek MT7530 ethernet switch"
+@@ -25,7 +25,7 @@ config MTK_ETH_SWITCH_MT7530
+ config MTK_ETH_SWITCH_MT7531
+       bool "Support for MediaTek MT7531 ethernet switch"
+       default y if TARGET_MT7622 || TARGET_MT7629 || TARGET_MT7981 || \
+-                   TARGET_MT7986
++                   TARGET_MT7986 || TARGET_MT7987
+ config MTK_ETH_SWITCH_MT7988
+       bool "Support for MediaTek MT7988 built-in ethernet switch"
+--- a/drivers/net/mtk_eth/mtk_eth.c
++++ b/drivers/net/mtk_eth/mtk_eth.c
+@@ -1477,6 +1477,15 @@ static const struct mtk_soc_data mt7988_
+       .rxd_size = sizeof(struct mtk_rx_dma_v2),
+ };
++static const struct mtk_soc_data mt7987_data = {
++      .caps = MT7987_CAPS,
++      .ana_rgc3 = 0x128,
++      .gdma_count = 3,
++      .pdma_base = PDMA_V3_BASE,
++      .txd_size = sizeof(struct mtk_tx_dma_v2),
++      .rxd_size = sizeof(struct mtk_rx_dma_v2),
++};
++
+ static const struct mtk_soc_data mt7986_data = {
+       .caps = MT7986_CAPS,
+       .ana_rgc3 = 0x128,
+@@ -1531,6 +1540,7 @@ static const struct mtk_soc_data mt7621_
+ static const struct udevice_id mtk_eth_ids[] = {
+       { .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data },
++      { .compatible = "mediatek,mt7987-eth", .data = (ulong)&mt7987_data },
+       { .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data },
+       { .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data },
+       { .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data },
diff --git a/package/boot/uboot-mediatek/patches/061-03-net-mediatek-add-support-for-Airoha-AN8855-ethernet-.patch b/package/boot/uboot-mediatek/patches/061-03-net-mediatek-add-support-for-Airoha-AN8855-ethernet-.patch
new file mode 100644 (file)
index 0000000..8e4f439
--- /dev/null
@@ -0,0 +1,1133 @@
+From cedafee9ff39d13aaf8b80361b673445a85f117e Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Fri, 10 Jan 2025 16:41:24 +0800
+Subject: [PATCH 3/3] net: mediatek: add support for Airoha AN8855 ethernet
+ switch
+
+Airoha AN8855 is a 5-port gigabit switch with a 2.5G HSGMII CPU port
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/net/mtk_eth/Kconfig  |    4 +
+ drivers/net/mtk_eth/Makefile |    1 +
+ drivers/net/mtk_eth/an8855.c | 1096 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 1101 insertions(+)
+ create mode 100644 drivers/net/mtk_eth/an8855.c
+
+--- a/drivers/net/mtk_eth/Kconfig
++++ b/drivers/net/mtk_eth/Kconfig
+@@ -32,4 +32,8 @@ config MTK_ETH_SWITCH_MT7988
+       depends on TARGET_MT7988
+       default y
++config MTK_ETH_SWITCH_AN8855
++      bool "Support for Airoha AN8855 ethernet switch"
++      default y if TARGET_MT7981 || TARGET_MT7987
++
+ endif # MEDIATEK_ETH
+--- a/drivers/net/mtk_eth/Makefile
++++ b/drivers/net/mtk_eth/Makefile
+@@ -7,3 +7,4 @@ obj-y += mtk_eth.o
+ obj-$(CONFIG_MTK_ETH_SWITCH_MT7530) += mt753x.o mt7530.o
+ obj-$(CONFIG_MTK_ETH_SWITCH_MT7531) += mt753x.o mt7531.o
+ obj-$(CONFIG_MTK_ETH_SWITCH_MT7988) += mt753x.o mt7988.o
++obj-$(CONFIG_MTK_ETH_SWITCH_AN8855) += an8855.o
+--- /dev/null
++++ b/drivers/net/mtk_eth/an8855.c
+@@ -0,0 +1,1096 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2025 MediaTek Inc.
++ *
++ * Author: Neal Yen <neal.yen@mediatek.com>
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <phy.h>
++#include <miiphy.h>
++#include <linux/bitops.h>
++#include <linux/delay.h>
++#include <linux/mdio.h>
++#include <linux/mii.h>
++#include "mtk_eth.h"
++
++/* AN8855 Register Definitions */
++#define AN8855_SYS_CTRL_REG                   0x100050c0
++#define AN8855_SW_SYS_RST                     BIT(31)
++
++#define AN8855_PMCR_REG(p)                    (0x10210000 + (p) * 0x200)
++#define AN8855_FORCE_MODE_LNK                 BIT(31)
++#define AN8855_FORCE_MODE                     0xb31593f0
++
++#define AN8855_PORT_CTRL_BASE                 (0x10208000)
++#define AN8855_PORT_CTRL_REG(p, r)            (AN8855_PORT_CTRL_BASE + (p) * 0x200 + (r))
++
++#define AN8855_PORTMATRIX_REG(p)              AN8855_PORT_CTRL_REG(p, 0x44)
++
++#define AN8855_PVC(p)                         AN8855_PORT_CTRL_REG(p, 0x10)
++#define AN8855_STAG_VPID_S                    16
++#define AN8855_STAG_VPID_M                    0xffff0000
++#define AN8855_VLAN_ATTR_S                    6
++#define AN8855_VLAN_ATTR_M                    0xc0
++
++#define VLAN_ATTR_USER                                0
++
++#define AN8855_INT_MASK                               0x100050F0
++#define AN8855_INT_SYS_BIT                    BIT(15)
++
++#define AN8855_RG_CLK_CPU_ICG                 0x10005034
++#define AN8855_MCU_ENABLE                     BIT(3)
++
++#define AN8855_RG_TIMER_CTL                   0x1000a100
++#define AN8855_WDOG_ENABLE                    BIT(25)
++
++#define AN8855_CKGCR                          0x10213e1c
++
++#define AN8855_SCU_BASE                       0x10000000
++#define AN8855_RG_RGMII_TXCK_C                        (AN8855_SCU_BASE + 0x1d0)
++#define AN8855_RG_GPIO_LED_MODE                       (AN8855_SCU_BASE + 0x0054)
++#define AN8855_RG_GPIO_LED_SEL(i)             (AN8855_SCU_BASE + (0x0058 + ((i) * 4)))
++#define AN8855_RG_INTB_MODE                   (AN8855_SCU_BASE + 0x0080)
++#define AN8855_RG_GDMP_RAM                    (AN8855_SCU_BASE + 0x10000)
++#define AN8855_RG_GPIO_L_INV                  (AN8855_SCU_BASE + 0x0010)
++#define AN8855_RG_GPIO_CTRL                   (AN8855_SCU_BASE + 0xa300)
++#define AN8855_RG_GPIO_DATA                   (AN8855_SCU_BASE + 0xa304)
++#define AN8855_RG_GPIO_OE                     (AN8855_SCU_BASE + 0xa314)
++
++#define AN8855_HSGMII_AN_CSR_BASE             0x10220000
++#define AN8855_SGMII_REG_AN0                  (AN8855_HSGMII_AN_CSR_BASE + 0x000)
++#define AN8855_SGMII_REG_AN_13                        (AN8855_HSGMII_AN_CSR_BASE + 0x034)
++#define AN8855_SGMII_REG_AN_FORCE_CL37                (AN8855_HSGMII_AN_CSR_BASE + 0x060)
++
++#define AN8855_HSGMII_CSR_PCS_BASE            0x10220000
++#define AN8855_RG_HSGMII_PCS_CTROL_1          (AN8855_HSGMII_CSR_PCS_BASE + 0xa00)
++#define AN8855_RG_AN_SGMII_MODE_FORCE         (AN8855_HSGMII_CSR_PCS_BASE + 0xa24)
++
++#define AN8855_MULTI_SGMII_CSR_BASE           0x10224000
++#define AN8855_SGMII_STS_CTRL_0               (AN8855_MULTI_SGMII_CSR_BASE + 0x018)
++#define AN8855_MSG_RX_CTRL_0                  (AN8855_MULTI_SGMII_CSR_BASE + 0x100)
++#define AN8855_MSG_RX_LIK_STS_0               (AN8855_MULTI_SGMII_CSR_BASE + 0x514)
++#define AN8855_MSG_RX_LIK_STS_2               (AN8855_MULTI_SGMII_CSR_BASE + 0x51c)
++#define AN8855_PHY_RX_FORCE_CTRL_0            (AN8855_MULTI_SGMII_CSR_BASE + 0x520)
++
++#define AN8855_XFI_CSR_PCS_BASE               0x10225000
++#define AN8855_RG_USXGMII_AN_CONTROL_0                (AN8855_XFI_CSR_PCS_BASE + 0xbf8)
++
++#define AN8855_MULTI_PHY_RA_CSR_BASE          0x10226000
++#define AN8855_RG_RATE_ADAPT_CTRL_0           (AN8855_MULTI_PHY_RA_CSR_BASE + 0x000)
++#define AN8855_RATE_ADP_P0_CTRL_0             (AN8855_MULTI_PHY_RA_CSR_BASE + 0x100)
++#define AN8855_MII_RA_AN_ENABLE               (AN8855_MULTI_PHY_RA_CSR_BASE + 0x300)
++
++#define AN8855_QP_DIG_CSR_BASE                        0x1022a000
++#define AN8855_QP_CK_RST_CTRL_4               (AN8855_QP_DIG_CSR_BASE + 0x310)
++#define AN8855_QP_DIG_MODE_CTRL_0             (AN8855_QP_DIG_CSR_BASE + 0x324)
++#define AN8855_QP_DIG_MODE_CTRL_1             (AN8855_QP_DIG_CSR_BASE + 0x330)
++
++#define AN8855_QP_PMA_TOP_BASE                        0x1022e000
++#define AN8855_PON_RXFEDIG_CTRL_0             (AN8855_QP_PMA_TOP_BASE + 0x100)
++#define AN8855_PON_RXFEDIG_CTRL_9             (AN8855_QP_PMA_TOP_BASE + 0x124)
++
++#define AN8855_SS_LCPLL_PWCTL_SETTING_2       (AN8855_QP_PMA_TOP_BASE + 0x208)
++#define AN8855_SS_LCPLL_TDC_FLT_2             (AN8855_QP_PMA_TOP_BASE + 0x230)
++#define AN8855_SS_LCPLL_TDC_FLT_5             (AN8855_QP_PMA_TOP_BASE + 0x23c)
++#define AN8855_SS_LCPLL_TDC_PCW_1             (AN8855_QP_PMA_TOP_BASE + 0x248)
++#define AN8855_INTF_CTRL_8                    (AN8855_QP_PMA_TOP_BASE + 0x320)
++#define AN8855_INTF_CTRL_9                    (AN8855_QP_PMA_TOP_BASE + 0x324)
++#define AN8855_PLL_CTRL_0                     (AN8855_QP_PMA_TOP_BASE + 0x400)
++#define AN8855_PLL_CTRL_2                     (AN8855_QP_PMA_TOP_BASE + 0x408)
++#define AN8855_PLL_CTRL_3                     (AN8855_QP_PMA_TOP_BASE + 0x40c)
++#define AN8855_PLL_CTRL_4                     (AN8855_QP_PMA_TOP_BASE + 0x410)
++#define AN8855_PLL_CK_CTRL_0                  (AN8855_QP_PMA_TOP_BASE + 0x414)
++#define AN8855_RX_DLY_0                       (AN8855_QP_PMA_TOP_BASE + 0x614)
++#define AN8855_RX_CTRL_2                      (AN8855_QP_PMA_TOP_BASE + 0x630)
++#define AN8855_RX_CTRL_5                      (AN8855_QP_PMA_TOP_BASE + 0x63c)
++#define AN8855_RX_CTRL_6                      (AN8855_QP_PMA_TOP_BASE + 0x640)
++#define AN8855_RX_CTRL_7                      (AN8855_QP_PMA_TOP_BASE + 0x644)
++#define AN8855_RX_CTRL_8                      (AN8855_QP_PMA_TOP_BASE + 0x648)
++#define AN8855_RX_CTRL_26                     (AN8855_QP_PMA_TOP_BASE + 0x690)
++#define AN8855_RX_CTRL_42                     (AN8855_QP_PMA_TOP_BASE + 0x6d0)
++
++#define AN8855_QP_ANA_CSR_BASE                        0x1022f000
++#define AN8855_RG_QP_RX_DAC_EN                        (AN8855_QP_ANA_CSR_BASE + 0x00)
++#define AN8855_RG_QP_RXAFE_RESERVE            (AN8855_QP_ANA_CSR_BASE + 0x04)
++#define AN8855_RG_QP_CDR_LPF_MJV_LIM          (AN8855_QP_ANA_CSR_BASE + 0x0c)
++#define AN8855_RG_QP_CDR_LPF_SETVALUE         (AN8855_QP_ANA_CSR_BASE + 0x14)
++#define AN8855_RG_QP_CDR_PR_CKREF_DIV1                (AN8855_QP_ANA_CSR_BASE + 0x18)
++#define AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE    (AN8855_QP_ANA_CSR_BASE + 0x1c)
++#define AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF (AN8855_QP_ANA_CSR_BASE + 0x20)
++#define AN8855_RG_QP_TX_MODE_16B_EN           (AN8855_QP_ANA_CSR_BASE + 0x28)
++#define AN8855_RG_QP_PLL_IPLL_DIG_PWR_SEL     (AN8855_QP_ANA_CSR_BASE + 0x3c)
++#define AN8855_RG_QP_PLL_SDM_ORD              (AN8855_QP_ANA_CSR_BASE + 0x40)
++
++#define AN8855_ETHER_SYS_BASE                 0x1028c800
++#define RG_GPHY_AFE_PWD                               (AN8855_ETHER_SYS_BASE + 0x40)
++
++#define AN8855_PKG_SEL                                0x10000094
++#define PAG_SEL_AN8855H                               0x2
++
++/* PHY LED Register bitmap of define */
++#define PHY_LED_CTRL_SELECT                   0x3e8
++#define PHY_SINGLE_LED_ON_CTRL(i)             (0x3e0 + ((i) * 2))
++#define PHY_SINGLE_LED_BLK_CTRL(i)            (0x3e1 + ((i) * 2))
++#define PHY_SINGLE_LED_ON_DUR(i)              (0x3e9 + ((i) * 2))
++#define PHY_SINGLE_LED_BLK_DUR(i)             (0x3ea + ((i) * 2))
++
++#define PHY_PMA_CTRL                          (0x340)
++
++#define PHY_DEV1F                             0x1f
++
++#define PHY_LED_ON_CTRL(i)                    (0x24 + ((i) * 2))
++#define LED_ON_EN                             (1 << 15)
++#define LED_ON_POL                            (1 << 14)
++#define LED_ON_EVT_MASK                               (0x7f)
++
++/* LED ON Event */
++#define LED_ON_EVT_FORCE                      (1 << 6)
++#define LED_ON_EVT_LINK_HD                    (1 << 5)
++#define LED_ON_EVT_LINK_FD                    (1 << 4)
++#define LED_ON_EVT_LINK_DOWN                  (1 << 3)
++#define LED_ON_EVT_LINK_10M                   (1 << 2)
++#define LED_ON_EVT_LINK_100M                  (1 << 1)
++#define LED_ON_EVT_LINK_1000M                 (1 << 0)
++
++#define PHY_LED_BLK_CTRL(i)                   (0x25 + ((i) * 2))
++#define LED_BLK_EVT_MASK                      (0x3ff)
++/* LED Blinking Event */
++#define LED_BLK_EVT_FORCE                     (1 << 9)
++#define LED_BLK_EVT_10M_RX_ACT                        (1 << 5)
++#define LED_BLK_EVT_10M_TX_ACT                        (1 << 4)
++#define LED_BLK_EVT_100M_RX_ACT                       (1 << 3)
++#define LED_BLK_EVT_100M_TX_ACT                       (1 << 2)
++#define LED_BLK_EVT_1000M_RX_ACT              (1 << 1)
++#define LED_BLK_EVT_1000M_TX_ACT              (1 << 0)
++
++#define PHY_LED_BCR                           (0x21)
++#define LED_BCR_EXT_CTRL                      (1 << 15)
++#define LED_BCR_CLK_EN                                (1 << 3)
++#define LED_BCR_TIME_TEST                     (1 << 2)
++#define LED_BCR_MODE_MASK                     (3)
++#define LED_BCR_MODE_DISABLE                  (0)
++
++#define PHY_LED_ON_DUR                                (0x22)
++#define LED_ON_DUR_MASK                               (0xffff)
++
++#define PHY_LED_BLK_DUR                               (0x23)
++#define LED_BLK_DUR_MASK                      (0xffff)
++
++#define PHY_LED_BLINK_DUR_CTRL                        (0x720)
++
++/* Definition of LED */
++#define LED_ON_EVENT  (LED_ON_EVT_LINK_1000M | \
++                      LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M |\
++                      LED_ON_EVT_LINK_HD | LED_ON_EVT_LINK_FD)
++
++#define LED_BLK_EVENT (LED_BLK_EVT_1000M_TX_ACT | \
++                      LED_BLK_EVT_1000M_RX_ACT | \
++                      LED_BLK_EVT_100M_TX_ACT | \
++                      LED_BLK_EVT_100M_RX_ACT | \
++                      LED_BLK_EVT_10M_TX_ACT | \
++                      LED_BLK_EVT_10M_RX_ACT)
++
++#define LED_FREQ                              AIR_LED_BLK_DUR_64M
++
++#define AN8855_NUM_PHYS                               5
++#define AN8855_NUM_PORTS                      6
++#define AN8855_PHY_ADDR(base, addr)           (((base) + (addr)) & 0x1f)
++
++/* PHY LED Register bitmap of define */
++#define PHY_LED_CTRL_SELECT                   0x3e8
++#define PHY_SINGLE_LED_ON_CTRL(i)             (0x3e0 + ((i) * 2))
++#define PHY_SINGLE_LED_BLK_CTRL(i)            (0x3e1 + ((i) * 2))
++#define PHY_SINGLE_LED_ON_DUR(i)              (0x3e9 + ((i) * 2))
++#define PHY_SINGLE_LED_BLK_DUR(i)             (0x3ea + ((i) * 2))
++
++/* AN8855 LED */
++enum an8855_led_blk_dur {
++      AIR_LED_BLK_DUR_32M,
++      AIR_LED_BLK_DUR_64M,
++      AIR_LED_BLK_DUR_128M,
++      AIR_LED_BLK_DUR_256M,
++      AIR_LED_BLK_DUR_512M,
++      AIR_LED_BLK_DUR_1024M,
++      AIR_LED_BLK_DUR_LAST
++};
++
++enum an8855_led_polarity {
++      LED_LOW,
++      LED_HIGH,
++};
++
++enum an8855_led_mode {
++      AN8855_LED_MODE_DISABLE,
++      AN8855_LED_MODE_USER_DEFINE,
++      AN8855_LED_MODE_LAST
++};
++
++enum phy_led_idx {
++      P0_LED0,
++      P0_LED1,
++      P0_LED2,
++      P0_LED3,
++      P1_LED0,
++      P1_LED1,
++      P1_LED2,
++      P1_LED3,
++      P2_LED0,
++      P2_LED1,
++      P2_LED2,
++      P2_LED3,
++      P3_LED0,
++      P3_LED1,
++      P3_LED2,
++      P3_LED3,
++      P4_LED0,
++      P4_LED1,
++      P4_LED2,
++      P4_LED3,
++      PHY_LED_MAX
++};
++
++struct an8855_led_cfg {
++      u16 en;
++      u8  phy_led_idx;
++      u16 pol;
++      u16 on_cfg;
++      u16 blk_cfg;
++      u8 led_freq;
++};
++
++struct an8855_switch_priv {
++      struct mtk_eth_switch_priv epriv;
++      struct mii_dev *mdio_bus;
++      u32 phy_base;
++};
++
++/* AN8855 Reference Board */
++static const struct an8855_led_cfg led_cfg[] = {
++/*************************************************************************
++ * Enable, LED idx, LED Polarity, LED ON event,  LED Blink event  LED Freq
++ *************************************************************************
++ */
++      /* GPIO0 */
++      {1, P4_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO1 */
++      {1, P4_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO2 */
++      {1, P0_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO3 */
++      {1, P0_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO4 */
++      {1, P1_LED0, LED_LOW,  LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO5 */
++      {1, P1_LED1, LED_LOW,  LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO6 */
++      {0, PHY_LED_MAX, LED_LOW,  LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO7 */
++      {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO8 */
++      {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO9 */
++      {1, P2_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO10 */
++      {1, P2_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO11 */
++      {1, P3_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO12 */
++      {1, P3_LED1, LED_HIGH,  LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO13 */
++      {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO14 */
++      {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO15 */
++      {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO16 */
++      {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO17 */
++      {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO18 */
++      {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO19 */
++      {0, PHY_LED_MAX, LED_LOW,  LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++      /* GPIO20 */
++      {0, PHY_LED_MAX, LED_LOW,  LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
++};
++
++static int __an8855_reg_read(struct mtk_eth_priv *priv, u8 phy_base, u32 reg, u32 *data)
++{
++      int ret, low_word, high_word;
++
++      ret = mtk_mii_write(priv, phy_base, 0x1f, 0x4);
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv, phy_base, 0x10, 0);
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv, phy_base, 0x15, ((reg >> 16) & 0xFFFF));
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv, phy_base, 0x16, (reg & 0xFFFF));
++      if (ret)
++              return ret;
++
++      low_word = mtk_mii_read(priv, phy_base, 0x18);
++      if (low_word < 0)
++              return low_word;
++
++      high_word = mtk_mii_read(priv, phy_base, 0x17);
++      if (high_word < 0)
++              return high_word;
++
++      ret = mtk_mii_write(priv, phy_base, 0x1f, 0);
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv, phy_base, 0x10, 0);
++      if (ret)
++              return ret;
++
++      if (data)
++              *data = ((u32)high_word << 16) | (low_word & 0xffff);
++
++      return 0;
++}
++
++static int an8855_reg_read(struct an8855_switch_priv *priv, u32 reg, u32 *data)
++{
++      return __an8855_reg_read(priv->epriv.eth, priv->phy_base, reg, data);
++}
++
++static int an8855_reg_write(struct an8855_switch_priv *priv, u32 reg, u32 data)
++{
++      int ret;
++
++      ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x1f, 0x4);
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x10, 0);
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x11,
++                          ((reg >> 16) & 0xFFFF));
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x12,
++                          (reg & 0xFFFF));
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x13,
++                          ((data >> 16) & 0xFFFF));
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x14,
++                          (data & 0xFFFF));
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x1f, 0);
++      if (ret)
++              return ret;
++
++      ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x10, 0);
++      if (ret)
++              return ret;
++
++      return 0;
++}
++
++static int an8855_phy_cl45_read(struct an8855_switch_priv *priv, int port,
++                              int devad, int regnum, u16 *data)
++{
++      u16 phy_addr = AN8855_PHY_ADDR(priv->phy_base, port);
++
++      *data = mtk_mmd_ind_read(priv->epriv.eth, phy_addr, devad, regnum);
++
++      return 0;
++}
++
++static int an8855_phy_cl45_write(struct an8855_switch_priv *priv, int port,
++                               int devad, int regnum, u16 data)
++{
++      u16 phy_addr = AN8855_PHY_ADDR(priv->phy_base, port);
++
++      mtk_mmd_ind_write(priv->epriv.eth, phy_addr, devad, regnum, data);
++
++      return 0;
++}
++
++static int an8855_port_sgmii_init(struct an8855_switch_priv *priv, u32 port)
++{
++      u32 val = 0;
++
++      if (port != 5) {
++              printf("an8855: port %d is not a SGMII port\n", port);
++              return -EINVAL;
++      }
++
++      /* PLL */
++      an8855_reg_read(priv, AN8855_QP_DIG_MODE_CTRL_1, &val);
++      val &= ~(0x3 << 2);
++      val |= (0x1 << 2);
++      an8855_reg_write(priv, AN8855_QP_DIG_MODE_CTRL_1, val);
++
++      /* PLL - LPF */
++      an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
++      val &= ~(0x3 << 0);
++      val |= (0x1 << 0);
++      val &= ~(0x7 << 2);
++      val |= (0x5 << 2);
++      val &= ~GENMASK(7, 6);
++      val &= ~(0x7 << 8);
++      val |= (0x3 << 8);
++      val |= BIT(29);
++      val &= ~GENMASK(13, 12);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
++
++      /* PLL - ICO */
++      an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val);
++      val |= BIT(2);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_4, val);
++
++      an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
++      val &= ~BIT(14);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
++
++      /* PLL - CHP */
++      an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
++      val &= ~(0xf << 16);
++      val |= (0x6 << 16);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
++
++      /* PLL - PFD */
++      an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
++      val &= ~(0x3 << 20);
++      val |= (0x1 << 20);
++      val &= ~(0x3 << 24);
++      val |= (0x1 << 24);
++      val &= ~BIT(26);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
++
++      /* PLL - POSTDIV */
++      an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
++      val |= BIT(22);
++      val &= ~BIT(27);
++      val &= ~BIT(28);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
++
++      /* PLL - SDM */
++      an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val);
++      val &= ~GENMASK(4, 3);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_4, val);
++
++      an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
++      val &= ~BIT(30);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
++
++      an8855_reg_read(priv, AN8855_SS_LCPLL_PWCTL_SETTING_2, &val);
++      val &= ~(0x3 << 16);
++      val |= (0x1 << 16);
++      an8855_reg_write(priv, AN8855_SS_LCPLL_PWCTL_SETTING_2, val);
++
++      an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_FLT_2, 0x7a000000);
++      an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_PCW_1, 0x7a000000);
++
++      an8855_reg_read(priv, AN8855_SS_LCPLL_TDC_FLT_5, &val);
++      val &= ~BIT(24);
++      an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_FLT_5, val);
++
++      an8855_reg_read(priv, AN8855_PLL_CK_CTRL_0, &val);
++      val &= ~BIT(8);
++      an8855_reg_write(priv, AN8855_PLL_CK_CTRL_0, val);
++
++      /* PLL - SS */
++      an8855_reg_read(priv, AN8855_PLL_CTRL_3, &val);
++      val &= ~GENMASK(15, 0);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_3, val);
++
++      an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val);
++      val &= ~GENMASK(1, 0);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_4, val);
++
++      an8855_reg_read(priv, AN8855_PLL_CTRL_3, &val);
++      val &= ~GENMASK(31, 16);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_3, val);
++
++      /* PLL - TDC */
++      an8855_reg_read(priv, AN8855_PLL_CK_CTRL_0, &val);
++      val &= ~BIT(9);
++      an8855_reg_write(priv, AN8855_PLL_CK_CTRL_0, val);
++
++      an8855_reg_read(priv, AN8855_RG_QP_PLL_SDM_ORD, &val);
++      val |= BIT(3);
++      val |= BIT(4);
++      an8855_reg_write(priv, AN8855_RG_QP_PLL_SDM_ORD, val);
++
++      an8855_reg_read(priv, AN8855_RG_QP_RX_DAC_EN, &val);
++      val &= ~(0x3 << 16);
++      val |= (0x2 << 16);
++      an8855_reg_write(priv, AN8855_RG_QP_RX_DAC_EN, val);
++
++      /* TCL Disable (only for Co-SIM) */
++      an8855_reg_read(priv, AN8855_PON_RXFEDIG_CTRL_0, &val);
++      val &= ~BIT(12);
++      an8855_reg_write(priv, AN8855_PON_RXFEDIG_CTRL_0, val);
++
++      /* TX Init */
++      an8855_reg_read(priv, AN8855_RG_QP_TX_MODE_16B_EN, &val);
++      val &= ~BIT(0);
++      val &= ~(0xffff << 16);
++      val |= (0x4 << 16);
++      an8855_reg_write(priv, AN8855_RG_QP_TX_MODE_16B_EN, val);
++
++      /* RX Control */
++      an8855_reg_read(priv, AN8855_RG_QP_RXAFE_RESERVE, &val);
++      val |= BIT(11);
++      an8855_reg_write(priv, AN8855_RG_QP_RXAFE_RESERVE, val);
++
++      an8855_reg_read(priv, AN8855_RG_QP_CDR_LPF_MJV_LIM, &val);
++      val &= ~(0x3 << 4);
++      val |= (0x1 << 4);
++      an8855_reg_write(priv, AN8855_RG_QP_CDR_LPF_MJV_LIM, val);
++
++      an8855_reg_read(priv, AN8855_RG_QP_CDR_LPF_SETVALUE, &val);
++      val &= ~(0xf << 25);
++      val |= (0x1 << 25);
++      val &= ~(0x7 << 29);
++      val |= (0x3 << 29);
++      an8855_reg_write(priv, AN8855_RG_QP_CDR_LPF_SETVALUE, val);
++
++      an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, &val);
++      val &= ~(0x1f << 8);
++      val |= (0xf << 8);
++      an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, val);
++
++      an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, &val);
++      val &= ~(0x3f << 0);
++      val |= (0x19 << 0);
++      val &= ~BIT(6);
++      an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
++
++      an8855_reg_read(priv, AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF, &val);
++      val &= ~(0x7f << 6);
++      val |= (0x21 << 6);
++      val &= ~(0x3 << 16);
++      val |= (0x2 << 16);
++      val &= ~BIT(13);
++      an8855_reg_write(priv, AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val);
++
++      an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, &val);
++      val &= ~BIT(30);
++      an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
++
++      an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, &val);
++      val &= ~(0x7 << 24);
++      val |= (0x4 << 24);
++      an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, val);
++
++      an8855_reg_read(priv, AN8855_PLL_CTRL_0, &val);
++      val |= BIT(0);
++      an8855_reg_write(priv, AN8855_PLL_CTRL_0, val);
++
++      an8855_reg_read(priv, AN8855_RX_CTRL_26, &val);
++      val &= ~BIT(23);
++      val |= BIT(26);
++      an8855_reg_write(priv, AN8855_RX_CTRL_26, val);
++
++      an8855_reg_read(priv, AN8855_RX_DLY_0, &val);
++      val &= ~(0xff << 0);
++      val |= (0x6f << 0);
++      val |= GENMASK(13, 8);
++      an8855_reg_write(priv, AN8855_RX_DLY_0, val);
++
++      an8855_reg_read(priv, AN8855_RX_CTRL_42, &val);
++      val &= ~(0x1fff << 0);
++      val |= (0x150 << 0);
++      an8855_reg_write(priv, AN8855_RX_CTRL_42, val);
++
++      an8855_reg_read(priv, AN8855_RX_CTRL_2, &val);
++      val &= ~(0x1fff << 16);
++      val |= (0x150 << 16);
++      an8855_reg_write(priv, AN8855_RX_CTRL_2, val);
++
++      an8855_reg_read(priv, AN8855_PON_RXFEDIG_CTRL_9, &val);
++      val &= ~(0x7 << 0);
++      val |= (0x1 << 0);
++      an8855_reg_write(priv, AN8855_PON_RXFEDIG_CTRL_9, val);
++
++      an8855_reg_read(priv, AN8855_RX_CTRL_8, &val);
++      val &= ~(0xfff << 16);
++      val |= (0x200 << 16);
++      val &= ~(0x7fff << 14);
++      val |= (0xfff << 14);
++      an8855_reg_write(priv, AN8855_RX_CTRL_8, val);
++
++      /* Frequency memter */
++      an8855_reg_read(priv, AN8855_RX_CTRL_5, &val);
++      val &= ~(0xfffff << 10);
++      val |= (0x10 << 10);
++      an8855_reg_write(priv, AN8855_RX_CTRL_5, val);
++
++      an8855_reg_read(priv, AN8855_RX_CTRL_6, &val);
++      val &= ~(0xfffff << 0);
++      val |= (0x64 << 0);
++      an8855_reg_write(priv, AN8855_RX_CTRL_6, val);
++
++      an8855_reg_read(priv, AN8855_RX_CTRL_7, &val);
++      val &= ~(0xfffff << 0);
++      val |= (0x2710 << 0);
++      an8855_reg_write(priv, AN8855_RX_CTRL_7, val);
++
++      /* PCS Init */
++      an8855_reg_read(priv, AN8855_RG_HSGMII_PCS_CTROL_1, &val);
++      val &= ~BIT(30);
++      an8855_reg_write(priv, AN8855_RG_HSGMII_PCS_CTROL_1, val);
++
++      /* Rate Adaption */
++      an8855_reg_read(priv, AN8855_RATE_ADP_P0_CTRL_0, &val);
++      val &= ~BIT(31);
++      an8855_reg_write(priv, AN8855_RATE_ADP_P0_CTRL_0, val);
++
++      an8855_reg_read(priv, AN8855_RG_RATE_ADAPT_CTRL_0, &val);
++      val |= BIT(0);
++      val |= BIT(4);
++      val |= GENMASK(27, 26);
++      an8855_reg_write(priv, AN8855_RG_RATE_ADAPT_CTRL_0, val);
++
++      /* Disable AN */
++      an8855_reg_read(priv, AN8855_SGMII_REG_AN0, &val);
++      val &= ~BIT(12);
++      an8855_reg_write(priv, AN8855_SGMII_REG_AN0, val);
++
++      /* Force Speed */
++      an8855_reg_read(priv, AN8855_SGMII_STS_CTRL_0, &val);
++      val |= BIT(2);
++      val |= GENMASK(5, 4);
++      an8855_reg_write(priv, AN8855_SGMII_STS_CTRL_0, val);
++
++      /* bypass flow control to MAC */
++      an8855_reg_write(priv, AN8855_MSG_RX_LIK_STS_0, 0x01010107);
++      an8855_reg_write(priv, AN8855_MSG_RX_LIK_STS_2, 0x00000EEF);
++
++      return 0;
++}
++
++static void an8855_led_set_usr_def(struct an8855_switch_priv *priv, u8 entity,
++                                 enum an8855_led_polarity pol, u16 on_evt,
++                                 u16 blk_evt, u8 led_freq)
++{
++      u32 cl45_data;
++
++      if (pol == LED_HIGH)
++              on_evt |= LED_ON_POL;
++      else
++              on_evt &= ~LED_ON_POL;
++
++      /* LED on event */
++      an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
++                            PHY_SINGLE_LED_ON_CTRL(entity % 4),
++                            on_evt | LED_ON_EN);
++
++      /* LED blink event */
++      an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
++                            PHY_SINGLE_LED_BLK_CTRL(entity % 4),
++                            blk_evt);
++
++      /* LED freq */
++      switch (led_freq) {
++      case AIR_LED_BLK_DUR_32M:
++              cl45_data = 0x30e;
++              break;
++
++      case AIR_LED_BLK_DUR_64M:
++              cl45_data = 0x61a;
++              break;
++
++      case AIR_LED_BLK_DUR_128M:
++              cl45_data = 0xc35;
++              break;
++
++      case AIR_LED_BLK_DUR_256M:
++              cl45_data = 0x186a;
++              break;
++
++      case AIR_LED_BLK_DUR_512M:
++              cl45_data = 0x30d4;
++              break;
++
++      case AIR_LED_BLK_DUR_1024M:
++              cl45_data = 0x61a8;
++              break;
++
++      default:
++              cl45_data = 0;
++              break;
++      }
++
++      an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
++                            PHY_SINGLE_LED_BLK_DUR(entity % 4),
++                            cl45_data);
++
++      an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
++                            PHY_SINGLE_LED_ON_DUR(entity % 4),
++                            (cl45_data >> 1));
++
++      /* Disable DATA & BAD_SSD for port LED blink behavior */
++      cl45_data = mtk_mmd_ind_read(priv->epriv.eth, (entity / 4), 0x1e, PHY_PMA_CTRL);
++      cl45_data &= ~BIT(0);
++      cl45_data &= ~BIT(15);
++      an8855_phy_cl45_write(priv, (entity / 4), 0x1e, PHY_PMA_CTRL, cl45_data);
++}
++
++static int an8855_led_set_mode(struct an8855_switch_priv *priv, u8 mode)
++{
++      u16 cl45_data;
++
++      an8855_phy_cl45_read(priv, 0, 0x1f, PHY_LED_BCR, &cl45_data);
++
++      switch (mode) {
++      case AN8855_LED_MODE_DISABLE:
++              cl45_data &= ~LED_BCR_EXT_CTRL;
++              cl45_data &= ~LED_BCR_MODE_MASK;
++              cl45_data |= LED_BCR_MODE_DISABLE;
++              break;
++
++      case AN8855_LED_MODE_USER_DEFINE:
++              cl45_data |= LED_BCR_EXT_CTRL;
++              cl45_data |= LED_BCR_CLK_EN;
++              break;
++
++      default:
++              printf("an8855: LED mode%d is not supported!\n", mode);
++              return -EINVAL;
++      }
++
++      an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BCR, cl45_data);
++
++      return 0;
++}
++
++static int an8855_led_set_state(struct an8855_switch_priv *priv, u8 entity,
++                              u8 state)
++{
++      u16 cl45_data = 0;
++
++      /* Change to per port contorl */
++      an8855_phy_cl45_read(priv, (entity / 4), 0x1e, PHY_LED_CTRL_SELECT,
++                           &cl45_data);
++
++      if (state == 1)
++              cl45_data |= (1 << (entity % 4));
++      else
++              cl45_data &= ~(1 << (entity % 4));
++
++      an8855_phy_cl45_write(priv, (entity / 4), 0x1e, PHY_LED_CTRL_SELECT,
++                            cl45_data);
++
++      /* LED enable setting */
++      an8855_phy_cl45_read(priv, (entity / 4), 0x1e,
++                           PHY_SINGLE_LED_ON_CTRL(entity % 4), &cl45_data);
++
++      if (state == 1)
++              cl45_data |= LED_ON_EN;
++      else
++              cl45_data &= ~LED_ON_EN;
++
++      an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
++                            PHY_SINGLE_LED_ON_CTRL(entity % 4), cl45_data);
++
++      return 0;
++}
++
++static int an8855_led_init(struct an8855_switch_priv *priv)
++{
++      u32 val, id, tmp_id = 0;
++      int ret;
++
++      ret = an8855_led_set_mode(priv, AN8855_LED_MODE_USER_DEFINE);
++      if (ret) {
++              printf("an8855: led_set_mode failed with %d!\n", ret);
++              return ret;
++      }
++
++      for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
++              ret = an8855_led_set_state(priv, led_cfg[id].phy_led_idx,
++                                         led_cfg[id].en);
++              if (ret != 0) {
++                      printf("an8855: led_set_state failed with %d!\n", ret);
++                      return ret;
++              }
++
++              if (led_cfg[id].en == 1) {
++                      an8855_led_set_usr_def(priv,
++                                             led_cfg[id].phy_led_idx,
++                                             led_cfg[id].pol,
++                                             led_cfg[id].on_cfg,
++                                             led_cfg[id].blk_cfg,
++                                             led_cfg[id].led_freq);
++              }
++      }
++
++      /* Setting for System LED & Loop LED */
++      an8855_reg_write(priv, AN8855_RG_GPIO_OE, 0x0);
++      an8855_reg_write(priv, AN8855_RG_GPIO_CTRL, 0x0);
++      an8855_reg_write(priv, AN8855_RG_GPIO_L_INV, 0);
++
++      an8855_reg_write(priv, AN8855_RG_GPIO_CTRL, 0x1001);
++      an8855_reg_read(priv, AN8855_RG_GPIO_DATA, &val);
++      val |= GENMASK(3, 1);
++      val &= ~(BIT(0));
++      val &= ~(BIT(6));
++      an8855_reg_write(priv, AN8855_RG_GPIO_DATA, val);
++
++      an8855_reg_read(priv, AN8855_RG_GPIO_OE, &val);
++      val |= 0x41;
++      an8855_reg_write(priv, AN8855_RG_GPIO_OE, val);
++
++      /* Mapping between GPIO & LED */
++      val = 0;
++      for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
++              /* Skip GPIO6, due to GPIO6 does not support PORT LED */
++              if (id == 6)
++                      continue;
++
++              if (led_cfg[id].en == 1) {
++                      if (id < 7)
++                              val |= led_cfg[id].phy_led_idx << ((id % 4) * 8);
++                      else
++                              val |= led_cfg[id].phy_led_idx << (((id - 1) % 4) * 8);
++              }
++
++              if (id < 7)
++                      tmp_id = id;
++              else
++                      tmp_id = id - 1;
++
++              if ((tmp_id % 4) == 0x3) {
++                      an8855_reg_write(priv,
++                                       AN8855_RG_GPIO_LED_SEL(tmp_id / 4),
++                                       val);
++                      val = 0;
++              }
++      }
++
++      /* Turn on LAN LED mode */
++      val = 0;
++      for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
++              if (led_cfg[id].en == 1)
++                      val |= 0x1 << id;
++      }
++      an8855_reg_write(priv, AN8855_RG_GPIO_LED_MODE, val);
++
++      /* Force clear blink pulse for per port LED */
++      an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BLINK_DUR_CTRL, 0x1f);
++      udelay(1000);
++      an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BLINK_DUR_CTRL, 0);
++
++      return 0;
++}
++
++static void an8855_port_isolation(struct an8855_switch_priv *priv)
++{
++      u32 i;
++
++      for (i = 0; i < AN8855_NUM_PORTS; i++) {
++              /* Set port matrix mode */
++              if (i != 5)
++                      an8855_reg_write(priv, AN8855_PORTMATRIX_REG(i), 0x20);
++              else
++                      an8855_reg_write(priv, AN8855_PORTMATRIX_REG(i), 0x1f);
++
++              /* Set port mode to user port */
++              an8855_reg_write(priv, AN8855_PVC(i),
++                               (0x8100 << AN8855_STAG_VPID_S) |
++                               (VLAN_ATTR_USER << AN8855_VLAN_ATTR_S));
++      }
++}
++
++static void an8855_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
++{
++      struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv;
++      u32 pmcr = AN8855_FORCE_MODE_LNK;
++
++      if (enable)
++              pmcr = AN8855_FORCE_MODE;
++
++      an8855_reg_write(priv, AN8855_PMCR_REG(5), pmcr);
++}
++
++static int an8855_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
++{
++      struct an8855_switch_priv *priv = bus->priv;
++
++      if (devad < 0)
++              return mtk_mii_read(priv->epriv.eth, addr, reg);
++
++      return mtk_mmd_ind_read(priv->epriv.eth, addr, devad, reg);
++}
++
++static int an8855_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
++                           u16 val)
++{
++      struct an8855_switch_priv *priv = bus->priv;
++
++      if (devad < 0)
++              return mtk_mii_write(priv->epriv.eth, addr, reg, val);
++
++      return mtk_mmd_ind_write(priv->epriv.eth, addr, devad, reg, val);
++}
++
++static int an8855_mdio_register(struct an8855_switch_priv *priv)
++{
++      struct mii_dev *mdio_bus = mdio_alloc();
++      int ret;
++
++      if (!mdio_bus)
++              return -ENOMEM;
++
++      mdio_bus->read = an8855_mdio_read;
++      mdio_bus->write = an8855_mdio_write;
++      snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
++
++      mdio_bus->priv = priv;
++
++      ret = mdio_register(mdio_bus);
++      if (ret) {
++              mdio_free(mdio_bus);
++              return ret;
++      }
++
++      priv->mdio_bus = mdio_bus;
++
++      return 0;
++}
++
++static int an8855_setup(struct mtk_eth_switch_priv *swpriv)
++{
++      struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv;
++      u16 phy_addr, phy_val;
++      u32 i, id, val = 0;
++      int ret;
++
++      priv->phy_base = 1;
++
++      /* Turn off PHYs */
++      for (i = 0; i < AN8855_NUM_PHYS; i++) {
++              phy_addr = AN8855_PHY_ADDR(priv->phy_base, i);
++              phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
++              phy_val |= BMCR_PDOWN;
++              mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
++      }
++
++      /* Force MAC link down before reset */
++      an8855_reg_write(priv, AN8855_PMCR_REG(5), AN8855_FORCE_MODE_LNK);
++
++      /* Switch soft reset */
++      an8855_reg_write(priv, AN8855_SYS_CTRL_REG, AN8855_SW_SYS_RST);
++      udelay(100000);
++
++      an8855_reg_read(priv, AN8855_PKG_SEL, &val);
++      if ((val & 0x7) == PAG_SEL_AN8855H) {
++              /* Release power down */
++              an8855_reg_write(priv, RG_GPHY_AFE_PWD, 0x0);
++
++              /* Invert for LED activity change */
++              an8855_reg_read(priv, AN8855_RG_GPIO_L_INV, &val);
++              for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
++                      if ((led_cfg[id].pol == LED_HIGH) &&
++                          (led_cfg[id].en == 1))
++                              val |= 0x1 << id;
++              }
++              an8855_reg_write(priv, AN8855_RG_GPIO_L_INV, (val | 0x1));
++
++              /* MCU NOP CMD */
++              an8855_reg_write(priv, AN8855_RG_GDMP_RAM, 0x846);
++              an8855_reg_write(priv, AN8855_RG_GDMP_RAM + 4, 0x4a);
++
++              /* Enable MCU */
++              an8855_reg_read(priv, AN8855_RG_CLK_CPU_ICG, &val);
++              an8855_reg_write(priv, AN8855_RG_CLK_CPU_ICG,
++                               val | AN8855_MCU_ENABLE);
++              udelay(1000);
++
++              /* Disable MCU watchdog */
++              an8855_reg_read(priv, AN8855_RG_TIMER_CTL, &val);
++              an8855_reg_write(priv, AN8855_RG_TIMER_CTL,
++                               (val & (~AN8855_WDOG_ENABLE)));
++
++              /* LED settings for T830 reference board */
++              ret = an8855_led_init(priv);
++              if (ret < 0) {
++                      printf("an8855: an8855_led_init failed with %d\n", ret);
++                      return ret;
++              }
++      }
++
++      switch (priv->epriv.phy_interface) {
++      case PHY_INTERFACE_MODE_2500BASEX:
++              an8855_port_sgmii_init(priv, 5);
++              break;
++
++      default:
++              break;
++      }
++
++      an8855_reg_read(priv, AN8855_CKGCR, &val);
++      val &= ~(0x3);
++      an8855_reg_write(priv, AN8855_CKGCR, val);
++
++      /* Enable port isolation to block inter-port communication */
++      an8855_port_isolation(priv);
++
++      /* Turn on PHYs */
++      for (i = 0; i < AN8855_NUM_PHYS; i++) {
++              phy_addr = AN8855_PHY_ADDR(priv->phy_base, i);
++              phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
++              phy_val &= ~BMCR_PDOWN;
++              mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
++      }
++
++      return an8855_mdio_register(priv);
++}
++
++static int an8855_cleanup(struct mtk_eth_switch_priv *swpriv)
++{
++      struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv;
++
++      mdio_unregister(priv->mdio_bus);
++
++      return 0;
++}
++
++static int an8855_detect(struct mtk_eth_priv *priv)
++{
++      int ret;
++      u32 val;
++
++      ret = __an8855_reg_read(priv, 1, 0x10005000, &val);
++      if (ret)
++              return ret;
++
++      if (val == 0x8855)
++              return 0;
++
++      return -ENODEV;
++}
++
++MTK_ETH_SWITCH(an8855) = {
++      .name = "an8855",
++      .desc = "Airoha AN8855",
++      .priv_size = sizeof(struct an8855_switch_priv),
++      .reset_wait_time = 100,
++
++      .detect = an8855_detect,
++      .setup = an8855_setup,
++      .cleanup = an8855_cleanup,
++      .mac_control = an8855_mac_control,
++};