[][kernel][common][eth][Update Airoha EN8811H 2.5G PHY driver to v1.2.4]

[Description]
Change Airoha EN8811H 2.5G PHY driver to v1.2.4.

Change Log:
[2024/01/12] v1.2.4
1. Added SSC API.
* MD32 8811_240112_02 updated:
1. Fixed the issue of MAC Deadbeef
2. Fixed the issue of LDO Bus Deadbeef
3. Improved IoT performance and stability

[2023/11/23] v1.2.3
1. Supported polarity setting in dts
2. Added temperature API and link partner ability API.
* MD32 8811_23112102 updated:
1. Fixed the issue of 1G speed down shift to 100M
2. Added the loopback recovery function for 2.5G Ext / 2.5G Int / 1G
Ext loopback settings
3. Improved IoT performance and stability
4. Fixed the issue of settings being lost when powering down and then
powering up.
5. Fixed the issue of losing settings when the device is powered off
and then powered on
6. Fixed the issue of experiencing abnormal behavior when changing the
speed to 100/1000Mbps and powering down/up the PHY

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

&eth {
	...

	gmac1: mac@1 {
		compatible = "mediatek,eth-mac";
		reg = <1>;
		phy-mode = "2500base-x";

		fixed-link {
			speed = <2500>;
			full-duplex;
			pause;
		};
	};

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

      		phy15: phy@15 {
       			compatible = "ethernet-phy-id03a2.a411";
			reg = <15>;
			phy-mode = "2500base-x";
			full-duplex;
			pause;
			airoha,polarity = <1>;
		};

       		...
	};
};

Note:
SerDes polarity setting could be configured in dts. Please refer to the
following description.
Tx Reverse, Rx Normal:
		airoha,polarity = <0>;
Tx Normal, Rx Normal:
		airoha,polarity = <1>;
Tx Reverse, Rx Reverse:
		airoha,polarity = <2>;
Tx Normal, Rx Reverse:
		airoha,polarity = <3>;

=====================================================================
In addition, if EN8811H 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 EN8811H.

[Release-log]
N/A


Change-Id: Ie528ebe07a0998d485505343c9b41db03c1afa01
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8633562
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h.h b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h.h
index 6a0afaf..38d4c07 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h.h
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h.h
@@ -46,7 +46,7 @@
 #define MII_MMD_ADDR_DATA_REG       0x0e
 #define MMD_OP_MODE_DATA            BIT(14)
 
-#define EN8811H_DRIVER_VERSION      "v1.2.2"
+#define EN8811H_DRIVER_VERSION      "v1.2.4"
 
 #define LED_ON_CTRL(i)              (0x024 + ((i)*2))
 #define LED_ON_EN                   (1 << 15)
@@ -98,6 +98,7 @@
 	unsigned int        dm_crc32;
 	unsigned int        dsp_crc32;
 	char                buf[512];
+	int                 pol;
 };
 
 struct air_base_t_led_cfg {
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.c
index 731a37d..a73bcee 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.c
@@ -87,7 +87,7 @@
 	return ret;
 }
 
-static int __air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg)
+int __air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg)
 {
 	int ret = 0;
 	int data;
@@ -107,7 +107,7 @@
 	return data;
 }
 
-static int __air_mii_cl45_write(struct phy_device *phydev,
+int __air_mii_cl45_write(struct phy_device *phydev,
 					int devad, u16 reg, u16 write_data)
 {
 	int ret = 0;
@@ -334,6 +334,40 @@
 	}
 	return ret;
 }
