]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: phy: add basic RTL8218B setup 19491/head
authorMarkus Stockhausen <markus.stockhausen@gmx.de>
Tue, 22 Jul 2025 07:14:59 +0000 (03:14 -0400)
committerHauke Mehrtens <hauke@hauke-m.de>
Wed, 23 Jul 2025 22:44:02 +0000 (00:44 +0200)
On some devices (like ZyXEL GS1920) the phys are not initialized and patched
by the bootloader. This is done through the vendor SDK when the software
starts. To make these devices usable too, provide the most basic setup
sequence for the RTL8218B.

Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/19491
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.c

index e794b1296d7be6e6d5ed92662daf299b2e6b412d..439ba9aa37a8dafe2a7811aa4a90d095fdbe60da 100644 (file)
@@ -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,