From 1673390905620e85c954ca87ea07de74d89cf920 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 24 Aug 2025 05:23:13 -0400 Subject: [PATCH] generic: backport upstream v6.18 Realtek PHY patch 3a752e678 net: phy: realtek: enable serdes option mode for RTL8226-CG Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/19843 Signed-off-by: Hauke Mehrtens --- ...le-serdes-option-mode-for-RTL8226-CG.patch | 92 +++++++++++++++++++ ...-use-genphy_soft_reset-for-2.5G-PHYs.patch | 14 +-- ...sable-SGMII-in-band-AN-for-2-5G-PHYs.patch | 48 ++++++---- ...make-sure-paged-read-is-protected-by.patch | 2 +- .../720-04-net-phy-realtek-setup-aldps.patch | 6 +- ...tek-detect-early-version-of-RTL8221B.patch | 2 +- ...ealtek-support-interrupt-of-RTL8221B.patch | 10 +- ...ealtek-mark-existing-MMDs-as-present.patch | 2 +- ...hy-realtek-work-around-broken-serdes.patch | 8 +- ...t-phy-realtek-disable-MDIO-broadcast.patch | 2 +- 10 files changed, 147 insertions(+), 39 deletions(-) create mode 100644 target/linux/generic/backport-6.12/781-29-v6.18-net-phy-realtek-enable-serdes-option-mode-for-RTL8226-CG.patch diff --git a/target/linux/generic/backport-6.12/781-29-v6.18-net-phy-realtek-enable-serdes-option-mode-for-RTL8226-CG.patch b/target/linux/generic/backport-6.12/781-29-v6.18-net-phy-realtek-enable-serdes-option-mode-for-RTL8226-CG.patch new file mode 100644 index 00000000000..9ffb260df15 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-29-v6.18-net-phy-realtek-enable-serdes-option-mode-for-RTL8226-CG.patch @@ -0,0 +1,92 @@ +From 3a752e67800106a5c42d802d67e06c60aa71d07b Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Fri, 15 Aug 2025 04:20:09 -0400 +Subject: net: phy: realtek: enable serdes option mode for RTL8226-CG + +The RTL8226-CG can make use of the serdes option mode feature to +dynamically switch between SGMII and 2500base-X. From what is +known the setup sequence is much simpler with no magic values. + +Convert the exiting config_init() into a helper that configures +the PHY depending on generation 1 or 2. Call the helper from two +separated new config_init() functions. + +Finally convert the phy_driver specs of the RTL8226-CG to make +use of the new configuration and switch over to the extended +read_status() function to dynamically change the interface +according to the serdes mode. + +Remark! The logic could be simpler if the serdes mode could be +set before all other generation 2 magic values. Due to missing +RTL8221B test hardware the mmd command order was kept. + +Tested on Zyxel XGS1210-12. + +Signed-off-by: Markus Stockhausen +Link: https://patch.msgid.link/20250815082009.3678865-1-markus.stockhausen@gmx.de +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1032,7 +1032,7 @@ static int rtl822x_probe(struct phy_devi + return 0; + } + +-static int rtl822xb_config_init(struct phy_device *phydev) ++static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) + { + bool has_2500, has_sgmii; + u16 mode; +@@ -1067,15 +1067,18 @@ static int rtl822xb_config_init(struct p + /* the following sequence with magic numbers sets up the SerDes + * option mode + */ +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); +- if (ret < 0) +- return ret; ++ ++ if (!gen1) { ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); ++ if (ret < 0) ++ return ret; ++ } + + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, + RTL822X_VND1_SERDES_OPTION, + RTL822X_VND1_SERDES_OPTION_MODE_MASK, + mode); +- if (ret < 0) ++ if (gen1 || ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); +@@ -1089,6 +1092,16 @@ static int rtl822xb_config_init(struct p + return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); + } + ++static int rtl822x_config_init(struct phy_device *phydev) ++{ ++ return rtl822x_set_serdes_option_mode(phydev, true); ++} ++ ++static int rtl822xb_config_init(struct phy_device *phydev) ++{ ++ return rtl822x_set_serdes_option_mode(phydev, false); ++} ++ + static int rtl822xb_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) + { +@@ -1678,7 +1691,8 @@ static struct phy_driver realtek_drvs[] + .soft_reset = rtl822x_c45_soft_reset, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, +- .read_status = rtl822x_c45_read_status, ++ .config_init = rtl822x_config_init, ++ .read_status = rtl822xb_c45_read_status, + .suspend = genphy_c45_pma_suspend, + .resume = rtlgen_c45_resume, + }, { diff --git a/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch b/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch index 5b335ba888d..abe7478a656 100644 --- a/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch +++ b/target/linux/generic/pending-6.12/720-01-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch @@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c -@@ -1653,6 +1653,7 @@ static struct phy_driver realtek_drvs[] +@@ -1666,6 +1666,7 @@ static struct phy_driver realtek_drvs[] }, { .name = "RTL8226 2.5Gbps PHY", .match_phy_device = rtl8226_match_phy_device, @@ -23,7 +23,7 @@ Signed-off-by: Daniel Golle .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .read_status = rtl822x_read_status, -@@ -1663,6 +1664,7 @@ static struct phy_driver realtek_drvs[] +@@ -1676,6 +1677,7 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_match_phy_device, .name = "RTL8226B_RTL8221B 2.5Gbps PHY", @@ -31,7 +31,7 @@ Signed-off-by: Daniel Golle .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .config_init = rtl822xb_config_init, -@@ -1684,6 +1686,7 @@ static struct phy_driver realtek_drvs[] +@@ -1698,6 +1700,7 @@ static struct phy_driver realtek_drvs[] }, { PHY_ID_MATCH_EXACT(0x001cc848), .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", @@ -39,7 +39,7 @@ Signed-off-by: Daniel Golle .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .config_init = rtl822xb_config_init, -@@ -1696,6 +1699,7 @@ static struct phy_driver realtek_drvs[] +@@ -1710,6 +1713,7 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", @@ -47,7 +47,7 @@ Signed-off-by: Daniel Golle .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, -@@ -1709,6 +1713,7 @@ static struct phy_driver realtek_drvs[] +@@ -1723,6 +1727,7 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", @@ -55,7 +55,7 @@ Signed-off-by: Daniel Golle .probe = rtl822x_probe, .config_init = rtl822xb_config_init, .get_rate_matching = rtl822xb_get_rate_matching, -@@ -1720,6 +1725,7 @@ static struct phy_driver realtek_drvs[] +@@ -1734,6 +1739,7 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", @@ -63,7 +63,7 @@ Signed-off-by: Daniel Golle .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, -@@ -1733,6 +1739,7 @@ static struct phy_driver realtek_drvs[] +@@ -1747,6 +1753,7 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", diff --git a/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch b/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch index e11a7984d45..e1d98087478 100644 --- a/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch +++ b/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch @@ -21,7 +21,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1035,8 +1035,8 @@ static int rtl822x_probe(struct phy_devi - static int rtl822xb_config_init(struct phy_device *phydev) + static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) { bool has_2500, has_sgmii; + int ret, val; @@ -30,15 +30,28 @@ Signed-off-by: Daniel Golle has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->host_interfaces) || -@@ -1086,7 +1086,29 @@ static int rtl822xb_config_init(struct p - if (ret < 0) - return ret; - -- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); +@@ -1078,18 +1078,42 @@ static int rtl822x_set_serdes_option_mod + RTL822X_VND1_SERDES_OPTION, + RTL822X_VND1_SERDES_OPTION_MODE_MASK, + mode); +- if (gen1 || ret < 0) + if (ret < 0) + return ret; + ++ if (!gen1) { ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); ++ if (ret < 0) ++ return ret; ++ } ++ + /* Disable SGMII AN */ + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2); + if (ret < 0) @@ -46,18 +59,21 @@ Signed-off-by: Daniel Golle + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7589, 0x71d0); + if (ret < 0) -+ return ret; -+ + return ret; + +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7587, 0x3); -+ if (ret < 0) -+ return ret; -+ + if (ret < 0) + return ret; + +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 0x7587, + val, !(val & BIT(0)), 500, 100000, false); -+ if (ret < 0) -+ return ret; -+ + if (ret < 0) + return ret; + +- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); + return 0; } - static int rtl822xb_get_rate_matching(struct phy_device *phydev, + static int rtl822x_config_init(struct phy_device *phydev) diff --git a/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch b/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch index 085fad99ccd..74bf74e0129 100644 --- a/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch +++ b/target/linux/generic/pending-6.12/720-03-net-phy-realtek-make-sure-paged-read-is-protected-by.patch @@ -18,7 +18,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c -@@ -1328,9 +1328,11 @@ static bool rtlgen_supports_2_5gbps(stru +@@ -1343,9 +1343,11 @@ static bool rtlgen_supports_2_5gbps(stru { int val; diff --git a/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch b/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch index b36e54717d1..6d1bf08600d 100644 --- a/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch +++ b/target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch @@ -24,9 +24,9 @@ Signed-off-by: Daniel Golle #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) -@@ -1090,6 +1094,15 @@ static int rtl822xb_config_init(struct p - if (ret < 0) - return ret; +@@ -1095,6 +1099,15 @@ static int rtl822x_set_serdes_option_mod + return ret; + } + if (of_property_read_bool(phydev->mdio.dev.of_node, "realtek,aldps-enable")) + ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, diff --git a/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch b/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch index 29706fa6305..4e07882b1ec 100644 --- a/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch +++ b/target/linux/generic/pending-6.12/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch @@ -14,7 +14,7 @@ Signed-off-by: Daniel Golle Signed-off-by: Mieczyslaw Nalewaj --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c -@@ -1383,10 +1383,32 @@ static int rtl8226_match_phy_device(stru +@@ -1398,10 +1398,32 @@ static int rtl8226_match_phy_device(stru static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, bool is_c45) { diff --git a/target/linux/generic/pending-6.12/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch b/target/linux/generic/pending-6.12/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch index 41d6efafb32..bac46cbeef0 100644 --- a/target/linux/generic/pending-6.12/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch +++ b/target/linux/generic/pending-6.12/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch @@ -12,7 +12,7 @@ Signed-off-by: Jianhui Zhao --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c -@@ -1595,6 +1595,51 @@ static irqreturn_t rtl9000a_handle_inter +@@ -1610,6 +1610,51 @@ static irqreturn_t rtl9000a_handle_inter return IRQ_HANDLED; } @@ -64,7 +64,7 @@ Signed-off-by: Jianhui Zhao static struct phy_driver realtek_drvs[] = { { PHY_ID_MATCH_EXACT(0x00008201), -@@ -1758,6 +1803,8 @@ static struct phy_driver realtek_drvs[] +@@ -1774,6 +1819,8 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", @@ -73,7 +73,7 @@ Signed-off-by: Jianhui Zhao .soft_reset = genphy_soft_reset, .probe = rtl822x_probe, .get_features = rtl822x_get_features, -@@ -1772,6 +1819,8 @@ static struct phy_driver realtek_drvs[] +@@ -1788,6 +1835,8 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", @@ -82,7 +82,7 @@ Signed-off-by: Jianhui Zhao .soft_reset = genphy_soft_reset, .probe = rtl822x_probe, .config_init = rtl822xb_config_init, -@@ -1784,6 +1833,8 @@ static struct phy_driver realtek_drvs[] +@@ -1800,6 +1849,8 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", @@ -91,7 +91,7 @@ Signed-off-by: Jianhui Zhao .soft_reset = genphy_soft_reset, .probe = rtl822x_probe, .get_features = rtl822x_get_features, -@@ -1798,6 +1849,8 @@ static struct phy_driver realtek_drvs[] +@@ -1814,6 +1865,8 @@ static struct phy_driver realtek_drvs[] }, { .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", diff --git a/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch b/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch index 20bd666fd2e..4441a5039ec 100644 --- a/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch +++ b/target/linux/generic/pending-6.12/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch @@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c -@@ -1244,6 +1244,9 @@ static int rtl822x_c45_get_features(stru +@@ -1259,6 +1259,9 @@ static int rtl822x_c45_get_features(stru linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, phydev->supported); diff --git a/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch b/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch index 3eada2d5ad2..ceb67c23792 100644 --- a/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch +++ b/target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch @@ -15,8 +15,8 @@ Signed-off-by: Daniel Golle --- --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c -@@ -1124,6 +1124,22 @@ static int rtl822xb_config_init(struct p - return 0; +@@ -1139,6 +1139,22 @@ static int rtl822xb_config_init(struct p + return rtl822x_set_serdes_option_mode(phydev, false); } +static int rtl822xb_config_init_war(struct phy_device *phydev) @@ -38,7 +38,7 @@ Signed-off-by: Daniel Golle static int rtl822xb_get_rate_matching(struct phy_device *phydev, phy_interface_t iface) { -@@ -1826,7 +1842,7 @@ static struct phy_driver realtek_drvs[] +@@ -1842,7 +1858,7 @@ static struct phy_driver realtek_drvs[] .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = genphy_soft_reset, .probe = rtl822x_probe, @@ -47,7 +47,7 @@ Signed-off-by: Daniel Golle .get_rate_matching = rtl822xb_get_rate_matching, .get_features = rtl822x_c45_get_features, .config_aneg = rtl822x_c45_config_aneg, -@@ -1856,7 +1872,7 @@ static struct phy_driver realtek_drvs[] +@@ -1872,7 +1888,7 @@ static struct phy_driver realtek_drvs[] .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = genphy_soft_reset, .probe = rtl822x_probe, diff --git a/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch b/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch index bb207500335..24db18c2a79 100644 --- a/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch +++ b/target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch @@ -13,7 +13,7 @@ Signed-off-by: Daniel Golle --- --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c -@@ -1050,6 +1050,11 @@ static int rtl822xb_config_init(struct p +@@ -1050,6 +1050,11 @@ static int rtl822x_set_serdes_option_mod phydev->host_interfaces) || phydev->interface == PHY_INTERFACE_MODE_SGMII; -- 2.47.3