[][kernel][mt7987][eth][net: phy: mediatek: Add support for mt7987 built-in 2.5Gphy]

[Description]
Add support for mt7987 built-in 2.5Gphy:
1. fix LED behaviors for mt7987.
2. Add firmware of 20240916 version:
  - Modify initial control of DAC and ANACAL flow
  - Update min IPG of FCM setup to PHY side
  - Update Efuse table configuration

[Release-log]
N/A

Change-Id: Ibd179ef7559dfb25e4d049b4ece90a9aaaa30611
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/9640512
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek/mtk-2p5ge.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek/mtk-2p5ge.c
index e3bb20f..87a91e9 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek/mtk-2p5ge.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek/mtk-2p5ge.c
@@ -12,16 +12,78 @@
 
 #include "mtk.h"
 
+#define MTK_2P5GPHY_ID_MT7987	(0x00339c91)
 #define MTK_2P5GPHY_ID_MT7988	(0x00339c11)
 
+#define MT7987_2P5GE_PMB_FW		"mediatek/mt7987/i2p5ge-phy-pmb.bin"
+#define MT7987_2P5GE_PMB_FW_SIZE	(0x18000)
+#define MT7987_2P5GE_DSPBITTB \
+	"mediatek/mt7987/i2p5ge-phy-DSPBitTb.bin"
+#define MT7987_2P5GE_DSPBITTB_SIZE	(0x7000)
+
 #define MT7988_2P5GE_PMB_FW		"mediatek/mt7988/i2p5ge-phy-pmb.bin"
 #define MT7988_2P5GE_PMB_FW_SIZE	(0x20000)
 #define MT7988_2P5GE_PMB_FW_BASE	(0x0f100000)
 #define MT7988_2P5GE_PMB_FW_LEN		(0x20000)
-#define MT7988_2P5GE_MD32_EN_CFG_BASE	(0x0f0f0018)
-#define MT7988_2P5GE_MD32_EN_CFG_LEN	(0x20)
+
+#define MTK_2P5GPHY_PMD_REG_BASE	(0x0f010000)
+#define MTK_2P5GPHY_PMD_REG_LEN		(0x210)
+#define DO_NOT_RESET			(0x28)
+#define   DO_NOT_RESET_XBZ		BIT(0)
+#define   DO_NOT_RESET_PMA		BIT(3)
+#define   DO_NOT_RESET_RX		BIT(5)
+#define FNPLL_PWR_CTRL1			(0x208)
+#define   RG_SPEED_MASK			GENMASK(3, 0)
+#define   RG_SPEED_2500			BIT(3)
+#define   RG_SPEED_100			BIT(0)
+#define FNPLL_PWR_CTRL_STATUS		(0x20c)
+#define   RG_STABLE_MASK		GENMASK(3, 0)
+#define   RG_SPEED_2500_STABLE		BIT(3)
+#define   RG_SPEED_100_STABLE		BIT(0)
+
+#define MTK_2P5GPHY_XBZ_PCS_REG_BASE	(0x0f030000)
+#define MTK_2P5GPHY_XBZ_PCS_REG_LEN	(0x844)
+#define PHY_CTRL_CONFIG			(0x200)
+#define PMU_WP				(0x800)
+#define   WRITE_PROTECT_KEY		(0xCAFEF00D)
+#define PMU_PMA_AUTO_CFG		(0x820)
+#define   POWER_ON_AUTO_MODE		BIT(16)
+#define   PMU_AUTO_MODE_EN		BIT(0)
+#define PMU_PMA_STATUS			(0x840)
+#define   CLK_IS_DISABLED		BIT(3)
+
+#define MTK_2P5GPHY_XBZ_PMA_RX_BASE	(0x0f080000)
+#define MTK_2P5GPHY_XBZ_PMA_RX_LEN	(0x5228)
+#define SMEM_WDAT0			(0x5000)
+#define SMEM_WDAT1			(0x5004)
+#define SMEM_WDAT2			(0x5008)
+#define SMEM_WDAT3			(0x500c)
+#define SMEM_CTRL			(0x5024)
+#define   SMEM_HW_RDATA_ZERO		BIT(24)
+#define SMEM_ADDR_REF_ADDR		(0x502c)
+#define CM_CTRL_P01			(0x5100)
+#define CM_CTRL_P23			(0x5124)
+#define DM_CTRL_P01			(0x5200)
+#define DM_CTRL_P23			(0x5224)
+
+#define MTK_2P5GPHY_CHIP_SCU_BASE	(0x0f0cf800)
+#define MTK_2P5GPHY_CHIP_SCU_LEN	(0x12c)
+#define SYS_SW_RESET			(0x128)
+#define   RESET_RST_CNT			BIT(0)
+
+#define MTK_2P5GPHY_MCU_CSR_BASE	(0x0f0f0000)
+#define MTK_2P5GPHY_MCU_CSR_LEN		(0x20)
+#define MD32_EN_CFG			(0x18)
 #define   MD32_EN			BIT(0)
 