+#if defined(CONFIG_OF)
+int en8811h_of_init(struct phy_device *phydev)
+{
+	struct device *dev = phydev_dev(phydev);
+	struct device_node *of_node = dev->of_node;
+	struct en8811h_priv *priv = phydev->priv;
+	u32 val = 0;
+
+	dev_info(dev, "%s: start\n", __func__);
+	if (of_find_property(of_node, "airoha,polarity", NULL)) {
+		if (of_property_read_u32(of_node, "airoha,polarity",
+					 &val) != 0) {
+			phydev_err(phydev, "airoha,polarity value is invalid.");
+			return -EINVAL;
+		}
+		if (val < AIR_POL_TX_REV_RX_NOR ||
+		    val > AIR_POL_TX_NOR_RX_REV) {
+			phydev_err(phydev,
+				   "airoha,polarity value %u out of range.",
+				   val);
+			return -EINVAL;
+		}
+		priv->pol = val;
+	} else
+		priv->pol = AIR_POL_TX_NOR_RX_NOR;
+
+	return 0;
+}
+#else
+int en8811h_of_init(struct phy_device *phydev)
+{
+	return -ESRCH;
+}
+#endif /* CONFIG_OF */
 
 static int air_resolve_an_speed(struct phy_device *phydev)
 {
@@ -588,31 +622,21 @@
 		if (unlikely(ret < 0))
 			break;
 		break;
-	case AIR_PORT_MODE_FC_DIS:
-		pr_notice("\nFlow Control Disabled\n");
-		pbus_data = air_buckpbus_reg_read(phydev, 0xe0008);
-		pbus_data &= ~(BIT(6) | BIT(7));
-		ret = air_buckpbus_reg_write(phydev, 0xe0008, pbus_data);
+	case AIR_PORT_MODE_SSC_DISABLE:
+		pr_notice("\nSSC Disabled\n");
+		pbus_data = air_buckpbus_reg_read(phydev, 0xca000);
+		pbus_data &= ~BIT(21);
+		ret = air_buckpbus_reg_write(phydev, 0xca000, pbus_data);
 		if (unlikely(ret < 0))
 			break;
-		pbus_data = air_buckpbus_reg_read(phydev, 0xe000c);
-		pbus_data &= ~(BIT(0) | BIT(1));
-		ret = air_buckpbus_reg_write(phydev, 0xe000c, pbus_data);
-		if (unlikely(ret < 0))
-			break;
 		break;
-	case AIR_PORT_MODE_FC_EN:
-		pr_notice("\nFlow Control Enabled\n");
-		pbus_data = air_buckpbus_reg_read(phydev, 0xe0008);
-		pbus_data |= (BIT(6) | BIT(7));
-		ret = air_buckpbus_reg_write(phydev, 0xe0008, pbus_data);
+	case AIR_PORT_MODE_SSC_ENABLE:
+		pr_notice("\nSSC Enabled\n");
+		pbus_data = air_buckpbus_reg_read(phydev, 0xca000);
+		pbus_data |= BIT(21);
+		ret = air_buckpbus_reg_write(phydev, 0xca000, pbus_data);
 		if (unlikely(ret < 0))
 			break;
-		pbus_data = air_buckpbus_reg_read(phydev, 0xe000c);
-		pbus_data |= (BIT(0) | BIT(1));
-		ret = air_buckpbus_reg_write(phydev, 0xe000c, pbus_data);
-		if (unlikely(ret < 0))
-			break;
 		break;
 	default:
 		pr_notice("\nWrong Port mode\n");
@@ -645,7 +669,6 @@
 	val = (air_buckpbus_reg_read(phydev, 0xca0f8) & 0x3);
 	seq_printf(seq, "| Tx, Rx Polarity      : %s(%02d)\n",
 						tx_rx_string[val], val);
-
 	seq_puts(seq, "\n");
 
 	return 0;
@@ -714,7 +737,7 @@
 	seq_printf(seq, "%010u |\n", pkt_cnt);
 	seq_puts(seq, "| RX Terminal              :");
 	pkt_cnt = air_buckpbus_reg_read(phydev, 0xC60C0);
-	seq_printf(seq, "%010u |\n\n", pkt_cnt);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
 	ret = air_buckpbus_reg_write(phydev, 0xC602C, 0x4);
 	if (ret < 0)
 		return ret;
@@ -732,9 +755,29 @@
 	if (ret < 0)
 		return ret;
 	seq_puts(seq, "==========AIR PHY COUNTER==========\n");
+	if (phydev->link) {
+		ret = airphy_ss_counter_show(phydev, seq);
+		if (ret < 0)
+			return ret;
+	}
 	ret = airphy_fcm_counter_show(phydev, seq);
 	if (ret < 0)
 		return ret;
+	if (phydev->link) {
+		seq_puts(seq, "|\t<<MAC Counter>>\n");
+		seq_puts(seq, "| Tx Error from System side:");
+		pkt_cnt = air_buckpbus_reg_read(phydev, 0x131000);
+		seq_printf(seq, "%010u |\n", pkt_cnt);
+		seq_puts(seq, "| Rx Error to System side  :");
+		pkt_cnt = air_buckpbus_reg_read(phydev, 0x132000);
+		seq_printf(seq, "%010u |\n", pkt_cnt);
+		seq_puts(seq, "| Tx from System side      :");
+		pkt_cnt = air_buckpbus_reg_read(phydev, 0x131004);
+		seq_printf(seq, "%010u |\n", pkt_cnt);
+		seq_puts(seq, "| Rx to System Side        :");
+		pkt_cnt = air_buckpbus_reg_read(phydev, 0x132004);
+		seq_printf(seq, "%010u |\n", pkt_cnt);
+	}
 	if (phydev->link && phydev->speed == SPEED_2500) {
 		seq_puts(seq, "|\t<<LS Counter>>\n");
 		ret = air_buckpbus_reg_write(phydev, 0x30718, 0x10);
@@ -744,37 +787,37 @@
 		if (ret < 0)
 			return ret;
 		seq_puts(seq, "|\tBefore EF\n");
-		seq_puts(seq, "| TX to Line side_S        :");
+		seq_puts(seq, "| Tx to Line side_S        :");
 		pkt_cnt = air_buckpbus_reg_read(phydev, 0x3071c);
 		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| TX to Line side_T        :");
+		seq_puts(seq, "| Tx to Line side_T        :");
 		pkt_cnt = air_buckpbus_reg_read(phydev, 0x30720);
 		seq_printf(seq, "%010u |\n", pkt_cnt);
+		seq_puts(seq, "| Tx_ENC                   :");
+		pkt_cnt = air_buckpbus_reg_read(phydev, 0x30724);
+		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| RX from Line side_S      :");
+		seq_puts(seq, "| Rx from Line side_S      :");
 		pkt_cnt = air_buckpbus_reg_read(phydev, 0x3072c);
 		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| RX from Line side_T      :");
+		seq_puts(seq, "| Rx from Line side_T      :");
 		pkt_cnt = air_buckpbus_reg_read(phydev, 0x30730);
 		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| TX_ENC                   :");
-		pkt_cnt = air_buckpbus_reg_read(phydev, 0x30724);
-		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| RX_DEC                   :");
+		seq_puts(seq, "| Rx_DEC                   :");
 		pkt_cnt = air_buckpbus_reg_read(phydev, 0x30728);
 		seq_printf(seq, "%010u |\n", pkt_cnt);
 		seq_puts(seq, "|\tAfter EF\n");
-		seq_puts(seq, "| TX to Line side_S        :");
+		seq_puts(seq, "| Tx to Line side_S        :");
 		pkt_cnt = air_buckpbus_reg_read(phydev, 0x30734);
 		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| TX to Line side_T        :");
+		seq_puts(seq, "| Tx to Line side_T        :");
 		pkt_cnt = air_buckpbus_reg_read(phydev, 0x30738);
 		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| RX from Line side_S      :");
+		seq_puts(seq, "| Rx from Line side_S      :");
 		pkt_cnt = air_buckpbus_reg_read(phydev, 0x30764);
 		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| RX from Line side_T      :");
+		seq_puts(seq, "| Rx from Line side_T      :");
 		pkt_cnt = air_buckpbus_reg_read(phydev, 0x30768);
-		seq_printf(seq, "%010u |\n", pkt_cnt);
+		seq_printf(seq, "%010u |\n\n", pkt_cnt);
 		ret = air_buckpbus_reg_write(phydev, 0x30718, 0x13);
 		if (ret < 0)
 			return ret;
@@ -787,29 +830,16 @@
 		ret = air_buckpbus_reg_write(phydev, 0x30718, 0x0);
 		if (ret < 0)
 			return ret;
-		seq_puts(seq, "|\t<<MAC Counter>>\n");
-		seq_puts(seq, "| TX Error from System side:");
-		pkt_cnt = air_buckpbus_reg_read(phydev, 0x131000);
-		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| RX Error to System side  :");
-		pkt_cnt = air_buckpbus_reg_read(phydev, 0x132000);
-		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| TX from System side      :");
-		pkt_cnt = air_buckpbus_reg_read(phydev, 0x131004);
-		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| RX to System Side        :");
-		pkt_cnt = air_buckpbus_reg_read(phydev, 0x132004);
-		seq_printf(seq, "%010u |\n", pkt_cnt);
 	}
 	if (phydev->link && ((phydev->speed != SPEED_2500))) {
 		seq_puts(seq, "|\t<<LS Counter>>\n");
 		ret = air_mii_cl22_write(mbus, addr, 0x1f, 1);
 		if (ret < 0)
 			return ret;
-		seq_puts(seq, "| RX from Line side        :");
+		seq_puts(seq, "| Rx from Line side        :");
 		pkt_cnt = air_mii_cl22_read(mbus, addr, 0x12) & 0x7fff;
 		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| RX Error from Line side  :");
+		seq_puts(seq, "| Rx Error from Line side  :");
 		pkt_cnt = air_mii_cl22_read(mbus, addr, 0x17) & 0xff;
 		seq_printf(seq, "%010u |\n", pkt_cnt);
 		ret = air_mii_cl22_write(mbus, addr, 0x1f, 0);
@@ -821,22 +851,17 @@
 		ret = air_mii_cl22_write(mbus, addr, 0x10, 0xBF92);
 		if (ret < 0)
 			return ret;
-		seq_puts(seq, "| TX to Line side          :");
+		seq_puts(seq, "| Tx to Line side          :");
 		pkt_cnt = (air_mii_cl22_read(mbus, addr, 0x11) & 0x7ffe) >> 1;
 		seq_printf(seq, "%010u |\n", pkt_cnt);
-		seq_puts(seq, "| TX Error to Line side    :");
+		seq_puts(seq, "| Tx Error to Line side    :");
 		pkt_cnt = air_mii_cl22_read(mbus, addr, 0x12);
 		pkt_cnt &= 0x7f;
-		seq_printf(seq, "%010u |\n", pkt_cnt);
+		seq_printf(seq, "%010u |\n\n", pkt_cnt);
 		ret = air_mii_cl22_write(mbus, addr, 0x1f, 0);
 		if (ret < 0)
 			return ret;
 	}
-	if (phydev->link) {
-		ret = airphy_ss_counter_show(phydev, seq);
-		if (ret < 0)
-			return ret;
-	}
 	return ret;
 }
 
