kernel: backport of changes & helpers
[openwrt/openwrt.git] / target / linux / generic / backport-5.10 / 746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch
1 From ba3c01ee02ed0d821c9f241f179bbc9457542b8f Mon Sep 17 00:00:00 2001
2 From: Ansuel Smith <ansuelsmth@gmail.com>
3 Date: Sun, 10 Oct 2021 00:46:15 +0200
4 Subject: net: phy: at803x: fix resume for QCA8327 phy
5
6 From Documentation phy resume triggers phy reset and restart
7 auto-negotiation. Add a dedicated function to wait reset to finish as
8 it was notice a regression where port sometime are not reliable after a
9 suspend/resume session. The reset wait logic is copied from phy_poll_reset.
10 Add dedicated suspend function to use genphy_suspend only with QCA8337
11 phy and set only additional debug settings for QCA8327. With more test
12 it was reported that QCA8327 doesn't proprely support this mode and
13 using this cause the unreliability of the switch ports, especially the
14 malfunction of the port0.
15
16 Fixes: 15b9df4ece17 ("net: phy: at803x: add resume/suspend function to qca83xx phy")
17 Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
18 Signed-off-by: David S. Miller <davem@davemloft.net>
19 ---
20 drivers/net/phy/at803x.c | 69 +++++++++++++++++++++++++++++++++++++++++++-----
21 1 file changed, 63 insertions(+), 6 deletions(-)
22
23 --- a/drivers/net/phy/at803x.c
24 +++ b/drivers/net/phy/at803x.c
25 @@ -92,9 +92,14 @@
26 #define AT803X_DEBUG_REG_5 0x05
27 #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
28
29 +#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
30 +#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10)
31 +#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13)
32 +
33 #define AT803X_DEBUG_REG_3C 0x3C
34
35 #define AT803X_DEBUG_REG_3D 0x3D
36 +#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
37
38 #define AT803X_DEBUG_REG_1F 0x1F
39 #define AT803X_DEBUG_PLL_ON BIT(2)
40 @@ -1220,6 +1225,58 @@ static int qca83xx_config_init(struct ph
41 return 0;
42 }
43
44 +static int qca83xx_resume(struct phy_device *phydev)
45 +{
46 + int ret, val;
47 +
48 + /* Skip reset if not suspended */
49 + if (!phydev->suspended)
50 + return 0;
51 +
52 + /* Reinit the port, reset values set by suspend */
53 + qca83xx_config_init(phydev);
54 +
55 + /* Reset the port on port resume */
56 + phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
57 +
58 + /* On resume from suspend the switch execute a reset and
59 + * restart auto-negotiation. Wait for reset to complete.
60 + */
61 + ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
62 + 50000, 600000, true);
63 + if (ret)
64 + return ret;
65 +
66 + msleep(1);
67 +
68 + return 0;
69 +}
70 +
71 +static int qca83xx_suspend(struct phy_device *phydev)
72 +{
73 + u16 mask = 0;
74 +
75 + /* Only QCA8337 support actual suspend.
76 + * QCA8327 cause port unreliability when phy suspend
77 + * is set.
78 + */
79 + if (phydev->drv->phy_id == QCA8337_PHY_ID) {
80 + genphy_suspend(phydev);
81 + } else {
82 + mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
83 + phy_modify(phydev, MII_BMCR, mask, 0);
84 + }
85 +
86 + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D,
87 + AT803X_DEBUG_GATE_CLK_IN1000, 0);
88 +
89 + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
90 + AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
91 + AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
92 +
93 + return 0;
94 +}
95 +
96 static struct phy_driver at803x_driver[] = {
97 {
98 /* Qualcomm Atheros AR8035 */
99 @@ -1329,8 +1386,8 @@ static struct phy_driver at803x_driver[]
100 .get_sset_count = at803x_get_sset_count,
101 .get_strings = at803x_get_strings,
102 .get_stats = at803x_get_stats,
103 - .suspend = genphy_suspend,
104 - .resume = genphy_resume,
105 + .suspend = qca83xx_suspend,
106 + .resume = qca83xx_resume,
107 }, {
108 /* QCA8327-A from switch QCA8327-AL1A */
109 .phy_id = QCA8327_A_PHY_ID,
110 @@ -1344,8 +1401,8 @@ static struct phy_driver at803x_driver[]
111 .get_sset_count = at803x_get_sset_count,
112 .get_strings = at803x_get_strings,
113 .get_stats = at803x_get_stats,
114 - .suspend = genphy_suspend,
115 - .resume = genphy_resume,
116 + .suspend = qca83xx_suspend,
117 + .resume = qca83xx_resume,
118 }, {
119 /* QCA8327-B from switch QCA8327-BL1A */
120 .phy_id = QCA8327_B_PHY_ID,
121 @@ -1359,8 +1416,8 @@ static struct phy_driver at803x_driver[]
122 .get_sset_count = at803x_get_sset_count,
123 .get_strings = at803x_get_strings,
124 .get_stats = at803x_get_stats,
125 - .suspend = genphy_suspend,
126 - .resume = genphy_resume,
127 + .suspend = qca83xx_suspend,
128 + .resume = qca83xx_resume,
129 }, };
130
131 module_phy_driver(at803x_driver);