From 3ddcd5265f928ff82e22f29bdb4dedb8cd32159e Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 15 Jan 2026 18:25:31 +0100 Subject: [PATCH] realtek: phy: add RTL8218D initialization The RTL8218D currently relies on proper U-Boot configuration. In case that is not possible, provide a basic setup sequence that can bring the PHY "alive". The SDK provides multiple configuration sequences for two operation modes (XSGMII or QSGMII) and the different SoC families. Due to limited testing resources only provide a setup for RTL93xx devices and both modes at the moment. Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/21551 Signed-off-by: Robert Marko --- .../files-6.12/drivers/net/phy/rtl83xx-phy.c | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.c b/target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.c index e1a60ce55e8..fad43dd8aa0 100644 --- a/target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.c +++ b/target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.c @@ -738,6 +738,68 @@ static int rtl821x_config_init(struct phy_device *phydev) return 0; } +static int rtl8218d_config_init(struct phy_device *phydev) +{ + int oldpage, oldxpage; + bool is_qsgmii; + int chip_info; + + rtl821x_config_init(phydev); + + if (phydev->mdio.addr % 8) + return 0; + /* + * The RTl8218D has two MAC (aka SoC side) operation modes. Either dual QSGMII + * or single XSGMII (Realtek proprietary) link. The mode is usually configured via + * strapping pins CHIP_MODE1/2. For the moment offer a configuration that at least + * works for RTL93xx devices. This sequence even "revives" a PHY that has been hard + * reset with + * + * phy_write(phydev, 0x1e, 0x8); + * phy_write_paged(phydev, 0x262, 0x10, 0x1); + */ + oldpage = phy_read(phydev, RTL8XXX_PAGE_SELECT); + oldxpage = phy_read(phydev, RTL821XEXT_MEDIA_PAGE_SELECT); + + phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x8); + chip_info = phy_read_paged(phydev, 0x327, 0x15); + is_qsgmii = (phy_read_paged(phydev, 0x260, 0x12) & 0xf0) == 0xd0; + + pr_info("RTL8218D (chip_id=%d, rev_id=%d) on port %d running in %s mode\n", + (chip_info >> 7) & 0x7, chip_info & 0x7f, phydev->mdio.addr, + is_qsgmii ? "QSGMII" : "XSGMII"); + + if (is_qsgmii) { + for (int sds = 0; sds < 2; sds++) { + /* unknown amplification value */ + phy_modify_paged(phydev, 0x4a8 + sds * 0x100, 0x12, BIT(3), 0); + /* main aplification */ + phy_modify_paged(phydev, 0x4ab + sds * 0x100, 0x16, 0x3e0, 0x1e0); + /* unknown LCCMU value */ + phy_write_paged(phydev, 0x4ac + sds * 0x100, 0x15, 0x4380); + } + } else { + /* serdes 0/1 disable auto negotiation */ + phy_modify_paged(phydev, 0x400, 0x12, 0, BIT(8)); + phy_modify_paged(phydev, 0x500, 0x12, 0, BIT(8)); + /* unknown eye configuration */ + phy_modify_paged(phydev, 0x4b8, 0x12, BIT(3), 0); + } + + /* reset serdes 0 */ + phy_write_paged(phydev, 0x400, 0x10, 0x1700); + phy_write_paged(phydev, 0x400, 0x10, 0x1703); + + /* reset serdes 1 */ + phy_write_paged(phydev, 0x500, 0x10, 0x1400); + phy_write_paged(phydev, 0x500, 0x10, 0x1403); + + phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, oldxpage); + phy_write(phydev, RTL8XXX_PAGE_SELECT, oldpage); + + return 0; +} + static void rtl8218b_cmu_reset(struct phy_device *phydev, int reset_id) { int bitpos = reset_id * 2; @@ -896,7 +958,7 @@ static struct phy_driver rtl83xx_phy_driver[] = { { PHY_ID_MATCH_EXACT(PHY_ID_RTL8218D), .name = "REALTEK RTL8218D", - .config_init = rtl821x_config_init, + .config_init = rtl8218d_config_init, .features = PHY_GBIT_FEATURES, .probe = rtl8218x_phy_probe, .read_mmd = rtl821x_read_mmd, -- 2.47.3