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 b03b72b33..9440c23e6 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 + } + + 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 000000000..d4d09b64f --- /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 +Date: Fri, 9 May 2025 13:22:14 +0800 +Subject: [PATCH] net: pcs: mtk_lynxi add mt7987 support + +Signed-off-by: Bo-Cun Chen +--- + 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 000000000..eef6e361a --- /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 +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 +--- +--- 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 + + #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 000000000..238e7a76b --- /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 +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 +--- + 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 000000000..56dd3257c --- /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 +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 +--- + 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 000000000..de720a357 --- /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,