+#define MTK_2P5GPHY_PMB_FW_BASE		(0x0f100000)
+//#define MTK_2P5GPHY_PMB_FW_LEN		MT7988_2P5GE_PMB_FW_SIZE
+
+#define MTK_2P5GPHY_APB_BASE		(0x11c30000)
+#define MTK_2P5GPHY_APB_LEN		(0x9c)
+#define SW_RESET			(0x94)
+#define   MD32_RESTART_EN_CLEAR		BIT(9)
+
 #define BASE100T_STATUS_EXTEND		(0x10)
 #define BASE1000T_STATUS_EXTEND		(0x11)
 #define EXTEND_CTRL_AND_STATUS		(0x16)
@@ -30,6 +92,15 @@
 #define   PHY_AUX_DPX_MASK		GENMASK(5, 5)
 #define   PHY_AUX_SPEED_MASK		GENMASK(4, 2)
 
+/* Registers on MDIO_MMD_VEND1 */
+#define MTK_PHY_LINK_STATUS_RELATED		(0x147)
+#define   MTK_PHY_BYPASS_LINK_STATUS_OK		BIT(4)
+#define   MTK_PHY_FORCE_LINK_STATUS_HCD		BIT(3)
+
+#define MTK_PHY_AN_FORCE_SPEED_REG		(0x313)
+#define   MTK_PHY_MASTER_FORCE_SPEED_SEL_EN	BIT(7)
+#define   MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK	GENMASK(6, 0)
+
 #define MTK_PHY_LPI_PCS_DSP_CTRL		(0x121)
 #define   MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK	GENMASK(12, 8)
 
@@ -48,14 +119,253 @@
 	PHY_AUX_SPD_2500,
 };
 