@@ -901,6 +926,7 @@
 			"echo 2500 > /[debugfs]/port_mode\n"
 			"echo 1000 > /[debugfs]/port_mode\n"
 			"echo 100 > /[debugfs]/port_mode\n"
+			"echo ssc ena/dis > /[debugfs]/port_mode\n"
 			"echo power up/down >  /[debugfs]/port_mode\n");
 }
 
@@ -941,9 +967,11 @@
 			ret = air_set_mode(phydev, AIR_PORT_MODE_POWER_DOWN);
 		else if (!strncmp("up", param, strlen("up")))
 			ret = air_set_mode(phydev, AIR_PORT_MODE_POWER_UP);
-	} else if (!strncmp("int_sw_release", cmd, strlen("int_sw_release"))) {
-		ret = air_pbus_reg_write(phydev, 0xcf928, 0x0);
-		pr_notice("\ninternal sw reset released\n");
+	} else if (!strncmp("ssc", cmd, strlen("ssc"))) {
+		if (!strncmp("dis", param, strlen("dis")))
+			ret = air_set_mode(phydev, AIR_PORT_MODE_SSC_DISABLE);
+		else if (!strncmp("ena", param, strlen("ena")))
+			ret = air_set_mode(phydev, AIR_PORT_MODE_SSC_ENABLE);
 	} else if (!strncmp("help", cmd, strlen("help"))) {
 		airphy_port_mode_help();
 	}
