From c87a767801ef375feadb0a5c41d5a674ad3a7d2c Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 30 Jan 2025 05:49:43 +0000 Subject: [PATCH] generic: net: phy: realtek: work-around hang on SerDes setup On some but not all devices using the RTL8221B 2.5GBit/s PHY the SerDes setup sequence may hang under some circumstances (eg. <2500M link partner present during boot). RTL8221B-VB-CG 2.5Gbps PHY (C45) mdio-bus:01: rtl822xb_config_init failed: -110 Work-around the issue by performing a hardware reset and subsequent retry of the SerDes setup, which seems to always succeed. Doing this requires moving ALDPS setup to config_init (which is anyway the better place for that) as it otherwise doesn't survive the reset. Also disable listening on MDIO address 0 which may be used by other PHYs despite being spec'ed as "broadcast address", as bus activity on address 0 may otherwise confuse the RealTek PHY for good reasons. Tested-by: Luis Mita Signed-off-by: Daniel Golle --- ...ealtek-introduce-rtl822x_aldps_probe.patch | 104 ------------------ .../720-04-net-phy-realtek-setup-aldps.patch | 42 +++++++ ...tek-detect-early-version-of-RTL8221B.patch | 2 +- ...ealtek-support-interrupt-of-RTL8221B.patch | 18 +-- ...ealtek-mark-existing-MMDs-as-present.patch | 2 +- ...hy-realtek-work-around-broken-serdes.patch | 58 ++++++++++ ...t-phy-realtek-disable-MDIO-broadcast.patch | 27 +++++ 7 files changed, 138 insertions(+), 115 deletions(-) delete mode 100644 target/linux/generic/pending-6.6/720-04-net-phy-realtek-introduce-rtl822x_aldps_probe.patch create mode 100644 target/linux/generic/pending-6.6/720-04-net-phy-realtek-setup-aldps.patch create mode 100644 target/linux/generic/pending-6.6/720-08-net-phy-realtek-work-around-broken-serdes.patch create mode 100644 target/linux/generic/pending-6.6/720-09-net-phy-realtek-disable-MDIO-broadcast.patch diff --git a/target/linux/generic/pending-6.6/720-04-net-phy-realtek-introduce-rtl822x_aldps_probe.patch b/target/linux/generic/pending-6.6/720-04-net-phy-realtek-introduce-rtl822x_aldps_probe.patch deleted file mode 100644 index 6610af12c3..0000000000 --- a/target/linux/generic/pending-6.6/720-04-net-phy-realtek-introduce-rtl822x_aldps_probe.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Sat, 22 Apr 2023 03:26:01 +0100 -Subject: [PATCH] net: phy: realtek: setup ALDPS on RTL822x - -Setup Link Down Power Saving Mode according the DTS property -just like for RTL821x 1GE PHYs. - -Signed-off-by: Daniel Golle ---- - drivers/net/phy/realtek/realtek_main.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -82,6 +82,10 @@ - - #define RTL822X_VND2_GANLPAR 0xa414 - -+#define RTL8221B_PHYCR1 0xa430 -+#define RTL8221B_PHYCR1_ALDPS_EN BIT(2) -+#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12) -+ - #define RTL8366RB_POWER_SAVE 0x15 - #define RTL8366RB_POWER_SAVE_ON BIT(12) - -@@ -1207,6 +1211,25 @@ static int rtl8251b_c45_match_phy_device - return rtlgen_is_c45_match(phydev, RTL_8251B, true); - } - -+static int rtl822x_aldps_probe(struct phy_device *phydev) -+{ -+ struct device *dev = &phydev->mdio.dev; -+ int val; -+ -+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1); -+ if (val < 0) -+ return val; -+ -+ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) -+ val |= RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN; -+ else -+ val &= ~(RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); -+ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, val); -+ -+ return rtl822x_probe(phydev); -+} -+ - static int rtlgen_resume(struct phy_device *phydev) - { - int ret = genphy_resume(phydev); -@@ -1478,6 +1501,7 @@ static struct phy_driver realtek_drvs[] - }, { - PHY_ID_MATCH_EXACT(0x001cc838), - .name = "RTL8226-CG 2.5Gbps PHY", -+ .probe = rtl822x_aldps_probe, - .soft_reset = genphy_soft_reset, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, -@@ -1489,6 +1513,7 @@ static struct phy_driver realtek_drvs[] - }, { - PHY_ID_MATCH_EXACT(0x001cc848), - .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", -+ .probe = rtl822x_aldps_probe, - .soft_reset = genphy_soft_reset, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, -@@ -1503,7 +1528,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)", - .soft_reset = genphy_soft_reset, -- .probe = rtl822x_probe, -+ .probe = rtl822x_aldps_probe, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, - .config_init = rtl822xb_config_init, -@@ -1517,7 +1542,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)", - .soft_reset = genphy_soft_reset, -- .probe = rtl822x_probe, -+ .probe = rtl822x_aldps_probe, - .config_init = rtl822xb_config_init, - .get_rate_matching = rtl822xb_get_rate_matching, - .get_features = rtl822x_c45_get_features, -@@ -1529,7 +1554,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)", - .soft_reset = genphy_soft_reset, -- .probe = rtl822x_probe, -+ .probe = rtl822x_aldps_probe, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, - .config_init = rtl822xb_config_init, -@@ -1543,7 +1568,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)", - .soft_reset = genphy_soft_reset, -- .probe = rtl822x_probe, -+ .probe = rtl822x_aldps_probe, - .config_init = rtl822xb_config_init, - .get_rate_matching = rtl822xb_get_rate_matching, - .get_features = rtl822x_c45_get_features, diff --git a/target/linux/generic/pending-6.6/720-04-net-phy-realtek-setup-aldps.patch b/target/linux/generic/pending-6.6/720-04-net-phy-realtek-setup-aldps.patch new file mode 100644 index 0000000000..23b3ca893a --- /dev/null +++ b/target/linux/generic/pending-6.6/720-04-net-phy-realtek-setup-aldps.patch @@ -0,0 +1,42 @@ +From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 22 Apr 2023 03:26:01 +0100 +Subject: [PATCH] net: phy: realtek: setup ALDPS on RTL822x + +Setup Link Down Power Saving Mode according the DTS property +just like for RTL821x 1GE PHYs. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek/realtek_main.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -82,6 +82,10 @@ + + #define RTL822X_VND2_GANLPAR 0xa414 + ++#define RTL8221B_PHYCR1 0xa430 ++#define RTL8221B_PHYCR1_ALDPS_EN BIT(2) ++#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12) ++ + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) + +@@ -889,6 +893,15 @@ static int rtl822xb_config_init(struct p + if (ret < 0) + 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, ++ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); ++ else ++ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, ++ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); ++ if (ret < 0) ++ return ret; ++ + /* Disable SGMII AN */ + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2); + if (ret < 0) diff --git a/target/linux/generic/pending-6.6/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch b/target/linux/generic/pending-6.6/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch index 22c271c3eb..d7fbf3a2a6 100644 --- a/target/linux/generic/pending-6.6/720-05-net-phy-realtek-detect-early-version-of-RTL8221B.patch +++ b/target/linux/generic/pending-6.6/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 -@@ -1157,10 +1157,32 @@ static int rtl8226_match_phy_device(stru +@@ -1166,10 +1166,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.6/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch b/target/linux/generic/pending-6.6/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch index 3e9b34b8a5..45ca5413f3 100644 --- a/target/linux/generic/pending-6.6/720-06-net-phy-realtek-support-interrupt-of-RTL8221B.patch +++ b/target/linux/generic/pending-6.6/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 -@@ -1387,6 +1387,51 @@ static irqreturn_t rtl9000a_handle_inter +@@ -1377,6 +1377,51 @@ static irqreturn_t rtl9000a_handle_inter return IRQ_HANDLED; } @@ -64,39 +64,39 @@ Signed-off-by: Jianhui Zhao static struct phy_driver realtek_drvs[] = { { PHY_ID_MATCH_EXACT(0x00008201), -@@ -1549,6 +1594,8 @@ static struct phy_driver realtek_drvs[] +@@ -1537,6 +1582,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)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = genphy_soft_reset, - .probe = rtl822x_aldps_probe, + .probe = rtl822x_probe, .get_features = rtl822x_get_features, -@@ -1563,6 +1610,8 @@ static struct phy_driver realtek_drvs[] +@@ -1551,6 +1598,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)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = genphy_soft_reset, - .probe = rtl822x_aldps_probe, + .probe = rtl822x_probe, .config_init = rtl822xb_config_init, -@@ -1575,6 +1624,8 @@ static struct phy_driver realtek_drvs[] +@@ -1563,6 +1612,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)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = genphy_soft_reset, - .probe = rtl822x_aldps_probe, + .probe = rtl822x_probe, .get_features = rtl822x_get_features, -@@ -1589,6 +1640,8 @@ static struct phy_driver realtek_drvs[] +@@ -1577,6 +1628,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)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = genphy_soft_reset, - .probe = rtl822x_aldps_probe, + .probe = rtl822x_probe, .config_init = rtl822xb_config_init, diff --git a/target/linux/generic/pending-6.6/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch b/target/linux/generic/pending-6.6/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch index 1ef42e866d..555e5905d3 100644 --- a/target/linux/generic/pending-6.6/720-07-net-phy-realtek-mark-existing-MMDs-as-present.patch +++ b/target/linux/generic/pending-6.6/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 -@@ -1034,6 +1034,9 @@ static int rtl822x_c45_get_features(stru +@@ -1043,6 +1043,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.6/720-08-net-phy-realtek-work-around-broken-serdes.patch b/target/linux/generic/pending-6.6/720-08-net-phy-realtek-work-around-broken-serdes.patch new file mode 100644 index 0000000000..e356a0a6ee --- /dev/null +++ b/target/linux/generic/pending-6.6/720-08-net-phy-realtek-work-around-broken-serdes.patch @@ -0,0 +1,58 @@ +From: Daniel Golle +Date: Thu, 30 Jan 2025 05:33:12 +0000 +Subject: [PATCH] net: phy: realtek: work around broken SerDes + +For still unknown reasons the SerDes init sequence may sometimes +time out because a self-clearing bit never clears, indicating the +PHY has entered an unrecoverable error state. + +Work-around the issue by triggering a hardware reset and retry the +setup sequence while warning the user that this has happened. +This is really more of a work-around than a fix, and should be +replaced by a better actual fix in future (hopefully). + +Signed-off-by: Daniel Golle +--- +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -923,6 +923,22 @@ static int rtl822xb_config_init(struct p + return 0; + } + ++static int rtl822xb_config_init_war(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = rtl822xb_config_init(phydev); ++ ++ if (ret == -ETIMEDOUT) { ++ phydev_warn(phydev, "SerDes setup timed out, retrying\n"); ++ phy_device_reset(phydev, 1); ++ phy_device_reset(phydev, 0); ++ ret = rtl822xb_config_init(phydev); ++ } ++ ++ return ret; ++} ++ + static int rtl822xb_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) + { +@@ -1605,7 +1621,7 @@ static struct phy_driver realtek_drvs[] + .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, +- .config_init = rtl822xb_config_init, ++ .config_init = rtl822xb_config_init_war, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, +@@ -1635,7 +1651,7 @@ static struct phy_driver realtek_drvs[] + .handle_interrupt = rtl8221b_handle_interrupt, + .soft_reset = genphy_soft_reset, + .probe = rtl822x_probe, +- .config_init = rtl822xb_config_init, ++ .config_init = rtl822xb_config_init_war, + .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.6/720-09-net-phy-realtek-disable-MDIO-broadcast.patch b/target/linux/generic/pending-6.6/720-09-net-phy-realtek-disable-MDIO-broadcast.patch new file mode 100644 index 0000000000..b2d26a8780 --- /dev/null +++ b/target/linux/generic/pending-6.6/720-09-net-phy-realtek-disable-MDIO-broadcast.patch @@ -0,0 +1,27 @@ +From: Daniel Golle +Date: Thu, 30 Jan 2025 05:38:31 +0000 +Subject: [PATCH] net: phy: realtek: disable MDIO broadcast + +RealTek's PHYs by default also listen on MDIO address 0 which is defined +as broadcast address. This can lead to problems if there is an actual PHY +(such as MT7981 built-in PHY) present at this address, as accessing that +PHY may then confuse the RealTek PHY. + +Disabled listening on the MDIO broadcast address to avoid such problems. + +Signed-off-by: Daniel Golle +--- +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -849,6 +849,11 @@ static int rtl822xb_config_init(struct p + phydev->host_interfaces) || + phydev->interface == PHY_INTERFACE_MODE_SGMII; + ++ /* disable listening on MDIO broadcast address (0) */ ++ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xa430, BIT(13)); ++ if (ret < 0) ++ return ret; ++ + /* fill in possible interfaces */ + __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, + has_2500); -- 2.30.2