Skip to content

Commit 8b33f8a

Browse files
committed
kernel: net: phy: realtek: replace hack with proper fix
RealTek's 2.5G PHYs suffer from an up to now inexplicable problem which results in the SerDes mode not being properly setup and disabling in-band AN leading to a timeout waiting for a busy-bit to clear. Up to now there has been a crude work-around: resetting the PHY and trying another time. The cause has now been found as a wrong access to register PHYCR1 on MDIO_MMD_VEND1 instead of MDIO_MMD_VEND2 when setting up ALDPS as well as disabling the MDIO broadcast address 0. In order to access MDIO_MMD_VEND2 on Clause-22-only busses a custom .read_mmd and .write_mmd ops are implemented, mapping MDIO_MMD_VEND2 to paged access as this is required. Also, as ALDPS by design disables the SerDes PCS of the PHY in case the link has been down for a while, move enabling ALDPS to the end of the config_init function to not face problems when configuring the interface mode and in-band AN. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
1 parent 4f551e4 commit 8b33f8a

6 files changed

+152
-158
lines changed

target/linux/generic/pending-6.12/720-04-net-phy-realtek-setup-aldps.patch

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,68 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2424
#define RTL8366RB_POWER_SAVE 0x15
2525
#define RTL8366RB_POWER_SAVE_ON BIT(12)
2626

27-
@@ -1090,6 +1094,15 @@ static int rtl822xb_config_init(struct p
27+
@@ -175,6 +179,10 @@ struct rtl821x_priv {
28+
u32 saved_wolopts;
29+
};
30+
31+
+struct rtl822x_priv {
32+
+ bool enable_aldps;
33+
+};
34+
+
35+
static int rtl821x_read_page(struct phy_device *phydev)
36+
{
37+
return __phy_read(phydev, RTL821x_PAGE_SELECT);
38+
@@ -1025,6 +1033,18 @@ static int rtl822x_write_mmd(struct phy_
39+
40+
static int rtl822x_probe(struct phy_device *phydev)
41+
{
42+
+ struct device *dev = &phydev->mdio.dev;
43+
+ struct rtl822x_priv *priv;
44+
+
45+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
46+
+ if (!priv)
47+
+ return -ENOMEM;
48+
+
49+
+ priv->enable_aldps = of_property_read_bool(dev->of_node,
50+
+ "realtek,aldps-enable");
51+
+
52+
+ phydev->priv = priv;
53+
+
54+
if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) &&
55+
phydev->phy_id != RTL_GENERIC_PHYID)
56+
return rtl822x_hwmon_init(phydev);
57+
@@ -1032,6 +1052,19 @@ static int rtl822x_probe(struct phy_devi
58+
return 0;
59+
}
60+
61+
+static int rtl822x_init_phycr1(struct phy_device *phydev, bool no_aldps)
62+
+{
63+
+ struct rtl822x_priv *priv = phydev->priv;
64+
+ u16 val = 0;
65+
+
66+
+ if (priv->enable_aldps && !no_aldps)
67+
+ val = RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN;
68+
+
69+
+ return phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL8221B_PHYCR1,
70+
+ RTL8221B_PHYCR1_ALDPS_EN |
71+
+ RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN, val);
72+
+}
73+
+
74+
static int rtl822xb_config_init(struct phy_device *phydev)
75+
{
76+
bool has_2500, has_sgmii;
77+
@@ -1108,6 +1141,14 @@ static int rtl822xb_config_init(struct p
2878
if (ret < 0)
2979
return ret;
3080

31-
+ if (of_property_read_bool(phydev->mdio.dev.of_node, "realtek,aldps-enable"))
32-
+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1,
33-
+ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
34-
+ else
35-
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1,
36-
+ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
81+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
3782
+ if (ret < 0)
3883
+ return ret;
3984
+
40-
/* Disable SGMII AN */
41-
ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2);
42-
if (ret < 0)
85+
+ ret = rtl822x_init_phycr1(phydev, false);
86+
+ if (ret < 0)
87+
+ return ret;
88+
+
89+
return 0;
90+
}
91+

target/linux/generic/pending-6.12/720-08-net-phy-realtek-work-around-broken-serdes.patch

Lines changed: 0 additions & 58 deletions
This file was deleted.

target/linux/generic/pending-6.12/720-09-net-phy-realtek-disable-MDIO-broadcast.patch

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
1313
---
1414
--- a/drivers/net/phy/realtek/realtek_main.c
1515
+++ b/drivers/net/phy/realtek/realtek_main.c
16-
@@ -1050,6 +1050,11 @@ static int rtl822xb_config_init(struct p
17-
phydev->host_interfaces) ||
18-
phydev->interface == PHY_INTERFACE_MODE_SGMII;
16+
@@ -132,6 +132,7 @@
17+
#define RTL8221B_PHYCR1 0xa430
18+
#define RTL8221B_PHYCR1_ALDPS_EN BIT(2)
19+
#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12)
20+
+#define RTL8221B_PHYCR1_PHYAD_0_EN BIT(13)
1921

20-
+ /* disable listening on MDIO broadcast address (0) */
21-
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xa430, BIT(13));
22-
+ if (ret < 0)
23-
+ return ret;
24-
+
25-
/* fill in possible interfaces */
26-
__assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
27-
has_2500);
22+
#define RTL8366RB_POWER_SAVE 0x15
23+
#define RTL8366RB_POWER_SAVE_ON BIT(12)
24+
@@ -1062,7 +1063,8 @@ static int rtl822x_init_phycr1(struct ph
25+
26+
return phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL8221B_PHYCR1,
27+
RTL8221B_PHYCR1_ALDPS_EN |
28+
- RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN, val);
29+
+ RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN |
30+
+ RTL8221B_PHYCR1_PHYAD_0_EN, val);
31+
}
32+
33+
static int rtl822xb_config_init(struct phy_device *phydev)

