]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
mediatek: import patches from SDK to support MT7987 Ethernet
authorDaniel Golle <daniel@makrotopia.org>
Sun, 5 Oct 2025 02:39:52 +0000 (03:39 +0100)
committerDaniel Golle <daniel@makrotopia.org>
Wed, 5 Nov 2025 14:19:39 +0000 (14:19 +0000)
Compared to MT7988 (NETSYSv3) the Ethernet Frame Engine of MT7987
has been slighly updated (NETSYSv3.1), among other things the packet
scheduler (shaper) has apparently been reworked.
Import patches for basic support of the Ethernet Frame Engine of the
MT7987 SoC.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
target/linux/generic/pending-6.12/737-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch
target/linux/mediatek/patches-6.12/740-net-pcs-mtk_lynxi-add-mt7987-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-6.12/741-net-pcs-mtk-lynxi-add-phya-tx-rx-clock-path.patch [new file with mode: 0644]
target/linux/mediatek/patches-6.12/750-net-ethernet-mtk_eth_soc-add-mt7987-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-6.12/751-net-ethernet-mtk_eth_soc-revise-hardware-configuration-for-mt7987.patch [new file with mode: 0644]
target/linux/mediatek/patches-6.12/752-net-phy-mediatek-i2p5g-add-support-for-mt7987.patch [new file with mode: 0644]

