hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
kernel/drivers/net/phy/smsc.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * drivers/net/phy/smsc.c
34 *
....@@ -7,15 +8,11 @@
78 *
89 * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
910 *
10
- * This program is free software; you can redistribute it and/or modify it
11
- * under the terms of the GNU General Public License as published by the
12
- * Free Software Foundation; either version 2 of the License, or (at your
13
- * option) any later version.
14
- *
1511 * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@shawell.net
1612 *
1713 */
1814
15
+#include <linux/clk.h>
1916 #include <linux/kernel.h>
2017 #include <linux/module.h>
2118 #include <linux/mii.h>
....@@ -24,6 +21,17 @@
2421 #include <linux/phy.h>
2522 #include <linux/netdevice.h>
2623 #include <linux/smscphy.h>
24
+
25
+/* Vendor-specific PHY Definitions */
26
+/* EDPD NLP / crossover time configuration */
27
+#define PHY_EDPD_CONFIG 16
28
+#define PHY_EDPD_CONFIG_EXT_CROSSOVER_ 0x0001
29
+
30
+/* Control/Status Indication Register */
31
+#define SPECIAL_CTRL_STS 27
32
+#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ 0x8000
33
+#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ 0x4000
34
+#define SPECIAL_CTRL_STS_AMDIX_STATE_ 0x2000
2735
2836 struct smsc_hw_stat {
2937 const char *string;
....@@ -37,14 +45,22 @@
3745
3846 struct smsc_phy_priv {
3947 bool energy_enable;
48
+ struct clk *refclk;
4049 };
4150
4251 static int smsc_phy_config_intr(struct phy_device *phydev)
4352 {
44
- int rc = phy_write (phydev, MII_LAN83C185_IM,
45
- ((PHY_INTERRUPT_ENABLED == phydev->interrupts)
46
- ? MII_LAN83C185_ISF_INT_PHYLIB_EVENTS
47
- : 0));
53
+ struct smsc_phy_priv *priv = phydev->priv;
54
+ u16 intmask = 0;
55
+ int rc;
56
+
57
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
58
+ intmask = MII_LAN83C185_ISF_INT4 | MII_LAN83C185_ISF_INT6;
59
+ if (priv->energy_enable)
60
+ intmask |= MII_LAN83C185_ISF_INT7;
61
+ }
62
+
63
+ rc = phy_write(phydev, MII_LAN83C185_IM, intmask);
4864
4965 return rc < 0 ? rc : 0;
5066 }
....@@ -59,19 +75,21 @@
5975 static int smsc_phy_config_init(struct phy_device *phydev)
6076 {
6177 struct smsc_phy_priv *priv = phydev->priv;
78
+ int rc;
6279
63
- int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
80
+ if (!priv->energy_enable)
81
+ return 0;
82
+
83
+ rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
6484
6585 if (rc < 0)
6686 return rc;
6787
68
- if (priv->energy_enable) {
69
- /* Enable energy detect mode for this SMSC Transceivers */
70
- rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
71
- rc | MII_LAN83C185_EDPWRDOWN);
72
- if (rc < 0)
73
- return rc;
74
- }
88
+ /* Enable energy detect mode for this SMSC Transceivers */
89
+ rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
90
+ rc | MII_LAN83C185_EDPWRDOWN);
91
+ if (rc < 0)
92
+ return rc;
7593
7694 return smsc_phy_ack_interrupt(phydev);
7795 }
....@@ -100,6 +118,57 @@
100118 return smsc_phy_ack_interrupt(phydev);
101119 }
102120
121
+static int lan87xx_config_aneg(struct phy_device *phydev)
122
+{
123
+ int rc;
124
+ int val;
125
+
126
+ switch (phydev->mdix_ctrl) {
127
+ case ETH_TP_MDI:
128
+ val = SPECIAL_CTRL_STS_OVRRD_AMDIX_;
129
+ break;
130
+ case ETH_TP_MDI_X:
131
+ val = SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
132
+ SPECIAL_CTRL_STS_AMDIX_STATE_;
133
+ break;
134
+ case ETH_TP_MDI_AUTO:
135
+ val = SPECIAL_CTRL_STS_AMDIX_ENABLE_;
136
+ break;
137
+ default:
138
+ return genphy_config_aneg(phydev);
139
+ }
140
+
141
+ rc = phy_read(phydev, SPECIAL_CTRL_STS);
142
+ if (rc < 0)
143
+ return rc;
144
+
145
+ rc &= ~(SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
146
+ SPECIAL_CTRL_STS_AMDIX_ENABLE_ |
147
+ SPECIAL_CTRL_STS_AMDIX_STATE_);
148
+ rc |= val;
149
+ phy_write(phydev, SPECIAL_CTRL_STS, rc);
150
+
151
+ phydev->mdix = phydev->mdix_ctrl;
152
+ return genphy_config_aneg(phydev);
153
+}
154
+
155
+static int lan95xx_config_aneg_ext(struct phy_device *phydev)
156
+{
157
+ int rc;
158
+
159
+ if (phydev->phy_id != 0x0007c0f0) /* not (LAN9500A or LAN9505A) */
160
+ return lan87xx_config_aneg(phydev);
161
+
162
+ /* Extend Manual AutoMDIX timer */
163
+ rc = phy_read(phydev, PHY_EDPD_CONFIG);
164
+ if (rc < 0)
165
+ return rc;
166
+
167
+ rc |= PHY_EDPD_CONFIG_EXT_CROSSOVER_;
168
+ phy_write(phydev, PHY_EDPD_CONFIG, rc);
169
+ return lan87xx_config_aneg(phydev);
170
+}
171
+
103172 /*
104173 * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable
105174 * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to
....@@ -116,8 +185,6 @@
116185 int err = genphy_read_status(phydev);
117186
118187 if (!phydev->link && priv->energy_enable) {
119
- int i;
120
-
121188 /* Disable EDPD to wake up PHY */
122189 int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
123190 if (rc < 0)
....@@ -128,16 +195,15 @@
128195 if (rc < 0)
129196 return rc;
130197
131
- /* Wait max 640 ms to detect energy */
132
- for (i = 0; i < 64; i++) {
133
- /* Sleep to allow link test pulses to be sent */
134
- msleep(10);
135
- rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
136
- if (rc < 0)
137
- return rc;
138
- if (rc & MII_LAN83C185_ENERGYON)
139
- break;
140
- }
198
+ /* Wait max 640 ms to detect energy and the timeout is not
199
+ * an actual error.
200
+ */
201
+ read_poll_timeout(phy_read, rc,
202
+ rc & MII_LAN83C185_ENERGYON || rc < 0,
203
+ 10000, 640000, true, phydev,
204
+ MII_LAN83C185_CTRL_STATUS);
205
+ if (rc < 0)
206
+ return rc;
141207
142208 /* Re-enable EDPD */
143209 rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
....@@ -192,11 +258,20 @@
192258 data[i] = smsc_get_stat(phydev, i);
193259 }
194260
261
+static void smsc_phy_remove(struct phy_device *phydev)
262
+{
263
+ struct smsc_phy_priv *priv = phydev->priv;
264
+
265
+ clk_disable_unprepare(priv->refclk);
266
+ clk_put(priv->refclk);
267
+}
268
+
195269 static int smsc_phy_probe(struct phy_device *phydev)
196270 {
197271 struct device *dev = &phydev->mdio.dev;
198272 struct device_node *of_node = dev->of_node;
199273 struct smsc_phy_priv *priv;
274
+ int ret;
200275
201276 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
202277 if (!priv)
....@@ -209,6 +284,22 @@
209284
210285 phydev->priv = priv;
211286
287
+ /* Make clk optional to keep DTB backward compatibility. */
288
+ priv->refclk = clk_get_optional(dev, NULL);
289
+ if (IS_ERR(priv->refclk))
290
+ return dev_err_probe(dev, PTR_ERR(priv->refclk),
291
+ "Failed to request clock\n");
292
+
293
+ ret = clk_prepare_enable(priv->refclk);
294
+ if (ret)
295
+ return ret;
296
+
297
+ ret = clk_set_rate(priv->refclk, 50 * 1000 * 1000);
298
+ if (ret) {
299
+ clk_disable_unprepare(priv->refclk);
300
+ return ret;
301
+ }
302
+
212303 return 0;
213304 }
214305
....@@ -218,8 +309,7 @@
218309 .phy_id_mask = 0xfffffff0,
219310 .name = "SMSC LAN83C185",
220311
221
- .features = PHY_BASIC_FEATURES,
222
- .flags = PHY_HAS_INTERRUPT,
312
+ /* PHY_BASIC_FEATURES */
223313
224314 .probe = smsc_phy_probe,
225315
....@@ -238,8 +328,7 @@
238328 .phy_id_mask = 0xfffffff0,
239329 .name = "SMSC LAN8187",
240330
241
- .features = PHY_BASIC_FEATURES,
242
- .flags = PHY_HAS_INTERRUPT,
331
+ /* PHY_BASIC_FEATURES */
243332
244333 .probe = smsc_phy_probe,
245334
....@@ -259,12 +348,14 @@
259348 .suspend = genphy_suspend,
260349 .resume = genphy_resume,
261350 }, {
351
+ /* This covers internal PHY (phy_id: 0x0007C0C3) for
352
+ * LAN9500 (PID: 0x9500), LAN9514 (PID: 0xec00), LAN9505 (PID: 0x9505)
353
+ */
262354 .phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
263355 .phy_id_mask = 0xfffffff0,
264356 .name = "SMSC LAN8700",
265357
266
- .features = PHY_BASIC_FEATURES,
267
- .flags = PHY_HAS_INTERRUPT,
358
+ /* PHY_BASIC_FEATURES */
268359
269360 .probe = smsc_phy_probe,
270361
....@@ -272,6 +363,7 @@
272363 .read_status = lan87xx_read_status,
273364 .config_init = smsc_phy_config_init,
274365 .soft_reset = smsc_phy_reset,
366
+ .config_aneg = lan87xx_config_aneg,
275367
276368 /* IRQ related */
277369 .ack_interrupt = smsc_phy_ack_interrupt,
....@@ -289,8 +381,7 @@
289381 .phy_id_mask = 0xfffffff0,
290382 .name = "SMSC LAN911x Internal PHY",
291383
292
- .features = PHY_BASIC_FEATURES,
293
- .flags = PHY_HAS_INTERRUPT,
384
+ /* PHY_BASIC_FEATURES */
294385
295386 .probe = smsc_phy_probe,
296387
....@@ -304,19 +395,23 @@
304395 .suspend = genphy_suspend,
305396 .resume = genphy_resume,
306397 }, {
398
+ /* This covers internal PHY (phy_id: 0x0007C0F0) for
399
+ * LAN9500A (PID: 0x9E00), LAN9505A (PID: 0x9E01)
400
+ */
307401 .phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
308402 .phy_id_mask = 0xfffffff0,
309403 .name = "SMSC LAN8710/LAN8720",
310404
311
- .features = PHY_BASIC_FEATURES,
312
- .flags = PHY_HAS_INTERRUPT | PHY_RST_AFTER_CLK_EN,
405
+ /* PHY_BASIC_FEATURES */
313406
314407 .probe = smsc_phy_probe,
408
+ .remove = smsc_phy_remove,
315409
316410 /* basic functions */
317411 .read_status = lan87xx_read_status,
318412 .config_init = smsc_phy_config_init,
319413 .soft_reset = smsc_phy_reset,
414
+ .config_aneg = lan95xx_config_aneg_ext,
320415
321416 /* IRQ related */
322417 .ack_interrupt = smsc_phy_ack_interrupt,
....@@ -334,8 +429,8 @@
334429 .phy_id_mask = 0xfffffff0,
335430 .name = "SMSC LAN8740",
336431
337
- .features = PHY_BASIC_FEATURES,
338
- .flags = PHY_HAS_INTERRUPT,
432
+ /* PHY_BASIC_FEATURES */
433
+ .flags = PHY_RST_AFTER_CLK_EN,
339434
340435 .probe = smsc_phy_probe,
341436