[openwrt/openwrt] mediatek: backport pending Ethernet PHY driver patches

LEDE Commits lede-commits at lists.infradead.org
Wed Aug 21 16:27:19 PDT 2024


dangole pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/1069514978c419cc5bdfc18c5670b46d0443a686

commit 1069514978c419cc5bdfc18c5670b46d0443a686
Author: Daniel Golle <daniel at makrotopia.org>
AuthorDate: Tue Aug 20 17:20:29 2024 +0100

    mediatek: backport pending Ethernet PHY driver patches
    
    Use pending patchset for 2.5GE PHY driver, unifying LED handling
    accross all MediaTek Ethernet PHYs.
    
    Signed-off-by: Daniel Golle <daniel at makrotopia.org>
---
 .../arch/arm64/boot/dts/mediatek/mt7988a.dtsi      |   17 +
 .../files-6.6/drivers/net/phy/mediatek-2p5ge.c     |  321 --
 target/linux/mediatek/filogic/config-6.6           |    2 +-
 ...iatek-Re-organize-MediaTek-ethernet-phy-d.patch | 3513 ++++++++++++++++++++
 ...iatek-Fix-spelling-errors-and-rearrange-v.patch |   62 +
 ...iatek-Move-LED-helper-functions-into-mtk-.patch |  742 +++++
 ...iatek-Improve-readability-of-mtk-phy-lib..patch |   70 +
 ...iatek-Integrate-read-write-page-helper-fu.patch |  141 +
 ...iatek-Hook-LED-helper-functions-in-mtk-ge.patch |  146 +
 ...ediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch |   54 +
 ...ediatek-Change-mtk-ge-soc.c-line-wrapping.patch |  182 +
 ...iatek-Add-token-ring-access-helper-functi.patch |  614 ++++
 ...-mediatek-Extend-1G-TX-RX-link-pulse-time.patch |  209 ++
 ...-driver-for-built-in-2.5G-ethernet-PHY-on.patch |  477 +++
 ...iatek-Fix-alignment-in-callback-functions.patch |  130 +
 ...iatek-Remove-unnecessary-outer-parens-of-.patch |   65 +
 ...-net-phy-add-driver-for-MediaTek-2.5G-PHY.patch |   39 -
 17 files changed, 6423 insertions(+), 361 deletions(-)

diff --git a/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a.dtsi
index 9ad068fe05..6a15dcff3d 100644
--- a/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a.dtsi
+++ b/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a.dtsi
@@ -1490,6 +1490,23 @@
 					compatible = "ethernet-phy-ieee802.3-c45";
 					reg = <15>;
 					phy-mode = "internal";
+
+					leds {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						i2p5gbe_led0: i2p5gbe-led0 at 0 {
+							reg = <0>;
+							function = LED_FUNCTION_LAN;
+							status = "disabled";
+						};
+
+						i2p5gbe_led1: i2p5gbe-led1 at 1 {
+							reg = <1>;
+							function = LED_FUNCTION_LAN;
+							status = "disabled";
+						};
+					};
 				};
 			};
 		};
diff --git a/target/linux/mediatek/files-6.6/drivers/net/phy/mediatek-2p5ge.c b/target/linux/mediatek/files-6.6/drivers/net/phy/mediatek-2p5ge.c
deleted file mode 100644
index d1d01190ed..0000000000
--- a/target/linux/mediatek/files-6.6/drivers/net/phy/mediatek-2p5ge.c
+++ /dev/null
@@ -1,321 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#include <linux/bitfield.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/nvmem-consumer.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/pinctrl/consumer.h>
-#include <linux/phy.h>
-#include <linux/pm_domain.h>
-#include <linux/pm_runtime.h>
-
-#define MT7988_2P5GE_PMB "mediatek/mt7988/i2p5ge-phy-pmb.bin"
-
-#define MD32_EN					BIT(0)
-#define PMEM_PRIORITY				BIT(8)
-#define DMEM_PRIORITY				BIT(16)
-
-#define BASE100T_STATUS_EXTEND			0x10
-#define BASE1000T_STATUS_EXTEND			0x11
-#define EXTEND_CTRL_AND_STATUS			0x16
-
-#define PHY_AUX_CTRL_STATUS			0x1d
-#define   PHY_AUX_DPX_MASK			GENMASK(5, 5)
-#define   PHY_AUX_SPEED_MASK			GENMASK(4, 2)
-
-/* Registers on MDIO_MMD_VEND1 */
-#define MTK_PHY_LINK_STATUS_MISC		0xa2
-#define   MTK_PHY_FDX_ENABLE			BIT(5)
-
-#define MTK_PHY_LPI_PCS_DSP_CTRL		0x121
-#define   MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK	GENMASK(12, 8)
-
-/* Registers on MDIO_MMD_VEND2 */
-#define MTK_PHY_LED0_ON_CTRL			0x24
-#define   MTK_PHY_LED0_ON_LINK1000		BIT(0)
-#define   MTK_PHY_LED0_ON_LINK100		BIT(1)
-#define   MTK_PHY_LED0_ON_LINK10		BIT(2)
-#define   MTK_PHY_LED0_ON_LINK2500		BIT(7)
-#define   MTK_PHY_LED0_POLARITY			BIT(14)
-
-#define MTK_PHY_LED1_ON_CTRL			0x26
-#define   MTK_PHY_LED1_ON_FDX			BIT(4)
-#define   MTK_PHY_LED1_ON_HDX			BIT(5)
-#define   MTK_PHY_LED1_POLARITY			BIT(14)
-
-#define MTK_EXT_PAGE_ACCESS			0x1f
-#define MTK_PHY_PAGE_STANDARD			0x0000
-#define MTK_PHY_PAGE_EXTENDED_52B5		0x52b5
-
-struct mtk_i2p5ge_phy_priv {
-	bool fw_loaded;
-};
-
-enum {
-	PHY_AUX_SPD_10 = 0,
-	PHY_AUX_SPD_100,
-	PHY_AUX_SPD_1000,
-	PHY_AUX_SPD_2500,
-};
-
-static int mtk_2p5ge_phy_read_page(struct phy_device *phydev)
-{
-	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-}
-
-static int mtk_2p5ge_phy_write_page(struct phy_device *phydev, int page)
-{
-	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-}
-
-static int mt7988_2p5ge_phy_probe(struct phy_device *phydev)
-{
-	struct mtk_i2p5ge_phy_priv *phy_priv;
-
-	phy_priv = devm_kzalloc(&phydev->mdio.dev,
-				sizeof(struct mtk_i2p5ge_phy_priv), GFP_KERNEL);
-	if (!phy_priv)
-		return -ENOMEM;
-
-	phydev->priv = phy_priv;
-
-	return 0;
-}
-
-static int mt7988_2p5ge_phy_config_init(struct phy_device *phydev)
-{
-	int ret, i;
-	const struct firmware *fw;
-	struct device *dev = &phydev->mdio.dev;
-	struct device_node *np;
-	void __iomem *pmb_addr;
-	void __iomem *md32_en_cfg_base;
-	struct mtk_i2p5ge_phy_priv *phy_priv = phydev->priv;
-	u16 reg;
-	struct pinctrl *pinctrl;
-
-	if (!phy_priv->fw_loaded) {
-		np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw");
-		if (!np)
-			return -ENOENT;
-		pmb_addr = of_iomap(np, 0);
-		if (!pmb_addr)
-			return -ENOMEM;
-		md32_en_cfg_base = of_iomap(np, 1);
-		if (!md32_en_cfg_base)
-			return -ENOMEM;
-
-		ret = request_firmware(&fw, MT7988_2P5GE_PMB, dev);
-		if (ret) {
-			dev_err(dev, "failed to load firmware: %s, ret: %d\n",
-				MT7988_2P5GE_PMB, ret);
-			return ret;
-		}
-
-		reg = readw(md32_en_cfg_base);
-		if (reg & MD32_EN) {
-			phy_set_bits(phydev, 0, BIT(15));
-			usleep_range(10000, 11000);
-		}
-		phy_set_bits(phydev, 0, BIT(11));
-
-		/* Write magic number to safely stall MCU */
-		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800e, 0x1100);
-		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800f, 0x00df);
-
-		for (i = 0; i < fw->size - 1; i += 4)
-			writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
-		release_firmware(fw);
-
-		writew(reg & ~MD32_EN, md32_en_cfg_base);
-		writew(reg | MD32_EN, md32_en_cfg_base);
-		phy_set_bits(phydev, 0, BIT(15));
-		dev_info(dev, "Firmware loading/trigger ok.\n");
-
-		phy_priv->fw_loaded = true;
-	}
-
-	/* Setup LED */
-
-	/* Set polarity of led0 to active-high for BPI-R4 */
-	phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
-			 MTK_PHY_LED0_POLARITY);
-
-	phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
-			 MTK_PHY_LED0_ON_LINK10 |
-			 MTK_PHY_LED0_ON_LINK100 |
-			 MTK_PHY_LED0_ON_LINK1000 |
-			 MTK_PHY_LED0_ON_LINK2500);
-	phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL,
-			 MTK_PHY_LED1_ON_FDX | MTK_PHY_LED1_ON_HDX);
-
-	pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "i2p5gbe-led");
-	if (IS_ERR(pinctrl)) {
-		dev_err(&phydev->mdio.dev, "Fail to set LED pins!\n");
-		return PTR_ERR(pinctrl);
-	}
-
-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL,
-		       MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0);
-
-	/* Enable 16-bit next page exchange bit if 1000-BT isn't advertizing */
-	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-	__phy_write(phydev, 0x11, 0xfbfa);
-	__phy_write(phydev, 0x12, 0xc3);
-	__phy_write(phydev, 0x10, 0x87f8);
-	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
-	return 0;
-}
-
-static int mt7988_2p5ge_phy_config_aneg(struct phy_device *phydev)
-{
-	bool changed = false;
-	u32 adv;
-	int ret;
-
-	if (phydev->autoneg == AUTONEG_DISABLE) {
-		/* Configure half duplex with genphy_setup_forced,
-		 * because genphy_c45_pma_setup_forced does not support.
-		 */
-		return phydev->duplex != DUPLEX_FULL
-			? genphy_setup_forced(phydev)
-			: genphy_c45_pma_setup_forced(phydev);
-	}
-
-	ret = genphy_c45_an_config_aneg(phydev);
-	if (ret < 0)
-		return ret;
-	if (ret > 0)
-		changed = true;
-
-	adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
-	ret = phy_modify_changed(phydev, MII_CTRL1000,
-				 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
-				 adv);
-	if (ret < 0)
-		return ret;
-	if (ret > 0)
-		changed = true;
-
-	return genphy_c45_check_and_restart_aneg(phydev, changed);
-}
-
-static int mt7988_2p5ge_phy_get_features(struct phy_device *phydev)
-{
-	int ret;
-
-	ret = genphy_read_abilities(phydev);
-	if (ret)
-		return ret;
-
-	/* We don't support HDX at MAC layer on mt7988.
-	 * So mask phy's HDX capabilities, too.
-	 */
-	linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
-			 phydev->supported);
-	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
-			 phydev->supported);
-	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-			 phydev->supported);
-	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-			 phydev->supported);
-	linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
-
-	return 0;
-}
-
-static int mt7988_2p5ge_phy_read_status(struct phy_device *phydev)
-{
-	int ret;
-
-	ret = genphy_update_link(phydev);
-	if (ret)
-		return ret;
-
-	phydev->speed = SPEED_UNKNOWN;
-	phydev->duplex = DUPLEX_UNKNOWN;
-	phydev->pause = 0;
-	phydev->asym_pause = 0;
-
-	if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
-		ret = genphy_c45_read_lpa(phydev);
-		if (ret < 0)
-			return ret;
-
-		/* Read the link partner's 1G advertisement */
-		ret = phy_read(phydev, MII_STAT1000);
-		if (ret < 0)
-			return ret;
-		mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
-	} else if (phydev->autoneg == AUTONEG_DISABLE) {
-		linkmode_zero(phydev->lp_advertising);
-	}
-
-	ret = phy_read(phydev, PHY_AUX_CTRL_STATUS);
-	if (ret < 0)
-		return ret;
-
-	switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) {
-	case PHY_AUX_SPD_10:
-		phydev->speed = SPEED_10;
-		break;
-	case PHY_AUX_SPD_100:
-		phydev->speed = SPEED_100;
-		break;
-	case PHY_AUX_SPD_1000:
-		phydev->speed = SPEED_1000;
-		break;
-	case PHY_AUX_SPD_2500:
-		phydev->speed = SPEED_2500;
-		break;
-	}
-
-	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_MISC);
-	if (ret < 0)
-		return ret;
-
-	phydev->duplex = (ret & MTK_PHY_FDX_ENABLE) ? DUPLEX_FULL : DUPLEX_HALF;
-	/* FIXME: The current firmware always enables rate adaptation mode. */
-	phydev->rate_matching = RATE_MATCH_PAUSE;
-
-	return 0;
-}
-
-static int mt7988_2p5ge_phy_get_rate_matching(struct phy_device *phydev,
-					      phy_interface_t iface)
-{
-	return RATE_MATCH_PAUSE;
-}
-
-static struct phy_driver mtk_gephy_driver[] = {
-	{
-		PHY_ID_MATCH_MODEL(0x00339c11),
-		.name		= "MediaTek MT798x 2.5GbE PHY",
-		.probe		= mt7988_2p5ge_phy_probe,
-		.config_init	= mt7988_2p5ge_phy_config_init,
-		.config_aneg    = mt7988_2p5ge_phy_config_aneg,
-		.get_features	= mt7988_2p5ge_phy_get_features,
-		.read_status	= mt7988_2p5ge_phy_read_status,
-		.get_rate_matching	= mt7988_2p5ge_phy_get_rate_matching,
-		.suspend	= genphy_suspend,
-		.resume		= genphy_resume,
-		.read_page	= mtk_2p5ge_phy_read_page,
-		.write_page	= mtk_2p5ge_phy_write_page,
-	},
-};
-
-module_phy_driver(mtk_gephy_driver);
-
-static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
-	{ PHY_ID_MATCH_VENDOR(0x00339c00) },
-	{ }
-};
-
-MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
-MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang at mediatek.com>");
-MODULE_LICENSE("GPL");
-
-MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);
-MODULE_FIRMWARE(MT7988_2P5GE_PMB);
diff --git a/target/linux/mediatek/filogic/config-6.6 b/target/linux/mediatek/filogic/config-6.6
index 6d9d42853b..cb36d74e1d 100644
--- a/target/linux/mediatek/filogic/config-6.6
+++ b/target/linux/mediatek/filogic/config-6.6
@@ -240,7 +240,7 @@ CONFIG_MAXLINEAR_GPHY=y
 CONFIG_MDIO_BUS=y
 CONFIG_MDIO_DEVICE=y
 CONFIG_MDIO_DEVRES=y
-CONFIG_MEDIATEK_2P5G_PHY=y
+CONFIG_MEDIATEK_2P5GE_PHY=y
 CONFIG_MEDIATEK_GE_PHY=y
 CONFIG_MEDIATEK_GE_SOC_PHY=y
 CONFIG_MEDIATEK_WATCHDOG=y