@@ -1088,10 +1116,24 @@
 	int addr = phydev_addr(phydev);
 
 	seq_puts(seq, "\t<<DEBUG REG DUMP>>\n");
+	seq_printf(seq, "| RG_MII_BMCR           : 0x%08x |\n",
+		   air_mii_cl22_read(mbus, addr, MII_BMCR));
 	seq_printf(seq, "| RG_MII_BMSR           : 0x%08x |\n",
 		   air_mii_cl22_read(mbus, addr, MII_BMSR));
+	seq_printf(seq, "| RG_MII_ADVERTISE      : 0x%08x |\n",
+		   air_mii_cl22_read(mbus, addr, MII_ADVERTISE));
+	seq_printf(seq, "| RG_MII_LPA            : 0x%08x |\n",
+		   air_mii_cl22_read(mbus, addr, MII_LPA));
+	seq_printf(seq, "| RG_MII_CTRL1000       : 0x%08x |\n",
+		   air_mii_cl22_read(mbus, addr, MII_CTRL1000));
+	seq_printf(seq, "| RG_MII_STAT1000       : 0x%08x |\n",
+		   air_mii_cl22_read(mbus, addr, MII_STAT1000));
 	seq_printf(seq, "| RG_MII_REF_CLK        : 0x%08x |\n",
 		   air_mii_cl22_read(mbus, addr, 0x1d));
+	seq_printf(seq, "| RG_HW_STRAP1          : 0x%08x |\n",
+		   air_buckpbus_reg_read(phydev, 0xcf910));
+	seq_printf(seq, "| RG_HW_STRAP2          : 0x%08x |\n",
+		   air_buckpbus_reg_read(phydev, 0xcf914));
 	seq_printf(seq, "| RG_SYS_LINK_MODE      : 0x%08x |\n",
 		   air_buckpbus_reg_read(phydev, 0xe0004));
 	seq_printf(seq, "| RG_FCM_CTRL           : 0x%08x |\n",
@@ -1119,11 +1161,144 @@
 	return single_open(file, dbg_regs_show, inode->i_private);
 }
 
