mirror of
https://github.com/openwrt/openwrt.git
synced 2025-03-14 08:16:40 +00:00
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 <luis@luismita.com> Signed-off-by: Daniel Golle <daniel@makrotopia.org> (cherry picked from commit c87a767801ef375feadb0a5c41d5a674ad3a7d2c) Link: https://github.com/openwrt/openwrt/pull/17790 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
parent
7a916c75e8
commit
81db307748
@ -1,104 +0,0 @@
|
||||
From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
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 <daniel@makrotopia.org>
|
||||
---
|
||||
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,
|
@ -0,0 +1,42 @@
|
||||
From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
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 <daniel@makrotopia.org>
|
||||
---
|
||||
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)
|
@ -14,7 +14,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
|
||||
--- 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)
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
|
||||
|
||||
--- 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 <zhaojh329@gmail.com>
|
||||
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,
|
||||
|
@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- 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);
|
||||
|
||||
|
@ -0,0 +1,58 @@
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
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 <daniel@makrotopia.org>
|
||||
---
|
||||
--- 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,
|
@ -0,0 +1,27 @@
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
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 <daniel@makrotopia.org>
|
||||
---
|
||||
--- 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);
|
Loading…
x
Reference in New Issue
Block a user