summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Stockhausen2025-07-22 07:14:59 +0000
committerHauke Mehrtens2025-07-23 22:44:02 +0000
commit19bc6e8c7f86b197b7bccc45c6af4a3ff521e8ee (patch)
tree366f9f3b658123bacae1560b6b1aa8bba1f9d846
parent9533e2e574c73320f0410c763b2ec658b8b91639 (diff)
downloadopenwrt-19bc6e8c7f86b197b7bccc45c6af4a3ff521e8ee.tar.gz
realtek: phy: add basic RTL8218B setup
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>
-rw-r--r--target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.c52
1 files changed, 51 insertions, 1 deletions
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,