[][kernel][common][eth][Update Airoha EN8801SC 1G PHY driver to v1.1.7 Generic]

[Description]
Change Airoha EN8801SC 1G PHY driver to v1.1.7 Generic.

Change Log:
[2023/05/12] V1.1.7_Generic
* Modify to Linux coding style.

[2023/04/21] V1.1.6_Generic
* Improve Tx compliance test items for PCB variation
* Adjust initial process to solve potential issue
* Optimize detecting phase 2 mechanism
* Optimize initial process

If your board that GMAC2 connects with Airoha EN8801SC, please change
the eth node as following.
=====================================================================
&eth {
	...

	gmac1: mac@1 {
		compatible = "mediatek,eth-mac";
		reg = <1>;
		phy-mode = "sgmii";
		phy-handle = <&phy24>;
	};

	mdio: mdio-bus {
		#address-cells = <1>;
		#size-cells = <0>;

		phy24: phy@24 {
			compatible = "ethernet-phy-id03a2.9471";
			reg = <24>;
			phy-mode = "sgmii";
			full-duplex;
			pause;
		};

		...
	};
};
=====================================================================
In addition, if EN8801SC connects with a RESET GPIO, please check the
GPIO number, and then add reset-gpio related definition to above phy
node.
=====================================================================
reset-gpios = <&gpio 6 1>;
reset-assert-us = <10000>;
reset-deassert-us = <10000>;
=====================================================================

If without this patch, kernel cannot load up-to-date PHY driver
for the Airoha EN8801SC.

[Release-log]
N/A