+
+static int airphy_temp_show(struct seq_file *seq, void *v)
+{
+	struct phy_device *phydev = seq->private;
+	int ret = 0;
+	u32 pbus_value = 0;
+
+	seq_puts(seq, "<<AIR EN8811H Temp>>\n");
+	air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1100);
+	air_mii_cl45_write(phydev, 0x1e, 0x800f, 0xe5);
+	pbus_value = air_buckpbus_reg_read(phydev, 0x3B38);
+	seq_printf(seq, "| Temperature  : %dC |\n",
+						pbus_value);
+	seq_puts(seq, "\n");
+
+	return 0;
+}
+
+static int airphy_temp_show_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, airphy_temp_show, inode->i_private);
+}
+
+
+static unsigned int air_read_lp_speed(struct phy_device *phydev)
+{
+	int val = 0, an = AUTONEG_DISABLE;
+	unsigned int ret = 0;
+	int count = 15, i, lpa, lpagb;
+	struct air_lp_speed *m;
+	struct device *dev = phydev_dev(phydev);
+	struct mii_bus *mbus = phydev_mdio_bus(phydev);
+	int addr = phydev_addr(phydev);
+
+	val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
+	ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
+	if (unlikely(ret < 0))
+		return ret;
+	msleep(1500);
+	do {
+		msleep(100);
+		ret = air_mii_cl45_read(phydev, MDIO_MMD_AN, 0x21);
+		ret &= BIT(5);
+		if (ret)
+			break;
+		count--;
+	} while (count);
+
+	count = 10;
+	do {
+		msleep(500);
+		val = air_mii_cl22_read(mbus, addr, MII_BMSR);
+		if (val < 0) {
+			dev_err(dev, "MII_BMSR reg 0x%x!\n", val);
+			return val;
+		}
+		val = air_mii_cl22_read(mbus, addr, MII_BMSR);
+		if (val < 0) {
+			dev_err(dev, "MII_BMSR reg 0x%x!\n", val);
+			return val;
+		}
+		dev_dbg(dev, "val 0x%x\n", val);
+		if (val & BMSR_LSTATUS) {
+			val = air_mii_cl22_read(mbus, addr, MII_LPA);
+			if (val < 0)
+				return val;
+			lpa = (val & (BIT(5) | BIT(6) | BIT(7) | BIT(8))) >> 5;
+			val = air_mii_cl22_read(mbus, addr, MII_STAT1000);
+			if (val < 0)
+				return val;
+			lpagb = GET_BIT(val, 11) << 4;
+			ret |= (lpagb | lpa);
+			return ret;
+		}
+	} while (count--);
+
+	return 0;
+}
+
+static int airphy_lp_speed(struct seq_file *seq, void *v)
+{
+	unsigned int ret = 0, val = 0, did1 = 0, i;
+	struct phy_device *phydev = seq->private;
+	static const struct {
+		unsigned int bit_index;
+		const char *name;
+	} mode_defs[] = {
+		{ AIR_LINK_MODE_10baseT_Half_BIT,
+		"10baseT/Half" },
+		{ AIR_LINK_MODE_10baseT_Full_BIT,
+		"10baseT/Full" },
+		{ AIR_LINK_MODE_100baseT_Half_BIT,
+		"100baseT/Half" },
+		{ AIR_LINK_MODE_100baseT_Full_BIT,
+		"100baseT/Full" },
+		{ AIR_LINK_MODE_1000baseT_Full_BIT,
+		"1000baseT/Full" },
+		{ AIR_LINK_MODE_2500baseT_Full_BIT,
+		"2500baseT/Full" }
+	};
+
+	seq_printf(seq, "%s Link Partner Ability:\n",
+			dev_name(phydev_dev(phydev)));
+	ret = air_read_lp_speed(phydev);
+	if (val < 0)
+		return val;
+	for (i = 0; i < ARRAY_SIZE(mode_defs); i++) {
+		if (ret & BIT(mode_defs[i].bit_index)) {
+			seq_printf(seq, "\t\t\t %s\n",
+						mode_defs[i].name);
+			did1++;
+		}
+	}
+	if (did1 == 0)
+		seq_puts(seq, "\t\t\t Not reported\n");
+
+	return 0;
+}
+
+static int airphy_lp_speed_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, airphy_lp_speed, inode->i_private);
+}
+
+static const struct file_operations airphy_lp_speed_fops = {
+	.owner = THIS_MODULE,
+	.open = airphy_lp_speed_open,
+	.read = seq_read,
+	.llseek = noop_llseek,
+	.release = single_release,
+};
+
 static const struct file_operations airphy_info_fops = {
 	.owner = THIS_MODULE,
 	.open = airphy_info_open,
 	.read = seq_read,
 	.llseek = noop_llseek,
+	.release = single_release,
 };
 
 static const struct file_operations airphy_counter_fops = {
@@ -1131,6 +1306,7 @@
 	.open = airphy_counter_open,
 	.read = seq_read,
 	.llseek = noop_llseek,
+	.release = single_release,
 };
 
 static const struct file_operations airphy_debugfs_buckpbus_fops = {
@@ -1166,6 +1342,7 @@
 	.open = airphy_link_status_open,
 	.read = seq_read,
 	.llseek = noop_llseek,
+	.release = single_release,
 };
 
 static const struct file_operations airphy_dbg_reg_show_fops = {
@@ -1173,8 +1350,17 @@
 	.open = airphy_dbg_regs_show_open,
 	.read = seq_read,
 	.llseek = noop_llseek,
+	.release = single_release,
 };
 
