[openwrt/openwrt] uboot-mediatek: backport mtk_eth fixes from u-boot next

LEDE Commits lede-commits at lists.infradead.org
Sun Feb 9 14:02:47 PST 2025


dangole pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/24ade65ab545c169992c3c95f8cd3ca73a072c8f

commit 24ade65ab545c169992c3c95f8cd3ca73a072c8f
Author: Shiji Yang <yangshiji66 at qq.com>
AuthorDate: Thu Jan 9 18:10:28 2025 +0800

    uboot-mediatek: backport mtk_eth fixes from u-boot next
    
    This patch series will provide better support for Mediatek
    ethernet and add support for Airoha AN8855.
    
    Signed-off-by: Shiji Yang <yangshiji66 at qq.com>
---
 ...k-mt7629-fix-parent-clock-of-some-top-clo.patch |   45 +
 ...629-fix-sgmii-clock-selection-for-etherne.patch |   28 +
 ...k-use-correct-register-field-for-SGMII-sp.patch |   64 +
 ...k-correct-register-name-of-ethsys-syscfg1.patch |   78 +
 ...t-mediatek-fix-sgmii-selection-for-mt7622.patch |   90 +
 ...t-mediatek-fix-gmac2-usability-for-mt7629.patch |   73 +
 ...07-net-mediatek-add-support-for-10GBASE-R.patch |  147 +
 ...-net-mediatek-make-sgmii-usxgmii-optional.patch |  144 +
 ...k-don-t-enable-GDMA-cpu-bridge-unconditio.patch |   36 +
 ...-mediatek-fix-usability-with-wget-command.patch |   37 +
 ...k-split-ethernet-switch-code-from-mtk_eth.patch | 6311 ++++++++++++++++++++
 ...iatek-add-support-for-MediaTek-MT7987-SoC.patch |   63 +
 ...k-add-support-for-Airoha-AN8855-ethernet-.patch | 1133 ++++
 13 files changed, 8249 insertions(+)

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
index 0000000000..387cf90477
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-01-clk-mediatek-mt7629-fix-parent-clock-of-some-top-clo.patch
@@ -0,0 +1,45 @@
+From 6e45549f4dac42748d66462e04f940ef6737289d Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..c96490e408
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-02-arm-dts-mt7629-fix-sgmii-clock-selection-for-etherne.patch
@@ -0,0 +1,28 @@
+From ba365c3d23411620d86b5baf621c8f5a4000ab33 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..ba3fbf6d7f
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-03-net-mediatek-use-correct-register-field-for-SGMII-sp.patch
@@ -0,0 +1,64 @@
+From 0d4d8e6f47ef22ea6b3041b4c0cb27b4ed4bf188 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..8c549e76b1
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-04-net-mediatek-correct-register-name-of-ethsys-syscfg1.patch
@@ -0,0 +1,78 @@
+From 7562da9454c1a6eff3db3b41c183e03039e855e6 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..a45e8789d2
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-05-net-mediatek-fix-sgmii-selection-for-mt7622.patch
@@ -0,0 +1,90 @@
+From 82f05bc48821f3709f22f3d1f6e45290547f74be Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..5bc6e705d0
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-06-net-mediatek-fix-gmac2-usability-for-mt7629.patch
@@ -0,0 +1,73 @@
+From d8d7e566545f836dd49611cafbf44eef56434e08 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..f7a63a5b8a
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-07-net-mediatek-add-support-for-10GBASE-R.patch
@@ -0,0 +1,147 @@
+From ad0c47109e4c9f6297aa247d8bbf7131438bc435 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at mediatek.com>
+Signed-off-by: Weijie Gao <weijie.gao at 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
index 0000000000..d6a885f889
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-08-net-mediatek-make-sgmii-usxgmii-optional.patch
@@ -0,0 +1,144 @@
+From 5ac929fd1ab1d0dc77b9167952aea7cafdb8619f Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..c9ea8f4401
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-09-net-mediatek-don-t-enable-GDMA-cpu-bridge-unconditio.patch
@@ -0,0 +1,36 @@
+From b9dfb5636bc5eb9b783b88b8388dc7d1f41d6498 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..a20d79030f
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/060-10-net-mediatek-fix-usability-with-wget-command.patch
@@ -0,0 +1,37 @@
+From c949686e558e00cbb8c38f7c060701006d70cea8 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..b212c6c219
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/061-01-net-mediatek-split-ethernet-switch-code-from-mtk_eth.patch
@@ -0,0 +1,6311 @@
+From 626cdca5b68acdc72d2533e2ed2306c06f296725 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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 at 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 at mediatek.com>
++ * Author: Mark Lee <mark-mc.lee at 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 at mediatek.com>
++ * Author: Mark Lee <mark-mc.lee at 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 at mediatek.com>
++ * Author: Mark Lee <mark-mc.lee at 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 at mediatek.com>
++ * Author: Mark Lee <mark-mc.lee at 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 at mediatek.com>
++ * Author: Mark Lee <mark-mc.lee at 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 at mediatek.com>
+- * Author: Mark Lee <mark-mc.lee at 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 at mediatek.com>
++ * Author: Mark Lee <mark-mc.lee at 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 at mediatek.com>
+- * Author: Mark Lee <mark-mc.lee at 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 at mediatek.com>
++ * Author: Mark Lee <mark-mc.lee at 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
index 0000000000..183c7129ab
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/061-02-net-mediatek-add-support-for-MediaTek-MT7987-SoC.patch
@@ -0,0 +1,63 @@
+From fe106f2093733b8bd61946372945dfea552b4755 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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
index 0000000000..8e4f4391b1
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/061-03-net-mediatek-add-support-for-Airoha-AN8855-ethernet-.patch
@@ -0,0 +1,1133 @@
+From cedafee9ff39d13aaf8b80361b673445a85f117e Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at 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 at 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 at mediatek.com>
++ * Author: Weijie Gao <weijie.gao at 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,
++};




More information about the lede-commits mailing list