target/linux/generic/pending-6.6/720-04-net-phy-realtek-setup-aldps.patch

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,68 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2424
#define RTL8366RB_POWER_SAVE 0x15
2525
#define RTL8366RB_POWER_SAVE_ON BIT(12)
2626

27-
@@ -1090,6 +1094,15 @@ static int rtl822xb_config_init(struct p
27+
@@ -175,6 +179,10 @@ struct rtl821x_priv {
28+
u32 saved_wolopts;
29+
};
30+
31+
+struct rtl822x_priv {
32+
+ bool enable_aldps;
33+
+};
34+
+
35+
static int rtl821x_read_page(struct phy_device *phydev)
36+
{
37+
return __phy_read(phydev, RTL821x_PAGE_SELECT);
38+
@@ -1025,6 +1033,18 @@ static int rtl822x_write_mmd(struct phy_
39+
40+
static int rtl822x_probe(struct phy_device *phydev)
41+
{
42+
+ struct device *dev = &phydev->mdio.dev;
43+
+ struct rtl822x_priv *priv;
44+
+
45+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
46+
+ if (!priv)
47+
+ return -ENOMEM;
48+
+
49+
+ priv->enable_aldps = of_property_read_bool(dev->of_node,
50+
+ "realtek,aldps-enable");
51+
+
52+
+ phydev->priv = priv;
53+
+
54+
if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) &&
55+
phydev->phy_id != RTL_GENERIC_PHYID)
56+
return rtl822x_hwmon_init(phydev);
57+
@@ -1032,6 +1052,19 @@ static int rtl822x_probe(struct phy_devi
58+
return 0;
59+
}
60+
61+
+static int rtl822x_init_phycr1(struct phy_device *phydev, bool no_aldps)
62+
+{
63+
+ struct rtl822x_priv *priv = phydev->priv;
64+
+ u16 val = 0;
65+
+
66+
+ if (priv->enable_aldps && !no_aldps)
67+
+ val = RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN;
68+
+
69+
+ return phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL8221B_PHYCR1,
70+
+ RTL8221B_PHYCR1_ALDPS_EN |
71+
+ RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN, val);
72+
+}
73+
+
74+
static int rtl822xb_config_init(struct phy_device *phydev)
75+
{
76+
bool has_2500, has_sgmii;
77+
@@ -1108,6 +1141,14 @@ static int rtl822xb_config_init(struct p
2878
if (ret < 0)
2979
return ret;
3080

31-
+ if (of_property_read_bool(phydev->mdio.dev.of_node, "realtek,aldps-enable"))
32-
+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1,
33-
+ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
34-
+ else
35-
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1,
36-
+ RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
81+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
3782
+ if (ret < 0)
3883
+ return ret;
3984
+
40-
/* Disable SGMII AN */
41-
ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2);
42-
if (ret < 0)
85+
+ ret = rtl822x_init_phycr1(phydev, false);
86+
+ if (ret < 0)
87+
+ return ret;
88+
+
89+
return 0;
90+
}
91+

target/linux/generic/pending-6.6/720-08-net-phy-realtek-work-around-broken-serdes.patch

Lines changed: 0 additions & 58 deletions
This file was deleted.

target/linux/generic/pending-6.6/720-09-net-phy-realtek-disable-MDIO-broadcast.patch

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
1313
---
1414
--- a/drivers/net/phy/realtek/realtek_main.c
1515
+++ b/drivers/net/phy/realtek/realtek_main.c
16-
@@ -1050,6 +1050,11 @@ static int rtl822xb_config_init(struct p
17-
phydev->host_interfaces) ||
18-
phydev->interface == PHY_INTERFACE_MODE_SGMII;
16+
@@ -132,6 +132,7 @@
17+
#define RTL8221B_PHYCR1 0xa430
18+
#define RTL8221B_PHYCR1_ALDPS_EN BIT(2)
19+
#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12)
20+
+#define RTL8221B_PHYCR1_PHYAD_0_EN BIT(13)
1921

20-
+ /* disable listening on MDIO broadcast address (0) */
21-
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xa430, BIT(13));
22-
+ if (ret < 0)
23-
+ return ret;
24-
+
25-
/* fill in possible interfaces */
26-
__assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
27-
has_2500);
22+
#define RTL8366RB_POWER_SAVE 0x15
23+
#define RTL8366RB_POWER_SAVE_ON BIT(12)
24+
@@ -1062,7 +1063,8 @@ static int rtl822x_init_phycr1(struct ph
25+
26+
return phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL8221B_PHYCR1,
27+
RTL8221B_PHYCR1_ALDPS_EN |
28+
- RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN, val);
29+
+ RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN |
30+
+ RTL8221B_PHYCR1_PHYAD_0_EN, val);
31+
}
32+
33+
static int rtl822xb_config_init(struct phy_device *phydev)

0 commit comments

Comments
 (0)