diff --git a/target/linux/mediatek/patches-6.6/733-01-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch b/target/linux/mediatek/patches-6.6/733-01-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch
new file mode 100644
index 0000000000..3ec756bb4b
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-01-net-phy-mediatek-Re-organize-MediaTek-ethernet-phy-d.patch
@@ -0,0 +1,3513 @@
+From c14e7c954fd752fbb3da17a8bcf65cd9dbf41186 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:05 +0800
+Subject: [PATCH 01/13] net: phy: mediatek: Re-organize MediaTek ethernet phy
+ drivers
+
+Re-organize MediaTek ethernet phy driver files and get ready to integrate
+some common functions and add new 2.5G phy driver.
+mtk-ge.c: MT7530 Gphy on MT7621 & MT7531 Gphy
+mtk-ge-soc.c: Built-in Gphy on MT7981 & Built-in switch Gphy on MT7988
+mtk-2p5ge.c: Planned for built-in 2.5G phy on MT7988
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/Kconfig                       | 17 +-------------
+ drivers/net/phy/Makefile                      |  3 +--
+ drivers/net/phy/mediatek/Kconfig              | 22 +++++++++++++++++++
+ drivers/net/phy/mediatek/Makefile             |  3 +++
+ .../mtk-ge-soc.c}                             |  0
+ .../phy/{mediatek-ge.c => mediatek/mtk-ge.c}  |  0
+ 7 files changed, 29 insertions(+), 20 deletions(-)
+ create mode 100644 drivers/net/phy/mediatek/Kconfig
+ create mode 100644 drivers/net/phy/mediatek/Makefile
+ rename drivers/net/phy/{mediatek-ge-soc.c => mediatek/mtk-ge-soc.c} (100%)
+ rename drivers/net/phy/{mediatek-ge.c => mediatek/mtk-ge.c} (100%)
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -313,22 +313,7 @@ config MAXLINEAR_GPHY
+ 	  Support for the Maxlinear GPY115, GPY211, GPY212, GPY215,
+ 	  GPY241, GPY245 PHYs.
+ 
+-config MEDIATEK_GE_PHY
+-	tristate "MediaTek Gigabit Ethernet PHYs"
+-	help
+-	  Supports the MediaTek Gigabit Ethernet PHYs.
+-
+-config MEDIATEK_GE_SOC_PHY
+-	tristate "MediaTek SoC Ethernet PHYs"
+-	depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
+-	depends on NVMEM_MTK_EFUSE
+-	help
+-	  Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+-
+-	  Include support for built-in Ethernet PHYs which are present in
+-	  the MT7981 and MT7988 SoCs. These PHYs need calibration data
+-	  present in the SoCs efuse and will dynamically calibrate VCM
+-	  (common-mode voltage) during startup.
++source "drivers/net/phy/mediatek/Kconfig"
+ 
+ config MICREL_PHY
+ 	tristate "Micrel PHYs"
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -82,8 +82,7 @@ obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+ obj-$(CONFIG_MARVELL_88Q2XXX_PHY)	+= marvell-88q2xxx.o
+ obj-$(CONFIG_MARVELL_88X2222_PHY)	+= marvell-88x2222.o
+ obj-$(CONFIG_MAXLINEAR_GPHY)	+= mxl-gpy.o
+-obj-$(CONFIG_MEDIATEK_GE_PHY)	+= mediatek-ge.o
+-obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)	+= mediatek-ge-soc.o
++obj-y				+= mediatek/
+ obj-$(CONFIG_MESON_GXL_PHY)	+= meson-gxl.o
+ obj-$(CONFIG_MICREL_KS8995MA)	+= spi_ks8995.o
+ obj-$(CONFIG_MICREL_PHY)	+= micrel.o
+--- /dev/null
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -0,0 +1,22 @@
++# SPDX-License-Identifier: GPL-2.0-only
++config MEDIATEK_GE_PHY
++	tristate "MediaTek Gigabit Ethernet PHYs"
++	help
++	  Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
++
++	  Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531.
++	  You may find mt7530 inside mt7621. This driver shares some
++	  common operations with MediaTek SoC built-in Gigabit
++	  Ethernet PHYs.
++
++config MEDIATEK_GE_SOC_PHY
++	tristate "MediaTek SoC Ethernet PHYs"
++	depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
++	select NVMEM_MTK_EFUSE
++	help
++	  Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
++
++	  Include support for built-in Ethernet PHYs which are present in
++	  the MT7981 and MT7988 SoCs. These PHYs need calibration data
++	  present in the SoCs efuse and will dynamically calibrate VCM
++	  (common-mode voltage) during startup.
+--- /dev/null
++++ b/drivers/net/phy/mediatek/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_MEDIATEK_GE_PHY)		+= mtk-ge.o
++obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)	+= mtk-ge-soc.o
+--- a/drivers/net/phy/mediatek-ge-soc.c
++++ /dev/null
+@@ -1,1555 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0+
+-#include <linux/bitfield.h>
+-#include <linux/bitmap.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/module.h>
+-#include <linux/nvmem-consumer.h>
+-#include <linux/pinctrl/consumer.h>
+-#include <linux/phy.h>
+-#include <linux/regmap.h>
+-
+-#define MTK_GPHY_ID_MT7981			0x03a29461
+-#define MTK_GPHY_ID_MT7988			0x03a29481
+-
+-#define MTK_EXT_PAGE_ACCESS			0x1f
+-#define MTK_PHY_PAGE_STANDARD			0x0000
+-#define MTK_PHY_PAGE_EXTENDED_3			0x0003
+-
+-#define MTK_PHY_LPI_REG_14			0x14
+-#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK	GENMASK(8, 0)
+-
+-#define MTK_PHY_LPI_REG_1c			0x1c
+-#define MTK_PHY_SMI_DET_ON_THRESH_MASK		GENMASK(13, 8)
+-
+-#define MTK_PHY_PAGE_EXTENDED_2A30		0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5		0x52b5
+-
+-#define ANALOG_INTERNAL_OPERATION_MAX_US	20
+-#define TXRESERVE_MIN				0
+-#define TXRESERVE_MAX				7
+-
+-#define MTK_PHY_ANARG_RG			0x10
+-#define   MTK_PHY_TCLKOFFSET_MASK		GENMASK(12, 8)
+-
+-/* Registers on MDIO_MMD_VEND1 */
+-#define MTK_PHY_TXVLD_DA_RG			0x12
+-#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK	GENMASK(15, 10)
+-#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK	GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_A2		0x16
+-#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK	GENMASK(15, 10)
+-#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK	GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_B1		0x17
+-#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK	GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK	GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_B2		0x18
+-#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK	GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK	GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_C1		0x19
+-#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK	GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK	GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_C2		0x20
+-#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK	GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK	GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_D1		0x21
+-#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK	GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK	GENMASK(5, 0)
+-
+-#define MTK_PHY_TX_I2MPB_TEST_MODE_D2		0x22
+-#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK	GENMASK(13, 8)
+-#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK	GENMASK(5, 0)
+-
+-#define MTK_PHY_RXADC_CTRL_RG7			0xc6
+-#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK	GENMASK(9, 8)
+-
+-#define MTK_PHY_RXADC_CTRL_RG9			0xc8
+-#define   MTK_PHY_DA_RX_PSBN_TBT_MASK		GENMASK(14, 12)
+-#define   MTK_PHY_DA_RX_PSBN_HBT_MASK		GENMASK(10, 8)
+-#define   MTK_PHY_DA_RX_PSBN_GBE_MASK		GENMASK(6, 4)
+-#define   MTK_PHY_DA_RX_PSBN_LP_MASK		GENMASK(2, 0)
+-
+-#define MTK_PHY_LDO_OUTPUT_V			0xd7
+-
+-#define MTK_PHY_RG_ANA_CAL_RG0			0xdb
+-#define   MTK_PHY_RG_CAL_CKINV			BIT(12)
+-#define   MTK_PHY_RG_ANA_CALEN			BIT(8)
+-#define   MTK_PHY_RG_ZCALEN_A			BIT(0)
+-
+-#define MTK_PHY_RG_ANA_CAL_RG1			0xdc
+-#define   MTK_PHY_RG_ZCALEN_B			BIT(12)
+-#define   MTK_PHY_RG_ZCALEN_C			BIT(8)
+-#define   MTK_PHY_RG_ZCALEN_D			BIT(4)
+-#define   MTK_PHY_RG_TXVOS_CALEN		BIT(0)
+-
+-#define MTK_PHY_RG_ANA_CAL_RG5			0xe0
+-#define   MTK_PHY_RG_REXT_TRIM_MASK		GENMASK(13, 8)
+-
+-#define MTK_PHY_RG_TX_FILTER			0xfe
+-
+-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120	0x120
+-#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK	GENMASK(12, 8)
+-#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK	GENMASK(4, 0)
+-
+-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122	0x122
+-#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK	GENMASK(7, 0)
+-
+-#define MTK_PHY_RG_TESTMUX_ADC_CTRL		0x144
+-#define   MTK_PHY_RG_TXEN_DIG_MASK		GENMASK(5, 5)
+-
+-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B		0x172
+-#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK	GENMASK(13, 8)
+-#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK	GENMASK(6, 0)
+-
+-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D		0x173
+-#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK	GENMASK(13, 8)
+-#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK	GENMASK(6, 0)
+-
+-#define MTK_PHY_RG_AD_CAL_COMP			0x17a
+-#define   MTK_PHY_AD_CAL_COMP_OUT_SHIFT		(8)
+-
+-#define MTK_PHY_RG_AD_CAL_CLK			0x17b
+-#define   MTK_PHY_DA_CAL_CLK			BIT(0)
+-
+-#define MTK_PHY_RG_AD_CALIN			0x17c
+-#define   MTK_PHY_DA_CALIN_FLAG			BIT(0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_A		0x17d
+-#define   MTK_PHY_DASN_DAC_IN0_A_MASK		GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_B		0x17e
+-#define   MTK_PHY_DASN_DAC_IN0_B_MASK		GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_C		0x17f
+-#define   MTK_PHY_DASN_DAC_IN0_C_MASK		GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN0_D		0x180
+-#define   MTK_PHY_DASN_DAC_IN0_D_MASK		GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_A		0x181
+-#define   MTK_PHY_DASN_DAC_IN1_A_MASK		GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_B		0x182
+-#define   MTK_PHY_DASN_DAC_IN1_B_MASK		GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_C		0x183
+-#define   MTK_PHY_DASN_DAC_IN1_C_MASK		GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DASN_DAC_IN1_D		0x184
+-#define   MTK_PHY_DASN_DAC_IN1_D_MASK		GENMASK(9, 0)
+-
+-#define MTK_PHY_RG_DEV1E_REG19b			0x19b
+-#define   MTK_PHY_BYPASS_DSP_LPI_READY		BIT(8)
+-
+-#define MTK_PHY_RG_LP_IIR2_K1_L			0x22a
+-#define MTK_PHY_RG_LP_IIR2_K1_U			0x22b
+-#define MTK_PHY_RG_LP_IIR2_K2_L			0x22c
+-#define MTK_PHY_RG_LP_IIR2_K2_U			0x22d
+-#define MTK_PHY_RG_LP_IIR2_K3_L			0x22e
+-#define MTK_PHY_RG_LP_IIR2_K3_U			0x22f
+-#define MTK_PHY_RG_LP_IIR2_K4_L			0x230
+-#define MTK_PHY_RG_LP_IIR2_K4_U			0x231
+-#define MTK_PHY_RG_LP_IIR2_K5_L			0x232
+-#define MTK_PHY_RG_LP_IIR2_K5_U			0x233
+-
+-#define MTK_PHY_RG_DEV1E_REG234			0x234
+-#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK		GENMASK(0, 0)
+-#define   MTK_PHY_LPF_X_AVERAGE_MASK		GENMASK(7, 4)
+-#define   MTK_PHY_TR_LP_IIR_EEE_EN		BIT(12)
+-
+-#define MTK_PHY_RG_LPF_CNT_VAL			0x235
+-
+-#define MTK_PHY_RG_DEV1E_REG238			0x238
+-#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK	GENMASK(8, 0)
+-#define   MTK_PHY_LPI_SLV_SEND_TX_EN		BIT(12)
+-
+-#define MTK_PHY_RG_DEV1E_REG239			0x239
+-#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK	GENMASK(8, 0)
+-#define   MTK_PHY_LPI_TXPCS_LOC_RCV		BIT(12)
+-
+-#define MTK_PHY_RG_DEV1E_REG27C			0x27c
+-#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK	GENMASK(12, 8)
+-#define MTK_PHY_RG_DEV1E_REG27D			0x27d
+-#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK	GENMASK(4, 0)
+-
+-#define MTK_PHY_RG_DEV1E_REG2C7			0x2c7
+-#define   MTK_PHY_MAX_GAIN_MASK			GENMASK(4, 0)
+-#define   MTK_PHY_MIN_GAIN_MASK			GENMASK(12, 8)
+-
+-#define MTK_PHY_RG_DEV1E_REG2D1			0x2d1
+-#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK	GENMASK(7, 0)
+-#define   MTK_PHY_LPI_SKIP_SD_SLV_TR		BIT(8)
+-#define   MTK_PHY_LPI_TR_READY			BIT(9)
+-#define   MTK_PHY_LPI_VCO_EEE_STG0_EN		BIT(10)
+-
+-#define MTK_PHY_RG_DEV1E_REG323			0x323
+-#define   MTK_PHY_EEE_WAKE_MAS_INT_DC		BIT(0)
+-#define   MTK_PHY_EEE_WAKE_SLV_INT_DC		BIT(4)
+-
+-#define MTK_PHY_RG_DEV1E_REG324			0x324
+-#define   MTK_PHY_SMI_DETCNT_MAX_MASK		GENMASK(5, 0)
+-#define   MTK_PHY_SMI_DET_MAX_EN		BIT(8)
+-
+-#define MTK_PHY_RG_DEV1E_REG326			0x326
+-#define   MTK_PHY_LPI_MODE_SD_ON		BIT(0)
+-#define   MTK_PHY_RESET_RANDUPD_CNT		BIT(1)
+-#define   MTK_PHY_TREC_UPDATE_ENAB_CLR		BIT(2)
+-#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF	BIT(4)
+-#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP	BIT(5)
+-
+-#define MTK_PHY_LDO_PUMP_EN_PAIRAB		0x502
+-#define MTK_PHY_LDO_PUMP_EN_PAIRCD		0x503
+-
+-#define MTK_PHY_DA_TX_R50_PAIR_A		0x53d
+-#define MTK_PHY_DA_TX_R50_PAIR_B		0x53e
+-#define MTK_PHY_DA_TX_R50_PAIR_C		0x53f
+-#define MTK_PHY_DA_TX_R50_PAIR_D		0x540
+-
+-/* Registers on MDIO_MMD_VEND2 */
+-#define MTK_PHY_LED0_ON_CTRL			0x24
+-#define MTK_PHY_LED1_ON_CTRL			0x26
+-#define   MTK_PHY_LED_ON_MASK			GENMASK(6, 0)
+-#define   MTK_PHY_LED_ON_LINK1000		BIT(0)
+-#define   MTK_PHY_LED_ON_LINK100		BIT(1)
+-#define   MTK_PHY_LED_ON_LINK10			BIT(2)
+-#define   MTK_PHY_LED_ON_LINK			(MTK_PHY_LED_ON_LINK10 |\
+-						 MTK_PHY_LED_ON_LINK100 |\
+-						 MTK_PHY_LED_ON_LINK1000)
+-#define   MTK_PHY_LED_ON_LINKDOWN		BIT(3)
+-#define   MTK_PHY_LED_ON_FDX			BIT(4) /* Full duplex */
+-#define   MTK_PHY_LED_ON_HDX			BIT(5) /* Half duplex */
+-#define   MTK_PHY_LED_ON_FORCE_ON		BIT(6)
+-#define   MTK_PHY_LED_ON_POLARITY		BIT(14)
+-#define   MTK_PHY_LED_ON_ENABLE			BIT(15)
+-
+-#define MTK_PHY_LED0_BLINK_CTRL			0x25
+-#define MTK_PHY_LED1_BLINK_CTRL			0x27
+-#define   MTK_PHY_LED_BLINK_1000TX		BIT(0)
+-#define   MTK_PHY_LED_BLINK_1000RX		BIT(1)
+-#define   MTK_PHY_LED_BLINK_100TX		BIT(2)
+-#define   MTK_PHY_LED_BLINK_100RX		BIT(3)
+-#define   MTK_PHY_LED_BLINK_10TX		BIT(4)
+-#define   MTK_PHY_LED_BLINK_10RX		BIT(5)
+-#define   MTK_PHY_LED_BLINK_RX			(MTK_PHY_LED_BLINK_10RX |\
+-						 MTK_PHY_LED_BLINK_100RX |\
+-						 MTK_PHY_LED_BLINK_1000RX)
+-#define   MTK_PHY_LED_BLINK_TX			(MTK_PHY_LED_BLINK_10TX |\
+-						 MTK_PHY_LED_BLINK_100TX |\
+-						 MTK_PHY_LED_BLINK_1000TX)
+-#define   MTK_PHY_LED_BLINK_COLLISION		BIT(6)
+-#define   MTK_PHY_LED_BLINK_RX_CRC_ERR		BIT(7)
+-#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR		BIT(8)
+-#define   MTK_PHY_LED_BLINK_FORCE_BLINK		BIT(9)
+-
+-#define MTK_PHY_LED1_DEFAULT_POLARITIES		BIT(1)
+-
+-#define MTK_PHY_RG_BG_RASEL			0x115
+-#define   MTK_PHY_RG_BG_RASEL_MASK		GENMASK(2, 0)
+-
+-/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
+-#define RG_GPIO_MISC_TPBANK0			0x6f0
+-#define   RG_GPIO_MISC_TPBANK0_BOOTMODE		GENMASK(11, 8)
+-
+-/* These macro privides efuse parsing for internal phy. */
+-#define EFS_DA_TX_I2MPB_A(x)			(((x) >> 0) & GENMASK(5, 0))
+-#define EFS_DA_TX_I2MPB_B(x)			(((x) >> 6) & GENMASK(5, 0))
+-#define EFS_DA_TX_I2MPB_C(x)			(((x) >> 12) & GENMASK(5, 0))
+-#define EFS_DA_TX_I2MPB_D(x)			(((x) >> 18) & GENMASK(5, 0))
+-#define EFS_DA_TX_AMP_OFFSET_A(x)		(((x) >> 24) & GENMASK(5, 0))
+-
+-#define EFS_DA_TX_AMP_OFFSET_B(x)		(((x) >> 0) & GENMASK(5, 0))
+-#define EFS_DA_TX_AMP_OFFSET_C(x)		(((x) >> 6) & GENMASK(5, 0))
+-#define EFS_DA_TX_AMP_OFFSET_D(x)		(((x) >> 12) & GENMASK(5, 0))
+-#define EFS_DA_TX_R50_A(x)			(((x) >> 18) & GENMASK(5, 0))
+-#define EFS_DA_TX_R50_B(x)			(((x) >> 24) & GENMASK(5, 0))
+-
+-#define EFS_DA_TX_R50_C(x)			(((x) >> 0) & GENMASK(5, 0))
+-#define EFS_DA_TX_R50_D(x)			(((x) >> 6) & GENMASK(5, 0))
+-
+-#define EFS_RG_BG_RASEL(x)			(((x) >> 4) & GENMASK(2, 0))
+-#define EFS_RG_REXT_TRIM(x)			(((x) >> 7) & GENMASK(5, 0))
+-
+-enum {
+-	NO_PAIR,
+-	PAIR_A,
+-	PAIR_B,
+-	PAIR_C,
+-	PAIR_D,
+-};
+-
+-enum calibration_mode {
+-	EFUSE_K,
+-	SW_K
+-};
+-
+-enum CAL_ITEM {
+-	REXT,
+-	TX_OFFSET,
+-	TX_AMP,
+-	TX_R50,
+-	TX_VCM
+-};
+-
+-enum CAL_MODE {
+-	EFUSE_M,
+-	SW_M
+-};
+-
+-#define MTK_PHY_LED_STATE_FORCE_ON	0
+-#define MTK_PHY_LED_STATE_FORCE_BLINK	1
+-#define MTK_PHY_LED_STATE_NETDEV	2
+-
+-struct mtk_socphy_priv {
+-	unsigned long		led_state;
+-};
+-
+-struct mtk_socphy_shared {
+-	u32			boottrap;
+-	struct mtk_socphy_priv	priv[4];
+-};
+-
+-static int mtk_socphy_read_page(struct phy_device *phydev)
+-{
+-	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_socphy_write_page(struct phy_device *phydev, int page)
+-{
+-	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+-/* One calibration cycle consists of:
+- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
+- *   until AD_CAL_COMP is ready to output calibration result.
+- * 2.Wait until DA_CAL_CLK is available.
+- * 3.Fetch AD_CAL_COMP_OUT.
+- */
+-static int cal_cycle(struct phy_device *phydev, int devad,
+-		     u32 regnum, u16 mask, u16 cal_val)
+-{
+-	int reg_val;
+-	int ret;
+-
+-	phy_modify_mmd(phydev, devad, regnum,
+-		       mask, cal_val);
+-	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+-			 MTK_PHY_DA_CALIN_FLAG);
+-
+-	ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
+-					MTK_PHY_RG_AD_CAL_CLK, reg_val,
+-					reg_val & MTK_PHY_DA_CAL_CLK, 500,
+-					ANALOG_INTERNAL_OPERATION_MAX_US, false);
+-	if (ret) {
+-		phydev_err(phydev, "Calibration cycle timeout\n");
+-		return ret;
+-	}
+-
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+-			   MTK_PHY_DA_CALIN_FLAG);
+-	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >>
+-			   MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
+-	phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
+-
+-	return ret;
+-}
+-
+-static int rext_fill_result(struct phy_device *phydev, u16 *buf)
+-{
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+-		       MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
+-		       MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
+-
+-	return 0;
+-}
+-
+-static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
+-{
+-	u16 rext_cal_val[2];
+-
+-	rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
+-	rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
+-	rext_fill_result(phydev, rext_cal_val);
+-
+-	return 0;
+-}
+-
+-static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
+-{
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
+-		       MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
+-		       MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
+-		       MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
+-		       MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
+-
+-	return 0;
+-}
+-
+-static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
+-{
+-	u16 tx_offset_cal_val[4];
+-
+-	tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
+-	tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
+-	tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
+-	tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
+-
+-	tx_offset_fill_result(phydev, tx_offset_cal_val);
+-
+-	return 0;
+-}
+-
+-static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
+-{
+-	int i;
+-	int bias[16] = {};
+-	const int vals_9461[16] = { 7, 1, 4, 7,
+-				    7, 1, 4, 7,
+-				    7, 1, 4, 7,
+-				    7, 1, 4, 7 };
+-	const int vals_9481[16] = { 10, 6, 6, 10,
+-				    10, 6, 6, 10,
+-				    10, 6, 6, 10,
+-				    10, 6, 6, 10 };
+-	switch (phydev->drv->phy_id) {
+-	case MTK_GPHY_ID_MT7981:
+-		/* We add some calibration to efuse values
+-		 * due to board level influence.
+-		 * GBE: +7, TBT: +1, HBT: +4, TST: +7
+-		 */
+-		memcpy(bias, (const void *)vals_9461, sizeof(bias));
+-		break;
+-	case MTK_GPHY_ID_MT7988:
+-		memcpy(bias, (const void *)vals_9481, sizeof(bias));
+-		break;
+-	}
+-
+-	/* Prevent overflow */
+-	for (i = 0; i < 12; i++) {
+-		if (buf[i >> 2] + bias[i] > 63) {
+-			buf[i >> 2] = 63;
+-			bias[i] = 0;
+-		}
+-	}
+-
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+-		       MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+-		       MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+-		       MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+-		       MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]);
+-
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+-		       MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+-		       MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+-		       MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+-		       MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]);
+-
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+-		       MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+-		       MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+-		       MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+-		       MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]);
+-
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+-		       MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+-		       MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+-		       MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+-		       MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]);
+-
+-	return 0;
+-}
+-
+-static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
+-{
+-	u16 tx_amp_cal_val[4];
+-
+-	tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
+-	tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
+-	tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
+-	tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
+-	tx_amp_fill_result(phydev, tx_amp_cal_val);
+-
+-	return 0;
+-}
+-
+-static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
+-			      u8 txg_calen_x)
+-{
+-	int bias = 0;
+-	u16 reg, val;
+-
+-	if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
+-		bias = -1;
+-
+-	val = clamp_val(bias + tx_r50_cal_val, 0, 63);
+-
+-	switch (txg_calen_x) {
+-	case PAIR_A:
+-		reg = MTK_PHY_DA_TX_R50_PAIR_A;
+-		break;
+-	case PAIR_B:
+-		reg = MTK_PHY_DA_TX_R50_PAIR_B;
+-		break;
+-	case PAIR_C:
+-		reg = MTK_PHY_DA_TX_R50_PAIR_C;
+-		break;
+-	case PAIR_D:
+-		reg = MTK_PHY_DA_TX_R50_PAIR_D;
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
+-
+-	return 0;
+-}
+-
+-static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
+-			    u8 txg_calen_x)
+-{
+-	u16 tx_r50_cal_val;
+-
+-	switch (txg_calen_x) {
+-	case PAIR_A:
+-		tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
+-		break;
+-	case PAIR_B:
+-		tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
+-		break;
+-	case PAIR_C:
+-		tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
+-		break;
+-	case PAIR_D:
+-		tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-	tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
+-
+-	return 0;
+-}
+-
+-static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
+-{
+-	u8 lower_idx, upper_idx, txreserve_val;
+-	u8 lower_ret, upper_ret;
+-	int ret;
+-
+-	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+-			 MTK_PHY_RG_ANA_CALEN);
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+-			   MTK_PHY_RG_CAL_CKINV);
+-	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+-			 MTK_PHY_RG_TXVOS_CALEN);
+-
+-	switch (rg_txreserve_x) {
+-	case PAIR_A:
+-		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				   MTK_PHY_RG_DASN_DAC_IN0_A,
+-				   MTK_PHY_DASN_DAC_IN0_A_MASK);
+-		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				   MTK_PHY_RG_DASN_DAC_IN1_A,
+-				   MTK_PHY_DASN_DAC_IN1_A_MASK);
+-		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				 MTK_PHY_RG_ANA_CAL_RG0,
+-				 MTK_PHY_RG_ZCALEN_A);
+-		break;
+-	case PAIR_B:
+-		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				   MTK_PHY_RG_DASN_DAC_IN0_B,
+-				   MTK_PHY_DASN_DAC_IN0_B_MASK);
+-		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				   MTK_PHY_RG_DASN_DAC_IN1_B,
+-				   MTK_PHY_DASN_DAC_IN1_B_MASK);
+-		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				 MTK_PHY_RG_ANA_CAL_RG1,
+-				 MTK_PHY_RG_ZCALEN_B);
+-		break;
+-	case PAIR_C:
+-		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				   MTK_PHY_RG_DASN_DAC_IN0_C,
+-				   MTK_PHY_DASN_DAC_IN0_C_MASK);
+-		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				   MTK_PHY_RG_DASN_DAC_IN1_C,
+-				   MTK_PHY_DASN_DAC_IN1_C_MASK);
+-		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				 MTK_PHY_RG_ANA_CAL_RG1,
+-				 MTK_PHY_RG_ZCALEN_C);
+-		break;
+-	case PAIR_D:
+-		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				   MTK_PHY_RG_DASN_DAC_IN0_D,
+-				   MTK_PHY_DASN_DAC_IN0_D_MASK);
+-		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				   MTK_PHY_RG_DASN_DAC_IN1_D,
+-				   MTK_PHY_DASN_DAC_IN1_D_MASK);
+-		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-				 MTK_PHY_RG_ANA_CAL_RG1,
+-				 MTK_PHY_RG_ZCALEN_D);
+-		break;
+-	default:
+-		ret = -EINVAL;
+-		goto restore;
+-	}
+-
+-	lower_idx = TXRESERVE_MIN;
+-	upper_idx = TXRESERVE_MAX;
+-
+-	phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
+-	while ((upper_idx - lower_idx) > 1) {
+-		txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
+-		ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+-				MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-				MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-				MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-				MTK_PHY_DA_RX_PSBN_LP_MASK,
+-				txreserve_val << 12 | txreserve_val << 8 |
+-				txreserve_val << 4 | txreserve_val);
+-		if (ret == 1) {
+-			upper_idx = txreserve_val;
+-			upper_ret = ret;
+-		} else if (ret == 0) {
+-			lower_idx = txreserve_val;
+-			lower_ret = ret;
+-		} else {
+-			goto restore;
+-		}
+-	}
+-
+-	if (lower_idx == TXRESERVE_MIN) {
+-		lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
+-				      MTK_PHY_RXADC_CTRL_RG9,
+-				      MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-				      MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-				      MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-				      MTK_PHY_DA_RX_PSBN_LP_MASK,
+-				      lower_idx << 12 | lower_idx << 8 |
+-				      lower_idx << 4 | lower_idx);
+-		ret = lower_ret;
+-	} else if (upper_idx == TXRESERVE_MAX) {
+-		upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
+-				      MTK_PHY_RXADC_CTRL_RG9,
+-				      MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-				      MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-				      MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-				      MTK_PHY_DA_RX_PSBN_LP_MASK,
+-				      upper_idx << 12 | upper_idx << 8 |
+-				      upper_idx << 4 | upper_idx);
+-		ret = upper_ret;
+-	}
+-	if (ret < 0)
+-		goto restore;
+-
+-	/* We calibrate TX-VCM in different logic. Check upper index and then
+-	 * lower index. If this calibration is valid, apply lower index's result.
+-	 */
+-	ret = upper_ret - lower_ret;
+-	if (ret == 1) {
+-		ret = 0;
+-		/* Make sure we use upper_idx in our calibration system */
+-		cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+-			  MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-			  MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-			  MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-			  MTK_PHY_DA_RX_PSBN_LP_MASK,
+-			  upper_idx << 12 | upper_idx << 8 |
+-			  upper_idx << 4 | upper_idx);
+-		phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
+-	} else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
+-		   lower_ret == 1) {
+-		ret = 0;
+-		cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+-			  MTK_PHY_DA_RX_PSBN_TBT_MASK |
+-			  MTK_PHY_DA_RX_PSBN_HBT_MASK |
+-			  MTK_PHY_DA_RX_PSBN_GBE_MASK |
+-			  MTK_PHY_DA_RX_PSBN_LP_MASK,
+-			  lower_idx << 12 | lower_idx << 8 |
+-			  lower_idx << 4 | lower_idx);
+-		phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
+-			    lower_idx);
+-	} else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
+-		   lower_ret == 0) {
+-		ret = 0;
+-		phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n",
+-			    upper_idx);
+-	} else {
+-		ret = -EINVAL;
+-	}
+-
+-restore:
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+-			   MTK_PHY_RG_ANA_CALEN);
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+-			   MTK_PHY_RG_TXVOS_CALEN);
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+-			   MTK_PHY_RG_ZCALEN_A);
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+-			   MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
+-			   MTK_PHY_RG_ZCALEN_D);
+-
+-	return ret;
+-}
+-
+-static void mt798x_phy_common_finetune(struct phy_device *phydev)
+-{
+-	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	/* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
+-	__phy_write(phydev, 0x11, 0xc71);
+-	__phy_write(phydev, 0x12, 0xc);
+-	__phy_write(phydev, 0x10, 0x8fae);
+-
+-	/* EnabRandUpdTrig = 1 */
+-	__phy_write(phydev, 0x11, 0x2f00);
+-	__phy_write(phydev, 0x12, 0xe);
+-	__phy_write(phydev, 0x10, 0x8fb0);
+-
+-	/* NormMseLoThresh = 85 */
+-	__phy_write(phydev, 0x11, 0x55a0);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x83aa);
+-
+-	/* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
+-	__phy_write(phydev, 0x11, 0x240);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x9680);
+-
+-	/* TrFreeze = 0 (mt7988 default) */
+-	__phy_write(phydev, 0x11, 0x0);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x9686);
+-
+-	/* SSTrKp100 = 5 */
+-	/* SSTrKf100 = 6 */
+-	/* SSTrKp1000Mas = 5 */
+-	/* SSTrKf1000Mas = 6 */
+-	/* SSTrKp1000Slv = 5 */
+-	/* SSTrKf1000Slv = 6 */
+-	__phy_write(phydev, 0x11, 0xbaef);
+-	__phy_write(phydev, 0x12, 0x2e);
+-	__phy_write(phydev, 0x10, 0x968c);
+-	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-}
+-
+-static void mt7981_phy_finetune(struct phy_device *phydev)
+-{
+-	u16 val[8] = { 0x01ce, 0x01c1,
+-		       0x020f, 0x0202,
+-		       0x03d0, 0x03c0,
+-		       0x0013, 0x0005 };
+-	int i, k;
+-
+-	/* 100M eye finetune:
+-	 * Keep middle level of TX MLT3 shapper as default.
+-	 * Only change TX MLT3 overshoot level here.
+-	 */
+-	for (k = 0, i = 1; i < 12; i++) {
+-		if (i % 3 == 0)
+-			continue;
+-		phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
+-	}
+-
+-	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	/* ResetSyncOffset = 6 */
+-	__phy_write(phydev, 0x11, 0x600);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x8fc0);
+-
+-	/* VgaDecRate = 1 */
+-	__phy_write(phydev, 0x11, 0x4c2a);
+-	__phy_write(phydev, 0x12, 0x3e);
+-	__phy_write(phydev, 0x10, 0x8fa4);
+-
+-	/* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
+-	 * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
+-	 */
+-	__phy_write(phydev, 0x11, 0xd10a);
+-	__phy_write(phydev, 0x12, 0x34);
+-	__phy_write(phydev, 0x10, 0x8f82);
+-
+-	/* VcoSlicerThreshBitsHigh */
+-	__phy_write(phydev, 0x11, 0x5555);
+-	__phy_write(phydev, 0x12, 0x55);
+-	__phy_write(phydev, 0x10, 0x8ec0);
+-	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-	/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+-		       MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
+-		       BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
+-
+-	/* rg_tr_lpf_cnt_val = 512 */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
+-
+-	/* IIR2 related */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
+-
+-	/* FFE peaking */
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
+-		       MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
+-		       MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
+-
+-	/* Disable LDO pump */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
+-	/* Adjust LDO output voltage */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
+-}
+-
+-static void mt7988_phy_finetune(struct phy_device *phydev)
+-{
+-	u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
+-			0x020d, 0x0206, 0x0384, 0x03d0,
+-			0x03c6, 0x030a, 0x0011, 0x0005 };
+-	int i;
+-
+-	/* Set default MLT3 shaper first */
+-	for (i = 0; i < 12; i++)
+-		phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
+-
+-	/* TCT finetune */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
+-
+-	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	/* ResetSyncOffset = 5 */
+-	__phy_write(phydev, 0x11, 0x500);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x8fc0);
+-
+-	/* VgaDecRate is 1 at default on mt7988 */
+-
+-	/* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
+-	 * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
+-	 */
+-	__phy_write(phydev, 0x11, 0xb90a);
+-	__phy_write(phydev, 0x12, 0x6f);
+-	__phy_write(phydev, 0x10, 0x8f82);
+-
+-	/* RemAckCntLimitCtrl = 1 */
+-	__phy_write(phydev, 0x11, 0xfbba);
+-	__phy_write(phydev, 0x12, 0xc3);
+-	__phy_write(phydev, 0x10, 0x87f8);
+-
+-	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-	/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+-		       MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
+-		       BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
+-
+-	/* rg_tr_lpf_cnt_val = 1023 */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
+-}
+-
+-static void mt798x_phy_eee(struct phy_device *phydev)
+-{
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+-		       MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
+-		       MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
+-		       MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
+-		       FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
+-		       FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
+-
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+-		       MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
+-		       MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+-		       FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+-				  0xff));
+-
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-			   MTK_PHY_RG_TESTMUX_ADC_CTRL,
+-			   MTK_PHY_RG_TXEN_DIG_MASK);
+-
+-	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+-			 MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
+-
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+-			   MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
+-
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
+-		       MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
+-		       MTK_PHY_LPI_SLV_SEND_TX_EN,
+-		       FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
+-
+-	/* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
+-			   MTK_PHY_LPI_TXPCS_LOC_RCV);
+-
+-	/* This also fixes some IoT issues, such as CH340 */
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
+-		       MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
+-		       FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
+-		       FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
+-
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
+-		       MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
+-		       FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
+-				  0x33) |
+-		       MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
+-		       MTK_PHY_LPI_VCO_EEE_STG0_EN);
+-
+-	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
+-			 MTK_PHY_EEE_WAKE_MAS_INT_DC |
+-			 MTK_PHY_EEE_WAKE_SLV_INT_DC);
+-
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
+-		       MTK_PHY_SMI_DETCNT_MAX_MASK,
+-		       FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
+-		       MTK_PHY_SMI_DET_MAX_EN);
+-
+-	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
+-			 MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
+-			 MTK_PHY_TREC_UPDATE_ENAB_CLR |
+-			 MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
+-			 MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
+-
+-	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	/* Regsigdet_sel_1000 = 0 */
+-	__phy_write(phydev, 0x11, 0xb);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x9690);
+-
+-	/* REG_EEE_st2TrKf1000 = 2 */
+-	__phy_write(phydev, 0x11, 0x114f);
+-	__phy_write(phydev, 0x12, 0x2);
+-	__phy_write(phydev, 0x10, 0x969a);
+-
+-	/* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
+-	__phy_write(phydev, 0x11, 0x3028);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x969e);
+-
+-	/* RegEEE_slv_wake_int_timer_tar = 8 */
+-	__phy_write(phydev, 0x11, 0x5010);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x96a0);
+-
+-	/* RegEEE_trfreeze_timer2 = 586 */
+-	__phy_write(phydev, 0x11, 0x24a);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x96a8);
+-
+-	/* RegEEE100Stg1_tar = 16 */
+-	__phy_write(phydev, 0x11, 0x3210);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x96b8);
+-
+-	/* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
+-	__phy_write(phydev, 0x11, 0x1463);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x96ca);
+-
+-	/* DfeTailEnableVgaThresh1000 = 27 */
+-	__phy_write(phydev, 0x11, 0x36);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x8f80);
+-	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
+-	__phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
+-		     FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
+-
+-	__phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
+-		     FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
+-	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+-		       MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
+-		       MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+-		       FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff));
+-}
+-
+-static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
+-		  u8 start_pair, u8 end_pair)
+-{
+-	u8 pair_n;
+-	int ret;
+-
+-	for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
+-		/* TX_OFFSET & TX_AMP have no SW calibration. */
+-		switch (cal_item) {
+-		case TX_VCM:
+-			ret = tx_vcm_cal_sw(phydev, pair_n);
+-			break;
+-		default:
+-			return -EINVAL;
+-		}
+-		if (ret)
+-			return ret;
+-	}
+-	return 0;
+-}
+-
+-static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
+-		     u8 start_pair, u8 end_pair, u32 *buf)
+-{
+-	u8 pair_n;
+-	int ret;
+-
+-	for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
+-		/* TX_VCM has no efuse calibration. */
+-		switch (cal_item) {
+-		case REXT:
+-			ret = rext_cal_efuse(phydev, buf);
+-			break;
+-		case TX_OFFSET:
+-			ret = tx_offset_cal_efuse(phydev, buf);
+-			break;
+-		case TX_AMP:
+-			ret = tx_amp_cal_efuse(phydev, buf);
+-			break;
+-		case TX_R50:
+-			ret = tx_r50_cal_efuse(phydev, buf, pair_n);
+-			break;
+-		default:
+-			return -EINVAL;
+-		}
+-		if (ret)
+-			return ret;
+-	}
+-
+-	return 0;
+-}
+-
+-static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
+-		     enum CAL_MODE cal_mode, u8 start_pair,
+-		     u8 end_pair, u32 *buf)
+-{
+-	int ret;
+-
+-	switch (cal_mode) {
+-	case EFUSE_M:
+-		ret = cal_efuse(phydev, cal_item, start_pair,
+-				end_pair, buf);
+-		break;
+-	case SW_M:
+-		ret = cal_sw(phydev, cal_item, start_pair, end_pair);
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-
+-	if (ret) {
+-		phydev_err(phydev, "cal %d failed\n", cal_item);
+-		return -EIO;
+-	}
+-
+-	return 0;
+-}
+-
+-static int mt798x_phy_calibration(struct phy_device *phydev)
+-{
+-	int ret = 0;
+-	u32 *buf;
+-	size_t len;
+-	struct nvmem_cell *cell;
+-
+-	cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
+-	if (IS_ERR(cell)) {
+-		if (PTR_ERR(cell) == -EPROBE_DEFER)
+-			return PTR_ERR(cell);
+-		return 0;
+-	}
+-
+-	buf = (u32 *)nvmem_cell_read(cell, &len);
+-	if (IS_ERR(buf))
+-		return PTR_ERR(buf);
+-	nvmem_cell_put(cell);
+-
+-	if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
+-		phydev_err(phydev, "invalid efuse data\n");
+-		ret = -EINVAL;
+-		goto out;
+-	}
+-
+-	ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
+-	if (ret)
+-		goto out;
+-	ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
+-	if (ret)
+-		goto out;
+-	ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
+-	if (ret)
+-		goto out;
+-	ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
+-	if (ret)
+-		goto out;
+-	ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
+-	if (ret)
+-		goto out;
+-
+-out:
+-	kfree(buf);
+-	return ret;
+-}
+-
+-static int mt798x_phy_config_init(struct phy_device *phydev)
+-{
+-	switch (phydev->drv->phy_id) {
+-	case MTK_GPHY_ID_MT7981:
+-		mt7981_phy_finetune(phydev);
+-		break;
+-	case MTK_GPHY_ID_MT7988:
+-		mt7988_phy_finetune(phydev);
+-		break;
+-	}
+-
+-	mt798x_phy_common_finetune(phydev);
+-	mt798x_phy_eee(phydev);
+-
+-	return mt798x_phy_calibration(phydev);
+-}
+-
+-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+-				    bool on)
+-{
+-	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+-	struct mtk_socphy_priv *priv = phydev->priv;
+-	bool changed;
+-
+-	if (on)
+-		changed = !test_and_set_bit(bit_on, &priv->led_state);
+-	else
+-		changed = !!test_and_clear_bit(bit_on, &priv->led_state);
+-
+-	changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
+-					(index ? 16 : 0), &priv->led_state);
+-	if (changed)
+-		return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-				      MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+-				      MTK_PHY_LED_ON_MASK,
+-				      on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+-	else
+-		return 0;
+-}
+-
+-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+-				       bool blinking)
+-{
+-	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
+-	struct mtk_socphy_priv *priv = phydev->priv;
+-	bool changed;
+-
+-	if (blinking)
+-		changed = !test_and_set_bit(bit_blink, &priv->led_state);
+-	else
+-		changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
+-
+-	changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
+-			      (index ? 16 : 0), &priv->led_state);
+-	if (changed)
+-		return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+-				     MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL,
+-				     blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+-	else
+-		return 0;
+-}
+-
+-static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
+-				    unsigned long *delay_on,
+-				    unsigned long *delay_off)
+-{
+-	bool blinking = false;
+-	int err = 0;
+-
+-	if (index > 1)
+-		return -EINVAL;
+-
+-	if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+-		blinking = true;
+-		*delay_on = 50;
+-		*delay_off = 50;
+-	}
+-
+-	err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
+-	if (err)
+-		return err;
+-
+-	return mt798x_phy_hw_led_on_set(phydev, index, false);
+-}
+-
+-static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
+-					 u8 index, enum led_brightness value)
+-{
+-	int err;
+-
+-	err = mt798x_phy_hw_led_blink_set(phydev, index, false);
+-	if (err)
+-		return err;
+-
+-	return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
+-}
+-
+-static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+-						 BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+-						 BIT(TRIGGER_NETDEV_LINK)        |
+-						 BIT(TRIGGER_NETDEV_LINK_10)     |
+-						 BIT(TRIGGER_NETDEV_LINK_100)    |
+-						 BIT(TRIGGER_NETDEV_LINK_1000)   |
+-						 BIT(TRIGGER_NETDEV_RX)          |
+-						 BIT(TRIGGER_NETDEV_TX));
+-
+-static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+-					  unsigned long rules)
+-{
+-	if (index > 1)
+-		return -EINVAL;
+-
+-	/* All combinations of the supported triggers are allowed */
+-	if (rules & ~supported_triggers)
+-		return -EOPNOTSUPP;
+-
+-	return 0;
+-};
+-
+-static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+-					 unsigned long *rules)
+-{
+-	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
+-	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+-	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+-	struct mtk_socphy_priv *priv = phydev->priv;
+-	int on, blink;
+-
+-	if (index > 1)
+-		return -EINVAL;
+-
+-	on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+-			  index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
+-
+-	if (on < 0)
+-		return -EIO;
+-
+-	blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+-			     index ? MTK_PHY_LED1_BLINK_CTRL :
+-				     MTK_PHY_LED0_BLINK_CTRL);
+-	if (blink < 0)
+-		return -EIO;
+-
+-	if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX |
+-		   MTK_PHY_LED_ON_LINKDOWN)) ||
+-	    (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
+-		set_bit(bit_netdev, &priv->led_state);
+-	else
+-		clear_bit(bit_netdev, &priv->led_state);
+-
+-	if (on & MTK_PHY_LED_ON_FORCE_ON)
+-		set_bit(bit_on, &priv->led_state);
+-	else
+-		clear_bit(bit_on, &priv->led_state);
+-
+-	if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
+-		set_bit(bit_blink, &priv->led_state);
+-	else
+-		clear_bit(bit_blink, &priv->led_state);
+-
+-	if (!rules)
+-		return 0;
+-
+-	if (on & MTK_PHY_LED_ON_LINK)
+-		*rules |= BIT(TRIGGER_NETDEV_LINK);
+-
+-	if (on & MTK_PHY_LED_ON_LINK10)
+-		*rules |= BIT(TRIGGER_NETDEV_LINK_10);
+-
+-	if (on & MTK_PHY_LED_ON_LINK100)
+-		*rules |= BIT(TRIGGER_NETDEV_LINK_100);
+-
+-	if (on & MTK_PHY_LED_ON_LINK1000)
+-		*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+-
+-	if (on & MTK_PHY_LED_ON_FDX)
+-		*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+-
+-	if (on & MTK_PHY_LED_ON_HDX)
+-		*rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
+-
+-	if (blink & MTK_PHY_LED_BLINK_RX)
+-		*rules |= BIT(TRIGGER_NETDEV_RX);
+-
+-	if (blink & MTK_PHY_LED_BLINK_TX)
+-		*rules |= BIT(TRIGGER_NETDEV_TX);
+-
+-	return 0;
+-};
+-
+-static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
+-					 unsigned long rules)
+-{
+-	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+-	struct mtk_socphy_priv *priv = phydev->priv;
+-	u16 on = 0, blink = 0;
+-	int ret;
+-
+-	if (index > 1)
+-		return -EINVAL;
+-
+-	if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+-		on |= MTK_PHY_LED_ON_FDX;
+-
+-	if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
+-		on |= MTK_PHY_LED_ON_HDX;
+-
+-	if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
+-		on |= MTK_PHY_LED_ON_LINK10;
+-
+-	if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+-		on |= MTK_PHY_LED_ON_LINK100;
+-
+-	if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+-		on |= MTK_PHY_LED_ON_LINK1000;
+-
+-	if (rules & BIT(TRIGGER_NETDEV_RX)) {
+-		blink |= (on & MTK_PHY_LED_ON_LINK) ?
+-			  (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) :
+-			  MTK_PHY_LED_BLINK_RX;
+-	}
+-
+-	if (rules & BIT(TRIGGER_NETDEV_TX)) {
+-		blink |= (on & MTK_PHY_LED_ON_LINK) ?
+-			  (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) :
+-			  MTK_PHY_LED_BLINK_TX;
+-	}
+-
+-	if (blink || on)
+-		set_bit(bit_netdev, &priv->led_state);
+-	else
+-		clear_bit(bit_netdev, &priv->led_state);
+-
+-	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-				MTK_PHY_LED1_ON_CTRL :
+-				MTK_PHY_LED0_ON_CTRL,
+-			     MTK_PHY_LED_ON_FDX     |
+-			     MTK_PHY_LED_ON_HDX     |
+-			     MTK_PHY_LED_ON_LINK,
+-			     on);
+-
+-	if (ret)
+-		return ret;
+-
+-	return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+-				MTK_PHY_LED1_BLINK_CTRL :
+-				MTK_PHY_LED0_BLINK_CTRL, blink);
+-};
+-
+-static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
+-{
+-	struct mtk_socphy_shared *priv = phydev->shared->priv;
+-	u32 polarities;
+-
+-	if (led_num == 0)
+-		polarities = ~(priv->boottrap);
+-	else
+-		polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
+-
+-	if (polarities & BIT(phydev->mdio.addr))
+-		return true;
+-
+-	return false;
+-}
+-
+-static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
+-{
+-	struct pinctrl *pinctrl;
+-	int index;
+-
+-	/* Setup LED polarity according to bootstrap use of LED pins */
+-	for (index = 0; index < 2; ++index)
+-		phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-				MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+-			       MTK_PHY_LED_ON_POLARITY,
+-			       mt7988_phy_led_get_polarity(phydev, index) ?
+-				MTK_PHY_LED_ON_POLARITY : 0);
+-
+-	/* Only now setup pinctrl to avoid bogus blinking */
+-	pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
+-	if (IS_ERR(pinctrl))
+-		dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n");
+-
+-	return 0;
+-}
+-
+-static int mt7988_phy_probe_shared(struct phy_device *phydev)
+-{
+-	struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
+-	struct mtk_socphy_shared *shared = phydev->shared->priv;
+-	struct regmap *regmap;
+-	u32 reg;
+-	int ret;
+-
+-	/* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
+-	 * LED_C and LED_D respectively. At the same time those pins are used to
+-	 * bootstrap configuration of the reference clock source (LED_A),
+-	 * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
+-	 * In practise this is done using a LED and a resistor pulling the pin
+-	 * either to GND or to VIO.
+-	 * The detected value at boot time is accessible at run-time using the
+-	 * TPBANK0 register located in the gpio base of the pinctrl, in order
+-	 * to read it here it needs to be referenced by a phandle called
+-	 * 'mediatek,pio' in the MDIO bus hosting the PHY.
+-	 * The 4 bits in TPBANK0 are kept as package shared data and are used to
+-	 * set LED polarity for each of the LED0.
+-	 */
+-	regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
+-	if (IS_ERR(regmap))
+-		return PTR_ERR(regmap);
+-
+-	ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, &reg);
+-	if (ret)
+-		return ret;
+-
+-	shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
+-
+-	return 0;
+-}
+-
+-static void mt798x_phy_leds_state_init(struct phy_device *phydev)
+-{
+-	int i;
+-
+-	for (i = 0; i < 2; ++i)
+-		mt798x_phy_led_hw_control_get(phydev, i, NULL);
+-}
+-
+-static int mt7988_phy_probe(struct phy_device *phydev)
+-{
+-	struct mtk_socphy_shared *shared;
+-	struct mtk_socphy_priv *priv;
+-	int err;
+-
+-	if (phydev->mdio.addr > 3)
+-		return -EINVAL;
+-
+-	err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
+-				    sizeof(struct mtk_socphy_shared));
+-	if (err)
+-		return err;
+-
+-	if (phy_package_probe_once(phydev)) {
+-		err = mt7988_phy_probe_shared(phydev);
+-		if (err)
+-			return err;
+-	}
+-
+-	shared = phydev->shared->priv;
+-	priv = &shared->priv[phydev->mdio.addr];
+-
+-	phydev->priv = priv;
+-
+-	mt798x_phy_leds_state_init(phydev);
+-
+-	err = mt7988_phy_fix_leds_polarities(phydev);
+-	if (err)
+-		return err;
+-
+-	/* Disable TX power saving at probing to:
+-	 * 1. Meet common mode compliance test criteria
+-	 * 2. Make sure that TX-VCM calibration works fine
+-	 */
+-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
+-		       MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
+-
+-	return mt798x_phy_calibration(phydev);
+-}
+-
+-static int mt7981_phy_probe(struct phy_device *phydev)
+-{
+-	struct mtk_socphy_priv *priv;
+-
+-	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
+-			    GFP_KERNEL);
+-	if (!priv)
+-		return -ENOMEM;
+-
+-	phydev->priv = priv;
+-
+-	mt798x_phy_leds_state_init(phydev);
+-
+-	return mt798x_phy_calibration(phydev);
+-}
+-
+-static struct phy_driver mtk_socphy_driver[] = {
+-	{
+-		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
+-		.name		= "MediaTek MT7981 PHY",
+-		.config_init	= mt798x_phy_config_init,
+-		.config_intr	= genphy_no_config_intr,
+-		.handle_interrupt = genphy_handle_interrupt_no_ack,
+-		.probe		= mt7981_phy_probe,
+-		.suspend	= genphy_suspend,
+-		.resume		= genphy_resume,
+-		.read_page	= mtk_socphy_read_page,
+-		.write_page	= mtk_socphy_write_page,
+-		.led_blink_set	= mt798x_phy_led_blink_set,
+-		.led_brightness_set = mt798x_phy_led_brightness_set,
+-		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+-		.led_hw_control_set = mt798x_phy_led_hw_control_set,
+-		.led_hw_control_get = mt798x_phy_led_hw_control_get,
+-	},
+-	{
+-		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
+-		.name		= "MediaTek MT7988 PHY",
+-		.config_init	= mt798x_phy_config_init,
+-		.config_intr	= genphy_no_config_intr,
+-		.handle_interrupt = genphy_handle_interrupt_no_ack,
+-		.probe		= mt7988_phy_probe,
+-		.suspend	= genphy_suspend,
+-		.resume		= genphy_resume,
+-		.read_page	= mtk_socphy_read_page,
+-		.write_page	= mtk_socphy_write_page,
+-		.led_blink_set	= mt798x_phy_led_blink_set,
+-		.led_brightness_set = mt798x_phy_led_brightness_set,
+-		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+-		.led_hw_control_set = mt798x_phy_led_hw_control_set,
+-		.led_hw_control_get = mt798x_phy_led_hw_control_get,
+-	},
+-};
+-
+-module_phy_driver(mtk_socphy_driver);
+-
+-static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
+-	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
+-	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
+-	{ }
+-};
+-
+-MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver");
+-MODULE_AUTHOR("Daniel Golle <daniel at makrotopia.org>");
+-MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang at mediatek.com>");
+-MODULE_LICENSE("GPL");
+-
+-MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
+--- a/drivers/net/phy/mediatek-ge.c
++++ /dev/null
+@@ -1,148 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0+
+-#include <linux/of.h>
+-#include <linux/bitfield.h>
+-#include <linux/module.h>
+-#include <linux/phy.h>
+-
+-#define MTK_EXT_PAGE_ACCESS		0x1f
+-#define MTK_PHY_PAGE_STANDARD		0x0000
+-#define MTK_PHY_PAGE_EXTENDED		0x0001
+-#define MTK_PHY_PAGE_EXTENDED_2		0x0002
+-#define MTK_PHY_PAGE_EXTENDED_3		0x0003
+-#define MTK_PHY_PAGE_EXTENDED_2A30	0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5	0x52b5
+-
+-static int mtk_gephy_read_page(struct phy_device *phydev)
+-{
+-	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_gephy_write_page(struct phy_device *phydev, int page)
+-{
+-	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+-static void mtk_gephy_config_init(struct phy_device *phydev)
+-{
+-	/* Disable EEE */
+-	phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
+-
+-	/* Enable HW auto downshift */
+-	phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
+-
+-	/* Increase SlvDPSready time */
+-	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	__phy_write(phydev, 0x10, 0xafae);
+-	__phy_write(phydev, 0x12, 0x2f);
+-	__phy_write(phydev, 0x10, 0x8fae);
+-	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-
+-	/* Adjust 100_mse_threshold */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
+-
+-	/* Disable mcc */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
+-}
+-
+-static int mt7530_phy_config_init(struct phy_device *phydev)
+-{
+-	mtk_gephy_config_init(phydev);
+-
+-	/* Increase post_update_timer */
+-	phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
+-
+-	return 0;
+-}
+-
+-static int mt7530_led_config_of(struct phy_device *phydev)
+-{
+-	struct device_node *np = phydev->mdio.dev.of_node;
+-	const __be32 *paddr;
+-	int len;
+-	int i;
+-
+-	paddr = of_get_property(np, "mediatek,led-config", &len);
+-	if (!paddr)
+-		return 0;
+-
+-	if (len < (2 * sizeof(*paddr)))
+-		return -EINVAL;
+-
+-	len /= sizeof(*paddr);
+-
+-	phydev_warn(phydev, "Configure LED registers (num=%d)\n", len);
+-	for (i = 0; i < len - 1; i += 2) {
+-		u32 reg;
+-		u32 val;
+-
+-		reg = be32_to_cpup(paddr + i);
+-		val = be32_to_cpup(paddr + i + 1);
+-
+-		phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, val);
+-	}
+-
+-	return 0;
+-}
+-
+-static int mt7531_phy_config_init(struct phy_device *phydev)
+-{
+-	mtk_gephy_config_init(phydev);
+-
+-	/* PHY link down power saving enable */
+-	phy_set_bits(phydev, 0x17, BIT(4));
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
+-
+-	/* Set TX Pair delay selection */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
+-
+-	/* LED Config*/
+-	mt7530_led_config_of(phydev);
+-
+-	return 0;
+-}
+-
+-static struct phy_driver mtk_gephy_driver[] = {
+-	{
+-		PHY_ID_MATCH_EXACT(0x03a29412),
+-		.name		= "MediaTek MT7530 PHY",
+-		.config_init	= mt7530_phy_config_init,
+-		/* Interrupts are handled by the switch, not the PHY
+-		 * itself.
+-		 */
+-		.config_intr	= genphy_no_config_intr,
+-		.handle_interrupt = genphy_handle_interrupt_no_ack,
+-		.suspend	= genphy_suspend,
+-		.resume		= genphy_resume,
+-		.read_page	= mtk_gephy_read_page,
+-		.write_page	= mtk_gephy_write_page,
+-	},
+-	{
+-		PHY_ID_MATCH_EXACT(0x03a29441),
+-		.name		= "MediaTek MT7531 PHY",
+-		.config_init	= mt7531_phy_config_init,
+-		/* Interrupts are handled by the switch, not the PHY
+-		 * itself.
+-		 */
+-		.config_intr	= genphy_no_config_intr,
+-		.handle_interrupt = genphy_handle_interrupt_no_ack,
+-		.suspend	= genphy_suspend,
+-		.resume		= genphy_resume,
+-		.read_page	= mtk_gephy_read_page,
+-		.write_page	= mtk_gephy_write_page,
+-	},
+-};
+-
+-module_phy_driver(mtk_gephy_driver);
+-
+-static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
+-	{ PHY_ID_MATCH_EXACT(0x03a29441) },
+-	{ PHY_ID_MATCH_EXACT(0x03a29412) },
+-	{ }
+-};
+-
+-MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
+-MODULE_AUTHOR("DENG, Qingfang <dqfext at gmail.com>");
+-MODULE_LICENSE("GPL");
+-
+-MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -0,0 +1,1555 @@
++// SPDX-License-Identifier: GPL-2.0+
++#include <linux/bitfield.h>
++#include <linux/bitmap.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/phy.h>
++#include <linux/regmap.h>
++
++#define MTK_GPHY_ID_MT7981			0x03a29461
++#define MTK_GPHY_ID_MT7988			0x03a29481
++
++#define MTK_EXT_PAGE_ACCESS			0x1f
++#define MTK_PHY_PAGE_STANDARD			0x0000
++#define MTK_PHY_PAGE_EXTENDED_3			0x0003
++
++#define MTK_PHY_LPI_REG_14			0x14
++#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK	GENMASK(8, 0)
++
++#define MTK_PHY_LPI_REG_1c			0x1c
++#define MTK_PHY_SMI_DET_ON_THRESH_MASK		GENMASK(13, 8)
++
++#define MTK_PHY_PAGE_EXTENDED_2A30		0x2a30
++#define MTK_PHY_PAGE_EXTENDED_52B5		0x52b5
++
++#define ANALOG_INTERNAL_OPERATION_MAX_US	20
++#define TXRESERVE_MIN				0
++#define TXRESERVE_MAX				7
++
++#define MTK_PHY_ANARG_RG			0x10
++#define   MTK_PHY_TCLKOFFSET_MASK		GENMASK(12, 8)
++
++/* Registers on MDIO_MMD_VEND1 */
++#define MTK_PHY_TXVLD_DA_RG			0x12
++#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK	GENMASK(15, 10)
++#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK	GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_A2		0x16
++#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK	GENMASK(15, 10)
++#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK	GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_B1		0x17
++#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK	GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK	GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_B2		0x18
++#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK	GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK	GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_C1		0x19
++#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK	GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK	GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_C2		0x20
++#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK	GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK	GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_D1		0x21
++#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK	GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK	GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_D2		0x22
++#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK	GENMASK(13, 8)
++#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK	GENMASK(5, 0)
++
++#define MTK_PHY_RXADC_CTRL_RG7			0xc6
++#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK	GENMASK(9, 8)
++
++#define MTK_PHY_RXADC_CTRL_RG9			0xc8
++#define   MTK_PHY_DA_RX_PSBN_TBT_MASK		GENMASK(14, 12)
++#define   MTK_PHY_DA_RX_PSBN_HBT_MASK		GENMASK(10, 8)
++#define   MTK_PHY_DA_RX_PSBN_GBE_MASK		GENMASK(6, 4)
++#define   MTK_PHY_DA_RX_PSBN_LP_MASK		GENMASK(2, 0)
++
++#define MTK_PHY_LDO_OUTPUT_V			0xd7
++
++#define MTK_PHY_RG_ANA_CAL_RG0			0xdb
++#define   MTK_PHY_RG_CAL_CKINV			BIT(12)
++#define   MTK_PHY_RG_ANA_CALEN			BIT(8)
++#define   MTK_PHY_RG_ZCALEN_A			BIT(0)
++
++#define MTK_PHY_RG_ANA_CAL_RG1			0xdc
++#define   MTK_PHY_RG_ZCALEN_B			BIT(12)
++#define   MTK_PHY_RG_ZCALEN_C			BIT(8)
++#define   MTK_PHY_RG_ZCALEN_D			BIT(4)
++#define   MTK_PHY_RG_TXVOS_CALEN		BIT(0)
++
++#define MTK_PHY_RG_ANA_CAL_RG5			0xe0
++#define   MTK_PHY_RG_REXT_TRIM_MASK		GENMASK(13, 8)
++
++#define MTK_PHY_RG_TX_FILTER			0xfe
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120	0x120
++#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK	GENMASK(12, 8)
++#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK	GENMASK(4, 0)
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122	0x122
++#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK	GENMASK(7, 0)
++
++#define MTK_PHY_RG_TESTMUX_ADC_CTRL		0x144
++#define   MTK_PHY_RG_TXEN_DIG_MASK		GENMASK(5, 5)
++
++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B		0x172
++#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK	GENMASK(13, 8)
++#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK	GENMASK(6, 0)
++
++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D		0x173
++#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK	GENMASK(13, 8)
++#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK	GENMASK(6, 0)
++
++#define MTK_PHY_RG_AD_CAL_COMP			0x17a
++#define   MTK_PHY_AD_CAL_COMP_OUT_SHIFT		(8)
++
++#define MTK_PHY_RG_AD_CAL_CLK			0x17b
++#define   MTK_PHY_DA_CAL_CLK			BIT(0)
++
++#define MTK_PHY_RG_AD_CALIN			0x17c
++#define   MTK_PHY_DA_CALIN_FLAG			BIT(0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_A		0x17d
++#define   MTK_PHY_DASN_DAC_IN0_A_MASK		GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_B		0x17e
++#define   MTK_PHY_DASN_DAC_IN0_B_MASK		GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_C		0x17f
++#define   MTK_PHY_DASN_DAC_IN0_C_MASK		GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_D		0x180
++#define   MTK_PHY_DASN_DAC_IN0_D_MASK		GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_A		0x181
++#define   MTK_PHY_DASN_DAC_IN1_A_MASK		GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_B		0x182
++#define   MTK_PHY_DASN_DAC_IN1_B_MASK		GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_C		0x183
++#define   MTK_PHY_DASN_DAC_IN1_C_MASK		GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_D		0x184
++#define   MTK_PHY_DASN_DAC_IN1_D_MASK		GENMASK(9, 0)
++
++#define MTK_PHY_RG_DEV1E_REG19b			0x19b
++#define   MTK_PHY_BYPASS_DSP_LPI_READY		BIT(8)
++
++#define MTK_PHY_RG_LP_IIR2_K1_L			0x22a
++#define MTK_PHY_RG_LP_IIR2_K1_U			0x22b
++#define MTK_PHY_RG_LP_IIR2_K2_L			0x22c
++#define MTK_PHY_RG_LP_IIR2_K2_U			0x22d
++#define MTK_PHY_RG_LP_IIR2_K3_L			0x22e
++#define MTK_PHY_RG_LP_IIR2_K3_U			0x22f
++#define MTK_PHY_RG_LP_IIR2_K4_L			0x230
++#define MTK_PHY_RG_LP_IIR2_K4_U			0x231
++#define MTK_PHY_RG_LP_IIR2_K5_L			0x232
++#define MTK_PHY_RG_LP_IIR2_K5_U			0x233
++
++#define MTK_PHY_RG_DEV1E_REG234			0x234
++#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK		GENMASK(0, 0)
++#define   MTK_PHY_LPF_X_AVERAGE_MASK		GENMASK(7, 4)
++#define   MTK_PHY_TR_LP_IIR_EEE_EN		BIT(12)
++
++#define MTK_PHY_RG_LPF_CNT_VAL			0x235
++
++#define MTK_PHY_RG_DEV1E_REG238			0x238
++#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK	GENMASK(8, 0)
++#define   MTK_PHY_LPI_SLV_SEND_TX_EN		BIT(12)
++
++#define MTK_PHY_RG_DEV1E_REG239			0x239
++#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK	GENMASK(8, 0)
++#define   MTK_PHY_LPI_TXPCS_LOC_RCV		BIT(12)
++
++#define MTK_PHY_RG_DEV1E_REG27C			0x27c
++#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK	GENMASK(12, 8)
++#define MTK_PHY_RG_DEV1E_REG27D			0x27d
++#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK	GENMASK(4, 0)
++
++#define MTK_PHY_RG_DEV1E_REG2C7			0x2c7
++#define   MTK_PHY_MAX_GAIN_MASK			GENMASK(4, 0)
++#define   MTK_PHY_MIN_GAIN_MASK			GENMASK(12, 8)
++
++#define MTK_PHY_RG_DEV1E_REG2D1			0x2d1
++#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK	GENMASK(7, 0)
++#define   MTK_PHY_LPI_SKIP_SD_SLV_TR		BIT(8)
++#define   MTK_PHY_LPI_TR_READY			BIT(9)
++#define   MTK_PHY_LPI_VCO_EEE_STG0_EN		BIT(10)
++
++#define MTK_PHY_RG_DEV1E_REG323			0x323
++#define   MTK_PHY_EEE_WAKE_MAS_INT_DC		BIT(0)
++#define   MTK_PHY_EEE_WAKE_SLV_INT_DC		BIT(4)
++
++#define MTK_PHY_RG_DEV1E_REG324			0x324
++#define   MTK_PHY_SMI_DETCNT_MAX_MASK		GENMASK(5, 0)
++#define   MTK_PHY_SMI_DET_MAX_EN		BIT(8)
++
++#define MTK_PHY_RG_DEV1E_REG326			0x326
++#define   MTK_PHY_LPI_MODE_SD_ON		BIT(0)
++#define   MTK_PHY_RESET_RANDUPD_CNT		BIT(1)
++#define   MTK_PHY_TREC_UPDATE_ENAB_CLR		BIT(2)
++#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF	BIT(4)
++#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP	BIT(5)
++
++#define MTK_PHY_LDO_PUMP_EN_PAIRAB		0x502
++#define MTK_PHY_LDO_PUMP_EN_PAIRCD		0x503
++
++#define MTK_PHY_DA_TX_R50_PAIR_A		0x53d
++#define MTK_PHY_DA_TX_R50_PAIR_B		0x53e
++#define MTK_PHY_DA_TX_R50_PAIR_C		0x53f
++#define MTK_PHY_DA_TX_R50_PAIR_D		0x540
++
++/* Registers on MDIO_MMD_VEND2 */
++#define MTK_PHY_LED0_ON_CTRL			0x24
++#define MTK_PHY_LED1_ON_CTRL			0x26
++#define   MTK_PHY_LED_ON_MASK			GENMASK(6, 0)
++#define   MTK_PHY_LED_ON_LINK1000		BIT(0)
++#define   MTK_PHY_LED_ON_LINK100		BIT(1)
++#define   MTK_PHY_LED_ON_LINK10			BIT(2)
++#define   MTK_PHY_LED_ON_LINK			(MTK_PHY_LED_ON_LINK10 |\
++						 MTK_PHY_LED_ON_LINK100 |\
++						 MTK_PHY_LED_ON_LINK1000)
++#define   MTK_PHY_LED_ON_LINKDOWN		BIT(3)
++#define   MTK_PHY_LED_ON_FDX			BIT(4) /* Full duplex */
++#define   MTK_PHY_LED_ON_HDX			BIT(5) /* Half duplex */
++#define   MTK_PHY_LED_ON_FORCE_ON		BIT(6)
++#define   MTK_PHY_LED_ON_POLARITY		BIT(14)
++#define   MTK_PHY_LED_ON_ENABLE			BIT(15)
++
++#define MTK_PHY_LED0_BLINK_CTRL			0x25
++#define MTK_PHY_LED1_BLINK_CTRL			0x27
++#define   MTK_PHY_LED_BLINK_1000TX		BIT(0)
++#define   MTK_PHY_LED_BLINK_1000RX		BIT(1)
++#define   MTK_PHY_LED_BLINK_100TX		BIT(2)
++#define   MTK_PHY_LED_BLINK_100RX		BIT(3)
++#define   MTK_PHY_LED_BLINK_10TX		BIT(4)
++#define   MTK_PHY_LED_BLINK_10RX		BIT(5)
++#define   MTK_PHY_LED_BLINK_RX			(MTK_PHY_LED_BLINK_10RX |\
++						 MTK_PHY_LED_BLINK_100RX |\
++						 MTK_PHY_LED_BLINK_1000RX)
++#define   MTK_PHY_LED_BLINK_TX			(MTK_PHY_LED_BLINK_10TX |\
++						 MTK_PHY_LED_BLINK_100TX |\
++						 MTK_PHY_LED_BLINK_1000TX)
++#define   MTK_PHY_LED_BLINK_COLLISION		BIT(6)
++#define   MTK_PHY_LED_BLINK_RX_CRC_ERR		BIT(7)
++#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR		BIT(8)
++#define   MTK_PHY_LED_BLINK_FORCE_BLINK		BIT(9)
++
++#define MTK_PHY_LED1_DEFAULT_POLARITIES		BIT(1)
++
++#define MTK_PHY_RG_BG_RASEL			0x115
++#define   MTK_PHY_RG_BG_RASEL_MASK		GENMASK(2, 0)
++
++/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
++#define RG_GPIO_MISC_TPBANK0			0x6f0
++#define   RG_GPIO_MISC_TPBANK0_BOOTMODE		GENMASK(11, 8)
++
++/* These macro privides efuse parsing for internal phy. */
++#define EFS_DA_TX_I2MPB_A(x)			(((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_B(x)			(((x) >> 6) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_C(x)			(((x) >> 12) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_D(x)			(((x) >> 18) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_A(x)		(((x) >> 24) & GENMASK(5, 0))
++
++#define EFS_DA_TX_AMP_OFFSET_B(x)		(((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_C(x)		(((x) >> 6) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_D(x)		(((x) >> 12) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_A(x)			(((x) >> 18) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_B(x)			(((x) >> 24) & GENMASK(5, 0))
++
++#define EFS_DA_TX_R50_C(x)			(((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_D(x)			(((x) >> 6) & GENMASK(5, 0))
++
++#define EFS_RG_BG_RASEL(x)			(((x) >> 4) & GENMASK(2, 0))
++#define EFS_RG_REXT_TRIM(x)			(((x) >> 7) & GENMASK(5, 0))
++
++enum {
++	NO_PAIR,
++	PAIR_A,
++	PAIR_B,
++	PAIR_C,
++	PAIR_D,
++};
++
++enum calibration_mode {
++	EFUSE_K,
++	SW_K
++};
++
++enum CAL_ITEM {
++	REXT,
++	TX_OFFSET,
++	TX_AMP,
++	TX_R50,
++	TX_VCM
++};
++
++enum CAL_MODE {
++	EFUSE_M,
++	SW_M
++};
++
++#define MTK_PHY_LED_STATE_FORCE_ON	0
++#define MTK_PHY_LED_STATE_FORCE_BLINK	1
++#define MTK_PHY_LED_STATE_NETDEV	2
++
++struct mtk_socphy_priv {
++	unsigned long		led_state;
++};
++
++struct mtk_socphy_shared {
++	u32			boottrap;
++	struct mtk_socphy_priv	priv[4];
++};
++
++static int mtk_socphy_read_page(struct phy_device *phydev)
++{
++	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++
++static int mtk_socphy_write_page(struct phy_device *phydev, int page)
++{
++	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++
++/* One calibration cycle consists of:
++ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
++ *   until AD_CAL_COMP is ready to output calibration result.
++ * 2.Wait until DA_CAL_CLK is available.
++ * 3.Fetch AD_CAL_COMP_OUT.
++ */
++static int cal_cycle(struct phy_device *phydev, int devad,
++		     u32 regnum, u16 mask, u16 cal_val)
++{
++	int reg_val;
++	int ret;
++
++	phy_modify_mmd(phydev, devad, regnum,
++		       mask, cal_val);
++	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
++			 MTK_PHY_DA_CALIN_FLAG);
++
++	ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
++					MTK_PHY_RG_AD_CAL_CLK, reg_val,
++					reg_val & MTK_PHY_DA_CAL_CLK, 500,
++					ANALOG_INTERNAL_OPERATION_MAX_US, false);
++	if (ret) {
++		phydev_err(phydev, "Calibration cycle timeout\n");
++		return ret;
++	}
++
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
++			   MTK_PHY_DA_CALIN_FLAG);
++	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >>
++			   MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
++	phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
++
++	return ret;
++}
++
++static int rext_fill_result(struct phy_device *phydev, u16 *buf)
++{
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
++		       MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
++		       MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
++
++	return 0;
++}
++
++static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++	u16 rext_cal_val[2];
++
++	rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
++	rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
++	rext_fill_result(phydev, rext_cal_val);
++
++	return 0;
++}
++
++static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
++{
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
++		       MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
++		       MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
++		       MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
++		       MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
++
++	return 0;
++}
++
++static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++	u16 tx_offset_cal_val[4];
++
++	tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
++	tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
++	tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
++	tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
++
++	tx_offset_fill_result(phydev, tx_offset_cal_val);
++
++	return 0;
++}
++
++static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
++{
++	int i;
++	int bias[16] = {};
++	const int vals_9461[16] = { 7, 1, 4, 7,
++				    7, 1, 4, 7,
++				    7, 1, 4, 7,
++				    7, 1, 4, 7 };
++	const int vals_9481[16] = { 10, 6, 6, 10,
++				    10, 6, 6, 10,
++				    10, 6, 6, 10,
++				    10, 6, 6, 10 };
++	switch (phydev->drv->phy_id) {
++	case MTK_GPHY_ID_MT7981:
++		/* We add some calibration to efuse values
++		 * due to board level influence.
++		 * GBE: +7, TBT: +1, HBT: +4, TST: +7
++		 */
++		memcpy(bias, (const void *)vals_9461, sizeof(bias));
++		break;
++	case MTK_GPHY_ID_MT7988:
++		memcpy(bias, (const void *)vals_9481, sizeof(bias));
++		break;
++	}
++
++	/* Prevent overflow */
++	for (i = 0; i < 12; i++) {
++		if (buf[i >> 2] + bias[i] > 63) {
++			buf[i >> 2] = 63;
++			bias[i] = 0;
++		}
++	}
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
++		       MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
++		       MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
++		       MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
++		       MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]);
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
++		       MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
++		       MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
++		       MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
++		       MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]);
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
++		       MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
++		       MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
++		       MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
++		       MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]);
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
++		       MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
++		       MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
++		       MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
++		       MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]);
++
++	return 0;
++}
++
++static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++	u16 tx_amp_cal_val[4];
++
++	tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
++	tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
++	tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
++	tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
++	tx_amp_fill_result(phydev, tx_amp_cal_val);
++
++	return 0;
++}
++
++static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
++			      u8 txg_calen_x)
++{
++	int bias = 0;
++	u16 reg, val;
++
++	if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
++		bias = -1;
++
++	val = clamp_val(bias + tx_r50_cal_val, 0, 63);
++
++	switch (txg_calen_x) {
++	case PAIR_A:
++		reg = MTK_PHY_DA_TX_R50_PAIR_A;
++		break;
++	case PAIR_B:
++		reg = MTK_PHY_DA_TX_R50_PAIR_B;
++		break;
++	case PAIR_C:
++		reg = MTK_PHY_DA_TX_R50_PAIR_C;
++		break;
++	case PAIR_D:
++		reg = MTK_PHY_DA_TX_R50_PAIR_D;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
++
++	return 0;
++}
++
++static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
++			    u8 txg_calen_x)
++{
++	u16 tx_r50_cal_val;
++
++	switch (txg_calen_x) {
++	case PAIR_A:
++		tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
++		break;
++	case PAIR_B:
++		tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
++		break;
++	case PAIR_C:
++		tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
++		break;
++	case PAIR_D:
++		tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
++		break;
++	default:
++		return -EINVAL;
++	}
++	tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
++
++	return 0;
++}
++
++static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
++{
++	u8 lower_idx, upper_idx, txreserve_val;
++	u8 lower_ret, upper_ret;
++	int ret;
++
++	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++			 MTK_PHY_RG_ANA_CALEN);
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++			   MTK_PHY_RG_CAL_CKINV);
++	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++			 MTK_PHY_RG_TXVOS_CALEN);
++
++	switch (rg_txreserve_x) {
++	case PAIR_A:
++		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++				   MTK_PHY_RG_DASN_DAC_IN0_A,
++				   MTK_PHY_DASN_DAC_IN0_A_MASK);
++		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++				   MTK_PHY_RG_DASN_DAC_IN1_A,
++				   MTK_PHY_DASN_DAC_IN1_A_MASK);
++		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++				 MTK_PHY_RG_ANA_CAL_RG0,
++				 MTK_PHY_RG_ZCALEN_A);
++		break;
++	case PAIR_B:
++		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++				   MTK_PHY_RG_DASN_DAC_IN0_B,
++				   MTK_PHY_DASN_DAC_IN0_B_MASK);
++		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++				   MTK_PHY_RG_DASN_DAC_IN1_B,
++				   MTK_PHY_DASN_DAC_IN1_B_MASK);
++		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++				 MTK_PHY_RG_ANA_CAL_RG1,
++				 MTK_PHY_RG_ZCALEN_B);
++		break;
++	case PAIR_C:
++		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++				   MTK_PHY_RG_DASN_DAC_IN0_C,
++				   MTK_PHY_DASN_DAC_IN0_C_MASK);
++		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++				   MTK_PHY_RG_DASN_DAC_IN1_C,
++				   MTK_PHY_DASN_DAC_IN1_C_MASK);
++		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++				 MTK_PHY_RG_ANA_CAL_RG1,
++				 MTK_PHY_RG_ZCALEN_C);
++		break;
++	case PAIR_D:
++		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++				   MTK_PHY_RG_DASN_DAC_IN0_D,
++				   MTK_PHY_DASN_DAC_IN0_D_MASK);
++		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++				   MTK_PHY_RG_DASN_DAC_IN1_D,
++				   MTK_PHY_DASN_DAC_IN1_D_MASK);
++		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++				 MTK_PHY_RG_ANA_CAL_RG1,
++				 MTK_PHY_RG_ZCALEN_D);
++		break;
++	default:
++		ret = -EINVAL;
++		goto restore;
++	}
++
++	lower_idx = TXRESERVE_MIN;
++	upper_idx = TXRESERVE_MAX;
++
++	phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
++	while ((upper_idx - lower_idx) > 1) {
++		txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
++		ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++				MTK_PHY_DA_RX_PSBN_TBT_MASK |
++				MTK_PHY_DA_RX_PSBN_HBT_MASK |
++				MTK_PHY_DA_RX_PSBN_GBE_MASK |
++				MTK_PHY_DA_RX_PSBN_LP_MASK,
++				txreserve_val << 12 | txreserve_val << 8 |
++				txreserve_val << 4 | txreserve_val);
++		if (ret == 1) {
++			upper_idx = txreserve_val;
++			upper_ret = ret;
++		} else if (ret == 0) {
++			lower_idx = txreserve_val;
++			lower_ret = ret;
++		} else {
++			goto restore;
++		}
++	}
++
++	if (lower_idx == TXRESERVE_MIN) {
++		lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
++				      MTK_PHY_RXADC_CTRL_RG9,
++				      MTK_PHY_DA_RX_PSBN_TBT_MASK |
++				      MTK_PHY_DA_RX_PSBN_HBT_MASK |
++				      MTK_PHY_DA_RX_PSBN_GBE_MASK |
++				      MTK_PHY_DA_RX_PSBN_LP_MASK,
++				      lower_idx << 12 | lower_idx << 8 |
++				      lower_idx << 4 | lower_idx);
++		ret = lower_ret;
++	} else if (upper_idx == TXRESERVE_MAX) {
++		upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
++				      MTK_PHY_RXADC_CTRL_RG9,
++				      MTK_PHY_DA_RX_PSBN_TBT_MASK |
++				      MTK_PHY_DA_RX_PSBN_HBT_MASK |
++				      MTK_PHY_DA_RX_PSBN_GBE_MASK |
++				      MTK_PHY_DA_RX_PSBN_LP_MASK,
++				      upper_idx << 12 | upper_idx << 8 |
++				      upper_idx << 4 | upper_idx);
++		ret = upper_ret;
++	}
++	if (ret < 0)
++		goto restore;
++
++	/* We calibrate TX-VCM in different logic. Check upper index and then
++	 * lower index. If this calibration is valid, apply lower index's result.
++	 */
++	ret = upper_ret - lower_ret;
++	if (ret == 1) {
++		ret = 0;
++		/* Make sure we use upper_idx in our calibration system */
++		cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++			  MTK_PHY_DA_RX_PSBN_TBT_MASK |
++			  MTK_PHY_DA_RX_PSBN_HBT_MASK |
++			  MTK_PHY_DA_RX_PSBN_GBE_MASK |
++			  MTK_PHY_DA_RX_PSBN_LP_MASK,
++			  upper_idx << 12 | upper_idx << 8 |
++			  upper_idx << 4 | upper_idx);
++		phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
++	} else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
++		   lower_ret == 1) {
++		ret = 0;
++		cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++			  MTK_PHY_DA_RX_PSBN_TBT_MASK |
++			  MTK_PHY_DA_RX_PSBN_HBT_MASK |
++			  MTK_PHY_DA_RX_PSBN_GBE_MASK |
++			  MTK_PHY_DA_RX_PSBN_LP_MASK,
++			  lower_idx << 12 | lower_idx << 8 |
++			  lower_idx << 4 | lower_idx);
++		phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
++			    lower_idx);
++	} else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
++		   lower_ret == 0) {
++		ret = 0;
++		phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n",
++			    upper_idx);
++	} else {
++		ret = -EINVAL;
++	}
++
++restore:
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++			   MTK_PHY_RG_ANA_CALEN);
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++			   MTK_PHY_RG_TXVOS_CALEN);
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++			   MTK_PHY_RG_ZCALEN_A);
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++			   MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
++			   MTK_PHY_RG_ZCALEN_D);
++
++	return ret;
++}
++
++static void mt798x_phy_common_finetune(struct phy_device *phydev)
++{
++	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++	/* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
++	__phy_write(phydev, 0x11, 0xc71);
++	__phy_write(phydev, 0x12, 0xc);
++	__phy_write(phydev, 0x10, 0x8fae);
++
++	/* EnabRandUpdTrig = 1 */
++	__phy_write(phydev, 0x11, 0x2f00);
++	__phy_write(phydev, 0x12, 0xe);
++	__phy_write(phydev, 0x10, 0x8fb0);
++
++	/* NormMseLoThresh = 85 */
++	__phy_write(phydev, 0x11, 0x55a0);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x83aa);
++
++	/* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
++	__phy_write(phydev, 0x11, 0x240);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x9680);
++
++	/* TrFreeze = 0 (mt7988 default) */
++	__phy_write(phydev, 0x11, 0x0);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x9686);
++
++	/* SSTrKp100 = 5 */
++	/* SSTrKf100 = 6 */
++	/* SSTrKp1000Mas = 5 */
++	/* SSTrKf1000Mas = 6 */
++	/* SSTrKp1000Slv = 5 */
++	/* SSTrKf1000Slv = 6 */
++	__phy_write(phydev, 0x11, 0xbaef);
++	__phy_write(phydev, 0x12, 0x2e);
++	__phy_write(phydev, 0x10, 0x968c);
++	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++}
++
++static void mt7981_phy_finetune(struct phy_device *phydev)
++{
++	u16 val[8] = { 0x01ce, 0x01c1,
++		       0x020f, 0x0202,
++		       0x03d0, 0x03c0,
++		       0x0013, 0x0005 };
++	int i, k;
++
++	/* 100M eye finetune:
++	 * Keep middle level of TX MLT3 shapper as default.
++	 * Only change TX MLT3 overshoot level here.
++	 */
++	for (k = 0, i = 1; i < 12; i++) {
++		if (i % 3 == 0)
++			continue;
++		phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
++	}
++
++	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++	/* ResetSyncOffset = 6 */
++	__phy_write(phydev, 0x11, 0x600);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x8fc0);
++
++	/* VgaDecRate = 1 */
++	__phy_write(phydev, 0x11, 0x4c2a);
++	__phy_write(phydev, 0x12, 0x3e);
++	__phy_write(phydev, 0x10, 0x8fa4);
++
++	/* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
++	 * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
++	 */
++	__phy_write(phydev, 0x11, 0xd10a);
++	__phy_write(phydev, 0x12, 0x34);
++	__phy_write(phydev, 0x10, 0x8f82);
++
++	/* VcoSlicerThreshBitsHigh */
++	__phy_write(phydev, 0x11, 0x5555);
++	__phy_write(phydev, 0x12, 0x55);
++	__phy_write(phydev, 0x10, 0x8ec0);
++	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++	/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
++		       MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
++		       BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
++
++	/* rg_tr_lpf_cnt_val = 512 */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
++
++	/* IIR2 related */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
++
++	/* FFE peaking */
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
++		       MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
++		       MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
++
++	/* Disable LDO pump */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
++	/* Adjust LDO output voltage */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
++}
++
++static void mt7988_phy_finetune(struct phy_device *phydev)
++{
++	u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
++			0x020d, 0x0206, 0x0384, 0x03d0,
++			0x03c6, 0x030a, 0x0011, 0x0005 };
++	int i;
++
++	/* Set default MLT3 shaper first */
++	for (i = 0; i < 12; i++)
++		phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
++
++	/* TCT finetune */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
++
++	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++	/* ResetSyncOffset = 5 */
++	__phy_write(phydev, 0x11, 0x500);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x8fc0);
++
++	/* VgaDecRate is 1 at default on mt7988 */
++
++	/* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
++	 * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
++	 */
++	__phy_write(phydev, 0x11, 0xb90a);
++	__phy_write(phydev, 0x12, 0x6f);
++	__phy_write(phydev, 0x10, 0x8f82);
++
++	/* RemAckCntLimitCtrl = 1 */
++	__phy_write(phydev, 0x11, 0xfbba);
++	__phy_write(phydev, 0x12, 0xc3);
++	__phy_write(phydev, 0x10, 0x87f8);
++
++	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++	/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
++		       MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
++		       BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
++
++	/* rg_tr_lpf_cnt_val = 1023 */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
++}
++
++static void mt798x_phy_eee(struct phy_device *phydev)
++{
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++		       MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
++		       MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
++		       MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
++		       FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
++		       FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++		       MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
++		       MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++		       FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++				  0xff));
++
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++			   MTK_PHY_RG_TESTMUX_ADC_CTRL,
++			   MTK_PHY_RG_TXEN_DIG_MASK);
++
++	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++			 MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
++
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++			   MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
++		       MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
++		       MTK_PHY_LPI_SLV_SEND_TX_EN,
++		       FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
++
++	/* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
++			   MTK_PHY_LPI_TXPCS_LOC_RCV);
++
++	/* This also fixes some IoT issues, such as CH340 */
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
++		       MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
++		       FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
++		       FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
++		       MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
++		       FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
++				  0x33) |
++		       MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
++		       MTK_PHY_LPI_VCO_EEE_STG0_EN);
++
++	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
++			 MTK_PHY_EEE_WAKE_MAS_INT_DC |
++			 MTK_PHY_EEE_WAKE_SLV_INT_DC);
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
++		       MTK_PHY_SMI_DETCNT_MAX_MASK,
++		       FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
++		       MTK_PHY_SMI_DET_MAX_EN);
++
++	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
++			 MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
++			 MTK_PHY_TREC_UPDATE_ENAB_CLR |
++			 MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
++			 MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
++
++	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++	/* Regsigdet_sel_1000 = 0 */
++	__phy_write(phydev, 0x11, 0xb);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x9690);
++
++	/* REG_EEE_st2TrKf1000 = 2 */
++	__phy_write(phydev, 0x11, 0x114f);
++	__phy_write(phydev, 0x12, 0x2);
++	__phy_write(phydev, 0x10, 0x969a);
++
++	/* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
++	__phy_write(phydev, 0x11, 0x3028);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x969e);
++
++	/* RegEEE_slv_wake_int_timer_tar = 8 */
++	__phy_write(phydev, 0x11, 0x5010);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x96a0);
++
++	/* RegEEE_trfreeze_timer2 = 586 */
++	__phy_write(phydev, 0x11, 0x24a);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x96a8);
++
++	/* RegEEE100Stg1_tar = 16 */
++	__phy_write(phydev, 0x11, 0x3210);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x96b8);
++
++	/* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
++	__phy_write(phydev, 0x11, 0x1463);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x96ca);
++
++	/* DfeTailEnableVgaThresh1000 = 27 */
++	__phy_write(phydev, 0x11, 0x36);
++	__phy_write(phydev, 0x12, 0x0);
++	__phy_write(phydev, 0x10, 0x8f80);
++	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
++	__phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
++		     FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
++
++	__phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
++		     FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
++	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++		       MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
++		       MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++		       FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff));
++}
++
++static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
++		  u8 start_pair, u8 end_pair)
++{
++	u8 pair_n;
++	int ret;
++
++	for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
++		/* TX_OFFSET & TX_AMP have no SW calibration. */
++		switch (cal_item) {
++		case TX_VCM:
++			ret = tx_vcm_cal_sw(phydev, pair_n);
++			break;
++		default:
++			return -EINVAL;
++		}
++		if (ret)
++			return ret;
++	}
++	return 0;
++}
++
++static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
++		     u8 start_pair, u8 end_pair, u32 *buf)
++{
++	u8 pair_n;
++	int ret;
++
++	for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
++		/* TX_VCM has no efuse calibration. */
++		switch (cal_item) {
++		case REXT:
++			ret = rext_cal_efuse(phydev, buf);
++			break;
++		case TX_OFFSET:
++			ret = tx_offset_cal_efuse(phydev, buf);
++			break;
++		case TX_AMP:
++			ret = tx_amp_cal_efuse(phydev, buf);
++			break;
++		case TX_R50:
++			ret = tx_r50_cal_efuse(phydev, buf, pair_n);
++			break;
++		default:
++			return -EINVAL;
++		}
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
++		     enum CAL_MODE cal_mode, u8 start_pair,
++		     u8 end_pair, u32 *buf)
++{
++	int ret;
++
++	switch (cal_mode) {
++	case EFUSE_M:
++		ret = cal_efuse(phydev, cal_item, start_pair,
++				end_pair, buf);
++		break;
++	case SW_M:
++		ret = cal_sw(phydev, cal_item, start_pair, end_pair);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	if (ret) {
++		phydev_err(phydev, "cal %d failed\n", cal_item);
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static int mt798x_phy_calibration(struct phy_device *phydev)
++{
++	int ret = 0;
++	u32 *buf;
++	size_t len;
++	struct nvmem_cell *cell;
++
++	cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
++	if (IS_ERR(cell)) {
++		if (PTR_ERR(cell) == -EPROBE_DEFER)
++			return PTR_ERR(cell);
++		return 0;
++	}
++
++	buf = (u32 *)nvmem_cell_read(cell, &len);
++	if (IS_ERR(buf))
++		return PTR_ERR(buf);
++	nvmem_cell_put(cell);
++
++	if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
++		phydev_err(phydev, "invalid efuse data\n");
++		ret = -EINVAL;
++		goto out;
++	}
++
++	ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++	if (ret)
++		goto out;
++	ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++	if (ret)
++		goto out;
++	ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++	if (ret)
++		goto out;
++	ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
++	if (ret)
++		goto out;
++	ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
++	if (ret)
++		goto out;
++
++out:
++	kfree(buf);
++	return ret;
++}
++
++static int mt798x_phy_config_init(struct phy_device *phydev)
++{
++	switch (phydev->drv->phy_id) {
++	case MTK_GPHY_ID_MT7981:
++		mt7981_phy_finetune(phydev);
++		break;
++	case MTK_GPHY_ID_MT7988:
++		mt7988_phy_finetune(phydev);
++		break;
++	}
++
++	mt798x_phy_common_finetune(phydev);
++	mt798x_phy_eee(phydev);
++
++	return mt798x_phy_calibration(phydev);
++}
++
++static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
++				    bool on)
++{
++	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++	struct mtk_socphy_priv *priv = phydev->priv;
++	bool changed;
++
++	if (on)
++		changed = !test_and_set_bit(bit_on, &priv->led_state);
++	else
++		changed = !!test_and_clear_bit(bit_on, &priv->led_state);
++
++	changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
++					(index ? 16 : 0), &priv->led_state);
++	if (changed)
++		return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++				      MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++				      MTK_PHY_LED_ON_MASK,
++				      on ? MTK_PHY_LED_ON_FORCE_ON : 0);
++	else
++		return 0;
++}
++
++static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
++				       bool blinking)
++{
++	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
++	struct mtk_socphy_priv *priv = phydev->priv;
++	bool changed;
++
++	if (blinking)
++		changed = !test_and_set_bit(bit_blink, &priv->led_state);
++	else
++		changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
++
++	changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
++			      (index ? 16 : 0), &priv->led_state);
++	if (changed)
++		return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++				     MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL,
++				     blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
++	else
++		return 0;
++}
++
++static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
++				    unsigned long *delay_on,
++				    unsigned long *delay_off)
++{
++	bool blinking = false;
++	int err = 0;
++
++	if (index > 1)
++		return -EINVAL;
++
++	if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
++		blinking = true;
++		*delay_on = 50;
++		*delay_off = 50;
++	}
++
++	err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
++	if (err)
++		return err;
++
++	return mt798x_phy_hw_led_on_set(phydev, index, false);
++}
++
++static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
++					 u8 index, enum led_brightness value)
++{
++	int err;
++
++	err = mt798x_phy_hw_led_blink_set(phydev, index, false);
++	if (err)
++		return err;
++
++	return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
++}
++
++static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++						 BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
++						 BIT(TRIGGER_NETDEV_LINK)        |
++						 BIT(TRIGGER_NETDEV_LINK_10)     |
++						 BIT(TRIGGER_NETDEV_LINK_100)    |
++						 BIT(TRIGGER_NETDEV_LINK_1000)   |
++						 BIT(TRIGGER_NETDEV_RX)          |
++						 BIT(TRIGGER_NETDEV_TX));
++
++static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++					  unsigned long rules)
++{
++	if (index > 1)
++		return -EINVAL;
++
++	/* All combinations of the supported triggers are allowed */
++	if (rules & ~supported_triggers)
++		return -EOPNOTSUPP;
++
++	return 0;
++};
++
++static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
++					 unsigned long *rules)
++{
++	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
++	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++	struct mtk_socphy_priv *priv = phydev->priv;
++	int on, blink;
++
++	if (index > 1)
++		return -EINVAL;
++
++	on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++			  index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
++
++	if (on < 0)
++		return -EIO;
++
++	blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++			     index ? MTK_PHY_LED1_BLINK_CTRL :
++				     MTK_PHY_LED0_BLINK_CTRL);
++	if (blink < 0)
++		return -EIO;
++
++	if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX |
++		   MTK_PHY_LED_ON_LINKDOWN)) ||
++	    (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
++		set_bit(bit_netdev, &priv->led_state);
++	else
++		clear_bit(bit_netdev, &priv->led_state);
++
++	if (on & MTK_PHY_LED_ON_FORCE_ON)
++		set_bit(bit_on, &priv->led_state);
++	else
++		clear_bit(bit_on, &priv->led_state);
++
++	if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
++		set_bit(bit_blink, &priv->led_state);
++	else
++		clear_bit(bit_blink, &priv->led_state);
++
++	if (!rules)
++		return 0;
++
++	if (on & MTK_PHY_LED_ON_LINK)
++		*rules |= BIT(TRIGGER_NETDEV_LINK);
++
++	if (on & MTK_PHY_LED_ON_LINK10)
++		*rules |= BIT(TRIGGER_NETDEV_LINK_10);
++
++	if (on & MTK_PHY_LED_ON_LINK100)
++		*rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++	if (on & MTK_PHY_LED_ON_LINK1000)
++		*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++	if (on & MTK_PHY_LED_ON_FDX)
++		*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
++
++	if (on & MTK_PHY_LED_ON_HDX)
++		*rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
++
++	if (blink & MTK_PHY_LED_BLINK_RX)
++		*rules |= BIT(TRIGGER_NETDEV_RX);
++
++	if (blink & MTK_PHY_LED_BLINK_TX)
++		*rules |= BIT(TRIGGER_NETDEV_TX);
++
++	return 0;
++};
++
++static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
++					 unsigned long rules)
++{
++	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++	struct mtk_socphy_priv *priv = phydev->priv;
++	u16 on = 0, blink = 0;
++	int ret;
++
++	if (index > 1)
++		return -EINVAL;
++
++	if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
++		on |= MTK_PHY_LED_ON_FDX;
++
++	if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
++		on |= MTK_PHY_LED_ON_HDX;
++
++	if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
++		on |= MTK_PHY_LED_ON_LINK10;
++
++	if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
++		on |= MTK_PHY_LED_ON_LINK100;
++
++	if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
++		on |= MTK_PHY_LED_ON_LINK1000;
++
++	if (rules & BIT(TRIGGER_NETDEV_RX)) {
++		blink |= (on & MTK_PHY_LED_ON_LINK) ?
++			  (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) :
++			  MTK_PHY_LED_BLINK_RX;
++	}
++
++	if (rules & BIT(TRIGGER_NETDEV_TX)) {
++		blink |= (on & MTK_PHY_LED_ON_LINK) ?
++			  (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) :
++			  MTK_PHY_LED_BLINK_TX;
++	}
++
++	if (blink || on)
++		set_bit(bit_netdev, &priv->led_state);
++	else
++		clear_bit(bit_netdev, &priv->led_state);
++
++	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++				MTK_PHY_LED1_ON_CTRL :
++				MTK_PHY_LED0_ON_CTRL,
++			     MTK_PHY_LED_ON_FDX     |
++			     MTK_PHY_LED_ON_HDX     |
++			     MTK_PHY_LED_ON_LINK,
++			     on);
++
++	if (ret)
++		return ret;
++
++	return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++				MTK_PHY_LED1_BLINK_CTRL :
++				MTK_PHY_LED0_BLINK_CTRL, blink);
++};
++
++static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
++{
++	struct mtk_socphy_shared *priv = phydev->shared->priv;
++	u32 polarities;
++
++	if (led_num == 0)
++		polarities = ~(priv->boottrap);
++	else
++		polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
++
++	if (polarities & BIT(phydev->mdio.addr))
++		return true;
++
++	return false;
++}
++
++static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
++{
++	struct pinctrl *pinctrl;
++	int index;
++
++	/* Setup LED polarity according to bootstrap use of LED pins */
++	for (index = 0; index < 2; ++index)
++		phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++				MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++			       MTK_PHY_LED_ON_POLARITY,
++			       mt7988_phy_led_get_polarity(phydev, index) ?
++				MTK_PHY_LED_ON_POLARITY : 0);
++
++	/* Only now setup pinctrl to avoid bogus blinking */
++	pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
++	if (IS_ERR(pinctrl))
++		dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n");
++
++	return 0;
++}
++
++static int mt7988_phy_probe_shared(struct phy_device *phydev)
++{
++	struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
++	struct mtk_socphy_shared *shared = phydev->shared->priv;
++	struct regmap *regmap;
++	u32 reg;
++	int ret;
++
++	/* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
++	 * LED_C and LED_D respectively. At the same time those pins are used to
++	 * bootstrap configuration of the reference clock source (LED_A),
++	 * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
++	 * In practise this is done using a LED and a resistor pulling the pin
++	 * either to GND or to VIO.
++	 * The detected value at boot time is accessible at run-time using the
++	 * TPBANK0 register located in the gpio base of the pinctrl, in order
++	 * to read it here it needs to be referenced by a phandle called
++	 * 'mediatek,pio' in the MDIO bus hosting the PHY.
++	 * The 4 bits in TPBANK0 are kept as package shared data and are used to
++	 * set LED polarity for each of the LED0.
++	 */
++	regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
++	if (IS_ERR(regmap))
++		return PTR_ERR(regmap);
++
++	ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, &reg);
++	if (ret)
++		return ret;
++
++	shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
++
++	return 0;
++}
++
++static void mt798x_phy_leds_state_init(struct phy_device *phydev)
++{
++	int i;
++
++	for (i = 0; i < 2; ++i)
++		mt798x_phy_led_hw_control_get(phydev, i, NULL);
++}
++
++static int mt7988_phy_probe(struct phy_device *phydev)
++{
++	struct mtk_socphy_shared *shared;
++	struct mtk_socphy_priv *priv;
++	int err;
++
++	if (phydev->mdio.addr > 3)
++		return -EINVAL;
++
++	err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
++				    sizeof(struct mtk_socphy_shared));
++	if (err)
++		return err;
++
++	if (phy_package_probe_once(phydev)) {
++		err = mt7988_phy_probe_shared(phydev);
++		if (err)
++			return err;
++	}
++
++	shared = phydev->shared->priv;
++	priv = &shared->priv[phydev->mdio.addr];
++
++	phydev->priv = priv;
++
++	mt798x_phy_leds_state_init(phydev);
++
++	err = mt7988_phy_fix_leds_polarities(phydev);
++	if (err)
++		return err;
++
++	/* Disable TX power saving at probing to:
++	 * 1. Meet common mode compliance test criteria
++	 * 2. Make sure that TX-VCM calibration works fine
++	 */
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
++		       MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
++
++	return mt798x_phy_calibration(phydev);
++}
++
++static int mt7981_phy_probe(struct phy_device *phydev)
++{
++	struct mtk_socphy_priv *priv;
++
++	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
++			    GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	phydev->priv = priv;
++
++	mt798x_phy_leds_state_init(phydev);
++
++	return mt798x_phy_calibration(phydev);
++}
++
++static struct phy_driver mtk_socphy_driver[] = {
++	{
++		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
++		.name		= "MediaTek MT7981 PHY",
++		.config_init	= mt798x_phy_config_init,
++		.config_intr	= genphy_no_config_intr,
++		.handle_interrupt = genphy_handle_interrupt_no_ack,
++		.probe		= mt7981_phy_probe,
++		.suspend	= genphy_suspend,
++		.resume		= genphy_resume,
++		.read_page	= mtk_socphy_read_page,
++		.write_page	= mtk_socphy_write_page,
++		.led_blink_set	= mt798x_phy_led_blink_set,
++		.led_brightness_set = mt798x_phy_led_brightness_set,
++		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
++		.led_hw_control_set = mt798x_phy_led_hw_control_set,
++		.led_hw_control_get = mt798x_phy_led_hw_control_get,
++	},
++	{
++		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
++		.name		= "MediaTek MT7988 PHY",
++		.config_init	= mt798x_phy_config_init,
++		.config_intr	= genphy_no_config_intr,
++		.handle_interrupt = genphy_handle_interrupt_no_ack,
++		.probe		= mt7988_phy_probe,
++		.suspend	= genphy_suspend,
++		.resume		= genphy_resume,
++		.read_page	= mtk_socphy_read_page,
++		.write_page	= mtk_socphy_write_page,
++		.led_blink_set	= mt798x_phy_led_blink_set,
++		.led_brightness_set = mt798x_phy_led_brightness_set,
++		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
++		.led_hw_control_set = mt798x_phy_led_hw_control_set,
++		.led_hw_control_get = mt798x_phy_led_hw_control_get,
++	},
++};
++
++module_phy_driver(mtk_socphy_driver);
++
++static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
++	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
++	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
++	{ }
++};
++
++MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver");
++MODULE_AUTHOR("Daniel Golle <daniel at makrotopia.org>");
++MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang at mediatek.com>");
++MODULE_LICENSE("GPL");
++
++MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -0,0 +1,148 @@
++// SPDX-License-Identifier: GPL-2.0+
++#include <linux/of.h>
++#include <linux/bitfield.h>
++#include <linux/module.h>
++#include <linux/phy.h>
++
++#define MTK_EXT_PAGE_ACCESS		0x1f
++#define MTK_PHY_PAGE_STANDARD		0x0000
++#define MTK_PHY_PAGE_EXTENDED		0x0001
++#define MTK_PHY_PAGE_EXTENDED_2		0x0002
++#define MTK_PHY_PAGE_EXTENDED_3		0x0003
++#define MTK_PHY_PAGE_EXTENDED_2A30	0x2a30
++#define MTK_PHY_PAGE_EXTENDED_52B5	0x52b5
++
++static int mtk_gephy_read_page(struct phy_device *phydev)
++{
++	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++
++static int mtk_gephy_write_page(struct phy_device *phydev, int page)
++{
++	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++
++static void mtk_gephy_config_init(struct phy_device *phydev)
++{
++	/* Disable EEE */
++	phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
++
++	/* Enable HW auto downshift */
++	phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
++
++	/* Increase SlvDPSready time */
++	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++	__phy_write(phydev, 0x10, 0xafae);
++	__phy_write(phydev, 0x12, 0x2f);
++	__phy_write(phydev, 0x10, 0x8fae);
++	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++	/* Adjust 100_mse_threshold */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
++
++	/* Disable mcc */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
++}
++
++static int mt7530_phy_config_init(struct phy_device *phydev)
++{
++	mtk_gephy_config_init(phydev);
++
++	/* Increase post_update_timer */
++	phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
++
++	return 0;
++}
++
++static int mt7530_led_config_of(struct phy_device *phydev)
++{
++	struct device_node *np = phydev->mdio.dev.of_node;
++	const __be32 *paddr;
++	int len;
++	int i;
++
++	paddr = of_get_property(np, "mediatek,led-config", &len);
++	if (!paddr)
++		return 0;
++
++	if (len < (2 * sizeof(*paddr)))
++		return -EINVAL;
++
++	len /= sizeof(*paddr);
++
++	phydev_warn(phydev, "Configure LED registers (num=%d)\n", len);
++	for (i = 0; i < len - 1; i += 2) {
++		u32 reg;
++		u32 val;
++
++		reg = be32_to_cpup(paddr + i);
++		val = be32_to_cpup(paddr + i + 1);
++
++		phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, val);
++	}
++
++	return 0;
++}
++
++static int mt7531_phy_config_init(struct phy_device *phydev)
++{
++	mtk_gephy_config_init(phydev);
++
++	/* PHY link down power saving enable */
++	phy_set_bits(phydev, 0x17, BIT(4));
++	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
++
++	/* Set TX Pair delay selection */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
++
++	/* LED Config*/
++	mt7530_led_config_of(phydev);
++
++	return 0;
++}
++
++static struct phy_driver mtk_gephy_driver[] = {
++	{
++		PHY_ID_MATCH_EXACT(0x03a29412),
++		.name		= "MediaTek MT7530 PHY",
++		.config_init	= mt7530_phy_config_init,
++		/* Interrupts are handled by the switch, not the PHY
++		 * itself.
++		 */
++		.config_intr	= genphy_no_config_intr,
++		.handle_interrupt = genphy_handle_interrupt_no_ack,
++		.suspend	= genphy_suspend,
++		.resume		= genphy_resume,
++		.read_page	= mtk_gephy_read_page,
++		.write_page	= mtk_gephy_write_page,
++	},
++	{
++		PHY_ID_MATCH_EXACT(0x03a29441),
++		.name		= "MediaTek MT7531 PHY",
++		.config_init	= mt7531_phy_config_init,
++		/* Interrupts are handled by the switch, not the PHY
++		 * itself.
++		 */
++		.config_intr	= genphy_no_config_intr,
++		.handle_interrupt = genphy_handle_interrupt_no_ack,
++		.suspend	= genphy_suspend,
++		.resume		= genphy_resume,
++		.read_page	= mtk_gephy_read_page,
++		.write_page	= mtk_gephy_write_page,
++	},
++};
++
++module_phy_driver(mtk_gephy_driver);
++
++static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
++	{ PHY_ID_MATCH_EXACT(0x03a29441) },
++	{ PHY_ID_MATCH_EXACT(0x03a29412) },
++	{ }
++};
++
++MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
++MODULE_AUTHOR("DENG, Qingfang <dqfext at gmail.com>");
++MODULE_LICENSE("GPL");
++
++MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
diff --git a/target/linux/mediatek/patches-6.6/733-02-net-phy-mediatek-Fix-spelling-errors-and-rearrange-v.patch b/target/linux/mediatek/patches-6.6/733-02-net-phy-mediatek-Fix-spelling-errors-and-rearrange-v.patch
new file mode 100644
index 0000000000..901949fe9f
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-02-net-phy-mediatek-Fix-spelling-errors-and-rearrange-v.patch
@@ -0,0 +1,62 @@
+From 12054d38fc55adbfa2b40299ad8af3449d882ee2 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:06 +0800
+Subject: [PATCH 02/13] net: phy: mediatek: Fix spelling errors and rearrange
+ variables
+
+This patch fixes spelling errors which comes from mediatek-ge-soc.c and
+rearrange variables with reverse Xmas tree order.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -408,16 +408,17 @@ static int tx_offset_cal_efuse(struct ph
+ 
+ static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
+ {
+-	int i;
+-	int bias[16] = {};
+-	const int vals_9461[16] = { 7, 1, 4, 7,
+-				    7, 1, 4, 7,
+-				    7, 1, 4, 7,
+-				    7, 1, 4, 7 };
+ 	const int vals_9481[16] = { 10, 6, 6, 10,
+ 				    10, 6, 6, 10,
+ 				    10, 6, 6, 10,
+ 				    10, 6, 6, 10 };
++	const int vals_9461[16] = { 7, 1, 4, 7,
++				    7, 1, 4, 7,
++				    7, 1, 4, 7,
++				    7, 1, 4, 7 };
++	int bias[16] = {};
++	int i;
++
+ 	switch (phydev->drv->phy_id) {
+ 	case MTK_GPHY_ID_MT7981:
+ 		/* We add some calibration to efuse values
+@@ -1069,10 +1070,10 @@ static int start_cal(struct phy_device *
+ 
+ static int mt798x_phy_calibration(struct phy_device *phydev)
+ {
++	struct nvmem_cell *cell;
+ 	int ret = 0;
+-	u32 *buf;
+ 	size_t len;
+-	struct nvmem_cell *cell;
++	u32 *buf;
+ 
+ 	cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
+ 	if (IS_ERR(cell)) {
+@@ -1415,7 +1416,7 @@ static int mt7988_phy_probe_shared(struc
+ 	 * LED_C and LED_D respectively. At the same time those pins are used to
+ 	 * bootstrap configuration of the reference clock source (LED_A),
+ 	 * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
+-	 * In practise this is done using a LED and a resistor pulling the pin
++	 * In practice this is done using a LED and a resistor pulling the pin
+ 	 * either to GND or to VIO.
+ 	 * The detected value at boot time is accessible at run-time using the
+ 	 * TPBANK0 register located in the gpio base of the pinctrl, in order
diff --git a/target/linux/mediatek/patches-6.6/733-03-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch b/target/linux/mediatek/patches-6.6/733-03-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch
new file mode 100644
index 0000000000..9e6ae4b136
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-03-net-phy-mediatek-Move-LED-helper-functions-into-mtk-.patch
@@ -0,0 +1,742 @@
+From 434e41555c45ec10b19320024163bb009da168bc Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:07 +0800
+Subject: [PATCH 03/13] net: phy: mediatek: Move LED helper functions into mtk
+ phy lib
+
+This patch creates mtk-phy-lib.c & mtk-phy.h and integrates mtk-ge-soc.c's
+LED helper functions so that we can use those helper functions in other
+MTK's ethernet phy driver.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/Kconfig       |   5 +
+ drivers/net/phy/mediatek/Makefile      |   1 +
+ drivers/net/phy/mediatek/mtk-ge-soc.c  | 262 +++----------------------
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 251 +++++++++++++++++++++++
+ drivers/net/phy/mediatek/mtk.h         |  82 ++++++++
+ 6 files changed, 368 insertions(+), 235 deletions(-)
+ create mode 100644 drivers/net/phy/mediatek/mtk-phy-lib.c
+ create mode 100644 drivers/net/phy/mediatek/mtk.h
+
+--- a/drivers/net/phy/mediatek/Kconfig
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -1,6 +1,10 @@
+ # SPDX-License-Identifier: GPL-2.0-only
++config MTK_NET_PHYLIB
++	tristate
++
+ config MEDIATEK_GE_PHY
+ 	tristate "MediaTek Gigabit Ethernet PHYs"
++	select MTK_NET_PHYLIB
+ 	help
+ 	  Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
+ 
+@@ -13,6 +17,7 @@ config MEDIATEK_GE_SOC_PHY
+ 	tristate "MediaTek SoC Ethernet PHYs"
+ 	depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
+ 	select NVMEM_MTK_EFUSE
++	select MTK_NET_PHYLIB
+ 	help
+ 	  Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+ 
+--- a/drivers/net/phy/mediatek/Makefile
++++ b/drivers/net/phy/mediatek/Makefile
+@@ -1,3 +1,4 @@
+ # SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_MTK_NET_PHYLIB)		+= mtk-phy-lib.o
+ obj-$(CONFIG_MEDIATEK_GE_PHY)		+= mtk-ge.o
+ obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)	+= mtk-ge-soc.o
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -8,6 +8,8 @@
+ #include <linux/phy.h>
+ #include <linux/regmap.h>
+ 
++#include "mtk.h"
++
+ #define MTK_GPHY_ID_MT7981			0x03a29461
+ #define MTK_GPHY_ID_MT7988			0x03a29481
+ 
+@@ -210,41 +212,6 @@
+ #define MTK_PHY_DA_TX_R50_PAIR_D		0x540
+ 
+ /* Registers on MDIO_MMD_VEND2 */
+-#define MTK_PHY_LED0_ON_CTRL			0x24
+-#define MTK_PHY_LED1_ON_CTRL			0x26
+-#define   MTK_PHY_LED_ON_MASK			GENMASK(6, 0)
+-#define   MTK_PHY_LED_ON_LINK1000		BIT(0)
+-#define   MTK_PHY_LED_ON_LINK100		BIT(1)
+-#define   MTK_PHY_LED_ON_LINK10			BIT(2)
+-#define   MTK_PHY_LED_ON_LINK			(MTK_PHY_LED_ON_LINK10 |\
+-						 MTK_PHY_LED_ON_LINK100 |\
+-						 MTK_PHY_LED_ON_LINK1000)
+-#define   MTK_PHY_LED_ON_LINKDOWN		BIT(3)
+-#define   MTK_PHY_LED_ON_FDX			BIT(4) /* Full duplex */
+-#define   MTK_PHY_LED_ON_HDX			BIT(5) /* Half duplex */
+-#define   MTK_PHY_LED_ON_FORCE_ON		BIT(6)
+-#define   MTK_PHY_LED_ON_POLARITY		BIT(14)
+-#define   MTK_PHY_LED_ON_ENABLE			BIT(15)
+-
+-#define MTK_PHY_LED0_BLINK_CTRL			0x25
+-#define MTK_PHY_LED1_BLINK_CTRL			0x27
+-#define   MTK_PHY_LED_BLINK_1000TX		BIT(0)
+-#define   MTK_PHY_LED_BLINK_1000RX		BIT(1)
+-#define   MTK_PHY_LED_BLINK_100TX		BIT(2)
+-#define   MTK_PHY_LED_BLINK_100RX		BIT(3)
+-#define   MTK_PHY_LED_BLINK_10TX		BIT(4)
+-#define   MTK_PHY_LED_BLINK_10RX		BIT(5)
+-#define   MTK_PHY_LED_BLINK_RX			(MTK_PHY_LED_BLINK_10RX |\
+-						 MTK_PHY_LED_BLINK_100RX |\
+-						 MTK_PHY_LED_BLINK_1000RX)
+-#define   MTK_PHY_LED_BLINK_TX			(MTK_PHY_LED_BLINK_10TX |\
+-						 MTK_PHY_LED_BLINK_100TX |\
+-						 MTK_PHY_LED_BLINK_1000TX)
+-#define   MTK_PHY_LED_BLINK_COLLISION		BIT(6)
+-#define   MTK_PHY_LED_BLINK_RX_CRC_ERR		BIT(7)
+-#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR		BIT(8)
+-#define   MTK_PHY_LED_BLINK_FORCE_BLINK		BIT(9)
+-
+ #define MTK_PHY_LED1_DEFAULT_POLARITIES		BIT(1)
+ 
+ #define MTK_PHY_RG_BG_RASEL			0x115
+@@ -299,10 +266,6 @@ enum CAL_MODE {
+ 	SW_M
+ };
+ 
+-#define MTK_PHY_LED_STATE_FORCE_ON	0
+-#define MTK_PHY_LED_STATE_FORCE_BLINK	1
+-#define MTK_PHY_LED_STATE_NETDEV	2
+-
+ struct mtk_socphy_priv {
+ 	unsigned long		led_state;
+ };
+@@ -1131,84 +1094,39 @@ static int mt798x_phy_config_init(struct
+ 	return mt798x_phy_calibration(phydev);
+ }
+ 
+-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+-				    bool on)
+-{
+-	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+-	struct mtk_socphy_priv *priv = phydev->priv;
+-	bool changed;
+-
+-	if (on)
+-		changed = !test_and_set_bit(bit_on, &priv->led_state);
+-	else
+-		changed = !!test_and_clear_bit(bit_on, &priv->led_state);
+-
+-	changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
+-					(index ? 16 : 0), &priv->led_state);
+-	if (changed)
+-		return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-				      MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+-				      MTK_PHY_LED_ON_MASK,
+-				      on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+-	else
+-		return 0;
+-}
+-
+-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+-				       bool blinking)
+-{
+-	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
+-	struct mtk_socphy_priv *priv = phydev->priv;
+-	bool changed;
+-
+-	if (blinking)
+-		changed = !test_and_set_bit(bit_blink, &priv->led_state);
+-	else
+-		changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
+-
+-	changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
+-			      (index ? 16 : 0), &priv->led_state);
+-	if (changed)
+-		return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+-				     MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL,
+-				     blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+-	else
+-		return 0;
+-}
+-
+ static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
+ 				    unsigned long *delay_on,
+ 				    unsigned long *delay_off)
+ {
++	struct mtk_socphy_priv *priv = phydev->priv;
+ 	bool blinking = false;
+ 	int err = 0;
+ 
+-	if (index > 1)
+-		return -EINVAL;
+-
+-	if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+-		blinking = true;
+-		*delay_on = 50;
+-		*delay_off = 50;
+-	}
++	err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
++	if (err < 0)
++		return err;
+ 
+-	err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
++	err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state,
++				       blinking);
+ 	if (err)
+ 		return err;
+ 
+-	return mt798x_phy_hw_led_on_set(phydev, index, false);
++	return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
++				     MTK_GPHY_LED_ON_MASK, false);
+ }
+ 
+ static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
+ 					 u8 index, enum led_brightness value)
+ {
++	struct mtk_socphy_priv *priv = phydev->priv;
+ 	int err;
+ 
+-	err = mt798x_phy_hw_led_blink_set(phydev, index, false);
++	err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state, false);
+ 	if (err)
+ 		return err;
+ 
+-	return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
++	return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
++				     MTK_GPHY_LED_ON_MASK, (value != LED_OFF));
+ }
+ 
+ static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+@@ -1223,148 +1141,30 @@ static const unsigned long supported_tri
+ static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ 					  unsigned long rules)
+ {
+-	if (index > 1)
+-		return -EINVAL;
+-
+-	/* All combinations of the supported triggers are allowed */
+-	if (rules & ~supported_triggers)
+-		return -EOPNOTSUPP;
+-
+-	return 0;
+-};
++	return mtk_phy_led_hw_is_supported(phydev, index, rules,
++					   supported_triggers);
++}
+ 
+ static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+ 					 unsigned long *rules)
+ {
+-	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
+-	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+-	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+ 	struct mtk_socphy_priv *priv = phydev->priv;
+-	int on, blink;
+-
+-	if (index > 1)
+-		return -EINVAL;
+-
+-	on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+-			  index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
+-
+-	if (on < 0)
+-		return -EIO;
+-
+-	blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+-			     index ? MTK_PHY_LED1_BLINK_CTRL :
+-				     MTK_PHY_LED0_BLINK_CTRL);
+-	if (blink < 0)
+-		return -EIO;
+-
+-	if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX |
+-		   MTK_PHY_LED_ON_LINKDOWN)) ||
+-	    (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
+-		set_bit(bit_netdev, &priv->led_state);
+-	else
+-		clear_bit(bit_netdev, &priv->led_state);
+-
+-	if (on & MTK_PHY_LED_ON_FORCE_ON)
+-		set_bit(bit_on, &priv->led_state);
+-	else
+-		clear_bit(bit_on, &priv->led_state);
+-
+-	if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
+-		set_bit(bit_blink, &priv->led_state);
+-	else
+-		clear_bit(bit_blink, &priv->led_state);
+-
+-	if (!rules)
+-		return 0;
+-
+-	if (on & MTK_PHY_LED_ON_LINK)
+-		*rules |= BIT(TRIGGER_NETDEV_LINK);
+ 
+-	if (on & MTK_PHY_LED_ON_LINK10)
+-		*rules |= BIT(TRIGGER_NETDEV_LINK_10);
+-
+-	if (on & MTK_PHY_LED_ON_LINK100)
+-		*rules |= BIT(TRIGGER_NETDEV_LINK_100);
+-
+-	if (on & MTK_PHY_LED_ON_LINK1000)
+-		*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+-
+-	if (on & MTK_PHY_LED_ON_FDX)
+-		*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+-
+-	if (on & MTK_PHY_LED_ON_HDX)
+-		*rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
+-
+-	if (blink & MTK_PHY_LED_BLINK_RX)
+-		*rules |= BIT(TRIGGER_NETDEV_RX);
+-
+-	if (blink & MTK_PHY_LED_BLINK_TX)
+-		*rules |= BIT(TRIGGER_NETDEV_TX);
+-
+-	return 0;
++	return mtk_phy_led_hw_ctrl_get(phydev, index, rules, &priv->led_state,
++				       MTK_GPHY_LED_ON_SET,
++				       MTK_GPHY_LED_RX_BLINK_SET,
++				       MTK_GPHY_LED_TX_BLINK_SET);
+ };
+ 
+ static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
+ 					 unsigned long rules)
+ {
+-	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+ 	struct mtk_socphy_priv *priv = phydev->priv;
+-	u16 on = 0, blink = 0;
+-	int ret;
+ 
+-	if (index > 1)
+-		return -EINVAL;
+-
+-	if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+-		on |= MTK_PHY_LED_ON_FDX;
+-
+-	if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
+-		on |= MTK_PHY_LED_ON_HDX;
+-
+-	if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
+-		on |= MTK_PHY_LED_ON_LINK10;
+-
+-	if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+-		on |= MTK_PHY_LED_ON_LINK100;
+-
+-	if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+-		on |= MTK_PHY_LED_ON_LINK1000;
+-
+-	if (rules & BIT(TRIGGER_NETDEV_RX)) {
+-		blink |= (on & MTK_PHY_LED_ON_LINK) ?
+-			  (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) :
+-			  MTK_PHY_LED_BLINK_RX;
+-	}
+-
+-	if (rules & BIT(TRIGGER_NETDEV_TX)) {
+-		blink |= (on & MTK_PHY_LED_ON_LINK) ?
+-			  (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) :
+-			  MTK_PHY_LED_BLINK_TX;
+-	}
+-
+-	if (blink || on)
+-		set_bit(bit_netdev, &priv->led_state);
+-	else
+-		clear_bit(bit_netdev, &priv->led_state);
+-
+-	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+-				MTK_PHY_LED1_ON_CTRL :
+-				MTK_PHY_LED0_ON_CTRL,
+-			     MTK_PHY_LED_ON_FDX     |
+-			     MTK_PHY_LED_ON_HDX     |
+-			     MTK_PHY_LED_ON_LINK,
+-			     on);
+-
+-	if (ret)
+-		return ret;
+-
+-	return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+-				MTK_PHY_LED1_BLINK_CTRL :
+-				MTK_PHY_LED0_BLINK_CTRL, blink);
++	return mtk_phy_led_hw_ctrl_set(phydev, index, rules, &priv->led_state,
++				       MTK_GPHY_LED_ON_SET,
++				       MTK_GPHY_LED_RX_BLINK_SET,
++				       MTK_GPHY_LED_TX_BLINK_SET);
+ };
+ 
+ static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
+@@ -1438,14 +1238,6 @@ static int mt7988_phy_probe_shared(struc
+ 	return 0;
+ }
+ 
+-static void mt798x_phy_leds_state_init(struct phy_device *phydev)
+-{
+-	int i;
+-
+-	for (i = 0; i < 2; ++i)
+-		mt798x_phy_led_hw_control_get(phydev, i, NULL);
+-}
+-
+ static int mt7988_phy_probe(struct phy_device *phydev)
+ {
+ 	struct mtk_socphy_shared *shared;
+@@ -1471,7 +1263,7 @@ static int mt7988_phy_probe(struct phy_d
+ 
+ 	phydev->priv = priv;
+ 
+-	mt798x_phy_leds_state_init(phydev);
++	mtk_phy_leds_state_init(phydev);
+ 
+ 	err = mt7988_phy_fix_leds_polarities(phydev);
+ 	if (err)
+@@ -1498,7 +1290,7 @@ static int mt7981_phy_probe(struct phy_d
+ 
+ 	phydev->priv = priv;
+ 
+-	mt798x_phy_leds_state_init(phydev);
++	mtk_phy_leds_state_init(phydev);
+ 
+ 	return mt798x_phy_calibration(phydev);
+ }
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -0,0 +1,251 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <linux/phy.h>
++#include <linux/module.h>
++
++#include <linux/netdevice.h>
++
++#include "mtk.h"
++
++int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++				unsigned long rules,
++				unsigned long supported_triggers)
++{
++	if (index > 1)
++		return -EINVAL;
++
++	/* All combinations of the supported triggers are allowed */
++	if (rules & ~supported_triggers)
++		return -EOPNOTSUPP;
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
++
++int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
++			    unsigned long *rules, unsigned long *led_state,
++			    u16 on_set, u16 rx_blink_set, u16 tx_blink_set)
++{
++	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++				 (index ? 16 : 0);
++	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++	int on, blink;
++
++	if (index > 1)
++		return -EINVAL;
++
++	on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++			  index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
++
++	if (on < 0)
++		return -EIO;
++
++	blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++			     index ? MTK_PHY_LED1_BLINK_CTRL :
++				     MTK_PHY_LED0_BLINK_CTRL);
++	if (blink < 0)
++		return -EIO;
++
++	if ((on & (on_set | MTK_PHY_LED_ON_FDX |
++		   MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
++	    (blink & (rx_blink_set | tx_blink_set)))
++		set_bit(bit_netdev, led_state);
++	else
++		clear_bit(bit_netdev, led_state);
++
++	if (on & MTK_PHY_LED_ON_FORCE_ON)
++		set_bit(bit_on, led_state);
++	else
++		clear_bit(bit_on, led_state);
++
++	if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
++		set_bit(bit_blink, led_state);
++	else
++		clear_bit(bit_blink, led_state);
++
++	if (!rules)
++		return 0;
++
++	if (on & on_set)
++		*rules |= BIT(TRIGGER_NETDEV_LINK);
++
++	if (on & MTK_PHY_LED_ON_LINK10)
++		*rules |= BIT(TRIGGER_NETDEV_LINK_10);
++
++	if (on & MTK_PHY_LED_ON_LINK100)
++		*rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++	if (on & MTK_PHY_LED_ON_LINK1000)
++		*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++	if (on & MTK_PHY_LED_ON_LINK2500)
++		*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
++
++	if (on & MTK_PHY_LED_ON_FDX)
++		*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
++
++	if (on & MTK_PHY_LED_ON_HDX)
++		*rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
++
++	if (blink & rx_blink_set)
++		*rules |= BIT(TRIGGER_NETDEV_RX);
++
++	if (blink & tx_blink_set)
++		*rules |= BIT(TRIGGER_NETDEV_TX);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
++
++int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
++			    unsigned long rules, unsigned long *led_state,
++			    u16 on_set, u16 rx_blink_set, u16 tx_blink_set)
++{
++	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++	u16 on = 0, blink = 0;
++	int ret;
++
++	if (index > 1)
++		return -EINVAL;
++
++	if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
++		on |= MTK_PHY_LED_ON_FDX;
++
++	if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
++		on |= MTK_PHY_LED_ON_HDX;
++
++	if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
++		on |= MTK_PHY_LED_ON_LINK10;
++
++	if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
++		on |= MTK_PHY_LED_ON_LINK100;
++
++	if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
++		on |= MTK_PHY_LED_ON_LINK1000;
++
++	if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
++		on |= MTK_PHY_LED_ON_LINK2500;
++
++	if (rules & BIT(TRIGGER_NETDEV_RX)) {
++		blink |= (on & on_set) ?
++			  (((on & MTK_PHY_LED_ON_LINK10) ?
++			    MTK_PHY_LED_BLINK_10RX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK100) ?
++			    MTK_PHY_LED_BLINK_100RX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK1000) ?
++			    MTK_PHY_LED_BLINK_1000RX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK2500) ?
++			    MTK_PHY_LED_BLINK_2500RX : 0)) :
++			  rx_blink_set;
++	}
++
++	if (rules & BIT(TRIGGER_NETDEV_TX)) {
++		blink |= (on & on_set) ?
++			  (((on & MTK_PHY_LED_ON_LINK10) ?
++			    MTK_PHY_LED_BLINK_10TX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK100) ?
++			    MTK_PHY_LED_BLINK_100TX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK1000) ?
++			    MTK_PHY_LED_BLINK_1000TX : 0) |
++			   ((on & MTK_PHY_LED_ON_LINK2500) ?
++			    MTK_PHY_LED_BLINK_2500TX : 0)) :
++			  tx_blink_set;
++	}
++
++	if (blink || on)
++		set_bit(bit_netdev, led_state);
++	else
++		clear_bit(bit_netdev, led_state);
++
++	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++			     MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++			     MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
++			     on);
++
++	if (ret)
++		return ret;
++
++	return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++			     MTK_PHY_LED1_BLINK_CTRL :
++			     MTK_PHY_LED0_BLINK_CTRL, blink);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
++
++int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
++			    unsigned long *delay_off, bool *blinking)
++{
++	if (index > 1)
++		return -EINVAL;
++
++	if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
++		*blinking = true;
++		*delay_on = 50;
++		*delay_off = 50;
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
++
++int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
++			  unsigned long *led_state, u16 led_on_mask, bool on)
++{
++	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++	bool changed;
++
++	if (on)
++		changed = !test_and_set_bit(bit_on, led_state);
++	else
++		changed = !!test_and_clear_bit(bit_on, led_state);
++
++	changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
++					(index ? 16 : 0), led_state);
++	if (changed)
++		return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++				      MTK_PHY_LED1_ON_CTRL :
++				      MTK_PHY_LED0_ON_CTRL,
++				      led_on_mask,
++				      on ? MTK_PHY_LED_ON_FORCE_ON : 0);
++	else
++		return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
++
++int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
++			     unsigned long *led_state, bool blinking)
++{
++	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
++				 (index ? 16 : 0);
++	bool changed;
++
++	if (blinking)
++		changed = !test_and_set_bit(bit_blink, led_state);
++	else
++		changed = !!test_and_clear_bit(bit_blink, led_state);
++
++	changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
++			      (index ? 16 : 0), led_state);
++	if (changed)
++		return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++				     MTK_PHY_LED1_BLINK_CTRL :
++				     MTK_PHY_LED0_BLINK_CTRL,
++				     blinking ?
++				     MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
++	else
++		return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
++
++void mtk_phy_leds_state_init(struct phy_device *phydev)
++{
++	int i;
++
++	for (i = 0; i < 2; ++i)
++		phydev->drv->led_hw_control_get(phydev, i, NULL);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
++
++MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
++MODULE_AUTHOR("Sky Huang <SkyLake.Huang at mediatek.com>");
++MODULE_AUTHOR("Daniel Golle <daniel at makrotopia.org>");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -0,0 +1,82 @@
++/* SPDX-License-Identifier: GPL-2.0
++ *
++ * Common definition for Mediatek Ethernet PHYs
++ * Author: SkyLake Huang <SkyLake.Huang at mediatek.com>
++ * Copyright (c) 2024 MediaTek Inc.
++ */
++
++#ifndef _MTK_EPHY_H_
++#define _MTK_EPHY_H_
++
++#define MTK_EXT_PAGE_ACCESS			0x1f
++
++/* Registers on MDIO_MMD_VEND2 */
++#define MTK_PHY_LED0_ON_CTRL			0x24
++#define MTK_PHY_LED1_ON_CTRL			0x26
++#define   MTK_GPHY_LED_ON_MASK			GENMASK(6, 0)
++#define   MTK_2P5GPHY_LED_ON_MASK		GENMASK(7, 0)
++#define   MTK_PHY_LED_ON_LINK1000		BIT(0)
++#define   MTK_PHY_LED_ON_LINK100		BIT(1)
++#define   MTK_PHY_LED_ON_LINK10			BIT(2)
++#define   MTK_PHY_LED_ON_LINKDOWN		BIT(3)
++#define   MTK_PHY_LED_ON_FDX			BIT(4) /* Full duplex */
++#define   MTK_PHY_LED_ON_HDX			BIT(5) /* Half duplex */
++#define   MTK_PHY_LED_ON_FORCE_ON		BIT(6)
++#define   MTK_PHY_LED_ON_LINK2500		BIT(7)
++#define   MTK_PHY_LED_ON_POLARITY		BIT(14)
++#define   MTK_PHY_LED_ON_ENABLE			BIT(15)
++
++#define MTK_PHY_LED0_BLINK_CTRL			0x25
++#define MTK_PHY_LED1_BLINK_CTRL			0x27
++#define   MTK_PHY_LED_BLINK_1000TX		BIT(0)
++#define   MTK_PHY_LED_BLINK_1000RX		BIT(1)
++#define   MTK_PHY_LED_BLINK_100TX		BIT(2)
++#define   MTK_PHY_LED_BLINK_100RX		BIT(3)
++#define   MTK_PHY_LED_BLINK_10TX		BIT(4)
++#define   MTK_PHY_LED_BLINK_10RX		BIT(5)
++#define   MTK_PHY_LED_BLINK_COLLISION		BIT(6)
++#define   MTK_PHY_LED_BLINK_RX_CRC_ERR		BIT(7)
++#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR		BIT(8)
++#define   MTK_PHY_LED_BLINK_FORCE_BLINK		BIT(9)
++#define   MTK_PHY_LED_BLINK_2500TX		BIT(10)
++#define   MTK_PHY_LED_BLINK_2500RX		BIT(11)
++
++#define MTK_GPHY_LED_ON_SET			(MTK_PHY_LED_ON_LINK1000 | \
++						 MTK_PHY_LED_ON_LINK100 | \
++						 MTK_PHY_LED_ON_LINK10)
++#define MTK_GPHY_LED_RX_BLINK_SET		(MTK_PHY_LED_BLINK_1000RX | \
++						 MTK_PHY_LED_BLINK_100RX | \
++						 MTK_PHY_LED_BLINK_10RX)
++#define MTK_GPHY_LED_TX_BLINK_SET		(MTK_PHY_LED_BLINK_1000RX | \
++						 MTK_PHY_LED_BLINK_100RX | \
++						 MTK_PHY_LED_BLINK_10RX)
++
++#define MTK_2P5GPHY_LED_ON_SET			(MTK_PHY_LED_ON_LINK2500 | \
++						 MTK_GPHY_LED_ON_SET)
++#define MTK_2P5GPHY_LED_RX_BLINK_SET		(MTK_PHY_LED_BLINK_2500RX | \
++						 MTK_GPHY_LED_RX_BLINK_SET)
++#define MTK_2P5GPHY_LED_TX_BLINK_SET		(MTK_PHY_LED_BLINK_2500RX | \
++						 MTK_GPHY_LED_TX_BLINK_SET)
++
++#define MTK_PHY_LED_STATE_FORCE_ON	0
++#define MTK_PHY_LED_STATE_FORCE_BLINK	1
++#define MTK_PHY_LED_STATE_NETDEV	2
++
++int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++				unsigned long rules,
++				unsigned long supported_triggers);
++int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
++			    unsigned long rules, unsigned long *led_state,
++			    u16 on_set, u16 rx_blink_set, u16 tx_blink_set);
++int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
++			    unsigned long *rules, unsigned long *led_state,
++			    u16 on_set, u16 rx_blink_set, u16 tx_blink_set);
++int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
++			    unsigned long *delay_off, bool *blinking);
++int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
++			  unsigned long *led_state, u16 led_on_mask, bool on);
++int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
++			     unsigned long *led_state, bool blinking);
++void mtk_phy_leds_state_init(struct phy_device *phydev);
++
++#endif /* _MTK_EPHY_H_ */
diff --git a/target/linux/mediatek/patches-6.6/733-04-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch b/target/linux/mediatek/patches-6.6/733-04-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch
new file mode 100644
index 0000000000..717dc890e3
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-04-net-phy-mediatek-Improve-readability-of-mtk-phy-lib..patch
@@ -0,0 +1,70 @@
+From 2783929879854d5750ba82e2e203663313362abb Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:08 +0800
+Subject: [PATCH 04/13] net: phy: mediatek: Improve readability of
+ mtk-phy-lib.c's mtk_phy_led_hw_ctrl_set()
+
+This patch removes parens around TRIGGER_NETDEV_RX/TRIGGER_NETDEV_TX in
+mtk_phy_led_hw_ctrl_set(), which improves readability.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 44 ++++++++++++++------------
+ 1 file changed, 24 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -127,29 +127,33 @@ int mtk_phy_led_hw_ctrl_set(struct phy_d
+ 		on |= MTK_PHY_LED_ON_LINK2500;
+ 
+ 	if (rules & BIT(TRIGGER_NETDEV_RX)) {
+-		blink |= (on & on_set) ?
+-			  (((on & MTK_PHY_LED_ON_LINK10) ?
+-			    MTK_PHY_LED_BLINK_10RX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK100) ?
+-			    MTK_PHY_LED_BLINK_100RX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK1000) ?
+-			    MTK_PHY_LED_BLINK_1000RX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK2500) ?
+-			    MTK_PHY_LED_BLINK_2500RX : 0)) :
+-			  rx_blink_set;
++		if (on & on_set) {
++			if (on & MTK_PHY_LED_ON_LINK10)
++				blink |= MTK_PHY_LED_BLINK_10RX;
++			if (on & MTK_PHY_LED_ON_LINK100)
++				blink |= MTK_PHY_LED_BLINK_100RX;
++			if (on & MTK_PHY_LED_ON_LINK1000)
++				blink |= MTK_PHY_LED_BLINK_1000RX;
++			if (on & MTK_PHY_LED_ON_LINK2500)
++				blink |= MTK_PHY_LED_BLINK_2500RX;
++		} else {
++			blink |= rx_blink_set;
++		}
+ 	}
+ 
+ 	if (rules & BIT(TRIGGER_NETDEV_TX)) {
+-		blink |= (on & on_set) ?
+-			  (((on & MTK_PHY_LED_ON_LINK10) ?
+-			    MTK_PHY_LED_BLINK_10TX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK100) ?
+-			    MTK_PHY_LED_BLINK_100TX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK1000) ?
+-			    MTK_PHY_LED_BLINK_1000TX : 0) |
+-			   ((on & MTK_PHY_LED_ON_LINK2500) ?
+-			    MTK_PHY_LED_BLINK_2500TX : 0)) :
+-			  tx_blink_set;
++		if (on & on_set) {
++			if (on & MTK_PHY_LED_ON_LINK10)
++				blink |= MTK_PHY_LED_BLINK_10TX;
++			if (on & MTK_PHY_LED_ON_LINK100)
++				blink |= MTK_PHY_LED_BLINK_100TX;
++			if (on & MTK_PHY_LED_ON_LINK1000)
++				blink |= MTK_PHY_LED_BLINK_1000TX;
++			if (on & MTK_PHY_LED_ON_LINK2500)
++				blink |= MTK_PHY_LED_BLINK_2500TX;
++		} else {
++			blink |= tx_blink_set;
++		}
+ 	}
+ 
+ 	if (blink || on)
diff --git a/target/linux/mediatek/patches-6.6/733-05-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch b/target/linux/mediatek/patches-6.6/733-05-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch
new file mode 100644
index 0000000000..4a112a202c
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-05-net-phy-mediatek-Integrate-read-write-page-helper-fu.patch
@@ -0,0 +1,141 @@
+From 58c1270423ab48464cdc31ef71ffe7f5b2441961 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:09 +0800
+Subject: [PATCH 05/13] net: phy: mediatek: Integrate read/write page helper
+ functions
+
+This patch integrates read/write page helper functions as MTK phy lib.
+They are basically the same in mtk-ge.c & mtk-ge-soc.c.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c  | 18 ++++--------------
+ drivers/net/phy/mediatek/mtk-ge.c      | 20 ++++++--------------
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 12 ++++++++++++
+ drivers/net/phy/mediatek/mtk.h         |  3 +++
+ 4 files changed, 25 insertions(+), 28 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -275,16 +275,6 @@ struct mtk_socphy_shared {
+ 	struct mtk_socphy_priv	priv[4];
+ };
+ 
+-static int mtk_socphy_read_page(struct phy_device *phydev)
+-{
+-	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_socphy_write_page(struct phy_device *phydev, int page)
+-{
+-	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+ /* One calibration cycle consists of:
+  * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
+  *   until AD_CAL_COMP is ready to output calibration result.
+@@ -1305,8 +1295,8 @@ static struct phy_driver mtk_socphy_driv
+ 		.probe		= mt7981_phy_probe,
+ 		.suspend	= genphy_suspend,
+ 		.resume		= genphy_resume,
+-		.read_page	= mtk_socphy_read_page,
+-		.write_page	= mtk_socphy_write_page,
++		.read_page	= mtk_phy_read_page,
++		.write_page	= mtk_phy_write_page,
+ 		.led_blink_set	= mt798x_phy_led_blink_set,
+ 		.led_brightness_set = mt798x_phy_led_brightness_set,
+ 		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+@@ -1322,8 +1312,8 @@ static struct phy_driver mtk_socphy_driv
+ 		.probe		= mt7988_phy_probe,
+ 		.suspend	= genphy_suspend,
+ 		.resume		= genphy_resume,
+-		.read_page	= mtk_socphy_read_page,
+-		.write_page	= mtk_socphy_write_page,
++		.read_page	= mtk_phy_read_page,
++		.write_page	= mtk_phy_write_page,
+ 		.led_blink_set	= mt798x_phy_led_blink_set,
+ 		.led_brightness_set = mt798x_phy_led_brightness_set,
+ 		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -4,6 +4,8 @@
+ #include <linux/module.h>
+ #include <linux/phy.h>
+ 
++#include "mtk.h"
++
+ #define MTK_EXT_PAGE_ACCESS		0x1f
+ #define MTK_PHY_PAGE_STANDARD		0x0000
+ #define MTK_PHY_PAGE_EXTENDED		0x0001
+@@ -12,16 +14,6 @@
+ #define MTK_PHY_PAGE_EXTENDED_2A30	0x2a30
+ #define MTK_PHY_PAGE_EXTENDED_52B5	0x52b5
+ 
+-static int mtk_gephy_read_page(struct phy_device *phydev)
+-{
+-	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+-}
+-
+-static int mtk_gephy_write_page(struct phy_device *phydev, int page)
+-{
+-	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+-}
+-
+ static void mtk_gephy_config_init(struct phy_device *phydev)
+ {
+ 	/* Disable EEE */
+@@ -114,8 +106,8 @@ static struct phy_driver mtk_gephy_drive
+ 		.handle_interrupt = genphy_handle_interrupt_no_ack,
+ 		.suspend	= genphy_suspend,
+ 		.resume		= genphy_resume,
+-		.read_page	= mtk_gephy_read_page,
+-		.write_page	= mtk_gephy_write_page,
++		.read_page	= mtk_phy_read_page,
++		.write_page	= mtk_phy_write_page,
+ 	},
+ 	{
+ 		PHY_ID_MATCH_EXACT(0x03a29441),
+@@ -128,8 +120,8 @@ static struct phy_driver mtk_gephy_drive
+ 		.handle_interrupt = genphy_handle_interrupt_no_ack,
+ 		.suspend	= genphy_suspend,
+ 		.resume		= genphy_resume,
+-		.read_page	= mtk_gephy_read_page,
+-		.write_page	= mtk_gephy_write_page,
++		.read_page	= mtk_phy_read_page,
++		.write_page	= mtk_phy_write_page,
+ 	},
+ };
+ 
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -6,6 +6,18 @@
+ 
+ #include "mtk.h"
+ 
++int mtk_phy_read_page(struct phy_device *phydev)
++{
++	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_read_page);
++
++int mtk_phy_write_page(struct phy_device *phydev, int page)
++{
++	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++EXPORT_SYMBOL_GPL(mtk_phy_write_page);
++
+ int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ 				unsigned long rules,
+ 				unsigned long supported_triggers)
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -62,6 +62,9 @@
+ #define MTK_PHY_LED_STATE_FORCE_BLINK	1
+ #define MTK_PHY_LED_STATE_NETDEV	2
+ 
++int mtk_phy_read_page(struct phy_device *phydev);
++int mtk_phy_write_page(struct phy_device *phydev, int page);
++
+ int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ 				unsigned long rules,
+ 				unsigned long supported_triggers);
diff --git a/target/linux/mediatek/patches-6.6/733-06-net-phy-mediatek-Hook-LED-helper-functions-in-mtk-ge.patch b/target/linux/mediatek/patches-6.6/733-06-net-phy-mediatek-Hook-LED-helper-functions-in-mtk-ge.patch
new file mode 100644
index 0000000000..485e262134
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-06-net-phy-mediatek-Hook-LED-helper-functions-in-mtk-ge.patch
@@ -0,0 +1,146 @@
+From 9403f1d54598ae56386a8bf47a5b6b34c884e4f5 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:10 +0800
+Subject: [PATCH 06/13] net: phy: mediatek: Hook LED helper functions in
+ mtk-ge.c
+
+We have mtk-phy-lib.c now so that we can use LED helper functions in
+mtk-ge.c(mt7531 part). It also means that mt7531/mt7981/mt7988's
+Giga ethernet phys share almost the same HW LED controller design.
+Also, add probe function for mt7531 so that it can initialize LED state.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-ge.c | 100 ++++++++++++++++++++++++++++++
+ 1 file changed, 100 insertions(+)
+
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -14,6 +14,10 @@
+ #define MTK_PHY_PAGE_EXTENDED_2A30	0x2a30
+ #define MTK_PHY_PAGE_EXTENDED_52B5	0x52b5
+ 
++struct mtk_gephy_priv {
++	unsigned long		led_state;
++};
++
+ static void mtk_gephy_config_init(struct phy_device *phydev)
+ {
+ 	/* Disable EEE */
+@@ -94,6 +98,96 @@ static int mt7531_phy_config_init(struct
+ 	return 0;
+ }
+ 
++static int mt7531_phy_probe(struct phy_device *phydev)
++{
++	struct mtk_gephy_priv *priv;
++
++	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_gephy_priv),
++			    GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	phydev->priv = priv;
++
++	mtk_phy_leds_state_init(phydev);
++
++	return 0;
++}
++
++static int mt753x_phy_led_blink_set(struct phy_device *phydev, u8 index,
++				    unsigned long *delay_on,
++				    unsigned long *delay_off)
++{
++	struct mtk_gephy_priv *priv = phydev->priv;
++	bool blinking = false;
++	int err = 0;
++
++	err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
++	if (err < 0)
++		return err;
++
++	err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state,
++				       blinking);
++	if (err)
++		return err;
++
++	return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
++				     MTK_GPHY_LED_ON_MASK, false);
++}
++
++static int mt753x_phy_led_brightness_set(struct phy_device *phydev,
++					 u8 index, enum led_brightness value)
++{
++	struct mtk_gephy_priv *priv = phydev->priv;
++	int err;
++
++	err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state, false);
++	if (err)
++		return err;
++
++	return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
++				     MTK_GPHY_LED_ON_MASK, (value != LED_OFF));
++}
++
++static const unsigned long supported_triggers =
++	(BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++	 BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
++	 BIT(TRIGGER_NETDEV_LINK)        |
++	 BIT(TRIGGER_NETDEV_LINK_10)     |
++	 BIT(TRIGGER_NETDEV_LINK_100)    |
++	 BIT(TRIGGER_NETDEV_LINK_1000)   |
++	 BIT(TRIGGER_NETDEV_RX)          |
++	 BIT(TRIGGER_NETDEV_TX));
++
++static int mt753x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++					  unsigned long rules)
++{
++	return mtk_phy_led_hw_is_supported(phydev, index, rules,
++					   supported_triggers);
++}
++
++static int mt753x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
++					 unsigned long *rules)
++{
++	struct mtk_gephy_priv *priv = phydev->priv;
++
++	return mtk_phy_led_hw_ctrl_get(phydev, index, rules, &priv->led_state,
++				       MTK_GPHY_LED_ON_SET,
++				       MTK_GPHY_LED_RX_BLINK_SET,
++				       MTK_GPHY_LED_TX_BLINK_SET);
++};
++
++static int mt753x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
++					 unsigned long rules)
++{
++	struct mtk_gephy_priv *priv = phydev->priv;
++
++	return mtk_phy_led_hw_ctrl_set(phydev, index, rules, &priv->led_state,
++				       MTK_GPHY_LED_ON_SET,
++				       MTK_GPHY_LED_RX_BLINK_SET,
++				       MTK_GPHY_LED_TX_BLINK_SET);
++};
++
+ static struct phy_driver mtk_gephy_driver[] = {
+ 	{
+ 		PHY_ID_MATCH_EXACT(0x03a29412),
+@@ -112,6 +206,7 @@ static struct phy_driver mtk_gephy_drive
+ 	{
+ 		PHY_ID_MATCH_EXACT(0x03a29441),
+ 		.name		= "MediaTek MT7531 PHY",
++		.probe		= mt7531_phy_probe,
+ 		.config_init	= mt7531_phy_config_init,
+ 		/* Interrupts are handled by the switch, not the PHY
+ 		 * itself.
+@@ -122,6 +217,11 @@ static struct phy_driver mtk_gephy_drive
+ 		.resume		= genphy_resume,
+ 		.read_page	= mtk_phy_read_page,
+ 		.write_page	= mtk_phy_write_page,
++		.led_blink_set	= mt753x_phy_led_blink_set,
++		.led_brightness_set = mt753x_phy_led_brightness_set,
++		.led_hw_is_supported = mt753x_phy_led_hw_is_supported,
++		.led_hw_control_set = mt753x_phy_led_hw_control_set,
++		.led_hw_control_get = mt753x_phy_led_hw_control_get,
+ 	},
+ };
+ 
diff --git a/target/linux/mediatek/patches-6.6/733-07-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch b/target/linux/mediatek/patches-6.6/733-07-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch
new file mode 100644
index 0000000000..bfdf864f8d
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-07-net-phy-mediatek-add-MT7530-MT7531-s-PHY-ID-macros.patch
@@ -0,0 +1,54 @@
+From 51ee83602dbb84716180d9b6e43f6bebb0c2d7bd Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:11 +0800
+Subject: [PATCH 07/13] net: phy: mediatek: add MT7530 & MT7531's PHY ID macros
+
+This patch adds MT7530 & MT7531's PHY ID macros in mtk-ge.c so that
+it follows the same rule of mtk-ge-soc.c.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-ge.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -6,6 +6,9 @@
+ 
+ #include "mtk.h"
+ 
++#define MTK_GPHY_ID_MT7530		0x03a29412
++#define MTK_GPHY_ID_MT7531		0x03a29441
++
+ #define MTK_EXT_PAGE_ACCESS		0x1f
+ #define MTK_PHY_PAGE_STANDARD		0x0000
+ #define MTK_PHY_PAGE_EXTENDED		0x0001
+@@ -190,7 +193,7 @@ static int mt753x_phy_led_hw_control_set
+ 
+ static struct phy_driver mtk_gephy_driver[] = {
+ 	{
+-		PHY_ID_MATCH_EXACT(0x03a29412),
++		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
+ 		.name		= "MediaTek MT7530 PHY",
+ 		.config_init	= mt7530_phy_config_init,
+ 		/* Interrupts are handled by the switch, not the PHY
+@@ -204,7 +207,7 @@ static struct phy_driver mtk_gephy_drive
+ 		.write_page	= mtk_phy_write_page,
+ 	},
+ 	{
+-		PHY_ID_MATCH_EXACT(0x03a29441),
++		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531),
+ 		.name		= "MediaTek MT7531 PHY",
+ 		.probe		= mt7531_phy_probe,
+ 		.config_init	= mt7531_phy_config_init,
+@@ -228,8 +231,8 @@ static struct phy_driver mtk_gephy_drive
+ module_phy_driver(mtk_gephy_driver);
+ 
+ static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
+-	{ PHY_ID_MATCH_EXACT(0x03a29441) },
+-	{ PHY_ID_MATCH_EXACT(0x03a29412) },
++	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) },
++	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) },
+ 	{ }
+ };
+ 
diff --git a/target/linux/mediatek/patches-6.6/733-08-net-phy-mediatek-Change-mtk-ge-soc.c-line-wrapping.patch b/target/linux/mediatek/patches-6.6/733-08-net-phy-mediatek-Change-mtk-ge-soc.c-line-wrapping.patch
new file mode 100644
index 0000000000..ca155e5012
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-08-net-phy-mediatek-Change-mtk-ge-soc.c-line-wrapping.patch
@@ -0,0 +1,182 @@
+From e73df692396b0d6bdcb2317299fa1e8e547f3446 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:12 +0800
+Subject: [PATCH 08/13] net: phy: mediatek: Change mtk-ge-soc.c line wrapping
+
+This patch shrinks mtk-ge-soc.c line wrapping to 80 characters.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 67 +++++++++++++++++----------
+ 1 file changed, 42 insertions(+), 25 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -295,7 +295,8 @@ static int cal_cycle(struct phy_device *
+ 	ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
+ 					MTK_PHY_RG_AD_CAL_CLK, reg_val,
+ 					reg_val & MTK_PHY_DA_CAL_CLK, 500,
+-					ANALOG_INTERNAL_OPERATION_MAX_US, false);
++					ANALOG_INTERNAL_OPERATION_MAX_US,
++					false);
+ 	if (ret) {
+ 		phydev_err(phydev, "Calibration cycle timeout\n");
+ 		return ret;
+@@ -304,7 +305,7 @@ static int cal_cycle(struct phy_device *
+ 	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+ 			   MTK_PHY_DA_CALIN_FLAG);
+ 	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >>
+-			   MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
++	      MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
+ 	phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
+ 
+ 	return ret;
+@@ -394,38 +395,46 @@ static int tx_amp_fill_result(struct phy
+ 	}
+ 
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+-		       MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10);
++		       MTK_PHY_DA_TX_I2MPB_A_GBE_MASK,
++		       (buf[0] + bias[0]) << 10);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+ 		       MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+-		       MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10);
++		       MTK_PHY_DA_TX_I2MPB_A_HBT_MASK,
++		       (buf[0] + bias[2]) << 10);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+ 		       MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]);
+ 
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+-		       MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8);
++		       MTK_PHY_DA_TX_I2MPB_B_GBE_MASK,
++		       (buf[1] + bias[4]) << 8);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+ 		       MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+-		       MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8);
++		       MTK_PHY_DA_TX_I2MPB_B_HBT_MASK,
++		       (buf[1] + bias[6]) << 8);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+ 		       MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]);
+ 
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+-		       MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8);
++		       MTK_PHY_DA_TX_I2MPB_C_GBE_MASK,
++		       (buf[2] + bias[8]) << 8);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+ 		       MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+-		       MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8);
++		       MTK_PHY_DA_TX_I2MPB_C_HBT_MASK,
++		       (buf[2] + bias[10]) << 8);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+ 		       MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]);
+ 
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+-		       MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8);
++		       MTK_PHY_DA_TX_I2MPB_D_GBE_MASK,
++		       (buf[3] + bias[12]) << 8);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+ 		       MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+-		       MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8);
++		       MTK_PHY_DA_TX_I2MPB_D_HBT_MASK,
++		       (buf[3] + bias[14]) << 8);
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+ 		       MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]);
+ 
+@@ -616,7 +625,8 @@ static int tx_vcm_cal_sw(struct phy_devi
+ 		goto restore;
+ 
+ 	/* We calibrate TX-VCM in different logic. Check upper index and then
+-	 * lower index. If this calibration is valid, apply lower index's result.
++	 * lower index. If this calibration is valid, apply lower index's
++	 * result.
+ 	 */
+ 	ret = upper_ret - lower_ret;
+ 	if (ret == 1) {
+@@ -645,7 +655,8 @@ static int tx_vcm_cal_sw(struct phy_devi
+ 	} else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
+ 		   lower_ret == 0) {
+ 		ret = 0;
+-		phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n",
++		phydev_warn(phydev,
++			    "TX-VCM SW cal result at high margin 0x%x\n",
+ 			    upper_idx);
+ 	} else {
+ 		ret = -EINVAL;
+@@ -749,7 +760,8 @@ static void mt7981_phy_finetune(struct p
+ 
+ 	/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+-		       MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
++		       MTK_PHY_TR_OPEN_LOOP_EN_MASK |
++		       MTK_PHY_LPF_X_AVERAGE_MASK,
+ 		       BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
+ 
+ 	/* rg_tr_lpf_cnt_val = 512 */
+@@ -818,7 +830,8 @@ static void mt7988_phy_finetune(struct p
+ 
+ 	/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+-		       MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
++		       MTK_PHY_TR_OPEN_LOOP_EN_MASK |
++		       MTK_PHY_LPF_X_AVERAGE_MASK,
+ 		       BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
+ 
+ 	/* rg_tr_lpf_cnt_val = 1023 */
+@@ -930,7 +943,8 @@ static void mt798x_phy_eee(struct phy_de
+ 	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+ 
+ 	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
+-	__phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
++	__phy_modify(phydev, MTK_PHY_LPI_REG_14,
++		     MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
+ 		     FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
+ 
+ 	__phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
+@@ -940,7 +954,8 @@ static void mt798x_phy_eee(struct phy_de
+ 	phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+ 		       MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
+ 		       MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
+-		       FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff));
++		       FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++				  0xff));
+ }
+ 
+ static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
+@@ -1119,14 +1134,15 @@ static int mt798x_phy_led_brightness_set
+ 				     MTK_GPHY_LED_ON_MASK, (value != LED_OFF));
+ }
+ 
+-static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+-						 BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+-						 BIT(TRIGGER_NETDEV_LINK)        |
+-						 BIT(TRIGGER_NETDEV_LINK_10)     |
+-						 BIT(TRIGGER_NETDEV_LINK_100)    |
+-						 BIT(TRIGGER_NETDEV_LINK_1000)   |
+-						 BIT(TRIGGER_NETDEV_RX)          |
+-						 BIT(TRIGGER_NETDEV_TX));
++static const unsigned long supported_triggers =
++	(BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++	 BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
++	 BIT(TRIGGER_NETDEV_LINK)        |
++	 BIT(TRIGGER_NETDEV_LINK_10)     |
++	 BIT(TRIGGER_NETDEV_LINK_100)    |
++	 BIT(TRIGGER_NETDEV_LINK_1000)   |
++	 BIT(TRIGGER_NETDEV_RX)          |
++	 BIT(TRIGGER_NETDEV_TX));
+ 
+ static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ 					  unsigned long rules)
+@@ -1189,7 +1205,8 @@ static int mt7988_phy_fix_leds_polaritie
+ 	/* Only now setup pinctrl to avoid bogus blinking */
+ 	pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
+ 	if (IS_ERR(pinctrl))
+-		dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n");
++		dev_err(&phydev->mdio.bus->dev,
++			"Failed to setup PHY LED pinctrl\n");
+ 
+ 	return 0;
+ }
diff --git a/target/linux/mediatek/patches-6.6/733-09-net-phy-mediatek-Add-token-ring-access-helper-functi.patch b/target/linux/mediatek/patches-6.6/733-09-net-phy-mediatek-Add-token-ring-access-helper-functi.patch
new file mode 100644
index 0000000000..49e4c2057f
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-09-net-phy-mediatek-Add-token-ring-access-helper-functi.patch
@@ -0,0 +1,614 @@
+From 60228de48d8bfde62b4db5945314e6a62079f091 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:13 +0800
+Subject: [PATCH 09/13] net: phy: mediatek: Add token ring access helper
+ functions in mtk-phy-lib
+
+This patch adds TR(token ring) manipulations and adds correct
+macro names for those magic numbers. TR is a way to access
+proprietary registers on page 52b5. Use these helper functions
+so we can see which fields we're going to modify/set/clear.
+
+This patch doesn't really change registers' settings but just
+enhances readability and maintainability.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c  | 297 ++++++++++++++++---------
+ drivers/net/phy/mediatek/mtk-ge.c      |  82 +++++--
+ drivers/net/phy/mediatek/mtk-phy-lib.c |  91 ++++++++
+ drivers/net/phy/mediatek/mtk.h         |  13 ++
+ 4 files changed, 358 insertions(+), 125 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -24,7 +24,108 @@
+ #define MTK_PHY_SMI_DET_ON_THRESH_MASK		GENMASK(13, 8)
+ 
+ #define MTK_PHY_PAGE_EXTENDED_2A30		0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5		0x52b5
++
++/* Registers on Token Ring debug nodes */
++/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */
++/* NormMseLoThresh */
++#define NORMAL_MSE_LO_THRESH_MASK		GENMASK(15, 8)
++
++/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
++/* RemAckCntLimitCtrl */
++#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK	GENMASK(2, 1)
++
++/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */
++/* VcoSlicerThreshBitsHigh */
++#define VCO_SLICER_THRESH_HIGH_MASK		GENMASK(23, 0)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */
++/* DfeTailEnableVgaThresh1000 */
++#define DFE_TAIL_EANBLE_VGA_TRHESH_1000		GENMASK(5, 1)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */
++/* MrvlTrFix100Kp */
++#define MRVL_TR_FIX_100KP_MASK			GENMASK(22, 20)
++/* MrvlTrFix100Kf */
++#define MRVL_TR_FIX_100KF_MASK			GENMASK(19, 17)
++/* MrvlTrFix1000Kp */
++#define MRVL_TR_FIX_1000KP_MASK			GENMASK(16, 14)
++/* MrvlTrFix1000Kf */
++#define MRVL_TR_FIX_1000KF_MASK			GENMASK(13, 11)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */
++/* VgaDecRate */
++#define VGA_DECIMATION_RATE_MASK		GENMASK(8, 5)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
++/* SlvDSPreadyTime */
++#define SLAVE_DSP_READY_TIME_MASK		GENMASK(22, 15)
++/* MasDSPreadyTime */
++#define MASTER_DSP_READY_TIME_MASK		GENMASK(14, 7)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */
++/* EnabRandUpdTrig */
++#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER	BIT(8)
++
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
++/* ResetSyncOffset */
++#define RESET_SYNC_OFFSET_MASK			GENMASK(11, 8)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */
++/* FfeUpdGainForceVal */
++#define FFE_UPDATE_GAIN_FORCE_VAL_MASK		GENMASK(9, 7)
++/* FfeUpdGainForce */
++#define FFE_UPDATE_GAIN_FORCE			BIT(6)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */
++/* TrFreeze */
++#define TR_FREEZE_MASK				GENMASK(11, 0)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
++/* SS: Steady-state, KP: Proportional Gain */
++/* SSTrKp100 */
++#define SS_TR_KP100_MASK			GENMASK(21, 19)
++/* SSTrKf100 */
++#define SS_TR_KF100_MASK			GENMASK(18, 16)
++/* SSTrKp1000Mas */
++#define SS_TR_KP1000_MASTER_MASK		GENMASK(15, 13)
++/* SSTrKf1000Mas */
++#define SS_TR_KF1000_MASTER_MASK		GENMASK(12, 10)
++/* SSTrKp1000Slv */
++#define SS_TR_KP1000_SLAVE_MASK			GENMASK(9, 7)
++/* SSTrKf1000Slv */
++#define SS_TR_KF1000_SLAVE_MASK			GENMASK(6, 4)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */
++/* clear this bit if wanna select from AFE */
++/* Regsigdet_sel_1000 */
++#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE	BIT(4)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
++/* RegEEE_st2TrKf1000 */
++#define EEE1000_STAGE2_TR_KF_MASK		GENMASK(13, 11)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */
++/* RegEEE_slv_waketr_timer_tar */
++#define SLAVE_WAKETR_TIMER_MASK			GENMASK(20, 11)
++/* RegEEE_slv_remtx_timer_tar */
++#define SLAVE_REMTX_TIMER_MASK			GENMASK(10, 1)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */
++/* RegEEE_slv_wake_int_timer_tar */
++#define SLAVE_WAKEINT_TIMER_MASK		GENMASK(10, 1)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */
++/* RegEEE_trfreeze_timer2 */
++#define TR_FREEZE_TIMER2_MASK			GENMASK(9, 0)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */
++/* RegEEE100Stg1_tar */
++#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK	GENMASK(8, 0)
++
++/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */
++/* REGEEE_wake_slv_tr_wait_dfesigdet_en */
++#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN	BIT(11)
++
+ 
+ #define ANALOG_INTERNAL_OPERATION_MAX_US	20
+ #define TXRESERVE_MIN				0
+@@ -679,40 +780,36 @@ restore:
+ static void mt798x_phy_common_finetune(struct phy_device *phydev)
+ {
+ 	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	/* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
+-	__phy_write(phydev, 0x11, 0xc71);
+-	__phy_write(phydev, 0x12, 0xc);
+-	__phy_write(phydev, 0x10, 0x8fae);
+-
+-	/* EnabRandUpdTrig = 1 */
+-	__phy_write(phydev, 0x11, 0x2f00);
+-	__phy_write(phydev, 0x12, 0xe);
+-	__phy_write(phydev, 0x10, 0x8fb0);
+-
+-	/* NormMseLoThresh = 85 */
+-	__phy_write(phydev, 0x11, 0x55a0);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x83aa);
+-
+-	/* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
+-	__phy_write(phydev, 0x11, 0x240);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x9680);
+-
+-	/* TrFreeze = 0 (mt7988 default) */
+-	__phy_write(phydev, 0x11, 0x0);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x9686);
+-
+-	/* SSTrKp100 = 5 */
+-	/* SSTrKf100 = 6 */
+-	/* SSTrKp1000Mas = 5 */
+-	/* SSTrKf1000Mas = 6 */
+-	/* SSTrKp1000Slv = 5 */
+-	/* SSTrKf1000Slv = 6 */
+-	__phy_write(phydev, 0x11, 0xbaef);
+-	__phy_write(phydev, 0x12, 0x2e);
+-	__phy_write(phydev, 0x10, 0x968c);
++	__mtk_tr_modify(phydev, 0x1, 0xf, 0x17,
++			SLAVE_DSP_READY_TIME_MASK | MASTER_DSP_READY_TIME_MASK,
++			FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) |
++			FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18));
++
++	__mtk_tr_set_bits(phydev, 0x1, 0xf, 0x18,
++			  ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER);
++
++	__mtk_tr_modify(phydev, 0x0, 0x7, 0x15,
++			NORMAL_MSE_LO_THRESH_MASK,
++			FIELD_PREP(NORMAL_MSE_LO_THRESH_MASK, 0x55));
++
++	__mtk_tr_modify(phydev, 0x2, 0xd, 0x0,
++			FFE_UPDATE_GAIN_FORCE_VAL_MASK,
++			FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) |
++				   FFE_UPDATE_GAIN_FORCE);
++
++	__mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x3, TR_FREEZE_MASK);
++
++	__mtk_tr_modify(phydev, 0x2, 0xd, 0x6,
++			SS_TR_KP100_MASK | SS_TR_KF100_MASK |
++			SS_TR_KP1000_MASTER_MASK | SS_TR_KF1000_MASTER_MASK |
++			SS_TR_KP1000_SLAVE_MASK | SS_TR_KF1000_SLAVE_MASK,
++			FIELD_PREP(SS_TR_KP100_MASK, 0x5) |
++			FIELD_PREP(SS_TR_KF100_MASK, 0x6) |
++			FIELD_PREP(SS_TR_KP1000_MASTER_MASK, 0x5) |
++			FIELD_PREP(SS_TR_KF1000_MASTER_MASK, 0x6) |
++			FIELD_PREP(SS_TR_KP1000_SLAVE_MASK, 0x5) |
++			FIELD_PREP(SS_TR_KF1000_SLAVE_MASK, 0x6));
++
+ 	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+ }
+ 
+@@ -735,27 +832,29 @@ static void mt7981_phy_finetune(struct p
+ 	}
+ 
+ 	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	/* ResetSyncOffset = 6 */
+-	__phy_write(phydev, 0x11, 0x600);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x8fc0);
+-
+-	/* VgaDecRate = 1 */
+-	__phy_write(phydev, 0x11, 0x4c2a);
+-	__phy_write(phydev, 0x12, 0x3e);
+-	__phy_write(phydev, 0x10, 0x8fa4);
++	__mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
++			RESET_SYNC_OFFSET_MASK,
++			FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x6));
++
++	__mtk_tr_modify(phydev, 0x1, 0xf, 0x12,
++			VGA_DECIMATION_RATE_MASK,
++			FIELD_PREP(VGA_DECIMATION_RATE_MASK, 0x1));
+ 
+ 	/* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
+ 	 * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
+ 	 */
+-	__phy_write(phydev, 0x11, 0xd10a);
+-	__phy_write(phydev, 0x12, 0x34);
+-	__phy_write(phydev, 0x10, 0x8f82);
++	__mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
++			MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
++			MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
++			FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x3) |
++			FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x2) |
++			FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x3) |
++			FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x2));
+ 
+ 	/* VcoSlicerThreshBitsHigh */
+-	__phy_write(phydev, 0x11, 0x5555);
+-	__phy_write(phydev, 0x12, 0x55);
+-	__phy_write(phydev, 0x10, 0x8ec0);
++	__mtk_tr_modify(phydev, 0x1, 0xd, 0x20,
++			VCO_SLICER_THRESH_HIGH_MASK,
++			FIELD_PREP(VCO_SLICER_THRESH_HIGH_MASK, 0x555555));
+ 	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+ 
+ 	/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
+@@ -807,25 +906,23 @@ static void mt7988_phy_finetune(struct p
+ 	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
+ 
+ 	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	/* ResetSyncOffset = 5 */
+-	__phy_write(phydev, 0x11, 0x500);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x8fc0);
++	__mtk_tr_modify(phydev, 0x1, 0xf, 0x20,
++			RESET_SYNC_OFFSET_MASK,
++			FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x5));
+ 
+ 	/* VgaDecRate is 1 at default on mt7988 */
+ 
+-	/* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
+-	 * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
+-	 */
+-	__phy_write(phydev, 0x11, 0xb90a);
+-	__phy_write(phydev, 0x12, 0x6f);
+-	__phy_write(phydev, 0x10, 0x8f82);
+-
+-	/* RemAckCntLimitCtrl = 1 */
+-	__phy_write(phydev, 0x11, 0xfbba);
+-	__phy_write(phydev, 0x12, 0xc3);
+-	__phy_write(phydev, 0x10, 0x87f8);
+-
++	__mtk_tr_modify(phydev, 0x1, 0xf, 0x1,
++			MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK |
++			MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK,
++			FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x6) |
++			FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x7) |
++			FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x6) |
++			FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x7));
++
++	__mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
++			REMOTE_ACK_COUNT_LIMIT_CTRL_MASK,
++			FIELD_PREP(REMOTE_ACK_COUNT_LIMIT_CTRL_MASK, 0x1));
+ 	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+ 
+ 	/* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+@@ -901,45 +998,37 @@ static void mt798x_phy_eee(struct phy_de
+ 			 MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
+ 
+ 	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	/* Regsigdet_sel_1000 = 0 */
+-	__phy_write(phydev, 0x11, 0xb);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x9690);
+-
+-	/* REG_EEE_st2TrKf1000 = 2 */
+-	__phy_write(phydev, 0x11, 0x114f);
+-	__phy_write(phydev, 0x12, 0x2);
+-	__phy_write(phydev, 0x10, 0x969a);
+-
+-	/* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
+-	__phy_write(phydev, 0x11, 0x3028);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x969e);
+-
+-	/* RegEEE_slv_wake_int_timer_tar = 8 */
+-	__phy_write(phydev, 0x11, 0x5010);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x96a0);
+-
+-	/* RegEEE_trfreeze_timer2 = 586 */
+-	__phy_write(phydev, 0x11, 0x24a);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x96a8);
+-
+-	/* RegEEE100Stg1_tar = 16 */
+-	__phy_write(phydev, 0x11, 0x3210);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x96b8);
+-
+-	/* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
+-	__phy_write(phydev, 0x11, 0x1463);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x96ca);
+-
+-	/* DfeTailEnableVgaThresh1000 = 27 */
+-	__phy_write(phydev, 0x11, 0x36);
+-	__phy_write(phydev, 0x12, 0x0);
+-	__phy_write(phydev, 0x10, 0x8f80);
++	__mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x8,
++			  EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE);
++
++	__mtk_tr_modify(phydev, 0x2, 0xd, 0xd,
++			EEE1000_STAGE2_TR_KF_MASK,
++			FIELD_PREP(EEE1000_STAGE2_TR_KF_MASK, 0x2));
++
++	__mtk_tr_modify(phydev, 0x2, 0xd, 0xf,
++			SLAVE_WAKETR_TIMER_MASK | SLAVE_REMTX_TIMER_MASK,
++			FIELD_PREP(SLAVE_WAKETR_TIMER_MASK, 0x6) |
++			FIELD_PREP(SLAVE_REMTX_TIMER_MASK, 0x14));
++
++	__mtk_tr_modify(phydev, 0x2, 0xd, 0x10,
++			SLAVE_WAKEINT_TIMER_MASK,
++			FIELD_PREP(SLAVE_WAKEINT_TIMER_MASK, 0x8));
++
++	__mtk_tr_modify(phydev, 0x2, 0xd, 0x14,
++			TR_FREEZE_TIMER2_MASK,
++			FIELD_PREP(TR_FREEZE_TIMER2_MASK, 0x24a));
++
++	__mtk_tr_modify(phydev, 0x2, 0xd, 0x1c,
++			EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
++			FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK,
++				   0x10));
++
++	__mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x25,
++			  WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN);
++
++	__mtk_tr_modify(phydev, 0x1, 0xf, 0x0,
++			DFE_TAIL_EANBLE_VGA_TRHESH_1000,
++			FIELD_PREP(DFE_TAIL_EANBLE_VGA_TRHESH_1000, 0x1b));
+ 	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+ 
+ 	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -9,13 +9,35 @@
+ #define MTK_GPHY_ID_MT7530		0x03a29412
+ #define MTK_GPHY_ID_MT7531		0x03a29441
+ 
+-#define MTK_EXT_PAGE_ACCESS		0x1f
+-#define MTK_PHY_PAGE_STANDARD		0x0000
+-#define MTK_PHY_PAGE_EXTENDED		0x0001
+-#define MTK_PHY_PAGE_EXTENDED_2		0x0002
+-#define MTK_PHY_PAGE_EXTENDED_3		0x0003
+-#define MTK_PHY_PAGE_EXTENDED_2A30	0x2a30
+-#define MTK_PHY_PAGE_EXTENDED_52B5	0x52b5
++#define MTK_PHY_PAGE_EXTENDED_1			0x0001
++#define MTK_PHY_AUX_CTRL_AND_STATUS		0x14
++#define   MTK_PHY_ENABLE_DOWNSHIFT		BIT(4)
++
++#define MTK_PHY_PAGE_EXTENDED_2			0x0002
++#define MTK_PHY_PAGE_EXTENDED_3			0x0003
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11	0x11
++
++#define MTK_PHY_PAGE_EXTENDED_2A30		0x2a30
++
++/* Registers on Token Ring debug nodes */
++/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
++#define SLAVE_DSP_READY_TIME_MASK		GENMASK(22, 15)
++
++/* Registers on MDIO_MMD_VEND1 */
++#define MTK_PHY_GBE_MODE_TX_DELAY_SEL		0x13
++#define MTK_PHY_TEST_MODE_TX_DELAY_SEL		0x14
++#define   MTK_TX_DELAY_PAIR_B_MASK		GENMASK(10, 8)
++#define   MTK_TX_DELAY_PAIR_D_MASK		GENMASK(2, 0)
++
++#define MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL	0xa6
++#define   MTK_MCC_NEARECHO_OFFSET_MASK		GENMASK(15, 8)
++
++#define MTK_PHY_RXADC_CTRL_RG7			0xc6
++#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK	GENMASK(9, 8)
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123	0x123
++#define   MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK	GENMASK(15, 8)
++#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK	GENMASK(7, 0)
+ 
+ struct mtk_gephy_priv {
+ 	unsigned long		led_state;
+@@ -27,20 +49,29 @@ static void mtk_gephy_config_init(struct
+ 	phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
+ 
+ 	/* Enable HW auto downshift */
+-	phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
++	phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
++			 MTK_PHY_AUX_CTRL_AND_STATUS,
++			 0, MTK_PHY_ENABLE_DOWNSHIFT);
+ 
+ 	/* Increase SlvDPSready time */
+-	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-	__phy_write(phydev, 0x10, 0xafae);
+-	__phy_write(phydev, 0x12, 0x2f);
+-	__phy_write(phydev, 0x10, 0x8fae);
+-	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++	mtk_tr_modify(phydev, 0x1, 0xf, 0x17, SLAVE_DSP_READY_TIME_MASK,
++		      FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x5e));
+ 
+ 	/* Adjust 100_mse_threshold */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
+-
+-	/* Disable mcc */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++		       MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123,
++		       MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK |
++		       MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
++		       FIELD_PREP(MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK,
++				  0xff) |
++		       FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
++				  0xff));
++
++	/* If echo time is narrower than 0x3, it will be regarded as noise */
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++		       MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL,
++		       MTK_MCC_NEARECHO_OFFSET_MASK,
++		       FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3));
+ }
+ 
+ static int mt7530_phy_config_init(struct phy_device *phydev)
+@@ -48,7 +79,8 @@ static int mt7530_phy_config_init(struct
+ 	mtk_gephy_config_init(phydev);
+ 
+ 	/* Increase post_update_timer */
+-	phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
++	phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3,
++			MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11, 0x4b);
+ 
+ 	return 0;
+ }
+@@ -89,11 +121,19 @@ static int mt7531_phy_config_init(struct
+ 
+ 	/* PHY link down power saving enable */
+ 	phy_set_bits(phydev, 0x17, BIT(4));
+-	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
++		       MTK_PHY_DA_AD_BUF_BIAS_LP_MASK,
++		       FIELD_PREP(MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3));
+ 
+ 	/* Set TX Pair delay selection */
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
+-	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_GBE_MODE_TX_DELAY_SEL,
++		       MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
++		       FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
++		       FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TEST_MODE_TX_DELAY_SEL,
++		       MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
++		       FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
++		       FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
+ 
+ 	/* LED Config*/
+ 	mt7530_led_config_of(phydev);
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -6,6 +6,97 @@
+ 
+ #include "mtk.h"
+ 
++/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is
++ * mtk_tr* functions: wrapped by page switching operations
++ * __mtk_tr* functions: no page switching operations
++ */
++
++static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr,
++			    u8 node_addr, u8 data_addr)
++{
++	u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */
++
++	if (read)
++		tr_cmd |= BIT(13);
++
++	tr_cmd |= (((ch_addr & 0x3) << 11) |
++		   ((node_addr & 0xf) << 7) |
++		   ((data_addr & 0x3f) << 1));
++	dev_dbg(&phydev->mdio.dev, "tr_cmd: 0x%x\n", tr_cmd);
++	__phy_write(phydev, 0x10, tr_cmd);
++}
++
++static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++			  u8 data_addr, u16 *tr_high, u16 *tr_low)
++{
++	__mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr);
++	*tr_low = __phy_read(phydev, 0x11);
++	*tr_high = __phy_read(phydev, 0x12);
++	dev_dbg(&phydev->mdio.dev, "tr_high read: 0x%x, tr_low read: 0x%x\n",
++		*tr_high, *tr_low);
++}
++
++u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		u8 data_addr)
++{
++	u16 tr_high;
++	u16 tr_low;
++
++	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++	__mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low);
++	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++	return (tr_high << 16) | tr_low;
++}
++EXPORT_SYMBOL_GPL(mtk_tr_read);
++
++static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++			   u8 data_addr, u32 tr_data)
++{
++	__phy_write(phydev, 0x11, tr_data & 0xffff);
++	__phy_write(phydev, 0x12, tr_data >> 16);
++	dev_dbg(&phydev->mdio.dev, "tr_high write: 0x%x, tr_low write: 0x%x\n",
++		tr_data >> 16, tr_data & 0xffff);
++	__mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr);
++}
++
++void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		     u8 data_addr, u32 mask, u32 set)
++{
++	u32 tr_data;
++	u16 tr_high;
++	u16 tr_low;
++
++	__mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low);
++	tr_data = (tr_high << 16) | tr_low;
++	tr_data = (tr_data & ~mask) | set;
++	__mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data);
++}
++EXPORT_SYMBOL_GPL(__mtk_tr_modify);
++
++void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		   u8 data_addr, u32 mask, u32 set)
++{
++	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++	__mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set);
++	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++}
++EXPORT_SYMBOL_GPL(mtk_tr_modify);
++
++void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		       u8 data_addr, u32 set)
++{
++	__mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set);
++}
++EXPORT_SYMBOL_GPL(__mtk_tr_set_bits);
++
++void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		       u8 data_addr, u32 clr)
++{
++	__mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0);
++}
++EXPORT_SYMBOL_GPL(__mtk_tr_clr_bits);
++
+ int mtk_phy_read_page(struct phy_device *phydev)
+ {
+ 	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -9,6 +9,8 @@
+ #define _MTK_EPHY_H_
+ 
+ #define MTK_EXT_PAGE_ACCESS			0x1f
++#define MTK_PHY_PAGE_STANDARD			0x0000
++#define MTK_PHY_PAGE_EXTENDED_52B5		0x52b5
+ 
+ /* Registers on MDIO_MMD_VEND2 */
+ #define MTK_PHY_LED0_ON_CTRL			0x24
+@@ -62,6 +64,17 @@
+ #define MTK_PHY_LED_STATE_FORCE_BLINK	1
+ #define MTK_PHY_LED_STATE_NETDEV	2
+ 
++u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		u8 data_addr);
++void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		     u8 data_addr, u32 mask, u32 set);
++void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		   u8 data_addr, u32 mask, u32 set);
++void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		       u8 data_addr, u32 set);
++void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
++		       u8 data_addr, u32 clr);
++
+ int mtk_phy_read_page(struct phy_device *phydev);
+ int mtk_phy_write_page(struct phy_device *phydev, int page);
+ 
diff --git a/target/linux/mediatek/patches-6.6/733-10-net-phy-mediatek-Extend-1G-TX-RX-link-pulse-time.patch b/target/linux/mediatek/patches-6.6/733-10-net-phy-mediatek-Extend-1G-TX-RX-link-pulse-time.patch
new file mode 100644
index 0000000000..dcbe957836
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-10-net-phy-mediatek-Extend-1G-TX-RX-link-pulse-time.patch
@@ -0,0 +1,209 @@
+From 3c05195fc2c232cd853fc8cebf55310c4605111d Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:14 +0800
+Subject: [PATCH 10/13] net: phy: mediatek: Extend 1G TX/RX link pulse time
+
+We observe that some 10G devices' (mostly Marvell's chips inside) 1G
+training time violates specification, which may last 2230ms and affect
+later TX/RX link pulse time. This will invalidate MediaTek series
+gigabit Ethernet PHYs' hardware auto downshift mechanism.
+
+Without this patch, if someone is trying to use "4-wire" cable to
+connect above devices, MediaTek' gigabit Ethernet PHYs may fail
+to downshift to 100Mbps. (If partner 10G devices' downshift mechanism
+stops at 1G)
+
+This patch extends our 1G TX/RX link pulse time so that we can still
+link up with those 10G devices.
+
+Tested device:
+- Netgear GS110EMX's 10G port (Marvell 88X3340P)
+- QNAP QSW-M408-4C
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c  |  2 +
+ drivers/net/phy/mediatek/mtk-ge.c      |  5 +-
+ drivers/net/phy/mediatek/mtk-phy-lib.c | 92 ++++++++++++++++++++++++++
+ drivers/net/phy/mediatek/mtk.h         | 21 ++++++
+ 4 files changed, 116 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -1396,6 +1396,7 @@ static struct phy_driver mtk_socphy_driv
+ 		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
+ 		.name		= "MediaTek MT7981 PHY",
+ 		.config_init	= mt798x_phy_config_init,
++		.read_status	= mtk_gphy_cl22_read_status,
+ 		.config_intr	= genphy_no_config_intr,
+ 		.handle_interrupt = genphy_handle_interrupt_no_ack,
+ 		.probe		= mt7981_phy_probe,
+@@ -1413,6 +1414,7 @@ static struct phy_driver mtk_socphy_driv
+ 		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
+ 		.name		= "MediaTek MT7988 PHY",
+ 		.config_init	= mt798x_phy_config_init,
++		.read_status	= mtk_gphy_cl22_read_status,
+ 		.config_intr	= genphy_no_config_intr,
+ 		.handle_interrupt = genphy_handle_interrupt_no_ack,
+ 		.probe		= mt7988_phy_probe,
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -9,10 +9,6 @@
+ #define MTK_GPHY_ID_MT7530		0x03a29412
+ #define MTK_GPHY_ID_MT7531		0x03a29441
+ 
+-#define MTK_PHY_PAGE_EXTENDED_1			0x0001
+-#define MTK_PHY_AUX_CTRL_AND_STATUS		0x14
+-#define   MTK_PHY_ENABLE_DOWNSHIFT		BIT(4)
+-
+ #define MTK_PHY_PAGE_EXTENDED_2			0x0002
+ #define MTK_PHY_PAGE_EXTENDED_3			0x0003
+ #define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11	0x11
+@@ -251,6 +247,7 @@ static struct phy_driver mtk_gephy_drive
+ 		.name		= "MediaTek MT7531 PHY",
+ 		.probe		= mt7531_phy_probe,
+ 		.config_init	= mt7531_phy_config_init,
++		.read_status	= mtk_gphy_cl22_read_status,
+ 		/* Interrupts are handled by the switch, not the PHY
+ 		 * itself.
+ 		 */
+--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
++++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
+@@ -109,6 +109,98 @@ int mtk_phy_write_page(struct phy_device
+ }
+ EXPORT_SYMBOL_GPL(mtk_phy_write_page);
+ 
++/* This function deals with the case that 1G AN starts but isn't completed. We
++ * set AN_NEW_LP_CNT_LIMIT with different values time after time to let our
++ * 1G->100Mbps hardware automatic downshift to fit more partner devices.
++ */
++static int extend_an_new_lp_cnt_limit(struct phy_device *phydev)
++{
++	int mmd_read_ret;
++	u32 reg_val;
++	int timeout;
++
++	/* According to table 28-9 & Figure 28-18 in IEEE 802.3,
++	 * link_fail_inhibit_timer of 10/100/1000 Mbps devices ranges from 750
++	 * to "1000ms". Once MTK_PHY_FINAL_SPEED_1000 is set, it means that we
++	 * enter "FLP LINK GOOD CHECK" state, link_fail_inhibit_timer starts and
++	 * this PHY's 1G training starts. If 1G training never starts, we do
++	 * nothing but leave.
++	 */
++	timeout = read_poll_timeout(mmd_read_ret = phy_read_mmd, reg_val,
++				    (mmd_read_ret < 0) ||
++				    reg_val & MTK_PHY_FINAL_SPEED_1000,
++				    10000, 1000000, false, phydev,
++				    MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_MISC);
++	if (mmd_read_ret < 0)
++		return mmd_read_ret;
++
++	if (!timeout) {
++		/* Once we found MTK_PHY_FINAL_SPEED_1000 is set, no matter 1G
++		 * AN is completed or not, we'll set AN_NEW_LP_CNT_LIMIT again
++		 * and again.
++		 */
++		mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AN_NEW_LP_CNT_LIMIT_MASK,
++			      FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK, 0xf));
++		mdelay(1500);
++
++		timeout = read_poll_timeout(mtk_tr_read, reg_val,
++					    (reg_val & AN_STATE_MASK) !=
++					    (AN_STATE_TX_DISABLE <<
++					     AN_STATE_SHIFT),
++					    10000, 1000000, false, phydev,
++					    0x0, 0xf, 0x2);
++		if (!timeout) {
++			mdelay(625);
++			mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
++				      AN_NEW_LP_CNT_LIMIT_MASK,
++				      FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK,
++						 0x8));
++			mdelay(500);
++			mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
++				      AN_NEW_LP_CNT_LIMIT_MASK,
++				      FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK,
++						 0xf));
++		} else {
++			return -ETIMEDOUT;
++		}
++	}
++
++	return 0;
++}
++
++int mtk_gphy_cl22_read_status(struct phy_device *phydev)
++{
++	int ret;
++
++	ret = genphy_read_status(phydev);
++	if (ret)
++		return ret;
++
++	if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete) {
++		ret = phy_read_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
++				     MTK_PHY_AUX_CTRL_AND_STATUS);
++		if (ret < 0)
++			return ret;
++
++		/* Once LP_DETECTED is set, it means that"ability_match" in
++		 * IEEE 802.3 Figure 28-18 is set. This happens after we plug in
++		 * cable. Also, LP_DETECTED will be cleared after AN complete.
++		 */
++		if (!FIELD_GET(MTK_PHY_LP_DETECTED_MASK, ret))
++			return 0;
++
++		ret = phy_read(phydev, MII_CTRL1000);
++		if (ret & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) {
++			ret = extend_an_new_lp_cnt_limit(phydev);
++			if (ret < 0)
++				return ret;
++		}
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_gphy_cl22_read_status);
++
+ int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ 				unsigned long rules,
+ 				unsigned long supported_triggers)
+--- a/drivers/net/phy/mediatek/mtk.h
++++ b/drivers/net/phy/mediatek/mtk.h
+@@ -10,8 +10,28 @@
+ 
+ #define MTK_EXT_PAGE_ACCESS			0x1f
+ #define MTK_PHY_PAGE_STANDARD			0x0000
++#define MTK_PHY_PAGE_EXTENDED_1			0x0001
++#define MTK_PHY_AUX_CTRL_AND_STATUS		0x14
++/* suprv_media_select_RefClk */
++#define   MTK_PHY_LP_DETECTED_MASK		GENMASK(7, 6)
++#define   MTK_PHY_ENABLE_DOWNSHIFT		BIT(4)
++
+ #define MTK_PHY_PAGE_EXTENDED_52B5		0x52b5
+ 
++/* Registers on Token Ring debug nodes */
++/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x2 */
++#define   AN_STATE_MASK			GENMASK(22, 19)
++#define   AN_STATE_SHIFT		19
++#define   AN_STATE_TX_DISABLE		1
++
++/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
++#define AN_NEW_LP_CNT_LIMIT_MASK		GENMASK(23, 20)
++#define AUTO_NP_10XEN				BIT(6)
++
++/* Registers on MDIO_MMD_VEND1 */
++#define MTK_PHY_LINK_STATUS_MISC	(0xa2)
++#define   MTK_PHY_FINAL_SPEED_1000	BIT(3)
++
+ /* Registers on MDIO_MMD_VEND2 */
+ #define MTK_PHY_LED0_ON_CTRL			0x24
+ #define MTK_PHY_LED1_ON_CTRL			0x26
+@@ -78,6 +98,7 @@ void __mtk_tr_clr_bits(struct phy_device
+ int mtk_phy_read_page(struct phy_device *phydev);
+ int mtk_phy_write_page(struct phy_device *phydev, int page);
+ 
++int mtk_gphy_cl22_read_status(struct phy_device *phydev);
+ int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ 				unsigned long rules,
+ 				unsigned long supported_triggers);
diff --git a/target/linux/mediatek/patches-6.6/733-11-net-phy-add-driver-for-built-in-2.5G-ethernet-PHY-on.patch b/target/linux/mediatek/patches-6.6/733-11-net-phy-add-driver-for-built-in-2.5G-ethernet-PHY-on.patch
new file mode 100644
index 0000000000..a9595157ff
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-11-net-phy-add-driver-for-built-in-2.5G-ethernet-PHY-on.patch
@@ -0,0 +1,477 @@
+From 69ca89165e39e6b6f4c79e6b4c03559e0fac7051 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:15 +0800
+Subject: [PATCH 11/13] net: phy: add driver for built-in 2.5G ethernet PHY on
+ MT7988
+
+Add support for internal 2.5Gphy on MT7988. This driver will load
+necessary firmware, add appropriate time delay and figure out LED.
+Also, certain control registers will be set to fix link-up issues.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/Kconfig     |  11 +
+ drivers/net/phy/mediatek/Makefile    |   1 +
+ drivers/net/phy/mediatek/mtk-2p5ge.c | 432 +++++++++++++++++++++++++++
+ 4 files changed, 445 insertions(+)
+ create mode 100644 drivers/net/phy/mediatek/mtk-2p5ge.c
+
+--- a/drivers/net/phy/mediatek/Kconfig
++++ b/drivers/net/phy/mediatek/Kconfig
+@@ -25,3 +25,14 @@ config MEDIATEK_GE_SOC_PHY
+ 	  the MT7981 and MT7988 SoCs. These PHYs need calibration data
+ 	  present in the SoCs efuse and will dynamically calibrate VCM
+ 	  (common-mode voltage) during startup.
++
++config MEDIATEK_2P5GE_PHY
++	tristate "MediaTek 2.5Gb Ethernet PHYs"
++	depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
++	select MTK_NET_PHYLIB
++	help
++	  Supports MediaTek SoC built-in 2.5Gb Ethernet PHYs.
++
++	  This will load necessary firmware and add appropriate time delay.
++	  Accelerate this procedure through internal pbus instead of MDIO
++	  bus. Certain link-up issues will also be fixed here.
+--- a/drivers/net/phy/mediatek/Makefile
++++ b/drivers/net/phy/mediatek/Makefile
+@@ -2,3 +2,4 @@
+ obj-$(CONFIG_MTK_NET_PHYLIB)		+= mtk-phy-lib.o
+ obj-$(CONFIG_MEDIATEK_GE_PHY)		+= mtk-ge.o
+ obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)	+= mtk-ge-soc.o
++obj-$(CONFIG_MEDIATEK_2P5GE_PHY)	+= mtk-2p5ge.o
+--- /dev/null
++++ b/drivers/net/phy/mediatek/mtk-2p5ge.c
+@@ -0,0 +1,432 @@
++// SPDX-License-Identifier: GPL-2.0+
++#include <linux/bitfield.h>
++#include <linux/firmware.h>
++#include <linux/module.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/phy.h>
++#include <linux/pm_domain.h>
++#include <linux/pm_runtime.h>
++
++#include "mtk.h"
++
++#define MTK_2P5GPHY_ID_MT7988	(0x00339c11)
++
++#define MT7988_2P5GE_PMB_FW		"mediatek/mt7988/i2p5ge-phy-pmb.bin"
++#define MT7988_2P5GE_PMB_FW_SIZE	(0x20000)
++#define MT7988_2P5GE_PMB_FW_BASE	(0x0f100000)
++#define MT7988_2P5GE_PMB_FW_LEN		(0x20000)
++#define MT7988_2P5GE_MD32_EN_CFG_BASE	(0x0f0f0018)
++#define MT7988_2P5GE_MD32_EN_CFG_LEN	(0x20)
++#define   MD32_EN			BIT(0)
++
++#define BASE100T_STATUS_EXTEND		(0x10)
++#define BASE1000T_STATUS_EXTEND		(0x11)
++#define EXTEND_CTRL_AND_STATUS		(0x16)
++
++#define PHY_AUX_CTRL_STATUS		(0x1d)
++#define   PHY_AUX_DPX_MASK		GENMASK(5, 5)
++#define   PHY_AUX_SPEED_MASK		GENMASK(4, 2)
++
++#define MTK_PHY_LPI_PCS_DSP_CTRL		(0x121)
++#define   MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK	GENMASK(12, 8)
++
++/* Registers on Token Ring debug nodes */
++/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
++#define AUTO_NP_10XEN				BIT(6)
++
++struct mtk_i2p5ge_phy_priv {
++	bool fw_loaded;
++	unsigned long led_state;
++};
++
++enum {
++	PHY_AUX_SPD_10 = 0,
++	PHY_AUX_SPD_100,
++	PHY_AUX_SPD_1000,
++	PHY_AUX_SPD_2500,
++};
++
++static int mt798x_2p5ge_phy_load_fw(struct phy_device *phydev)
++{
++	struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
++	void __iomem *md32_en_cfg_base, *pmb_addr;
++	struct device *dev = &phydev->mdio.dev;
++	const struct firmware *fw;
++	int ret, i;
++	u16 reg;
++
++	if (priv->fw_loaded)
++		return 0;
++
++	pmb_addr = ioremap(MT7988_2P5GE_PMB_FW_BASE, MT7988_2P5GE_PMB_FW_LEN);
++	if (!pmb_addr)
++		return -ENOMEM;
++	md32_en_cfg_base = ioremap(MT7988_2P5GE_MD32_EN_CFG_BASE,
++				   MT7988_2P5GE_MD32_EN_CFG_LEN);
++	if (!md32_en_cfg_base) {
++		ret = -ENOMEM;
++		goto free_pmb;
++	}
++
++	ret = request_firmware(&fw, MT7988_2P5GE_PMB_FW, dev);
++	if (ret) {
++		dev_err(dev, "failed to load firmware: %s, ret: %d\n",
++			MT7988_2P5GE_PMB_FW, ret);
++		goto free;
++	}
++
++	if (fw->size != MT7988_2P5GE_PMB_FW_SIZE) {
++		dev_err(dev, "Firmware size 0x%zx != 0x%x\n",
++			fw->size, MT7988_2P5GE_PMB_FW_SIZE);
++		ret = -EINVAL;
++		goto release_fw;
++	}
++
++	reg = readw(md32_en_cfg_base);
++	if (reg & MD32_EN) {
++		phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
++		usleep_range(10000, 11000);
++	}
++	phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
++
++	/* Write magic number to safely stall MCU */
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800e, 0x1100);
++	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800f, 0x00df);
++
++	for (i = 0; i < MT7988_2P5GE_PMB_FW_SIZE - 1; i += 4)
++		writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
++	dev_info(dev, "Firmware date code: %x/%x/%x, version: %x.%x\n",
++		 be16_to_cpu(*((__be16 *)(fw->data +
++					  MT7988_2P5GE_PMB_FW_SIZE - 8))),
++		 *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 6),
++		 *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 5),
++		 *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 2),
++		 *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 1));
++
++	writew(reg & ~MD32_EN, md32_en_cfg_base);
++	writew(reg | MD32_EN, md32_en_cfg_base);
++	phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
++	/* We need a delay here to stabilize initialization of MCU */
++	usleep_range(7000, 8000);
++	dev_info(dev, "Firmware loading/trigger ok.\n");
++
++	priv->fw_loaded = true;
++
++release_fw:
++	release_firmware(fw);
++free:
++	iounmap(md32_en_cfg_base);
++free_pmb:
++	iounmap(pmb_addr);
++
++	return ret;
++}
++
++static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
++{
++	struct pinctrl *pinctrl;
++	int ret;
++
++	/* Check if PHY interface type is compatible */
++	if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL)
++		return -ENODEV;
++
++	ret = mt798x_2p5ge_phy_load_fw(phydev);
++	if (ret < 0)
++		return ret;
++
++	/* Setup LED */
++	phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
++			 MTK_PHY_LED_ON_POLARITY | MTK_PHY_LED_ON_LINK10 |
++			 MTK_PHY_LED_ON_LINK100 | MTK_PHY_LED_ON_LINK1000 |
++			 MTK_PHY_LED_ON_LINK2500);
++	phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL,
++			 MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX);
++
++	/* Switch pinctrl after setting polarity to avoid bogus blinking */
++	pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "i2p5gbe-led");
++	if (IS_ERR(pinctrl))
++		dev_err(&phydev->mdio.dev, "Fail to set LED pins!\n");
++
++	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL,
++		       MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0);
++
++	/* Enable 16-bit next page exchange bit if 1000-BT isn't advertising */
++	mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AUTO_NP_10XEN,
++		      FIELD_PREP(AUTO_NP_10XEN, 0x1));
++
++	/* Enable HW auto downshift */
++	phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
++			 MTK_PHY_AUX_CTRL_AND_STATUS,
++			 0, MTK_PHY_ENABLE_DOWNSHIFT);
++
++	return 0;
++}
++
++static int mt798x_2p5ge_phy_config_aneg(struct phy_device *phydev)
++{
++	bool changed = false;
++	u32 adv;
++	int ret;
++
++	/* In fact, if we disable autoneg, we can't link up correctly:
++	 * 2.5G/1G: Need AN to exchange master/slave information.
++	 * 100M/10M: Without AN, link starts at half duplex (According to
++	 *           IEEE 802.3-2018), which this phy doesn't support.
++	 */
++	if (phydev->autoneg == AUTONEG_DISABLE)
++		return -EOPNOTSUPP;
++
++	ret = genphy_c45_an_config_aneg(phydev);
++	if (ret < 0)
++		return ret;
++	if (ret > 0)
++		changed = true;
++
++	/* Clause 45 doesn't define 1000BaseT support. Use Clause 22 instead in
++	 * our design.
++	 */
++	adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
++	ret = phy_modify_changed(phydev, MII_CTRL1000, ADVERTISE_1000FULL, adv);
++	if (ret < 0)
++		return ret;
++	if (ret > 0)
++		changed = true;
++
++	return genphy_c45_check_and_restart_aneg(phydev, changed);
++}
++
++static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
++{
++	int ret;
++
++	ret = genphy_c45_pma_read_abilities(phydev);
++	if (ret)
++		return ret;
++
++	/* This phy can't handle collision, and neither can (XFI)MAC it's
++	 * connected to. Although it can do HDX handshake, it doesn't support
++	 * CSMA/CD that HDX requires.
++	 */
++	linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
++			   phydev->supported);
++
++	return 0;
++}
++
++static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev)
++{
++	int ret;
++
++	/* When MDIO_STAT1_LSTATUS is raised genphy_c45_read_link(), this phy
++	 * actually hasn't finished AN. So use CL22's link update function
++	 * instead.
++	 */
++	ret = genphy_update_link(phydev);
++	if (ret)
++		return ret;
++
++	phydev->speed = SPEED_UNKNOWN;
++	phydev->duplex = DUPLEX_UNKNOWN;
++	phydev->pause = 0;
++	phydev->asym_pause = 0;
++
++	/* We'll read link speed through vendor specific registers down below.
++	 * So remove phy_resolve_aneg_linkmode (AN on) & genphy_c45_read_pma
++	 * (AN off).
++	 */
++	if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
++		ret = genphy_c45_read_lpa(phydev);
++		if (ret < 0)
++			return ret;
++
++		/* Clause 45 doesn't define 1000BaseT support. Read the link
++		 * partner's 1G advertisement via Clause 22.
++		 */
++		ret = phy_read(phydev, MII_STAT1000);
++		if (ret < 0)
++			return ret;
++		mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
++	} else if (phydev->autoneg == AUTONEG_DISABLE) {
++		linkmode_zero(phydev->lp_advertising);
++	}
++
++	if (phydev->link) {
++		ret = phy_read(phydev, PHY_AUX_CTRL_STATUS);
++		if (ret < 0)
++			return ret;
++
++		switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) {
++		case PHY_AUX_SPD_10:
++			phydev->speed = SPEED_10;
++			break;
++		case PHY_AUX_SPD_100:
++			phydev->speed = SPEED_100;
++			break;
++		case PHY_AUX_SPD_1000:
++			phydev->speed = SPEED_1000;
++			break;
++		case PHY_AUX_SPD_2500:
++			phydev->speed = SPEED_2500;
++			break;
++		}
++
++		phydev->duplex = DUPLEX_FULL;
++		/* FIXME:
++		 * The current firmware always enables rate adaptation mode.
++		 */
++		phydev->rate_matching = RATE_MATCH_PAUSE;
++	}
++
++	return 0;
++}
++
++static int mt798x_2p5ge_phy_get_rate_matching(struct phy_device *phydev,
++					      phy_interface_t iface)
++{
++	return RATE_MATCH_PAUSE;
++}
++
++static const unsigned long supported_triggers =
++	BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++	BIT(TRIGGER_NETDEV_LINK)        |
++	BIT(TRIGGER_NETDEV_LINK_10)     |
++	BIT(TRIGGER_NETDEV_LINK_100)    |
++	BIT(TRIGGER_NETDEV_LINK_1000)   |
++	BIT(TRIGGER_NETDEV_LINK_2500)   |
++	BIT(TRIGGER_NETDEV_RX)          |
++	BIT(TRIGGER_NETDEV_TX);
++
++static int mt798x_2p5ge_phy_led_blink_set(struct phy_device *phydev, u8 index,
++					  unsigned long *delay_on,
++					  unsigned long *delay_off)
++{
++	struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
++	bool blinking = false;
++	int err = 0;
++
++	err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
++	if (err < 0)
++		return err;
++
++	err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state,
++				       blinking);
++	if (err)
++		return err;
++
++	return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
++				     MTK_2P5GPHY_LED_ON_MASK, false);
++}
++
++static int mt798x_2p5ge_phy_led_brightness_set(struct phy_device *phydev,
++					       u8 index,
++					       enum led_brightness value)
++{
++	struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
++	int err;
++
++	err = mtk_phy_hw_led_blink_set(phydev, index, &priv->led_state, false);
++	if (err)
++		return err;
++
++	return mtk_phy_hw_led_on_set(phydev, index, &priv->led_state,
++				     MTK_2P5GPHY_LED_ON_MASK,
++				     (value != LED_OFF));
++}
++
++static int mt798x_2p5ge_phy_led_hw_is_supported(struct phy_device *phydev,
++						u8 index, unsigned long rules)
++{
++	return mtk_phy_led_hw_is_supported(phydev, index, rules,
++					   supported_triggers);
++}
++
++static int mt798x_2p5ge_phy_led_hw_control_get(struct phy_device *phydev,
++					       u8 index, unsigned long *rules)
++{
++	struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
++
++	return mtk_phy_led_hw_ctrl_get(phydev, index, rules, &priv->led_state,
++				       MTK_2P5GPHY_LED_ON_SET,
++				       MTK_2P5GPHY_LED_RX_BLINK_SET,
++				       MTK_2P5GPHY_LED_TX_BLINK_SET);
++};
++
++static int mt798x_2p5ge_phy_led_hw_control_set(struct phy_device *phydev,
++					       u8 index, unsigned long rules)
++{
++	struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
++
++	return mtk_phy_led_hw_ctrl_set(phydev, index, rules, &priv->led_state,
++				       MTK_2P5GPHY_LED_ON_SET,
++				       MTK_2P5GPHY_LED_RX_BLINK_SET,
++				       MTK_2P5GPHY_LED_TX_BLINK_SET);
++};
++
++static int mt798x_2p5ge_phy_probe(struct phy_device *phydev)
++{
++	struct mtk_i2p5ge_phy_priv *priv;
++
++	priv = devm_kzalloc(&phydev->mdio.dev,
++			    sizeof(struct mtk_i2p5ge_phy_priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	switch (phydev->drv->phy_id) {
++	case MTK_2P5GPHY_ID_MT7988:
++		/* The original hardware only sets MDIO_DEVS_PMAPMD */
++		phydev->c45_ids.mmds_present |= MDIO_DEVS_PCS |
++						MDIO_DEVS_AN |
++						MDIO_DEVS_VEND1 |
++						MDIO_DEVS_VEND2;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	priv->fw_loaded = false;
++	phydev->priv = priv;
++
++	mtk_phy_leds_state_init(phydev);
++
++	return 0;
++}
++
++static struct phy_driver mtk_2p5gephy_driver[] = {
++	{
++		PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7988),
++		.name = "MediaTek MT7988 2.5GbE PHY",
++		.probe = mt798x_2p5ge_phy_probe,
++		.config_init = mt798x_2p5ge_phy_config_init,
++		.config_aneg = mt798x_2p5ge_phy_config_aneg,
++		.get_features = mt798x_2p5ge_phy_get_features,
++		.read_status = mt798x_2p5ge_phy_read_status,
++		.get_rate_matching = mt798x_2p5ge_phy_get_rate_matching,
++		.suspend = genphy_suspend,
++		.resume = genphy_resume,
++		.read_page = mtk_phy_read_page,
++		.write_page = mtk_phy_write_page,
++		.led_blink_set = mt798x_2p5ge_phy_led_blink_set,
++		.led_brightness_set = mt798x_2p5ge_phy_led_brightness_set,
++		.led_hw_is_supported = mt798x_2p5ge_phy_led_hw_is_supported,
++		.led_hw_control_get = mt798x_2p5ge_phy_led_hw_control_get,
++		.led_hw_control_set = mt798x_2p5ge_phy_led_hw_control_set,
++	},
++};
++
++module_phy_driver(mtk_2p5gephy_driver);
++
++static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
++	{ PHY_ID_MATCH_VENDOR(0x00339c00) },
++	{ }
++};
++
++MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
++MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang at mediatek.com>");
++MODULE_LICENSE("GPL");
++
++MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);
++MODULE_FIRMWARE(MT7988_2P5GE_PMB_FW);
diff --git a/target/linux/mediatek/patches-6.6/733-12-net-phy-mediatek-Fix-alignment-in-callback-functions.patch b/target/linux/mediatek/patches-6.6/733-12-net-phy-mediatek-Fix-alignment-in-callback-functions.patch
new file mode 100644
index 0000000000..8657886138
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-12-net-phy-mediatek-Fix-alignment-in-callback-functions.patch
@@ -0,0 +1,130 @@
+From 07e90eb1819319a0c34b0cf3a57a4a3878e96e4d Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:16 +0800
+Subject: [PATCH 12/13] net: phy: mediatek: Fix alignment in callback
+ functions' hook
+
+Align declarations in mtk_gephy_driver(mtk-ge.c) and
+mtk_socphy_driver(mtk-ge-soc.c). At first, some of them are
+".foo<tab>= method_foo", and others are ".bar<space>= method_bar".
+Use space instead for all of them here in case line is longer than
+80 chars.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 40 +++++++++++++--------------
+ drivers/net/phy/mediatek/mtk-ge.c     | 34 +++++++++++------------
+ 2 files changed, 37 insertions(+), 37 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -1394,17 +1394,17 @@ static int mt7981_phy_probe(struct phy_d
+ static struct phy_driver mtk_socphy_driver[] = {
+ 	{
+ 		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
+-		.name		= "MediaTek MT7981 PHY",
+-		.config_init	= mt798x_phy_config_init,
+-		.read_status	= mtk_gphy_cl22_read_status,
+-		.config_intr	= genphy_no_config_intr,
++		.name = "MediaTek MT7981 PHY",
++		.config_init = mt798x_phy_config_init,
++		.read_status = mtk_gphy_cl22_read_status,
++		.config_intr = genphy_no_config_intr,
+ 		.handle_interrupt = genphy_handle_interrupt_no_ack,
+-		.probe		= mt7981_phy_probe,
+-		.suspend	= genphy_suspend,
+-		.resume		= genphy_resume,
+-		.read_page	= mtk_phy_read_page,
+-		.write_page	= mtk_phy_write_page,
+-		.led_blink_set	= mt798x_phy_led_blink_set,
++		.probe = mt7981_phy_probe,
++		.suspend = genphy_suspend,
++		.resume = genphy_resume,
++		.read_page = mtk_phy_read_page,
++		.write_page = mtk_phy_write_page,
++		.led_blink_set = mt798x_phy_led_blink_set,
+ 		.led_brightness_set = mt798x_phy_led_brightness_set,
+ 		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+ 		.led_hw_control_set = mt798x_phy_led_hw_control_set,
+@@ -1412,17 +1412,17 @@ static struct phy_driver mtk_socphy_driv
+ 	},
+ 	{
+ 		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
+-		.name		= "MediaTek MT7988 PHY",
+-		.config_init	= mt798x_phy_config_init,
+-		.read_status	= mtk_gphy_cl22_read_status,
+-		.config_intr	= genphy_no_config_intr,
++		.name = "MediaTek MT7988 PHY",
++		.config_init = mt798x_phy_config_init,
++		.read_status = mtk_gphy_cl22_read_status,
++		.config_intr = genphy_no_config_intr,
+ 		.handle_interrupt = genphy_handle_interrupt_no_ack,
+-		.probe		= mt7988_phy_probe,
+-		.suspend	= genphy_suspend,
+-		.resume		= genphy_resume,
+-		.read_page	= mtk_phy_read_page,
+-		.write_page	= mtk_phy_write_page,
+-		.led_blink_set	= mt798x_phy_led_blink_set,
++		.probe = mt7988_phy_probe,
++		.suspend = genphy_suspend,
++		.resume = genphy_resume,
++		.read_page = mtk_phy_read_page,
++		.write_page = mtk_phy_write_page,
++		.led_blink_set = mt798x_phy_led_blink_set,
+ 		.led_brightness_set = mt798x_phy_led_brightness_set,
+ 		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+ 		.led_hw_control_set = mt798x_phy_led_hw_control_set,
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -230,34 +230,34 @@ static int mt753x_phy_led_hw_control_set
+ static struct phy_driver mtk_gephy_driver[] = {
+ 	{
+ 		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
+-		.name		= "MediaTek MT7530 PHY",
+-		.config_init	= mt7530_phy_config_init,
++		.name = "MediaTek MT7530 PHY",
++		.config_init = mt7530_phy_config_init,
+ 		/* Interrupts are handled by the switch, not the PHY
+ 		 * itself.
+ 		 */
+-		.config_intr	= genphy_no_config_intr,
++		.config_intr = genphy_no_config_intr,
+ 		.handle_interrupt = genphy_handle_interrupt_no_ack,
+-		.suspend	= genphy_suspend,
+-		.resume		= genphy_resume,
+-		.read_page	= mtk_phy_read_page,
+-		.write_page	= mtk_phy_write_page,
++		.suspend = genphy_suspend,
++		.resume = genphy_resume,
++		.read_page = mtk_phy_read_page,
++		.write_page = mtk_phy_write_page,
+ 	},
+ 	{
+ 		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531),
+-		.name		= "MediaTek MT7531 PHY",
+-		.probe		= mt7531_phy_probe,
+-		.config_init	= mt7531_phy_config_init,
+-		.read_status	= mtk_gphy_cl22_read_status,
++		.name = "MediaTek MT7531 PHY",
++		.probe = mt7531_phy_probe,
++		.config_init = mt7531_phy_config_init,
++		.read_status = mtk_gphy_cl22_read_status,
+ 		/* Interrupts are handled by the switch, not the PHY
+ 		 * itself.
+ 		 */
+-		.config_intr	= genphy_no_config_intr,
++		.config_intr = genphy_no_config_intr,
+ 		.handle_interrupt = genphy_handle_interrupt_no_ack,
+-		.suspend	= genphy_suspend,
+-		.resume		= genphy_resume,
+-		.read_page	= mtk_phy_read_page,
+-		.write_page	= mtk_phy_write_page,
+-		.led_blink_set	= mt753x_phy_led_blink_set,
++		.suspend = genphy_suspend,
++		.resume = genphy_resume,
++		.read_page = mtk_phy_read_page,
++		.write_page = mtk_phy_write_page,
++		.led_blink_set = mt753x_phy_led_blink_set,
+ 		.led_brightness_set = mt753x_phy_led_brightness_set,
+ 		.led_hw_is_supported = mt753x_phy_led_hw_is_supported,
+ 		.led_hw_control_set = mt753x_phy_led_hw_control_set,
diff --git a/target/linux/mediatek/patches-6.6/733-13-net-phy-mediatek-Remove-unnecessary-outer-parens-of-.patch b/target/linux/mediatek/patches-6.6/733-13-net-phy-mediatek-Remove-unnecessary-outer-parens-of-.patch
new file mode 100644
index 0000000000..dd99bbba9a
--- /dev/null
+++ b/target/linux/mediatek/patches-6.6/733-13-net-phy-mediatek-Remove-unnecessary-outer-parens-of-.patch
@@ -0,0 +1,65 @@
+From e59883b637ae317c2ac275b542e8a50670d76e7c Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang at mediatek.com>
+Date: Mon, 1 Jul 2024 18:54:17 +0800
+Subject: [PATCH 13/13] net: phy: mediatek: Remove unnecessary outer parens of
+ "supported_triggers" var
+
+This patch removes unnecessary outer parens of "supported_triggers" vars
+in mtk-ge.c & mtk-ge-soc.c to improve readability.
+
+Signed-off-by: SkyLake.Huang <skylake.huang at mediatek.com>
+---
+ drivers/net/phy/mediatek/mtk-ge-soc.c | 16 ++++++++--------
+ drivers/net/phy/mediatek/mtk-ge.c     | 16 ++++++++--------
+ 2 files changed, 16 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
+@@ -1224,14 +1224,14 @@ static int mt798x_phy_led_brightness_set
+ }
+ 
+ static const unsigned long supported_triggers =
+-	(BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+-	 BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+-	 BIT(TRIGGER_NETDEV_LINK)        |
+-	 BIT(TRIGGER_NETDEV_LINK_10)     |
+-	 BIT(TRIGGER_NETDEV_LINK_100)    |
+-	 BIT(TRIGGER_NETDEV_LINK_1000)   |
+-	 BIT(TRIGGER_NETDEV_RX)          |
+-	 BIT(TRIGGER_NETDEV_TX));
++	BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++	BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
++	BIT(TRIGGER_NETDEV_LINK)        |
++	BIT(TRIGGER_NETDEV_LINK_10)     |
++	BIT(TRIGGER_NETDEV_LINK_100)    |
++	BIT(TRIGGER_NETDEV_LINK_1000)   |
++	BIT(TRIGGER_NETDEV_RX)          |
++	BIT(TRIGGER_NETDEV_TX);
+ 
+ static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ 					  unsigned long rules)
+--- a/drivers/net/phy/mediatek/mtk-ge.c
++++ b/drivers/net/phy/mediatek/mtk-ge.c
+@@ -189,14 +189,14 @@ static int mt753x_phy_led_brightness_set
+ }
+ 
+ static const unsigned long supported_triggers =
+-	(BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+-	 BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+-	 BIT(TRIGGER_NETDEV_LINK)        |
+-	 BIT(TRIGGER_NETDEV_LINK_10)     |
+-	 BIT(TRIGGER_NETDEV_LINK_100)    |
+-	 BIT(TRIGGER_NETDEV_LINK_1000)   |
+-	 BIT(TRIGGER_NETDEV_RX)          |
+-	 BIT(TRIGGER_NETDEV_TX));
++	BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++	BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
++	BIT(TRIGGER_NETDEV_LINK)        |
++	BIT(TRIGGER_NETDEV_LINK_10)     |
++	BIT(TRIGGER_NETDEV_LINK_100)    |
++	BIT(TRIGGER_NETDEV_LINK_1000)   |
++	BIT(TRIGGER_NETDEV_RX)          |
++	BIT(TRIGGER_NETDEV_TX);
+ 
+ static int mt753x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ 					  unsigned long rules)
diff --git a/target/linux/mediatek/patches-6.6/733-net-phy-add-driver-for-MediaTek-2.5G-PHY.patch b/target/linux/mediatek/patches-6.6/733-net-phy-add-driver-for-MediaTek-2.5G-PHY.patch
deleted file mode 100644
index 74b16be152..0000000000
--- a/target/linux/mediatek/patches-6.6/733-net-phy-add-driver-for-MediaTek-2.5G-PHY.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 128dc09b0af36772062142ce9e85b19c84ac789a Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel at makrotopia.org>
-Date: Tue, 28 Feb 2023 17:53:37 +0000
-Subject: [PATCH] net: phy: add driver for MediaTek 2.5G PHY
-
-Signed-off-by: Daniel Golle <daniel at makrotopia.org>
----
- drivers/net/phy/Kconfig          |   7 ++
- drivers/net/phy/Makefile         |   1 +
- drivers/net/phy/mediatek-2p5ge.c | 220 +++++++++++++++++++++++++++++++
- 3 files changed, 226 insertions(+)
- create mode 100644 drivers/net/phy/mediatek-2p5ge.c
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -330,6 +330,13 @@ config MEDIATEK_GE_SOC_PHY
- 	  present in the SoCs efuse and will dynamically calibrate VCM
- 	  (common-mode voltage) during startup.
- 
-+config MEDIATEK_2P5G_PHY
-+	tristate "MediaTek 2.5G Ethernet PHY"
-+	depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
-+	default NET_MEDIATEK_SOC
-+	help
-+	  Supports the MediaTek 2.5G Ethernet PHY.
-+
- config MICREL_PHY
- 	tristate "Micrel PHYs"
- 	depends on PTP_1588_CLOCK_OPTIONAL
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -82,6 +82,7 @@ obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
- obj-$(CONFIG_MARVELL_88Q2XXX_PHY)	+= marvell-88q2xxx.o
- obj-$(CONFIG_MARVELL_88X2222_PHY)	+= marvell-88x2222.o
- obj-$(CONFIG_MAXLINEAR_GPHY)	+= mxl-gpy.o
-+obj-$(CONFIG_MEDIATEK_2P5G_PHY)	+= mediatek-2p5ge.o
- obj-$(CONFIG_MEDIATEK_GE_PHY)	+= mediatek-ge.o
- obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)	+= mediatek-ge-soc.o
- obj-$(CONFIG_MESON_GXL_PHY)	+= meson-gxl.o




More information about the lede-commits mailing list