From 626cdca5b68acdc72d2533e2ed2306c06f296725 Mon Sep 17 00:00:00 2001
From: Weijie Gao <weijie.gao@mediatek.com>
Date: Fri, 10 Jan 2025 16:41:13 +0800
Subject: [PATCH 1/3] net: mediatek: split ethernet switch code from mtk_eth.c

mtk_eth.c contains not only the ethernet GMAC/DMA driver, but also
some ethernet switch initialization code. As we may add more switch
support in the future, it's better to move them out of mtk_eth.c to
avoid increasing the code complexity.

Since not all switches are supported for a particular board, Kconfig
options are added to allow user to select which switch should be
built into u-boot. If multiple switches are selected, auto-detecting
can also be enabled.

Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
---
 drivers/net/Kconfig                 |  21 +-
 drivers/net/Makefile                |   2 +-
 drivers/net/mtk_eth/Kconfig         |  35 +
 drivers/net/mtk_eth/Makefile        |   9 +
 drivers/net/mtk_eth/mt7530.c        | 281 ++++++++
 drivers/net/mtk_eth/mt7531.c        | 293 +++++++++
 drivers/net/mtk_eth/mt753x.c        | 262 ++++++++
 drivers/net/mtk_eth/mt753x.h        | 286 ++++++++
 drivers/net/mtk_eth/mt7988.c        | 160 +++++
 drivers/net/{ => mtk_eth}/mtk_eth.c | 971 ++++------------------------
 drivers/net/{ => mtk_eth}/mtk_eth.h | 301 ++-------
 11 files changed, 1520 insertions(+), 1101 deletions(-)
 create mode 100644 drivers/net/mtk_eth/Kconfig
 create mode 100644 drivers/net/mtk_eth/Makefile
 create mode 100644 drivers/net/mtk_eth/mt7530.c
 create mode 100644 drivers/net/mtk_eth/mt7531.c
 create mode 100644 drivers/net/mtk_eth/mt753x.c
 create mode 100644 drivers/net/mtk_eth/mt753x.h
 create mode 100644 drivers/net/mtk_eth/mt7988.c
 rename drivers/net/{ => mtk_eth}/mtk_eth.c (62%)
 rename drivers/net/{ => mtk_eth}/mtk_eth.h (59%)

--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -912,26 +912,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
@@ -65,7 +65,7 @@ obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio
 obj-$(CONFIG_MDIO_MUX_MMIOREG) += mdio_mux_mmioreg.o
 obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o
 obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
-obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
+obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth/
 obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
 obj-$(CONFIG_MT7620_ETH) += mt7620-eth.o
 obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o
