[openwrt/openwrt] mediatek: import patches from SDK to support MT7987 Ethernet
LEDE Commits
lede-commits at lists.infradead.org
Wed Nov 5 06:23:06 PST 2025
dangole pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/d62fc50ff42223df2bd82c1ea0f1786ea26d3f08
commit d62fc50ff42223df2bd82c1ea0f1786ea26d3f08
Author: Daniel Golle <daniel at makrotopia.org>
AuthorDate: Sun Oct 5 03:39:52 2025 +0100
mediatek: import patches from SDK to support MT7987 Ethernet
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 at makrotopia.org>
---
...t-mtk_eth_soc-add-paths-and-SerDes-modes-.patch | 2 +-
.../740-net-pcs-mtk_lynxi-add-mt7987-support.patch | 36 ++
...t-pcs-mtk-lynxi-add-phya-tx-rx-clock-path.patch | 89 +++++
...t-ethernet-mtk_eth_soc-add-mt7987-support.patch | 325 +++++++++++++++++
...-revise-hardware-configuration-for-mt7987.patch | 79 ++++
...phy-mediatek-i2p5g-add-support-for-mt7987.patch | 397 +++++++++++++++++++++
6 files changed, 927 insertions(+), 1 deletion(-)
diff --git a/target/linux/generic/pending-6.12/737-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch b/target/linux/generic/pending-6.12/737-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch
index 165eb1e45c..46ad32a9da 100644
--- a/target/linux/generic/pending-6.12/737-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch
+++ b/target/linux/generic/pending-6.12/737-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch
@@ -544,7 +544,7 @@ Signed-off-by: Daniel Golle <daniel at 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
index 0000000000..d4d09b64fd
--- /dev/null
+++ b/target/linux/mediatek/patches-6.12/740-net-pcs-mtk_lynxi-add-mt7987-support.patch
@@ -0,0 +1,36 @@
+From 6e9ec5ade644eeb136c6b827d72fac80bf2c3817 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen at 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 at 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
index 0000000000..eef6e361a9
--- /dev/null
+++ b/target/linux/mediatek/patches-6.12/741-net-pcs-mtk-lynxi-add-phya-tx-rx-clock-path.patch
@@ -0,0 +1,89 @@
+From be193994deca7cc3ca6ddedc6efd06182b032f21 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen at 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 at 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
index 0000000000..238e7a76bd
--- /dev/null
+++ b/target/linux/mediatek/patches-6.12/750-net-ethernet-mtk_eth_soc-add-mt7987-support.patch
@@ -0,0 +1,325 @@
+From 56973433cbea9f91f5f7eddebbc361ffc2bd6156 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen at 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 at 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
index 0000000000..56dd3257c6
--- /dev/null
+++ b/target/linux/mediatek/patches-6.12/751-net-ethernet-mtk_eth_soc-revise-hardware-configuration-for-mt7987.patch
@@ -0,0 +1,79 @@
+From 5ef0b04d30efff8f171e30bfbe876c00e3b9036a Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen at 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 at 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
index 0000000000..de720a3571
--- /dev/null
+++ b/target/linux/mediatek/patches-6.12/752-net-phy-mediatek-i2p5g-add-support-for-mt7987.patch
@@ -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,
More information about the lede-commits
mailing list