Change-Id: Icdb753309040c83e7f1925461e987963b7b6c1eb
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7538123
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.c b/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.c
new file mode 100644
index 0000000..f8c5ad6
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.c
@@ -0,0 +1,1153 @@
+// SPDX-License-Identifier: GPL-2.0
+/* FILE NAME:  en8801sc.c
+ * PURPOSE:
+ *      EN8801SC phy driver for Linux
+ * NOTES:
+ *
+ */
+
+/* INCLUDE FILE DECLARATIONS
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/delay.h>
+
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
+#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#endif
+
+#include "en8801sc.h"
+
+MODULE_DESCRIPTION("Airoha EN8801S PHY drivers for MediaTek SoC");
+MODULE_AUTHOR("Airoha");
+MODULE_LICENSE("GPL");
+
+#define airoha_mdio_lock(bus)   mutex_lock(&((bus)->mdio_lock))
+#define airoha_mdio_unlock(bus) mutex_unlock(&((bus)->mdio_lock))
+
+#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
+#define phydev_mdio_bus(_dev) (_dev->bus)
+#define phydev_phy_addr(_dev) (_dev->addr)
+#define phydev_dev(_dev) (&_dev->dev)
+#define phydev_pbus_addr(dev) ((dev)->addr + 1)
+#else
+#define phydev_mdio_bus(_dev) (_dev->mdio.bus)
+#define phydev_phy_addr(_dev) (_dev->mdio.addr)
+#define phydev_dev(_dev) (&_dev->mdio.dev)
+#define phydev_pbus_addr(dev) ((dev)->mdio.addr + 1)
+#endif
+
+enum {
+	PHY_STATE_DONE = 0,
+	PHY_STATE_INIT = 1,
+	PHY_STATE_PROCESS = 2,
+	PHY_STATE_FAIL = 3,
+};
+
+struct en8801s_priv {
+	bool first_init;
+	u16 count;
+#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
+	struct gpio_desc *hw_reset;
+#endif
+};
+
+/*
+The following led_cfg example is for reference only.
+LED5 1000M/LINK/ACT   (GPIO5)  <-> BASE_T_LED0,
+LED6 10/100M/LINK/ACT (GPIO9)  <-> BASE_T_LED1,
+LED4 100M/LINK/ACT    (GPIO8)  <-> BASE_T_LED2,
+*/
+/* User-defined.B */
+#define AIR_LED_SUPPORT
+#ifdef AIR_LED_SUPPORT
+static const struct AIR_BASE_T_LED_CFG_S led_cfg[4] = {
+/*
+*   {LED Enable,    GPIO,   LED Polarity,   LED ON, LED Blink}
+*/
+	/* BASE-T LED0 */
+	{LED_ENABLE, 5, AIR_ACTIVE_LOW,
+	 BASE_T_LED0_ON_CFG, BASE_T_LED0_BLK_CFG},
+	/* BASE-T LED1 */
+	{LED_ENABLE, 9, AIR_ACTIVE_LOW,
+	 BASE_T_LED1_ON_CFG, BASE_T_LED1_BLK_CFG},
+	/* BASE-T LED2 */
+	{LED_ENABLE, 8, AIR_ACTIVE_LOW,
+	 BASE_T_LED2_ON_CFG, BASE_T_LED2_BLK_CFG},
+	/* BASE-T LED3 */
+	{LED_DISABLE, 1, AIR_ACTIVE_LOW,
+	 BASE_T_LED3_ON_CFG, BASE_T_LED3_BLK_CFG},
+};
+static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
+#endif
+
+/* User-defined.E */
+
+/************************************************************************
+*                  F U N C T I O N S
+************************************************************************/
+static unsigned int airoha_cl22_read(struct mii_bus *ebus, int phy_addr,
+			unsigned int phy_register, unsigned int *read_data)
+{
+	*read_data = mdiobus_read(ebus, phy_addr, phy_register);
+	return 0;
+}
+
+static int airoha_cl22_write(struct mii_bus *ebus, int phy_addr,
+			unsigned int phy_register, unsigned int write_data)
+{
+	int ret = 0;
+	struct device *dev = &ebus->dev;
+
+	ret = mdiobus_write(ebus, phy_addr, phy_register, write_data);
+	if (ret < 0) {
+		dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int __airoha_cl45_write(struct mii_bus *bus, int port,
+			u32 devad, u32 reg, u16 val)
+{
+	int ret = 0;
+	struct device *dev = &bus->dev;
+
+	ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad);
+	if (ret < 0) {
+		dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret);
+		return ret;
+	}
+	ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg);
+	if (ret < 0) {
+		dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret);
+		return ret;
+	}
+	ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG,
+				MMD_OP_MODE_DATA | devad);
+	if (ret < 0) {
+		dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret);
+		return ret;
+	}
+	ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, val);
+	if (ret < 0) {
+		dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int __airoha_cl45_read(struct mii_bus *bus, int port,
+			u32 devad, u32 reg, u16 *read_data)
+{
+	int ret = 0;
+	struct device *dev = &bus->dev;
+
+	ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad);
+	if (ret < 0) {
+		dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret);
+		return ret;
+	}
+	ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg);
+	if (ret < 0) {
+		dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret);
+		return ret;
+	}
+	ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG,
+				MMD_OP_MODE_DATA | devad);
+	if (ret < 0) {
+		dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret);
+		return ret;
+	}
+	*read_data = __mdiobus_read(bus, port, MII_MMD_ADDR_DATA_REG);
+
+	return ret;
+}
+
+static int airoha_cl45_write(struct mii_bus *bus, int port,
+			u32 devad, u32 reg, u16 val)
+{
+	int ret = 0;
+
+	airoha_mdio_lock(bus);
+	ret = __airoha_cl45_write(bus, port, devad, reg, val);
+	airoha_mdio_unlock(bus);
+
+	return ret;
+}
+
+static int airoha_cl45_read(struct mii_bus *bus, int port,
+			u32 devad, u32 reg, u16 *read_data)
+{
+	int ret = 0;
+
+	airoha_mdio_lock(bus);
+	ret = __airoha_cl45_read(bus, port, devad, reg, read_data);
+	airoha_mdio_unlock(bus);
+
+	return ret;
+}
+
+static int __airoha_pbus_write(struct mii_bus *ebus, int pbus_id,
+			unsigned long pbus_address, unsigned long pbus_data)
+{
+	int ret = 0;
+	struct device *dev = &ebus->dev;
+
+	ret = __mdiobus_write(ebus, pbus_id, 0x1F,
+				(unsigned int)(pbus_address >> 6));
+	if (ret < 0)
+		return ret;
+	ret = __mdiobus_write(ebus, pbus_id,
+				(unsigned int)((pbus_address >> 2) & 0xf),
+				(unsigned int)(pbus_data & 0xFFFF));
+	if (ret < 0)
+		return ret;
+	ret = __mdiobus_write(ebus, pbus_id, 0x10,
+				(unsigned int)(pbus_data >> 16));
+	if (ret < 0)
+		return ret;
+	return ret;
+}
+
+static unsigned long __airoha_pbus_read(struct mii_bus *ebus, int pbus_id,
+			unsigned long pbus_address)
+{
+	unsigned long pbus_data;
+	unsigned int pbus_data_low, pbus_data_high;
+	int ret = 0;
+	struct device *dev = &ebus->dev;
+
+	ret = __mdiobus_write(ebus, pbus_id, 0x1F,
+				(unsigned int)(pbus_address >> 6));
+	if (ret < 0) {
+		dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret);
+		return INVALID_DATA;
+	}
+	pbus_data_low = __mdiobus_read(ebus, pbus_id,
+				(unsigned int)((pbus_address >> 2) & 0xf));
+	pbus_data_high = __mdiobus_read(ebus, pbus_id, 0x10);
+	pbus_data = (pbus_data_high << 16) + pbus_data_low;
+	return pbus_data;
+}
+
+static int airoha_pbus_write(struct mii_bus *ebus, int pbus_id,
+			unsigned long pbus_address, unsigned long pbus_data)
+{
+	int ret = 0;
+
+	airoha_mdio_lock(ebus);
+	ret = __airoha_pbus_write(ebus, pbus_id, pbus_address, pbus_data);
+	airoha_mdio_unlock(ebus);
+
+	return ret;
+}
+
+static unsigned long airoha_pbus_read(struct mii_bus *ebus, int pbus_id,
+			unsigned long pbus_address)
+{
+	unsigned long pbus_data;
+
+	airoha_mdio_lock(ebus);
+	pbus_data = __airoha_pbus_read(ebus, pbus_id, pbus_address);
+	airoha_mdio_unlock(ebus);
+
+	return pbus_data;
+}
+
+/* Airoha Token Ring Write function */
+static int airoha_tr_reg_write(struct phy_device *phydev,
+			unsigned long tr_address, unsigned long tr_data)
+{
+	int ret = 0;
+	int phy_addr = phydev_phy_addr(phydev);
+	struct mii_bus *ebus = phydev_mdio_bus(phydev);
+
+	airoha_mdio_lock(ebus);
+	ret = __mdiobus_write(ebus, phy_addr, 0x1F, 0x52b5); /* page select */
+	ret = __mdiobus_write(ebus, phy_addr, 0x11,
+				(unsigned int)(tr_data & 0xffff));
+	ret = __mdiobus_write(ebus, phy_addr, 0x12,
+				(unsigned int)(tr_data >> 16));
+	ret = __mdiobus_write(ebus, phy_addr, 0x10,
+				(unsigned int)(tr_address | TrReg_WR));
+	ret = __mdiobus_write(ebus, phy_addr, 0x1F, 0x0);    /* page resetore */
+	airoha_mdio_unlock(ebus);
+
+	return ret;
+}
+
+#ifdef AIR_LED_SUPPORT
+static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity,
+			int polar, u16 on_evt, u16 blk_evt)
+{
+	int ret = 0;
+	int phy_addr = phydev_phy_addr(phydev);
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+
+	if (polar == AIR_ACTIVE_HIGH)
+		on_evt |= LED_ON_POL;
+	else
+		on_evt &= ~LED_ON_POL;
+
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1f,
+				LED_ON_CTRL(entity), on_evt | LED_ON_EN);
+	if (ret < 0)
+		return ret;
+
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1f,
+				LED_BLK_CTRL(entity), blk_evt);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int airoha_led_set_mode(struct phy_device *phydev, u8 mode)
+{
+	u16 cl45_data;
+	int err = 0;
+	int phy_addr = phydev_phy_addr(phydev);
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+
+	err = airoha_cl45_read(mbus, phy_addr, 0x1f, LED_BCR, &cl45_data);
+	if (err < 0)
+		return err;
+
+	switch (mode) {
+	case AIR_LED_MODE_DISABLE:
+		cl45_data &= ~LED_BCR_EXT_CTRL;
+		cl45_data &= ~LED_BCR_MODE_MASK;
+		cl45_data |= LED_BCR_MODE_DISABLE;
+		break;
+	case AIR_LED_MODE_USER_DEFINE:
+		cl45_data |= LED_BCR_EXT_CTRL;
+		cl45_data |= LED_BCR_CLK_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_BCR, cl45_data);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state)
+{
+	u16 cl45_data;
+	int err;
+	int phy_addr = phydev_phy_addr(phydev);
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+
+	err = airoha_cl45_read(mbus, phy_addr, 0x1f,
+				LED_ON_CTRL(entity), &cl45_data);
+	if (err < 0)
+		return err;
+	if (state == LED_ENABLE)
+		cl45_data |= LED_ON_EN;
+	else
+		cl45_data &= ~LED_ON_EN;
+
+	err = airoha_cl45_write(mbus, phy_addr, 0x1f,
+				LED_ON_CTRL(entity), cl45_data);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int en8801s_led_init(struct phy_device *phydev)
+{
+
+	unsigned long led_gpio = 0, reg_value = 0;
+	int ret = 0, led_id;
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+	int gpio_led_rg[3] = {0x1870, 0x1874, 0x1878};
+	u16 cl45_data = led_dur;
+	struct device *dev = phydev_dev(phydev);
+	int phy_addr = phydev_phy_addr(phydev);
+	int pbus_addr = phydev_pbus_addr(phydev);
+
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_BLK_DUR, cl45_data);
+	if (ret < 0)
+		return ret;
+	cl45_data >>= 1;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_ON_DUR, cl45_data);
+	if (ret < 0)
+		return ret;
+	ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE);
+	if (ret != 0) {
+		dev_err(dev, "LED fail to set mode, ret %d !\n", ret);
+		return ret;
+	}
+	for (led_id = 0; led_id < EN8801S_LED_COUNT; led_id++) {
+		reg_value = 0;
+		ret = airoha_led_set_state(phydev, led_id, led_cfg[led_id].en);
+		if (ret != 0) {
+			dev_err(dev, "LED fail to set state, ret %d !\n", ret);
+			return ret;
+		}
+		if (led_cfg[led_id].en == LED_ENABLE) {
+			if ((led_cfg[led_id].gpio < 0)
+				|| led_cfg[led_id].gpio > 9) {
+				dev_err(dev, "GPIO%d is out of range!! GPIO number is 0~9.\n",
+					led_cfg[led_id].gpio);
+				return -EIO;
+			}
+			led_gpio |= BIT(led_cfg[led_id].gpio);
+			reg_value = airoha_pbus_read(mbus, pbus_addr,
+					gpio_led_rg[led_cfg[led_id].gpio / 4]);
+			LED_SET_GPIO_SEL(led_cfg[led_id].gpio,
+					led_id, reg_value);
+			dev_dbg(dev, "[Airoha] gpio%d, reg_value 0x%lx\n",
+					led_cfg[led_id].gpio, reg_value);
+			ret = airoha_pbus_write(mbus, pbus_addr,
+					gpio_led_rg[led_cfg[led_id].gpio / 4],
+					reg_value);
+			if (ret < 0)
+				return ret;
+			ret = airoha_led_set_usr_def(phydev, led_id,
+					led_cfg[led_id].pol,
+					led_cfg[led_id].on_cfg,
+					led_cfg[led_id].blk_cfg);
+			if (ret != 0) {
+				dev_err(dev, "LED fail to set usr def, ret %d !\n",
+				ret);
+				return ret;
+			}
+		}
+	}
+	reg_value = (airoha_pbus_read(mbus, pbus_addr, 0x1880) & ~led_gpio);
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x1880, reg_value);
+	if (ret < 0)
+		return ret;
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x186c, led_gpio);
+	if (ret < 0)
+		return ret;
+	dev_info(dev, "LED initialize OK !\n");
+	return 0;
+}
+#endif
+static int en8801s_phy_process(struct phy_device *phydev)
+{
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+	unsigned long reg_value = 0;
+	int ret = 0;
+	int pbus_addr = phydev_pbus_addr(phydev);
+
+	reg_value = airoha_pbus_read(mbus, pbus_addr, 0x19e0);
+	reg_value |= BIT(0);
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, reg_value);
+	if (ret < 0)
+		return ret;
+	reg_value = airoha_pbus_read(mbus, pbus_addr, 0x19e0);
+	reg_value &= ~BIT(0);
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, reg_value);
+	if (ret < 0)
+		return ret;
+	return ret;
+}
+
+static int en8801s_phase1_init(struct phy_device *phydev)
+{
+	unsigned long pbus_data;
+	int pbusAddress = EN8801S_PBUS_DEFAULT_ID;
+	u16 reg_value;
+	int retry, ret = 0;
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+	struct device *dev = phydev_dev(phydev);
+	struct en8801s_priv *priv = phydev->priv;
+
+#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
+	/* Deassert the reset signal */
+	if (priv->hw_reset)
+		gpiod_set_value(priv->hw_reset, 0);
+#endif
+	priv->count = 1;
+	msleep(1000);
+
+	retry = MAX_OUI_CHECK;
+	while (1) {
+		pbus_data = airoha_pbus_read(mbus, pbusAddress,
+				EN8801S_RG_ETHER_PHY_OUI);      /* PHY OUI */
+		if (pbus_data == EN8801S_PBUS_OUI) {
+			dev_info(dev, "PBUS addr 0x%x: Start initialized.\n",
+					pbusAddress);
+			break;
+		}
+		pbusAddress = phydev_pbus_addr(phydev);
+		if (0 == --retry) {
+			dev_err(dev, "Probe fail !\n");
+			return 0;
+		}
+	}
+
+	ret = airoha_pbus_write(mbus, pbusAddress, EN8801S_RG_BUCK_CTL, 0x03);
+	if (ret < 0)
+		return ret;
+	mdelay(10);
+	pbus_data = (airoha_pbus_read(mbus, pbusAddress, EN8801S_RG_LTR_CTL)
+				 & 0xfffffffc) | BIT(2);
+	ret = airoha_pbus_write(mbus, pbusAddress,
+				EN8801S_RG_LTR_CTL, pbus_data);
+	if (ret < 0)
+		return ret;
+	mdelay(500);
+	pbus_data = (pbus_data & ~BIT(2)) |
+				EN8801S_RX_POLARITY_NORMAL |
+				EN8801S_TX_POLARITY_NORMAL;
+	ret = airoha_pbus_write(mbus, pbusAddress,
+				EN8801S_RG_LTR_CTL, pbus_data);
+	if (ret < 0)
+		return ret;
+	mdelay(500);
+
+	pbus_data = airoha_pbus_read(mbus, pbusAddress,
+				EN8801S_RG_SMI_ADDR); /* SMI ADDR */
+	pbus_data = (pbus_data & 0xffff0000) |
+				(unsigned long)(phydev_pbus_addr(phydev) << 8) |
+				(unsigned long)(phydev_phy_addr(phydev));
+	dev_info(phydev_dev(phydev), "SMI_ADDR=%lx (renew)\n", pbus_data);
+	ret = airoha_pbus_write(mbus, pbusAddress,
+				EN8801S_RG_SMI_ADDR, pbus_data);
+	mdelay(10);
+
+	retry = MAX_RETRY;
+	while (1) {
+		mdelay(10);
+		reg_value = phy_read(phydev, MII_PHYSID2);
+		if (reg_value == EN8801S_PHY_ID2)
+			break;    /* wait GPHY ready */
+
+		retry--;
+		if (retry == 0) {
+			dev_err(dev, "Initialize fail !\n");
+			return 0;
+		}
+	}
+	/* Software Reset PHY */
+	reg_value = phy_read(phydev, MII_BMCR);
+	reg_value |= BMCR_RESET;
+	ret = phy_write(phydev, MII_BMCR, reg_value);
+	if (ret < 0)
+		return ret;
+	retry = MAX_RETRY;
+	do {
+		mdelay(10);
+		reg_value = phy_read(phydev, MII_BMCR);
+		retry--;
+		if (retry == 0) {
+			dev_err(dev, "Reset fail !\n");
+			return 0;
+		}
+	} while (reg_value & BMCR_RESET);
+
+	phydev->dev_flags = PHY_STATE_INIT;
+
+	dev_info(dev, "Phase1 initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION);
+
+	return 0;
+}
+
+static int en8801s_phase2_init(struct phy_device *phydev)
+{
+	union gephy_all_REG_LpiReg1Ch      GPHY_RG_LPI_1C;
+	union gephy_all_REG_dev1Eh_reg324h GPHY_RG_1E_324;
+	union gephy_all_REG_dev1Eh_reg012h GPHY_RG_1E_012;
+	union gephy_all_REG_dev1Eh_reg017h GPHY_RG_1E_017;
+	unsigned long pbus_data;
+	int phy_addr = phydev_phy_addr(phydev);
+	int pbus_addr = phydev_pbus_addr(phydev);
+	u16 cl45_value;
+	int retry, ret = 0;
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+	struct device *dev = phydev_dev(phydev);
+	struct en8801s_priv *priv = phydev->priv;
+
+	pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1690);
+	pbus_data |= BIT(31);
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x1690, pbus_data);
+	if (ret < 0)
+		return ret;
+
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00);
+	if (ret < 0)
+		return ret;
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD801);
+	if (ret < 0)
+		return ret;
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x0,  0x9140);
+	if (ret < 0)
+		return ret;
+
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0003);
+	if (ret < 0)
+		return ret;
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00);
+	if (ret < 0)
+		return ret;
+	/* Set FCM control */
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x004b);
+	if (ret < 0)
+		return ret;
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007);
+	if (ret < 0)
+		return ret;
+
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x142c, 0x05050505);
+	if (ret < 0)
+		return ret;
+	pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1440);
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x1440, pbus_data & ~BIT(11));
+	if (ret < 0)
+		return ret;
+
+	pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1408);
+	ret = airoha_pbus_write(mbus, pbus_addr, 0x1408, pbus_data | BIT(5));
+	if (ret < 0)
+		return ret;
+
+	/* Set GPHY Perfomance*/
+	/* Token Ring */
+	ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_15h, 0x0055A0);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_17h, 0x07FF3F);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_PMA_00h,      0x00001E);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_PMA_01h,      0x6FB90A);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_PMA_17h,      0x060671);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_PMA_18h,      0x0E2F00);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_TR_26h,       0x444444);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_03h,     0x000000);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_06h,     0x2EBAEF);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_08h,     0x00000B);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Ch,     0x00504D);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Dh,     0x02314F);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Fh,     0x003028);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_10h,     0x005010);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_11h,     0x040001);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_13h,     0x018670);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_14h,     0x00024A);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Bh,     0x000072);
+	if (ret < 0)
+		return ret;
+	ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Ch,     0x003210);
+	if (ret < 0)
+		return ret;
+
+	/* CL22 & CL45 */
+	ret = phy_write(phydev, 0x1f, 0x03);
+	if (ret < 0)
+		return ret;
+	GPHY_RG_LPI_1C.DATA = phy_read(phydev, RgAddr_LPI_1Ch);
+	GPHY_RG_LPI_1C.DataBitField.smi_deton_th = 0x0C;
+	ret = phy_write(phydev, RgAddr_LPI_1Ch, GPHY_RG_LPI_1C.DATA);
+	if (ret < 0)
+		return ret;
+	ret = phy_write(phydev, RgAddr_LPI_1Ch, 0xC92);
+	if (ret < 0)
+		return ret;
+	ret = phy_write(phydev, RgAddr_AUXILIARY_1Dh, 0x1);
+	if (ret < 0)
+		return ret;
+	ret = phy_write(phydev, 0x1f, 0x0);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x120, 0x8014);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x122, 0xffff);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x123, 0xffff);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x144, 0x0200);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x14A, 0xEE20);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x189, 0x0110);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x19B, 0x0111);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x234, 0x0181);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x238, 0x0120);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x239, 0x0117);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x268, 0x07F4);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x2D1, 0x0733);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x323, 0x0011);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, 0x013F);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x326, 0x0037);
+	if (ret < 0)
+		return ret;
+
+	ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x324, &cl45_value);
+	if (ret < 0)
+		return ret;
+	GPHY_RG_1E_324.DATA = cl45_value;
+	GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = 0;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324,
+				GPHY_RG_1E_324.DATA);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x19E, 0xC2);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x013, 0x0);
+	if (ret < 0)
+		return ret;
+
+	/* EFUSE */
+	airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40000040);
+	retry = MAX_RETRY;
+	while (retry != 0) {
+		mdelay(1);
+		pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08);
+		if ((pbus_data & BIT(30)) == 0)
+			break;
+
+		retry--;
+	}
+	pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C38); /* RAW#2 */
+	ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x12, &cl45_value);
+	if (ret < 0)
+		return ret;
+	GPHY_RG_1E_012.DATA = cl45_value;
+	GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt =
+				(u16)(pbus_data & 0x03f);
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12,
+				GPHY_RG_1E_012.DATA);
+	if (ret < 0)
+		return ret;
+	ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x17, &cl45_value);
+	if (ret < 0)
+		return ret;
+	GPHY_RG_1E_017.DATA = cl45_value;
+	GPHY_RG_1E_017.DataBitField.da_tx_i2mpb_b_tbt =
+				(u16)((pbus_data >> 8) & 0x03f);
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x17,
+				GPHY_RG_1E_017.DATA);
+	if (ret < 0)
+		return ret;
+
+	airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40400040);
+	retry = MAX_RETRY;
+	while (retry != 0) {
+		mdelay(1);
+		pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08);
+		if ((pbus_data & BIT(30)) == 0)
+			break;
+
+		retry--;
+	}
+	pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C30); /* RAW#16 */
+	GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off =
+				(u16)((pbus_data >> 12) & 0x01);
+	ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324,
+				GPHY_RG_1E_324.DATA);
+	if (ret < 0)
+		return ret;
+#ifdef AIR_LED_SUPPORT
+	ret = en8801s_led_init(phydev);
+	if (ret != 0)
+		dev_err(dev, "en8801s_led_init fail (ret:%d) !\n", ret);
+#endif
+
+	ret = airoha_cl45_read(mbus, phy_addr, MDIO_MMD_AN,
+				MDIO_AN_EEE_ADV, &cl45_value);
+	if (ret < 0)
+		return ret;
+	if (cl45_value == 0) {
+		pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1960);
+		if (0xA == ((pbus_data & 0x07c00000) >> 22)) {
+			pbus_data = (pbus_data & 0xf83fffff) | (0xC << 22);
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x1960,
+						pbus_data);
+			if (ret < 0)
+				return ret;
+			mdelay(10);
+			pbus_data = (pbus_data & 0xf83fffff) | (0xE << 22);
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x1960,
+						pbus_data);
+			if (ret < 0)
+				return ret;
+			mdelay(10);
+		}
+	} else {
+		pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1960);
+		if (0xE == ((pbus_data & 0x07c00000) >> 22)) {
+			pbus_data = (pbus_data & 0xf83fffff) | (0xC << 22);
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x1960,
+						pbus_data);
+			if (ret < 0)
+				return ret;
+			mdelay(10);
+			pbus_data = (pbus_data & 0xf83fffff) | (0xA << 22);
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x1960,
+						pbus_data);
+			if (ret < 0)
+				return ret;
+			mdelay(10);
+		}
+	}
+
+	priv->first_init = false;
+	dev_info(phydev_dev(phydev), "Phase2 initialize OK !\n");
+	return 0;
+}
+
+static int en8801s_read_status(struct phy_device *phydev)
+{
+	int ret = 0, preSpeed = phydev->speed;
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+	u32 reg_value;
+	struct device *dev = phydev_dev(phydev);
+	int pbus_addr = phydev_pbus_addr(phydev);
+	struct en8801s_priv *priv = phydev->priv;
+
+	ret = genphy_read_status(phydev);
+	if (phydev->link == LINK_DOWN)
+		preSpeed = phydev->speed = 0;
+
+	if (phydev->dev_flags == PHY_STATE_PROCESS) {
+		en8801s_phy_process(phydev);
+		phydev->dev_flags = PHY_STATE_DONE;
+	}
+
+	if (phydev->dev_flags == PHY_STATE_INIT) {
+		dev_dbg(dev, "phydev->link %d, count %d\n",
+					phydev->link, priv->count);
+		if ((phydev->link) || (priv->count == 5)) {
+			ret = en8801s_phase2_init(phydev);
+			if (ret != 0) {
+				dev_info(dev, "en8801_phase2_init failed\n");
+				phydev->dev_flags = PHY_STATE_FAIL;
+				return 0;
+			}
+			phydev->dev_flags = PHY_STATE_PROCESS;
+		}
+		priv->count++;
+	}
+
+	if ((preSpeed != phydev->speed) && (phydev->link == LINK_UP)) {
+		preSpeed = phydev->speed;
+
+		if (preSpeed == SPEED_10) {
+			reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1694);
+			reg_value |= BIT(31);
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x1694,
+					reg_value);
+			if (ret < 0)
+				return ret;
+			phydev->dev_flags = PHY_STATE_PROCESS;
+		} else {
+			reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1694);
+			reg_value &= ~BIT(31);
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x1694,
+					reg_value);
+			if (ret < 0)
+				return ret;
+			phydev->dev_flags = PHY_STATE_PROCESS;
+		}
+
+		airoha_pbus_write(mbus, pbus_addr, 0x0600,
+				0x0c000c00);
+		if (preSpeed == SPEED_1000) {
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x10,
+					0xD801);
+			if (ret < 0)
+				return ret;
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x0,
+					0x9140);
+			if (ret < 0)
+				return ret;
+
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14,
+					0x0003);
+			if (ret < 0)
+				return ret;
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x0600,
+					0x0c000c00);
+			if (ret < 0)
+				return ret;
+			mdelay(2);      /* delay 2 ms */
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x1404,
+					0x004b);
+			if (ret < 0)
+				return ret;
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x140c,
+					0x0007);
+			if (ret < 0)
+				return ret;
+		} else if (preSpeed == SPEED_100) {
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x10,
+					0xD401);
+			if (ret < 0)
+				return ret;
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x0,
+					0x9140);
+			if (ret < 0)
+				return ret;
+
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14,
+					0x0007);
+			if (ret < 0)
+				return ret;
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x0600,
+					0x0c11);
+			if (ret < 0)
+				return ret;
+			mdelay(2);      /* delay 2 ms */
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x1404,
+					0x0027);
+			if (ret < 0)
+				return ret;
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x140c,
+					0x0007);
+			if (ret < 0)
+				return ret;
+		} else if (preSpeed == SPEED_10) {
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x10,
+					0xD001);
+			if (ret < 0)
+				return ret;
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x0,
+					0x9140);
+			if (ret < 0)
+				return ret;
+
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14,
+					0x000b);
+			if (ret < 0)
+				return ret;
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x0600,
+					0x0c11);
+			if (ret < 0)
+				return ret;
+			mdelay(2);      /* delay 2 ms */
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x1404,
+					0x0027);
+			if (ret < 0)
+				return ret;
+			ret = airoha_pbus_write(mbus, pbus_addr, 0x140c,
+					0x0007);
+			if (ret < 0)
+				return ret;
+		}
+	}
+	return ret;
+}
+
+static int en8801s_probe(struct phy_device *phydev)
+{
+	struct en8801s_priv *priv;
+	unsigned long phy_addr = phydev_phy_addr(phydev);
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+	struct device *dev = &mbus->dev;
+#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
+	struct gpio_desc *en8801s_reset;
+	int err = 0;
+#else
+	struct mdio_device *mdiodev = &phydev->mdio;
+#endif
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->count = 0;
+	priv->first_init = true;
+
+#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
+	/* Assert the optional reset signal */
+	en8801s_reset = gpiod_get_optional(&phydev->dev,
+				"reset", GPIOD_OUT_HIGH);
+	err = PTR_ERR_OR_ZERO(en8801s_reset);
+	if (err) {
+		dev_dbg(phydev_dev(phydev),
+				"PHY %lx have no reset pin in device tree.\n",
+				phy_addr);
+	} else {
+		dev_dbg(phydev_dev(phydev),
+				"Assert PHY %lx HWRST until config_init\n",
+				phy_addr);
+		priv->hw_reset = en8801s_reset;
+	}
+
+#else
+	if (mdiodev->reset_gpio) {
+		dev_dbg(phydev_dev(phydev),
+				"Assert PHY %lx HWRST until phy_init_hw\n",
+				phy_addr);
+		phy_device_reset(phydev, 1);
+	}
+#endif
+
+	phydev->priv = priv;
+
+	return 0;
+}
+
+#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
+static int airoha_mmd_read(struct phy_device *phydev,
+			int devad, u16 reg)
+{
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+	int phy_addr = phydev_phy_addr(phydev);
+	int ret = 0;
+	u16 cl45_value;
+
+	ret = __airoha_cl45_read(mbus, phy_addr, devad, reg, &cl45_value);
+	if (ret < 0)
+		return ret;
+
+	return cl45_value;
+}
+
+static int airoha_mmd_write(struct phy_device *phydev,
+			int devad, u16 reg, u16 val)
+{
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+	int phy_addr = phydev_phy_addr(phydev);
+	int pbus_addr = phydev_pbus_addr(phydev);
+	unsigned long pbus_data;
+	int ret = 0;
+
+	if (MDIO_MMD_AN == devad && MDIO_AN_EEE_ADV == reg) {
+		if (val == 0) {
+			pbus_data = __airoha_pbus_read(mbus, pbus_addr, 0x1960);
+			if (0xA == ((pbus_data & 0x07c00000) >> 22)) {
+				pbus_data = (pbus_data & 0xf83fffff) |
+							(0xC << 22);
+				__airoha_pbus_write(mbus, pbus_addr, 0x1960,
+							pbus_data);
+				mdelay(10);
+				pbus_data = (pbus_data & 0xf83fffff) |
+							(0xE << 22);
+				__airoha_pbus_write(mbus, pbus_addr, 0x1960,
+							pbus_data);
+				mdelay(10);
+			}
+		} else {
+			pbus_data = __airoha_pbus_read(mbus, pbus_addr, 0x1960);
+			if (0xE == ((pbus_data & 0x07c00000) >> 22)) {
+				pbus_data = (pbus_data & 0xf83fffff) |
+							(0xC << 22);
+				__airoha_pbus_write(mbus, pbus_addr, 0x1960,
+							pbus_data);
+				mdelay(10);
+				pbus_data = (pbus_data & 0xf83fffff) |
+							(0xA << 22);
+				__airoha_pbus_write(mbus, pbus_addr, 0x1960,
+							pbus_data);
+				mdelay(10);
+			}
+		}
+	}
+
+	ret = __airoha_cl45_write(mbus, phy_addr, devad, reg, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+#endif
+
+static struct phy_driver Airoha_driver[] = {
+	{
+		.phy_id         = EN8801SC_PHY_ID,
+		.name           = "Airoha EN8801SC",
+		.phy_id_mask    = 0x0ffffff0,
+		.features       = PHY_GBIT_FEATURES,
+		.probe          = en8801s_probe,
+		.config_init    = en8801s_phase1_init,
+		.config_aneg    = genphy_config_aneg,
+		.read_status    = en8801s_read_status,
+		.suspend        = genphy_suspend,
+		.resume         = genphy_resume,
+#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
+		.read_mmd       = airoha_mmd_read,
+		.write_mmd      = airoha_mmd_write,
+#endif
+	}
+};
+
+module_phy_driver(Airoha_driver);
+
+static struct mdio_device_id __maybe_unused Airoha_tbl[] = {
+	{ EN8801SC_PHY_ID, 0x0ffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, Airoha_tbl);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.h b/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.h
new file mode 100644
index 0000000..0a077c3
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.h
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0
+/* FILE NAME:  en8801sc.h
+ * PURPOSE:
+ *      Define EN8801SC driver function
+ *
+ * NOTES:
+ *
+ */
+
+#ifndef __EN8801SC_H
+#define __EN8801SC_H
+
+/* NAMING DECLARATIONS
+ */
+#define EN8801S_DRIVER_VERSION  "1.1.7_Generic"
+#define EN8801S_PBUS_DEFAULT_ID 0x1e
+#define EN8801S_RG_ETHER_PHY_OUI 0x19a4
+#define EN8801S_RG_SMI_ADDR      0x19a8
+#define EN8801S_RG_BUCK_CTL      0x1a20
+#define EN8801S_RG_LTR_CTL       0x0cf8
+
+#define EN8801S_PBUS_OUI        0x17a5
+#define EN8801S_PHY_ID1         0x03a2
+#define EN8801S_PHY_ID2         0x9461
+#define EN8801SC_PHY_ID         0x03a29471
+
+#define LED_ON_CTRL(i)              (0x024 + ((i)*2))
+#define LED_ON_EN                   (1 << 15)
+#define LED_ON_POL                  (1 << 14)
+#define LED_ON_EVT_MASK             (0x7f)
+/* LED ON Event Option.B */
+#define LED_ON_EVT_FORCE            (1 << 6)
+#define LED_ON_EVT_LINK_DOWN        (1 << 3)
+#define LED_ON_EVT_LINK_10M         (1 << 2)
+#define LED_ON_EVT_LINK_100M        (1 << 1)
+#define LED_ON_EVT_LINK_1000M       (1 << 0)
+/* LED ON Event Option.E */
+
+#define LED_BLK_CTRL(i)             (0x025 + ((i)*2))
+#define LED_BLK_EVT_MASK            (0x3ff)
+/* LED Blinking Event Option.B*/
+#define LED_BLK_EVT_FORCE           (1 << 9)
+#define LED_BLK_EVT_10M_RX_ACT      (1 << 5)
+#define LED_BLK_EVT_10M_TX_ACT      (1 << 4)
+#define LED_BLK_EVT_100M_RX_ACT     (1 << 3)
+#define LED_BLK_EVT_100M_TX_ACT     (1 << 2)
+#define LED_BLK_EVT_1000M_RX_ACT    (1 << 1)
+#define LED_BLK_EVT_1000M_TX_ACT    (1 << 0)
+/* LED Blinking Event Option.E*/
+#define LED_ENABLE                  1
+#define LED_DISABLE                 0
+
+#define LINK_UP                 1
+#define LINK_DOWN               0
+
+/*
+SFP Sample for verification
+Tx Reverse, Rx Reverse
+*/
+#define EN8801S_TX_POLARITY_NORMAL   0x0
+#define EN8801S_TX_POLARITY_REVERSE  0x1
+
+#define EN8801S_RX_POLARITY_NORMAL   (0x1 << 1)
+#define EN8801S_RX_POLARITY_REVERSE  (0x0 << 1)
+
+/*
+The following led_cfg example is for reference only.
+LED5 1000M/LINK/ACT  (GPIO5)  <-> BASE_T_LED0,
+LED6 10/100M/LINK/ACT(GPIO9)  <-> BASE_T_LED1,
+LED4 100M/LINK/ACT   (GPIO8)  <-> BASE_T_LED2,
+*/
+/* User-defined.B */
+#define BASE_T_LED0_ON_CFG      (LED_ON_EVT_LINK_1000M)
+#define BASE_T_LED0_BLK_CFG \
+			(LED_BLK_EVT_1000M_TX_ACT | \
+			LED_BLK_EVT_1000M_RX_ACT)
+#define BASE_T_LED1_ON_CFG \
+			(LED_ON_EVT_LINK_100M | \
+			 LED_ON_EVT_LINK_10M)
+#define BASE_T_LED1_BLK_CFG \
+			(LED_BLK_EVT_100M_TX_ACT | \
+			 LED_BLK_EVT_100M_RX_ACT | \
+			 LED_BLK_EVT_10M_TX_ACT | \
+			 LED_BLK_EVT_10M_RX_ACT)
+#define BASE_T_LED2_ON_CFG \
+			(LED_ON_EVT_LINK_100M)
+#define BASE_T_LED2_BLK_CFG \
+			(LED_BLK_EVT_100M_TX_ACT | \
+			 LED_BLK_EVT_100M_RX_ACT)
+#define BASE_T_LED3_ON_CFG      (0x0)
+#define BASE_T_LED3_BLK_CFG     (0x0)
+/* User-defined.E */
+
+#define EN8801S_LED_COUNT       4
+
+#define MAX_RETRY               5
+#define MAX_OUI_CHECK           2
+/* CL45 MDIO control */
+#define MII_MMD_ACC_CTL_REG     0x0d
+#define MII_MMD_ADDR_DATA_REG   0x0e
+#define MMD_OP_MODE_DATA        BIT(14)
+
+#define MAX_TRG_COUNTER         5
+
+/* CL22 Reg Support Page Select */
+#define RgAddr_Reg1Fh        0x1f
+#define CL22_Page_Reg        0x0000
+#define CL22_Page_ExtReg     0x0001
+#define CL22_Page_MiscReg    0x0002
+#define CL22_Page_LpiReg     0x0003
+#define CL22_Page_tReg       0x02A3
+#define CL22_Page_TrReg      0x52B5
+
+/* CL45 Reg Support DEVID */
+#define DEVID_03             0x03
+#define DEVID_07             0x07
+#define DEVID_1E             0x1E
+#define DEVID_1F             0x1F
+
+/* TokenRing Reg Access */
+#define TrReg_PKT_XMT_STA    0x8000
+#define TrReg_WR             0x8000
+#define TrReg_RD             0xA000
+
+#define RgAddr_LPI_1Ch       0x1c
+#define RgAddr_AUXILIARY_1Dh 0x1d
+#define RgAddr_PMA_00h       0x0f80
+#define RgAddr_PMA_01h       0x0f82
+#define RgAddr_PMA_17h       0x0fae
+#define RgAddr_PMA_18h       0x0fb0
+#define RgAddr_DSPF_03h      0x1686
+#define RgAddr_DSPF_06h      0x168c
+#define RgAddr_DSPF_08h      0x1690
+#define RgAddr_DSPF_0Ch      0x1698
+#define RgAddr_DSPF_0Dh      0x169a
+#define RgAddr_DSPF_0Fh      0x169e
+#define RgAddr_DSPF_10h      0x16a0
+#define RgAddr_DSPF_11h      0x16a2
+#define RgAddr_DSPF_13h      0x16a6
+#define RgAddr_DSPF_14h      0x16a8
+#define RgAddr_DSPF_1Bh      0x16b6
+#define RgAddr_DSPF_1Ch      0x16b8
+#define RgAddr_TR_26h        0x0ecc
+#define RgAddr_R1000DEC_15h  0x03aa
+#define RgAddr_R1000DEC_17h  0x03ae
+
+#define LED_BCR                     (0x021)
+#define LED_BCR_EXT_CTRL            (1 << 15)
+#define LED_BCR_CLK_EN              (1 << 3)
+#define LED_BCR_TIME_TEST           (1 << 2)
+#define LED_BCR_MODE_MASK           (3)
+#define LED_BCR_MODE_DISABLE        (0)
+
+#define LED_ON_DUR                  (0x022)
+#define LED_ON_DUR_MASK             (0xffff)
+
+#define LED_BLK_DUR                 (0x023)
+#define LED_BLK_DUR_MASK            (0xffff)
+
+#define LED_GPIO_SEL_MASK 0x7FFFFFF
+
+#define UNIT_LED_BLINK_DURATION     1024
+
+/* Invalid data */
+#define INVALID_DATA            0xffffffff
+
+#define LED_SET_EVT(reg, cod, result, bit) do         \
+	{                                                 \
+		if (reg & cod) {                              \
+			result |= bit;                            \
+		}                                             \
+	} while (0)
+
+#define LED_SET_GPIO_SEL(gpio, led, val)             \
+			(val |= (led << (8 * (gpio % 4))))       \
+
+
+/* DATA TYPE DECLARATIONS
+ */
+struct AIR_BASE_T_LED_CFG_S {
+	u16 en;
+	u16 gpio;
+	u16 pol;
+	u16 on_cfg;
+	u16 blk_cfg;
+};
+
+union gephy_all_REG_LpiReg1Ch {
+	struct {
+		/* b[15:00] */
+		u16 smi_deton_wt                             : 3;
+		u16 smi_det_mdi_inv                          : 1;
+		u16 smi_detoff_wt                            : 3;
+		u16 smi_sigdet_debouncing_en                 : 1;
+		u16 smi_deton_th                             : 6;
+		u16 rsv_14                                   : 2;
+	} DataBitField;
+	u16 DATA;
+};
+
+union gephy_all_REG_dev1Eh_reg324h {
+	struct {
+		/* b[15:00] */
+		u16 rg_smi_detcnt_max                        : 6;
+		u16 rsv_6                                    : 2;
+		u16 rg_smi_det_max_en                        : 1;
+		u16 smi_det_deglitch_off                     : 1;
+		u16 rsv_10                                   : 6;
+	} DataBitField;
+	u16 DATA;
+};
+
+union gephy_all_REG_dev1Eh_reg012h {
+	struct {
+		/* b[15:00] */
+		u16 da_tx_i2mpb_a_tbt                        : 6;
+		u16 rsv_6                                    : 4;
+		u16 da_tx_i2mpb_a_gbe                        : 6;
+	} DataBitField;
+	u16 DATA;
+};
+
+union gephy_all_REG_dev1Eh_reg017h {
+	struct {
+		/* b[15:00] */
+		u16 da_tx_i2mpb_b_tbt                        : 6;
+		u16 rsv_6                                    : 2;
+		u16 da_tx_i2mpb_b_gbe                        : 6;
+		u16 rsv_14                                   : 2;
+	} DataBitField;
+	u16 DATA;
+};
+
+enum {
+	AIR_LED_BLK_DUR_32M,
+	AIR_LED_BLK_DUR_64M,
+	AIR_LED_BLK_DUR_128M,
+	AIR_LED_BLK_DUR_256M,
+	AIR_LED_BLK_DUR_512M,
+	AIR_LED_BLK_DUR_1024M,
+	AIR_LED_BLK_DUR_LAST
+};
+
+enum {
+	AIR_ACTIVE_LOW,
+	AIR_ACTIVE_HIGH,
+};
+
+enum {
+	AIR_LED_MODE_DISABLE,
+	AIR_LED_MODE_USER_DEFINE,
+	AIR_LED_MODE_LAST
+};
+
+#endif /* End of __EN8801SC_H */
diff --git a/target/linux/mediatek/patches-5.4/745-en8801sc-gphy-support.patch b/target/linux/mediatek/patches-5.4/745-en8801sc-gphy-support.patch
index b50a7bb..6de04c3 100644
--- a/target/linux/mediatek/patches-5.4/745-en8801sc-gphy-support.patch
+++ b/target/linux/mediatek/patches-5.4/745-en8801sc-gphy-support.patch
@@ -1,1021 +1,3 @@
-Index: drivers/net/phy/en8801sc.c
-===================================================================
---- /dev/null
-+++ b/drivers/net/phy/en8801sc.c
-@@ -0,0 +1,732 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* FILE NAME:  en8801sc.c
-+ * PURPOSE:
-+ *      EN8801SC phy driver for Linux
-+ * NOTES:
-+ *
-+ */
-+
-+/* INCLUDE FILE DECLARATIONS
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/errno.h>
-+#include <linux/unistd.h>
-+#include <linux/interrupt.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/spinlock.h>
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/mii.h>
-+#include <linux/ethtool.h>
-+#include <linux/phy.h>
-+#include <linux/delay.h>
-+
-+#include <linux/uaccess.h>
-+#include <linux/version.h>
-+
-+#include "en8801sc.h"
-+
-+MODULE_DESCRIPTION("Airoha EN8801S PHY drivers for MediaTek SoC");
-+MODULE_AUTHOR("Airoha");
-+MODULE_LICENSE("GPL");
-+
-+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0))
-+#define phydev_mdio_bus(dev) ((dev)->bus)
-+#else
-+#define phydev_mdio_bus(dev) ((dev)->mdio.bus)
-+#endif
-+
-+enum {
-+    PHY_STATE_DONE = 0,
-+    PHY_STATE_INIT = 1,
-+    PHY_STATE_PROCESS = 2,
-+    PHY_STATE_SS_FAIL = 3,
-+    PHY_STATE_FAIL = 4
-+};
-+
-+/*
-+The following led_cfg example is for reference only.
-+LED5 1000M/LINK/ACT   (GPIO5)  <-> BASE_T_LED0,
-+LED6 10/100M/LINK/ACT (GPIO9)  <-> BASE_T_LED1,
-+LED4 100M/LINK/ACT    (GPIO8)  <-> BASE_T_LED2,
-+*/
-+/* User-defined.B */
-+#define AIR_LED_SUPPORT
-+#ifdef AIR_LED_SUPPORT
-+static const AIR_BASE_T_LED_CFG_T led_cfg[4] =
-+{
-+    /*
-+     *    LED Enable,     GPIO,       LED Polarity,            LED ON,               LED Blink
-+     */
-+         {LED_ENABLE,       5,       AIR_ACTIVE_LOW,      BASE_T_LED0_ON_CFG,    BASE_T_LED0_BLK_CFG}, /* BASE-T LED0 */
-+         {LED_ENABLE,       9,       AIR_ACTIVE_LOW,      BASE_T_LED1_ON_CFG,    BASE_T_LED1_BLK_CFG}, /* BASE-T LED1 */
-+         {LED_ENABLE,       8,       AIR_ACTIVE_LOW,      BASE_T_LED2_ON_CFG,    BASE_T_LED2_BLK_CFG}, /* BASE-T LED2 */
-+         {LED_DISABLE,      1,       AIR_ACTIVE_LOW,      BASE_T_LED3_ON_CFG,    BASE_T_LED3_BLK_CFG}  /* BASE-T LED3 */
-+};
-+static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
-+#endif
-+/* User-defined.E */
-+
-+/************************************************************************
-+*                  F U N C T I O N S
-+************************************************************************/
-+static int airoha_cl45_write(struct mii_bus *bus, u32 port, u32 devad, u32 reg, u16 val)
-+{
-+    int ret = 0;
-+    struct device *dev = &bus->dev;
-+
-+    ret = mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad);
-+    AIR_RTN_ON_ERR_MSG(ret < 0, ret, "%s fail. (ret=%d)\n", __func__, ret);
-+    ret = mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg);
-+    AIR_RTN_ON_ERR_MSG(ret < 0, ret, "%s fail. (ret=%d)\n", __func__, ret);
-+    ret = mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-+    AIR_RTN_ON_ERR_MSG(ret < 0, ret, "%s fail. (ret=%d)\n", __func__, ret);
-+    ret = mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, val);
-+    AIR_RTN_ON_ERR_MSG(ret < 0, ret, "%s fail. (ret=%d)\n", __func__, ret);
-+    return ret;
-+}
-+
-+static int airoha_cl45_read(struct mii_bus *bus, u32 port, u32 devad, u32 reg, u16 *read_data)
-+{
-+    int ret = 0;
-+    struct device *dev = &bus->dev;
-+
-+    ret = mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad);
-+    AIR_RTN_ON_ERR_MSG(ret < 0, ret, "%s fail. (ret=%d)\n", __func__, ret);
-+    ret = mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg);
-+    AIR_RTN_ON_ERR_MSG(ret < 0, ret, "%s fail. (ret=%d)\n", __func__, ret);
-+    ret = mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-+    AIR_RTN_ON_ERR_MSG(ret < 0, ret, "%s fail. (ret=%d)\n", __func__, ret);
-+    *read_data = mdiobus_read(bus, port, MII_MMD_ADDR_DATA_REG);
-+    return 0;
-+}
-+
-+static unsigned int airoha_cl22_read(struct mii_bus *ebus, unsigned int phy_addr, unsigned int phy_register, unsigned int *read_data)
-+{
-+    *read_data = mdiobus_read(ebus, phy_addr, phy_register);
-+    return 0;
-+}
-+
-+static int airoha_cl22_write(struct mii_bus *ebus, unsigned int phy_addr, unsigned int phy_register, unsigned int write_data)
-+{
-+    int ret = 0;
-+    struct device *dev = &ebus->dev;
-+
-+    ret = mdiobus_write(ebus, phy_addr, phy_register, write_data);
-+    AIR_RTN_ON_ERR_MSG(ret < 0, ret, "%s fail. (ret=%d)\n", __func__, ret);
-+    return ret;
-+}
-+
-+static int airoha_pbus_write(struct mii_bus *ebus, unsigned long pbus_id, unsigned long pbus_address, unsigned long pbus_data)
-+{
-+    int ret = 0;
-+
-+    ret = airoha_cl22_write(ebus, pbus_id, 0x1F, (unsigned int)(pbus_address >> 6));
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl22_write(ebus, pbus_id, (unsigned int)((pbus_address >> 2) & 0xf), (unsigned int)(pbus_data & 0xFFFF));
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl22_write(ebus, pbus_id, 0x10, (unsigned int)(pbus_data >> 16));
-+    AIR_RTN_ERR(ret);
-+    return ret;
-+}
-+
-+static unsigned long airoha_pbus_read(struct mii_bus *ebus, unsigned long pbus_id, unsigned long pbus_address)
-+{
-+    unsigned long pbus_data;
-+    unsigned int pbus_data_low, pbus_data_high;
-+    int ret = 0;
-+    struct device *dev = &ebus->dev;
-+    ret = airoha_cl22_write(ebus, pbus_id, 0x1F, (unsigned int)(pbus_address >> 6));
-+    if ( ret < 0) {
-+        AIR_RTN_ON_ERR_MSG(ret < 0, ret, "%s fail. (ret=%d)\n", __func__, ret);
-+        return INVALID_DATA;
-+    }
-+    airoha_cl22_read(ebus, pbus_id, (unsigned int)((pbus_address >> 2) & 0xf), &pbus_data_low);
-+    airoha_cl22_read(ebus, pbus_id, 0x10, &pbus_data_high);
-+    pbus_data = (pbus_data_high << 16) + pbus_data_low;
-+    return pbus_data;
-+}
-+
-+/* Airoha Token Ring Write function */
-+static int airoha_tr_reg_write(struct mii_bus *ebus, unsigned long tr_address, unsigned long tr_data)
-+{
-+    int ret = 0;
-+    ret = airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x52b5);       /* page select */
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x11, (unsigned int)(tr_data & 0xffff));
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x12, (unsigned int)(tr_data >> 16));
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x10, (unsigned int)(tr_address | TrReg_WR));
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x0);          /* page resetore */
-+    AIR_RTN_ERR(ret);
-+    return ret;
-+}
-+
-+#if 0
-+/* Airoha Token Ring Read function */
-+static unsigned long airoha_tr_reg_read(struct mii_bus *ebus, unsigned long tr_address)
-+{
-+    unsigned long tr_data;
-+    unsigned int tr_data_low, tr_data_high;
-+
-+    airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x52b5);       /* page select */
-+    airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x10, (unsigned int)(tr_address | TrReg_RD));
-+    airoha_cl22_read(ebus, EN8801S_MDIO_PHY_ID, 0x11, &tr_data_low);
-+    airoha_cl22_read(ebus, EN8801S_MDIO_PHY_ID, 0x12, &tr_data_high);
-+    airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x0);          /* page resetore */
-+    tr_data = (tr_data_high << 16) + tr_data_low;
-+    return tr_data;
-+}
-+#endif
-+#ifdef AIR_LED_SUPPORT
-+static int airoha_led_set_usr_def(struct mii_bus *mbus, u8 entity, int polar,
-+                                   u16 on_evt, u16 blk_evt)
-+{
-+    int ret = 0;
-+    if (AIR_ACTIVE_HIGH == polar) {
-+        on_evt |= LED_ON_POL;
-+    } else {
-+        on_evt &= ~LED_ON_POL;
-+    }
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, LED_ON_CTRL(entity), on_evt | LED_ON_EN);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, LED_BLK_CTRL(entity), blk_evt);
-+    AIR_RTN_ERR(ret);
-+    return 0;
-+}
-+
-+static int airoha_led_set_mode(struct mii_bus *mbus, u8 mode)
-+{
-+    u16 cl45_data;
-+    int err = 0;
-+
-+    err = airoha_cl45_read(mbus, EN8801S_MDIO_PHY_ID, 0x1f, LED_BCR, &cl45_data);
-+    AIR_RTN_ERR(err);
-+
-+    switch (mode) {
-+    case AIR_LED_MODE_DISABLE:
-+        cl45_data &= ~LED_BCR_EXT_CTRL;
-+        cl45_data &= ~LED_BCR_MODE_MASK;
-+        cl45_data |= LED_BCR_MODE_DISABLE;
-+        break;
-+    case AIR_LED_MODE_USER_DEFINE:
-+        cl45_data |= LED_BCR_EXT_CTRL;
-+        cl45_data |= LED_BCR_CLK_EN;
-+        break;
-+    default:
-+        return -EINVAL;
-+    }
-+
-+    err = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, LED_BCR, cl45_data);
-+    AIR_RTN_ERR(err);
-+    return 0;
-+}
-+
-+static int airoha_led_set_state(struct mii_bus *mbus, u8 entity, u8 state)
-+{
-+    u16 cl45_data;
-+    int err;
-+
-+    err = airoha_cl45_read(mbus, EN8801S_MDIO_PHY_ID, 0x1f, LED_ON_CTRL(entity), &cl45_data);
-+    AIR_RTN_ERR(err);
-+    if (LED_ENABLE == state) {
-+        cl45_data |= LED_ON_EN;
-+    } else {
-+        cl45_data &= ~LED_ON_EN;
-+    }
-+
-+    err = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, LED_ON_CTRL(entity), cl45_data);
-+    AIR_RTN_ERR(err);
-+    return 0;
-+}
-+
-+static int en8801s_led_init(struct phy_device *phydev)
-+{
-+
-+    unsigned long led_gpio = 0, reg_value = 0;
-+    int ret = 0, led_id;
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+    int gpio_led_rg[3] = {0x1870, 0x1874, 0x1878};
-+    u16 cl45_data = led_dur;
-+    struct device *dev = &mbus->dev;
-+
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, LED_BLK_DUR, cl45_data);
-+    AIR_RTN_ERR(ret);
-+    cl45_data >>= 1;
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, LED_ON_DUR, cl45_data);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_led_set_mode(mbus, AIR_LED_MODE_USER_DEFINE);
-+    if (ret != 0) {
-+        dev_err(dev, "LED fail to set mode, ret %d !\n", ret);
-+        return ret;
-+    }
-+    for(led_id = 0; led_id < EN8801S_LED_COUNT; led_id++)
-+    {
-+        reg_value = 0;
-+        ret = airoha_led_set_state(mbus, led_id, led_cfg[led_id].en);
-+        if (ret != 0)
-+        {
-+            dev_err(dev, "LED fail to set state, ret %d !\n", ret);
-+            return ret;
-+        }
-+        if (LED_ENABLE == led_cfg[led_id].en)
-+        {
-+            if ( (led_cfg[led_id].gpio < 0) || led_cfg[led_id].gpio > 9)
-+            {
-+                dev_err(dev, "GPIO%d is out of range!! GPIO number is 0~9.\n", led_cfg[led_id].gpio);
-+                return -EIO;
-+            }
-+            led_gpio |= BIT(led_cfg[led_id].gpio);
-+            reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, gpio_led_rg[led_cfg[led_id].gpio / 4]);
-+            LED_SET_GPIO_SEL(led_cfg[led_id].gpio, led_id, reg_value);
-+            dev_dbg(dev, "[Airoha] gpio%d, reg_value 0x%lx\n", led_cfg[led_id].gpio, reg_value);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, gpio_led_rg[led_cfg[led_id].gpio / 4], reg_value);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_led_set_usr_def(mbus, led_id, led_cfg[led_id].pol, led_cfg[led_id].on_cfg, led_cfg[led_id].blk_cfg);
-+            if (ret != 0)
-+            {
-+                dev_err(dev, "LED fail to set usr def, ret %d !\n", ret);
-+                return ret;
-+            }
-+        }
-+    }
-+    reg_value = (airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1880) & ~led_gpio);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1880, reg_value);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x186c, led_gpio);
-+    AIR_RTN_ERR(ret);
-+
-+    dev_info(dev, "LED initialize OK !\n");
-+    return 0;
-+}
-+#endif
-+static int en8801s_phy_process(struct phy_device *phydev)
-+{
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+    unsigned long reg_value = 0;
-+    int ret = 0;
-+
-+    reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x19e0);
-+    reg_value |= BIT(0);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x19e0, reg_value);
-+    AIR_RTN_ERR(ret);
-+    reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x19e0);
-+    reg_value &= ~BIT(0);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x19e0, reg_value);
-+    AIR_RTN_ERR(ret);
-+    return ret;
-+}
-+
-+static int en8801s_phase1_init(struct phy_device *phydev)
-+{
-+    unsigned long pbus_data;
-+    unsigned int pbusAddress;
-+    u16 reg_value;
-+    int retry, ret = 0;
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+    struct device *dev = &mbus->dev;
-+    msleep(1500);
-+
-+    pbusAddress = EN8801S_PBUS_DEFAULT_ID;
-+    retry = MAX_OUI_CHECK;
-+    while (1) {
-+        pbus_data = airoha_pbus_read(mbus, pbusAddress, EN8801S_RG_ETHER_PHY_OUI);      /* PHY OUI */
-+        if (EN8801S_PBUS_OUI == pbus_data) {
-+            pbus_data = airoha_pbus_read(mbus, pbusAddress, EN8801S_RG_SMI_ADDR);       /* SMI ADDR */
-+            pbus_data = (pbus_data & 0xffff0000) | (unsigned long)(EN8801S_PBUS_PHY_ID << 8) | (unsigned long)(EN8801S_MDIO_PHY_ID);
-+            dev_info(dev, "SMI_ADDR=%lx (renew)\n", pbus_data);
-+            ret = airoha_pbus_write(mbus, pbusAddress, EN8801S_RG_SMI_ADDR, pbus_data);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_BUCK_CTL, 0x03);
-+            AIR_RTN_ERR(ret);
-+            mdelay(10);
-+            break;
-+        } else {
-+            pbusAddress = EN8801S_PBUS_PHY_ID;
-+        }
-+        if (0 == --retry) {
-+            dev_err(dev, "Probe fail !\n");
-+            return 0;
-+        }
-+    }
-+
-+    pbus_data = (airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL) & 0xfffffffc) | 0x10 | (EN8801S_RX_POLARITY << 1) | EN8801S_TX_POLARITY;
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL, pbus_data);
-+    AIR_RTN_ERR(ret);
-+    mdelay(10);
-+    pbus_data &= ~BIT(4);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL, pbus_data);
-+    AIR_RTN_ERR(ret);
-+
-+    retry = MAX_RETRY;
-+    while (1) {
-+        mdelay(10);
-+        reg_value = phy_read(phydev, MII_PHYSID2);
-+        if (reg_value == EN8801S_PHY_ID2) {
-+            break;    /* wait GPHY ready */
-+        }
-+        retry--;
-+        if (0 == retry) {
-+            dev_err(dev, "Initialize fail !\n");
-+            return 0;
-+        }
-+    }
-+    /* Software Reset PHY */
-+    reg_value = phy_read(phydev, MII_BMCR);
-+    reg_value |= BMCR_RESET;
-+    ret = phy_write(phydev, MII_BMCR, reg_value);
-+    AIR_RTN_ERR(ret);
-+    retry = MAX_RETRY;
-+    do {
-+        mdelay(10);
-+        reg_value = phy_read(phydev, MII_BMCR);
-+        retry--;
-+        if (0 == retry) {
-+            dev_err(dev, "Reset fail !\n");
-+            return 0;
-+        }
-+    } while (reg_value & BMCR_RESET);
-+
-+    phydev->dev_flags = PHY_STATE_INIT;
-+
-+    dev_info(dev, "Phase1 initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION);
-+    return 0;
-+}
-+
-+static int en8801s_phase2_init(struct phy_device *phydev)
-+{
-+    gephy_all_REG_LpiReg1Ch      GPHY_RG_LPI_1C;
-+    gephy_all_REG_dev1Eh_reg324h GPHY_RG_1E_324;
-+    gephy_all_REG_dev1Eh_reg012h GPHY_RG_1E_012;
-+    gephy_all_REG_dev1Eh_reg017h GPHY_RG_1E_017;
-+    unsigned long pbus_data;
-+    u16 cl45_value;
-+    int retry, ret = 0;
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+    struct device *dev = &mbus->dev;
-+
-+    pbus_data = (airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL) & 0xfffffffc) | 0x10 | (EN8801S_RX_POLARITY << 1) | EN8801S_TX_POLARITY;
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL, pbus_data);
-+    AIR_RTN_ERR(ret);
-+    mdelay(10);
-+    pbus_data &= 0xffffffef;
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL, pbus_data);
-+    AIR_RTN_ERR(ret);
-+
-+    pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1690);
-+    pbus_data |= BIT(31);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1690, pbus_data);
-+    AIR_RTN_ERR(ret);
-+
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c000c00);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x10, 0xD801);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0,  0x9140);
-+    AIR_RTN_ERR(ret);
-+
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0A14, 0x0003);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c000c00);
-+    AIR_RTN_ERR(ret);
-+    /* Set FCM control */
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1404, 0x004b);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x140c, 0x0007);
-+    AIR_RTN_ERR(ret);
-+
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x142c, 0x05050505);
-+    AIR_RTN_ERR(ret);
-+    pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1440);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1440, pbus_data & ~BIT(11));
-+    AIR_RTN_ERR(ret);
-+
-+    pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1408);
-+    ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1408, pbus_data | BIT(5));
-+    AIR_RTN_ERR(ret);
-+
-+    /* Set GPHY Perfomance*/
-+    /* Token Ring */
-+    ret = airoha_tr_reg_write(mbus, RgAddr_R1000DEC_15h, 0x0055A0);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_R1000DEC_17h, 0x07FF3F);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_PMA_00h,      0x00001E);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_PMA_01h,      0x6FB90A);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_PMA_17h,      0x060671);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_PMA_18h,      0x0E2F00);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_TR_26h,       0x444444);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_03h,     0x000000);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_06h,     0x2EBAEF);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_08h,     0x00000B);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_0Ch,     0x00504D);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_0Dh,     0x02314F);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_0Fh,     0x003028);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_10h,     0x005010);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_11h,     0x040001);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_13h,     0x018670);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_14h,     0x00024A);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_1Bh,     0x000072);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_tr_reg_write(mbus, RgAddr_DSPF_1Ch,     0x003210);
-+    AIR_RTN_ERR(ret);
-+
-+    /* CL22 & CL45 */
-+    ret = phy_write(phydev, 0x1f, 0x03);
-+    AIR_RTN_ERR(ret);
-+    GPHY_RG_LPI_1C.DATA = phy_read(phydev, RgAddr_LPI_1Ch);
-+    GPHY_RG_LPI_1C.DataBitField.smi_deton_th = 0x0C;
-+    ret = phy_write(phydev, RgAddr_LPI_1Ch, GPHY_RG_LPI_1C.DATA);
-+    AIR_RTN_ERR(ret);
-+    ret = phy_write(phydev, RgAddr_LPI_1Ch, 0xC92);
-+    AIR_RTN_ERR(ret);
-+    ret = phy_write(phydev, RgAddr_AUXILIARY_1Dh, 0x1);
-+    AIR_RTN_ERR(ret);
-+    ret = phy_write(phydev, 0x1f, 0x0);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x120, 0x8014);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x122, 0xffff);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x123, 0xffff);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x144, 0x0200);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x14A, 0xEE20);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x189, 0x0110);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x19B, 0x0111);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x234, 0x0181);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x238, 0x0120);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x239, 0x0117);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x268, 0x07F4);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x2D1, 0x0733);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x323, 0x0011);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, 0x013F);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x326, 0x0037);
-+    AIR_RTN_ERR(ret);
-+
-+    ret = airoha_cl45_read(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, &cl45_value);
-+    AIR_RTN_ERR(ret);
-+    GPHY_RG_1E_324.DATA = cl45_value;
-+    GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = 0;
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, GPHY_RG_1E_324.DATA);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x19E, 0xC2);
-+    AIR_RTN_ERR(ret);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x013, 0x0);
-+    AIR_RTN_ERR(ret);
-+
-+    /* EFUSE */
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1C08, 0x40000040);
-+    retry = MAX_RETRY;
-+    while (0 != retry) {
-+        mdelay(1);
-+        pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1C08);
-+        if ((pbus_data & BIT(30)) == 0) {
-+            break;
-+        }
-+        retry--;
-+    }
-+    pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1C38);          /* RAW#2 */
-+    GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt = (u16)(pbus_data & 0x03f);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x12, GPHY_RG_1E_012.DATA);
-+    AIR_RTN_ERR(ret);
-+    GPHY_RG_1E_017.DataBitField.da_tx_i2mpb_b_tbt = (u16)((pbus_data >> 8) & 0x03f);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x12, GPHY_RG_1E_017.DATA);
-+    AIR_RTN_ERR(ret);
-+
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1C08, 0x40400040);
-+    retry = MAX_RETRY;
-+    while (0 != retry) {
-+        mdelay(1);
-+        pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1C08);
-+        if ((pbus_data & BIT(30)) == 0) {
-+            break;
-+        }
-+        retry--;
-+    }
-+    pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1C30);          /* RAW#16 */
-+    GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = (u16)((pbus_data >> 12) & 0x01);
-+    ret = airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, GPHY_RG_1E_324.DATA);
-+    AIR_RTN_ERR(ret);
-+#ifdef AIR_LED_SUPPORT
-+    ret = en8801s_led_init(phydev);
-+    if (ret != 0){
-+        dev_err(dev, "en8801s_led_init fail (ret:%d) !\n", ret);
-+    }
-+#endif
-+    pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1960);
-+    pbus_data -= (2 << 22);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1960, pbus_data);
-+    mdelay(10);
-+    pbus_data -= (2 << 22);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1960, pbus_data);
-+
-+    dev_info(dev, "Phase2 initialize OK !\n");
-+    return 0;
-+}
-+
-+static int en8801s_read_status(struct phy_device *phydev)
-+{
-+    int ret = 0, preSpeed = phydev->speed, retry = MAX_RETRY;
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+    u32 reg_value;
-+    struct device *dev = &mbus->dev;
-+
-+    ret = genphy_read_status(phydev);
-+    if (LINK_DOWN == phydev->link) preSpeed = phydev->speed = 0;
-+
-+    if (phydev->dev_flags == PHY_STATE_PROCESS) {
-+        en8801s_phy_process(phydev);
-+        phydev->dev_flags = PHY_STATE_DONE;
-+    }
-+
-+    if (phydev->dev_flags == PHY_STATE_INIT) {
-+        do {
-+            mdelay(100);
-+            reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0xb04);
-+            dev_dbg(dev, "[Airoha] 0xB04, reg_value 0x%x\n", reg_value);
-+            reg_value &= 0x21;
-+            if(reg_value == 0x21) {
-+                ret = en8801s_phase2_init(phydev);
-+                if (ret != 0) {
-+                    dev_info(dev, "en8801_phase2_init failed\n");
-+                    phydev->dev_flags = PHY_STATE_FAIL;
-+                    return -1;
-+                } else {
-+                    phydev->dev_flags = PHY_STATE_PROCESS;
-+                    break;
-+                }
-+
-+            }
-+            if(0 == --retry) {
-+                dev_err(dev, "0xB04 return 0x%x !\n", reg_value);
-+                phydev->dev_flags = PHY_STATE_SS_FAIL;
-+                return -1;
-+            }
-+        } while(retry);
-+    }
-+
-+    if ((preSpeed != phydev->speed) && (LINK_UP == phydev->link)) {
-+        preSpeed = phydev->speed;
-+
-+        if (preSpeed == SPEED_10) {
-+            reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1694);
-+            reg_value |= BIT(31);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1694, reg_value);
-+            AIR_RTN_ERR(ret);
-+            phydev->dev_flags = PHY_STATE_PROCESS;
-+        } else {
-+            reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1694);
-+            reg_value &= ~BIT(31);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1694, reg_value);
-+            AIR_RTN_ERR(ret);
-+            phydev->dev_flags = PHY_STATE_PROCESS;
-+        }
-+
-+        airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c000c00);
-+        if (SPEED_1000 == preSpeed) {
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x10, 0xD801);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0,  0x9140);
-+            AIR_RTN_ERR(ret);
-+
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0A14, 0x0003);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c000c00);
-+            AIR_RTN_ERR(ret);
-+            mdelay(2);      /* delay 2 ms */
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1404, 0x004b);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x140c, 0x0007);
-+            AIR_RTN_ERR(ret);
-+        } else if (SPEED_100 == preSpeed) {
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x10, 0xD401);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0,  0x9140);
-+            AIR_RTN_ERR(ret);
-+
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0A14, 0x0007);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c11);
-+            AIR_RTN_ERR(ret);
-+            mdelay(2);      /* delay 2 ms */
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1404, 0x0027);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x140c, 0x0007);
-+            AIR_RTN_ERR(ret);
-+        } else if (SPEED_10 == preSpeed) {
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x10, 0xD001);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0,  0x9140);
-+            AIR_RTN_ERR(ret);
-+
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0A14, 0x000b);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c11);
-+            AIR_RTN_ERR(ret);
-+            mdelay(2);      /* delay 2 ms */
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1404, 0x0027);
-+            AIR_RTN_ERR(ret);
-+            ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x140c, 0x0007);
-+            AIR_RTN_ERR(ret);
-+        }
-+    }
-+    return ret;
-+}
-+
-+static struct phy_driver Airoha_driver[] = {
-+    {
-+        .phy_id         = EN8801SC_PHY_ID,
-+        .name           = "Airoha EN8801SC",
-+        .phy_id_mask    = 0x0ffffff0,
-+        .features       = PHY_GBIT_FEATURES,
-+        .config_init    = en8801s_phase1_init,
-+        .config_aneg    = genphy_config_aneg,
-+        .read_status    = en8801s_read_status,
-+        .suspend        = genphy_suspend,
-+        .resume         = genphy_resume,
-+    }
-+};
-+
-+module_phy_driver(Airoha_driver);
-+
-+static struct mdio_device_id __maybe_unused Airoha_tbl[] = {
-+    { EN8801SC_PHY_ID, 0x0ffffff0 },
-+    { }
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, Airoha_tbl);
-Index: drivers/net/phy/en8801sc.h
-===================================================================
---- /dev/null
-+++ b/drivers/net/phy/en8801sc.h
-@@ -0,0 +1,276 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* FILE NAME:  en8801sc.h
-+ * PURPOSE:
-+ *      Define EN8801SC driver function
-+ *
-+ * NOTES:
-+ *
-+ */
-+
-+#ifndef __EN8801SC_H
-+#define __EN8801SC_H
-+
-+/* NAMING DECLARATIONS
-+ */
-+#define EN8801S_DRIVER_VERSION  "1.1.5"
-+
-+#define PHY_ADDRESS_RANGE       0x18
-+#define EN8801S_PBUS_DEFAULT_ID 0x1e
-+#define EN8801S_MDIO_PHY_ID     0x18       /* Range PHY_ADDRESS_RANGE .. 0x1e */
-+#define EN8801S_PBUS_PHY_ID     (EN8801S_MDIO_PHY_ID + 1)
-+
-+#define EN8801S_RG_ETHER_PHY_OUI 0x19a4
-+#define EN8801S_RG_SMI_ADDR      0x19a8
-+#define EN8801S_RG_BUCK_CTL      0x1a20
-+#define EN8801S_RG_LTR_CTL      0x0cf8
-+
-+#define EN8801S_PBUS_OUI        0x17a5
-+#define EN8801S_PHY_ID1         0x03a2
-+#define EN8801S_PHY_ID2         0x9461
-+#define EN8801SC_PHY_ID         0x03a29471
-+
-+#define LED_ON_CTRL(i)              (0x024 + ((i)*2))
-+#define LED_ON_EN                   (1 << 15)
-+#define LED_ON_POL                  (1 << 14)
-+#define LED_ON_EVT_MASK             (0x7f)
-+/* LED ON Event Option.B */
-+#define LED_ON_EVT_FORCE            (1 << 6)
-+#define LED_ON_EVT_LINK_DOWN        (1 << 3)
-+#define LED_ON_EVT_LINK_10M         (1 << 2)
-+#define LED_ON_EVT_LINK_100M        (1 << 1)
-+#define LED_ON_EVT_LINK_1000M       (1 << 0)
-+/* LED ON Event Option.E */
-+
-+#define LED_BLK_CTRL(i)             (0x025 + ((i)*2))
-+#define LED_BLK_EVT_MASK            (0x3ff)
-+/* LED Blinking Event Option.B*/
-+#define LED_BLK_EVT_FORCE           (1 << 9)
-+#define LED_BLK_EVT_10M_RX_ACT      (1 << 5)
-+#define LED_BLK_EVT_10M_TX_ACT      (1 << 4)
-+#define LED_BLK_EVT_100M_RX_ACT     (1 << 3)
-+#define LED_BLK_EVT_100M_TX_ACT     (1 << 2)
-+#define LED_BLK_EVT_1000M_RX_ACT    (1 << 1)
-+#define LED_BLK_EVT_1000M_TX_ACT    (1 << 0)
-+/* LED Blinking Event Option.E*/
-+#define LED_ENABLE                  1
-+#define LED_DISABLE                 0
-+
-+#define LINK_UP                 1
-+#define LINK_DOWN               0
-+
-+//#define TEST_BOARD
-+#if defined(TEST_BOARD)
-+/* SFP sample for verification */
-+#define EN8801S_TX_POLARITY     1
-+#define EN8801S_RX_POLARITY     0
-+#else
-+/* chip on board */
-+#define EN8801S_TX_POLARITY     0
-+#define EN8801S_RX_POLARITY     1       /* The pin default assignment is set to 1 */
-+#endif
-+
-+/*
-+The following led_cfg example is for reference only.
-+LED5 1000M/LINK/ACT  (GPIO5)  <-> BASE_T_LED0,
-+LED6 10/100M/LINK/ACT(GPIO9)  <-> BASE_T_LED1,
-+LED4 100M/LINK/ACT   (GPIO8)  <-> BASE_T_LED2,
-+*/
-+/* User-defined.B */
-+#define BASE_T_LED0_ON_CFG      (LED_ON_EVT_LINK_1000M)
-+#define BASE_T_LED0_BLK_CFG     (LED_BLK_EVT_1000M_TX_ACT | LED_BLK_EVT_1000M_RX_ACT)
-+#define BASE_T_LED1_ON_CFG      (LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M)
-+#define BASE_T_LED1_BLK_CFG     (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT | \
-+                                 LED_BLK_EVT_10M_TX_ACT | LED_BLK_EVT_10M_RX_ACT )
-+#define BASE_T_LED2_ON_CFG      (LED_ON_EVT_LINK_100M)
-+#define BASE_T_LED2_BLK_CFG     (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT)
-+#define BASE_T_LED3_ON_CFG      (0x0)
-+#define BASE_T_LED3_BLK_CFG     (0x0)
-+/* User-defined.E */
-+
-+#define EN8801S_LED_COUNT       4
-+
-+#define MAX_RETRY               5
-+#define MAX_OUI_CHECK           2
-+/* CL45 MDIO control */
-+#define MII_MMD_ACC_CTL_REG     0x0d
-+#define MII_MMD_ADDR_DATA_REG   0x0e
-+#define MMD_OP_MODE_DATA        BIT(14)
-+
-+#define MAX_TRG_COUNTER         5
-+
-+/* CL22 Reg Support Page Select */
-+#define RgAddr_Reg1Fh        0x1f
-+#define CL22_Page_Reg        0x0000
-+#define CL22_Page_ExtReg     0x0001
-+#define CL22_Page_MiscReg    0x0002
-+#define CL22_Page_LpiReg     0x0003
-+#define CL22_Page_tReg       0x02A3
-+#define CL22_Page_TrReg      0x52B5
-+
-+/* CL45 Reg Support DEVID */
-+#define DEVID_03             0x03
-+#define DEVID_07             0x07
-+#define DEVID_1E             0x1E
-+#define DEVID_1F             0x1F
-+
-+/* TokenRing Reg Access */
-+#define TrReg_PKT_XMT_STA    0x8000
-+#define TrReg_WR             0x8000
-+#define TrReg_RD             0xA000
-+
-+#define RgAddr_LPI_1Ch       0x1c
-+#define RgAddr_AUXILIARY_1Dh 0x1d
-+#define RgAddr_PMA_00h       0x0f80
-+#define RgAddr_PMA_01h       0x0f82
-+#define RgAddr_PMA_17h       0x0fae
-+#define RgAddr_PMA_18h       0x0fb0
-+#define RgAddr_DSPF_03h      0x1686
-+#define RgAddr_DSPF_06h      0x168c
-+#define RgAddr_DSPF_08h      0x1690
-+#define RgAddr_DSPF_0Ch      0x1698
-+#define RgAddr_DSPF_0Dh      0x169a
-+#define RgAddr_DSPF_0Fh      0x169e
-+#define RgAddr_DSPF_10h      0x16a0
-+#define RgAddr_DSPF_11h      0x16a2
-+#define RgAddr_DSPF_13h      0x16a6
-+#define RgAddr_DSPF_14h      0x16a8
-+#define RgAddr_DSPF_1Bh      0x16b6
-+#define RgAddr_DSPF_1Ch      0x16b8
-+#define RgAddr_TR_26h        0x0ecc
-+#define RgAddr_R1000DEC_15h  0x03aa
-+#define RgAddr_R1000DEC_17h  0x03ae
-+
-+#define LED_BCR                     (0x021)
-+#define LED_BCR_EXT_CTRL            (1 << 15)
-+#define LED_BCR_CLK_EN              (1 << 3)
-+#define LED_BCR_TIME_TEST           (1 << 2)
-+#define LED_BCR_MODE_MASK           (3)
-+#define LED_BCR_MODE_DISABLE        (0)
-+
-+#define LED_ON_DUR                  (0x022)
-+#define LED_ON_DUR_MASK             (0xffff)
-+
-+#define LED_BLK_DUR                 (0x023)
-+#define LED_BLK_DUR_MASK            (0xffff)
-+
-+#define LED_GPIO_SEL_MASK 0x7FFFFFF
-+
-+#define UNIT_LED_BLINK_DURATION     1024
-+
-+/* Invalid data */
-+#define INVALID_DATA            0xffffffff
-+
-+#define AIR_RTN_ON_ERR(cond, err)  \
-+    do { if ((cond)) return (err); } while(0)
-+
-+#define AIR_RTN_ERR(err)                       AIR_RTN_ON_ERR(err < 0, err)
-+#define AIR_RTN_ON_ERR_MSG(cond, err, msg...) \
-+    do { if ((cond)) { dev_err(dev, ##msg); return (err); } } while(0)
-+
-+#define LED_SET_EVT(reg, cod, result, bit) do         \
-+    {                                                 \
-+        if(reg & cod) {                               \
-+            result |= bit;                            \
-+        }                                             \
-+    } while(0)
-+
-+#define LED_SET_GPIO_SEL(gpio, led, val) do           \
-+    {                                                 \
-+            val |= (led << (8 * (gpio % 4)));         \
-+    } while(0)
-+
-+/* DATA TYPE DECLARATIONS
-+ */
-+typedef struct AIR_BASE_T_LED_CFG_S
-+{
-+    u16 en;
-+    u16 gpio;
-+    u16 pol;
-+    u16 on_cfg;
-+    u16 blk_cfg;
-+}AIR_BASE_T_LED_CFG_T;
-+
-+typedef struct
-+{
-+    u16 DATA_Lo;
-+    u16 DATA_Hi;
-+}TR_DATA_T;
-+
-+typedef union
-+{
-+    struct
-+    {
-+        /* b[15:00] */
-+        u16 smi_deton_wt                             : 3;
-+        u16 smi_det_mdi_inv                          : 1;
-+        u16 smi_detoff_wt                            : 3;
-+        u16 smi_sigdet_debouncing_en                 : 1;
-+        u16 smi_deton_th                             : 6;
-+        u16 rsv_14                                   : 2;
-+    } DataBitField;
-+    u16 DATA;
-+} gephy_all_REG_LpiReg1Ch, *Pgephy_all_REG_LpiReg1Ch;
-+
-+typedef union
-+{
-+    struct
-+    {
-+        /* b[15:00] */
-+        u16 rg_smi_detcnt_max                        : 6;
-+        u16 rsv_6                                    : 2;
-+        u16 rg_smi_det_max_en                        : 1;
-+        u16 smi_det_deglitch_off                     : 1;
-+        u16 rsv_10                                   : 6;
-+    } DataBitField;
-+    u16 DATA;
-+} gephy_all_REG_dev1Eh_reg324h, *Pgephy_all_REG_dev1Eh_reg324h;
-+
-+typedef union
-+{
-+    struct
-+    {
-+        /* b[15:00] */
-+        u16 da_tx_i2mpb_a_tbt                        : 6;
-+        u16 rsv_6                                    : 4;
-+        u16 da_tx_i2mpb_a_gbe                        : 6;
-+    } DataBitField;
-+    u16 DATA;
-+} gephy_all_REG_dev1Eh_reg012h, *Pgephy_all_REG_dev1Eh_reg012h;
-+
-+typedef union
-+{
-+    struct
-+    {
-+        /* b[15:00] */
-+        u16 da_tx_i2mpb_b_tbt                        : 6;
-+        u16 rsv_6                                    : 2;
-+        u16 da_tx_i2mpb_b_gbe                        : 6;
-+        u16 rsv_14                                   : 2;
-+    } DataBitField;
-+    u16 DATA;
-+} gephy_all_REG_dev1Eh_reg017h, *Pgephy_all_REG_dev1Eh_reg017h;
-+
-+typedef enum
-+{
-+    AIR_LED_BLK_DUR_32M,
-+    AIR_LED_BLK_DUR_64M,
-+    AIR_LED_BLK_DUR_128M,
-+    AIR_LED_BLK_DUR_256M,
-+    AIR_LED_BLK_DUR_512M,
-+    AIR_LED_BLK_DUR_1024M,
-+    AIR_LED_BLK_DUR_LAST
-+} AIR_LED_BLK_DUT_T;
-+
-+typedef enum
-+{
-+    AIR_ACTIVE_LOW,
-+    AIR_ACTIVE_HIGH,
-+} AIR_LED_POLARITY;
-+typedef enum
-+{
-+    AIR_LED_MODE_DISABLE,
-+    AIR_LED_MODE_USER_DEFINE,
-+    AIR_LED_MODE_LAST
-+} AIR_LED_MODE_T;
-+
-+#endif /* End of __EN8801SC_H */
 Index: drivers/net/phy/Kconfig
 ===================================================================
 --- a/drivers/net/phy/Kconfig