+static int mt7987_2p5ge_phy_load_fw(struct phy_device *phydev)
+{
+	struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
+	struct device *dev = &phydev->mdio.dev;
+	void __iomem *xbz_pcs_reg_base;
+	void __iomem *xbz_pma_rx_base;
+	void __iomem *chip_scu_base;
+	void __iomem *pmd_reg_base;
+	void __iomem *mcu_csr_base;
+	const struct firmware *fw;
+	void __iomem *apb_base;
+	void __iomem *pmb_addr;
+	int ret, i;
+	u32 reg;
+
+	if (priv->fw_loaded)
+		return 0;
+
+	apb_base = ioremap(MTK_2P5GPHY_APB_BASE,
+			   MTK_2P5GPHY_APB_LEN);
+	if (!apb_base)
+		return -ENOMEM;
+
+	pmd_reg_base = ioremap(MTK_2P5GPHY_PMD_REG_BASE,
+			       MTK_2P5GPHY_PMD_REG_LEN);
+	if (!pmd_reg_base) {
+		ret = -ENOMEM;
+		goto free_apb;
+	}
+
+	xbz_pcs_reg_base = ioremap(MTK_2P5GPHY_XBZ_PCS_REG_BASE,
+				   MTK_2P5GPHY_XBZ_PCS_REG_LEN);
+	if (!xbz_pcs_reg_base) {
+		ret = -ENOMEM;
+		goto free_pmd;
+	}
+
+	xbz_pma_rx_base = ioremap(MTK_2P5GPHY_XBZ_PMA_RX_BASE,
+				  MTK_2P5GPHY_XBZ_PMA_RX_LEN);
+	if (!xbz_pma_rx_base) {
+		ret = -ENOMEM;
+		goto free_pcs;
+	}
+
+	chip_scu_base = ioremap(MTK_2P5GPHY_CHIP_SCU_BASE,
+				MTK_2P5GPHY_CHIP_SCU_LEN);
+	if (!chip_scu_base) {
+		ret = -ENOMEM;
+		goto free_pma;
+	}
+
+	mcu_csr_base = ioremap(MTK_2P5GPHY_MCU_CSR_BASE,
+			       MTK_2P5GPHY_MCU_CSR_LEN);
+	if (!mcu_csr_base) {
+		ret = -ENOMEM;
+		goto free_chip_scu;
+	}
+
+	pmb_addr = ioremap(MTK_2P5GPHY_PMB_FW_BASE, MT7987_2P5GE_PMB_FW_SIZE);
+	if (!pmb_addr) {
+		return -ENOMEM;
+		goto free_mcu_csr;
+	}
+
+	ret = request_firmware(&fw, MT7987_2P5GE_PMB_FW, dev);
+	if (ret) {
+		dev_err(dev, "failed to load firmware: %s, ret: %d\n",
+			MT7987_2P5GE_PMB_FW, ret);
+		goto free_pmb_addr;
+	}
+
+	if (fw->size != MT7987_2P5GE_PMB_FW_SIZE) {
+		dev_err(dev, "PMb firmware size 0x%zx != 0x%x\n",
+			fw->size, MT7987_2P5GE_PMB_FW_SIZE);
+		ret = -EINVAL;
+		goto release_fw;
+	}
+
+	phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
+
+	reg = readw(apb_base + SW_RESET);
+	writew(reg & ~MD32_RESTART_EN_CLEAR, apb_base + SW_RESET);
+	writew(reg | MD32_RESTART_EN_CLEAR, apb_base + SW_RESET);
+	writew(reg & ~MD32_RESTART_EN_CLEAR, apb_base + SW_RESET);
+
+	reg = readw(mcu_csr_base + MD32_EN_CFG);
+	writew(reg & ~MD32_EN, mcu_csr_base + MD32_EN_CFG);
+
+	for (i = 0; i < MT7987_2P5GE_PMB_FW_SIZE - 1; i += 4)
+		writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
+	dev_info(dev, "Firmware date code: %x/%x/%x, version: %x.%x\n",
+		 be16_to_cpu(*((__be16 *)(fw->data +
+					  MT7987_2P5GE_PMB_FW_SIZE - 8))),
+		 *(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 6),
+		 *(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 5),
+		 *(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 2),
+		 *(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 1));
+	release_firmware(fw);
+
-static int mt798x_2p5ge_phy_load_fw(struct phy_device *phydev)
+	/* Enable 100Mbps module clock. */
+	writel(FIELD_PREP(RG_SPEED_MASK, RG_SPEED_100),
+	       pmd_reg_base + FNPLL_PWR_CTRL1);
+
+	/* Check if 100Mbps module clock is ready. */
+	ret = readl_poll_timeout(pmd_reg_base + FNPLL_PWR_CTRL_STATUS, reg,
+				 reg & RG_SPEED_100_STABLE, 1, 10000);
+	if (ret)
+		dev_err(dev, "Fail to enable 100Mbps module clock: %d\n", ret);
+
+	/* Enable 2.5Gbps module clock. */
+	writel(FIELD_PREP(RG_SPEED_MASK, RG_SPEED_2500),
+	       pmd_reg_base + FNPLL_PWR_CTRL1);
+
+	/* Check if 2.5Gbps module clock is ready. */
+	ret = readl_poll_timeout(pmd_reg_base + FNPLL_PWR_CTRL_STATUS, reg,
+				 reg & RG_SPEED_2500_STABLE, 1, 10000);
+
+	if (ret)
+		dev_err(dev, "Fail to enable 2.5Gbps module clock: %d\n", ret);
+
+	/* Disable AN */
+	phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE);
+
+	/* Force to run at 2.5G speed */
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_AN_FORCE_SPEED_REG,
+		       MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK,
+		       MTK_PHY_MASTER_FORCE_SPEED_SEL_EN |
+		       FIELD_PREP(MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK, 0x1b));
+
+	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_RELATED,
+			 MTK_PHY_BYPASS_LINK_STATUS_OK |
+			 MTK_PHY_FORCE_LINK_STATUS_HCD);
+
+	/* Set xbz, pma and rx as "do not reset" in order to input DSP code. */
+	reg = readl(pmd_reg_base + DO_NOT_RESET);
+	reg |= DO_NOT_RESET_XBZ | DO_NOT_RESET_PMA | DO_NOT_RESET_RX;
+	writel(reg, pmd_reg_base + DO_NOT_RESET);
+
+	reg = readl(chip_scu_base + SYS_SW_RESET);
+	writel(reg & ~RESET_RST_CNT, chip_scu_base + SYS_SW_RESET);
+
+	writel(WRITE_PROTECT_KEY, xbz_pcs_reg_base + PMU_WP);
+
+	reg = readl(xbz_pcs_reg_base + PMU_PMA_AUTO_CFG);
+	reg |= PMU_AUTO_MODE_EN | POWER_ON_AUTO_MODE;
+	writel(reg, xbz_pcs_reg_base + PMU_PMA_AUTO_CFG);
+
+	/* Check if clock in auto mode is disabled. */
+	ret = readl_poll_timeout(xbz_pcs_reg_base + PMU_PMA_STATUS, reg,
+				 (reg & CLK_IS_DISABLED) == 0x0, 1, 100000);
+	if (ret)
+		dev_err(dev, "Clock isn't disabled in auto mode: %d\n", ret);
+
+	reg = readl(xbz_pma_rx_base + SMEM_CTRL);
+	writel(reg | SMEM_HW_RDATA_ZERO, xbz_pma_rx_base + SMEM_CTRL);
+
+	reg = readl(xbz_pcs_reg_base + PHY_CTRL_CONFIG);
+	writel(reg | BIT(16), xbz_pcs_reg_base + PHY_CTRL_CONFIG);
+
+	/* Initialize data memory */
+	reg = readl(xbz_pma_rx_base + DM_CTRL_P01);
+	writel(reg | BIT(28), xbz_pma_rx_base + DM_CTRL_P01);
+	reg = readl(xbz_pma_rx_base + DM_CTRL_P23);
+	writel(reg | BIT(28), xbz_pma_rx_base + DM_CTRL_P23);
+
+	/* Initialize coefficient memory */
+	reg = readl(xbz_pma_rx_base + CM_CTRL_P01);
+	writel(reg | BIT(28), xbz_pma_rx_base + CM_CTRL_P01);
+	reg = readl(xbz_pma_rx_base + CM_CTRL_P23);
+	writel(reg | BIT(28), xbz_pma_rx_base + CM_CTRL_P23);
+
+	/* Initilize PM offset */
+	writel(0, xbz_pma_rx_base + SMEM_ADDR_REF_ADDR);
+
+	ret = request_firmware(&fw, MT7987_2P5GE_DSPBITTB, dev);
+	if (ret) {
+		dev_err(dev, "failed to load firmware: %s, ret: %d\n",
+			MT7987_2P5GE_DSPBITTB, ret);
+		goto free_pmb_addr;
+	}
+	if (fw->size != MT7987_2P5GE_DSPBITTB_SIZE) {
+		dev_err(dev, "DSPBITTB size 0x%zx != 0x%x\n",
+			fw->size, MT7987_2P5GE_DSPBITTB_SIZE);
+		ret = -EINVAL;
+		goto release_fw;
+	}
+
+	for (i = 0; i < fw->size - 1; i += 16) {
+		writel(*((uint32_t *)(fw->data + i)),
+		       xbz_pma_rx_base + SMEM_WDAT0);
+		writel(*((uint32_t *)(fw->data + i + 0x4)),
+		       xbz_pma_rx_base + SMEM_WDAT1);
+		writel(*((uint32_t *)(fw->data + i + 0x8)),
+		       xbz_pma_rx_base + SMEM_WDAT2);
+		writel(*((uint32_t *)(fw->data + i + 0xc)),
+		       xbz_pma_rx_base + SMEM_WDAT3);
+	}
+
+	reg = readl(xbz_pma_rx_base + DM_CTRL_P01);
+	writel(reg & ~BIT(28), xbz_pma_rx_base + DM_CTRL_P01);
+
+	reg = readl(xbz_pma_rx_base + DM_CTRL_P23);
+	writel(reg & ~BIT(28), xbz_pma_rx_base + DM_CTRL_P23);
+
+	reg = readl(xbz_pma_rx_base + CM_CTRL_P01);
+	writel(reg & ~BIT(28), xbz_pma_rx_base + CM_CTRL_P01);
+
+	reg = readl(xbz_pma_rx_base + CM_CTRL_P23);
+	writel(reg & ~BIT(28), xbz_pma_rx_base + CM_CTRL_P23);
+
+	reg = readw(mcu_csr_base + MD32_EN_CFG);
+	writew(reg | MD32_EN, mcu_csr_base + MD32_EN_CFG);
+	phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
+	/* We need a delay here to stabilize initialization of MCU */
+	usleep_range(7000, 8000);
+	dev_info(dev, "Firmware loading/trigger ok.\n");
+
+	priv->fw_loaded = true;
+
+release_fw:
+	release_firmware(fw);
+free_pmb_addr:
+	iounmap(pmb_addr);
+free_mcu_csr:
+	iounmap(mcu_csr_base);
+free_chip_scu:
+	iounmap(chip_scu_base);
+free_pma:
+	iounmap(xbz_pma_rx_base);
+free_pcs:
+	iounmap(xbz_pcs_reg_base);
+free_pmd:
+	iounmap(pmd_reg_base);
+free_apb:
+	iounmap(apb_base);
+
+	return ret;
+}
+
+static int mt7988_2p5ge_phy_load_fw(struct phy_device *phydev)
 {
 	struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
-	void __iomem *md32_en_cfg_base, *pmb_addr;
+	void __iomem *mcu_csr_base, *pmb_addr;
 	struct device *dev = &phydev->mdio.dev;
 	const struct firmware *fw;
 	int ret, i;
-	u16 reg;
+	u32 reg;
 
 	if (priv->fw_loaded)
 		return 0;
@@ -63,13 +373,16 @@
 	pmb_addr = ioremap(MT7988_2P5GE_PMB_FW_BASE, MT7988_2P5GE_PMB_FW_LEN);
 	if (!pmb_addr)
 		return -ENOMEM;
-	md32_en_cfg_base = ioremap(MT7988_2P5GE_MD32_EN_CFG_BASE,
-				   MT7988_2P5GE_MD32_EN_CFG_LEN);
-	if (!md32_en_cfg_base) {
+	mcu_csr_base = ioremap(MTK_2P5GPHY_MCU_CSR_BASE,
+			       MTK_2P5GPHY_MCU_CSR_LEN);
+	if (!mcu_csr_base) {
 		ret = -ENOMEM;
 		goto free_pmb;
 	}
 
+	reg = readw(mcu_csr_base + MD32_EN_CFG);
+	writew(reg | MD32_EN, mcu_csr_base + MD32_EN_CFG);
+
 	ret = request_firmware(&fw, MT7988_2P5GE_PMB_FW, dev);
 	if (ret) {
 		dev_err(dev, "failed to load firmware: %s, ret: %d\n",
@@ -84,7 +397,7 @@
 		goto release_fw;
 	}
 
-	reg = readw(md32_en_cfg_base);
+	reg = readw(mcu_csr_base + MD32_EN_CFG);
 	if (reg & MD32_EN) {
 		phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
 		usleep_range(10000, 11000);
@@ -105,8 +418,8 @@
 		 *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 2),
 		 *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 1));
 
-	writew(reg & ~MD32_EN, md32_en_cfg_base);
-	writew(reg | MD32_EN, md32_en_cfg_base);
+	writew(reg & ~MD32_EN, mcu_csr_base + MD32_EN_CFG);
+	writew(reg | MD32_EN, mcu_csr_base + MD32_EN_CFG);
 	phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
 	/* We need a delay here to stabilize initialization of MCU */
 	usleep_range(7000, 8000);
@@ -117,7 +430,7 @@
 release_fw:
 	release_firmware(fw);
 free:
-	iounmap(md32_en_cfg_base);
+	iounmap(mcu_csr_base);
 free_pmb:
 	iounmap(pmb_addr);
 
@@ -133,15 +446,27 @@
 	if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL)
 		return -ENODEV;
 