index 165eb1e45c400c7f02e7c3109c7527492541edbb..46ad32a9da9e248909332800a38a8aa60268f00b 100644 (file)
@@ -544,7 +544,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 +      }
 +
 +      if (mtk_is_netsys_v3_or_greater(eth) && (mac->sgmii_pcs || mac->usxgmii_pcs)) {
-+              mac->pextp = devm_of_phy_get(eth->dev, mac->of_node, NULL);
++              mac->pextp = devm_of_phy_optional_get(eth->dev, mac->of_node, NULL);
 +              if (IS_ERR(mac->pextp)) {
 +                      if (PTR_ERR(mac->pextp) != -EPROBE_DEFER)
 +                              dev_err(eth->dev, "cannot get PHY, error %ld\n",
diff --git a/target/linux/mediatek/patches-6.12/740-net-pcs-mtk_lynxi-add-mt7987-support.patch b/target/linux/mediatek/patches-6.12/740-net-pcs-mtk_lynxi-add-mt7987-support.patch
new file mode 100644 (file)
index 0000000..d4d09b6
--- /dev/null
@@ -0,0 +1,36 @@
+From 6e9ec5ade644eeb136c6b827d72fac80bf2c3817 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Fri, 9 May 2025 13:22:14 +0800
+Subject: [PATCH] net: pcs: mtk_lynxi add mt7987 support
+
+Signed-off-by: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+---
+ drivers/net/pcs/pcs-mtk-lynxi.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/pcs/pcs-mtk-lynxi.c
++++ b/drivers/net/pcs/pcs-mtk-lynxi.c
+@@ -413,9 +413,12 @@ static int mtk_pcs_lynxi_probe(struct pl
+       if (of_property_read_bool(np->parent, "mediatek,pnswap"))
+               flags |= MTK_SGMII_FLAG_PN_SWAP;
+-      mpcs->rstc = of_reset_control_get_shared(np->parent, NULL);
+-      if (IS_ERR(mpcs->rstc))
+-              return PTR_ERR(mpcs->rstc);
++      if (of_parse_phandle(np->parent, "resets", 0)) {
++              mpcs->rstc = of_reset_control_get_shared(np->parent, NULL);
++              if (IS_ERR(mpcs->rstc))
++                      return PTR_ERR(mpcs->rstc);
++      } else
++              mpcs->rstc = NULL;
+       reset_control_deassert(mpcs->rstc);
+       mpcs->sgmii_sel = devm_clk_get_enabled(dev, "sgmii_sel");
+@@ -462,6 +465,7 @@ static void mtk_pcs_lynxi_remove(struct
+ }
+ static const struct of_device_id mtk_pcs_lynxi_of_match[] = {
++      { .compatible = "mediatek,mt7987-sgmii", .data = (void *)MTK_NETSYS_V3_AMA_RGC3 },
+       { .compatible = "mediatek,mt7988-sgmii", .data = (void *)MTK_NETSYS_V3_AMA_RGC3 },
+       { /* sentinel */ },
+ };
diff --git a/target/linux/mediatek/patches-6.12/741-net-pcs-mtk-lynxi-add-phya-tx-rx-clock-path.patch b/target/linux/mediatek/patches-6.12/741-net-pcs-mtk-lynxi-add-phya-tx-rx-clock-path.patch
new file mode 100644 (file)
index 0000000..eef6e36
--- /dev/null
@@ -0,0 +1,89 @@
+From be193994deca7cc3ca6ddedc6efd06182b032f21 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Tue, 6 May 2025 12:53:37 +0800
+Subject: [PATCH] net: pcs: mtk-lynxi: add phya tx rx clock path
+
+In NETSYSv3.1, the SGMII hardware introduces a new clock path from PHYA.
+Consequently, users can switch the SGMII PCS to this new clock source
+for better performance on the MT7987.
+
+Signed-off-by: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+---
+--- a/drivers/net/pcs/pcs-mtk-lynxi.c
++++ b/drivers/net/pcs/pcs-mtk-lynxi.c
+@@ -25,6 +25,7 @@
+ #define SGMSYS_PCS_CONTROL_1          0x0
+ #define SGMII_BMCR                    GENMASK(15, 0)
+ #define SGMII_BMSR                    GENMASK(31, 16)
++#define SGMII_REF_CK_SEL              BIT(24)
+ #define SGMSYS_PCS_DEVICE_ID          0x4
+ #define SGMII_LYNXI_DEV_ID            0x4d544950
+@@ -52,6 +53,8 @@
+ #define SGMII_SPEED_1000              FIELD_PREP(SGMII_SPEED_MASK, 2)
+ #define SGMII_DUPLEX_HALF             BIT(4)
+ #define SGMII_REMOTE_FAULT_DIS                BIT(8)
++#define SGMII_TRXBUF_THR_MASK         GENMASK(31, 16)
++#define SGMII_TRXBUF_THR(x)           FIELD_PREP(SGMII_TRXBUF_THR_MASK, (x))
+ /* Register to reset SGMII design */
+ #define SGMSYS_RESERVED_0             0x34
+@@ -166,7 +169,7 @@ static int mtk_pcs_lynxi_config(struct p
+ {
+       struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
+       bool mode_changed = false, changed;
+-      unsigned int rgc3, sgm_mode, bmcr = 0;
++      unsigned int rgc3, sgm_mode, bmcr = 0, trxbuf_thr = 0x3112;
+       int advertise, link_timer;
+       advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
+@@ -193,6 +196,12 @@ static int mtk_pcs_lynxi_config(struct p
+                       bmcr = BMCR_ANENABLE;
+       }
++      /* Configure SGMII PCS clock source */
++      if (mpcs->flags & MTK_SGMII_FLAG_PHYA_TRX_CK) {
++              bmcr |= SGMII_REF_CK_SEL;
++              trxbuf_thr = 0x2111;
++      }
++
+       if (mpcs->interface != interface) {
+               link_timer = phylink_get_link_timer_ns(interface);
+               if (link_timer < 0)
+@@ -235,12 +244,14 @@ static int mtk_pcs_lynxi_config(struct p
+       /* Update the sgmsys mode register */
+       regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
++                         SGMII_TRXBUF_THR_MASK |
+                          SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN |
+-                         SGMII_IF_MODE_SGMII, sgm_mode);
++                         SGMII_IF_MODE_SGMII,
++                         SGMII_TRXBUF_THR(trxbuf_thr) | sgm_mode);
+       /* Update the BMCR */
+       regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
+-                         BMCR_ANENABLE, bmcr);
++                         SGMII_REF_CK_SEL | BMCR_ANENABLE, bmcr);
+       /* Release PHYA power down state
+        * Only removing bit SGMII_PHYA_PWD isn't enough.
+@@ -413,6 +424,9 @@ static int mtk_pcs_lynxi_probe(struct pl
+       if (of_property_read_bool(np->parent, "mediatek,pnswap"))
+               flags |= MTK_SGMII_FLAG_PN_SWAP;
++      if (of_property_read_bool(np->parent, "mediatek,phya_trx_ck"))
++              flags |= MTK_SGMII_FLAG_PHYA_TRX_CK;
++
+       if (of_parse_phandle(np->parent, "resets", 0)) {
+               mpcs->rstc = of_reset_control_get_shared(np->parent, NULL);
+               if (IS_ERR(mpcs->rstc))
+--- a/include/linux/pcs/pcs-mtk-lynxi.h
++++ b/include/linux/pcs/pcs-mtk-lynxi.h
+@@ -6,6 +6,7 @@
+ #include <linux/regmap.h>
+ #define MTK_SGMII_FLAG_PN_SWAP BIT(0)
++#define MTK_SGMII_FLAG_PHYA_TRX_CK BIT(2)
+ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
+                                        struct regmap *regmap,
+                                        u32 ana_rgc3, u32 flags);
diff --git a/target/linux/mediatek/patches-6.12/750-net-ethernet-mtk_eth_soc-add-mt7987-support.patch b/target/linux/mediatek/patches-6.12/750-net-ethernet-mtk_eth_soc-add-mt7987-support.patch
new file mode 100644 (file)
index 0000000..238e7a7
--- /dev/null
@@ -0,0 +1,325 @@
+From 56973433cbea9f91f5f7eddebbc361ffc2bd6156 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Mon, 26 May 2025 13:20:42 +0800
+Subject: [PATCH] net: ethernet: mtk_eth_soc: add mt7987 support
+
+Without this patch, users are unable to bring up ETH driver on the
+mt7987.
+
+Signed-off-by: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_path.c |   9 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c  | 138 ++++++++++++++++---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h  |  70 ++++++++--
+ 3 files changed, 179 insertions(+), 38 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_path.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c
+@@ -106,13 +106,14 @@ static int set_mux_gmac2_gmac0_to_gephy(
+       return 0;
+ }
+-static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)
++static int set_mux_u3_gmac23_to_qphy(struct mtk_eth *eth, u64 path)
+ {
+       unsigned int val = 0, mask = 0, reg = 0;
+       bool updated = true;
+       switch (path) {
+       case MTK_ETH_PATH_GMAC2_SGMII:
++      case MTK_ETH_PATH_GMAC3_SGMII:
+               if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) {
+                       reg = USB_PHY_SWITCH_REG;
+                       val = SGMII_QPHY_SEL;
+@@ -281,9 +282,9 @@ static const struct mtk_eth_muxc mtk_eth
+               .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
+               .set_path = set_mux_gmac2_gmac0_to_gephy,
+       }, {
+-              .name = "mux_u3_gmac2_to_qphy",
+-              .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
+-              .set_path = set_mux_u3_gmac2_to_qphy,
++              .name = "mux_u3_gmac23_to_qphy",
++              .cap_bit = MTK_ETH_MUX_U3_GMAC23_TO_QPHY,
++              .set_path = set_mux_u3_gmac23_to_qphy,
+       }, {
+               .name = "mux_gmac2_to_2p5gphy",
+               .cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY,
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -817,10 +817,16 @@ static void mtk_set_queue_speed(struct m
+               return;
+       val = MTK_QTX_SCH_MIN_RATE_EN |
+-            /* minimum: 10 Mbps */
+-            FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
+-            FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
+             MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
++      /* minimum: 10 Mbps */
++      if (mtk_is_netsys_v3_or_greater(eth) &&
++          (eth->soc->caps != MT7988_CAPS)) {
++              val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN_V3, 1) |
++                     FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP_V3, 4);
++      } else {
++              val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
++                     FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4);
++      }
+       if (mtk_is_netsys_v1(eth))
+               val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;
+@@ -847,6 +853,30 @@ static void mtk_set_queue_speed(struct m
+               default:
+                       break;
+               }
++      } else if (mtk_is_netsys_v3_or_greater(eth) &&
++                 (eth->soc->caps != MT7988_CAPS)) {
++              switch (speed) {
++              case SPEED_10:
++                      val |= MTK_QTX_SCH_MAX_RATE_EN_V3 |
++                             FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN_V3, 1) |
++                             FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP_V3, 4) |
++                             FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT_V3, 1);
++                      break;
++              case SPEED_100:
++                      val |= MTK_QTX_SCH_MAX_RATE_EN_V3 |
++                             FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN_V3, 1) |
++                             FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP_V3, 5) |
++                             FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT_V3, 1);
++                      break;
++              case SPEED_1000:
++                      val |= MTK_QTX_SCH_MAX_RATE_EN_V3 |
++                             FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN_V3, 1) |
++                             FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP_V3, 6) |
++                             FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT_V3, 10);
++                      break;
++              default:
++                      break;
++              }
+       } else {
+               switch (speed) {
+               case SPEED_10:
+@@ -935,7 +965,7 @@ static void mtk_xgdm_mac_link_up(struct
+               return;
+       /* Eliminate the interference(before link-up) caused by PHY noise */
+-      mtk_m32(mac->hw, XMAC_LOGIC_RST, 0, MTK_XMAC_LOGIC_RST(mac->id));
++      mtk_m32(mac->hw, XMAC_LOGIC_RST, 0, MTK_XMAC_LOGIC_RST(mac->hw, mac->id));
+       mdelay(20);
+       mtk_m32(mac->hw, XMAC_GLB_CNTCLR, XMAC_GLB_CNTCLR, MTK_XMAC_CNT_CTRL(mac->id));
+@@ -2901,10 +2931,16 @@ static int mtk_tx_alloc(struct mtk_eth *
+                       mtk_w32(eth, val, soc->reg_map->qdma.qtx_cfg + ofs);
+                       val = MTK_QTX_SCH_MIN_RATE_EN |
+-                            /* minimum: 10 Mbps */
+-                            FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
+-                            FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
+                             MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
++                      /* minimum: 10 Mbps */
++                      if (mtk_is_netsys_v3_or_greater(eth) &&
++                          (eth->soc->caps != MT7988_CAPS)) {
++                              val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN_V3, 1) |
++                                     FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP_V3, 4);
++                      } else {
++                              val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
++                                     FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4);
++                      }
+                       if (mtk_is_netsys_v1(eth))
+                               val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;
+                       mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);
+@@ -5873,6 +5909,36 @@ static const struct mtk_soc_data mt7986_
+       },
+ };
++static const struct mtk_soc_data mt7987_data = {
++      .reg_map = &mt7988_reg_map,
++      .ana_rgc3 = 0x128,
++      .caps = MT7987_CAPS,
++      .hw_features = MTK_HW_FEATURES,
++      .required_clks = MT7987_CLKS_BITMAP,
++      .required_pctl = false,
++      .version = 3,
++      .offload_version = 2,
++      .ppe_num = 2,
++      .hash_offset = 4,
++      .has_accounting = true,
++      .foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
++      .tx = {
++              DESC_SIZE(struct mtk_tx_dma_v2),
++              .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
++              .dma_len_offset = 8,
++              .dma_size = MTK_DMA_SIZE(2K),
++              .fq_dma_size = MTK_DMA_SIZE(4K),
++      },
++      .rx = {
++              DESC_SIZE(struct mtk_rx_dma_v2),
++              .irq_done_mask = MTK_RX_DONE_INT_V2,
++              .dma_l4_valid = RX_DMA_L4_VALID_V2,
++              .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
++              .dma_len_offset = 8,
++              .dma_size = MTK_DMA_SIZE(2K),
++      },
++};
++
+ static const struct mtk_soc_data mt7988_data = {
+       .reg_map = &mt7988_reg_map,
+       .ana_rgc3 = 0x128,
+@@ -5934,6 +6000,7 @@ const struct of_device_id of_mtk_match[]
+       { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data },
+       { .compatible = "mediatek,mt7981-eth", .data = &mt7981_data },
+       { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data },
++      { .compatible = "mediatek,mt7987-eth", .data = &mt7987_data },
+       { .compatible = "mediatek,mt7988-eth", .data = &mt7988_data },
+       { .compatible = "ralink,rt5350-eth", .data = &rt5350_data },
+       {},
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -262,6 +262,13 @@
+ #define MTK_QTX_SCH_MAX_RATE_MAN      GENMASK(10, 4)
+ #define MTK_QTX_SCH_MAX_RATE_EXP      GENMASK(3, 0)
++#define MTK_QTX_SCH_MAX_RATE_EN_V3    BIT(26)
++#define MTK_QTX_SCH_MIN_RATE_MAN_V3   GENMASK(25, 19)
++#define MTK_QTX_SCH_MIN_RATE_EXP_V3   GENMASK(18, 16)
++#define MTK_QTX_SCH_MAX_RATE_WEIGHT_V3        GENMASK(15, 10)
++#define MTK_QTX_SCH_MAX_RATE_MAN_V3   GENMASK(9, 3)
++#define MTK_QTX_SCH_MAX_RATE_EXP_V3   GENMASK(2, 0)
++
+ /* QDMA TX Scheduler Rate Control Register */
+ #define MTK_QDMA_TX_SCH_MAX_WFQ               BIT(15)
+@@ -536,9 +543,23 @@
+ #define XMAC_MCR_FORCE_RX_FC  BIT(4)
+ /* XFI Mac logic reset registers */
+-#define MTK_XMAC_LOGIC_RST(x) (MTK_XMAC_BASE(x) + 0x10)
++#define MTK_XMAC_LOGIC_RST(eth, x)    (MTK_XMAC_BASE(x) +                             \
++                                      (MTK_HAS_CAPS((eth)->soc->caps, MTK_XGMAC_V2) ? \
++                                      0x820 : 0x10))
+ #define XMAC_LOGIC_RST                BIT(0)
++/* XFI Mac status force registers */
++#define MTK_XMAC_STS(x)               (MTK_XMAC_MCR(x) + 0x14)
++
++/* XFI Mac status force registers */
++#define MTK_XMAC_STS_FRC(x)   (MTK_XMAC_MCR(x) + 0x18)
++#define XMAC_FORCE_RX_FC_MODE BIT(13)
++#define XMAC_FORCE_TX_FC_MODE BIT(12)
++#define XMAC_FORCE_LINK_MODE  BIT(8)
++#define XMAC_FORCE_RX_FC      BIT(5)
++#define XMAC_FORCE_TX_FC      BIT(4)
++#define XMAC_FORCE_LINK               BIT(0)
++
+ /* XFI Mac count global control */
+ #define MTK_XMAC_CNT_CTRL(x)  (MTK_XMAC_BASE(x) + 0x100)
+ #define XMAC_GLB_CNTCLR               BIT(0)
+@@ -834,6 +855,17 @@ enum mtk_clks_map {
+                                BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \
+                                BIT_ULL(MTK_CLK_SGMII2_CDR_REF) | \
+                                BIT_ULL(MTK_CLK_SGMII2_CDR_FB))
++#define MT7987_CLKS_BITMAP    (BIT_ULL(MTK_CLK_FE) |  BIT_ULL(MTK_CLK_GP1) | \
++                               BIT_ULL(MTK_CLK_GP2) | BIT_ULL(MTK_CLK_GP3) | \
++                               BIT_ULL(MTK_CLK_TOP_ETH_GMII_SEL) | \
++                               BIT_ULL(MTK_CLK_TOP_ETH_REFCK_50M_SEL) | \
++                               BIT_ULL(MTK_CLK_TOP_ETH_SYS_200M_SEL) | \
++                               BIT_ULL(MTK_CLK_TOP_ETH_SYS_SEL) | \
++                               BIT_ULL(MTK_CLK_TOP_ETH_XGMII_SEL) | \
++                               BIT_ULL(MTK_CLK_TOP_ETH_MII_SEL) | \
++                               BIT_ULL(MTK_CLK_TOP_NETSYS_SEL) | \
++                               BIT_ULL(MTK_CLK_TOP_NETSYS_500M_SEL) | \
++                               BIT_ULL(MTK_CLK_TOP_NETSYS_PAO_2X_SEL))
+ #define MT7988_CLKS_BITMAP    (BIT_ULL(MTK_CLK_FE) | BIT_ULL(MTK_CLK_ESW) | \
+                                BIT_ULL(MTK_CLK_GP1) | BIT_ULL(MTK_CLK_GP2) | \
+                                BIT_ULL(MTK_CLK_GP3) | BIT_ULL(MTK_CLK_XGP1) | \
+@@ -990,12 +1022,14 @@ enum mkt_eth_capabilities {
+       MTK_RSTCTRL_PPE2_BIT,
+       MTK_U3_COPHY_V2_BIT,
+       MTK_SRAM_BIT,
++      MTK_XGMAC_BIT,
++      MTK_XGMAC_V2_BIT,
+       MTK_36BIT_DMA_BIT,
+       /* MUX BITS*/
+       MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
+       MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT,
+-      MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT,
++      MTK_ETH_MUX_U3_GMAC23_TO_QPHY_BIT,
+       MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT,
+       MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT,
+       MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT,
+@@ -1037,14 +1071,16 @@ enum mkt_eth_capabilities {
+ #define MTK_RSTCTRL_PPE2      BIT_ULL(MTK_RSTCTRL_PPE2_BIT)
+ #define MTK_U3_COPHY_V2               BIT_ULL(MTK_U3_COPHY_V2_BIT)
+ #define MTK_SRAM              BIT_ULL(MTK_SRAM_BIT)
++#define MTK_XGMAC             BIT_ULL(MTK_XGMAC_BIT)
++#define MTK_XGMAC_V2          BIT_ULL(MTK_XGMAC_V2_BIT)
+ #define MTK_36BIT_DMA BIT_ULL(MTK_36BIT_DMA_BIT)
+ #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW         \
+       BIT_ULL(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
+ #define MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY      \
+       BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT)
+-#define MTK_ETH_MUX_U3_GMAC2_TO_QPHY          \
+-      BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT)
++#define MTK_ETH_MUX_U3_GMAC23_TO_QPHY         \
++      BIT_ULL(MTK_ETH_MUX_U3_GMAC23_TO_QPHY_BIT)
+ #define MTK_ETH_MUX_GMAC2_TO_2P5GPHY          \
+       BIT_ULL(MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT)
+ #define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII        \
+@@ -1076,12 +1112,13 @@ enum mkt_eth_capabilities {
+ #define MTK_GMAC2_RGMII               (MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII)
+ #define MTK_GMAC2_SGMII               (MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII)
+ #define MTK_GMAC2_GEPHY               (MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY)
+-#define MTK_GMAC2_2P5GPHY     (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY)
++#define MTK_GMAC2_2P5GPHY     (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY | MTK_XGMAC)
++#define MTK_GMAC2_2P5GPHY_V2  (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY | MTK_XGMAC_V2)
+ #define MTK_GMAC3_SGMII               (MTK_ETH_PATH_GMAC3_SGMII | MTK_SGMII)
+ #define MTK_GDM1_ESW          (MTK_ETH_PATH_GDM1_ESW | MTK_ESW)
+-#define MTK_GMAC1_USXGMII     (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII)
+-#define MTK_GMAC2_USXGMII     (MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII)
+-#define MTK_GMAC3_USXGMII     (MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII)
++#define MTK_GMAC1_USXGMII     (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII | MTK_XGMAC)
++#define MTK_GMAC2_USXGMII     (MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII | MTK_XGMAC)
++#define MTK_GMAC3_USXGMII     (MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII | MTK_XGMAC)
+ /* MUXes present on SoCs */
+ /* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */
+@@ -1091,9 +1128,9 @@ enum mkt_eth_capabilities {
+ #define MTK_MUX_GMAC2_GMAC0_TO_GEPHY    \
+       (MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY | MTK_MUX | MTK_INFRA)
+-/* 0: U3 -> QPHY, 1: GMAC2 -> QPHY */
+-#define MTK_MUX_U3_GMAC2_TO_QPHY        \
+-      (MTK_ETH_MUX_U3_GMAC2_TO_QPHY | MTK_MUX | MTK_INFRA)
++/* 0: U3 -> QPHY, 1: GMACx -> QPHY where x is 2 or 3 */
++#define MTK_MUX_U3_GMAC23_TO_QPHY        \
++      (MTK_ETH_MUX_U3_GMAC23_TO_QPHY | MTK_MUX | MTK_INFRA)
+ /* 2: GMAC1 -> SGMII, 3: GMAC2 -> SGMII */
+ #define MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII      \
+@@ -1133,18 +1170,24 @@ enum mkt_eth_capabilities {
+ #define MT7629_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
+                     MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \
+                     MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \
+-                    MTK_MUX_U3_GMAC2_TO_QPHY | \
++                    MTK_MUX_U3_GMAC23_TO_QPHY | \
+                     MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA)
+ #define MT7981_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
+                     MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
+-                    MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
++                    MTK_MUX_U3_GMAC23_TO_QPHY | MTK_U3_COPHY_V2 | \
+                     MTK_RSTCTRL_PPE1 | MTK_SRAM)
+ #define MT7986_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
+                     MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
+                     MTK_RSTCTRL_PPE1 | MTK_SRAM)
++#define MT7987_CAPS  (MTK_36BIT_DMA | MTK_GMAC1_SGMII | \
++                    MTK_GMAC2_2P5GPHY_V2 | MTK_GMAC2_SGMII | MTK_GMAC3_SGMII | \
++                    MTK_MUX_GMAC123_TO_GEPHY_SGMII | MTK_MUX_GMAC2_TO_2P5GPHY | \
++                    MTK_MUX_U3_GMAC23_TO_QPHY | MTK_U3_COPHY_V2 | \
++                    MTK_QDMA | MTK_RSTCTRL_PPE1)
++
+ #define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC1_SGMII | \
+                     MTK_GMAC2_2P5GPHY | MTK_GMAC2_SGMII | MTK_GMAC2_USXGMII | \
+                     MTK_GMAC3_SGMII | MTK_GMAC3_USXGMII | \
diff --git a/target/linux/mediatek/patches-6.12/751-net-ethernet-mtk_eth_soc-revise-hardware-configuration-for-mt7987.patch b/target/linux/mediatek/patches-6.12/751-net-ethernet-mtk_eth_soc-revise-hardware-configuration-for-mt7987.patch
new file mode 100644 (file)
index 0000000..56dd325
--- /dev/null
@@ -0,0 +1,79 @@
+From 5ef0b04d30efff8f171e30bfbe876c00e3b9036a Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Fri, 9 May 2025 09:49:04 +0800
+Subject: [PATCH] net: ethernet: mtk_eth_soc: revise hardware configuration for
+ mt7987
+
+Change hardware configuration for the MT7987.
+ - Enable PSE drop mechanism when the WDMA Rx ring full
+ - Enable PSE no-drop mechanism for packets from the WDMA Tx
+
+Signed-off-by: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 49 +++++++++++++--------
+ 1 file changed, 31 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -4445,27 +4445,40 @@ static int mtk_hw_init(struct mtk_eth *e
+               mtk_w32(eth, PSE_DUMMY_WORK_GDM(1) | PSE_DUMMY_WORK_GDM(2) |
+                       PSE_DUMMY_WORK_GDM(3) | DUMMY_PAGE_THR, PSE_DUMY_REQ);
+-              /* PSE free buffer drop threshold */
+-              mtk_w32(eth, 0x00600009, PSE_IQ_REV(8));
+-
+-              /* PSE should not drop port8, port9 and port13 packets from
+-               * WDMA Tx
+-               */
+-              mtk_w32(eth, 0x00002300, PSE_DROP_CFG);
+-
+-              /* PSE should drop packets to port8, port9 and port13 on WDMA Rx
+-               * ring full
+-               */
+-              mtk_w32(eth, 0x00002300, PSE_PPE_DROP(0));
+-              mtk_w32(eth, 0x00002300, PSE_PPE_DROP(1));
+-              mtk_w32(eth, 0x00002300, PSE_PPE_DROP(2));
+-
+-              /* GDM and CDM Threshold */
+-              mtk_w32(eth, 0x08000707, MTK_CDMW0_THRES);
+-              mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES);
+-
+-              /* Disable GDM1 RX CRC stripping */
+-              mtk_m32(eth, MTK_GDMA_STRP_CRC, 0, MTK_GDMA_FWD_CFG(0));
++              if (eth->soc->caps == MT7988_CAPS) {
++                      /* PSE free buffer drop threshold */
++                      mtk_w32(eth, 0x00600009, PSE_IQ_REV(8));
++
++                      /* PSE should not drop port8, port9 and port13 packets
++                       * from WDMA Tx
++                       */
++                      mtk_w32(eth, 0x00002300, PSE_DROP_CFG);
++
++                      /* PSE should drop packets to port8, port9 and port13
++                       * on WDMA Rx ring full
++                       */
++                      mtk_w32(eth, 0x00002300, PSE_PPE_DROP(0));
++                      mtk_w32(eth, 0x00002300, PSE_PPE_DROP(1));
++                      mtk_w32(eth, 0x00002300, PSE_PPE_DROP(2));
++
++                      /* GDM and CDM Threshold */
++                      mtk_w32(eth, 0x08000707, MTK_CDMW0_THRES);
++                      mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES);
++              } else if (eth->soc->caps == MT7987_CAPS) {
++                      /* PSE should not drop port8 packets from WDMA Tx */
++                      mtk_w32(eth, 0x00000100, PSE_DROP_CFG);
++
++                      /* PSE should drop packets to port8 on WDMA Rx ring
++                       * full
++                       */
++                      mtk_w32(eth, 0x00000100, PSE_PPE_DROP(0));
++                      mtk_w32(eth, 0x00000100, PSE_PPE_DROP(1));
++              }
++
++              if (MTK_HAS_CAPS(eth->soc->caps, MTK_ESW)) {
++                      /* Disable GDM1 RX CRC stripping */
++                      mtk_m32(eth, MTK_GDMA_STRP_CRC, 0, MTK_GDMA_FWD_CFG(0));
++              }
+               /* PSE GDM3 MIB counter has incorrect hw default values,
+                * so the driver ought to read clear the values beforehand
diff --git a/target/linux/mediatek/patches-6.12/752-net-phy-mediatek-i2p5g-add-support-for-mt7987.patch b/target/linux/mediatek/patches-6.12/752-net-phy-mediatek-i2p5g-add-support-for-mt7987.patch
new file mode 100644 (file)
index 0000000..de720a3
--- /dev/null
@@ -0,0 +1,397 @@
+--- a/drivers/net/phy/mediatek/mtk-2p5ge.c
++++ b/drivers/net/phy/mediatek/mtk-2p5ge.c
+@@ -12,13 +12,77 @@
+ #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 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)
+@@ -31,6 +95,14 @@
+ #define MTK_PHY_LPI_PCS_DSP_CTRL              (0x121)
+ #define   MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK        GENMASK(12, 8)
++#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_HOST_CMD1             0x800e
+ #define MTK_PHY_HOST_CMD2             0x800f
+ /* Registers on Token Ring debug nodes */
+@@ -48,7 +120,249 @@ enum {
+       PHY_AUX_SPD_2500,
+ };
+-static int mt798x_2p5ge_phy_load_fw(struct phy_device *phydev)
++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;
++      }
++
++      /* Force 2.5Gphy back to AN state */
++      phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
++      usleep_range(5000, 6000);
++      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);
++
++      /* 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 *mcu_csr_base, *pmb_addr;
+@@ -135,7 +449,20 @@ static int mt798x_2p5ge_phy_config_init(
+       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;
+@@ -293,6 +620,7 @@ static int mt798x_2p5ge_phy_probe(struct
+               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.mmds_present |= MDIO_DEVS_PCS |
+@@ -312,6 +640,20 @@ static int mt798x_2p5ge_phy_probe(struct
+ 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,