[][kernel][common][eth][Add Airoha EN8811H v1.1.3 2.5G PHY driver]

[Description]
Add Airoha EN8811H v1.1.3 2.5G PHY driver.

Please be reminded that EthMD32.dm.bin and EthMD32.DSP.bin firmwares
should be copied to /$ROOTFS/lib/firmware directory.

If without this driver, kernel cannot load corresponding PHY driver
for Airoha EN8811H.

[Release-log]
N/A


Change-Id: Ia09e0ebfd7b3716f56bca8a3b67a88b79a269378
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7038649
diff --git a/target/linux/mediatek/patches-5.4/744-en8801s-gphy-support.patch b/target/linux/mediatek/patches-5.4/744-en8801s-gphy-support.patch
deleted file mode 100644
index ae9fe7f..0000000
--- a/target/linux/mediatek/patches-5.4/744-en8801s-gphy-support.patch
+++ /dev/null
@@ -1,630 +0,0 @@
-Index: drivers/net/phy/Kconfig
-===================================================================
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -345,6 +345,11 @@ config SFP
- 	depends on HWMON || HWMON=n
- 	select MDIO_I2C
- 
-+config AIROHA_EN8801S_PHY
-+	tristate "Drivers for Airoha EN8801S Gigabit PHYs"
-+	---help---
-+	  Currently supports the Airoha EN8801S PHY.
-+
- config ADIN_PHY
- 	tristate "Analog Devices Industrial Ethernet PHYs"
- 	help
-Index: drivers/net/phy/Makefile
-===================================================================
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -67,6 +67,7 @@ aquantia-objs			+= aquantia_main.o
- ifdef CONFIG_HWMON
- aquantia-objs			+= aquantia_hwmon.o
- endif
-+obj-$(CONFIG_AIROHA_EN8801S_PHY)	+= en8801s.o
- obj-$(CONFIG_AQUANTIA_PHY)	+= aquantia.o
- obj-$(CONFIG_AX88796B_PHY)	+= ax88796b.o
- obj-$(CONFIG_AT803X_PHY)	+= at803x.o
-Index: drivers/net/phy/en8801s.c
-===================================================================
---- /dev/null
-+++ b/drivers/net/phy/en8801s.c
-@@ -0,0 +1,434 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* FILE NAME:  en8801s.c
-+ * PURPOSE:
-+ *      EN8801S 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 "en8801s.h"
-+
-+MODULE_DESCRIPTION("Airoha EN8801S PHY drivers");
-+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,
-+};
-+
-+/************************************************************************
-+*                  F U N C T I O N S
-+************************************************************************/
-+static unsigned int airoha_cl45_write(struct mii_bus *bus, u32 port, u32 devad, u32 reg, u16 val)
-+{
-+    mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad);
-+    mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg);
-+    mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-+    mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, val);
-+    return 0;
-+}
-+
-+static unsigned int airoha_cl45_read(struct mii_bus *bus, u32 port, u32 devad, u32 reg, u32 *read_data)
-+{
-+    mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad);
-+    mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg);
-+    mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-+    *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 unsigned int airoha_cl22_write(struct mii_bus *ebus, unsigned int phy_addr, unsigned int phy_register, unsigned int write_data)
-+{
-+    mdiobus_write(ebus, phy_addr, phy_register, write_data);
-+    return 0;
-+}
-+
-+static void airoha_pbus_write(struct mii_bus *ebus, unsigned long pbus_id, unsigned long pbus_address, unsigned long pbus_data)
-+{
-+    airoha_cl22_write(ebus, pbus_id, 0x1F, (unsigned int)(pbus_address >> 6));
-+    airoha_cl22_write(ebus, pbus_id, (unsigned int)((pbus_address >> 2) & 0xf), (unsigned int)(pbus_data & 0xFFFF));
-+    airoha_cl22_write(ebus, pbus_id, 0x10, (unsigned int)(pbus_data >> 16));
-+    return;
-+}
-+
-+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;
-+
-+    airoha_cl22_write(ebus, pbus_id, 0x1F, (unsigned int)(pbus_address >> 6));
-+    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 void airoha_tr_reg_write(struct mii_bus *ebus, unsigned long tr_address, unsigned long tr_data)
-+{
-+    airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x52b5);       /* page select */
-+    airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x11, (unsigned int)(tr_data & 0xffff));
-+    airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x12, (unsigned int)(tr_data >> 16));
-+    airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x10, (unsigned int)(tr_address | TrReg_WR));
-+    airoha_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x0);          /* page resetore */
-+    return;
-+}
-+
-+/* 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;
-+}
-+
-+static void en8801s_led_init(struct phy_device *phydev)
-+{
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+    u32 reg_value;
-+
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x186c, 0x3);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0X1870, 0x100);
-+    reg_value = (airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1880) & ~(0x3));
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1880, reg_value);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, 0x21, 0x8008);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, 0x22, 0x600);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, 0x23, 0xc00);
-+    /* LED0: 10M/100M */
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, 0x24, 0x8006);
-+    /* LED0: blink 10M/100M Tx/Rx */
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, 0x25, 0x3c);
-+    /* LED1: 1000M */
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, 0x26, 0x8001);
-+    /* LED1: blink 1000M Tx/Rx */
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1f, 0x27, 0x3);
-+}
-+
-+static int en8801s_phy_process(struct phy_device *phydev)
-+{
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+    u32 reg_value = 0;
-+
-+    reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x19e0);
-+    reg_value |= (1 << 0);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x19e0, reg_value);
-+    reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x19e0);
-+    reg_value &= ~(1 << 0);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x19e0, reg_value);
-+    return 0;
-+}
-+
-+static int en8801s_phase1_init(struct phy_device *phydev)
-+{
-+    unsigned long pbus_data;
-+    unsigned int pbusAddress;
-+    u32 reg_value;
-+    int retry;
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+
-+    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);
-+            phydev_info(phydev, "SMI_ADDR=%lx (renew)\n", pbus_data);
-+            airoha_pbus_write(mbus, pbusAddress, EN8801S_RG_SMI_ADDR, pbus_data);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_BUCK_CTL, 0x03);
-+            mdelay(10);
-+            break;
-+        } else {
-+            pbusAddress = EN8801S_PBUS_PHY_ID;
-+        }
-+        retry --;
-+        if (0 == retry) {
-+            phydev_err(phydev, "Probe fail !\n");
-+            return 0;
-+        }
-+    }
-+
-+    reg_value = (airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL) & 0xfffffffc) | 0x10 | (EN8801S_RX_POLARITY << 1) | EN8801S_TX_POLARITY;
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL, reg_value);
-+    mdelay(10);
-+    reg_value &= 0xffffffef;
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL, reg_value);
-+
-+    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) {
-+            phydev_err(phydev, "Initialize fail !\n");
-+            return 0;
-+        }
-+    }
-+    /* Software Reset PHY */
-+    reg_value = phy_read(phydev, MII_BMCR);
-+    reg_value |= BMCR_RESET;
-+    phy_write(phydev, MII_BMCR, reg_value);
-+    retry = MAX_RETRY;
-+    do {
-+        mdelay(10);
-+        reg_value = phy_read(phydev, MII_BMCR);
-+        retry--;
-+        if (0 == retry) {
-+            phydev_err(phydev, "Reset fail !\n");
-+            return 0;
-+        }
-+    } while (reg_value & BMCR_RESET);
-+
-+    phydev->dev_flags = PHY_STATE_INIT;
-+
-+    phydev_info(phydev, "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;
-+    u32 reg_value;
-+    int retry;
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+
-+    reg_value = (airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL) & 0xfffffffc) | 0x10 | (EN8801S_RX_POLARITY << 1) | EN8801S_TX_POLARITY;
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL, reg_value);
-+    mdelay(10);
-+    reg_value &= 0xffffffef;
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_LTR_CTL, reg_value);
-+
-+    pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1690);
-+    pbus_data |= (1 << 31);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1690, pbus_data);
-+
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c000c00);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x10, 0xD801);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0,  0x9140);
-+
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0A14, 0x0003);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c000c00);
-+    /* Set FCM control */
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1404, 0x004b);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x140c, 0x0007);
-+
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x142c, 0x05050505);
-+    pbus_data = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1440);
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1440, pbus_data & ~(1 << 11));
-+    /* Set GPHY Perfomance*/
-+    /* Token Ring */
-+    airoha_tr_reg_write(mbus, RgAddr_PMA_01h,     0x6FB90A);
-+    airoha_tr_reg_write(mbus, RgAddr_PMA_18h,     0x0E2F00);
-+    airoha_tr_reg_write(mbus, RgAddr_DSPF_06h,    0x2EBAEF);
-+    airoha_tr_reg_write(mbus, RgAddr_DSPF_11h,    0x040001);
-+    airoha_tr_reg_write(mbus, RgAddr_DSPF_03h,    0x000004);
-+    airoha_tr_reg_write(mbus, RgAddr_DSPF_1Ch,    0x003210);
-+    airoha_tr_reg_write(mbus, RgAddr_DSPF_14h,    0x00024A);
-+    airoha_tr_reg_write(mbus, RgAddr_DSPF_0Ch,    0x00704D);
-+    airoha_tr_reg_write(mbus, RgAddr_DSPF_0Dh,    0x02314F);
-+    airoha_tr_reg_write(mbus, RgAddr_DSPF_10h,    0x005010);
-+    airoha_tr_reg_write(mbus, RgAddr_DSPF_0Fh,    0x003028);
-+    airoha_tr_reg_write(mbus, RgAddr_TR_26h,      0x444444);
-+    airoha_tr_reg_write(mbus, RgAddr_R1000DEC_15h, 0x0055A0);
-+    /* CL22 & CL45 */
-+    phy_write(phydev, 0x1f, 0x03);
-+    GPHY_RG_LPI_1C.DATA = phy_read(phydev, RgAddr_LpiReg1Ch);
-+    GPHY_RG_LPI_1C.DataBitField.smi_deton_th = 0x0C;
-+    phy_write(phydev, RgAddr_LpiReg1Ch, GPHY_RG_LPI_1C.DATA);
-+    phy_write(phydev, 0x1f, 0x0);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x122, 0xffff);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x234, 0x0180);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x238, 0x0120);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x120, 0x9014);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x239, 0x0117);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x14A, 0xEE20);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x19B, 0x0111);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1F, 0x268, 0x07F4);
-+
-+    airoha_cl45_read(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, &reg_value);
-+    GPHY_RG_1E_324.DATA = (u16)reg_value;
-+    GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = 0;
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, (u32)GPHY_RG_1E_324.DATA);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x19E, 0xC2);
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x013, 0x0);
-+
-+    /* EFUSE */
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1C08, 0x40000040);
-+    retry = MAX_RETRY;
-+    while (0 != retry) {
-+        mdelay(1);
-+        reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1C08);
-+        if ((reg_value & (1 << 30)) == 0) {
-+            break;
-+        }
-+        retry--;
-+    }
-+    reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1C38);          /* RAW#2 */
-+    GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt = reg_value & 0x03f;
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x12, (u32)GPHY_RG_1E_012.DATA);
-+    GPHY_RG_1E_017.DataBitField.da_tx_i2mpb_b_tbt = (reg_value >> 8) & 0x03f;
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x12, (u32)GPHY_RG_1E_017.DATA);
-+
-+    airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1C08, 0x40400040);
-+    retry = MAX_RETRY;
-+    while (0 != retry) {
-+        mdelay(1);
-+        reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1C08);
-+        if ((reg_value & (1 << 30)) == 0) {
-+            break;
-+        }
-+        retry--;
-+    }
-+    reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1C30);          /* RAW#16 */
-+    GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = (reg_value >> 12) & 0x01;
-+    airoha_cl45_write(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, (u32)GPHY_RG_1E_324.DATA);
-+
-+    en8801s_led_init(phydev);
-+
-+    phydev_info(phydev, "Phase2 initialize OK !\n");
-+    return 0;
-+}
-+
-+static int en8801s_read_status(struct phy_device *phydev)
-+{
-+    int ret, preSpeed = phydev->speed;
-+    struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+    u32 reg_value;
-+
-+    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 ((preSpeed != phydev->speed) && (LINK_UP == phydev->link)) {
-+        preSpeed = phydev->speed;
-+
-+        if (phydev->dev_flags == PHY_STATE_INIT) {
-+            en8801s_phase2_init(phydev);
-+            phydev->dev_flags = PHY_STATE_PROCESS;
-+        }
-+
-+        if (preSpeed == SPEED_10) {
-+            reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1694);
-+            reg_value |= (1 << 31);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1694, reg_value);
-+            phydev->dev_flags = PHY_STATE_PROCESS;
-+        } else {
-+            reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1694);
-+            reg_value &= ~(1 << 31);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1694, reg_value);
-+            phydev->dev_flags = PHY_STATE_PROCESS;
-+        }
-+
-+        airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c000c00);
-+        if (SPEED_1000 == preSpeed) {
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x10, 0xD801);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0,  0x9140);
-+
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0A14, 0x0003);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c000c00);
-+            mdelay(2);      /* delay 2 ms */
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1404, 0x004b);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x140c, 0x0007);
-+        } else if (SPEED_100 == preSpeed) {
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x10, 0xD401);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0,  0x9140);
-+
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0A14, 0x0007);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c11);
-+            mdelay(2);      /* delay 2 ms */
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1404, 0x0027);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x140c, 0x0007);
-+        } else if (SPEED_10 == preSpeed) {
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x10, 0xD001);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0,  0x9140);
-+
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0A14, 0x000b);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x0600, 0x0c11);
-+            mdelay(2);      /* delay 2 ms */
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1404, 0x0027);
-+            airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x140c, 0x0007);
-+        }
-+    }
-+    return ret;
-+}
-+
-+static struct phy_driver Airoha_driver[] = {
-+    {
-+        .phy_id         = EN8801S_PHY_ID,
-+        .name           = "Airoha EN8801S",
-+        .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[] = {
-+    { EN8801S_PHY_ID, 0x0ffffff0 },
-+    { }
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, Airoha_tbl);
-Index: drivers/net/phy/en8801s.h
-===================================================================
---- /dev/null
-+++ b/drivers/net/phy/en8801s.h
-@@ -0,0 +1,158 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* FILE NAME:  en8801s.h
-+ * PURPOSE:
-+ *      Define EN8801S driver function
-+ *
-+ * NOTES:
-+ *
-+ */
-+
-+#ifndef __EN8801S_H
-+#define __EN8801S_H
-+
-+/* NAMING DECLARATIONS
-+ */
-+#define EN8801S_DRIVER_VERSION  "1.1.0"
-+
-+#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 EN8801S_PHY_ID          (unsigned long)((EN8801S_PHY_ID1 << 16) | EN8801S_PHY_ID2)
-+
-+#define DEV1E_REG013_VALUE      0
-+#define DEV1E_REG19E_VALUE      0xC2
-+#define DEV1E_REG324_VALUE      0x200
-+
-+#define TRUE                    1
-+#define FALSE                   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
-+
-+#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_LpiReg1Ch     0x1c
-+#define RgAddr_PMA_01h       0x0f82
-+#define RgAddr_PMA_18h       0x0fb0
-+#define RgAddr_DSPF_03h      0x1686
-+#define RgAddr_DSPF_06h      0x168c
-+#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_14h      0x16a8
-+#define RgAddr_DSPF_1Ch      0x16b8
-+#define RgAddr_TR_26h        0x0ecc
-+#define RgAddr_R1000DEC_15h  0x03aa
-+
-+/* DATA TYPE DECLARATIONS
-+ */
-+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;
-+
-+#endif /* End of __EN8801S_H */
diff --git a/target/linux/mediatek/patches-5.4/744-en8811h-2p5gphy-support.patch b/target/linux/mediatek/patches-5.4/744-en8811h-2p5gphy-support.patch
new file mode 100644
index 0000000..5a3e423
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/744-en8811h-2p5gphy-support.patch
@@ -0,0 +1,893 @@
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 207046b..21a4497 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -350,6 +350,11 @@ config AIROHA_EN8801SC_PHY
+         ---help---
+           Currently supports the Airoha EN8801S PHY for MT7981 SoC.
+ 
++config AIROHA_EN8811H_PHY
++	tristate "Drivers for Airoha EN8811H 2.5G Gigabit PHY"
++	---help---
++	  Currently supports the Airoha EN8811H PHY.
++
+ config ADIN_PHY
+ 	tristate "Analog Devices Industrial Ethernet PHYs"
+ 	help
+diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
+index 1b13c02..744b249 100644
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -71,6 +71,7 @@ ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
+ ifdef CONFIG_HWMON
+ aquantia-objs			+= aquantia_hwmon.o
+ endif
++obj-$(CONFIG_AIROHA_EN8811H_PHY)	+= air_en8811h.o
+ obj-$(CONFIG_AQUANTIA_PHY)	+= aquantia.o
+ obj-$(CONFIG_AX88796B_PHY)	+= ax88796b.o
+ obj-$(CONFIG_AT803X_PHY)	+= at803x.o
+diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
+new file mode 100644
+index 0000000..cf564fc
+--- /dev/null
++++ b/drivers/net/phy/air_en8811h.c
+@@ -0,0 +1,702 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++/* FILE NAME:  air_en8811h.c
++ * PURPOSE:
++ *      EN8811H phy driver for Linux
++ * NOTES:
++ *
++ */
++
++/* INCLUDE FILE DECLARATIONS
++ */
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mii.h>
++#include <linux/phy.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/delay.h>
++#include <linux/version.h>
++#include <linux/firmware.h>
++#include <linux/crc32.h>
++
++#include "air_en8811h.h"
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0))
++#define phydev_mdio_bus(_dev) (_dev->bus)
++#define phydev_addr(_dev) (_dev->addr)
++#define phydev_dev(_dev) (&_dev->dev)
++#else
++#define phydev_mdio_bus(_dev) (_dev->mdio.bus)
++#define phydev_addr(_dev) (_dev->mdio.addr)
++#define phydev_dev(_dev) (&_dev->mdio.dev)
++#endif
++
++MODULE_DESCRIPTION("Airoha EN8811H PHY drivers");
++MODULE_AUTHOR("Airoha");
++MODULE_LICENSE("GPL");
++
++/*
++GPIO5  <-> BASE_T_LED0,
++GPIO4  <-> BASE_T_LED1,
++GPIO3  <-> BASE_T_LED2,
++*/
++/* User-defined.B */
++#define AIR_LED_SUPPORT
++#ifdef AIR_LED_SUPPORT
++static const AIR_BASE_T_LED_CFG_T led_cfg[3] =
++{
++    /*
++     *    LED Enable,            GPIO,            LED Polarity,            LED ON,               LED Blink
++     */
++         {LED_ENABLE,      AIR_LED0_GPIO5,       AIR_ACTIVE_HIGH,     BASE_T_LED0_ON_CFG,    BASE_T_LED0_BLK_CFG}, /* BASE-T LED0 */
++         {LED_ENABLE,      AIR_LED1_GPIO4,       AIR_ACTIVE_HIGH,     BASE_T_LED1_ON_CFG,    BASE_T_LED1_BLK_CFG}, /* BASE-T LED1 */
++         {LED_ENABLE,      AIR_LED2_GPIO3,       AIR_ACTIVE_HIGH,     BASE_T_LED2_ON_CFG,    BASE_T_LED2_BLK_CFG}, /* BASE-T LED2 */
++};
++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
++************************************************************************/
++#if 0
++/* Airoha MII read function */
++static int air_mii_cl22_read(struct mii_bus *ebus, unsigned int phy_addr,unsigned int phy_register)
++{
++    int read_data;
++    read_data = mdiobus_read(ebus, phy_addr, phy_register);
++    return read_data;
++}
++#endif
++/* Airoha MII write function */
++static int air_mii_cl22_write(struct mii_bus *ebus, unsigned int phy_addr, unsigned int phy_register,unsigned int write_data)
++{
++    int ret = 0;
++    ret = mdiobus_write(ebus, phy_addr, phy_register, write_data);
++    return ret;
++}
++
++static int air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg)
++{
++    int ret = 0;
++    int data;
++    struct device *dev = phydev_dev(phydev);
++    ret = phy_write(phydev, MII_MMD_ACC_CTL_REG, devad);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return INVALID_DATA;
++    }
++    ret = phy_write(phydev, MII_MMD_ADDR_DATA_REG, reg);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return INVALID_DATA;
++    }
++    ret = phy_write(phydev, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return INVALID_DATA;
++    }
++    data = phy_read(phydev, MII_MMD_ADDR_DATA_REG);
++    return data;
++}
++
++static int air_mii_cl45_write(struct phy_device *phydev, int devad, u16 reg, u16 write_data)
++{
++    int ret = 0;
++    struct device *dev = phydev_dev(phydev);
++    ret = phy_write(phydev, MII_MMD_ACC_CTL_REG, devad);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, MII_MMD_ADDR_DATA_REG, reg);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, MII_MMD_ADDR_DATA_REG, write_data);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    return 0;
++}
++/* Use default PBUS_PHY_ID */
++/* EN8811H PBUS write function */
++static int air_pbus_reg_write(struct phy_device *phydev, unsigned long pbus_address, unsigned long pbus_data)
++{
++    struct mii_bus *mbus = phydev_mdio_bus(phydev);
++    int addr = phydev_addr(phydev);
++    int ret = 0;
++    ret = air_mii_cl22_write(mbus, (addr + 8), 0x1F, (unsigned int)(pbus_address >> 6));
++    AIR_RTN_ERR(ret);
++    ret = air_mii_cl22_write(mbus, (addr + 8), (unsigned int)((pbus_address >> 2) & 0xf), (unsigned int)(pbus_data & 0xFFFF));
++    AIR_RTN_ERR(ret);
++    ret = air_mii_cl22_write(mbus, (addr + 8), 0x10, (unsigned int)(pbus_data >> 16));
++    AIR_RTN_ERR(ret);
++    return 0;
++}
++
++/* EN8811H BUCK write function */
++static int air_buckpbus_reg_write(struct phy_device *phydev, unsigned long pbus_address, unsigned int pbus_data)
++{
++    int ret = 0;
++    struct device *dev = phydev_dev(phydev);
++    ret = phy_write(phydev, 0x1F, (unsigned int)4);        /* page 4 */
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, 0x10, (unsigned int)0);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, 0x11, (unsigned int)((pbus_address >> 16) & 0xffff));
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, 0x12, (unsigned int)(pbus_address & 0xffff));
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, 0x13, (unsigned int)((pbus_data >> 16) & 0xffff));
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, 0x14, (unsigned int)(pbus_data & 0xffff));
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, 0x1F, 0);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    return 0;
++}
++
++/* EN8811H BUCK read function */
++static unsigned int air_buckpbus_reg_read(struct phy_device *phydev, unsigned long pbus_address)
++{
++    unsigned int pbus_data = 0, pbus_data_low, pbus_data_high;
++    int ret = 0;
++    struct device *dev = phydev_dev(phydev);
++    ret = phy_write(phydev, 0x1F, (unsigned int)4);        /* page 4 */
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return PBUS_INVALID_DATA;
++    }
++    ret = phy_write(phydev, 0x10, (unsigned int)0);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return PBUS_INVALID_DATA;
++    }
++    ret = phy_write(phydev, 0x15, (unsigned int)((pbus_address >> 16) & 0xffff));
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return PBUS_INVALID_DATA;
++    }
++    ret = phy_write(phydev, 0x16, (unsigned int)(pbus_address & 0xffff));
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return PBUS_INVALID_DATA;
++    }
++
++    pbus_data_high = phy_read(phydev, 0x17);
++    pbus_data_low = phy_read(phydev, 0x18);
++    pbus_data = (pbus_data_high << 16) + pbus_data_low;
++    ret = phy_write(phydev, 0x1F, 0);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    return pbus_data;
++}
++
++static int MDIOWriteBuf(struct phy_device *phydev, unsigned long address, const struct firmware *fw)
++{
++    unsigned int write_data, offset ;
++    int ret = 0;
++    struct device *dev = phydev_dev(phydev);
++    ret = phy_write(phydev, 0x1F, (unsigned int)4);            /* page 4 */
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, 0x10, (unsigned int)0x8000);        /* address increment*/
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, 0x11, (unsigned int)((address >> 16) & 0xffff));
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    ret = phy_write(phydev, 0x12, (unsigned int)(address & 0xffff));
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++
++    for (offset = 0; offset < fw->size; offset += 4)
++    {
++        write_data = (fw->data[offset + 3] << 8) | fw->data[offset + 2];
++        ret = phy_write(phydev, 0x13, write_data);
++        if (ret < 0) {
++            dev_err(dev, "phy_write, ret: %d\n", ret);
++            return ret;
++        }
++        write_data = (fw->data[offset + 1] << 8) | fw->data[offset];
++        ret = phy_write(phydev, 0x14, write_data);
++        if (ret < 0) {
++            dev_err(dev, "phy_write, ret: %d\n", ret);
++            return ret;
++        }
++    }
++    ret = phy_write(phydev, 0x1F, (unsigned int)0);
++    if (ret < 0) {
++        dev_err(dev, "phy_write, ret: %d\n", ret);
++        return ret;
++    }
++    return 0;
++}
++
++static int en8811h_load_firmware(struct phy_device *phydev)
++{
++    struct device *dev = phydev_dev(phydev);
++    const struct firmware *fw;
++    const char *firmware;
++    int ret = 0;
++    unsigned int crc32;
++    u32 pbus_value = 0;
++
++    ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x0);
++    AIR_RTN_ERR(ret);
++    pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
++    pbus_value |= BIT(11);
++    ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
++    AIR_RTN_ERR(ret);
++    firmware = EN8811H_MD32_DM;
++    ret = request_firmware_direct(&fw, firmware, dev);
++    if (ret < 0) {
++        dev_info(dev, "failed to load firmware %s, ret: %d\n", firmware, ret);
++        return ret;
++    }
++    crc32 = ~crc32(~0, fw->data, fw->size);
++    dev_info(dev, "%s: crc32=0x%x\n", firmware, crc32);
++    /* Download DM */
++    ret = MDIOWriteBuf(phydev, 0x00000000, fw);
++    if (ret < 0) {
++        dev_info(dev, "MDIOWriteBuf 0x00000000 fail, ret: %d\n", ret);
++        return ret;
++    }
++    release_firmware(fw);
++
++    firmware = EN8811H_MD32_DSP;
++    ret = request_firmware_direct(&fw, firmware, dev);
++    if (ret < 0) {
++        dev_info(dev, "failed to load firmware %s, ret: %d\n", firmware, ret);
++        return ret;
++    }
++    crc32 = ~crc32(~0, fw->data, fw->size);
++    dev_info(dev, "%s: crc32=0x%x\n", firmware, crc32);
++    /* Download PM */
++    ret = MDIOWriteBuf(phydev, 0x00100000, fw);
++    if (ret < 0) {
++            dev_info(dev, "MDIOWriteBuf 0x00100000 fail , ret: %d\n", ret);
++            return ret;
++    }
++    release_firmware(fw);
++
++    pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
++    pbus_value &= ~BIT(11);
++    ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
++    AIR_RTN_ERR(ret);
++    ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x01);
++    AIR_RTN_ERR(ret);
++    return 0;
++}
++
++#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;
++    if (AIR_ACTIVE_HIGH == polar) {
++        on_evt |= LED_ON_POL;
++    } else {
++        on_evt &= ~LED_ON_POL ;
++    }
++    ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), on_evt | LED_ON_EN);
++    AIR_RTN_ERR(ret);
++    ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt);
++    AIR_RTN_ERR(ret);
++    return 0;
++}
++
++static int airoha_led_set_mode(struct phy_device *phydev, u8 mode)
++{
++    u16 cl45_data;
++    int err = 0;
++    struct device *dev = phydev_dev(phydev);
++    cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_BCR);
++    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:
++        dev_err(dev, "LED mode%d is not supported!\n", mode);
++        return -EINVAL;
++    }
++    err = air_mii_cl45_write(phydev, 0x1f, LED_BCR, cl45_data);
++    AIR_RTN_ERR(err);
++    return 0;
++}
++
++static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state)
++{
++    u16 cl45_data = 0;
++    int err;
++
++    cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity));
++    if (LED_ENABLE == state) {
++        cl45_data |= LED_ON_EN;
++    } else {
++        cl45_data &= ~LED_ON_EN;
++    }
++
++    err = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), cl45_data);
++    AIR_RTN_ERR(err);
++    return 0;
++}
++
++static int en8811h_led_init(struct phy_device *phydev)
++{
++
++    unsigned long led_gpio = 0, reg_value = 0;
++    u16 cl45_data = led_dur;
++    int ret = 0, led_id;
++    struct device *dev = phydev_dev(phydev);
++    ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data);
++    AIR_RTN_ERR(ret);
++    cl45_data >>= 1;
++    ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_DUR, cl45_data);
++    AIR_RTN_ERR(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 < EN8811H_LED_COUNT; led_id++)
++    {
++        /* LED0 <-> GPIO5, LED1 <-> GPIO4, LED0 <-> GPIO3 */
++        if (led_cfg[led_id].gpio != (led_id + (AIR_LED0_GPIO5 - (2 * led_id))))
++        {
++            dev_err(dev, "LED%d uses incorrect GPIO%d !\n", led_id, led_cfg[led_id].gpio);
++            return -EINVAL;
++        }
++        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_ENABLE == led_cfg[led_id].en)
++        {
++            led_gpio |= BIT(led_cfg[led_id].gpio);
++            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 default, ret %d !\n", ret);
++                return ret;
++            }
++        }
++    }
++    reg_value = air_buckpbus_reg_read(phydev, 0xcf8b8) | led_gpio;
++    ret = air_buckpbus_reg_write(phydev, 0xcf8b8, reg_value);
++    AIR_RTN_ERR(ret);
++
++    dev_info(dev, "LED initialize OK !\n");
++    return 0;
++}
++#endif /* AIR_LED_SUPPORT */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 5, 0))
++static int en8811h_get_features(struct phy_device *phydev)
++{
++    int ret;
++    struct device *dev = phydev_dev(phydev);
++    dev_info(dev, "%s()\n", __func__);
++    ret = air_pbus_reg_write(phydev, 0xcf928 , 0x0);
++    AIR_RTN_ERR(ret);
++    ret = genphy_read_abilities(phydev);
++    if (ret)
++        return ret;
++
++    /* EN8811H supports 100M/1G/2.5G speed. */
++    linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
++               phydev->supported);
++    linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
++               phydev->supported);
++    linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_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_2500baseX_Full_BIT,
++               phydev->supported);
++    return 0;
++}
++#endif
++static int en8811h_phy_probe(struct phy_device *phydev)
++{
++    int ret = 0;
++    int reg_value, pid1 = 0, pid2 = 0;
++    u32 pbus_value = 0, retry;
++    struct device *dev = phydev_dev(phydev);
++    ret = air_pbus_reg_write(phydev, 0xcf928 , 0x0);
++    AIR_RTN_ERR(ret);
++    pid1 = phy_read(phydev, MII_PHYSID1);
++    if (pid1 < 0)
++        return pid1;
++    pid2 = phy_read(phydev, MII_PHYSID2);
++    if (pid2 < 0)
++        return pid2;
++    dev_info(dev, "PHY = %x - %x\n", pid1, pid2);
++    if ((EN8811H_PHY_ID1 != pid1) || (EN8811H_PHY_ID2 != pid2))
++    {
++        dev_err(dev, "EN8811H dose not exist !\n");
++        return -ENODEV;
++    }
++    ret = en8811h_load_firmware(phydev);
++    if (ret)
++    {
++        dev_err(dev,"EN8811H load firmware fail.\n");
++        return ret;
++    }
++    retry = MAX_RETRY;
++    do {
++        mdelay(300);
++        reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009);
++        if (EN8811H_PHY_READY == reg_value)
++        {
++            dev_info(dev, "EN8811H PHY ready!\n");
++            break;
++        }
++        retry--;
++    } while (retry);
++    if (0 == retry)
++    {
++        dev_err(dev, "EN8811H initialize fail ! reg: 0x%x\n", reg_value);
++        return -EIO;
++    }
++    /* Mode selection*/
++    dev_info(dev, "EN8811H Mode 1 !\n");
++    ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
++    AIR_RTN_ERR(ret);
++    ret = air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
++    AIR_RTN_ERR(ret);
++    ret = air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
++    AIR_RTN_ERR(ret);
++    ret = air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
++    AIR_RTN_ERR(ret);
++
++    /* Serdes polarity */
++    pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
++    pbus_value = (pbus_value & 0xfffffffc) | EN8811H_RX_POLARITY_NORMAL | EN8811H_TX_POLARITY_NORMAL;
++    ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
++    AIR_RTN_ERR(ret);
++    pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
++    dev_info(dev, "0xca0f8= 0x%x\n", pbus_value);
++    pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
++    dev_info(dev, "Version(0x3b3c)= %x\n", pbus_value);
++#if defined(AIR_LED_SUPPORT)
++    ret = en8811h_led_init(phydev);
++    if (ret < 0)
++    {
++        dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
++        return ret;
++    }
++#endif
++    dev_info(dev, "EN8811H initialize OK ! (%s)\n", EN8811H_FW_VERSION);
++    return 0;
++}
++
++static int en8811h_get_autonego(struct phy_device *phydev, int *an)
++{
++    int reg;
++    reg = phy_read(phydev, MII_BMCR);
++    if (reg < 0)
++        return -EINVAL;
++    if (reg & BMCR_ANENABLE)
++        *an = AUTONEG_ENABLE;
++    else
++        *an = AUTONEG_DISABLE;
++    return 0;
++}
++
++static int en8811h_read_status(struct phy_device *phydev)
++{
++    int ret = 0, lpagb = 0, lpa = 0, common_adv_gb = 0, common_adv = 0, advgb = 0, adv = 0, reg = 0, an = AUTONEG_DISABLE, bmcr = 0;
++    int old_link = phydev->link;
++    u32 pbus_value = 0;
++    struct device *dev = phydev_dev(phydev);
++	ret = genphy_update_link(phydev);
++	if (ret)
++    {
++        dev_err(dev, "ret %d!\n", ret);
++		return ret;
++    }
++
++	if (old_link && phydev->link)
++		return 0;
++
++	phydev->speed = SPEED_UNKNOWN;
++	phydev->duplex = DUPLEX_UNKNOWN;
++	phydev->pause = 0;
++	phydev->asym_pause = 0;
++
++    reg = phy_read(phydev, MII_BMSR);
++    if (reg < 0)
++    {
++        dev_err(dev, "MII_BMSR reg %d!\n", reg);
++		return reg;
++    }
++    reg = phy_read(phydev, MII_BMSR);
++    if (reg < 0)
++    {
++        dev_err(dev, "MII_BMSR reg %d!\n", reg);
++		return reg;
++    }
++    if(reg & BMSR_LSTATUS)
++    {
++        pbus_value = air_buckpbus_reg_read(phydev, 0x109D4);
++        if (0x10 & pbus_value) {
++            phydev->speed = SPEED_2500;
++            phydev->duplex = DUPLEX_FULL;
++        }
++        else
++        {
++            ret = en8811h_get_autonego(phydev, &an);
++            if ((AUTONEG_ENABLE == an) && (0 == ret))
++            {
++                dev_dbg(dev, "AN mode!\n");
++                dev_dbg(dev, "SPEED 1000/100!\n");
++                lpagb = phy_read(phydev, MII_STAT1000);
++                if (lpagb < 0 )
++                    return lpagb;
++                advgb = phy_read(phydev, MII_CTRL1000);
++                if (adv < 0 )
++                    return adv;
++                common_adv_gb = (lpagb & (advgb << 2));
++
++                lpa = phy_read(phydev, MII_LPA);
++                if (lpa < 0 )
++                    return lpa;
++                adv = phy_read(phydev, MII_ADVERTISE);
++                if (adv < 0 )
++                    return adv;
++                common_adv = (lpa & adv);
++
++                phydev->speed = SPEED_10;
++                phydev->duplex = DUPLEX_HALF;
++                if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF))
++                {
++                    phydev->speed = SPEED_1000;
++                    if (common_adv_gb & LPA_1000FULL)
++
++                        phydev->duplex = DUPLEX_FULL;
++                }
++                else if (common_adv & (LPA_100FULL | LPA_100HALF))
++                {
++                    phydev->speed = SPEED_100;
++                    if (common_adv & LPA_100FULL)
++                        phydev->duplex = DUPLEX_FULL;
++                }
++                else
++                {
++                    if (common_adv & LPA_10FULL)
++                        phydev->duplex = DUPLEX_FULL;
++                }
++            }
++            else
++            {
++                dev_dbg(dev, "Force mode!\n");
++                bmcr = phy_read(phydev, MII_BMCR);
++
++                if (bmcr < 0)
++                    return bmcr;
++
++                if (bmcr & BMCR_FULLDPLX)
++                    phydev->duplex = DUPLEX_FULL;
++                else
++                    phydev->duplex = DUPLEX_HALF;
++
++                if (bmcr & BMCR_SPEED1000)
++                    phydev->speed = SPEED_1000;
++                else if (bmcr & BMCR_SPEED100)
++                    phydev->speed = SPEED_100;
++                else
++                    phydev->speed = SPEED_UNKNOWN;
++            }
++        }
++    }
++
++	return ret;
++}
++static struct phy_driver en8811h_driver[] = {
++{
++    .phy_id         = EN8811H_PHY_ID,
++    .name           = "Airoha EN8811H",
++    .phy_id_mask    = 0x0ffffff0,
++    .probe          = en8811h_phy_probe,
++    .read_status    = en8811h_read_status,
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 5, 0))
++    .get_features   = en8811h_get_features,
++    .read_mmd       = air_mii_cl45_read,
++    .write_mmd      = air_mii_cl45_write,
++#endif
++} };
++
++int __init en8811h_phy_driver_register(void)
++{
++    int ret;
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0))
++    ret = phy_driver_register(en8811h_driver);
++#else
++    ret = phy_driver_register(en8811h_driver, THIS_MODULE);
++#endif
++    if (!ret)
++        return 0;
++
++    phy_driver_unregister(en8811h_driver);
++    return ret;
++}
++
++void __exit en8811h_phy_driver_unregister(void)
++{
++    phy_driver_unregister(en8811h_driver);
++}
++
++module_init(en8811h_phy_driver_register);
++module_exit(en8811h_phy_driver_unregister);
+diff --git a/drivers/net/phy/air_en8811h.h b/drivers/net/phy/air_en8811h.h
+new file mode 100644
+index 0000000..1c91627
+--- /dev/null
++++ b/drivers/net/phy/air_en8811h.h
+@@ -0,0 +1,151 @@
++#ifndef __EN8811H_H
++#define __EN8811H_H
++
++#define EN8811H_MD32_DM             "EthMD32.dm.bin"
++#define EN8811H_MD32_DSP            "EthMD32.DSP.bin"
++
++#define EN8811H_PHY_ID1             0x03a2
++#define EN8811H_PHY_ID2             0xa411
++#define EN8811H_PHY_ID              ((EN8811H_PHY_ID1 << 16) | EN8811H_PHY_ID2)
++#define EN8811H_PHY_READY           0x02
++#define MAX_RETRY                   5
++
++#define EN8811H_TX_POLARITY_NORMAL   0x1
++#define EN8811H_TX_POLARITY_REVERSE  0x0
++
++#define EN8811H_RX_POLARITY_REVERSE  (0x1 << 1)
++#define EN8811H_RX_POLARITY_NORMAL   (0x0 << 1)
++
++
++/*
++The following led_cfg example is for reference only.
++LED0 Link 2500/Blink 2500 TxRx   (GPIO5)    <-> BASE_T_LED0,
++LED1 Link 1000/Blink 1000 TxRx   (GPIO4)    <-> BASE_T_LED1,
++LED2 Link 100 /Blink 100  TxRx   (GPIO3)    <-> BASE_T_LED2,
++*/
++/* User-defined.B */
++#define BASE_T_LED0_ON_CFG      (LED_ON_EVT_LINK_2500M)
++#define BASE_T_LED0_BLK_CFG     (LED_BLK_EVT_2500M_TX_ACT | LED_BLK_EVT_2500M_RX_ACT)
++#define BASE_T_LED1_ON_CFG      (LED_ON_EVT_LINK_1000M)
++#define BASE_T_LED1_BLK_CFG     (LED_BLK_EVT_1000M_TX_ACT | LED_BLK_EVT_1000M_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)
++/* User-defined.E */
++
++/* 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 EN8811H_FW_VERSION          "1.1.3"
++
++#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             (0x1ff)
++/* LED ON Event Option.B */
++#define LED_ON_EVT_LINK_2500M       (1 << 8)
++#define LED_ON_EVT_FORCE            (1 << 6)
++#define LED_ON_EVT_LINK_DOWN        (1 << 3)
++#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            (0xfff)
++/* LED Blinking Event Option.B*/
++#define LED_BLK_EVT_2500M_RX_ACT    (1 << 11)
++#define LED_BLK_EVT_2500M_TX_ACT    (1 << 10)
++#define LED_BLK_EVT_FORCE           (1 << 9)
++#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 EN8811H_LED_COUNT           3
++
++#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 UNIT_LED_BLINK_DURATION     1024
++
++#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 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)
++
++#define INVALID_DATA                0xffff
++#define PBUS_INVALID_DATA           0xffffffff
++
++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 enum
++{
++    AIR_LED2_GPIO3 = 3,
++    AIR_LED1_GPIO4,
++    AIR_LED0_GPIO5,
++    AIR_LED_LAST
++} AIR_LED_GPIO;
++
++typedef enum {
++    AIR_BASE_T_LED0,
++    AIR_BASE_T_LED1,
++    AIR_BASE_T_LED2,
++    AIR_BASE_T_LED3
++}AIR_BASE_T_LED;
++
++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 __EN8811H_MD32_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 38d6d4c..9156cb4 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
@@ -635,11 +635,10 @@
 ===================================================================
 --- a/drivers/net/phy/Makefile
 +++ b/drivers/net/phy/Makefile