-	ret = mt798x_2p5ge_phy_load_fw(phydev);
+	switch (phydev->drv->phy_id) {
+	case MTK_2P5GPHY_ID_MT7987:
+		ret = mt7987_2p5ge_phy_load_fw(phydev);
+		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
+				   MTK_PHY_LED_ON_POLARITY);
+		break;
+	case MTK_2P5GPHY_ID_MT7988:
+		ret = mt7988_2p5ge_phy_load_fw(phydev);
+		phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
+				 MTK_PHY_LED_ON_POLARITY);
+		break;
+	default:
+		return -EINVAL;
+	}
 	if (ret < 0)
 		return ret;
 
 	/* Setup LED */
 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
-			 MTK_PHY_LED_ON_POLARITY | MTK_PHY_LED_ON_LINK10 |
-			 MTK_PHY_LED_ON_LINK100 | MTK_PHY_LED_ON_LINK1000 |
-			 MTK_PHY_LED_ON_LINK2500);
+			 MTK_PHY_LED_ON_LINK10 | MTK_PHY_LED_ON_LINK100 |
+			 MTK_PHY_LED_ON_LINK1000 | MTK_PHY_LED_ON_LINK2500);
 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL,
 			 MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX);
 
@@ -299,6 +624,7 @@
 		return -ENOMEM;
 
 	switch (phydev->drv->phy_id) {
+	case MTK_2P5GPHY_ID_MT7987:
 	case MTK_2P5GPHY_ID_MT7988:
 		/* The original hardware only sets MDIO_DEVS_PMAPMD */
 		phydev->c45_ids.devices_in_package |= MDIO_DEVS_PCS |
@@ -318,6 +644,20 @@
 
 static struct phy_driver mtk_2p5gephy_driver[] = {
 	{
+		PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7987),
+		.name = "MediaTek MT7987 2.5GbE PHY",
+		.probe = mt798x_2p5ge_phy_probe,
+		.config_init = mt798x_2p5ge_phy_config_init,
+		.config_aneg = mt798x_2p5ge_phy_config_aneg,
+		.get_features = mt798x_2p5ge_phy_get_features,
+		.read_status = mt798x_2p5ge_phy_read_status,
+		.get_rate_matching = mt798x_2p5ge_phy_get_rate_matching,
+		.suspend = genphy_suspend,
+		.resume = genphy_resume,
+		.read_page = mtk_phy_read_page,
+		.write_page = mtk_phy_write_page,
+	},
+	{
 		PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7988),
 		.name = "MediaTek MT7988 2.5GbE PHY",
 		.probe = mt798x_2p5ge_phy_probe,
diff --git a/21.02/files/target/linux/mediatek/mt7987/base-files/lib/firmware/mediatek/mt7987/i2p5ge-phy-DSPBitTb.bin b/21.02/files/target/linux/mediatek/mt7987/base-files/lib/firmware/mediatek/mt7987/i2p5ge-phy-DSPBitTb.bin
new file mode 100644
index 0000000..5b0e44c
--- /dev/null
+++ b/21.02/files/target/linux/mediatek/mt7987/base-files/lib/firmware/mediatek/mt7987/i2p5ge-phy-DSPBitTb.bin
Binary files differ
diff --git a/21.02/files/target/linux/mediatek/mt7987/base-files/lib/firmware/mediatek/mt7987/i2p5ge-phy-pmb.bin b/21.02/files/target/linux/mediatek/mt7987/base-files/lib/firmware/mediatek/mt7987/i2p5ge-phy-pmb.bin
new file mode 100644
index 0000000..991c319
--- /dev/null
+++ b/21.02/files/target/linux/mediatek/mt7987/base-files/lib/firmware/mediatek/mt7987/i2p5ge-phy-pmb.bin
Binary files differ