From: Markus Stockhausen Date: Sun, 18 Jan 2026 21:09:00 +0000 (+0100) Subject: realtek: phy: fix RTL8214FC fibre/copper initialization X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F21582%2Fhead;p=thirdparty%2Fopenwrt.git realtek: phy: fix RTL8214FC fibre/copper initialization A phy is configured in two stages - phy_probe() for setup of structures - config_init() for device setup (after reset) RTL8214FC is a combo phy and the currently active port can be switched with the SFP helper functions that are triggered during SFP insertion and removal. In case a fibre SFP is inserted while booting the SFP trigger is run between the above mentioned stages. During the final setup in config_init() the phy is reset to the copper port. Thus no link is available on fibre and the SFP must be reinserted for normal operation. For a consistent behaviour the fibre/copper port setup must run before the SFP probing and not afterwards. Move the setup code from config_init() into phy_probe(). Fixes: 10ae743 ("realtek: phy: simplify RTL8214FC configuration") Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/21582 Signed-off-by: Robert Marko --- 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 b47e88aa98b..4eb4d138a1c 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 @@ -863,45 +863,45 @@ static int rtl8218b_config_init(struct phy_device *phydev) return 0; } -static int rtl8214fc_config_init(struct phy_device *phydev) +static int rtl8214fc_phy_probe(struct phy_device *phydev) { static int regs[] = {16, 19, 20, 21}; int ret; + rtl821x_package_join(phydev, 4); + + /* + * Normally phy_probe() only initializes PHY structures and setup is run in + * config_init(). The RTL8214FC needs configuration before SFP probing while + * the preferred media is still copper. This way all SFP events (even before + * the first config_init()) will find a consistent port state. + */ + /* Step 1 - package setup: Due to similar design reuse RTL8218B coding */ ret = rtl8218b_config_init(phydev); if (ret) return ret; if (phydev->mdio.addr % 8 == 0) { - for (int port = 0; port < 4; port++) { - phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x8); - /* setup basic fiber control in base phy and default to copper */ - phy_write_paged(phydev, 0x266, regs[port], 0x0f95); - phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x0); - } + /* Force all ports to copper */ + phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL); + for (int port = 0; port < 4; port++) + phy_modify_paged(phydev, 0x266, regs[port], 0, GENMASK(11, 10)); } /* Step 2 - port setup */ - phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x3); + phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_FIBRE); /* set fiber SerDes RX to negative edge */ phy_modify_paged(phydev, 0x8, 0x17, 0, BIT(14)); /* auto negotiation disable link on */ phy_modify_paged(phydev, 0x8, 0x14, 0, BIT(2)); /* disable fiber 100MBit */ phy_modify_paged(phydev, 0x8, 0x11, BIT(5), 0); - phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x0); + phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO); /* Disable EEE. 0xa5d/0x10 is the same as MDIO_MMD_AN / MDIO_AN_EEE_ADV */ phy_write_paged(phydev, 0xa5d, 0x10, 0x0000); - return 0; -} - -static int rtl8214fc_phy_probe(struct phy_device *phydev) -{ - rtl821x_package_join(phydev, 4); - return phy_sfp_probe(phydev, &rtl8214fc_sfp_ops); } @@ -920,7 +920,6 @@ static struct phy_driver rtl83xx_phy_driver[] = { .match_phy_device = rtl8214fc_match_phy_device, .name = "Realtek RTL8214FC", .config_aneg = rtl8214fc_config_aneg, - .config_init = rtl8214fc_config_init, .get_features = rtl8214fc_get_features, .get_tunable = rtl8214fc_get_tunable, .probe = rtl8214fc_phy_probe,