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 e794b1296d..439ba9aa37 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 @@ -38,6 +38,7 @@ extern int phy_package_read_paged(struct phy_device *phydev, int page, u32 regnu #define RTL821X_PAGE_MAC 0x0a43 #define RTL821X_PAGE_STATE 0x0b80 #define RTL821X_PAGE_PATCH 0x0b82 +#define RTL821X_MAC_SDS_PAGE(sds, page) (0x404 + (sds) * 0x20 + (page)) /* Using the special page 0xfff with the MDIO controller found in * RealTek SoCs allows to access the PHY in RAW mode, ie. bypassing @@ -3811,6 +3812,55 @@ static int rtl821x_config_init(struct phy_device *phydev) return 0; } +static void rtl8218b_cmu_reset(struct phy_device *phydev, int reset_id) +{ + int bitpos = reset_id * 2; + + /* CMU seems to have 8 pairs of reset bits that always work the same way */ + phy_modify_paged(phydev, 0x467, 0x14, 0, BIT(bitpos)); + phy_modify_paged(phydev, 0x467, 0x14, 0, BIT(bitpos + 1)); + phy_write_paged(phydev, 0x467, 0x14, 0x0); +} + +static int rtl8218b_config_init(struct phy_device *phydev) +{ + int oldpage, oldxpage; + + rtl821x_config_init(phydev); + + if (phydev->mdio.addr % 8) + return 0; + /* + * Realtek provides two ways of initializing the PHY package. Either by U-Boot or via + * vendor software and SDK. In case U-Boot setup is missing, run basic configuration + * so that ports at least get link up and pass traffic. + */ + + oldpage = phy_read(phydev, RTL8XXX_PAGE_SELECT); + oldxpage = phy_read(phydev, RTL821XEXT_MEDIA_PAGE_SELECT); + phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x8); + + /* activate 32/40 bit redundancy algorithm for first MAC serdes */ + phy_modify_paged(phydev, RTL821X_MAC_SDS_PAGE(0, 1), 0x14, 0, BIT(3)); + /* magic CMU setting for stable connectivity of first MAC serdes */ + phy_write_paged(phydev, 0x462, 0x15, 0x6e58); + rtl8218b_cmu_reset(phydev, 0); + + for (int sds = 0; sds < 2; sds++) { + /* force negative clock edge */ + phy_modify_paged(phydev, RTL821X_MAC_SDS_PAGE(sds, 0), 0x17, 0, BIT(14)); + rtl8218b_cmu_reset(phydev, 5 + sds); + /* soft reset */ + phy_modify_paged(phydev, RTL821X_MAC_SDS_PAGE(sds, 0), 0x13, 0, BIT(6)); + phy_modify_paged(phydev, RTL821X_MAC_SDS_PAGE(sds, 0), 0x13, BIT(6), 0); + } + + phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, oldxpage); + phy_write(phydev, RTL8XXX_PAGE_SELECT, oldpage); + + return 0; +} + static int rtl838x_serdes_probe(struct phy_device *phydev) { int addr = phydev->mdio.addr; @@ -3898,7 +3948,7 @@ static struct phy_driver rtl83xx_phy_driver[] = { { .match_phy_device = rtl8218b_ext_match_phy_device, .name = "Realtek RTL8218B (external)", - .config_init = rtl821x_config_init, + .config_init = rtl8218b_config_init, .features = PHY_GBIT_FEATURES, .probe = rtl8218b_ext_phy_probe, .read_mmd = rtl821x_read_mmd,