From b6ba4e9142b7e926dd3822beffdae26de34da98e Mon Sep 17 00:00:00 2001 From: Jonas Jelonek Date: Fri, 18 Sep 2026 13:16:47 +0000 Subject: [PATCH] realtek: phy: fix RTL8218E XSGMII initialization Commit c8c187f0f08a ("realtek: add support for RTL8218E") added the PHY identifier and reused the generic RTL821x callbacks. This is enough when the bootloader has already configured the package, but it leaves the MAC-side SerDes uninitialized without that setup. As a result, the XSGMII link is not established after a cold boot and/or without any pre-established PHY setup. Add package-level initialization on the base PHY address and gate it on the strapped XSGMII mode. Apply the minimal required subset of the vendor configuration, reset the active SerDes block, and force XSGMII mode by disabling SerDes autonegotiation. QSGMII remains unsupported. This completes RTL8218E support without relying on bootloader PHY setup while avoiding the large, mostly unnecessary vendor register table. This minimal sequence has been established through various testing iterations on two devices. Fixes: c8c187f0f08a ("realtek: add support for RTL8218E") Assisted-by: ChatGPT (OpenAI GPT-5.6 Sol) Link: https://github.com/openwrt/openwrt/pull/25255 Signed-off-by: Jonas Jelonek --- .../net/phy/realtek/realtek_multiport.c | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/target/linux/realtek/files-6.18/drivers/net/phy/realtek/realtek_multiport.c b/target/linux/realtek/files-6.18/drivers/net/phy/realtek/realtek_multiport.c index 29b5cce4c1a..3406242d698 100644 --- a/target/linux/realtek/files-6.18/drivers/net/phy/realtek/realtek_multiport.c +++ b/target/linux/realtek/files-6.18/drivers/net/phy/realtek/realtek_multiport.c @@ -449,6 +449,48 @@ static int rtl821x_config_init(struct phy_device *phydev) return 0; } +static int rtl8218e_config_init(struct phy_device *phydev) +{ + int oldpage, oldxpage; + bool is_xsgmii; + + rtl821x_config_init(phydev); + + if (phydev->mdio.addr % 8) + return 0; + + oldpage = phy_read(phydev, RTL821x_PAGE_SELECT); + oldxpage = phy_read(phydev, RTL821x_EXT_PAGE_SELECT); + + phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0x8); + is_xsgmii = (phy_read_paged(phydev, 0x260, 0x12) & 0xf0) == 0xb0; + + /* QSGMII configuration is not currently supported. */ + if (!is_xsgmii) + goto restore; + + /* Apply the minimal vendor XSGMII configuration, undocumented magic. */ + phy_write_paged(phydev, 0x4b8, 0x10, 0x8714); + phy_write_paged(phydev, 0x4b8, 0x12, 0x7230); + phy_write_paged(phydev, 0x4be, 0x16, 0x1000); + phy_write_paged(phydev, 0x4bf, 0x11, 0x7000); + phy_write_paged(phydev, 0x4bf, 0x16, 0x0042); + phy_write_paged(phydev, 0x4ba, 0x14, 0x9d04); + + /* Reset SerDes 0. */ + phy_write_paged(phydev, 0x400, 0x10, 0x1700); + phy_write_paged(phydev, 0x400, 0x10, 0x1703); + + /* Disable SerDes 0 XSGMII autonegotiation. */ + phy_modify_paged(phydev, 0x400, 0x12, GENMASK(9, 8), BIT(8)); + +restore: + phy_write(phydev, RTL821x_EXT_PAGE_SELECT, oldxpage); + phy_write(phydev, RTL821x_PAGE_SELECT, oldpage); + + return 0; +} + static int rtl8218d_config_init(struct phy_device *phydev) { int oldpage, oldxpage; @@ -681,7 +723,7 @@ static struct phy_driver rtl83xx_phy_driver[] = { { PHY_ID_MATCH_EXACT(PHY_ID_RTL8218E), .name = "REALTEK RTL8218E", - .config_init = rtl821x_config_init, + .config_init = rtl8218e_config_init, .features = PHY_GBIT_FEATURES, .probe = rtl8218x_phy_probe, .read_mmd = rtl821x_read_mmd,