From 4fa27cb325817cf0e439fffc52895ad4104568b5 Mon Sep 17 00:00:00 2001 From: Jonas Jelonek Date: Sun, 11 Jan 2026 10:59:54 +0000 Subject: [PATCH] realtek: mdio: apply phy polling config for RTL931x Apply the PHY polling configuration for RTL931x too, as previously implemented for RTL930x. This is needed for several PHYs on that platform to function properly. Add another flag called 'force_res' to the phy_info struct which is for RTL931x only. The SDK mentions this as a flag to force polling the Realtek proprietary PHY status resolution register. Effectively, this changes the polling to proprietary format instead of standard format, and sets an enable bit in another private polling register field. Signed-off-by: Jonas Jelonek Link: https://github.com/openwrt/openwrt/pull/21515 Signed-off-by: Robert Marko --- .../drivers/net/mdio/mdio-realtek-otto.c | 95 +++++++++++++++++-- 1 file changed, 85 insertions(+), 10 deletions(-) diff --git a/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto.c b/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto.c index 8e97e21c3f..bcc8f2b775 100644 --- a/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto.c +++ b/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto.c @@ -95,6 +95,11 @@ #define RTMDIO_931X_MAC_L2_GLOBAL_CTRL2 (0x1358) #define RTMDIO_931X_SMI_PORT_POLLING_SEL (0x0C9C) #define RTMDIO_931X_SMI_PORT_ADDR (0x0C74) +#define RTMDIO_931X_SMI_10GPHY_POLLING_SEL0 (0x0CF0) +#define RTMDIO_931X_SMI_10GPHY_POLLING_SEL1 (0x0CF4) +#define RTMDIO_931X_SMI_10GPHY_POLLING_SEL2 (0x0CF8) +#define RTMDIO_931X_SMI_10GPHY_POLLING_SEL3 (0x0CFC) +#define RTMDIO_931X_SMI_10GPHY_POLLING_SEL4 (0x0D00) #define sw_r32(reg) readl(RTMDIO_SW_BASE + reg) #define sw_w32(val, reg) writel(val, RTMDIO_SW_BASE + reg) @@ -193,6 +198,7 @@ struct rtmdio_phy_info { int mac_type; bool has_giga_lite; bool has_res_reg; + bool force_res; unsigned int poll_duplex; unsigned int poll_adv_1000; unsigned int poll_lpa_1000; @@ -749,6 +755,7 @@ static int rtmdio_930x_reset(struct mii_bus *bus) static int rtmdio_931x_reset(struct mii_bus *bus) { struct rtmdio_bus_priv *priv = bus->priv; + struct rtmdio_phy_info phyinfo; u32 poll_sel[4] = { 0 }; u32 poll_ctrl = 0; u32 c45_mask = 0; @@ -779,23 +786,91 @@ static int rtmdio_931x_reset(struct mii_bus *bus) sw_w32(poll_sel[i], RTMDIO_931X_SMI_PORT_POLLING_SEL + (i * 4)); } - /* Configure which SMI busses */ - pr_info("c45_mask: %08x, RTMDIO_931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTMDIO_931X_SMI_GLB_CTRL0)); + /* Configure c22/c45 polling (bit 1 of SMI_SETX_FMT_SEL) + * + * NOTE: this seems to be needed before accessing the bus though + * it should only apply to the SMI polling. Not setting c22/c45 here + * apparently causes garbage being read below. + */ for (int i = 0; i < RTMDIO_MAX_SMI_BUS; i++) { /* bus is polled in c45 */ if (priv->smi_bus_isc45[i]) c45_mask |= 0x2 << (i * 2); /* Std. C45, non-standard is 0x3 */ } - - pr_info("c45_mask: %08x, RTL931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTMDIO_931X_SMI_GLB_CTRL0)); - - /* We have a 10G PHY enable polling - * sw_w32(0x01010000, RTL931X_SMI_10GPHY_POLLING_SEL2); - * sw_w32(0x01E7C400, RTL931X_SMI_10GPHY_POLLING_SEL3); - * sw_w32(0x01E7E820, RTL931X_SMI_10GPHY_POLLING_SEL4); - */ + pr_info("%s: c45_mask: %08x", __func__, c45_mask); sw_w32_mask(GENMASK(7, 0), c45_mask, RTMDIO_931X_SMI_GLB_CTRL1); + /* Define PHY specific polling parameters + * + * Those are applied per port here but the SoC only supports them + * per SMI bus or for all GPHY/10GPHY. This should be guarded by + * the existing hardware designs (i.e. only equally polled PHYs on + * the same SMI bus or kind of PHYs). + */ + for (int addr = 0; addr < priv->cfg->cpu_port; addr++) { + unsigned int mask, val; + int smi = priv->smi_bus[addr]; + + if (smi < 0) + continue; + + rtmdio_get_phy_info(bus, addr, &phyinfo); + if (phyinfo.phy_unknown) { + pr_warn("skip polling setup for unknown PHY %08x on port %d\n", + phyinfo.phy_id, addr); + continue; + } + + mask = val = 0; + + /* PRVTE0 polling */ + mask |= BIT(20 + smi); + if (phyinfo.has_res_reg) + val |= BIT(20 + smi); + + /* PRVTE1 polling */ + mask |= BIT(24 + smi); + if (phyinfo.force_res) + val |= BIT(24 + smi); + + sw_w32_mask(mask, val, RTMDIO_931X_SMI_GLB_CTRL0); + + /* polling std. or proprietary format (bit 0 of SMI_SETX_FMT_SEL) */ + mask = BIT(smi * 2); + val = phyinfo.force_res ? mask : 0; + sw_w32_mask(mask, val, RTMDIO_931X_SMI_GLB_CTRL1); + + /* special polling registers */ + if (phyinfo.poll_duplex || phyinfo.poll_adv_1000 || phyinfo.poll_lpa_1000) { + sw_w32(phyinfo.poll_duplex, RTMDIO_931X_SMI_10GPHY_POLLING_SEL2); + sw_w32(phyinfo.poll_adv_1000, RTMDIO_931X_SMI_10GPHY_POLLING_SEL3); + sw_w32(phyinfo.poll_lpa_1000, RTMDIO_931X_SMI_10GPHY_POLLING_SEL4); + } + } + + pr_debug("%s: RTMDIO_931X_SMI_GLB_CTRL0 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_GLB_CTRL0)); + pr_debug("%s: RTMDIO_931X_SMI_GLB_CTRL1 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_GLB_CTRL1)); + pr_debug("%s: RTMDIO_931X_SMI_PORT_POLLING_SEL_0_15 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_PORT_POLLING_SEL)); + pr_debug("%s: RTMDIO_931X_SMI_PORT_POLLING_SEL_16_27 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_PORT_POLLING_SEL + 4)); + pr_debug("%s: RTMDIO_931X_SMI_PORT_POLLING_SEL_28_43 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_PORT_POLLING_SEL + 8)); + pr_debug("%s: RTMDIO_931X_SMI_PORT_POLLING_SEL_44_55 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_PORT_POLLING_SEL + 12)); + pr_debug("%s: RTMDIO_931X_SMI_10GPHY_POLLING_SEL0 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_10GPHY_POLLING_SEL0)); + pr_debug("%s: RTMDIO_931X_SMI_10GPHY_POLLING_SEL1 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_10GPHY_POLLING_SEL1)); + pr_debug("%s: RTMDIO_931X_SMI_10GPHY_POLLING_SEL2 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_10GPHY_POLLING_SEL2)); + pr_debug("%s: RTMDIO_931X_SMI_10GPHY_POLLING_SEL3 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_10GPHY_POLLING_SEL3)); + pr_debug("%s: RTMDIO_931X_SMI_10GPHY_POLLING_SEL4 %08x\n", __func__, + sw_r32(RTMDIO_931X_SMI_10GPHY_POLLING_SEL4)); + return 0; }