+static const struct file_operations airphy_temp_fops = {
+	.owner = THIS_MODULE,
+	.open = airphy_temp_show_open,
+	.read = seq_read,
+	.llseek = noop_llseek,
+	.release = single_release,
+};
+
 int airphy_debugfs_init(struct phy_device *phydev)
 {
 	int ret = 0;
@@ -1212,12 +1398,18 @@
 	debugfs_create_file(DEBUGFS_DBG_REG_SHOW, S_IFREG | 0444,
 					dir, phydev,
 					&airphy_dbg_reg_show_fops);
+	debugfs_create_file(DEBUGFS_TEMPERATURE, S_IFREG | 0444,
+					dir, phydev,
+					&airphy_temp_fops);
+	debugfs_create_file(DEBUGFS_LP_SPEED, S_IFREG | 0444,
+					dir, phydev,
+					&airphy_lp_speed_fops);
 
 	priv->debugfs_root = dir;
 	return ret;
 }
 
-void air_debugfs_remove(struct phy_device *phydev)
+void airphy_debugfs_remove(struct phy_device *phydev)
 {
 	struct en8811h_priv *priv = phydev->priv;
 
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.h b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.h
index a1d97ce..9715a58 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.h
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.h
@@ -21,8 +21,6 @@
 #define phydev_dev(_dev) (&_dev->mdio.dev)
 #endif
 
-#define BUFFER_LENGTH 512
-
 #define DEBUGFS_COUNTER		        "counter"
 #define DEBUGFS_DRIVER_INFO	        "drvinfo"
 #define DEBUGFS_PORT_MODE           "port_mode"
@@ -31,6 +29,8 @@
 #define DEBUGFS_POLARITY            "polarity"
 #define DEBUGFS_LINK_STATUS         "link_status"
 #define DEBUGFS_DBG_REG_SHOW        "dbg_regs_show"
+#define DEBUGFS_TEMPERATURE         "temp"
+#define DEBUGFS_LP_SPEED            "lp_speed"
 
 enum air_port_mode {
 	AIR_PORT_MODE_FORCE_100,
@@ -39,10 +39,8 @@
 	AIR_PORT_MODE_AUTONEGO,
 	AIR_PORT_MODE_POWER_DOWN,
 	AIR_PORT_MODE_POWER_UP,
-	AIR_PORT_MODE_FC_UNSUPPORT,
-	AIR_PORT_MODE_FC_SUPPORT,
-	AIR_PORT_MODE_FC_DIS,
-	AIR_PORT_MODE_FC_EN,
+	AIR_PORT_MODE_SSC_DISABLE,
+	AIR_PORT_MODE_SSC_ENABLE,
 	AIR_PORT_MODE_LAST = 0xFF,
 };
 
@@ -73,6 +71,9 @@
 	unsigned int phy_register, unsigned int write_data);
 int air_mii_cl22_read(struct mii_bus *ebus,
 	int addr, unsigned int phy_register);
+int __air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg);
+int __air_mii_cl45_write(struct phy_device *phydev,
+	int devad, u16 reg, u16 write_data);
 int air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg);
 int air_mii_cl45_write(struct phy_device *phydev,
 	int devad, u16 reg, u16 write_data);
@@ -80,8 +81,9 @@
 	unsigned int pbus_address);
 int air_buckpbus_reg_write(struct phy_device *phydev,
 	unsigned int pbus_address, unsigned int pbus_data);
+int en8811h_of_init(struct phy_device *phydev);
 #ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
 int airphy_debugfs_init(struct phy_device *phydev);
-void air_debugfs_remove(struct phy_device *phydev);
+void airphy_debugfs_remove(struct phy_device *phydev);
 #endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
 #endif /* End of __EN8811H_API_H */
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_main.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_main.c
index 353e226..50a7f49 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_main.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/air_en8811h_main.c
@@ -115,15 +115,16 @@
 	const char *firmware;
 	int ret = 0;
 	u32 pbus_value = 0;
