[openwrt/openwrt] kernel: net: phy: realtek: replace in-band AN hack

LEDE Commits lede-commits at lists.infradead.org
Tue Jan 6 17:31:41 PST 2026


dangole pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/dfce21df969b54e237ae3c1ea32b627efa8285f4

commit dfce21df969b54e237ae3c1ea32b627efa8285f4
Author: Daniel Golle <daniel at makrotopia.org>
AuthorDate: Sat Jan 3 15:41:17 2026 +0000

    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 <daniel at makrotopia.org>
---
 ...ek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch |  79 -----------
 ...-realtek-implement-configuring-in-band-an.patch | 146 +++++++++++++++++++++
 ...ltek-make-sure-paged-read-is-protected-by.patch |   2 +-
 .../720-04-net-phy-realtek-setup-aldps.patch       |  16 ++-
 ...-realtek-detect-early-version-of-RTL8221B.patch |   2 +-
 ...phy-realtek-mark-existing-MMDs-as-present.patch |   2 +-
 ...09-net-phy-realtek-disable-MDIO-broadcast.patch |   4 +-
 7 files changed, 160 insertions(+), 91 deletions(-)

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 <daniel at makrotopia.org>
-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 <ptpt52 at gmail.com>
-Reported-by: Chukun Pan <amadeus at jmu.edu.cn>
-Reported-by: Yevhen Kolomeiko <jarvis2709 at gmail.com>
-Tested-by: Yevhen Kolomeiko <jarvis2709 at gmail.com>
-Signed-off-by: Daniel Golle <daniel at makrotopia.org>
----
- 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 <daniel at makrotopia.org>
+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 <daniel at makrotopia.org>
+---
+ 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 <daniel at makrotopia.org>
 
 --- 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 <daniel at makrotopia.org>
 
 --- 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 <daniel at makrotopia.org>
  #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 <daniel at makrotopia.org>
  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 <daniel at makrotopia.org>
  	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 <daniel at makrotopia.org>
  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 <daniel at makrotopia.org>
 +	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 <daniel at makrotopia.org>
 Signed-off-by: Mieczyslaw Nalewaj <namiltd at yahoo.com>
 --- 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 <daniel at makrotopia.org>
 
 --- 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 <daniel at makrotopia.org>
 ---
 --- 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 <daniel at makrotopia.org>
  
  #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 |




More information about the lede-commits mailing list