-@@ -68,6 +68,7 @@ ifdef CONFIG_HWMON
+@@ -68,5 +68,6 @@ ifdef CONFIG_HWMON
  aquantia-objs			+= aquantia_hwmon.o
  endif
- obj-$(CONFIG_AIROHA_EN8801S_PHY)	+= en8801s.o
 +obj-$(CONFIG_AIROHA_EN8801SC_PHY)	+= en8801sc.o
+ obj-$(CONFIG_AIROHA_EN8811H_PHY)	+= air_en8811h.o
  obj-$(CONFIG_AQUANTIA_PHY)	+= aquantia.o
  obj-$(CONFIG_AX88796B_PHY)	+= ax88796b.o
- obj-$(CONFIG_AT803X_PHY)	+= at803x.o
diff --git a/target/linux/mediatek/patches-5.4/751-net-phy-aquantia-add-firmware-download.patch b/target/linux/mediatek/patches-5.4/751-net-phy-aquantia-add-firmware-download.patch
index ff3b383..a132dfe 100644
--- a/target/linux/mediatek/patches-5.4/751-net-phy-aquantia-add-firmware-download.patch
+++ b/target/linux/mediatek/patches-5.4/751-net-phy-aquantia-add-firmware-download.patch
@@ -64,14 +64,13 @@
 index 043a697..4f67110 100644
 --- a/drivers/net/phy/Makefile
 +++ b/drivers/net/phy/Makefile
-@@ -67,6 +67,9 @@ aquantia-objs			+= aquantia_main.o
+@@ -67,5 +67,8 @@ aquantia-objs			+= aquantia_main.o
  ifdef CONFIG_HWMON
  aquantia-objs			+= aquantia_hwmon.o
  endif
 +ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
 +aquantia-objs			+= aquantia_firmware.o
 +endif
- obj-$(CONFIG_AIROHA_EN8801S_PHY)	+= en8801s.o
  obj-$(CONFIG_AIROHA_EN8801SC_PHY)	+= en8801sc.o
  obj-$(CONFIG_AQUANTIA_PHY)	+= aquantia.o
 diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h