-#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
 	struct en8811h_priv *priv = phydev->priv;
-#endif
-	ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x0);
+
+	ret = air_buckpbus_reg_write(phydev,
+					0x0f0018, 0x0);
 	if (ret < 0)
 		return ret;
 	pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
 	pbus_value |= BIT(11);
-	ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
+	ret = air_buckpbus_reg_write(phydev,
+					0x800000, pbus_value);
 	if (ret < 0)
 		return ret;
 	firmware = EN8811H_MD32_DM;
@@ -133,9 +134,7 @@
 			"failed to load firmware %s, ret: %d\n", firmware, ret);
 		return ret;
 	}
-#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
 	priv->dm_crc32 = ~crc32(~0, fw->data, fw->size);
-#endif
 	dev_info(dev, "%s: crc32=0x%x\n",
 		firmware, ~crc32(~0, fw->data, fw->size));
 	/* Download DM */
@@ -154,9 +153,7 @@
 			"failed to load firmware %s, ret: %d\n", firmware, ret);
 		return ret;
 	}
-#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
 	priv->dsp_crc32 = ~crc32(~0, fw->data, fw->size);
-#endif
 	dev_info(dev, "%s: crc32=0x%x\n",
 		firmware, ~crc32(~0, fw->data, fw->size));
 	/* Download PM */
@@ -333,26 +330,21 @@
 	struct mii_bus *mbus = phydev_mdio_bus(phydev);
 	int addr = phydev_addr(phydev);
 
-#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
 	struct en8811h_priv *priv;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 	phydev->priv = priv;
-#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
 	ret = air_pbus_reg_write(phydev, 0xcf928, 0x0);
 	if (ret < 0)
-		return ret;
+		goto priv_free;
 	pid1 = air_mii_cl22_read(mbus, addr, MII_PHYSID1);
-	if (pid1 < 0)
-		return pid1;
 	pid2 = air_mii_cl22_read(mbus, addr, MII_PHYSID2);
-	if (pid2 < 0)
-		return pid2;
 	dev_info(dev, "PHY = %x - %x\n", pid1, pid2);
 	if ((pid1 != EN8811H_PHY_ID1) || (pid2 != EN8811H_PHY_ID2)) {
-		dev_err(dev, "EN8811H dose not exist !\n");
+		dev_err(dev, "EN8811H dose not exist!!\n");
+		kfree(priv);
 		return -ENODEV;
 	}
 	pbus_value = air_buckpbus_reg_read(phydev, 0xcf914);
@@ -362,15 +354,14 @@
 	ret = en8811h_load_firmware(phydev);
 	if (ret < 0) {
 		dev_err(dev, "EN8811H load firmware fail.\n");
-		return ret;
+		goto priv_free;
 	}
 #ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
 	ret = airphy_debugfs_init(phydev);
 	if (ret < 0) {
 		dev_err(dev, "air_debug_procfs_init fail. (ret=%d)\n", ret);
-		air_debugfs_remove(phydev);
-		kfree(priv);
-		return ret;
+		airphy_debugfs_remove(phydev);
+		goto priv_free;
 	}
 #endif /* CONFIG_AIROHA_EN8811H_PHY_DEBUGFS */
 	retry = MAX_RETRY;
@@ -390,29 +381,36 @@
 			"Check MD32 FW Version(0x3b3c) : %08x\n", pbus_value);
 		dev_err(dev,
 			"EN8811H initialize fail!\n");
-		return 0;
+		goto priv_free;
 	}
 	/* Mode selection*/
 	dev_info(dev, "EN8811H Mode 1 !\n");
 	ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
 	if (ret < 0)
-		return ret;
+		goto priv_free;
 	ret = air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
 	if (ret < 0)
-		return ret;
+		goto priv_free;
 	ret = air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
 	if (ret < 0)
-		return ret;
+		goto priv_free;
 	ret = air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
 	if (ret < 0)
-		return ret;
+		goto priv_free;
 	/* Serdes polarity */
+	ret = en8811h_of_init(phydev);
+	if (ret < 0)
+		goto priv_free;
 	pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
 	pbus_value &= ~0x3;
+#if defined(CONFIG_OF)
+	pbus_value |= priv->pol;
+#else
 	pbus_value |= (EN8811H_RX_POL_NORMAL | EN8811H_TX_POL_NORMAL);
+#endif
 	ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
 	if (ret < 0)
-		return ret;
+		goto priv_free;
 	pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
 	dev_info(dev, "Tx, Rx Polarity : %08x\n", pbus_value);
 	pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