--- /dev/null
+++ b/drivers/net/mtk_eth/Kconfig
@@ -0,0 +1,35 @@
+
+config MEDIATEK_ETH
+	bool "MediaTek Ethernet GMAC Driver"
+	select PHYLIB
+	select DM_GPIO
+	select DM_RESET
+	help
+	  This Driver support MediaTek Ethernet GMAC
+	  Say Y to enable support for the MediaTek Ethernet GMAC.
+
+if MEDIATEK_ETH
+
+config MTK_ETH_SGMII
+	bool
+	default y if ARCH_MEDIATEK && !TARGET_MT7623
+
+config MTK_ETH_XGMII
+	bool
+	default y if TARGET_MT7988
+
+config MTK_ETH_SWITCH_MT7530
+	bool "Support for MediaTek MT7530 ethernet switch"
+	default y if TARGET_MT7623 || SOC_MT7621
+
+config MTK_ETH_SWITCH_MT7531
+	bool "Support for MediaTek MT7531 ethernet switch"
+	default y if TARGET_MT7622 || TARGET_MT7629 || TARGET_MT7981 || \
+		     TARGET_MT7986
+
+config MTK_ETH_SWITCH_MT7988
+	bool "Support for MediaTek MT7988 built-in ethernet switch"
+	depends on TARGET_MT7988
+	default y
+
+endif # MEDIATEK_ETH
--- /dev/null
+++ b/drivers/net/mtk_eth/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2025 MediaTek Inc.
+# Author: Weijie Gao <weijie.gao@mediatek.com>
+
+obj-y += mtk_eth.o
+obj-$(CONFIG_MTK_ETH_SWITCH_MT7530) += mt753x.o mt7530.o
+obj-$(CONFIG_MTK_ETH_SWITCH_MT7531) += mt753x.o mt7531.o
+obj-$(CONFIG_MTK_ETH_SWITCH_MT7988) += mt753x.o mt7988.o
--- /dev/null
+++ b/drivers/net/mtk_eth/mt7530.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
+ */
+
+#include <miiphy.h>
+#include <linux/delay.h>
+#include <linux/mdio.h>
+#include <linux/mii.h>
+#include "mtk_eth.h"
+#include "mt753x.h"
+
+#define CHIP_REV			0x7ffc
+#define CHIP_NAME_S			16
+#define CHIP_NAME_M			0xffff0000
+#define CHIP_REV_S			0
+#define CHIP_REV_M			0x0f
+
+static void mt7530_core_reg_write(struct mt753x_switch_priv *priv, u32 reg,
+				  u32 val)
+{
+	u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
+
+	mtk_mmd_ind_write(priv->epriv.eth, phy_addr, 0x1f, reg, val);
+}
+
+static int mt7530_pad_clk_setup(struct mt753x_switch_priv *priv, int mode)
+{
+	u32 ncpo1, ssc_delta;
+
+	switch (mode) {
+	case PHY_INTERFACE_MODE_RGMII:
+		ncpo1 = 0x0c80;
+		ssc_delta = 0x87;
+		break;
+
+	default:
+		printf("error: xMII mode %d is not supported\n", mode);
+		return -EINVAL;
+	}
+
+	/* Disable MT7530 core clock */
+	mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0);
+
+	/* Disable MT7530 PLL */
+	mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1,
+			      (2 << RG_GSWPLL_POSDIV_200M_S) |
+			      (32 << RG_GSWPLL_FBKDIV_200M_S));
+
+	/* For MT7530 core clock = 500Mhz */
+	mt7530_core_reg_write(priv, CORE_GSWPLL_GRP2,
+			      (1 << RG_GSWPLL_POSDIV_500M_S) |
+			      (25 << RG_GSWPLL_FBKDIV_500M_S));
+
+	/* Enable MT7530 PLL */
+	mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1,
+			      (2 << RG_GSWPLL_POSDIV_200M_S) |
+			      (32 << RG_GSWPLL_FBKDIV_200M_S) |
+			      RG_GSWPLL_EN_PRE);
+
+	udelay(20);
+
+	mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
+
+	/* Setup the MT7530 TRGMII Tx Clock */
+	mt7530_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1);
+	mt7530_core_reg_write(priv, CORE_PLL_GROUP6, 0);
+	mt7530_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta);
+	mt7530_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta);
+	mt7530_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
+			      RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
+
+	mt7530_core_reg_write(priv, CORE_PLL_GROUP2,
+			      RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
+			      (1 << RG_SYSPLL_POSDIV_S));
+
+	mt7530_core_reg_write(priv, CORE_PLL_GROUP7,
+			      RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) |
+			      RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
+
+	/* Enable MT7530 core clock */
+	mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG,
+			      REG_GSWCK_EN | REG_TRGMIICK_EN);
+
+	return 0;
+}
+
+static void mt7530_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
+{
+	struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+	u32 pmcr = FORCE_MODE;
+
+	if (enable)
+		pmcr = priv->pmcr;
+
+	mt753x_reg_write(priv, PMCR_REG(6), pmcr);
+}
+
+static int mt7530_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	struct mt753x_switch_priv *priv = bus->priv;
+
+	if (devad < 0)
+		return mtk_mii_read(priv->epriv.eth, addr, reg);
+
+	return mtk_mmd_ind_read(priv->epriv.eth, addr, devad, reg);
+}
+
+static int mt7530_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+			     u16 val)
+{
+	struct mt753x_switch_priv *priv = bus->priv;
+
+	if (devad < 0)
+		return mtk_mii_write(priv->epriv.eth, addr, reg, val);
+
+	return mtk_mmd_ind_write(priv->epriv.eth, addr, devad, reg, val);
+}
+
+static int mt7530_mdio_register(struct mt753x_switch_priv *priv)
+{
+	struct mii_dev *mdio_bus = mdio_alloc();
+	int ret;
+
+	if (!mdio_bus)
+		return -ENOMEM;
+
+	mdio_bus->read = mt7530_mdio_read;
+	mdio_bus->write = mt7530_mdio_write;
+	snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
+
+	mdio_bus->priv = priv;
+
+	ret = mdio_register(mdio_bus);
+	if (ret) {
+		mdio_free(mdio_bus);
+		return ret;
+	}
+
+	priv->mdio_bus = mdio_bus;
+
+	return 0;
+}
+
+static int mt7530_setup(struct mtk_eth_switch_priv *swpriv)
+{
+	struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+	u16 phy_addr, phy_val;
+	u32 i, val, txdrv;
+
+	priv->smi_addr = MT753X_DFL_SMI_ADDR;
+	priv->reg_read = mt753x_mdio_reg_read;
+	priv->reg_write = mt753x_mdio_reg_write;
+
+	if (!MTK_HAS_CAPS(priv->epriv.soc->caps, MTK_TRGMII_MT7621_CLK)) {
+		/* Select 250MHz clk for RGMII mode */
+		mtk_ethsys_rmw(priv->epriv.eth, ETHSYS_CLKCFG0_REG,
+			       ETHSYS_TRGMII_CLK_SEL362_5, 0);
+
+		txdrv = 8;
+	} else {
+		txdrv = 4;
+	}
+
+	/* Modify HWTRAP first to allow direct access to internal PHYs */
+	mt753x_reg_read(priv, HWTRAP_REG, &val);
+	val |= CHG_TRAP;
+	val &= ~C_MDIO_BPS;
+	mt753x_reg_write(priv, MHWTRAP_REG, val);
+
+	/* Calculate the phy base address */
+	val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3;
+	priv->phy_base = (val | 0x7) + 1;
+
+	/* Turn off PHYs */
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
+		phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
+		phy_val |= BMCR_PDOWN;
+		mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
+	}
+
+	/* Force MAC link down before reset */
+	mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
+	mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
+
+	/* MT7530 reset */
+	mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
+	udelay(100);
+
+	val = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+	      MAC_MODE | FORCE_MODE |
+	      MAC_TX_EN | MAC_RX_EN |
+	      BKOFF_EN | BACKPR_EN |
+	      (SPEED_1000M << FORCE_SPD_S) |
+	      FORCE_DPX | FORCE_LINK;
+
+	/* MT7530 Port6: Forced 1000M/FD, FC disabled */
+	priv->pmcr = val;
+
+	/* MT7530 Port5: Forced link down */
+	mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
+
+	/* Keep MAC link down before starting eth */
+	mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
+
+	/* MT7530 Port6: Set to RGMII */
+	mt753x_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII);
+
+	/* Hardware Trap: Enable Port6, Disable Port5 */
+	mt753x_reg_read(priv, HWTRAP_REG, &val);
+	val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS |
+	       (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) |
+	       (P5_INTF_MODE_RGMII << P5_INTF_MODE_S);
+	val &= ~(C_MDIO_BPS | P6_INTF_DIS);
+	mt753x_reg_write(priv, MHWTRAP_REG, val);
+
+	/* Setup switch core pll */
+	mt7530_pad_clk_setup(priv, priv->epriv.phy_interface);
+
+	/* Lower Tx Driving for TRGMII path */
+	for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
+		mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i),
+				 (txdrv << TD_DM_DRVP_S) |
+				 (txdrv << TD_DM_DRVN_S));
+
+	for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
+		mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16);
+
+	/* Enable port isolation to block inter-port communication */
+	mt753x_port_isolation(priv);
+
+	/* Turn on PHYs */
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
+		phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
+		phy_val &= ~BMCR_PDOWN;
+		mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
+	}
+
+	return mt7530_mdio_register(priv);
+}
+
+static int mt7530_cleanup(struct mtk_eth_switch_priv *swpriv)
+{
+	struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+
+	mdio_unregister(priv->mdio_bus);
+
+	return 0;
+}
+
+static int mt7530_detect(struct mtk_eth_priv *priv)
+{
+	int ret;
+	u32 rev;
+
+	ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev);
+	if (ret)
+		return ret;
+
+	if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7530)
+		return 0;
+
+	return -ENODEV;
+}
+
+MTK_ETH_SWITCH(mt7530) = {
+	.name = "mt7530",
+	.desc = "MediaTek MT7530",
+	.priv_size = sizeof(struct mt753x_switch_priv),
+	.reset_wait_time = 1000,
+
+	.detect = mt7530_detect,
+	.setup = mt7530_setup,
+	.cleanup = mt7530_cleanup,
+	.mac_control = mt7530_mac_control,
+};
--- /dev/null
+++ b/drivers/net/mtk_eth/mt7531.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
+ */
+
+#include <miiphy.h>
+#include <linux/delay.h>
+#include <linux/mdio.h>
+#include <linux/mii.h>
+#include "mtk_eth.h"
+#include "mt753x.h"
+
+#define CHIP_REV			0x781C
+#define CHIP_NAME_S			16
+#define CHIP_NAME_M			0xffff0000
+#define CHIP_REV_S			0
+#define CHIP_REV_M			0x0f
+#define CHIP_REV_E1			0x0
+
+static int mt7531_core_reg_read(struct mt753x_switch_priv *priv, u32 reg)
+{
+	u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
+
+	return mt7531_mmd_read(priv, phy_addr, 0x1f, reg);
+}
+
+static void mt7531_core_reg_write(struct mt753x_switch_priv *priv, u32 reg,
+				  u32 val)
+{
+	u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
+
+	mt7531_mmd_write(priv, phy_addr, 0x1f, reg, val);
+}
+
+static void mt7531_core_pll_setup(struct mt753x_switch_priv *priv)
+{
+	/* Step 1 : Disable MT7531 COREPLL */
+	mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, 0);
+
+	/* Step 2: switch to XTAL output */
+	mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_CLKSW, SW_CLKSW);
+
+	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, 0);
+
+	/* Step 3: disable PLLGP and enable program PLLGP */
+	mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_PLLGP, SW_PLLGP);
+
+	/* Step 4: program COREPLL output frequency to 500MHz */
+	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_POSDIV_M,
+		       2 << RG_COREPLL_POSDIV_S);
+	udelay(25);
+
+	/* Currently, support XTAL 25Mhz only */
+	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_M,
+		       0x140000 << RG_COREPLL_SDM_PCW_S);
+
+	/* Set feedback divide ratio update signal to high */
+	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG,
+		       RG_COREPLL_SDM_PCW_CHG);
+
+	/* Wait for at least 16 XTAL clocks */
+	udelay(10);
+
+	/* Step 5: set feedback divide ratio update signal to low */
+	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, 0);
+
+	/* add enable 325M clock for SGMII */
+	mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
+
+	/* add enable 250SSC clock for RGMII */
+	mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
+
+	/*Step 6: Enable MT7531 PLL */
+	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, RG_COREPLL_EN);
+
+	mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, EN_COREPLL);
+
+	udelay(25);
+}
+
+static int mt7531_port_sgmii_init(struct mt753x_switch_priv *priv, u32 port)
+{
+	if (port != 5 && port != 6) {
+		printf("mt7531: port %d is not a SGMII port\n", port);
+		return -EINVAL;
+	}
+
+	/* Set SGMII GEN2 speed(2.5G) */
+	mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK,
+		       FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
+
+	/* Disable SGMII AN */
+	mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port),
+		       SGMII_AN_ENABLE, 0);
+
+	/* SGMII force mode setting */
+	mt753x_reg_write(priv, MT7531_SGMII_MODE(port), SGMII_FORCE_MODE);
+
+	/* Release PHYA power down state */
+	mt753x_reg_rmw(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
+		       SGMII_PHYA_PWD, 0);
+
+	return 0;
+}
+
+static int mt7531_port_rgmii_init(struct mt753x_switch_priv *priv, u32 port)
+{
+	u32 val;
+
+	if (port != 5) {
+		printf("error: RGMII mode is not available for port %d\n",
+		       port);
+		return -EINVAL;
+	}
+
+	mt753x_reg_read(priv, MT7531_CLKGEN_CTRL, &val);
+	val |= GP_CLK_EN;
+	val &= ~GP_MODE_M;
+	val |= GP_MODE_RGMII << GP_MODE_S;
+	val |= TXCLK_NO_REVERSE;
+	val |= RXCLK_NO_DELAY;
+	val &= ~CLK_SKEW_IN_M;
+	val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S;
+	val &= ~CLK_SKEW_OUT_M;
+	val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S;
+	mt753x_reg_write(priv, MT7531_CLKGEN_CTRL, val);
+
+	return 0;
+}
+
+static void mt7531_phy_setting(struct mt753x_switch_priv *priv)
+{
+	int i;
+	u32 val;
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		/* Enable HW auto downshift */
+		mt7531_mii_write(priv, i, 0x1f, 0x1);
+		val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
+		val |= PHY_EN_DOWN_SHFIT;
+		mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
+
+		/* PHY link down power saving enable */
+		val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
+		val |= PHY_LINKDOWN_POWER_SAVING_EN;
+		mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
+
+		val = mt7531_mmd_read(priv, i, 0x1e, PHY_DEV1E_REG_0C6);
+		val &= ~PHY_POWER_SAVING_M;
+		val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
+		mt7531_mmd_write(priv, i, 0x1e, PHY_DEV1E_REG_0C6, val);
+	}
+}
+
+static void mt7531_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
+{
+	struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+	u32 pmcr = FORCE_MODE_LNK;
+
+	if (enable)
+		pmcr = priv->pmcr;
+
+	mt753x_reg_write(priv, PMCR_REG(5), pmcr);
+	mt753x_reg_write(priv, PMCR_REG(6), pmcr);
+}
+
+static int mt7531_setup(struct mtk_eth_switch_priv *swpriv)
+{
+	struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+	u32 i, val, pmcr, port5_sgmii;
+	u16 phy_addr, phy_val;
+
+	priv->smi_addr = MT753X_DFL_SMI_ADDR;
+	priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
+	priv->reg_read = mt753x_mdio_reg_read;
+	priv->reg_write = mt753x_mdio_reg_write;
+
+	/* Turn off PHYs */
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
+		phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
+		phy_val |= BMCR_PDOWN;
+		mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
+	}
+
+	/* Force MAC link down before reset */
+	mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
+	mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
+
+	/* Switch soft reset */
+	mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
+	udelay(100);
+
+	/* Enable MDC input Schmitt Trigger */
+	mt753x_reg_rmw(priv, MT7531_SMT0_IOLB, SMT_IOLB_5_SMI_MDC_EN,
+		       SMT_IOLB_5_SMI_MDC_EN);
+
+	mt7531_core_pll_setup(priv);
+
+	mt753x_reg_read(priv, MT7531_TOP_SIG_SR, &val);
+	port5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
+
+	/* port5 support either RGMII or SGMII, port6 only support SGMII. */
+	switch (priv->epriv.phy_interface) {
+	case PHY_INTERFACE_MODE_RGMII:
+		if (!port5_sgmii)
+			mt7531_port_rgmii_init(priv, 5);
+		break;
+
+	case PHY_INTERFACE_MODE_2500BASEX:
+		mt7531_port_sgmii_init(priv, 6);
+		if (port5_sgmii)
+			mt7531_port_sgmii_init(priv, 5);
+		break;
+
+	default:
+		break;
+	}
+
+	pmcr = MT7531_FORCE_MODE |
+	       (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+	       MAC_MODE | MAC_TX_EN | MAC_RX_EN |
+	       BKOFF_EN | BACKPR_EN |
+	       FORCE_RX_FC | FORCE_TX_FC |
+	       (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
+	       FORCE_LINK;
+
+	priv->pmcr = pmcr;
+
+	/* Keep MAC link down before starting eth */
+	mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
+	mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
+
+	/* Enable port isolation to block inter-port communication */
+	mt753x_port_isolation(priv);
+
+	/* Turn on PHYs */
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
+		phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
+		phy_val &= ~BMCR_PDOWN;
+		mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
+	}
+
+	mt7531_phy_setting(priv);
+
+	/* Enable Internal PHYs */
+	val = mt7531_core_reg_read(priv, CORE_PLL_GROUP4);
+	val |= MT7531_BYPASS_MODE;
+	val &= ~MT7531_POWER_ON_OFF;
+	mt7531_core_reg_write(priv, CORE_PLL_GROUP4, val);
+
+	return mt7531_mdio_register(priv);
+}
+
+static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
+{
+	struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+
+	mdio_unregister(priv->mdio_bus);
+
+	return 0;
+}
+
+static int mt7531_detect(struct mtk_eth_priv *priv)
+{
+	int ret;
+	u32 rev;
+
+	ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev);
+	if (ret)
+		return ret;
+
+	if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7531)
+		return 0;
+
+	return -ENODEV;
+}
+
+MTK_ETH_SWITCH(mt7531) = {
+	.name = "mt7531",
+	.desc = "MediaTek MT7531",
+	.priv_size = sizeof(struct mt753x_switch_priv),
+	.reset_wait_time = 200,
+
+	.detect = mt7531_detect,
+	.setup = mt7531_setup,
+	.cleanup = mt7531_cleanup,
+	.mac_control = mt7531_mac_control,
+};
--- /dev/null
+++ b/drivers/net/mtk_eth/mt753x.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
+ */
+
+#include <errno.h>
+#include <time.h>
+#include "mtk_eth.h"
+#include "mt753x.h"
+
+/*
+ * MT753x Internal Register Address Bits
+ * -------------------------------------------------------------------
+ * | 15  14  13  12  11  10   9   8   7   6 | 5   4   3   2 | 1   0  |
+ * |----------------------------------------|---------------|--------|
+ * |              Page Address              |  Reg Address  | Unused |
+ * -------------------------------------------------------------------
+ */
+
+int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg,
+			   u32 *data)
+{
+	int ret, low_word, high_word;
+
+	/* Write page address */
+	ret = mtk_mii_write(priv, smi_addr, 0x1f, reg >> 6);
+	if (ret)
+		return ret;
+
+	/* Read low word */
+	low_word = mtk_mii_read(priv, smi_addr, (reg >> 2) & 0xf);
+	if (low_word < 0)
+		return low_word;
+
+	/* Read high word */
+	high_word = mtk_mii_read(priv, smi_addr, 0x10);
+	if (high_word < 0)
+		return high_word;
+
+	if (data)
+		*data = ((u32)high_word << 16) | (low_word & 0xffff);
+
+	return 0;
+}
+
+int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
+{
+	return __mt753x_mdio_reg_read(priv->epriv.eth, priv->smi_addr, reg,
+				      data);
+}
+
+int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
+{
+	int ret;
+
+	/* Write page address */
+	ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x1f, reg >> 6);
+	if (ret)
+		return ret;
+
+	/* Write low word */
+	ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, (reg >> 2) & 0xf,
+			    data & 0xffff);
+	if (ret)
+		return ret;
+
+	/* Write high word */
+	return mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x10, data >> 16);
+}
+
+int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
+{
+	return priv->reg_read(priv, reg, data);
+}
+
+int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
+{
+	return priv->reg_write(priv, reg, data);
+}
+
+void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set)
+{
+	u32 val;
+
+	priv->reg_read(priv, reg, &val);
+	val &= ~clr;
+	val |= set;
+	priv->reg_write(priv, reg, val);
+}
+
+/* Indirect MDIO clause 22/45 access */
+static int mt7531_mii_rw(struct mt753x_switch_priv *priv, int phy, int reg,
+			 u16 data, u32 cmd, u32 st)
+{
+	u32 val, timeout_ms;
+	ulong timeout;
+	int ret = 0;
+
+	val = (st << MDIO_ST_S) |
+	      ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
+	      ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
+	      ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
+
+	if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
+		val |= data & MDIO_RW_DATA_M;
+
+	mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST);
+
+	timeout_ms = 100;
+	timeout = get_timer(0);
+	while (1) {
+		mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
+
+		if ((val & PHY_ACS_ST) == 0)
+			break;
+
+		if (get_timer(timeout) > timeout_ms)
+			return -ETIMEDOUT;
+	}
+
+	if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
+		mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
+		ret = val & MDIO_RW_DATA_M;
+	}
+
+	return ret;
+}
+
+int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg)
+{
+	u8 phy_addr;
+
+	if (phy >= MT753X_NUM_PHYS)
+		return -EINVAL;
+
+	phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
+
+	return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ,
+			     MDIO_ST_C22);
+}
+
+int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val)
+{
+	u8 phy_addr;
+
+	if (phy >= MT753X_NUM_PHYS)
+		return -EINVAL;
+
+	phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
+
+	return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE,
+			     MDIO_ST_C22);
+}
+
+int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
+		    u16 reg)
+{
+	u8 phy_addr;
+	int ret;
+
+	if (addr >= MT753X_NUM_PHYS)
+		return -EINVAL;
+
+	phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
+
+	ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
+			    MDIO_ST_C45);
+	if (ret)
+		return ret;
+
+	return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45,
+			     MDIO_ST_C45);
+}
+
+int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
+		     u16 reg, u16 val)
+{
+	u8 phy_addr;
+	int ret;
+
+	if (addr >= MT753X_NUM_PHYS)
+		return 0;
+
+	phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
+
+	ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
+			    MDIO_ST_C45);
+	if (ret)
+		return ret;
+
+	return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE,
+			     MDIO_ST_C45);
+}
+
+static int mt7531_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	struct mt753x_switch_priv *priv = bus->priv;
+
+	if (devad < 0)
+		return mt7531_mii_read(priv, addr, reg);
+
+	return mt7531_mmd_read(priv, addr, devad, reg);
+}
+
+static int mt7531_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+			     u16 val)
+{
+	struct mt753x_switch_priv *priv = bus->priv;
+
+	if (devad < 0)
+		return mt7531_mii_write(priv, addr, reg, val);
+
+	return mt7531_mmd_write(priv, addr, devad, reg, val);
+}
+
+int mt7531_mdio_register(struct mt753x_switch_priv *priv)
+{
+	struct mii_dev *mdio_bus = mdio_alloc();
+	int ret;
+
+	if (!mdio_bus)
+		return -ENOMEM;
+
+	mdio_bus->read = mt7531_mdio_read;
+	mdio_bus->write = mt7531_mdio_write;
+	snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
+
+	mdio_bus->priv = priv;
+
+	ret = mdio_register(mdio_bus);
+	if (ret) {
+		mdio_free(mdio_bus);
+		return ret;
+	}
+
+	priv->mdio_bus = mdio_bus;
+
+	return 0;
+}
+
+void mt753x_port_isolation(struct mt753x_switch_priv *priv)
+{
+	u32 i;
+
+	for (i = 0; i < MT753X_NUM_PORTS; i++) {
+		/* Set port matrix mode */
+		if (i != 6)
+			mt753x_reg_write(priv, PCR_REG(i),
+					 (0x40 << PORT_MATRIX_S));
+		else
+			mt753x_reg_write(priv, PCR_REG(i),
+					 (0x3f << PORT_MATRIX_S));
+
+		/* Set port mode to user port */
+		mt753x_reg_write(priv, PVC_REG(i),
+				 (0x8100 << STAG_VPID_S) |
+				 (VLAN_ATTR_USER << VLAN_ATTR_S));
+	}
+}
--- /dev/null
+++ b/drivers/net/mtk_eth/mt753x.h
@@ -0,0 +1,286 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
+ */
+
+#ifndef _MTK_ETH_MT753X_H_
+#define _MTK_ETH_MT753X_H_
+
+#include <phy.h>
+#include <miiphy.h>
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+
+struct mtk_eth_priv;
+
+#define MT753X_NUM_PHYS		5
+#define MT753X_NUM_PORTS	7
+#define MT753X_DFL_SMI_ADDR	31
+#define MT753X_SMI_ADDR_MASK	0x1f
+
+#define MT753X_PHY_ADDR(base, addr) \
+	(((base) + (addr)) & 0x1f)
+
+/* MT7530 Registers */
+#define PCR_REG(p)			(0x2004 + (p) * 0x100)
+#define PORT_MATRIX_S			16
+#define PORT_MATRIX_M			0xff0000
+
+#define PVC_REG(p)			(0x2010 + (p) * 0x100)
+#define STAG_VPID_S			16
+#define STAG_VPID_M			0xffff0000
+#define VLAN_ATTR_S			6
+#define VLAN_ATTR_M			0xc0
+
+/* VLAN_ATTR: VLAN attributes */
+#define VLAN_ATTR_USER			0
+#define VLAN_ATTR_STACK			1
+#define VLAN_ATTR_TRANSLATION		2
+#define VLAN_ATTR_TRANSPARENT		3
+
+#define PMCR_REG(p)			(0x3000 + (p) * 0x100)
+/* XXX: all fields of MT7530 are defined under GMAC_PORT_MCR
+ * MT7531 specific fields are defined below
+ */
+#define FORCE_MODE_EEE1G		BIT(25)
+#define FORCE_MODE_EEE100		BIT(26)
+#define FORCE_MODE_TX_FC		BIT(27)
+#define FORCE_MODE_RX_FC		BIT(28)
+#define FORCE_MODE_DPX			BIT(29)
+#define FORCE_MODE_SPD			BIT(30)
+#define FORCE_MODE_LNK			BIT(31)
+#define MT7531_FORCE_MODE		FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
+					FORCE_MODE_DPX   | FORCE_MODE_SPD | \
+					FORCE_MODE_LNK
+#define MT7988_FORCE_MODE		FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
+					FORCE_MODE_DPX   | FORCE_MODE_SPD | \
+					FORCE_MODE_LNK
+
+/* MT7531 SGMII Registers */
+#define MT7531_SGMII_REG_BASE		0x5000
+#define MT7531_SGMII_REG_PORT_BASE	0x1000
+#define MT7531_SGMII_REG(p, r)		(MT7531_SGMII_REG_BASE + \
+					(p) * MT7531_SGMII_REG_PORT_BASE + (r))
+#define MT7531_PCS_CONTROL_1(p)		MT7531_SGMII_REG(((p) - 5), 0x00)
+#define MT7531_SGMII_MODE(p)		MT7531_SGMII_REG(((p) - 5), 0x20)
+#define MT7531_QPHY_PWR_STATE_CTRL(p)	MT7531_SGMII_REG(((p) - 5), 0xe8)
+#define MT7531_PHYA_CTRL_SIGNAL3(p)	MT7531_SGMII_REG(((p) - 5), 0x128)
+#define MT7531_PHYA_ANA_SYSPLL(p)	MT7531_SGMII_REG(((p) - 5), 0x158)
+/* XXX: all fields of MT7531 SGMII  are defined under SGMSYS */
+
+/* MT753x System Control Register */
+#define SYS_CTRL_REG			0x7000
+#define SW_PHY_RST			BIT(2)
+#define SW_SYS_RST			BIT(1)
+#define SW_REG_RST			BIT(0)
+
+/* MT7531  */
+#define MT7531_PHY_IAC			0x701c
+/* XXX: all fields are defined under GMAC_PIAC_REG */
+
+#define MT7531_CLKGEN_CTRL		0x7500
+#define CLK_SKEW_OUT_S			8
+#define CLK_SKEW_OUT_M			0x300
+#define CLK_SKEW_IN_S			6
+#define CLK_SKEW_IN_M			0xc0
+#define RXCLK_NO_DELAY			BIT(5)
+#define TXCLK_NO_REVERSE		BIT(4)
+#define GP_MODE_S			1
+#define GP_MODE_M			0x06
+#define GP_CLK_EN			BIT(0)
+
+/* Values of GP_MODE */
+#define GP_MODE_RGMII			0
+#define GP_MODE_MII			1
+#define GP_MODE_REV_MII			2
+
+/* Values of CLK_SKEW_IN */
+#define CLK_SKEW_IN_NO_CHANGE		0
+#define CLK_SKEW_IN_DELAY_100PPS	1
+#define CLK_SKEW_IN_DELAY_200PPS	2
+#define CLK_SKEW_IN_REVERSE		3
+
+/* Values of CLK_SKEW_OUT */
+#define CLK_SKEW_OUT_NO_CHANGE		0
+#define CLK_SKEW_OUT_DELAY_100PPS	1
+#define CLK_SKEW_OUT_DELAY_200PPS	2
+#define CLK_SKEW_OUT_REVERSE		3
+
+#define HWTRAP_REG			0x7800
+/* MT7530 Modified Hardware Trap Status Registers */
+#define MHWTRAP_REG			0x7804
+#define CHG_TRAP			BIT(16)
+#define LOOPDET_DIS			BIT(14)
+#define P5_INTF_SEL_S			13
+#define P5_INTF_SEL_M			0x2000
+#define SMI_ADDR_S			11
+#define SMI_ADDR_M			0x1800
+#define XTAL_FSEL_S			9
+#define XTAL_FSEL_M			0x600
+#define P6_INTF_DIS			BIT(8)
+#define P5_INTF_MODE_S			7
+#define P5_INTF_MODE_M			0x80
+#define P5_INTF_DIS			BIT(6)
+#define C_MDIO_BPS			BIT(5)
+#define CHIP_MODE_S			0
+#define CHIP_MODE_M			0x0f
+
+/* P5_INTF_SEL: Interface type of Port5 */
+#define P5_INTF_SEL_GPHY		0
+#define P5_INTF_SEL_GMAC5		1
+
+/* P5_INTF_MODE: Interface mode of Port5 */
+#define P5_INTF_MODE_GMII_MII		0
+#define P5_INTF_MODE_RGMII		1
+
+#define MT7530_P6ECR			0x7830
+#define P6_INTF_MODE_M			0x3
+#define P6_INTF_MODE_S			0
+
+/* P6_INTF_MODE: Interface mode of Port6 */
+#define P6_INTF_MODE_RGMII		0
+#define P6_INTF_MODE_TRGMII		1
+
+#define MT7530_TRGMII_RD(n)		(0x7a10 + (n) * 8)
+#define RD_TAP_S			0
+#define RD_TAP_M			0x7f
+
+#define MT7530_TRGMII_TD_ODT(n)		(0x7a54 + (n) * 8)
+/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */
+
+/* TOP Signals Status Register */
+#define MT7531_TOP_SIG_SR		0x780c
+#define PAD_MCM_SMI_EN			BIT(0)
+#define PAD_DUAL_SGMII_EN		BIT(1)
+
+/* MT7531 PLLGP Registers */
+#define MT7531_PLLGP_EN			0x7820
+#define EN_COREPLL			BIT(2)
+#define SW_CLKSW			BIT(1)
+#define SW_PLLGP			BIT(0)
+
+#define MT7531_PLLGP_CR0		0x78a8
+#define RG_COREPLL_EN			BIT(22)
+#define RG_COREPLL_POSDIV_S		23
+#define RG_COREPLL_POSDIV_M		0x3800000
+#define RG_COREPLL_SDM_PCW_S		1
+#define RG_COREPLL_SDM_PCW_M		0x3ffffe
+#define RG_COREPLL_SDM_PCW_CHG		BIT(0)
+
+/* MT7531 RGMII and SGMII PLL clock */
+#define MT7531_ANA_PLLGP_CR2		0x78b0
+#define MT7531_ANA_PLLGP_CR5		0x78bc
+
+/* MT7531 GPIO GROUP IOLB SMT0 Control */
+#define MT7531_SMT0_IOLB		0x7f04
+#define SMT_IOLB_5_SMI_MDC_EN		BIT(5)
+
+/* MT7530 GPHY MDIO MMD Registers */
+#define CORE_PLL_GROUP2			0x401
+#define RG_SYSPLL_EN_NORMAL		BIT(15)
+#define RG_SYSPLL_VODEN			BIT(14)
+#define RG_SYSPLL_POSDIV_S		5
+#define RG_SYSPLL_POSDIV_M		0x60
+
+#define CORE_PLL_GROUP4			0x403
+#define MT7531_BYPASS_MODE		BIT(4)
+#define MT7531_POWER_ON_OFF		BIT(5)
+#define RG_SYSPLL_DDSFBK_EN		BIT(12)
+#define RG_SYSPLL_BIAS_EN		BIT(11)
+#define RG_SYSPLL_BIAS_LPF_EN		BIT(10)
+
+#define CORE_PLL_GROUP5			0x404
+#define RG_LCDDS_PCW_NCPO1_S		0
+#define RG_LCDDS_PCW_NCPO1_M		0xffff
+
+#define CORE_PLL_GROUP6			0x405
+#define RG_LCDDS_PCW_NCPO0_S		0
+#define RG_LCDDS_PCW_NCPO0_M		0xffff
+
+#define CORE_PLL_GROUP7			0x406
+#define RG_LCDDS_PWDB			BIT(15)
+#define RG_LCDDS_ISO_EN			BIT(13)
+#define RG_LCCDS_C_S			4
+#define RG_LCCDS_C_M			0x70
+#define RG_LCDDS_PCW_NCPO_CHG		BIT(3)
+
+#define CORE_PLL_GROUP10		0x409
+#define RG_LCDDS_SSC_DELTA_S		0
+#define RG_LCDDS_SSC_DELTA_M		0xfff
+
+#define CORE_PLL_GROUP11		0x40a
+#define RG_LCDDS_SSC_DELTA1_S		0
+#define RG_LCDDS_SSC_DELTA1_M		0xfff
+
+#define CORE_GSWPLL_GRP1		0x40d
+#define RG_GSWPLL_POSDIV_200M_S		12
+#define RG_GSWPLL_POSDIV_200M_M		0x3000
+#define RG_GSWPLL_EN_PRE		BIT(11)
+#define RG_GSWPLL_FBKDIV_200M_S		0
+#define RG_GSWPLL_FBKDIV_200M_M		0xff
+
+#define CORE_GSWPLL_GRP2		0x40e
+#define RG_GSWPLL_POSDIV_500M_S		8
+#define RG_GSWPLL_POSDIV_500M_M		0x300
+#define RG_GSWPLL_FBKDIV_500M_S		0
+#define RG_GSWPLL_FBKDIV_500M_M		0xff
+
+#define CORE_TRGMII_GSW_CLK_CG		0x410
+#define REG_GSWCK_EN			BIT(0)
+#define REG_TRGMIICK_EN			BIT(1)
+
+/* Extend PHY Control Register 3 */
+#define PHY_EXT_REG_14			0x14
+
+/* Fields of PHY_EXT_REG_14 */
+#define PHY_EN_DOWN_SHFIT		BIT(4)
+
+/* Extend PHY Control Register 4 */
+#define PHY_EXT_REG_17			0x17
+
+/* Fields of PHY_EXT_REG_17 */
+#define PHY_LINKDOWN_POWER_SAVING_EN	BIT(4)
+
+/* PHY RXADC Control Register 7 */
+#define PHY_DEV1E_REG_0C6		0x0c6
+
+/* Fields of PHY_DEV1E_REG_0C6 */
+#define PHY_POWER_SAVING_S		8
+#define PHY_POWER_SAVING_M		0x300
+#define PHY_POWER_SAVING_TX		0x0
+
+struct mt753x_switch_priv {
+	struct mtk_eth_switch_priv epriv;
+	struct mii_dev *mdio_bus;
+	u32 smi_addr;
+	u32 phy_base;
+	u32 pmcr;
+
+	int (*reg_read)(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
+	int (*reg_write)(struct mt753x_switch_priv *priv, u32 reg, u32 data);
+};
+
+int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg,
+			   u32 *data);
+int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
+int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data);
+
+int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
+int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data);
+void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set);
+
+int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg);
+int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val);
+int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
+		    u16 reg);
+int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
+		     u16 reg, u16 val);
+
+int mt7531_mdio_register(struct mt753x_switch_priv *priv);
+
+void mt753x_port_isolation(struct mt753x_switch_priv *priv);
+
+#endif /* _MTK_ETH_MT753X_H_ */
--- /dev/null
+++ b/drivers/net/mtk_eth/mt7988.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
+ */
+
+#include <miiphy.h>
+#include <linux/delay.h>
+#include <linux/mdio.h>
+#include <linux/mii.h>
+#include <linux/io.h>
+#include "mtk_eth.h"
+#include "mt753x.h"
+
+static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
+{
+	*data = readl(priv->epriv.ethsys_base + GSW_BASE + reg);
+
+	return 0;
+}
+
+static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
+{
+	writel(data, priv->epriv.ethsys_base + GSW_BASE + reg);
+
+	return 0;
+}
+
+static void mt7988_phy_setting(struct mt753x_switch_priv *priv)
+{
+	u16 val;
+	u32 i;
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		/* Enable HW auto downshift */
+		mt7531_mii_write(priv, i, 0x1f, 0x1);
+		val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
+		val |= PHY_EN_DOWN_SHFIT;
+		mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
+
+		/* PHY link down power saving enable */
+		val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
+		val |= PHY_LINKDOWN_POWER_SAVING_EN;
+		mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
+	}
+}
+
+static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
+{
+	struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+	u32 pmcr = FORCE_MODE_LNK;
+
+	if (enable)
+		pmcr = priv->pmcr;
+
+	mt7988_reg_write(priv, PMCR_REG(6), pmcr);
+}
+
+static int mt7988_setup(struct mtk_eth_switch_priv *swpriv)
+{
+	struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+	u16 phy_addr, phy_val;
+	u32 pmcr;
+	int i;
+
+	priv->smi_addr = MT753X_DFL_SMI_ADDR;
+	priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
+	priv->reg_read = mt7988_reg_read;
+	priv->reg_write = mt7988_reg_write;
+
+	/* Turn off PHYs */
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
+		phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
+		phy_val |= BMCR_PDOWN;
+		mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
+	}
+
+	switch (priv->epriv.phy_interface) {
+	case PHY_INTERFACE_MODE_USXGMII:
+		/* Use CPU bridge instead of actual USXGMII path */
+
+		/* Disable GDM1 RX CRC stripping */
+		/* mtk_fe_rmw(priv, 0x500, BIT(16), 0); */
+
+		/* Set GDM1 no drop */
+		mtk_fe_rmw(priv->epriv.eth, PSE_NO_DROP_CFG_REG, 0,
+			   PSE_NO_DROP_GDM1);
+
+		/* Enable GSW CPU bridge as USXGMII */
+		/* mtk_fe_rmw(priv, 0x504, BIT(31), BIT(31)); */
+
+		/* Enable GDM1 to GSW CPU bridge */
+		mtk_gmac_rmw(priv->epriv.eth, GMAC_MAC_MISC_REG, 0, BIT(0));
+
+		/* XGMAC force link up */
+		mtk_gmac_rmw(priv->epriv.eth, GMAC_XGMAC_STS_REG, 0,
+			     P1_XGMAC_FORCE_LINK);
+
+		/* Setup GSW CPU bridge IPG */
+		mtk_gmac_rmw(priv->epriv.eth, GMAC_GSW_CFG_REG,
+			     GSWTX_IPG_M | GSWRX_IPG_M,
+			     (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S));
+		break;
+	default:
+		printf("Error: MT7988 GSW does not support %s interface\n",
+		       phy_string_for_interface(priv->epriv.phy_interface));
+		break;
+	}
+
+	pmcr = MT7988_FORCE_MODE |
+	       (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+	       MAC_MODE | MAC_TX_EN | MAC_RX_EN |
+	       BKOFF_EN | BACKPR_EN |
+	       FORCE_RX_FC | FORCE_TX_FC |
+	       (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
+	       FORCE_LINK;
+
+	priv->pmcr = pmcr;
+
+	/* Keep MAC link down before starting eth */
+	mt7988_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
+
+	/* Enable port isolation to block inter-port communication */
+	mt753x_port_isolation(priv);
+
+	/* Turn on PHYs */
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
+		phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
+		phy_val &= ~BMCR_PDOWN;
+		mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
+	}
+
+	mt7988_phy_setting(priv);
+
+	return mt7531_mdio_register(priv);
+}
+
+static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
+{
+	struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+
+	mdio_unregister(priv->mdio_bus);
+
+	return 0;
+}
+
+MTK_ETH_SWITCH(mt7988) = {
+	.name = "mt7988",
+	.desc = "MediaTek MT7988 built-in switch",
+	.priv_size = sizeof(struct mt753x_switch_priv),
+	.reset_wait_time = 50,
+
+	.setup = mt7988_setup,
+	.cleanup = mt7531_cleanup,
+	.mac_control = mt7988_mac_control,
+};
--- a/drivers/net/mtk_eth.c
+++ /dev/null
@@ -1,2280 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2018 MediaTek Inc.
- *
- * Author: Weijie Gao <weijie.gao@mediatek.com>
- * Author: Mark Lee <mark-mc.lee@mediatek.com>
- */
-
-#include <cpu_func.h>
-#include <dm.h>
-#include <log.h>
-#include <malloc.h>
-#include <miiphy.h>
-#include <net.h>
-#include <regmap.h>
-#include <reset.h>
-#include <syscon.h>
-#include <wait_bit.h>
-#include <asm/cache.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
-#include <dm/device_compat.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/ioport.h>
-#include <linux/mdio.h>
-#include <linux/mii.h>
-#include <linux/printk.h>
-
-#include "mtk_eth.h"
-
-#define NUM_TX_DESC		32
-#define NUM_RX_DESC		32
-#define TX_TOTAL_BUF_SIZE	(NUM_TX_DESC * PKTSIZE_ALIGN)
-#define RX_TOTAL_BUF_SIZE	(NUM_RX_DESC * PKTSIZE_ALIGN)
-#define TOTAL_PKT_BUF_SIZE	(TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE)
-
-#define MT753X_NUM_PHYS		5
-#define MT753X_NUM_PORTS	7
-#define MT753X_DFL_SMI_ADDR	31
-#define MT753X_SMI_ADDR_MASK	0x1f
-
-#define MT753X_PHY_ADDR(base, addr) \
-	(((base) + (addr)) & 0x1f)
-
-#define GDMA_FWD_TO_CPU \
-	(0x20000000 | \
-	GDM_ICS_EN | \
-	GDM_TCS_EN | \
-	GDM_UCS_EN | \
-	STRP_CRC | \
-	(DP_PDMA << MYMAC_DP_S) | \
-	(DP_PDMA << BC_DP_S) | \
-	(DP_PDMA << MC_DP_S) | \
-	(DP_PDMA << UN_DP_S))
-
-#define GDMA_BRIDGE_TO_CPU \
-	(0xC0000000 | \
-	GDM_ICS_EN | \
-	GDM_TCS_EN | \
-	GDM_UCS_EN | \
-	(DP_PDMA << MYMAC_DP_S) | \
-	(DP_PDMA << BC_DP_S) | \
-	(DP_PDMA << MC_DP_S) | \
-	(DP_PDMA << UN_DP_S))
-
-#define GDMA_FWD_DISCARD \
-	(0x20000000 | \
-	GDM_ICS_EN | \
-	GDM_TCS_EN | \
-	GDM_UCS_EN | \
-	STRP_CRC | \
-	(DP_DISCARD << MYMAC_DP_S) | \
-	(DP_DISCARD << BC_DP_S) | \
-	(DP_DISCARD << MC_DP_S) | \
-	(DP_DISCARD << UN_DP_S))
-
-enum mtk_switch {
-	SW_NONE,
-	SW_MT7530,
-	SW_MT7531,
-	SW_MT7988,
-};
-
-/* struct mtk_soc_data -	This is the structure holding all differences
- *				among various plaforms
- * @caps			Flags shown the extra capability for the SoC
- * @ana_rgc3:			The offset for register ANA_RGC3 related to
- *				sgmiisys syscon
- * @gdma_count:			Number of GDMAs
- * @pdma_base:			Register base of PDMA block
- * @txd_size:			Tx DMA descriptor size.
- * @rxd_size:			Rx DMA descriptor size.
- */
-struct mtk_soc_data {
-	u32 caps;
-	u32 ana_rgc3;
-	u32 gdma_count;
-	u32 pdma_base;
-	u32 txd_size;
-	u32 rxd_size;
-};
-
-struct mtk_eth_priv {
-	char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
-
-	void *tx_ring_noc;
-	void *rx_ring_noc;
-
-	int rx_dma_owner_idx0;
-	int tx_cpu_owner_idx0;
-
-	void __iomem *fe_base;
-	void __iomem *gmac_base;
-	void __iomem *sgmii_base;
-	void __iomem *gsw_base;
-
-	struct regmap *ethsys_regmap;
-
-	struct regmap *infra_regmap;
-
-	struct regmap *usxgmii_regmap;
-	struct regmap *xfi_pextp_regmap;
-	struct regmap *xfi_pll_regmap;
-	struct regmap *toprgu_regmap;
-
-	struct mii_dev *mdio_bus;
-	int (*mii_read)(struct mtk_eth_priv *priv, u8 phy, u8 reg);
-	int (*mii_write)(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 val);
-	int (*mmd_read)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg);
-	int (*mmd_write)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
-			 u16 val);
-
-	const struct mtk_soc_data *soc;
-	int gmac_id;
-	int force_mode;
-	int speed;
-	int duplex;
-	int mdc;
-	bool pn_swap;
-
-	struct phy_device *phydev;
-	int phy_interface;
-	int phy_addr;
-
-	enum mtk_switch sw;
-	int (*switch_init)(struct mtk_eth_priv *priv);
-	void (*switch_mac_control)(struct mtk_eth_priv *priv, bool enable);
-	u32 mt753x_smi_addr;
-	u32 mt753x_phy_base;
-	u32 mt753x_pmcr;
-	u32 mt753x_reset_wait_time;
-
-	struct gpio_desc rst_gpio;
-	int mcm;
-
-	struct reset_ctl rst_fe;
-	struct reset_ctl rst_mcm;
-};
-
-static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
-{
-	writel(val, priv->fe_base + priv->soc->pdma_base + reg);
-}
-
-static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
-			 u32 set)
-{
-	clrsetbits_le32(priv->fe_base + priv->soc->pdma_base + reg, clr, set);
-}
-
-static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg,
-			   u32 val)
-{
-	u32 gdma_base;
-
-	if (no == 2)
-		gdma_base = GDMA3_BASE;
-	else if (no == 1)
-		gdma_base = GDMA2_BASE;
-	else
-		gdma_base = GDMA1_BASE;
-
-	writel(val, priv->fe_base + gdma_base + reg);
-}
-
-static void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
-{
-	clrsetbits_le32(priv->fe_base + reg, clr, set);
-}
-
-static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg)
-{
-	return readl(priv->gmac_base + reg);
-}
-
-static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
-{
-	writel(val, priv->gmac_base + reg);
-}
-
-static void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
-{
-	clrsetbits_le32(priv->gmac_base + reg, clr, set);
-}
-
-static void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
-			   u32 set)
-{
-	uint val;
-
-	regmap_read(priv->ethsys_regmap, reg, &val);
-	val &= ~clr;
-	val |= set;
-	regmap_write(priv->ethsys_regmap, reg, val);
-}
-
-static void mtk_infra_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
-			  u32 set)
-{
-	uint val;
-
-	regmap_read(priv->infra_regmap, reg, &val);
-	val &= ~clr;
-	val |= set;
-	regmap_write(priv->infra_regmap, reg, val);
-}
-
-static u32 mtk_gsw_read(struct mtk_eth_priv *priv, u32 reg)
-{
-	return readl(priv->gsw_base + reg);
-}
-
-static void mtk_gsw_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
-{
-	writel(val, priv->gsw_base + reg);
-}
-
-/* Direct MDIO clause 22/45 access via SoC */
-static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data,
-		      u32 cmd, u32 st)
-{
-	int ret;
-	u32 val;
-
-	val = (st << MDIO_ST_S) |
-	      ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
-	      (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
-	      (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
-
-	if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
-		val |= data & MDIO_RW_DATA_M;
-
-	mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST);
-
-	ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG,
-				PHY_ACS_ST, 0, 5000, 0);
-	if (ret) {
-		pr_warn("MDIO access timeout\n");
-		return ret;
-	}
-
-	if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
-		val = mtk_gmac_read(priv, GMAC_PIAC_REG);
-		return val & MDIO_RW_DATA_M;
-	}
-
-	return 0;
-}
-
-/* Direct MDIO clause 22 read via SoC */
-static int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg)
-{
-	return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22);
-}
-
-/* Direct MDIO clause 22 write via SoC */
-static int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data)
-{
-	return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22);
-}
-
-/* Direct MDIO clause 45 read via SoC */
-static int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg)
-{
-	int ret;
-
-	ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
-	if (ret)
-		return ret;
-
-	return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45,
-			  MDIO_ST_C45);
-}
-
-/* Direct MDIO clause 45 write via SoC */
-static int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad,
-			 u16 reg, u16 val)
-{
-	int ret;
-
-	ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
-	if (ret)
-		return ret;
-
-	return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE,
-			  MDIO_ST_C45);
-}
-
-/* Indirect MDIO clause 45 read via MII registers */
-static int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad,
-			    u16 reg)
-{
-	int ret;
-
-	ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
-			      (MMD_ADDR << MMD_CMD_S) |
-			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
-	if (ret)
-		return ret;
-
-	ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
-	if (ret)
-		return ret;
-
-	ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
-			      (MMD_DATA << MMD_CMD_S) |
-			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
-	if (ret)
-		return ret;
-
-	return priv->mii_read(priv, addr, MII_MMD_ADDR_DATA_REG);
-}
-
-/* Indirect MDIO clause 45 write via MII registers */
-static int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad,
-			     u16 reg, u16 val)
-{
-	int ret;
-
-	ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
-			      (MMD_ADDR << MMD_CMD_S) |
-			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
-	if (ret)
-		return ret;
-
-	ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
-	if (ret)
-		return ret;
-
-	ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
-			      (MMD_DATA << MMD_CMD_S) |
-			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
-	if (ret)
-		return ret;
-
-	return priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val);
-}
-
-/*
- * MT7530 Internal Register Address Bits
- * -------------------------------------------------------------------
- * | 15  14  13  12  11  10   9   8   7   6 | 5   4   3   2 | 1   0  |
- * |----------------------------------------|---------------|--------|
- * |              Page Address              |  Reg Address  | Unused |
- * -------------------------------------------------------------------
- */
-
-static int mt753x_reg_read(struct mtk_eth_priv *priv, u32 reg, u32 *data)
-{
-	int ret, low_word, high_word;
-
-	if (priv->sw == SW_MT7988) {
-		*data = mtk_gsw_read(priv, reg);
-		return 0;
-	}
-
-	/* Write page address */
-	ret = mtk_mii_write(priv, priv->mt753x_smi_addr, 0x1f, reg >> 6);
-	if (ret)
-		return ret;
-
-	/* Read low word */
-	low_word = mtk_mii_read(priv, priv->mt753x_smi_addr, (reg >> 2) & 0xf);
-	if (low_word < 0)
-		return low_word;
-
-	/* Read high word */
-	high_word = mtk_mii_read(priv, priv->mt753x_smi_addr, 0x10);
-	if (high_word < 0)
-		return high_word;
-
-	if (data)
-		*data = ((u32)high_word << 16) | (low_word & 0xffff);
-
-	return 0;
-}
-
-static int mt753x_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 data)
-{
-	int ret;
-
-	if (priv->sw == SW_MT7988) {
-		mtk_gsw_write(priv, reg, data);
-		return 0;
-	}
-
-	/* Write page address */
-	ret = mtk_mii_write(priv, priv->mt753x_smi_addr, 0x1f, reg >> 6);
-	if (ret)
-		return ret;
-
-	/* Write low word */
-	ret = mtk_mii_write(priv, priv->mt753x_smi_addr, (reg >> 2) & 0xf,
-			    data & 0xffff);
-	if (ret)
-		return ret;
-
-	/* Write high word */
-	return mtk_mii_write(priv, priv->mt753x_smi_addr, 0x10, data >> 16);
-}
-
-static void mt753x_reg_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
-			   u32 set)
-{
-	u32 val;
-
-	mt753x_reg_read(priv, reg, &val);
-	val &= ~clr;
-	val |= set;
-	mt753x_reg_write(priv, reg, val);
-}
-
-/* Indirect MDIO clause 22/45 access */
-static int mt7531_mii_rw(struct mtk_eth_priv *priv, int phy, int reg, u16 data,
-			 u32 cmd, u32 st)
-{
-	ulong timeout;
-	u32 val, timeout_ms;
-	int ret = 0;
-
-	val = (st << MDIO_ST_S) |
-	      ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
-	      ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
-	      ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
-
-	if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
-		val |= data & MDIO_RW_DATA_M;
-
-	mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST);
-
-	timeout_ms = 100;
-	timeout = get_timer(0);
-	while (1) {
-		mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
-
-		if ((val & PHY_ACS_ST) == 0)
-			break;
-
-		if (get_timer(timeout) > timeout_ms)
-			return -ETIMEDOUT;
-	}
-
-	if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
-		mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
-		ret = val & MDIO_RW_DATA_M;
-	}
-
-	return ret;
-}
-
-static int mt7531_mii_ind_read(struct mtk_eth_priv *priv, u8 phy, u8 reg)
-{
-	u8 phy_addr;
-
-	if (phy >= MT753X_NUM_PHYS)
-		return -EINVAL;
-
-	phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, phy);
-
-	return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ,
-			     MDIO_ST_C22);
-}
-
-static int mt7531_mii_ind_write(struct mtk_eth_priv *priv, u8 phy, u8 reg,
-				u16 val)
-{
-	u8 phy_addr;
-
-	if (phy >= MT753X_NUM_PHYS)
-		return -EINVAL;
-
-	phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, phy);
-
-	return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE,
-			     MDIO_ST_C22);
-}
-
-static int mt7531_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad,
-			       u16 reg)
-{
-	u8 phy_addr;
-	int ret;
-
-	if (addr >= MT753X_NUM_PHYS)
-		return -EINVAL;
-
-	phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, addr);
-
-	ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
-			    MDIO_ST_C45);
-	if (ret)
-		return ret;
-
-	return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45,
-			     MDIO_ST_C45);
-}
-
-static int mt7531_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad,
-				u16 reg, u16 val)
-{
-	u8 phy_addr;
-	int ret;
-
-	if (addr >= MT753X_NUM_PHYS)
-		return 0;
-
-	phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, addr);
-
-	ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
-			    MDIO_ST_C45);
-	if (ret)
-		return ret;
-
-	return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE,
-			     MDIO_ST_C45);
-}
-
-static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
-{
-	struct mtk_eth_priv *priv = bus->priv;
-
-	if (devad < 0)
-		return priv->mii_read(priv, addr, reg);
-	else
-		return priv->mmd_read(priv, addr, devad, reg);
-}
-
-static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
-			  u16 val)
-{
-	struct mtk_eth_priv *priv = bus->priv;
-
-	if (devad < 0)
-		return priv->mii_write(priv, addr, reg, val);
-	else
-		return priv->mmd_write(priv, addr, devad, reg, val);
-}
-
-static int mtk_mdio_register(struct udevice *dev)
-{
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-	struct mii_dev *mdio_bus = mdio_alloc();
-	int ret;
-
-	if (!mdio_bus)
-		return -ENOMEM;
-
-	/* Assign MDIO access APIs according to the switch/phy */
-	switch (priv->sw) {
-	case SW_MT7530:
-		priv->mii_read = mtk_mii_read;
-		priv->mii_write = mtk_mii_write;
-		priv->mmd_read = mtk_mmd_ind_read;
-		priv->mmd_write = mtk_mmd_ind_write;
-		break;
-	case SW_MT7531:
-	case SW_MT7988:
-		priv->mii_read = mt7531_mii_ind_read;
-		priv->mii_write = mt7531_mii_ind_write;
-		priv->mmd_read = mt7531_mmd_ind_read;
-		priv->mmd_write = mt7531_mmd_ind_write;
-		break;
-	default:
-		priv->mii_read = mtk_mii_read;
-		priv->mii_write = mtk_mii_write;
-		priv->mmd_read = mtk_mmd_read;
-		priv->mmd_write = mtk_mmd_write;
-	}
-
-	mdio_bus->read = mtk_mdio_read;
-	mdio_bus->write = mtk_mdio_write;
-	snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
-
-	mdio_bus->priv = (void *)priv;
-
-	ret = mdio_register(mdio_bus);
-
-	if (ret)
-		return ret;
-
-	priv->mdio_bus = mdio_bus;
-
-	return 0;
-}
-
-static int mt753x_core_reg_read(struct mtk_eth_priv *priv, u32 reg)
-{
-	u8 phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, 0);
-
-	return priv->mmd_read(priv, phy_addr, 0x1f, reg);
-}
-
-static void mt753x_core_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
-{
-	u8 phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, 0);
-
-	priv->mmd_write(priv, phy_addr, 0x1f, reg, val);
-}
-
-static int mt7530_pad_clk_setup(struct mtk_eth_priv *priv, int mode)
-{
-	u32 ncpo1, ssc_delta;
-
-	switch (mode) {
-	case PHY_INTERFACE_MODE_RGMII:
-		ncpo1 = 0x0c80;
-		ssc_delta = 0x87;
-		break;
-	default:
-		printf("error: xMII mode %d not supported\n", mode);
-		return -EINVAL;
-	}
-
-	/* Disable MT7530 core clock */
-	mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0);
-
-	/* Disable MT7530 PLL */
-	mt753x_core_reg_write(priv, CORE_GSWPLL_GRP1,
-			      (2 << RG_GSWPLL_POSDIV_200M_S) |
-			      (32 << RG_GSWPLL_FBKDIV_200M_S));
-
-	/* For MT7530 core clock = 500Mhz */
-	mt753x_core_reg_write(priv, CORE_GSWPLL_GRP2,
-			      (1 << RG_GSWPLL_POSDIV_500M_S) |
-			      (25 << RG_GSWPLL_FBKDIV_500M_S));
-
-	/* Enable MT7530 PLL */
-	mt753x_core_reg_write(priv, CORE_GSWPLL_GRP1,
-			      (2 << RG_GSWPLL_POSDIV_200M_S) |
-			      (32 << RG_GSWPLL_FBKDIV_200M_S) |
-			      RG_GSWPLL_EN_PRE);
-
-	udelay(20);
-
-	mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
-
-	/* Setup the MT7530 TRGMII Tx Clock */
-	mt753x_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1);
-	mt753x_core_reg_write(priv, CORE_PLL_GROUP6, 0);
-	mt753x_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta);
-	mt753x_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta);
-	mt753x_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
-			      RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
-
-	mt753x_core_reg_write(priv, CORE_PLL_GROUP2,
-			      RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
-			      (1 << RG_SYSPLL_POSDIV_S));
-
-	mt753x_core_reg_write(priv, CORE_PLL_GROUP7,
-			      RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) |
-			      RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
-
-	/* Enable MT7530 core clock */
-	mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG,
-			      REG_GSWCK_EN | REG_TRGMIICK_EN);
-
-	return 0;
-}
-
-static void mt7530_mac_control(struct mtk_eth_priv *priv, bool enable)
-{
-	u32 pmcr = FORCE_MODE;
-
-	if (enable)
-		pmcr = priv->mt753x_pmcr;
-
-	mt753x_reg_write(priv, PMCR_REG(6), pmcr);
-}
-
-static int mt7530_setup(struct mtk_eth_priv *priv)
-{
-	u16 phy_addr, phy_val;
-	u32 val, txdrv;
-	int i;
-
-	if (!MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
-		/* Select 250MHz clk for RGMII mode */
-		mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG,
-			       ETHSYS_TRGMII_CLK_SEL362_5, 0);
-
-		txdrv = 8;
-	} else {
-		txdrv = 4;
-	}
-
-	/* Modify HWTRAP first to allow direct access to internal PHYs */
-	mt753x_reg_read(priv, HWTRAP_REG, &val);
-	val |= CHG_TRAP;
-	val &= ~C_MDIO_BPS;
-	mt753x_reg_write(priv, MHWTRAP_REG, val);
-
-	/* Calculate the phy base address */
-	val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3;
-	priv->mt753x_phy_base = (val | 0x7) + 1;
-
-	/* Turn off PHYs */
-	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
-		phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
-		phy_val |= BMCR_PDOWN;
-		priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
-	}
-
-	/* Force MAC link down before reset */
-	mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
-	mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
-
-	/* MT7530 reset */
-	mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
-	udelay(100);
-
-	val = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
-	      MAC_MODE | FORCE_MODE |
-	      MAC_TX_EN | MAC_RX_EN |
-	      BKOFF_EN | BACKPR_EN |
-	      (SPEED_1000M << FORCE_SPD_S) |
-	      FORCE_DPX | FORCE_LINK;
-
-	/* MT7530 Port6: Forced 1000M/FD, FC disabled */
-	priv->mt753x_pmcr = val;
-
-	/* MT7530 Port5: Forced link down */
-	mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
-
-	/* Keep MAC link down before starting eth */
-	mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
-
-	/* MT7530 Port6: Set to RGMII */
-	mt753x_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII);
-
-	/* Hardware Trap: Enable Port6, Disable Port5 */
-	mt753x_reg_read(priv, HWTRAP_REG, &val);
-	val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS |
-	       (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) |
-	       (P5_INTF_MODE_RGMII << P5_INTF_MODE_S);
-	val &= ~(C_MDIO_BPS | P6_INTF_DIS);
-	mt753x_reg_write(priv, MHWTRAP_REG, val);
-
-	/* Setup switch core pll */
-	mt7530_pad_clk_setup(priv, priv->phy_interface);
-
-	/* Lower Tx Driving for TRGMII path */
-	for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
-		mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i),
-				 (txdrv << TD_DM_DRVP_S) |
-				 (txdrv << TD_DM_DRVN_S));
-
-	for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
-		mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16);
-
-	/* Turn on PHYs */
-	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
-		phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
-		phy_val &= ~BMCR_PDOWN;
-		priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
-	}
-
-	return 0;
-}
-
-static void mt7531_core_pll_setup(struct mtk_eth_priv *priv, int mcm)
-{
-	/* Step 1 : Disable MT7531 COREPLL */
-	mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, 0);
-
-	/* Step 2: switch to XTAL output */
-	mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_CLKSW, SW_CLKSW);
-
-	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, 0);
-
-	/* Step 3: disable PLLGP and enable program PLLGP */
-	mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_PLLGP, SW_PLLGP);
-
-	/* Step 4: program COREPLL output frequency to 500MHz */
-	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_POSDIV_M,
-		       2 << RG_COREPLL_POSDIV_S);
-	udelay(25);
-
-	/* Currently, support XTAL 25Mhz only */
-	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_M,
-		       0x140000 << RG_COREPLL_SDM_PCW_S);
-
-	/* Set feedback divide ratio update signal to high */
-	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG,
-		       RG_COREPLL_SDM_PCW_CHG);
-
-	/* Wait for at least 16 XTAL clocks */
-	udelay(10);
-
-	/* Step 5: set feedback divide ratio update signal to low */
-	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, 0);
-
-	/* add enable 325M clock for SGMII */
-	mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
-
-	/* add enable 250SSC clock for RGMII */
-	mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
-
-	/*Step 6: Enable MT7531 PLL */
-	mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, RG_COREPLL_EN);
-
-	mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, EN_COREPLL);
-
-	udelay(25);
-}
-
-static int mt7531_port_sgmii_init(struct mtk_eth_priv *priv,
-				  u32 port)
-{
-	if (port != 5 && port != 6) {
-		printf("mt7531: port %d is not a SGMII port\n", port);
-		return -EINVAL;
-	}
-
-	/* Set SGMII GEN2 speed(2.5G) */
-	mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK,
-		       FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
-
-	/* Disable SGMII AN */
-	mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port),
-		       SGMII_AN_ENABLE, 0);
-
-	/* SGMII force mode setting */
-	mt753x_reg_write(priv, MT7531_SGMII_MODE(port), SGMII_FORCE_MODE);
-
-	/* Release PHYA power down state */
-	mt753x_reg_rmw(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
-		       SGMII_PHYA_PWD, 0);
-
-	return 0;
-}
-
-static int mt7531_port_rgmii_init(struct mtk_eth_priv *priv, u32 port)
-{
-	u32 val;
-
-	if (port != 5) {
-		printf("error: RGMII mode is not available for port %d\n",
-		       port);
-		return -EINVAL;
-	}
-
-	mt753x_reg_read(priv, MT7531_CLKGEN_CTRL, &val);
-	val |= GP_CLK_EN;
-	val &= ~GP_MODE_M;
-	val |= GP_MODE_RGMII << GP_MODE_S;
-	val |= TXCLK_NO_REVERSE;
-	val |= RXCLK_NO_DELAY;
-	val &= ~CLK_SKEW_IN_M;
-	val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S;
-	val &= ~CLK_SKEW_OUT_M;
-	val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S;
-	mt753x_reg_write(priv, MT7531_CLKGEN_CTRL, val);
-
-	return 0;
-}
-
-static void mt7531_phy_setting(struct mtk_eth_priv *priv)
-{
-	int i;
-	u32 val;
-
-	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		/* Enable HW auto downshift */
-		priv->mii_write(priv, i, 0x1f, 0x1);
-		val = priv->mii_read(priv, i, PHY_EXT_REG_14);
-		val |= PHY_EN_DOWN_SHFIT;
-		priv->mii_write(priv, i, PHY_EXT_REG_14, val);
-
-		/* PHY link down power saving enable */
-		val = priv->mii_read(priv, i, PHY_EXT_REG_17);
-		val |= PHY_LINKDOWN_POWER_SAVING_EN;
-		priv->mii_write(priv, i, PHY_EXT_REG_17, val);
-
-		val = priv->mmd_read(priv, i, 0x1e, PHY_DEV1E_REG_0C6);
-		val &= ~PHY_POWER_SAVING_M;
-		val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
-		priv->mmd_write(priv, i, 0x1e, PHY_DEV1E_REG_0C6, val);
-	}
-}
-
-static void mt7531_mac_control(struct mtk_eth_priv *priv, bool enable)
-{
-	u32 pmcr = FORCE_MODE_LNK;
-
-	if (enable)
-		pmcr = priv->mt753x_pmcr;
-
-	mt753x_reg_write(priv, PMCR_REG(5), pmcr);
-	mt753x_reg_write(priv, PMCR_REG(6), pmcr);
-}
-
-static int mt7531_setup(struct mtk_eth_priv *priv)
-{
-	u16 phy_addr, phy_val;
-	u32 val;
-	u32 pmcr;
-	u32 port5_sgmii;
-	int i;
-
-	priv->mt753x_phy_base = (priv->mt753x_smi_addr + 1) &
-				MT753X_SMI_ADDR_MASK;
-
-	/* Turn off PHYs */
-	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
-		phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
-		phy_val |= BMCR_PDOWN;
-		priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
-	}
-
-	/* Force MAC link down before reset */
-	mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
-	mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
-
-	/* Switch soft reset */
-	mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
-	udelay(100);
-
-	/* Enable MDC input Schmitt Trigger */
-	mt753x_reg_rmw(priv, MT7531_SMT0_IOLB, SMT_IOLB_5_SMI_MDC_EN,
-		       SMT_IOLB_5_SMI_MDC_EN);
-
-	mt7531_core_pll_setup(priv, priv->mcm);
-
-	mt753x_reg_read(priv, MT7531_TOP_SIG_SR, &val);
-	port5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
-
-	/* port5 support either RGMII or SGMII, port6 only support SGMII. */
-	switch (priv->phy_interface) {
-	case PHY_INTERFACE_MODE_RGMII:
-		if (!port5_sgmii)
-			mt7531_port_rgmii_init(priv, 5);
-		break;
-	case PHY_INTERFACE_MODE_2500BASEX:
-		mt7531_port_sgmii_init(priv, 6);
-		if (port5_sgmii)
-			mt7531_port_sgmii_init(priv, 5);
-		break;
-	default:
-		break;
-	}
-
-	pmcr = MT7531_FORCE_MODE |
-	       (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
-	       MAC_MODE | MAC_TX_EN | MAC_RX_EN |
-	       BKOFF_EN | BACKPR_EN |
-	       FORCE_RX_FC | FORCE_TX_FC |
-	       (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
-	       FORCE_LINK;
-
-	priv->mt753x_pmcr = pmcr;
-
-	/* Keep MAC link down before starting eth */
-	mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
-	mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
-
-	/* Turn on PHYs */
-	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
-		phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
-		phy_val &= ~BMCR_PDOWN;
-		priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
-	}
-
-	mt7531_phy_setting(priv);
-
-	/* Enable Internal PHYs */
-	val = mt753x_core_reg_read(priv, CORE_PLL_GROUP4);
-	val |= MT7531_BYPASS_MODE;
-	val &= ~MT7531_POWER_ON_OFF;
-	mt753x_core_reg_write(priv, CORE_PLL_GROUP4, val);
-
-	return 0;
-}
-
-static void mt7988_phy_setting(struct mtk_eth_priv *priv)
-{
-	u16 val;
-	u32 i;
-
-	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		/* Enable HW auto downshift */
-		priv->mii_write(priv, i, 0x1f, 0x1);
-		val = priv->mii_read(priv, i, PHY_EXT_REG_14);
-		val |= PHY_EN_DOWN_SHFIT;
-		priv->mii_write(priv, i, PHY_EXT_REG_14, val);
-
-		/* PHY link down power saving enable */
-		val = priv->mii_read(priv, i, PHY_EXT_REG_17);
-		val |= PHY_LINKDOWN_POWER_SAVING_EN;
-		priv->mii_write(priv, i, PHY_EXT_REG_17, val);
-	}
-}
-
-static void mt7988_mac_control(struct mtk_eth_priv *priv, bool enable)
-{
-	u32 pmcr = FORCE_MODE_LNK;
-
-	if (enable)
-		pmcr = priv->mt753x_pmcr;
-
-	mt753x_reg_write(priv, PMCR_REG(6), pmcr);
-}
-
-static int mt7988_setup(struct mtk_eth_priv *priv)
-{
-	u16 phy_addr, phy_val;
-	u32 pmcr;
-	int i;
-
-	priv->gsw_base = regmap_get_range(priv->ethsys_regmap, 0) + GSW_BASE;
-
-	priv->mt753x_phy_base = (priv->mt753x_smi_addr + 1) &
-				MT753X_SMI_ADDR_MASK;
-
-	/* Turn off PHYs */
-	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
-		phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
-		phy_val |= BMCR_PDOWN;
-		priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
-	}
-
-	switch (priv->phy_interface) {
-	case PHY_INTERFACE_MODE_USXGMII:
-		/* Use CPU bridge instead of actual USXGMII path */
-
-		/* Set GDM1 no drop */
-		mtk_fe_rmw(priv, PSE_NO_DROP_CFG_REG, 0, PSE_NO_DROP_GDM1);
-
-		/* Enable GDM1 to GSW CPU bridge */
-		mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, BIT(0));
-
-		/* XGMAC force link up */
-		mtk_gmac_rmw(priv, GMAC_XGMAC_STS_REG, 0, P1_XGMAC_FORCE_LINK);
-
-		/* Setup GSW CPU bridge IPG */
-		mtk_gmac_rmw(priv, GMAC_GSW_CFG_REG, GSWTX_IPG_M | GSWRX_IPG_M,
-			     (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S));
-		break;
-	default:
-		printf("Error: MT7988 GSW does not support %s interface\n",
-		       phy_string_for_interface(priv->phy_interface));
-		break;
-	}
-
-	pmcr = MT7988_FORCE_MODE |
-	       (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
-	       MAC_MODE | MAC_TX_EN | MAC_RX_EN |
-	       BKOFF_EN | BACKPR_EN |
-	       FORCE_RX_FC | FORCE_TX_FC |
-	       (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
-	       FORCE_LINK;
-
-	priv->mt753x_pmcr = pmcr;
-
-	/* Keep MAC link down before starting eth */
-	mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
-
-	/* Turn on PHYs */
-	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
-		phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
-		phy_val &= ~BMCR_PDOWN;
-		priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
-	}
-
-	mt7988_phy_setting(priv);
-
-	return 0;
-}
-
-static int mt753x_switch_init(struct mtk_eth_priv *priv)
-{
-	int ret;
-	int i;
-
-	/* Global reset switch */
-	if (priv->mcm) {
-		reset_assert(&priv->rst_mcm);
-		udelay(1000);
-		reset_deassert(&priv->rst_mcm);
-		mdelay(priv->mt753x_reset_wait_time);
-	} else if (dm_gpio_is_valid(&priv->rst_gpio)) {
-		dm_gpio_set_value(&priv->rst_gpio, 0);
-		udelay(1000);
-		dm_gpio_set_value(&priv->rst_gpio, 1);
-		mdelay(priv->mt753x_reset_wait_time);
-	}
-
-	ret = priv->switch_init(priv);
-	if (ret)
-		return ret;
-
-	/* Set port isolation */
-	for (i = 0; i < MT753X_NUM_PORTS; i++) {
-		/* Set port matrix mode */
-		if (i != 6)
-			mt753x_reg_write(priv, PCR_REG(i),
-					 (0x40 << PORT_MATRIX_S));
-		else
-			mt753x_reg_write(priv, PCR_REG(i),
-					 (0x3f << PORT_MATRIX_S));
-
-		/* Set port mode to user port */
-		mt753x_reg_write(priv, PVC_REG(i),
-				 (0x8100 << STAG_VPID_S) |
-				 (VLAN_ATTR_USER << VLAN_ATTR_S));
-	}
-
-	return 0;
-}
-
-static void mtk_xphy_link_adjust(struct mtk_eth_priv *priv)
-{
-	u16 lcl_adv = 0, rmt_adv = 0;
-	u8 flowctrl;
-	u32 mcr;
-
-	mcr = mtk_gmac_read(priv, XGMAC_PORT_MCR(priv->gmac_id));
-	mcr &= ~(XGMAC_FORCE_TX_FC | XGMAC_FORCE_RX_FC);
-
-	if (priv->phydev->duplex) {
-		if (priv->phydev->pause)
-			rmt_adv = LPA_PAUSE_CAP;
-		if (priv->phydev->asym_pause)
-			rmt_adv |= LPA_PAUSE_ASYM;
-
-		if (priv->phydev->advertising & ADVERTISED_Pause)
-			lcl_adv |= ADVERTISE_PAUSE_CAP;
-		if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
-			lcl_adv |= ADVERTISE_PAUSE_ASYM;
-
-		flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
-
-		if (flowctrl & FLOW_CTRL_TX)
-			mcr |= XGMAC_FORCE_TX_FC;
-		if (flowctrl & FLOW_CTRL_RX)
-			mcr |= XGMAC_FORCE_RX_FC;
-
-		debug("rx pause %s, tx pause %s\n",
-		      flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
-		      flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
-	}
-
-	mcr &= ~(XGMAC_TRX_DISABLE);
-	mtk_gmac_write(priv, XGMAC_PORT_MCR(priv->gmac_id), mcr);
-}
-
-static void mtk_phy_link_adjust(struct mtk_eth_priv *priv)
-{
-	u16 lcl_adv = 0, rmt_adv = 0;
-	u8 flowctrl;
-	u32 mcr;
-
-	mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
-	      (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
-	      MAC_MODE | FORCE_MODE |
-	      MAC_TX_EN | MAC_RX_EN |
-	      DEL_RXFIFO_CLR |
-	      BKOFF_EN | BACKPR_EN;
-
-	switch (priv->phydev->speed) {
-	case SPEED_10:
-		mcr |= (SPEED_10M << FORCE_SPD_S);
-		break;
-	case SPEED_100:
-		mcr |= (SPEED_100M << FORCE_SPD_S);
-		break;
-	case SPEED_1000:
-	case SPEED_2500:
-		mcr |= (SPEED_1000M << FORCE_SPD_S);
-		break;
-	};
-
-	if (priv->phydev->link)
-		mcr |= FORCE_LINK;
-
-	if (priv->phydev->duplex) {
-		mcr |= FORCE_DPX;
-
-		if (priv->phydev->pause)
-			rmt_adv = LPA_PAUSE_CAP;
-		if (priv->phydev->asym_pause)
-			rmt_adv |= LPA_PAUSE_ASYM;
-
-		if (priv->phydev->advertising & ADVERTISED_Pause)
-			lcl_adv |= ADVERTISE_PAUSE_CAP;
-		if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
-			lcl_adv |= ADVERTISE_PAUSE_ASYM;
-
-		flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
-
-		if (flowctrl & FLOW_CTRL_TX)
-			mcr |= FORCE_TX_FC;
-		if (flowctrl & FLOW_CTRL_RX)
-			mcr |= FORCE_RX_FC;
-
-		debug("rx pause %s, tx pause %s\n",
-		      flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
-		      flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
-	}
-
-	mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
-}
-
-static int mtk_phy_start(struct mtk_eth_priv *priv)
-{
-	struct phy_device *phydev = priv->phydev;
-	int ret;
-
-	ret = phy_startup(phydev);
-
-	if (ret) {
-		debug("Could not initialize PHY %s\n", phydev->dev->name);
-		return ret;
-	}
-
-	if (!phydev->link) {
-		debug("%s: link down.\n", phydev->dev->name);
-		return 0;
-	}
-
-	if (!priv->force_mode) {
-		if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
-		    priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
-		    priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
-			mtk_xphy_link_adjust(priv);
-		else
-			mtk_phy_link_adjust(priv);
-	}
-
-	debug("Speed: %d, %s duplex%s\n", phydev->speed,
-	      (phydev->duplex) ? "full" : "half",
-	      (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
-
-	return 0;
-}
-
-static int mtk_phy_probe(struct udevice *dev)
-{
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-	struct phy_device *phydev;
-
-	phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev,
-			     priv->phy_interface);
-	if (!phydev)
-		return -ENODEV;
-
-	phydev->supported &= PHY_GBIT_FEATURES;
-	phydev->advertising = phydev->supported;
-
-	priv->phydev = phydev;
-	phy_config(phydev);
-
-	return 0;
-}
-
-static void mtk_sgmii_an_init(struct mtk_eth_priv *priv)
-{
-	/* Set SGMII GEN1 speed(1G) */
-	clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK);
-
-	/* Enable SGMII AN */
-	setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
-		     SGMII_AN_ENABLE);
-
-	/* SGMII AN mode setting */
-	writel(SGMII_AN_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
-
-	/* SGMII PN SWAP setting */
-	if (priv->pn_swap) {
-		setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
-			     SGMII_PN_SWAP_TX_RX);
-	}
-
-	/* Release PHYA power down state */
-	clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
-			SGMII_PHYA_PWD, 0);
-}
-
-static void mtk_sgmii_force_init(struct mtk_eth_priv *priv)
-{
-	/* Set SGMII GEN2 speed(2.5G) */
-	clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
-			SGMSYS_SPEED_MASK,
-			FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
-
-	/* Disable SGMII AN */
-	clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
-			SGMII_AN_ENABLE, 0);
-
-	/* SGMII force mode setting */
-	writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
-
-	/* SGMII PN SWAP setting */
-	if (priv->pn_swap) {
-		setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
-			     SGMII_PN_SWAP_TX_RX);
-	}
-
-	/* Release PHYA power down state */
-	clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
-			SGMII_PHYA_PWD, 0);
-}
-
-static void mtk_xfi_pll_enable(struct mtk_eth_priv *priv)
-{
-	u32 val = 0;
-
-	/* Add software workaround for USXGMII PLL TCL issue */
-	regmap_write(priv->xfi_pll_regmap, XFI_PLL_ANA_GLB8,
-		     RG_XFI_PLL_ANA_SWWA);
-
-	regmap_read(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, &val);
-	val |= RG_XFI_PLL_EN;
-	regmap_write(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, val);
-}
-
-static void mtk_usxgmii_reset(struct mtk_eth_priv *priv)
-{
-	switch (priv->gmac_id) {
-	case 1:
-		regmap_write(priv->toprgu_regmap, 0xFC, 0x0000A004);
-		regmap_write(priv->toprgu_regmap, 0x18, 0x88F0A004);
-		regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
-		regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
-		regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
-		break;
-	case 2:
-		regmap_write(priv->toprgu_regmap, 0xFC, 0x00005002);
-		regmap_write(priv->toprgu_regmap, 0x18, 0x88F05002);
-		regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
-		regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
-		regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
-		break;
-	}
-
-	mdelay(10);
-}
-
-static void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth_priv *priv)
-{
-	regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6D);
-	regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
-	regmap_write(priv->usxgmii_regmap, 0x80C, 0x30000000);
-	ndelay(1020);
-	regmap_write(priv->usxgmii_regmap, 0x80C, 0x10000000);
-	ndelay(1020);
-	regmap_write(priv->usxgmii_regmap, 0x80C, 0x00000000);
-
-	regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
-	regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
-	regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
-	regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
-	regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
-	regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
-	regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
-	regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
-	regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
-	regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
-	regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
-	regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
-	regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
-	regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
-	regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
-	regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
-	regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
-	regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
-	regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
-	regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
-	regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
-	regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
-	regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
-	ndelay(1020);
-	regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
-	regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
-	regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
-	regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
-	regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
-	regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
-	regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
-	regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x40704000);
-	regmap_write(priv->xfi_pextp_regmap, 0x3050, 0xA8000000);
-	regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x000000AA);
-	regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
-	regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
-	regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
-	udelay(150);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
-	ndelay(1020);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
-	udelay(15);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
-	ndelay(1020);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
-	udelay(100);
-	regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
-	regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
-	regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
-	udelay(400);
-}
-
-static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv)
-{
-	regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C);
-	regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
-	regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000);
-	ndelay(1020);
-	regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000);
-	ndelay(1020);
-
-	regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
-	regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
-	regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
-	regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
-	regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
-	regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
-	regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
-	regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
-	regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
-	regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
-	regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
-	regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
-	regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
-	regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
-	regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
-	regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
-	regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
-	regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
-	regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
-	regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
-	regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
-	regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
-	regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
-	ndelay(1020);
-	regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
-	regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
-	regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
-	regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
-	regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
-	regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
-	regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
-	regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100);
-	regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000);
-	regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000);
-	regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
-	if (priv->gmac_id == 2)
-		regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400);
-	regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
-	regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
-	udelay(150);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
-	ndelay(1020);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
-	udelay(15);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
-	ndelay(1020);
-	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
-	udelay(100);
-	regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
-	regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
-	regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
-	udelay(400);
-}
-
-static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv)
-{
-	mtk_xfi_pll_enable(priv);
-	mtk_usxgmii_reset(priv);
-	mtk_usxgmii_setup_phya_an_10000(priv);
-}
-
-static void mtk_10gbaser_init(struct mtk_eth_priv *priv)
-{
-	mtk_xfi_pll_enable(priv);
-	mtk_usxgmii_reset(priv);
-	mtk_usxgmii_setup_phya_force_10000(priv);
-}
-
-static int mtk_mac_init(struct mtk_eth_priv *priv)
-{
-	int i, sgmii_sel_mask = 0, ge_mode = 0;
-	u32 mcr;
-
-	if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) {
-		mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG,
-			      INFRA_MISC2_BONDING_OPTION, priv->gmac_id);
-	}
-
-	switch (priv->phy_interface) {
-	case PHY_INTERFACE_MODE_RGMII_RXID:
-	case PHY_INTERFACE_MODE_RGMII:
-		ge_mode = GE_MODE_RGMII;
-		break;
-	case PHY_INTERFACE_MODE_SGMII:
-	case PHY_INTERFACE_MODE_2500BASEX:
-		if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
-			printf("Error: SGMII is not supported on this platform\n");
-			return -ENOTSUPP;
-		}
-
-		if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) {
-			mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK,
-				      SGMII_QPHY_SEL);
-		}
-
-		if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII))
-			sgmii_sel_mask = SYSCFG1_SGMII_SEL_M;
-
-		mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask,
-			       SYSCFG1_SGMII_SEL(priv->gmac_id));
-
-		if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
-			mtk_sgmii_an_init(priv);
-		else
-			mtk_sgmii_force_init(priv);
-
-		ge_mode = GE_MODE_RGMII;
-		break;
-	case PHY_INTERFACE_MODE_MII:
-	case PHY_INTERFACE_MODE_GMII:
-		ge_mode = GE_MODE_MII;
-		break;
-	case PHY_INTERFACE_MODE_RMII:
-		ge_mode = GE_MODE_RMII;
-		break;
-	default:
-		break;
-	}
-
-	/* set the gmac to the right mode */
-	mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
-		       SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
-		       ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id));
-
-	if (priv->force_mode) {
-		mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
-		      (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
-		      MAC_MODE | FORCE_MODE |
-		      MAC_TX_EN | MAC_RX_EN |
-		      BKOFF_EN | BACKPR_EN |
-		      FORCE_LINK;
-
-		switch (priv->speed) {
-		case SPEED_10:
-			mcr |= SPEED_10M << FORCE_SPD_S;
-			break;
-		case SPEED_100:
-			mcr |= SPEED_100M << FORCE_SPD_S;
-			break;
-		case SPEED_1000:
-		case SPEED_2500:
-			mcr |= SPEED_1000M << FORCE_SPD_S;
-			break;
-		}
-
-		if (priv->duplex)
-			mcr |= FORCE_DPX;
-
-		mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
-	}
-
-	if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC1_TRGMII) &&
-	    !MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
-		/* Lower Tx Driving for TRGMII path */
-		for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
-			mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i),
-				       (8 << TD_DM_DRVP_S) |
-				       (8 << TD_DM_DRVN_S));
-
-		mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0,
-			     RX_RST | RXC_DQSISEL);
-		mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0);
-	}
-
-	return 0;
-}
-
-static int mtk_xmac_init(struct mtk_eth_priv *priv)
-{
-	u32 force_link = 0;
-
-	if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
-		printf("Error: 10Gb interface is not supported on this platform\n");
-		return -ENOTSUPP;
-	}
-
-	switch (priv->phy_interface) {
-	case PHY_INTERFACE_MODE_USXGMII:
-		mtk_usxgmii_an_init(priv);
-		break;
-	case PHY_INTERFACE_MODE_10GBASER:
-		mtk_10gbaser_init(priv);
-		break;
-	default:
-		break;
-	}
-
-	/* Set GMAC to the correct mode */
-	mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
-		       SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
-		       0);
-
-	if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
-	     priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
-	    priv->gmac_id == 1) {
-		mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX,
-			      NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL);
-	}
-
-	if (priv->phy_interface == PHY_INTERFACE_MODE_XGMII ||
-	    priv->gmac_id == 2)
-		force_link = XGMAC_FORCE_LINK(priv->gmac_id);
-
-	mtk_gmac_rmw(priv, XGMAC_STS(priv->gmac_id),
-		     XGMAC_FORCE_LINK(priv->gmac_id), force_link);
-
-	/* Force GMAC link down */
-	mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE);
-
-	return 0;
-}
-
-static void mtk_eth_fifo_init(struct mtk_eth_priv *priv)
-{
-	char *pkt_base = priv->pkt_pool;
-	struct mtk_tx_dma_v2 *txd;
-	struct mtk_rx_dma_v2 *rxd;
-	int i;
-
-	mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0);
-	udelay(500);
-
-	memset(priv->tx_ring_noc, 0, NUM_TX_DESC * priv->soc->txd_size);
-	memset(priv->rx_ring_noc, 0, NUM_RX_DESC * priv->soc->rxd_size);
-	memset(priv->pkt_pool, 0xff, TOTAL_PKT_BUF_SIZE);
-
-	flush_dcache_range((ulong)pkt_base,
-			   (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE));
-
-	priv->rx_dma_owner_idx0 = 0;
-	priv->tx_cpu_owner_idx0 = 0;
-
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		txd = priv->tx_ring_noc + i * priv->soc->txd_size;
-
-		txd->txd1 = virt_to_phys(pkt_base);
-		txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0;
-
-		if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
-			txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id == 2 ?
-							   15 : priv->gmac_id + 1);
-		else if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
-			txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id + 1);
-		else
-			txd->txd4 = PDMA_V1_TXD4_FPORT_SET(priv->gmac_id + 1);
-
-		pkt_base += PKTSIZE_ALIGN;
-	}
-
-	for (i = 0; i < NUM_RX_DESC; i++) {
-		rxd = priv->rx_ring_noc + i * priv->soc->rxd_size;
-
-		rxd->rxd1 = virt_to_phys(pkt_base);
-
-		if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
-		    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
-			rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
-		else
-			rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
-
-		pkt_base += PKTSIZE_ALIGN;
-	}
-
-	mtk_pdma_write(priv, TX_BASE_PTR_REG(0),
-		       virt_to_phys(priv->tx_ring_noc));
-	mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC);
-	mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
-
-	mtk_pdma_write(priv, RX_BASE_PTR_REG(0),
-		       virt_to_phys(priv->rx_ring_noc));
-	mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC);
-	mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1);
-
-	mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0);
-}
-
-static void mtk_eth_mdc_init(struct mtk_eth_priv *priv)
-{
-	u32 divider;
-
-	if (priv->mdc == 0)
-		return;
-
-	divider = min_t(u32, DIV_ROUND_UP(MDC_MAX_FREQ, priv->mdc), MDC_MAX_DIVIDER);
-
-	/* Configure MDC turbo mode */
-	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
-		mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, MISC_MDC_TURBO);
-	else
-		mtk_gmac_rmw(priv, GMAC_PPSC_REG, 0, MISC_MDC_TURBO);
-
-	/* Configure MDC divider */
-	mtk_gmac_rmw(priv, GMAC_PPSC_REG, PHY_MDC_CFG,
-		     FIELD_PREP(PHY_MDC_CFG, divider));
-}
-
-static int mtk_eth_start(struct udevice *dev)
-{
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-	int i, ret;
-
-	/* Reset FE */
-	reset_assert(&priv->rst_fe);
-	udelay(1000);
-	reset_deassert(&priv->rst_fe);
-	mdelay(10);
-
-	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
-	    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
-		setbits_le32(priv->fe_base + FE_GLO_MISC_REG, PDMA_VER_V2);
-
-	/* Packets forward to PDMA */
-	mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU);
-
-	for (i = 0; i < priv->soc->gdma_count; i++) {
-		if (i == priv->gmac_id)
-			continue;
-
-		mtk_gdma_write(priv, i, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD);
-	}
-
-	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) {
-		if (priv->sw == SW_MT7988 && priv->gmac_id == 0) {
-			mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG,
-				       GDMA_BRIDGE_TO_CPU);
-
-			mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
-				       GDMA_CPU_BRIDGE_EN);
-		} else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
-			    priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
-			    priv->phy_interface == PHY_INTERFACE_MODE_XGMII) &&
-			   priv->gmac_id != 0) {
-			mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
-				       GDMA_CPU_BRIDGE_EN);
-		}
-	}
-
-	udelay(500);
-
-	mtk_eth_fifo_init(priv);
-
-	if (priv->switch_mac_control)
-		priv->switch_mac_control(priv, true);
-
-	/* Start PHY */
-	if (priv->sw == SW_NONE) {
-		ret = mtk_phy_start(priv);
-		if (ret)
-			return ret;
-	}
-
-	mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0,
-		     TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN);
-	udelay(500);
-
-	return 0;
-}
-
-static void mtk_eth_stop(struct udevice *dev)
-{
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-
-	if (priv->switch_mac_control)
-		priv->switch_mac_control(priv, false);
-
-	mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG,
-		     TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0);
-	udelay(500);
-
-	wait_for_bit_le32(priv->fe_base + priv->soc->pdma_base + PDMA_GLO_CFG_REG,
-			  RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0);
-}
-
-static int mtk_eth_write_hwaddr(struct udevice *dev)
-{
-	struct eth_pdata *pdata = dev_get_plat(dev);
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-	unsigned char *mac = pdata->enetaddr;
-	u32 macaddr_lsb, macaddr_msb;
-
-	macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1];
-	macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) |
-		      ((u32)mac[4] << 8) | (u32)mac[5];
-
-	mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb);
-	mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb);
-
-	return 0;
-}
-
-static int mtk_eth_send(struct udevice *dev, void *packet, int length)
-{
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-	u32 idx = priv->tx_cpu_owner_idx0;
-	struct mtk_tx_dma_v2 *txd;
-	void *pkt_base;
-
-	txd = priv->tx_ring_noc + idx * priv->soc->txd_size;
-
-	if (!(txd->txd2 & PDMA_TXD2_DDONE)) {
-		debug("mtk-eth: TX DMA descriptor ring is full\n");
-		return -EPERM;
-	}
-
-	pkt_base = (void *)phys_to_virt(txd->txd1);
-	memcpy(pkt_base, packet, length);
-	flush_dcache_range((ulong)pkt_base, (ulong)pkt_base +
-			   roundup(length, ARCH_DMA_MINALIGN));
-
-	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
-	    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
-		txd->txd2 = PDMA_TXD2_LS0 | PDMA_V2_TXD2_SDL0_SET(length);
-	else
-		txd->txd2 = PDMA_TXD2_LS0 | PDMA_V1_TXD2_SDL0_SET(length);
-
-	priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC;
-	mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
-
-	return 0;
-}
-
-static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp)
-{
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-	u32 idx = priv->rx_dma_owner_idx0;
-	struct mtk_rx_dma_v2 *rxd;
-	uchar *pkt_base;
-	u32 length;
-
-	rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
-
-	if (!(rxd->rxd2 & PDMA_RXD2_DDONE)) {
-		debug("mtk-eth: RX DMA descriptor ring is empty\n");
-		return -EAGAIN;
-	}
-
-	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
-	    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
-		length = PDMA_V2_RXD2_PLEN0_GET(rxd->rxd2);
-	else
-		length = PDMA_V1_RXD2_PLEN0_GET(rxd->rxd2);
-
-	pkt_base = (void *)phys_to_virt(rxd->rxd1);
-	invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base +
-				roundup(length, ARCH_DMA_MINALIGN));
-
-	if (packetp)
-		*packetp = pkt_base;
-
-	return length;
-}
-
-static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
-{
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-	u32 idx = priv->rx_dma_owner_idx0;
-	struct mtk_rx_dma_v2 *rxd;
-
-	rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
-
-	invalidate_dcache_range((ulong)rxd->rxd1,
-				(ulong)rxd->rxd1 + PKTSIZE_ALIGN);
-
-	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
-	    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
-		rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
-	else
-		rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
-
-	mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx);
-	priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC;
-
-	return 0;
-}
-
-static int mtk_eth_probe(struct udevice *dev)
-{
-	struct eth_pdata *pdata = dev_get_plat(dev);
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-	ulong iobase = pdata->iobase;
-	int ret;
-
-	/* Frame Engine Register Base */
-	priv->fe_base = (void *)iobase;
-
-	/* GMAC Register Base */
-	priv->gmac_base = (void *)(iobase + GMAC_BASE);
-
-	/* MDIO register */
-	ret = mtk_mdio_register(dev);
-	if (ret)
-		return ret;
-
-	/* Prepare for tx/rx rings */
-	priv->tx_ring_noc = (void *)
-		noncached_alloc(priv->soc->txd_size * NUM_TX_DESC,
-				ARCH_DMA_MINALIGN);
-	priv->rx_ring_noc = (void *)
-		noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC,
-				ARCH_DMA_MINALIGN);
-
-	/* Set MDC divider */
-	mtk_eth_mdc_init(priv);
-
-	/* Set MAC mode */
-	if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
-	    priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
-	    priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
-		ret = mtk_xmac_init(priv);
-	else
-		ret = mtk_mac_init(priv);
-
-	if (ret)
-		return ret;
-
-	/* Probe phy if switch is not specified */
-	if (priv->sw == SW_NONE)
-		return mtk_phy_probe(dev);
-
-	/* Initialize switch */
-	return mt753x_switch_init(priv);
-}
-
-static int mtk_eth_remove(struct udevice *dev)
-{
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-
-	/* MDIO unregister */
-	mdio_unregister(priv->mdio_bus);
-	mdio_free(priv->mdio_bus);
-
-	/* Stop possibly started DMA */
-	mtk_eth_stop(dev);
-
-	return 0;
-}
-
-static int mtk_eth_of_to_plat(struct udevice *dev)
-{
-	struct eth_pdata *pdata = dev_get_plat(dev);
-	struct mtk_eth_priv *priv = dev_get_priv(dev);
-	struct ofnode_phandle_args args;
-	struct regmap *regmap;
-	const char *str;
-	ofnode subnode;
-	int ret;
-
-	priv->soc = (const struct mtk_soc_data *)dev_get_driver_data(dev);
-	if (!priv->soc) {
-		dev_err(dev, "missing soc compatible data\n");
-		return -EINVAL;
-	}
-
-	pdata->iobase = (phys_addr_t)dev_remap_addr(dev);
-
-	/* get corresponding ethsys phandle */
-	ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0,
-					 &args);
-	if (ret)
-		return ret;
-
-	priv->ethsys_regmap = syscon_node_to_regmap(args.node);
-	if (IS_ERR(priv->ethsys_regmap))
-		return PTR_ERR(priv->ethsys_regmap);
-
-	if (MTK_HAS_CAPS(priv->soc->caps, MTK_INFRA)) {
-		/* get corresponding infracfg phandle */
-		ret = dev_read_phandle_with_args(dev, "mediatek,infracfg",
-						 NULL, 0, 0, &args);
-
-		if (ret)
-			return ret;
-
-		priv->infra_regmap = syscon_node_to_regmap(args.node);
-		if (IS_ERR(priv->infra_regmap))
-			return PTR_ERR(priv->infra_regmap);
-	}
-
-	/* Reset controllers */
-	ret = reset_get_by_name(dev, "fe", &priv->rst_fe);
-	if (ret) {
-		printf("error: Unable to get reset ctrl for frame engine\n");
-		return ret;
-	}
-
-	priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0);
-
-	priv->mdc = 0;
-	subnode = ofnode_find_subnode(dev_ofnode(dev), "mdio");
-	if (ofnode_valid(subnode)) {
-		priv->mdc = ofnode_read_u32_default(subnode, "clock-frequency", 2500000);
-		if (priv->mdc > MDC_MAX_FREQ ||
-		    priv->mdc < MDC_MAX_FREQ / MDC_MAX_DIVIDER) {
-			printf("error: MDIO clock frequency out of range\n");
-			return -EINVAL;
-		}
-	}
-
-	/* Interface mode is required */
-	pdata->phy_interface = dev_read_phy_mode(dev);
-	priv->phy_interface = pdata->phy_interface;
-	if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
-		printf("error: phy-mode is not set\n");
-		return -EINVAL;
-	}
-
-	/* Force mode or autoneg */
-	subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link");
-	if (ofnode_valid(subnode)) {
-		priv->force_mode = 1;
-		priv->speed = ofnode_read_u32_default(subnode, "speed", 0);
-		priv->duplex = ofnode_read_bool(subnode, "full-duplex");
-
-		if (priv->speed != SPEED_10 && priv->speed != SPEED_100 &&
-		    priv->speed != SPEED_1000 && priv->speed != SPEED_2500 &&
-		    priv->speed != SPEED_10000) {
-			printf("error: no valid speed set in fixed-link\n");
-			return -EINVAL;
-		}
-	}
-
-	if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII ||
-	     priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) &&
-	    IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
-		/* get corresponding sgmii phandle */
-		ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys",
-						 NULL, 0, 0, &args);
-		if (ret)
-			return ret;
-
-		regmap = syscon_node_to_regmap(args.node);
-
-		if (IS_ERR(regmap))
-			return PTR_ERR(regmap);
-
-		priv->sgmii_base = regmap_get_range(regmap, 0);
-
-		if (!priv->sgmii_base) {
-			dev_err(dev, "Unable to find sgmii\n");
-			return -ENODEV;
-		}
-
-		/* Upstream linux use mediatek,pnswap instead of pn_swap */
-		priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") ||
-				ofnode_read_bool(args.node, "mediatek,pnswap");
-	} else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
-		    priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
-		   IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
-		/* get corresponding usxgmii phandle */
-		ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys",
-						 NULL, 0, 0, &args);
-		if (ret)
-			return ret;
-
-		priv->usxgmii_regmap = syscon_node_to_regmap(args.node);
-		if (IS_ERR(priv->usxgmii_regmap))
-			return PTR_ERR(priv->usxgmii_regmap);
-
-		/* get corresponding xfi_pextp phandle */
-		ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pextp",
-						 NULL, 0, 0, &args);
-		if (ret)
-			return ret;
-
-		priv->xfi_pextp_regmap = syscon_node_to_regmap(args.node);
-		if (IS_ERR(priv->xfi_pextp_regmap))
-			return PTR_ERR(priv->xfi_pextp_regmap);
-
-		/* get corresponding xfi_pll phandle */
-		ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pll",
-						 NULL, 0, 0, &args);
-		if (ret)
-			return ret;
-
-		priv->xfi_pll_regmap = syscon_node_to_regmap(args.node);
-		if (IS_ERR(priv->xfi_pll_regmap))
-			return PTR_ERR(priv->xfi_pll_regmap);
-
-		/* get corresponding toprgu phandle */
-		ret = dev_read_phandle_with_args(dev, "mediatek,toprgu",
-						 NULL, 0, 0, &args);
-		if (ret)
-			return ret;
-
-		priv->toprgu_regmap = syscon_node_to_regmap(args.node);
-		if (IS_ERR(priv->toprgu_regmap))
-			return PTR_ERR(priv->toprgu_regmap);
-	}
-
-	/* check for switch first, otherwise phy will be used */
-	priv->sw = SW_NONE;
-	priv->switch_init = NULL;
-	priv->switch_mac_control = NULL;
-	str = dev_read_string(dev, "mediatek,switch");
-
-	if (str) {
-		if (!strcmp(str, "mt7530")) {
-			priv->sw = SW_MT7530;
-			priv->switch_init = mt7530_setup;
-			priv->switch_mac_control = mt7530_mac_control;
-			priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR;
-			priv->mt753x_reset_wait_time = 1000;
-		} else if (!strcmp(str, "mt7531")) {
-			priv->sw = SW_MT7531;
-			priv->switch_init = mt7531_setup;
-			priv->switch_mac_control = mt7531_mac_control;
-			priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR;
-			priv->mt753x_reset_wait_time = 200;
-		} else if (!strcmp(str, "mt7988")) {
-			priv->sw = SW_MT7988;
-			priv->switch_init = mt7988_setup;
-			priv->switch_mac_control = mt7988_mac_control;
-			priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR;
-			priv->mt753x_reset_wait_time = 50;
-		} else {
-			printf("error: unsupported switch\n");
-			return -EINVAL;
-		}
-
-		priv->mcm = dev_read_bool(dev, "mediatek,mcm");
-		if (priv->mcm) {
-			ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm);
-			if (ret) {
-				printf("error: no reset ctrl for mcm\n");
-				return ret;
-			}
-		} else {
-			gpio_request_by_name(dev, "reset-gpios", 0,
-					     &priv->rst_gpio, GPIOD_IS_OUT);
-		}
-	} else {
-		ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0,
-						 0, &args);
-		if (ret) {
-			printf("error: phy-handle is not specified\n");
-			return ret;
-		}
-
-		priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1);
-		if (priv->phy_addr < 0) {
-			printf("error: phy address is not specified\n");
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static const struct mtk_soc_data mt7988_data = {
-	.caps = MT7988_CAPS,
-	.ana_rgc3 = 0x128,
-	.gdma_count = 3,
-	.pdma_base = PDMA_V3_BASE,
-	.txd_size = sizeof(struct mtk_tx_dma_v2),
-	.rxd_size = sizeof(struct mtk_rx_dma_v2),
-};
-
-static const struct mtk_soc_data mt7986_data = {
-	.caps = MT7986_CAPS,
-	.ana_rgc3 = 0x128,
-	.gdma_count = 2,
-	.pdma_base = PDMA_V2_BASE,
-	.txd_size = sizeof(struct mtk_tx_dma_v2),
-	.rxd_size = sizeof(struct mtk_rx_dma_v2),
-};
-
-static const struct mtk_soc_data mt7981_data = {
-	.caps = MT7981_CAPS,
-	.ana_rgc3 = 0x128,
-	.gdma_count = 2,
-	.pdma_base = PDMA_V2_BASE,
-	.txd_size = sizeof(struct mtk_tx_dma_v2),
-	.rxd_size = sizeof(struct mtk_rx_dma_v2),
-};
-
-static const struct mtk_soc_data mt7629_data = {
-	.caps = MT7629_CAPS,
-	.ana_rgc3 = 0x128,
-	.gdma_count = 2,
-	.pdma_base = PDMA_V1_BASE,
-	.txd_size = sizeof(struct mtk_tx_dma),
-	.rxd_size = sizeof(struct mtk_rx_dma),
-};
-
-static const struct mtk_soc_data mt7623_data = {
-	.caps = MT7623_CAPS,
-	.gdma_count = 2,
-	.pdma_base = PDMA_V1_BASE,
-	.txd_size = sizeof(struct mtk_tx_dma),
-	.rxd_size = sizeof(struct mtk_rx_dma),
-};
-
-static const struct mtk_soc_data mt7622_data = {
-	.caps = MT7622_CAPS,
-	.ana_rgc3 = 0x2028,
-	.gdma_count = 2,
-	.pdma_base = PDMA_V1_BASE,
-	.txd_size = sizeof(struct mtk_tx_dma),
-	.rxd_size = sizeof(struct mtk_rx_dma),
-};
-
-static const struct mtk_soc_data mt7621_data = {
-	.caps = MT7621_CAPS,
-	.gdma_count = 2,
-	.pdma_base = PDMA_V1_BASE,
-	.txd_size = sizeof(struct mtk_tx_dma),
-	.rxd_size = sizeof(struct mtk_rx_dma),
-};
-
-static const struct udevice_id mtk_eth_ids[] = {
-	{ .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data },
-	{ .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data },
-	{ .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data },
-	{ .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data },
-	{ .compatible = "mediatek,mt7623-eth", .data = (ulong)&mt7623_data },
-	{ .compatible = "mediatek,mt7622-eth", .data = (ulong)&mt7622_data },
-	{ .compatible = "mediatek,mt7621-eth", .data = (ulong)&mt7621_data },
-	{}
-};
-
-static const struct eth_ops mtk_eth_ops = {
-	.start = mtk_eth_start,
-	.stop = mtk_eth_stop,
-	.send = mtk_eth_send,
-	.recv = mtk_eth_recv,
-	.free_pkt = mtk_eth_free_pkt,
-	.write_hwaddr = mtk_eth_write_hwaddr,
-};
-
-U_BOOT_DRIVER(mtk_eth) = {
-	.name = "mtk-eth",
-	.id = UCLASS_ETH,
-	.of_match = mtk_eth_ids,
-	.of_to_plat = mtk_eth_of_to_plat,
-	.plat_auto	= sizeof(struct eth_pdata),
-	.probe = mtk_eth_probe,
-	.remove = mtk_eth_remove,
-	.ops = &mtk_eth_ops,
-	.priv_auto	= sizeof(struct mtk_eth_priv),
-	.flags = DM_FLAG_ALLOC_PRIV_DMA,
-};
--- /dev/null
+++ b/drivers/net/mtk_eth/mtk_eth.c
@@ -0,0 +1,1563 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
+ */
+
+#include <cpu_func.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <net.h>
+#include <regmap.h>
+#include <reset.h>
+#include <syscon.h>
+#include <wait_bit.h>
+#include <asm/cache.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <linux/mdio.h>
+#include <linux/mii.h>
+#include <linux/printk.h>
+
+#include "mtk_eth.h"
+
+#define NUM_TX_DESC		32
+#define NUM_RX_DESC		32
+#define TX_TOTAL_BUF_SIZE	(NUM_TX_DESC * PKTSIZE_ALIGN)
+#define RX_TOTAL_BUF_SIZE	(NUM_RX_DESC * PKTSIZE_ALIGN)
+#define TOTAL_PKT_BUF_SIZE	(TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE)
+
+#define GDMA_FWD_TO_CPU \
+	(0x20000000 | \
+	GDM_ICS_EN | \
+	GDM_TCS_EN | \
+	GDM_UCS_EN | \
+	STRP_CRC | \
+	(DP_PDMA << MYMAC_DP_S) | \
+	(DP_PDMA << BC_DP_S) | \
+	(DP_PDMA << MC_DP_S) | \
+	(DP_PDMA << UN_DP_S))
+
+#define GDMA_BRIDGE_TO_CPU \
+	(0xC0000000 | \
+	GDM_ICS_EN | \
+	GDM_TCS_EN | \
+	GDM_UCS_EN | \
+	(DP_PDMA << MYMAC_DP_S) | \
+	(DP_PDMA << BC_DP_S) | \
+	(DP_PDMA << MC_DP_S) | \
+	(DP_PDMA << UN_DP_S))
+
+#define GDMA_FWD_DISCARD \
+	(0x20000000 | \
+	GDM_ICS_EN | \
+	GDM_TCS_EN | \
+	GDM_UCS_EN | \
+	STRP_CRC | \
+	(DP_DISCARD << MYMAC_DP_S) | \
+	(DP_DISCARD << BC_DP_S) | \
+	(DP_DISCARD << MC_DP_S) | \
+	(DP_DISCARD << UN_DP_S))
+
+struct mtk_eth_priv {
+	char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
+
+	void *tx_ring_noc;
+	void *rx_ring_noc;
+
+	int rx_dma_owner_idx0;
+	int tx_cpu_owner_idx0;
+
+	void __iomem *fe_base;
+	void __iomem *gmac_base;
+	void __iomem *sgmii_base;
+
+	struct regmap *ethsys_regmap;
+
+	struct regmap *infra_regmap;
+
+	struct regmap *usxgmii_regmap;
+	struct regmap *xfi_pextp_regmap;
+	struct regmap *xfi_pll_regmap;
+	struct regmap *toprgu_regmap;
+
+	struct mii_dev *mdio_bus;
+
+	const struct mtk_soc_data *soc;
+	int gmac_id;
+	int force_mode;
+	int speed;
+	int duplex;
+	int mdc;
+	bool pn_swap;
+
+	struct phy_device *phydev;
+	int phy_interface;
+	int phy_addr;
+
+	struct mtk_eth_switch_priv *swpriv;
+	const char *swname;
+
+	struct gpio_desc rst_gpio;
+	int mcm;
+
+	struct reset_ctl rst_fe;
+	struct reset_ctl rst_mcm;
+};
+
+static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
+{
+	writel(val, priv->fe_base + priv->soc->pdma_base + reg);
+}
+
+static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
+			 u32 set)
+{
+	clrsetbits_le32(priv->fe_base + priv->soc->pdma_base + reg, clr, set);
+}
+
+static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg,
+			   u32 val)
+{
+	u32 gdma_base;
+
+	if (no == 2)
+		gdma_base = GDMA3_BASE;
+	else if (no == 1)
+		gdma_base = GDMA2_BASE;
+	else
+		gdma_base = GDMA1_BASE;
+
+	writel(val, priv->fe_base + gdma_base + reg);
+}
+
+void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
+{
+	clrsetbits_le32(priv->fe_base + reg, clr, set);
+}
+
+static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg)
+{
+	return readl(priv->gmac_base + reg);
+}
+
+static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
+{
+	writel(val, priv->gmac_base + reg);
+}
+
+void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
+{
+	clrsetbits_le32(priv->gmac_base + reg, clr, set);
+}
+
+void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
+{
+	uint val;
+
+	regmap_read(priv->ethsys_regmap, reg, &val);
+	val &= ~clr;
+	val |= set;
+	regmap_write(priv->ethsys_regmap, reg, val);
+}
+
+static void mtk_infra_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
+			  u32 set)
+{
+	uint val;
+
+	regmap_read(priv->infra_regmap, reg, &val);
+	val &= ~clr;
+	val |= set;
+	regmap_write(priv->infra_regmap, reg, val);
+}
+
+/* Direct MDIO clause 22/45 access via SoC */
+static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data,
+		      u32 cmd, u32 st)
+{
+	int ret;
+	u32 val;
+
+	val = (st << MDIO_ST_S) |
+	      ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
+	      (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
+	      (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
+
+	if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
+		val |= data & MDIO_RW_DATA_M;
+
+	mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST);
+
+	ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG,
+				PHY_ACS_ST, 0, 5000, 0);
+	if (ret) {
+		pr_warn("MDIO access timeout\n");
+		return ret;
+	}
+
+	if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
+		val = mtk_gmac_read(priv, GMAC_PIAC_REG);
+		return val & MDIO_RW_DATA_M;
+	}
+
+	return 0;
+}
+
+/* Direct MDIO clause 22 read via SoC */
+int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg)
+{
+	return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22);
+}
+
+/* Direct MDIO clause 22 write via SoC */
+int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data)
+{
+	return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22);
+}
+
+/* Direct MDIO clause 45 read via SoC */
+int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg)
+{
+	int ret;
+
+	ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
+	if (ret)
+		return ret;
+
+	return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45,
+			  MDIO_ST_C45);
+}
+
+/* Direct MDIO clause 45 write via SoC */
+int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
+		  u16 val)
+{
+	int ret;
+
+	ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
+	if (ret)
+		return ret;
+
+	return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE,
+			  MDIO_ST_C45);
+}
+
+/* Indirect MDIO clause 45 read via MII registers */
+int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg)
+{
+	int ret;
+
+	ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
+			    (MMD_ADDR << MMD_CMD_S) |
+			    ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+	if (ret)
+		return ret;
+
+	ret = mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
+	if (ret)
+		return ret;
+
+	ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
+			    (MMD_DATA << MMD_CMD_S) |
+			    ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+	if (ret)
+		return ret;
+
+	return mtk_mii_read(priv, addr, MII_MMD_ADDR_DATA_REG);
+}
+
+/* Indirect MDIO clause 45 write via MII registers */
+int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
+		      u16 val)
+{
+	int ret;
+
+	ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
+			    (MMD_ADDR << MMD_CMD_S) |
+			    ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+	if (ret)
+		return ret;
+
+	ret = mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
+	if (ret)
+		return ret;
+
+	ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
+			    (MMD_DATA << MMD_CMD_S) |
+			    ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+	if (ret)
+		return ret;
+
+	return mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val);
+}
+
+static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	struct mtk_eth_priv *priv = bus->priv;
+
+	if (devad < 0)
+		return mtk_mii_read(priv, addr, reg);
+
+	return mtk_mmd_read(priv, addr, devad, reg);
+}
+
+static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+			  u16 val)
+{
+	struct mtk_eth_priv *priv = bus->priv;
+
+	if (devad < 0)
+		return mtk_mii_write(priv, addr, reg, val);
+
+	return mtk_mmd_write(priv, addr, devad, reg, val);
+}
+
+static int mtk_mdio_register(struct udevice *dev)
+{
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+	struct mii_dev *mdio_bus = mdio_alloc();
+	int ret;
+
+	if (!mdio_bus)
+		return -ENOMEM;
+
+	mdio_bus->read = mtk_mdio_read;
+	mdio_bus->write = mtk_mdio_write;
+	snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
+
+	mdio_bus->priv = (void *)priv;
+
+	ret = mdio_register(mdio_bus);
+
+	if (ret)
+		return ret;
+
+	priv->mdio_bus = mdio_bus;
+
+	return 0;
+}
+
+static int mtk_switch_init(struct mtk_eth_priv *priv)
+{
+	struct mtk_eth_switch *swdrvs = ll_entry_start(struct mtk_eth_switch,
+						       mtk_eth_switch);
+	const u32 n_swdrvs = ll_entry_count(struct mtk_eth_switch,
+					    mtk_eth_switch);
+	struct mtk_eth_switch *tmp, *swdrv = NULL;
+	u32 reset_wait_time = 500;
+	size_t priv_size;
+	int ret;
+
+	if (strcmp(priv->swname, "auto")) {
+		for (tmp = swdrvs; tmp < swdrvs + n_swdrvs; tmp++) {
+			if (!strcmp(tmp->name, priv->swname)) {
+				swdrv = tmp;
+				break;
+			}
+		}
+	}
+
+	if (swdrv)
+		reset_wait_time = swdrv->reset_wait_time;
+
+	/* Global reset switch */
+	if (priv->mcm) {
+		reset_assert(&priv->rst_mcm);
+		udelay(1000);
+		reset_deassert(&priv->rst_mcm);
+		mdelay(reset_wait_time);
+	} else if (dm_gpio_is_valid(&priv->rst_gpio)) {
+		dm_gpio_set_value(&priv->rst_gpio, 0);
+		udelay(1000);
+		dm_gpio_set_value(&priv->rst_gpio, 1);
+		mdelay(reset_wait_time);
+	}
+
+	if (!swdrv) {
+		for (tmp = swdrvs; tmp < swdrvs + n_swdrvs; tmp++) {
+			if (!tmp->detect)
+				continue;
+
+			ret = tmp->detect(priv);
+			if (!ret) {
+				swdrv = tmp;
+				break;
+			}
+		}
+
+		if (!swdrv) {
+			printf("Error: unable to detect switch\n");
+			return -ENODEV;
+		}
+	} else {
+		if (swdrv->detect) {
+			ret = swdrv->detect(priv);
+			if (ret) {
+				printf("Error: switch probing failed\n");
+				return -ENODEV;
+			}
+		}
+	}
+
+	printf("%s\n", swdrv->desc);
+
+	priv_size = swdrv->priv_size;
+	if (priv_size < sizeof(struct mtk_eth_switch_priv))
+		priv_size = sizeof(struct mtk_eth_switch_priv);
+
+	priv->swpriv = calloc(1, priv_size);
+	if (!priv->swpriv) {
+		printf("Error: no memory for switch data\n");
+		return -ENOMEM;
+	}
+
+	priv->swpriv->eth = priv;
+	priv->swpriv->soc = priv->soc;
+	priv->swpriv->phy_interface = priv->phy_interface;
+	priv->swpriv->sw = swdrv;
+	priv->swpriv->ethsys_base = regmap_get_range(priv->ethsys_regmap, 0);
+
+	ret = swdrv->setup(priv->swpriv);
+	if (ret) {
+		free(priv->swpriv);
+		priv->swpriv = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+static void mtk_xphy_link_adjust(struct mtk_eth_priv *priv)
+{
+	u16 lcl_adv = 0, rmt_adv = 0;
+	u8 flowctrl;
+	u32 mcr;
+
+	mcr = mtk_gmac_read(priv, XGMAC_PORT_MCR(priv->gmac_id));
+	mcr &= ~(XGMAC_FORCE_TX_FC | XGMAC_FORCE_RX_FC);
+
+	if (priv->phydev->duplex) {
+		if (priv->phydev->pause)
+			rmt_adv = LPA_PAUSE_CAP;
+		if (priv->phydev->asym_pause)
+			rmt_adv |= LPA_PAUSE_ASYM;
+
+		if (priv->phydev->advertising & ADVERTISED_Pause)
+			lcl_adv |= ADVERTISE_PAUSE_CAP;
+		if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
+			lcl_adv |= ADVERTISE_PAUSE_ASYM;
+
+		flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+
+		if (flowctrl & FLOW_CTRL_TX)
+			mcr |= XGMAC_FORCE_TX_FC;
+		if (flowctrl & FLOW_CTRL_RX)
+			mcr |= XGMAC_FORCE_RX_FC;
+
+		debug("rx pause %s, tx pause %s\n",
+		      flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
+		      flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
+	}
+
+	mcr &= ~(XGMAC_TRX_DISABLE);
+	mtk_gmac_write(priv, XGMAC_PORT_MCR(priv->gmac_id), mcr);
+}
+
+static void mtk_phy_link_adjust(struct mtk_eth_priv *priv)
+{
+	u16 lcl_adv = 0, rmt_adv = 0;
+	u8 flowctrl;
+	u32 mcr;
+
+	mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+	      (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
+	      MAC_MODE | FORCE_MODE |
+	      MAC_TX_EN | MAC_RX_EN |
+	      DEL_RXFIFO_CLR |
+	      BKOFF_EN | BACKPR_EN;
+
+	switch (priv->phydev->speed) {
+	case SPEED_10:
+		mcr |= (SPEED_10M << FORCE_SPD_S);
+		break;
+	case SPEED_100:
+		mcr |= (SPEED_100M << FORCE_SPD_S);
+		break;
+	case SPEED_1000:
+	case SPEED_2500:
+		mcr |= (SPEED_1000M << FORCE_SPD_S);
+		break;
+	};
+
+	if (priv->phydev->link)
+		mcr |= FORCE_LINK;
+
+	if (priv->phydev->duplex) {
+		mcr |= FORCE_DPX;
+
+		if (priv->phydev->pause)
+			rmt_adv = LPA_PAUSE_CAP;
+		if (priv->phydev->asym_pause)
+			rmt_adv |= LPA_PAUSE_ASYM;
+
+		if (priv->phydev->advertising & ADVERTISED_Pause)
+			lcl_adv |= ADVERTISE_PAUSE_CAP;
+		if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
+			lcl_adv |= ADVERTISE_PAUSE_ASYM;
+
+		flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+
+		if (flowctrl & FLOW_CTRL_TX)
+			mcr |= FORCE_TX_FC;
+		if (flowctrl & FLOW_CTRL_RX)
+			mcr |= FORCE_RX_FC;
+
+		debug("rx pause %s, tx pause %s\n",
+		      flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
+		      flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
+	}
+
+	mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
+}
+
+static int mtk_phy_start(struct mtk_eth_priv *priv)
+{
+	struct phy_device *phydev = priv->phydev;
+	int ret;
+
+	ret = phy_startup(phydev);
+
+	if (ret) {
+		debug("Could not initialize PHY %s\n", phydev->dev->name);
+		return ret;
+	}
+
+	if (!phydev->link) {
+		debug("%s: link down.\n", phydev->dev->name);
+		return 0;
+	}
+
+	if (!priv->force_mode) {
+		if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+		    priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
+		    priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
+			mtk_xphy_link_adjust(priv);
+		else
+			mtk_phy_link_adjust(priv);
+	}
+
+	debug("Speed: %d, %s duplex%s\n", phydev->speed,
+	      (phydev->duplex) ? "full" : "half",
+	      (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
+
+	return 0;
+}
+
+static int mtk_phy_probe(struct udevice *dev)
+{
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+	struct phy_device *phydev;
+
+	phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev,
+			     priv->phy_interface);
+	if (!phydev)
+		return -ENODEV;
+
+	phydev->supported &= PHY_GBIT_FEATURES;
+	phydev->advertising = phydev->supported;
+
+	priv->phydev = phydev;
+	phy_config(phydev);
+
+	return 0;
+}
+
+static void mtk_sgmii_an_init(struct mtk_eth_priv *priv)
+{
+	/* Set SGMII GEN1 speed(1G) */
+	clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK);
+
+	/* Enable SGMII AN */
+	setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
+		     SGMII_AN_ENABLE);
+
+	/* SGMII AN mode setting */
+	writel(SGMII_AN_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
+
+	/* SGMII PN SWAP setting */
+	if (priv->pn_swap) {
+		setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
+			     SGMII_PN_SWAP_TX_RX);
+	}
+
+	/* Release PHYA power down state */
+	clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
+			SGMII_PHYA_PWD, 0);
+}
+
+static void mtk_sgmii_force_init(struct mtk_eth_priv *priv)
+{
+	/* Set SGMII GEN2 speed(2.5G) */
+	clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
+			SGMSYS_SPEED_MASK,
+			FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
+
+	/* Disable SGMII AN */
+	clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
+			SGMII_AN_ENABLE, 0);
+
+	/* SGMII force mode setting */
+	writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
+
+	/* SGMII PN SWAP setting */
+	if (priv->pn_swap) {
+		setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
+			     SGMII_PN_SWAP_TX_RX);
+	}
+
+	/* Release PHYA power down state */
+	clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
+			SGMII_PHYA_PWD, 0);
+}
+
+static void mtk_xfi_pll_enable(struct mtk_eth_priv *priv)
+{
+	u32 val = 0;
+
+	/* Add software workaround for USXGMII PLL TCL issue */
+	regmap_write(priv->xfi_pll_regmap, XFI_PLL_ANA_GLB8,
+		     RG_XFI_PLL_ANA_SWWA);
+
+	regmap_read(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, &val);
+	val |= RG_XFI_PLL_EN;
+	regmap_write(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, val);
+}
+
+static void mtk_usxgmii_reset(struct mtk_eth_priv *priv)
+{
+	switch (priv->gmac_id) {
+	case 1:
+		regmap_write(priv->toprgu_regmap, 0xFC, 0x0000A004);
+		regmap_write(priv->toprgu_regmap, 0x18, 0x88F0A004);
+		regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
+		regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
+		regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
+		break;
+	case 2:
+		regmap_write(priv->toprgu_regmap, 0xFC, 0x00005002);
+		regmap_write(priv->toprgu_regmap, 0x18, 0x88F05002);
+		regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
+		regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
+		regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
+		break;
+	}
+
+	mdelay(10);
+}
+
+static void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth_priv *priv)
+{
+	regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6D);
+	regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
+	regmap_write(priv->usxgmii_regmap, 0x80C, 0x30000000);
+	ndelay(1020);
+	regmap_write(priv->usxgmii_regmap, 0x80C, 0x10000000);
+	ndelay(1020);
+	regmap_write(priv->usxgmii_regmap, 0x80C, 0x00000000);
+
+	regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
+	regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
+	regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
+	regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
+	regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
+	regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
+	regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
+	regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
+	regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
+	regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
+	regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
+	regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
+	regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
+	regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
+	regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
+	regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
+	regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
+	regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
+	regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
+	regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
+	regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
+	regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
+	regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
+	ndelay(1020);
+	regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
+	regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
+	regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
+	regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
+	regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
+	regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
+	regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
+	regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x40704000);
+	regmap_write(priv->xfi_pextp_regmap, 0x3050, 0xA8000000);
+	regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x000000AA);
+	regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
+	regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
+	regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
+	udelay(150);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
+	ndelay(1020);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
+	udelay(15);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
+	ndelay(1020);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
+	udelay(100);
+	regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
+	regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
+	regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
+	udelay(400);
+}
+
+static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv)
+{
+	regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C);
+	regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
+	regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000);
+	ndelay(1020);
+	regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000);
+	ndelay(1020);
+
+	regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
+	regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
+	regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
+	regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
+	regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
+	regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
+	regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
+	regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
+	regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
+	regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
+	regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
+	regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
+	regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
+	regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
+	regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
+	regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
+	regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
+	regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
+	regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
+	regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
+	regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
+	regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
+	regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
+	ndelay(1020);
+	regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
+	regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
+	regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
+	regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
+	regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
+	regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
+	regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
+	regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100);
+	regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000);
+	regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000);
+	regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
+	if (priv->gmac_id == 2)
+		regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400);
+	regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
+	regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
+	udelay(150);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
+	ndelay(1020);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
+	udelay(15);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
+	ndelay(1020);
+	regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
+	udelay(100);
+	regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
+	regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
+	regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
+	udelay(400);
+}
+
+static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv)
+{
+	mtk_xfi_pll_enable(priv);
+	mtk_usxgmii_reset(priv);
+	mtk_usxgmii_setup_phya_an_10000(priv);
+}
+
+static void mtk_10gbaser_init(struct mtk_eth_priv *priv)
+{
+	mtk_xfi_pll_enable(priv);
+	mtk_usxgmii_reset(priv);
+	mtk_usxgmii_setup_phya_force_10000(priv);
+}
+
+static int mtk_mac_init(struct mtk_eth_priv *priv)
+{
+	int i, sgmii_sel_mask = 0, ge_mode = 0;
+	u32 mcr;
+
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) {
+		mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG,
+			      INFRA_MISC2_BONDING_OPTION, priv->gmac_id);
+	}
+
+	switch (priv->phy_interface) {
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII:
+		ge_mode = GE_MODE_RGMII;
+		break;
+	case PHY_INTERFACE_MODE_SGMII:
+	case PHY_INTERFACE_MODE_2500BASEX:
+		if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
+			printf("Error: SGMII is not supported on this platform\n");
+			return -ENOTSUPP;
+		}
+
+		if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) {
+			mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK,
+				      SGMII_QPHY_SEL);
+		}
+
+		if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII))
+			sgmii_sel_mask = SYSCFG1_SGMII_SEL_M;
+
+		mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask,
+			       SYSCFG1_SGMII_SEL(priv->gmac_id));
+
+		if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
+			mtk_sgmii_an_init(priv);
+		else
+			mtk_sgmii_force_init(priv);
+
+		ge_mode = GE_MODE_RGMII;
+		break;
+	case PHY_INTERFACE_MODE_MII:
+	case PHY_INTERFACE_MODE_GMII:
+		ge_mode = GE_MODE_MII;
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		ge_mode = GE_MODE_RMII;
+		break;
+	default:
+		break;
+	}
+
+	/* set the gmac to the right mode */
+	mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
+		       SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
+		       ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id));
+
+	if (priv->force_mode) {
+		mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+		      (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
+		      MAC_MODE | FORCE_MODE |
+		      MAC_TX_EN | MAC_RX_EN |
+		      BKOFF_EN | BACKPR_EN |
+		      FORCE_LINK;
+
+		switch (priv->speed) {
+		case SPEED_10:
+			mcr |= SPEED_10M << FORCE_SPD_S;
+			break;
+		case SPEED_100:
+			mcr |= SPEED_100M << FORCE_SPD_S;
+			break;
+		case SPEED_1000:
+		case SPEED_2500:
+			mcr |= SPEED_1000M << FORCE_SPD_S;
+			break;
+		}
+
+		if (priv->duplex)
+			mcr |= FORCE_DPX;
+
+		mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
+	}
+
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC1_TRGMII) &&
+	    !MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
+		/* Lower Tx Driving for TRGMII path */
+		for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
+			mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i),
+				       (8 << TD_DM_DRVP_S) |
+				       (8 << TD_DM_DRVN_S));
+
+		mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0,
+			     RX_RST | RXC_DQSISEL);
+		mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0);
+	}
+
+	return 0;
+}
+
+static int mtk_xmac_init(struct mtk_eth_priv *priv)
+{
+	u32 force_link = 0;
+
+	if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
+		printf("Error: 10Gb interface is not supported on this platform\n");
+		return -ENOTSUPP;
+	}
+
+	switch (priv->phy_interface) {
+	case PHY_INTERFACE_MODE_USXGMII:
+		mtk_usxgmii_an_init(priv);
+		break;
+	case PHY_INTERFACE_MODE_10GBASER:
+		mtk_10gbaser_init(priv);
+		break;
+	default:
+		break;
+	}
+
+	/* Set GMAC to the correct mode */
+	mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
+		       SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
+		       0);
+
+	if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+	     priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
+	    priv->gmac_id == 1) {
+		mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX,
+			      NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL);
+	}
+
+	if (priv->phy_interface == PHY_INTERFACE_MODE_XGMII ||
+	    priv->gmac_id == 2)
+		force_link = XGMAC_FORCE_LINK(priv->gmac_id);
+
+	mtk_gmac_rmw(priv, XGMAC_STS(priv->gmac_id),
+		     XGMAC_FORCE_LINK(priv->gmac_id), force_link);
+
+	/* Force GMAC link down */
+	mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE);
+
+	return 0;
+}
+
+static void mtk_eth_fifo_init(struct mtk_eth_priv *priv)
+{
+	char *pkt_base = priv->pkt_pool;
+	struct mtk_tx_dma_v2 *txd;
+	struct mtk_rx_dma_v2 *rxd;
+	int i;
+
+	mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0);
+	udelay(500);
+
+	memset(priv->tx_ring_noc, 0, NUM_TX_DESC * priv->soc->txd_size);
+	memset(priv->rx_ring_noc, 0, NUM_RX_DESC * priv->soc->rxd_size);
+	memset(priv->pkt_pool, 0xff, TOTAL_PKT_BUF_SIZE);
+
+	flush_dcache_range((ulong)pkt_base,
+			   (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE));
+
+	priv->rx_dma_owner_idx0 = 0;
+	priv->tx_cpu_owner_idx0 = 0;
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		txd = priv->tx_ring_noc + i * priv->soc->txd_size;
+
+		txd->txd1 = virt_to_phys(pkt_base);
+		txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0;
+
+		if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+			txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id == 2 ?
+							   15 : priv->gmac_id + 1);
+		else if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
+			txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id + 1);
+		else
+			txd->txd4 = PDMA_V1_TXD4_FPORT_SET(priv->gmac_id + 1);
+
+		pkt_base += PKTSIZE_ALIGN;
+	}
+
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		rxd = priv->rx_ring_noc + i * priv->soc->rxd_size;
+
+		rxd->rxd1 = virt_to_phys(pkt_base);
+
+		if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+		    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+			rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+		else
+			rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+
+		pkt_base += PKTSIZE_ALIGN;
+	}
+
+	mtk_pdma_write(priv, TX_BASE_PTR_REG(0),
+		       virt_to_phys(priv->tx_ring_noc));
+	mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC);
+	mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
+
+	mtk_pdma_write(priv, RX_BASE_PTR_REG(0),
+		       virt_to_phys(priv->rx_ring_noc));
+	mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC);
+	mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1);
+
+	mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0);
+}
+
+static void mtk_eth_mdc_init(struct mtk_eth_priv *priv)
+{
+	u32 divider;
+
+	if (priv->mdc == 0)
+		return;
+
+	divider = min_t(u32, DIV_ROUND_UP(MDC_MAX_FREQ, priv->mdc), MDC_MAX_DIVIDER);
+
+	/* Configure MDC turbo mode */
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+		mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, MISC_MDC_TURBO);
+	else
+		mtk_gmac_rmw(priv, GMAC_PPSC_REG, 0, MISC_MDC_TURBO);
+
+	/* Configure MDC divider */
+	mtk_gmac_rmw(priv, GMAC_PPSC_REG, PHY_MDC_CFG,
+		     FIELD_PREP(PHY_MDC_CFG, divider));
+}
+
+static int mtk_eth_start(struct udevice *dev)
+{
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+	int i, ret;
+
+	/* Reset FE */
+	reset_assert(&priv->rst_fe);
+	udelay(1000);
+	reset_deassert(&priv->rst_fe);
+	mdelay(10);
+
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+	    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+		setbits_le32(priv->fe_base + FE_GLO_MISC_REG, PDMA_VER_V2);
+
+	/* Packets forward to PDMA */
+	mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU);
+
+	for (i = 0; i < priv->soc->gdma_count; i++) {
+		if (i == priv->gmac_id)
+			continue;
+
+		mtk_gdma_write(priv, i, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD);
+	}
+
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) {
+		if (priv->swpriv && !strcmp(priv->swpriv->sw->name, "mt7988") &&
+		    priv->gmac_id == 0) {
+			mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG,
+				       GDMA_BRIDGE_TO_CPU);
+
+			mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
+				       GDMA_CPU_BRIDGE_EN);
+		} else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+			    priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
+			    priv->phy_interface == PHY_INTERFACE_MODE_XGMII) &&
+			   priv->gmac_id != 0) {
+			mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
+				       GDMA_CPU_BRIDGE_EN);
+		}
+	}
+
+	udelay(500);
+
+	mtk_eth_fifo_init(priv);
+
+	if (priv->swpriv) {
+		/* Enable communication with switch */
+		if (priv->swpriv->sw->mac_control)
+			priv->swpriv->sw->mac_control(priv->swpriv, true);
+	} else {
+		/* Start PHY */
+		ret = mtk_phy_start(priv);
+		if (ret)
+			return ret;
+	}
+
+	mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0,
+		     TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN);
+	udelay(500);
+
+	return 0;
+}
+
+static void mtk_eth_stop(struct udevice *dev)
+{
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+
+	if (priv->swpriv) {
+		if (priv->swpriv->sw->mac_control)
+			priv->swpriv->sw->mac_control(priv->swpriv, false);
+	}
+
+	mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG,
+		     TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0);
+	udelay(500);
+
+	wait_for_bit_le32(priv->fe_base + priv->soc->pdma_base + PDMA_GLO_CFG_REG,
+			  RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0);
+}
+
+static int mtk_eth_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+	unsigned char *mac = pdata->enetaddr;
+	u32 macaddr_lsb, macaddr_msb;
+
+	macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1];
+	macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) |
+		      ((u32)mac[4] << 8) | (u32)mac[5];
+
+	mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb);
+	mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb);
+
+	return 0;
+}
+
+static int mtk_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+	u32 idx = priv->tx_cpu_owner_idx0;
+	struct mtk_tx_dma_v2 *txd;
+	void *pkt_base;
+
+	txd = priv->tx_ring_noc + idx * priv->soc->txd_size;
+
+	if (!(txd->txd2 & PDMA_TXD2_DDONE)) {
+		debug("mtk-eth: TX DMA descriptor ring is full\n");
+		return -EPERM;
+	}
+
+	pkt_base = (void *)phys_to_virt(txd->txd1);
+	memcpy(pkt_base, packet, length);
+	flush_dcache_range((ulong)pkt_base, (ulong)pkt_base +
+			   roundup(length, ARCH_DMA_MINALIGN));
+
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+	    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+		txd->txd2 = PDMA_TXD2_LS0 | PDMA_V2_TXD2_SDL0_SET(length);
+	else
+		txd->txd2 = PDMA_TXD2_LS0 | PDMA_V1_TXD2_SDL0_SET(length);
+
+	priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC;
+	mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
+
+	return 0;
+}
+
+static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+	u32 idx = priv->rx_dma_owner_idx0;
+	struct mtk_rx_dma_v2 *rxd;
+	uchar *pkt_base;
+	u32 length;
+
+	rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
+
+	if (!(rxd->rxd2 & PDMA_RXD2_DDONE)) {
+		debug("mtk-eth: RX DMA descriptor ring is empty\n");
+		return -EAGAIN;
+	}
+
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+	    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+		length = PDMA_V2_RXD2_PLEN0_GET(rxd->rxd2);
+	else
+		length = PDMA_V1_RXD2_PLEN0_GET(rxd->rxd2);
+
+	pkt_base = (void *)phys_to_virt(rxd->rxd1);
+	invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base +
+				roundup(length, ARCH_DMA_MINALIGN));
+
+	if (packetp)
+		*packetp = pkt_base;
+
+	return length;
+}
+
+static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+	u32 idx = priv->rx_dma_owner_idx0;
+	struct mtk_rx_dma_v2 *rxd;
+
+	rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
+
+	invalidate_dcache_range((ulong)rxd->rxd1,
+				(ulong)rxd->rxd1 + PKTSIZE_ALIGN);
+
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
+	    MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
+		rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+	else
+		rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+
+	mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx);
+	priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC;
+
+	return 0;
+}
+
+static int mtk_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+	ulong iobase = pdata->iobase;
+	int ret;
+
+	/* Frame Engine Register Base */
+	priv->fe_base = (void *)iobase;
+
+	/* GMAC Register Base */
+	priv->gmac_base = (void *)(iobase + GMAC_BASE);
+
+	/* MDIO register */
+	ret = mtk_mdio_register(dev);
+	if (ret)
+		return ret;
+
+	/* Prepare for tx/rx rings */
+	priv->tx_ring_noc = (void *)
+		noncached_alloc(priv->soc->txd_size * NUM_TX_DESC,
+				ARCH_DMA_MINALIGN);
+	priv->rx_ring_noc = (void *)
+		noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC,
+				ARCH_DMA_MINALIGN);
+
+	/* Set MDC divider */
+	mtk_eth_mdc_init(priv);
+
+	/* Set MAC mode */
+	if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+	    priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
+	    priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
+		ret = mtk_xmac_init(priv);
+	else
+		ret = mtk_mac_init(priv);
+
+	if (ret)
+		return ret;
+
+	/* Probe phy if switch is not specified */
+	if (!priv->swname)
+		return mtk_phy_probe(dev);
+
+	/* Initialize switch */
+	return mtk_switch_init(priv);
+}
+
+static int mtk_eth_remove(struct udevice *dev)
+{
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+
+	/* MDIO unregister */
+	mdio_unregister(priv->mdio_bus);
+	mdio_free(priv->mdio_bus);
+
+	/* Stop possibly started DMA */
+	mtk_eth_stop(dev);
+
+	if (priv->swpriv) {
+		if (priv->swpriv->sw->cleanup)
+			priv->swpriv->sw->cleanup(priv->swpriv);
+		free(priv->swpriv);
+	}
+
+	return 0;
+}
+
+static int mtk_eth_of_to_plat(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct mtk_eth_priv *priv = dev_get_priv(dev);
+	struct ofnode_phandle_args args;
+	struct regmap *regmap;
+	ofnode subnode;
+	int ret;
+
+	priv->soc = (const struct mtk_soc_data *)dev_get_driver_data(dev);
+	if (!priv->soc) {
+		dev_err(dev, "missing soc compatible data\n");
+		return -EINVAL;
+	}
+
+	pdata->iobase = (phys_addr_t)dev_remap_addr(dev);
+
+	/* get corresponding ethsys phandle */
+	ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0,
+					 &args);
+	if (ret)
+		return ret;
+
+	priv->ethsys_regmap = syscon_node_to_regmap(args.node);
+	if (IS_ERR(priv->ethsys_regmap))
+		return PTR_ERR(priv->ethsys_regmap);
+
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_INFRA)) {
+		/* get corresponding infracfg phandle */
+		ret = dev_read_phandle_with_args(dev, "mediatek,infracfg",
+						 NULL, 0, 0, &args);
+
+		if (ret)
+			return ret;
+
+		priv->infra_regmap = syscon_node_to_regmap(args.node);
+		if (IS_ERR(priv->infra_regmap))
+			return PTR_ERR(priv->infra_regmap);
+	}
+
+	/* Reset controllers */
+	ret = reset_get_by_name(dev, "fe", &priv->rst_fe);
+	if (ret) {
+		printf("error: Unable to get reset ctrl for frame engine\n");
+		return ret;
+	}
+
+	priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0);
+
+	priv->mdc = 0;
+	subnode = ofnode_find_subnode(dev_ofnode(dev), "mdio");
+	if (ofnode_valid(subnode)) {
+		priv->mdc = ofnode_read_u32_default(subnode, "clock-frequency", 2500000);
+		if (priv->mdc > MDC_MAX_FREQ ||
+		    priv->mdc < MDC_MAX_FREQ / MDC_MAX_DIVIDER) {
+			printf("error: MDIO clock frequency out of range\n");
+			return -EINVAL;
+		}
+	}
+
+	/* Interface mode is required */
+	pdata->phy_interface = dev_read_phy_mode(dev);
+	priv->phy_interface = pdata->phy_interface;
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
+		printf("error: phy-mode is not set\n");
+		return -EINVAL;
+	}
+
+	/* Force mode or autoneg */
+	subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link");
+	if (ofnode_valid(subnode)) {
+		priv->force_mode = 1;
+		priv->speed = ofnode_read_u32_default(subnode, "speed", 0);
+		priv->duplex = ofnode_read_bool(subnode, "full-duplex");
+
+		if (priv->speed != SPEED_10 && priv->speed != SPEED_100 &&
+		    priv->speed != SPEED_1000 && priv->speed != SPEED_2500 &&
+		    priv->speed != SPEED_10000) {
+			printf("error: no valid speed set in fixed-link\n");
+			return -EINVAL;
+		}
+	}
+
+	if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII ||
+	     priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) &&
+	    IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
+		/* get corresponding sgmii phandle */
+		ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys",
+						 NULL, 0, 0, &args);
+		if (ret)
+			return ret;
+
+		regmap = syscon_node_to_regmap(args.node);
+
+		if (IS_ERR(regmap))
+			return PTR_ERR(regmap);
+
+		priv->sgmii_base = regmap_get_range(regmap, 0);
+
+		if (!priv->sgmii_base) {
+			dev_err(dev, "Unable to find sgmii\n");
+			return -ENODEV;
+		}
+
+		/* Upstream linux use mediatek,pnswap instead of pn_swap */
+		priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") ||
+				ofnode_read_bool(args.node, "mediatek,pnswap");
+	} else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+		    priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
+		   IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
+		/* get corresponding usxgmii phandle */
+		ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys",
+						 NULL, 0, 0, &args);
+		if (ret)
+			return ret;
+
+		priv->usxgmii_regmap = syscon_node_to_regmap(args.node);
+		if (IS_ERR(priv->usxgmii_regmap))
+			return PTR_ERR(priv->usxgmii_regmap);
+
+		/* get corresponding xfi_pextp phandle */
+		ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pextp",
+						 NULL, 0, 0, &args);
+		if (ret)
+			return ret;
+
+		priv->xfi_pextp_regmap = syscon_node_to_regmap(args.node);
+		if (IS_ERR(priv->xfi_pextp_regmap))
+			return PTR_ERR(priv->xfi_pextp_regmap);
+
+		/* get corresponding xfi_pll phandle */
+		ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pll",
+						 NULL, 0, 0, &args);
+		if (ret)
+			return ret;
+
+		priv->xfi_pll_regmap = syscon_node_to_regmap(args.node);
+		if (IS_ERR(priv->xfi_pll_regmap))
+			return PTR_ERR(priv->xfi_pll_regmap);
+
+		/* get corresponding toprgu phandle */
+		ret = dev_read_phandle_with_args(dev, "mediatek,toprgu",
+						 NULL, 0, 0, &args);
+		if (ret)
+			return ret;
+
+		priv->toprgu_regmap = syscon_node_to_regmap(args.node);
+		if (IS_ERR(priv->toprgu_regmap))
+			return PTR_ERR(priv->toprgu_regmap);
+	}
+
+	priv->swname = dev_read_string(dev, "mediatek,switch");
+	if (priv->swname) {
+		priv->mcm = dev_read_bool(dev, "mediatek,mcm");
+		if (priv->mcm) {
+			ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm);
+			if (ret) {
+				printf("error: no reset ctrl for mcm\n");
+				return ret;
+			}
+		} else {
+			gpio_request_by_name(dev, "reset-gpios", 0,
+					     &priv->rst_gpio, GPIOD_IS_OUT);
+		}
+	} else {
+		ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0,
+						 0, &args);
+		if (ret) {
+			printf("error: phy-handle is not specified\n");
+			return ret;
+		}
+
+		priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1);
+		if (priv->phy_addr < 0) {
+			printf("error: phy address is not specified\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct mtk_soc_data mt7988_data = {
+	.caps = MT7988_CAPS,
+	.ana_rgc3 = 0x128,
+	.gdma_count = 3,
+	.pdma_base = PDMA_V3_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma_v2),
+	.rxd_size = sizeof(struct mtk_rx_dma_v2),
+};
+
+static const struct mtk_soc_data mt7986_data = {
+	.caps = MT7986_CAPS,
+	.ana_rgc3 = 0x128,
+	.gdma_count = 2,
+	.pdma_base = PDMA_V2_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma_v2),
+	.rxd_size = sizeof(struct mtk_rx_dma_v2),
+};
+
+static const struct mtk_soc_data mt7981_data = {
+	.caps = MT7981_CAPS,
+	.ana_rgc3 = 0x128,
+	.gdma_count = 2,
+	.pdma_base = PDMA_V2_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma_v2),
+	.rxd_size = sizeof(struct mtk_rx_dma_v2),
+};
+
+static const struct mtk_soc_data mt7629_data = {
+	.caps = MT7629_CAPS,
+	.ana_rgc3 = 0x128,
+	.gdma_count = 2,
+	.pdma_base = PDMA_V1_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma),
+	.rxd_size = sizeof(struct mtk_rx_dma),
+};
+
+static const struct mtk_soc_data mt7623_data = {
+	.caps = MT7623_CAPS,
+	.gdma_count = 2,
+	.pdma_base = PDMA_V1_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma),
+	.rxd_size = sizeof(struct mtk_rx_dma),
+};
+
+static const struct mtk_soc_data mt7622_data = {
+	.caps = MT7622_CAPS,
+	.ana_rgc3 = 0x2028,
+	.gdma_count = 2,
+	.pdma_base = PDMA_V1_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma),
+	.rxd_size = sizeof(struct mtk_rx_dma),
+};
+
+static const struct mtk_soc_data mt7621_data = {
+	.caps = MT7621_CAPS,
+	.gdma_count = 2,
+	.pdma_base = PDMA_V1_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma),
+	.rxd_size = sizeof(struct mtk_rx_dma),
+};
+
+static const struct udevice_id mtk_eth_ids[] = {
+	{ .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data },
+	{ .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data },
+	{ .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data },
+	{ .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data },
+	{ .compatible = "mediatek,mt7623-eth", .data = (ulong)&mt7623_data },
+	{ .compatible = "mediatek,mt7622-eth", .data = (ulong)&mt7622_data },
+	{ .compatible = "mediatek,mt7621-eth", .data = (ulong)&mt7621_data },
+	{}
+};
+
+static const struct eth_ops mtk_eth_ops = {
+	.start = mtk_eth_start,
+	.stop = mtk_eth_stop,
+	.send = mtk_eth_send,
+	.recv = mtk_eth_recv,
+	.free_pkt = mtk_eth_free_pkt,
+	.write_hwaddr = mtk_eth_write_hwaddr,
+};
+
+U_BOOT_DRIVER(mtk_eth) = {
+	.name = "mtk-eth",
+	.id = UCLASS_ETH,
+	.of_match = mtk_eth_ids,
+	.of_to_plat = mtk_eth_of_to_plat,
+	.plat_auto = sizeof(struct eth_pdata),
+	.probe = mtk_eth_probe,
+	.remove = mtk_eth_remove,
+	.ops = &mtk_eth_ops,
+	.priv_auto = sizeof(struct mtk_eth_priv),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
--- a/drivers/net/mtk_eth.h
+++ /dev/null
@@ -1,600 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2018 MediaTek Inc.
- *
- * Author: Weijie Gao <weijie.gao@mediatek.com>
- * Author: Mark Lee <mark-mc.lee@mediatek.com>
- */
-
-#ifndef _MTK_ETH_H_
-#define _MTK_ETH_H_
-
-#include <linux/bitops.h>
-#include <linux/bitfield.h>
-
-enum mkt_eth_capabilities {
-	MTK_TRGMII_BIT,
-	MTK_TRGMII_MT7621_CLK_BIT,
-	MTK_U3_COPHY_V2_BIT,
-	MTK_INFRA_BIT,
-	MTK_NETSYS_V2_BIT,
-	MTK_NETSYS_V3_BIT,
-
-	/* PATH BITS */
-	MTK_ETH_PATH_GMAC1_TRGMII_BIT,
-	MTK_ETH_PATH_GMAC2_SGMII_BIT,
-	MTK_ETH_PATH_MT7622_SGMII_BIT,
-	MTK_ETH_PATH_MT7629_GMAC2_BIT,
-};
-
-#define MTK_TRGMII			BIT(MTK_TRGMII_BIT)
-#define MTK_TRGMII_MT7621_CLK		BIT(MTK_TRGMII_MT7621_CLK_BIT)
-#define MTK_U3_COPHY_V2			BIT(MTK_U3_COPHY_V2_BIT)
-#define MTK_INFRA			BIT(MTK_INFRA_BIT)
-#define MTK_NETSYS_V2			BIT(MTK_NETSYS_V2_BIT)
-#define MTK_NETSYS_V3			BIT(MTK_NETSYS_V3_BIT)
-
-/* Supported path present on SoCs */
-#define MTK_ETH_PATH_GMAC1_TRGMII	BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
-
-#define MTK_ETH_PATH_GMAC2_SGMII	BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
-#define MTK_ETH_PATH_MT7622_SGMII	BIT(MTK_ETH_PATH_MT7622_SGMII_BIT)
-#define MTK_ETH_PATH_MT7629_GMAC2	BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT)
-
-#define MTK_GMAC1_TRGMII	(MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
-
-#define MTK_GMAC2_U3_QPHY	(MTK_ETH_PATH_GMAC2_SGMII | MTK_U3_COPHY_V2 | MTK_INFRA)
-
-#define MTK_HAS_CAPS(caps, _x)		(((caps) & (_x)) == (_x))
-
-#define MT7621_CAPS  (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK)
-
-#define MT7622_CAPS  (MTK_ETH_PATH_MT7622_SGMII)
-
-#define MT7623_CAPS  (MTK_GMAC1_TRGMII)
-
-#define MT7629_CAPS  (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA)
-
-#define MT7981_CAPS  (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2)
-
-#define MT7986_CAPS  (MTK_NETSYS_V2)
-
-#define MT7988_CAPS  (MTK_NETSYS_V3 | MTK_INFRA)
-
-/* Frame Engine Register Bases */
-#define PDMA_V1_BASE			0x0800
-#define PDMA_V2_BASE			0x6000
-#define PDMA_V3_BASE			0x6800
-#define GDMA1_BASE			0x0500
-#define GDMA2_BASE			0x1500
-#define GDMA3_BASE			0x0540
-#define GMAC_BASE			0x10000
-#define GSW_BASE			0x20000
-
-/* Ethernet subsystem registers */
-
-#define ETHSYS_SYSCFG1_REG		0x14
-#define SYSCFG1_GE_MODE_S(n)		(12 + ((n) * 2))
-#define SYSCFG1_GE_MODE_M		0x3
-#define SYSCFG1_SGMII_SEL_M		GENMASK(9, 8)
-#define SYSCFG1_SGMII_SEL(gmac)		BIT(9 - (gmac))
-
-#define ETHSYS_CLKCFG0_REG		0x2c
-#define ETHSYS_TRGMII_CLK_SEL362_5	BIT(11)
-
-/* Top misc registers */
-#define TOPMISC_NETSYS_PCS_MUX		0x84
-#define NETSYS_PCS_MUX_MASK		GENMASK(1, 0)
-#define MUX_G2_USXGMII_SEL		BIT(1)
-#define MUX_HSGMII1_G1_SEL		BIT(0)
-
-#define USB_PHY_SWITCH_REG		0x218
-#define QPHY_SEL_MASK			0x3
-#define SGMII_QPHY_SEL			0x2
-
-#define MT7629_INFRA_MISC2_REG		0x70c
-#define INFRA_MISC2_BONDING_OPTION	GENMASK(15, 0)
-
-/* SYSCFG1_GE_MODE: GE Modes */
-#define GE_MODE_RGMII			0
-#define GE_MODE_MII			1
-#define GE_MODE_MII_PHY			2
-#define GE_MODE_RMII			3
-
-/* SGMII subsystem config registers */
-#define SGMSYS_PCS_CONTROL_1		0x0
-#define SGMII_LINK_STATUS		BIT(18)
-#define SGMII_AN_ENABLE			BIT(12)
-#define SGMII_AN_RESTART		BIT(9)
-
-#define SGMSYS_SGMII_MODE		0x20
-#define SGMII_AN_MODE			0x31120103
-#define SGMII_FORCE_MODE		0x31120019
-
-#define SGMSYS_QPHY_PWR_STATE_CTRL	0xe8
-#define SGMII_PHYA_PWD			BIT(4)
-
-#define SGMSYS_QPHY_WRAP_CTRL		0xec
-#define SGMII_PN_SWAP_TX_RX		0x03
-
-#define SGMSYS_GEN2_SPEED		0x2028
-#define SGMSYS_GEN2_SPEED_V2		0x128
-#define SGMSYS_SPEED_MASK		GENMASK(3, 2)
-#define SGMSYS_SPEED_2500		1
-
-/* USXGMII subsystem config registers */
-/* Register to control USXGMII XFI PLL digital */
-#define XFI_PLL_DIG_GLB8		0x08
-#define RG_XFI_PLL_EN			BIT(31)
-
-/* Register to control USXGMII XFI PLL analog */
-#define XFI_PLL_ANA_GLB8		0x108
-#define RG_XFI_PLL_ANA_SWWA		0x02283248
-
-/* Frame Engine Registers */
-#define PSE_NO_DROP_CFG_REG		0x108
-#define PSE_NO_DROP_GDM1		BIT(1)
-
-#define FE_GLO_MISC_REG			0x124
-#define PDMA_VER_V2			BIT(4)
-
-/* PDMA */
-#define TX_BASE_PTR_REG(n)		(0x000 + (n) * 0x10)
-#define TX_MAX_CNT_REG(n)		(0x004 + (n) * 0x10)
-#define TX_CTX_IDX_REG(n)		(0x008 + (n) * 0x10)
-#define TX_DTX_IDX_REG(n)		(0x00c + (n) * 0x10)
-
-#define RX_BASE_PTR_REG(n)		(0x100 + (n) * 0x10)
-#define RX_MAX_CNT_REG(n)		(0x104 + (n) * 0x10)
-#define RX_CRX_IDX_REG(n)		(0x108 + (n) * 0x10)
-#define RX_DRX_IDX_REG(n)		(0x10c + (n) * 0x10)
-
-#define PDMA_GLO_CFG_REG		0x204
-#define TX_WB_DDONE			BIT(6)
-#define RX_DMA_BUSY			BIT(3)
-#define RX_DMA_EN			BIT(2)
-#define TX_DMA_BUSY			BIT(1)
-#define TX_DMA_EN			BIT(0)
-
-#define PDMA_RST_IDX_REG		0x208
-#define RST_DRX_IDX0			BIT(16)
-#define RST_DTX_IDX0			BIT(0)
-
-/* GDMA */
-#define GDMA_IG_CTRL_REG		0x000
-#define GDM_ICS_EN			BIT(22)
-#define GDM_TCS_EN			BIT(21)
-#define GDM_UCS_EN			BIT(20)
-#define STRP_CRC			BIT(16)
-#define MYMAC_DP_S			12
-#define MYMAC_DP_M			0xf000
-#define BC_DP_S				8
-#define BC_DP_M				0xf00
-#define MC_DP_S				4
-#define MC_DP_M				0xf0
-#define UN_DP_S				0
-#define UN_DP_M				0x0f
-
-#define GDMA_EG_CTRL_REG		0x004
-#define GDMA_CPU_BRIDGE_EN		BIT(31)
-
-#define GDMA_MAC_LSB_REG		0x008
-
-#define GDMA_MAC_MSB_REG		0x00c
-
-/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */
-#define DP_PDMA				0
-#define DP_GDMA1			1
-#define DP_GDMA2			2
-#define DP_PPE				4
-#define DP_QDMA				5
-#define DP_DISCARD			7
-
-/* GMAC Registers */
-
-#define GMAC_PPSC_REG			0x0000
-#define PHY_MDC_CFG			GENMASK(29, 24)
-#define MDC_TURBO			BIT(20)
-#define MDC_MAX_FREQ			25000000
-#define MDC_MAX_DIVIDER			63
-
-#define GMAC_PIAC_REG			0x0004
-#define PHY_ACS_ST			BIT(31)
-#define MDIO_REG_ADDR_S			25
-#define MDIO_REG_ADDR_M			0x3e000000
-#define MDIO_PHY_ADDR_S			20
-#define MDIO_PHY_ADDR_M			0x1f00000
-#define MDIO_CMD_S			18
-#define MDIO_CMD_M			0xc0000
-#define MDIO_ST_S			16
-#define MDIO_ST_M			0x30000
-#define MDIO_RW_DATA_S			0
-#define MDIO_RW_DATA_M			0xffff
-
-#define GMAC_XGMAC_STS_REG		0x000c
-#define P1_XGMAC_FORCE_LINK		BIT(15)
-
-#define GMAC_MAC_MISC_REG		0x0010
-#define MISC_MDC_TURBO			BIT(4)
-
-#define GMAC_GSW_CFG_REG		0x0080
-#define GSWTX_IPG_M			0xF0000
-#define GSWTX_IPG_S			16
-#define GSWRX_IPG_M			0xF
-#define GSWRX_IPG_S			0
-
-/* MDIO_CMD: MDIO commands */
-#define MDIO_CMD_ADDR			0
-#define MDIO_CMD_WRITE			1
-#define MDIO_CMD_READ			2
-#define MDIO_CMD_READ_C45		3
-
-/* MDIO_ST: MDIO start field */
-#define MDIO_ST_C45			0
-#define MDIO_ST_C22			1
-
-#define GMAC_PORT_MCR(p)		(0x0100 + (p) * 0x100)
-#define MAC_RX_PKT_LEN_S		24
-#define MAC_RX_PKT_LEN_M		0x3000000
-#define IPG_CFG_S			18
-#define IPG_CFG_M			0xc0000
-#define MAC_MODE			BIT(16)
-#define FORCE_MODE			BIT(15)
-#define MAC_TX_EN			BIT(14)
-#define MAC_RX_EN			BIT(13)
-#define DEL_RXFIFO_CLR			BIT(12)
-#define BKOFF_EN			BIT(9)
-#define BACKPR_EN			BIT(8)
-#define FORCE_RX_FC			BIT(5)
-#define FORCE_TX_FC			BIT(4)
-#define FORCE_SPD_S			2
-#define FORCE_SPD_M			0x0c
-#define FORCE_DPX			BIT(1)
-#define FORCE_LINK			BIT(0)
-
-/* Values of IPG_CFG */
-#define IPG_96BIT			0
-#define IPG_96BIT_WITH_SHORT_IPG	1
-#define IPG_64BIT			2
-
-/* MAC_RX_PKT_LEN: Max RX packet length */
-#define MAC_RX_PKT_LEN_1518		0
-#define MAC_RX_PKT_LEN_1536		1
-#define MAC_RX_PKT_LEN_1552		2
-#define MAC_RX_PKT_LEN_JUMBO		3
-
-/* FORCE_SPD: Forced link speed */
-#define SPEED_10M			0
-#define SPEED_100M			1
-#define SPEED_1000M			2
-
-#define GMAC_TRGMII_RCK_CTRL		0x300
-#define RX_RST				BIT(31)
-#define RXC_DQSISEL			BIT(30)
-
-#define GMAC_TRGMII_TD_ODT(n)		(0x354 + (n) * 8)
-#define TD_DM_DRVN_S			4
-#define TD_DM_DRVN_M			0xf0
-#define TD_DM_DRVP_S			0
-#define TD_DM_DRVP_M			0x0f
-
-/* XGMAC Status Registers */
-#define XGMAC_STS(x)			(((x) == 2) ? 0x001C : 0x000C)
-#define XGMAC_FORCE_LINK(x)		(((x) == 1) ? BIT(31) : BIT(15))
-
-/* XGMAC Registers */
-#define XGMAC_PORT_MCR(x)		(0x2000 + (((x) - 1) * 0x1000))
-#define XGMAC_TRX_DISABLE		0xf
-#define XGMAC_FORCE_TX_FC		BIT(5)
-#define XGMAC_FORCE_RX_FC		BIT(4)
-
-/* MT7530 Registers */
-
-#define PCR_REG(p)			(0x2004 + (p) * 0x100)
-#define PORT_MATRIX_S			16
-#define PORT_MATRIX_M			0xff0000
-
-#define PVC_REG(p)			(0x2010 + (p) * 0x100)
-#define STAG_VPID_S			16
-#define STAG_VPID_M			0xffff0000
-#define VLAN_ATTR_S			6
-#define VLAN_ATTR_M			0xc0
-
-/* VLAN_ATTR: VLAN attributes */
-#define VLAN_ATTR_USER			0
-#define VLAN_ATTR_STACK			1
-#define VLAN_ATTR_TRANSLATION		2
-#define VLAN_ATTR_TRANSPARENT		3
-
-#define PMCR_REG(p)			(0x3000 + (p) * 0x100)
-/* XXX: all fields of MT7530 are defined under GMAC_PORT_MCR
- * MT7531 specific fields are defined below
- */
-#define FORCE_MODE_EEE1G		BIT(25)
-#define FORCE_MODE_EEE100		BIT(26)
-#define FORCE_MODE_TX_FC		BIT(27)
-#define FORCE_MODE_RX_FC		BIT(28)
-#define FORCE_MODE_DPX			BIT(29)
-#define FORCE_MODE_SPD			BIT(30)
-#define FORCE_MODE_LNK			BIT(31)
-#define MT7531_FORCE_MODE		FORCE_MODE_EEE1G | FORCE_MODE_EEE100 |\
-					FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
-					FORCE_MODE_DPX   | FORCE_MODE_SPD | \
-					FORCE_MODE_LNK
-#define MT7988_FORCE_MODE		FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
-					FORCE_MODE_DPX   | FORCE_MODE_SPD | \
-					FORCE_MODE_LNK
-
-/* MT7531 SGMII Registers */
-#define MT7531_SGMII_REG_BASE		0x5000
-#define MT7531_SGMII_REG_PORT_BASE	0x1000
-#define MT7531_SGMII_REG(p, r)		(MT7531_SGMII_REG_BASE + \
-					(p) * MT7531_SGMII_REG_PORT_BASE + (r))
-#define MT7531_PCS_CONTROL_1(p)		MT7531_SGMII_REG(((p) - 5), 0x00)
-#define MT7531_SGMII_MODE(p)		MT7531_SGMII_REG(((p) - 5), 0x20)
-#define MT7531_QPHY_PWR_STATE_CTRL(p)	MT7531_SGMII_REG(((p) - 5), 0xe8)
-#define MT7531_PHYA_CTRL_SIGNAL3(p)	MT7531_SGMII_REG(((p) - 5), 0x128)
-/* XXX: all fields of MT7531 SGMII  are defined under SGMSYS */
-
-/* MT753x System Control Register */
-#define SYS_CTRL_REG			0x7000
-#define SW_PHY_RST			BIT(2)
-#define SW_SYS_RST			BIT(1)
-#define SW_REG_RST			BIT(0)
-
-/* MT7531  */
-#define MT7531_PHY_IAC			0x701c
-/* XXX: all fields are defined under GMAC_PIAC_REG */
-
-#define MT7531_CLKGEN_CTRL		0x7500
-#define CLK_SKEW_OUT_S			8
-#define CLK_SKEW_OUT_M			0x300
-#define CLK_SKEW_IN_S			6
-#define CLK_SKEW_IN_M			0xc0
-#define RXCLK_NO_DELAY			BIT(5)
-#define TXCLK_NO_REVERSE		BIT(4)
-#define GP_MODE_S			1
-#define GP_MODE_M			0x06
-#define GP_CLK_EN			BIT(0)
-
-/* Values of GP_MODE */
-#define GP_MODE_RGMII			0
-#define GP_MODE_MII			1
-#define GP_MODE_REV_MII			2
-
-/* Values of CLK_SKEW_IN */
-#define CLK_SKEW_IN_NO_CHANGE		0
-#define CLK_SKEW_IN_DELAY_100PPS	1
-#define CLK_SKEW_IN_DELAY_200PPS	2
-#define CLK_SKEW_IN_REVERSE		3
-
-/* Values of CLK_SKEW_OUT */
-#define CLK_SKEW_OUT_NO_CHANGE		0
-#define CLK_SKEW_OUT_DELAY_100PPS	1
-#define CLK_SKEW_OUT_DELAY_200PPS	2
-#define CLK_SKEW_OUT_REVERSE		3
-
-#define HWTRAP_REG			0x7800
-/* MT7530 Modified Hardware Trap Status Registers */
-#define MHWTRAP_REG			0x7804
-#define CHG_TRAP			BIT(16)
-#define LOOPDET_DIS			BIT(14)
-#define P5_INTF_SEL_S			13
-#define P5_INTF_SEL_M			0x2000
-#define SMI_ADDR_S			11
-#define SMI_ADDR_M			0x1800
-#define XTAL_FSEL_S			9
-#define XTAL_FSEL_M			0x600
-#define P6_INTF_DIS			BIT(8)
-#define P5_INTF_MODE_S			7
-#define P5_INTF_MODE_M			0x80
-#define P5_INTF_DIS			BIT(6)
-#define C_MDIO_BPS			BIT(5)
-#define CHIP_MODE_S			0
-#define CHIP_MODE_M			0x0f
-
-/* P5_INTF_SEL: Interface type of Port5 */
-#define P5_INTF_SEL_GPHY		0
-#define P5_INTF_SEL_GMAC5		1
-
-/* P5_INTF_MODE: Interface mode of Port5 */
-#define P5_INTF_MODE_GMII_MII		0
-#define P5_INTF_MODE_RGMII		1
-
-#define MT7530_P6ECR			0x7830
-#define P6_INTF_MODE_M			0x3
-#define P6_INTF_MODE_S			0
-
-/* P6_INTF_MODE: Interface mode of Port6 */
-#define P6_INTF_MODE_RGMII		0
-#define P6_INTF_MODE_TRGMII		1
-
-#define NUM_TRGMII_CTRL			5
-
-#define MT7530_TRGMII_RD(n)		(0x7a10 + (n) * 8)
-#define RD_TAP_S			0
-#define RD_TAP_M			0x7f
-
-#define MT7530_TRGMII_TD_ODT(n)		(0x7a54 + (n) * 8)
-/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */
-
-/* TOP Signals Status Register */
-#define MT7531_TOP_SIG_SR		0x780c
-#define PAD_MCM_SMI_EN			BIT(0)
-#define PAD_DUAL_SGMII_EN		BIT(1)
-
-/* MT7531 PLLGP Registers */
-#define MT7531_PLLGP_EN			0x7820
-#define EN_COREPLL			BIT(2)
-#define SW_CLKSW			BIT(1)
-#define SW_PLLGP			BIT(0)
-
-#define MT7531_PLLGP_CR0		0x78a8
-#define RG_COREPLL_EN			BIT(22)
-#define RG_COREPLL_POSDIV_S		23
-#define RG_COREPLL_POSDIV_M		0x3800000
-#define RG_COREPLL_SDM_PCW_S		1
-#define RG_COREPLL_SDM_PCW_M		0x3ffffe
-#define RG_COREPLL_SDM_PCW_CHG		BIT(0)
-
-/* MT7531 RGMII and SGMII PLL clock */
-#define MT7531_ANA_PLLGP_CR2		0x78b0
-#define MT7531_ANA_PLLGP_CR5		0x78bc
-
-/* MT7531 GPIO GROUP IOLB SMT0 Control */
-#define MT7531_SMT0_IOLB		0x7f04
-#define SMT_IOLB_5_SMI_MDC_EN		BIT(5)
-
-/* MT7530 GPHY MDIO Indirect Access Registers */
-#define MII_MMD_ACC_CTL_REG		0x0d
-#define MMD_CMD_S			14
-#define MMD_CMD_M			0xc000
-#define MMD_DEVAD_S			0
-#define MMD_DEVAD_M			0x1f
-
-/* MMD_CMD: MMD commands */
-#define MMD_ADDR			0
-#define MMD_DATA			1
-#define MMD_DATA_RW_POST_INC		2
-#define MMD_DATA_W_POST_INC		3
-
-#define MII_MMD_ADDR_DATA_REG		0x0e
-
-/* MT7530 GPHY MDIO MMD Registers */
-#define CORE_PLL_GROUP2			0x401
-#define RG_SYSPLL_EN_NORMAL		BIT(15)
-#define RG_SYSPLL_VODEN			BIT(14)
-#define RG_SYSPLL_POSDIV_S		5
-#define RG_SYSPLL_POSDIV_M		0x60
-
-#define CORE_PLL_GROUP4			0x403
-#define MT7531_BYPASS_MODE		BIT(4)
-#define MT7531_POWER_ON_OFF		BIT(5)
-#define RG_SYSPLL_DDSFBK_EN		BIT(12)
-#define RG_SYSPLL_BIAS_EN		BIT(11)
-#define RG_SYSPLL_BIAS_LPF_EN		BIT(10)
-
-#define CORE_PLL_GROUP5			0x404
-#define RG_LCDDS_PCW_NCPO1_S		0
-#define RG_LCDDS_PCW_NCPO1_M		0xffff
-
-#define CORE_PLL_GROUP6			0x405
-#define RG_LCDDS_PCW_NCPO0_S		0
-#define RG_LCDDS_PCW_NCPO0_M		0xffff
-
-#define CORE_PLL_GROUP7			0x406
-#define RG_LCDDS_PWDB			BIT(15)
-#define RG_LCDDS_ISO_EN			BIT(13)
-#define RG_LCCDS_C_S			4
-#define RG_LCCDS_C_M			0x70
-#define RG_LCDDS_PCW_NCPO_CHG		BIT(3)
-
-#define CORE_PLL_GROUP10		0x409
-#define RG_LCDDS_SSC_DELTA_S		0
-#define RG_LCDDS_SSC_DELTA_M		0xfff
-
-#define CORE_PLL_GROUP11		0x40a
-#define RG_LCDDS_SSC_DELTA1_S		0
-#define RG_LCDDS_SSC_DELTA1_M		0xfff
-
-#define CORE_GSWPLL_GRP1		0x40d
-#define RG_GSWPLL_POSDIV_200M_S		12
-#define RG_GSWPLL_POSDIV_200M_M		0x3000
-#define RG_GSWPLL_EN_PRE		BIT(11)
-#define RG_GSWPLL_FBKDIV_200M_S		0
-#define RG_GSWPLL_FBKDIV_200M_M		0xff
-
-#define CORE_GSWPLL_GRP2		0x40e
-#define RG_GSWPLL_POSDIV_500M_S		8
-#define RG_GSWPLL_POSDIV_500M_M		0x300
-#define RG_GSWPLL_FBKDIV_500M_S		0
-#define RG_GSWPLL_FBKDIV_500M_M		0xff
-
-#define CORE_TRGMII_GSW_CLK_CG		0x410
-#define REG_GSWCK_EN			BIT(0)
-#define REG_TRGMIICK_EN			BIT(1)
-
-/* Extend PHY Control Register 3 */
-#define PHY_EXT_REG_14			0x14
-
-/* Fields of PHY_EXT_REG_14 */
-#define PHY_EN_DOWN_SHFIT		BIT(4)
-
-/* Extend PHY Control Register 4 */
-#define PHY_EXT_REG_17			0x17
-
-/* Fields of PHY_EXT_REG_17 */
-#define PHY_LINKDOWN_POWER_SAVING_EN	BIT(4)
-
-/* PHY RXADC Control Register 7 */
-#define PHY_DEV1E_REG_0C6		0x0c6
-
-/* Fields of PHY_DEV1E_REG_0C6 */
-#define PHY_POWER_SAVING_S		8
-#define PHY_POWER_SAVING_M		0x300
-#define PHY_POWER_SAVING_TX		0x0
-
-/* PDMA descriptors */
-struct mtk_rx_dma {
-	unsigned int rxd1;
-	unsigned int rxd2;
-	unsigned int rxd3;
-	unsigned int rxd4;
-} __packed __aligned(4);
-
-struct mtk_rx_dma_v2 {
-	unsigned int rxd1;
-	unsigned int rxd2;
-	unsigned int rxd3;
-	unsigned int rxd4;
-	unsigned int rxd5;
-	unsigned int rxd6;
-	unsigned int rxd7;
-	unsigned int rxd8;
-} __packed __aligned(4);
-
-struct mtk_tx_dma {
-	unsigned int txd1;
-	unsigned int txd2;
-	unsigned int txd3;
-	unsigned int txd4;
-} __packed __aligned(4);
-
-struct mtk_tx_dma_v2 {
-	unsigned int txd1;
-	unsigned int txd2;
-	unsigned int txd3;
-	unsigned int txd4;
-	unsigned int txd5;
-	unsigned int txd6;
-	unsigned int txd7;
-	unsigned int txd8;
-} __packed __aligned(4);
-
-/* PDMA TXD fields */
-#define PDMA_TXD2_DDONE			BIT(31)
-#define PDMA_TXD2_LS0			BIT(30)
-#define PDMA_V1_TXD2_SDL0_M		GENMASK(29, 16)
-#define PDMA_V1_TXD2_SDL0_SET(_v)	FIELD_PREP(PDMA_V1_TXD2_SDL0_M, (_v))
-#define PDMA_V2_TXD2_SDL0_M		GENMASK(23, 8)
-#define PDMA_V2_TXD2_SDL0_SET(_v)	FIELD_PREP(PDMA_V2_TXD2_SDL0_M, (_v))
-
-#define PDMA_V1_TXD4_FPORT_M		GENMASK(27, 25)
-#define PDMA_V1_TXD4_FPORT_SET(_v)	FIELD_PREP(PDMA_V1_TXD4_FPORT_M, (_v))
-#define PDMA_V2_TXD4_FPORT_M		GENMASK(27, 24)
-#define PDMA_V2_TXD4_FPORT_SET(_v)	FIELD_PREP(PDMA_V2_TXD4_FPORT_M, (_v))
-
-#define PDMA_V2_TXD5_FPORT_M		GENMASK(19, 16)
-#define PDMA_V2_TXD5_FPORT_SET(_v)	FIELD_PREP(PDMA_V2_TXD5_FPORT_M, (_v))
-
-/* PDMA RXD fields */
-#define PDMA_RXD2_DDONE			BIT(31)
-#define PDMA_RXD2_LS0			BIT(30)
-#define PDMA_V1_RXD2_PLEN0_M		GENMASK(29, 16)
-#define PDMA_V1_RXD2_PLEN0_GET(_v)	FIELD_GET(PDMA_V1_RXD2_PLEN0_M, (_v))
-#define PDMA_V1_RXD2_PLEN0_SET(_v)	FIELD_PREP(PDMA_V1_RXD2_PLEN0_M, (_v))
-#define PDMA_V2_RXD2_PLEN0_M		GENMASK(23, 8)
-#define PDMA_V2_RXD2_PLEN0_GET(_v)	FIELD_GET(PDMA_V2_RXD2_PLEN0_M, (_v))
-#define PDMA_V2_RXD2_PLEN0_SET(_v)	FIELD_PREP(PDMA_V2_RXD2_PLEN0_M, (_v))
-
-#endif /* _MTK_ETH_H_ */
--- /dev/null
+++ b/drivers/net/mtk_eth/mtk_eth.h
@@ -0,0 +1,429 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
+ */
+
+#ifndef _MTK_ETH_H_
+#define _MTK_ETH_H_
+
+#include <linker_lists.h>
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+
+struct mtk_eth_priv;
+struct mtk_eth_switch_priv;
+
+/* struct mtk_soc_data -	This is the structure holding all differences
+ *				among various plaforms
+ * @caps			Flags shown the extra capability for the SoC
+ * @ana_rgc3:			The offset for register ANA_RGC3 related to
+ *				sgmiisys syscon
+ * @gdma_count:			Number of GDMAs
+ * @pdma_base:			Register base of PDMA block
+ * @txd_size:			Tx DMA descriptor size.
+ * @rxd_size:			Rx DMA descriptor size.
+ */
+struct mtk_soc_data {
+	u32 caps;
+	u32 ana_rgc3;
+	u32 gdma_count;
+	u32 pdma_base;
+	u32 txd_size;
+	u32 rxd_size;
+};
+
+struct mtk_eth_switch {
+	const char *name;
+	const char *desc;
+	size_t priv_size;
+	u32 reset_wait_time;
+
+	int (*detect)(struct mtk_eth_priv *priv);
+	int (*setup)(struct mtk_eth_switch_priv *priv);
+	int (*cleanup)(struct mtk_eth_switch_priv *priv);
+	void (*mac_control)(struct mtk_eth_switch_priv *priv, bool enable);
+};
+
+#define MTK_ETH_SWITCH(__name)	\
+	ll_entry_declare(struct mtk_eth_switch, __name, mtk_eth_switch)
+
+struct mtk_eth_switch_priv {
+	struct mtk_eth_priv *eth;
+	const struct mtk_eth_switch *sw;
+	const struct mtk_soc_data *soc;
+	void *ethsys_base;
+	int phy_interface;
+};
+
+enum mkt_eth_capabilities {
+	MTK_TRGMII_BIT,
+	MTK_TRGMII_MT7621_CLK_BIT,
+	MTK_U3_COPHY_V2_BIT,
+	MTK_INFRA_BIT,
+	MTK_NETSYS_V2_BIT,
+	MTK_NETSYS_V3_BIT,
+
+	/* PATH BITS */
+	MTK_ETH_PATH_GMAC1_TRGMII_BIT,
+	MTK_ETH_PATH_GMAC2_SGMII_BIT,
+	MTK_ETH_PATH_MT7622_SGMII_BIT,
+	MTK_ETH_PATH_MT7629_GMAC2_BIT,
+};
+
+#define MTK_TRGMII			BIT(MTK_TRGMII_BIT)
+#define MTK_TRGMII_MT7621_CLK		BIT(MTK_TRGMII_MT7621_CLK_BIT)
+#define MTK_U3_COPHY_V2			BIT(MTK_U3_COPHY_V2_BIT)
+#define MTK_INFRA			BIT(MTK_INFRA_BIT)
+#define MTK_NETSYS_V2			BIT(MTK_NETSYS_V2_BIT)
+#define MTK_NETSYS_V3			BIT(MTK_NETSYS_V3_BIT)
+
+/* Supported path present on SoCs */
+#define MTK_ETH_PATH_GMAC1_TRGMII	BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_SGMII	BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
+#define MTK_ETH_PATH_MT7622_SGMII	BIT(MTK_ETH_PATH_MT7622_SGMII_BIT)
+#define MTK_ETH_PATH_MT7629_GMAC2	BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT)
+
+#define MTK_GMAC1_TRGMII	(MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
+
+#define MTK_GMAC2_U3_QPHY	(MTK_ETH_PATH_GMAC2_SGMII | MTK_U3_COPHY_V2 | MTK_INFRA)
+
+#define MTK_HAS_CAPS(caps, _x)		(((caps) & (_x)) == (_x))
+
+#define MT7621_CAPS  (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK)
+
+#define MT7622_CAPS  (MTK_ETH_PATH_MT7622_SGMII)
+
+#define MT7623_CAPS  (MTK_GMAC1_TRGMII)
+
+#define MT7629_CAPS  (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA)
+
+#define MT7981_CAPS  (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2)
+
+#define MT7986_CAPS  (MTK_NETSYS_V2)
+
+#define MT7987_CAPS  (MTK_NETSYS_V3 | MTK_GMAC2_U3_QPHY | MTK_INFRA)
+
+#define MT7988_CAPS  (MTK_NETSYS_V3 | MTK_INFRA)
+
+/* Frame Engine Register Bases */
+#define PDMA_V1_BASE			0x0800
+#define PDMA_V2_BASE			0x6000
+#define PDMA_V3_BASE			0x6800
+#define GDMA1_BASE			0x0500
+#define GDMA2_BASE			0x1500
+#define GDMA3_BASE			0x0540
+#define GMAC_BASE			0x10000
+#define GSW_BASE			0x20000
+
+/* Ethernet subsystem registers */
+#define ETHSYS_SYSCFG1_REG		0x14
+#define SYSCFG1_GE_MODE_S(n)		(12 + ((n) * 2))
+#define SYSCFG1_GE_MODE_M		0x3
+#define SYSCFG1_SGMII_SEL_M		GENMASK(9, 8)
+#define SYSCFG1_SGMII_SEL(gmac)		BIT(9 - (gmac))
+
+#define ETHSYS_CLKCFG0_REG		0x2c
+#define ETHSYS_TRGMII_CLK_SEL362_5	BIT(11)
+
+/* Top misc registers */
+#define TOPMISC_NETSYS_PCS_MUX		0x84
+#define NETSYS_PCS_MUX_MASK		GENMASK(1, 0)
+#define MUX_G2_USXGMII_SEL		BIT(1)
+#define MUX_HSGMII1_G1_SEL		BIT(0)
+
+#define USB_PHY_SWITCH_REG		0x218
+#define QPHY_SEL_MASK			0x3
+#define SGMII_QPHY_SEL			0x2
+
+#define MT7629_INFRA_MISC2_REG		0x70c
+#define INFRA_MISC2_BONDING_OPTION	GENMASK(15, 0)
+
+/* SYSCFG1_GE_MODE: GE Modes */
+#define GE_MODE_RGMII			0
+#define GE_MODE_MII			1
+#define GE_MODE_MII_PHY			2
+#define GE_MODE_RMII			3
+
+/* SGMII subsystem config registers */
+#define SGMSYS_PCS_CONTROL_1		0x0
+#define SGMII_LINK_STATUS		BIT(18)
+#define SGMII_AN_ENABLE			BIT(12)
+#define SGMII_AN_RESTART		BIT(9)
+
+#define SGMSYS_SGMII_MODE		0x20
+#define SGMII_AN_MODE			0x31120103
+#define SGMII_FORCE_MODE		0x31120019
+
+#define SGMSYS_QPHY_PWR_STATE_CTRL	0xe8
+#define SGMII_PHYA_PWD			BIT(4)
+
+#define SGMSYS_QPHY_WRAP_CTRL		0xec
+#define SGMII_PN_SWAP_TX_RX		0x03
+
+#define SGMSYS_GEN2_SPEED		0x2028
+#define SGMSYS_GEN2_SPEED_V2		0x128
+#define SGMSYS_SPEED_MASK		GENMASK(3, 2)
+#define SGMSYS_SPEED_2500		1
+
+/* USXGMII subsystem config registers */
+/* Register to control USXGMII XFI PLL digital */
+#define XFI_PLL_DIG_GLB8		0x08
+#define RG_XFI_PLL_EN			BIT(31)
+
+/* Register to control USXGMII XFI PLL analog */
+#define XFI_PLL_ANA_GLB8		0x108
+#define RG_XFI_PLL_ANA_SWWA		0x02283248
+
+/* Frame Engine Registers */
+#define PSE_NO_DROP_CFG_REG		0x108
+#define PSE_NO_DROP_GDM1		BIT(1)
+
+#define FE_GLO_MISC_REG			0x124
+#define PDMA_VER_V2			BIT(4)
+
+/* PDMA */
+#define TX_BASE_PTR_REG(n)		(0x000 + (n) * 0x10)
+#define TX_MAX_CNT_REG(n)		(0x004 + (n) * 0x10)
+#define TX_CTX_IDX_REG(n)		(0x008 + (n) * 0x10)
+#define TX_DTX_IDX_REG(n)		(0x00c + (n) * 0x10)
+
+#define RX_BASE_PTR_REG(n)		(0x100 + (n) * 0x10)
+#define RX_MAX_CNT_REG(n)		(0x104 + (n) * 0x10)
+#define RX_CRX_IDX_REG(n)		(0x108 + (n) * 0x10)
+#define RX_DRX_IDX_REG(n)		(0x10c + (n) * 0x10)
+
+#define PDMA_GLO_CFG_REG		0x204
+#define TX_WB_DDONE			BIT(6)
+#define RX_DMA_BUSY			BIT(3)
+#define RX_DMA_EN			BIT(2)
+#define TX_DMA_BUSY			BIT(1)
+#define TX_DMA_EN			BIT(0)
+
+#define PDMA_RST_IDX_REG		0x208
+#define RST_DRX_IDX0			BIT(16)
+#define RST_DTX_IDX0			BIT(0)
+
+/* GDMA */
+#define GDMA_IG_CTRL_REG		0x000
+#define GDM_ICS_EN			BIT(22)
+#define GDM_TCS_EN			BIT(21)
+#define GDM_UCS_EN			BIT(20)
+#define STRP_CRC			BIT(16)
+#define MYMAC_DP_S			12
+#define MYMAC_DP_M			0xf000
+#define BC_DP_S				8
+#define BC_DP_M				0xf00
+#define MC_DP_S				4
+#define MC_DP_M				0xf0
+#define UN_DP_S				0
+#define UN_DP_M				0x0f
+
+#define GDMA_EG_CTRL_REG		0x004
+#define GDMA_CPU_BRIDGE_EN		BIT(31)
+
+#define GDMA_MAC_LSB_REG		0x008
+
+#define GDMA_MAC_MSB_REG		0x00c
+
+/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */
+#define DP_PDMA				0
+#define DP_GDMA1			1
+#define DP_GDMA2			2
+#define DP_PPE				4
+#define DP_QDMA				5
+#define DP_DISCARD			7
+
+/* GMAC Registers */
+#define GMAC_PPSC_REG			0x0000
+#define PHY_MDC_CFG			GENMASK(29, 24)
+#define MDC_TURBO			BIT(20)
+#define MDC_MAX_FREQ			25000000
+#define MDC_MAX_DIVIDER			63
+
+#define GMAC_PIAC_REG			0x0004
+#define PHY_ACS_ST			BIT(31)
+#define MDIO_REG_ADDR_S			25
+#define MDIO_REG_ADDR_M			0x3e000000
+#define MDIO_PHY_ADDR_S			20
+#define MDIO_PHY_ADDR_M			0x1f00000
+#define MDIO_CMD_S			18
+#define MDIO_CMD_M			0xc0000
+#define MDIO_ST_S			16
+#define MDIO_ST_M			0x30000
+#define MDIO_RW_DATA_S			0
+#define MDIO_RW_DATA_M			0xffff
+
+#define GMAC_XGMAC_STS_REG		0x000c
+#define P1_XGMAC_FORCE_LINK		BIT(15)
+
+#define GMAC_MAC_MISC_REG		0x0010
+#define MISC_MDC_TURBO			BIT(4)
+
+#define GMAC_GSW_CFG_REG		0x0080
+#define GSWTX_IPG_M			0xF0000
+#define GSWTX_IPG_S			16
+#define GSWRX_IPG_M			0xF
+#define GSWRX_IPG_S			0
+
+/* MDIO_CMD: MDIO commands */
+#define MDIO_CMD_ADDR			0
+#define MDIO_CMD_WRITE			1
+#define MDIO_CMD_READ			2
+#define MDIO_CMD_READ_C45		3
+
+/* MDIO_ST: MDIO start field */
+#define MDIO_ST_C45			0
+#define MDIO_ST_C22			1
+
+#define GMAC_PORT_MCR(p)		(0x0100 + (p) * 0x100)
+#define MAC_RX_PKT_LEN_S		24
+#define MAC_RX_PKT_LEN_M		0x3000000
+#define IPG_CFG_S			18
+#define IPG_CFG_M			0xc0000
+#define MAC_MODE			BIT(16)
+#define FORCE_MODE			BIT(15)
+#define MAC_TX_EN			BIT(14)
+#define MAC_RX_EN			BIT(13)
+#define DEL_RXFIFO_CLR			BIT(12)
+#define BKOFF_EN			BIT(9)
+#define BACKPR_EN			BIT(8)
+#define FORCE_RX_FC			BIT(5)
+#define FORCE_TX_FC			BIT(4)
+#define FORCE_SPD_S			2
+#define FORCE_SPD_M			0x0c
+#define FORCE_DPX			BIT(1)
+#define FORCE_LINK			BIT(0)
+
+/* Values of IPG_CFG */
+#define IPG_96BIT			0
+#define IPG_96BIT_WITH_SHORT_IPG	1
+#define IPG_64BIT			2
+
+/* MAC_RX_PKT_LEN: Max RX packet length */
+#define MAC_RX_PKT_LEN_1518		0
+#define MAC_RX_PKT_LEN_1536		1
+#define MAC_RX_PKT_LEN_1552		2
+#define MAC_RX_PKT_LEN_JUMBO		3
+
+/* FORCE_SPD: Forced link speed */
+#define SPEED_10M			0
+#define SPEED_100M			1
+#define SPEED_1000M			2
+
+#define GMAC_TRGMII_RCK_CTRL		0x300
+#define RX_RST				BIT(31)
+#define RXC_DQSISEL			BIT(30)
+
+#define NUM_TRGMII_CTRL			5
+
+#define GMAC_TRGMII_TD_ODT(n)		(0x354 + (n) * 8)
+#define TD_DM_DRVN_S			4
+#define TD_DM_DRVN_M			0xf0
+#define TD_DM_DRVP_S			0
+#define TD_DM_DRVP_M			0x0f
+
+/* XGMAC Status Registers */
+#define XGMAC_STS(x)			(((x) == 2) ? 0x001C : 0x000C)
+#define XGMAC_FORCE_LINK(x)		(((x) == 1) ? BIT(31) : BIT(15))
+
+/* XGMAC Registers */
+#define XGMAC_PORT_MCR(x)		(0x2000 + (((x) - 1) * 0x1000))
+#define XGMAC_TRX_DISABLE		0xf
+#define XGMAC_FORCE_TX_FC		BIT(5)
+#define XGMAC_FORCE_RX_FC		BIT(4)
+
+/* MDIO Indirect Access Registers */
+#define MII_MMD_ACC_CTL_REG		0x0d
+#define MMD_CMD_S			14
+#define MMD_CMD_M			0xc000
+#define MMD_DEVAD_S			0
+#define MMD_DEVAD_M			0x1f
+
+/* MMD_CMD: MMD commands */
+#define MMD_ADDR			0
+#define MMD_DATA			1
+#define MMD_DATA_RW_POST_INC		2
+#define MMD_DATA_W_POST_INC		3
+
+#define MII_MMD_ADDR_DATA_REG		0x0e
+
+/* PDMA descriptors */
+struct mtk_rx_dma {
+	unsigned int rxd1;
+	unsigned int rxd2;
+	unsigned int rxd3;
+	unsigned int rxd4;
+} __packed __aligned(4);
+
+struct mtk_rx_dma_v2 {
+	unsigned int rxd1;
+	unsigned int rxd2;
+	unsigned int rxd3;
+	unsigned int rxd4;
+	unsigned int rxd5;
+	unsigned int rxd6;
+	unsigned int rxd7;
+	unsigned int rxd8;
+} __packed __aligned(4);
+
+struct mtk_tx_dma {
+	unsigned int txd1;
+	unsigned int txd2;
+	unsigned int txd3;
+	unsigned int txd4;
+} __packed __aligned(4);
+
+struct mtk_tx_dma_v2 {
+	unsigned int txd1;
+	unsigned int txd2;
+	unsigned int txd3;
+	unsigned int txd4;
+	unsigned int txd5;
+	unsigned int txd6;
+	unsigned int txd7;
+	unsigned int txd8;
+} __packed __aligned(4);
+
+/* PDMA TXD fields */
+#define PDMA_TXD2_DDONE			BIT(31)
+#define PDMA_TXD2_LS0			BIT(30)
+#define PDMA_V1_TXD2_SDL0_M		GENMASK(29, 16)
+#define PDMA_V1_TXD2_SDL0_SET(_v)	FIELD_PREP(PDMA_V1_TXD2_SDL0_M, (_v))
+#define PDMA_V2_TXD2_SDL0_M		GENMASK(23, 8)
+#define PDMA_V2_TXD2_SDL0_SET(_v)	FIELD_PREP(PDMA_V2_TXD2_SDL0_M, (_v))
+
+#define PDMA_V1_TXD4_FPORT_M		GENMASK(27, 25)
+#define PDMA_V1_TXD4_FPORT_SET(_v)	FIELD_PREP(PDMA_V1_TXD4_FPORT_M, (_v))
+#define PDMA_V2_TXD4_FPORT_M		GENMASK(27, 24)
+#define PDMA_V2_TXD4_FPORT_SET(_v)	FIELD_PREP(PDMA_V2_TXD4_FPORT_M, (_v))
+
+#define PDMA_V2_TXD5_FPORT_M		GENMASK(19, 16)
+#define PDMA_V2_TXD5_FPORT_SET(_v)	FIELD_PREP(PDMA_V2_TXD5_FPORT_M, (_v))
+
+/* PDMA RXD fields */
+#define PDMA_RXD2_DDONE			BIT(31)
+#define PDMA_RXD2_LS0			BIT(30)
+#define PDMA_V1_RXD2_PLEN0_M		GENMASK(29, 16)
+#define PDMA_V1_RXD2_PLEN0_GET(_v)	FIELD_GET(PDMA_V1_RXD2_PLEN0_M, (_v))
+#define PDMA_V1_RXD2_PLEN0_SET(_v)	FIELD_PREP(PDMA_V1_RXD2_PLEN0_M, (_v))
+#define PDMA_V2_RXD2_PLEN0_M		GENMASK(23, 8)
+#define PDMA_V2_RXD2_PLEN0_GET(_v)	FIELD_GET(PDMA_V2_RXD2_PLEN0_M, (_v))
+#define PDMA_V2_RXD2_PLEN0_SET(_v)	FIELD_PREP(PDMA_V2_RXD2_PLEN0_M, (_v))
+
+void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set);
+void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set);
+void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set);
+
+int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg);
+int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data);
+int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg);
+int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
+		  u16 val);
+int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg);
+int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
+		      u16 val);
+
+#endif /* _MTK_ETH_H_ */
