From dfce21df969b54e237ae3c1ea32b627efa8285f4 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 3 Jan 2026 15:41:17 +0000 Subject: [PATCH] kernel: net: phy: realtek: replace in-band AN hack Replace downstream hack for RealTek PHYs with a more clean solution which could make it upstream. As SGMII in-band AN is broken on some platforms, or simply expected to be disabled by default in phy/sgmii mode (ie. on-board PHYs with MDIO for out-of-band configuration and status), a hack for the RealTek PHY driver was introduced to unconditionally disable SGMII in-band autonegotiation. Meanwhile the kernel has gained a proper interface for PHY and PCS to report in-band AN capabilities and enable/disable in-band, matching PHY and PCS capabilities. Thanks to Bevan Weiss' knowledge about how RealTek PHY SerDes registers are being handled in RealTek's SDK this can now be greatly improved: - report in-band capabilties - let phylink set in-band matching PCS and PHY capabilities - properly abstracted indirect access of SerDes registers Signed-off-by: Daniel Golle --- ...sable-SGMII-in-band-AN-for-2-5G-PHYs.patch | 79 ---------- ...tek-implement-configuring-in-band-an.patch | 146 ++++++++++++++++++ ...make-sure-paged-read-is-protected-by.patch | 2 +- .../720-04-net-phy-realtek-setup-aldps.patch | 16 +- ...tek-detect-early-version-of-RTL8221B.patch | 2 +- ...ealtek-mark-existing-MMDs-as-present.patch | 2 +- ...t-phy-realtek-disable-MDIO-broadcast.patch | 4 +- 7 files changed, 160 insertions(+), 91 deletions(-) delete mode 100644 target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch create mode 100644 target/linux/generic/pending-6.12/720-02-net-phy-realtek-implement-configuring-in-band-an.patch 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 deleted file mode 100644 index 4ee4e763d4..0000000000 --- a/target/linux/generic/pending-6.12/720-02-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch +++ /dev/null @@ -1,79 +0,0 @@ -From d54ef6aea00e7a6ace439baade6ad0aa38ee4b04 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Mon, 3 Apr 2023 01:21:57 +0300 -Subject: [PATCH 287/326] net: phy: realtek: disable SGMII in-band AN for 2.5G - PHYs - -MAC drivers don't use SGMII in-band autonegotiation unless told to do so -in device tree using 'managed = "in-band-status"'. When using MDIO to -access a PHY, in-band-status is unneeded as we have link-status via -MDIO. Switch off SGMII in-band autonegotiation using magic values. - -Reported-by: Chen Minqiang -Reported-by: Chukun Pan -Reported-by: Yevhen Kolomeiko -Tested-by: Yevhen Kolomeiko -Signed-off-by: Daniel Golle ---- - drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++++++++++-- - 1 file changed, 25 insertions(+), 2 deletions(-) - ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -1345,8 +1345,8 @@ static int rtl822xb_write_mmd(struct phy - static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) - { - bool has_2500, has_sgmii; -+ int ret, val; - u16 mode; -- int ret; - - has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, - phydev->host_interfaces) || -@@ -1388,18 +1388,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) -+ return ret; -+ -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7589, 0x71d0); -+ if (ret < 0) - 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; - -- 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; - -- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); -+ return 0; - } - - static int rtl822x_config_init(struct phy_device *phydev) diff --git a/target/linux/generic/pending-6.12/720-02-net-phy-realtek-implement-configuring-in-band-an.patch b/target/linux/generic/pending-6.12/720-02-net-phy-realtek-implement-configuring-in-band-an.patch new file mode 100644 index 0000000000..b0b56ac6e8 --- /dev/null +++ b/target/linux/generic/pending-6.12/720-02-net-phy-realtek-implement-configuring-in-band-an.patch @@ -0,0 +1,146 @@ +From 43a4dfb71e2d23bae10ae13b7314d0641321d35e Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 3 Jan 2026 02:53:59 +0000 +Subject: [PATCH 2/2] net: phy: realtek: implement configuring in-band an + +Implement the inband_caps() and config_inband() PHY driver methods to +allow configuring the use of in-band-status with SGMII and 2500Base-X on +RTL8226 and RTL8221B 2.5GE PHYs. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 67 ++++++++++++++++++++++++++ + 1 file changed, 67 insertions(+) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -135,6 +135,15 @@ + #define RTL822X_VND2_TO_PAGE_REG(reg) (16 + (((reg) & GENMASK(3, 0)) >> 1)) + #define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) + ++#define RTL822X_VND1_SERDES_CMD 0x7587 ++#define RTL822X_VND1_SERDES_CMD_WRITE BIT(1) ++#define RTL822X_VND1_SERDES_CMD_BUSY BIT(0) ++#define RTL822X_VND1_SERDES_ADDR 0x7588 ++#define RTL822X_VND1_SERDES_ADDR_AUTONEG 0x2 ++#define RTL822X_VND1_SERDES_INBAND_DISABLE 0x71d0 ++#define RTL822X_VND1_SERDES_INBAND_ENABLE 0x70d0 ++#define RTL822X_VND1_SERDES_DATA 0x7589 ++ + #define RTL8221B_VND2_INER 0xa4d2 + #define RTL8221B_VND2_INER_LINK_STATUS BIT(4) + +@@ -1381,6 +1390,50 @@ static int rtl822xb_config_init(struct p + return rtl822x_set_serdes_option_mode(phydev, false); + } + ++static int rtl822x_serdes_write(struct phy_device *phydev, u16 reg, u16 val) ++{ ++ int ret, poll; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_ADDR, reg); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_DATA, val); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CMD, ++ RTL822X_VND1_SERDES_CMD_WRITE | ++ RTL822X_VND1_SERDES_CMD_BUSY); ++ if (ret < 0) ++ return ret; ++ ++ return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, ++ RTL822X_VND1_SERDES_CMD, poll, ++ !(poll & RTL822X_VND1_SERDES_CMD_BUSY), ++ 500, 100000, false); ++} ++ ++static int rtl822x_config_inband(struct phy_device *phydev, unsigned int modes) ++{ ++ return rtl822x_serdes_write(phydev, RTL822X_VND1_SERDES_ADDR_AUTONEG, ++ (modes != LINK_INBAND_DISABLE) ? ++ RTL822X_VND1_SERDES_INBAND_ENABLE : ++ RTL822X_VND1_SERDES_INBAND_DISABLE); ++} ++ ++static unsigned int rtl822x_inband_caps(struct phy_device *phydev, ++ phy_interface_t interface) ++{ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_2500BASEX: ++ case PHY_INTERFACE_MODE_SGMII: ++ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; ++ default: ++ return 0; ++ } ++} ++ + static int rtl822xb_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) + { +@@ -2180,6 +2233,8 @@ static struct phy_driver realtek_drvs[] + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, ++ .inband_caps = rtl822x_inband_caps, ++ .config_inband = rtl822x_config_inband, + .get_rate_matching = rtl822xb_get_rate_matching, + .read_status = rtl822xb_read_status, + .suspend = genphy_suspend, +@@ -2195,6 +2250,8 @@ static struct phy_driver realtek_drvs[] + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, + .config_init = rtl822x_config_init, ++ .inband_caps = rtl822x_inband_caps, ++ .config_inband = rtl822x_config_inband, + .read_status = rtl822xb_c45_read_status, + .suspend = genphy_c45_pma_suspend, + .resume = rtlgen_c45_resume, +@@ -2207,6 +2264,8 @@ static struct phy_driver realtek_drvs[] + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, ++ .inband_caps = rtl822x_inband_caps, ++ .config_inband = rtl822x_config_inband, + .get_rate_matching = rtl822xb_get_rate_matching, + .read_status = rtl822xb_read_status, + .suspend = genphy_suspend, +@@ -2223,6 +2282,8 @@ static struct phy_driver realtek_drvs[] + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, ++ .inband_caps = rtl822x_inband_caps, ++ .config_inband = rtl822x_config_inband, + .get_rate_matching = rtl822xb_get_rate_matching, + .read_status = rtl822xb_read_status, + .suspend = genphy_suspend, +@@ -2239,6 +2300,8 @@ static struct phy_driver realtek_drvs[] + .soft_reset = rtl822x_c45_soft_reset, + .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, ++ .inband_caps = rtl822x_inband_caps, ++ .config_inband = rtl822x_config_inband, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, +@@ -2253,6 +2316,8 @@ static struct phy_driver realtek_drvs[] + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, ++ .inband_caps = rtl822x_inband_caps, ++ .config_inband = rtl822x_config_inband, + .get_rate_matching = rtl822xb_get_rate_matching, + .read_status = rtl822xb_read_status, + .suspend = genphy_suspend, +@@ -2269,6 +2334,8 @@ static struct phy_driver realtek_drvs[] + .soft_reset = rtl822x_c45_soft_reset, + .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, ++ .inband_caps = rtl822x_inband_caps, ++ .config_inband = rtl822x_config_inband, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, 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 710adf7e7a..d799cd2b63 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 -@@ -1815,9 +1815,11 @@ static bool rtlgen_supports_2_5gbps(stru +@@ -1813,9 +1813,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 d4a625a76a..3e6b23f58a 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 @@ -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 -@@ -162,6 +162,10 @@ +@@ -170,6 +170,10 @@ #define RTL8224_SRAM_RTCT_LEN(pair) (0x8028 + (pair) * 4) @@ -24,7 +24,7 @@ Signed-off-by: Daniel Golle #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) -@@ -208,6 +212,10 @@ struct rtl821x_priv { +@@ -216,6 +220,10 @@ struct rtl821x_priv { u16 iner; }; @@ -35,7 +35,7 @@ Signed-off-by: Daniel Golle static int rtl821x_read_page(struct phy_device *phydev) { return __phy_read(phydev, RTL821x_PAGE_SELECT); -@@ -1231,6 +1239,18 @@ static int rtl822x_write_mmd(struct phy_ +@@ -1239,6 +1247,18 @@ static int rtl822x_write_mmd(struct phy_ static int rtl822x_probe(struct phy_device *phydev) { @@ -54,10 +54,10 @@ Signed-off-by: Daniel Golle if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) && phydev->phy_id != RTL_GENERIC_PHYID) return rtl822x_hwmon_init(phydev); -@@ -1342,6 +1362,19 @@ static int rtl822xb_write_mmd(struct phy - return write_ret; +@@ -1320,6 +1340,19 @@ static int rtl822xb_write_mmd(struct phy } + +static int rtl822x_init_phycr1(struct phy_device *phydev, bool no_aldps) +{ + struct rtl822x_priv *priv = phydev->priv; @@ -74,10 +74,11 @@ Signed-off-by: Daniel Golle static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) { bool has_2500, has_sgmii; -@@ -1423,6 +1456,14 @@ static int rtl822x_set_serdes_option_mod +@@ -1377,7 +1410,15 @@ static int rtl822x_set_serdes_option_mod 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); + if (ret < 0) + return ret; @@ -86,6 +87,7 @@ Signed-off-by: Daniel Golle + if (ret < 0) + return ret; + - return 0; ++ return 0; } + static int rtl822x_config_init(struct phy_device *phydev) 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 7afa159588..c46942697f 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 -@@ -1900,10 +1900,32 @@ static int rtl8226_match_phy_device(stru +@@ -1898,10 +1898,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-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 50fa7c9efc..12663d334b 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 -@@ -1597,6 +1597,9 @@ static int rtl822x_c45_get_features(stru +@@ -1626,6 +1626,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-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 a23c88ebe5..e990bcc6fe 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 -@@ -165,6 +165,7 @@ +@@ -174,6 +174,7 @@ #define RTL8221B_PHYCR1 0xa430 #define RTL8221B_PHYCR1_ALDPS_EN BIT(2) #define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12) @@ -21,7 +21,7 @@ Signed-off-by: Daniel Golle #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) -@@ -1372,7 +1373,8 @@ static int rtl822x_init_phycr1(struct ph +@@ -1381,7 +1382,8 @@ static int rtl822x_init_phycr1(struct ph return phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL8221B_PHYCR1, RTL8221B_PHYCR1_ALDPS_EN |