@@ -421,25 +419,29 @@
 	ret = en8811h_led_init(phydev);
 	if (ret < 0) {
 		dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
-		return ret;
+		goto priv_free;
 	}
 #endif
 	dev_info(dev, "EN8811H initialize OK! (%s)\n", EN8811H_DRIVER_VERSION);
 	return 0;
+priv_free:
+	kfree(priv);
+	return ret;
 }
 void en8811h_remove(struct phy_device *phydev)
 {
-#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+
 	struct en8811h_priv *priv = phydev->priv;
 	struct device *dev = phydev_dev(phydev);
 
 	dev_dbg(dev, "%s: start\n", __func__);
 	if (priv) {
-		dev_info(dev, "%s: air_debugfs_remove\n", __func__);
-		air_debugfs_remove(phydev);
+		dev_info(dev, "%s: airphy_debugfs_remove\n", __func__);
+#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+		airphy_debugfs_remove(phydev);
+#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
 		kfree(priv);
 	}
-#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
 }
 
 static struct phy_driver en8811h_driver[] = {
@@ -451,8 +453,8 @@
 	.remove         = en8811h_remove,
 #if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
 	.get_features   = en8811h_get_features,
-	.read_mmd       = air_mii_cl45_read,
-	.write_mmd      = air_mii_cl45_write,
+	.read_mmd       = __air_mii_cl45_read,
+	.write_mmd      = __air_mii_cl45_write,
 #endif
 } };
 
diff --git a/21.02/files/target/linux/mediatek/mt7981/base-files/lib/firmware/EthMD32.DSP.bin b/21.02/files/target/linux/mediatek/mt7981/base-files/lib/firmware/EthMD32.DSP.bin
index 23c3dd1..c5d66bf 100644
--- a/21.02/files/target/linux/mediatek/mt7981/base-files/lib/firmware/EthMD32.DSP.bin
+++ b/21.02/files/target/linux/mediatek/mt7981/base-files/lib/firmware/EthMD32.DSP.bin
Binary files differ
diff --git a/21.02/files/target/linux/mediatek/mt7981/base-files/lib/firmware/EthMD32.dm.bin b/21.02/files/target/linux/mediatek/mt7981/base-files/lib/firmware/EthMD32.dm.bin
index efb89b7..56b26f0 100644
--- a/21.02/files/target/linux/mediatek/mt7981/base-files/lib/firmware/EthMD32.dm.bin
+++ b/21.02/files/target/linux/mediatek/mt7981/base-files/lib/firmware/EthMD32.dm.bin
Binary files differ
diff --git a/21.02/files/target/linux/mediatek/mt7986/base-files/lib/firmware/EthMD32.DSP.bin b/21.02/files/target/linux/mediatek/mt7986/base-files/lib/firmware/EthMD32.DSP.bin
index 23c3dd1..c5d66bf 100644
--- a/21.02/files/target/linux/mediatek/mt7986/base-files/lib/firmware/EthMD32.DSP.bin
+++ b/21.02/files/target/linux/mediatek/mt7986/base-files/lib/firmware/EthMD32.DSP.bin
Binary files differ
diff --git a/21.02/files/target/linux/mediatek/mt7986/base-files/lib/firmware/EthMD32.dm.bin b/21.02/files/target/linux/mediatek/mt7986/base-files/lib/firmware/EthMD32.dm.bin
index efb89b7..56b26f0 100644
--- a/21.02/files/target/linux/mediatek/mt7986/base-files/lib/firmware/EthMD32.dm.bin
+++ b/21.02/files/target/linux/mediatek/mt7986/base-files/lib/firmware/EthMD32.dm.bin
Binary files differ
diff --git a/21.02/files/target/linux/mediatek/mt7988/base-files/lib/firmware/EthMD32.DSP.bin b/21.02/files/target/linux/mediatek/mt7988/base-files/lib/firmware/EthMD32.DSP.bin
index 23c3dd1..c5d66bf 100644
--- a/21.02/files/target/linux/mediatek/mt7988/base-files/lib/firmware/EthMD32.DSP.bin
+++ b/21.02/files/target/linux/mediatek/mt7988/base-files/lib/firmware/EthMD32.DSP.bin
Binary files differ
diff --git a/21.02/files/target/linux/mediatek/mt7988/base-files/lib/firmware/EthMD32.dm.bin b/21.02/files/target/linux/mediatek/mt7988/base-files/lib/firmware/EthMD32.dm.bin
index efb89b7..56b26f0 100644
--- a/21.02/files/target/linux/mediatek/mt7988/base-files/lib/firmware/EthMD32.dm.bin
+++ b/21.02/files/target/linux/mediatek/mt7988/base-files/lib/firmware/EthMD32.dm.bin
Binary files differ