1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2018 Microchip Technology
3
4 #include <linux/kernel.h>
5 #include <linux/module.h>
6 #include <linux/delay.h>
7 #include <linux/mii.h>
8 #include <linux/phy.h>
9 #include <linux/ethtool.h>
10 #include <linux/ethtool_netlink.h>
11
12 /* External Register Control Register */
13 #define LAN87XX_EXT_REG_CTL (0x14)
14 #define LAN87XX_EXT_REG_CTL_RD_CTL (0x1000)
15 #define LAN87XX_EXT_REG_CTL_WR_CTL (0x0800)
16
17 /* External Register Read Data Register */
18 #define LAN87XX_EXT_REG_RD_DATA (0x15)
19
20 /* External Register Write Data Register */
21 #define LAN87XX_EXT_REG_WR_DATA (0x16)
22
23 /* Interrupt Source Register */
24 #define LAN87XX_INTERRUPT_SOURCE (0x18)
25
26 /* Interrupt Mask Register */
27 #define LAN87XX_INTERRUPT_MASK (0x19)
28 #define LAN87XX_MASK_LINK_UP (0x0004)
29 #define LAN87XX_MASK_LINK_DOWN (0x0002)
30
31 /* MISC Control 1 Register */
32 #define LAN87XX_CTRL_1 (0x11)
33 #define LAN87XX_MASK_RGMII_TXC_DLY_EN (0x4000)
34 #define LAN87XX_MASK_RGMII_RXC_DLY_EN (0x2000)
35
36 /* phyaccess nested types */
37 #define PHYACC_ATTR_MODE_READ 0
38 #define PHYACC_ATTR_MODE_WRITE 1
39 #define PHYACC_ATTR_MODE_MODIFY 2
40
41 #define PHYACC_ATTR_BANK_SMI 0
42 #define PHYACC_ATTR_BANK_MISC 1
43 #define PHYACC_ATTR_BANK_PCS 2
44 #define PHYACC_ATTR_BANK_AFE 3
45 #define PHYACC_ATTR_BANK_DSP 4
46 #define PHYACC_ATTR_BANK_MAX 7
47
48 /* measurement defines */
49 #define LAN87XX_CABLE_TEST_OK 0
50 #define LAN87XX_CABLE_TEST_OPEN 1
51 #define LAN87XX_CABLE_TEST_SAME_SHORT 2
52
53 #define DRIVER_AUTHOR "Nisar Sayed <nisar.sayed@microchip.com>"
54 #define DRIVER_DESC "Microchip LAN87XX T1 PHY driver"
55
56 struct access_ereg_val {
57 u8 mode;
58 u8 bank;
59 u8 offset;
60 u16 val;
61 u16 mask;
62 };
63
access_ereg(struct phy_device * phydev,u8 mode,u8 bank,u8 offset,u16 val)64 static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank,
65 u8 offset, u16 val)
66 {
67 u16 ereg = 0;
68 int rc = 0;
69
70 if (mode > PHYACC_ATTR_MODE_WRITE || bank > PHYACC_ATTR_BANK_MAX)
71 return -EINVAL;
72
73 if (bank == PHYACC_ATTR_BANK_SMI) {
74 if (mode == PHYACC_ATTR_MODE_WRITE)
75 rc = phy_write(phydev, offset, val);
76 else
77 rc = phy_read(phydev, offset);
78 return rc;
79 }
80
81 if (mode == PHYACC_ATTR_MODE_WRITE) {
82 ereg = LAN87XX_EXT_REG_CTL_WR_CTL;
83 rc = phy_write(phydev, LAN87XX_EXT_REG_WR_DATA, val);
84 if (rc < 0)
85 return rc;
86 } else {
87 ereg = LAN87XX_EXT_REG_CTL_RD_CTL;
88 }
89
90 ereg |= (bank << 8) | offset;
91
92 rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, ereg);
93 if (rc < 0)
94 return rc;
95
96 if (mode == PHYACC_ATTR_MODE_READ)
97 rc = phy_read(phydev, LAN87XX_EXT_REG_RD_DATA);
98
99 return rc;
100 }
101
access_ereg_modify_changed(struct phy_device * phydev,u8 bank,u8 offset,u16 val,u16 mask)102 static int access_ereg_modify_changed(struct phy_device *phydev,
103 u8 bank, u8 offset, u16 val, u16 mask)
104 {
105 int new = 0, rc = 0;
106
107 if (bank > PHYACC_ATTR_BANK_MAX)
108 return -EINVAL;
109
110 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, bank, offset, val);
111 if (rc < 0)
112 return rc;
113
114 new = val | (rc & (mask ^ 0xFFFF));
115 rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE, bank, offset, new);
116
117 return rc;
118 }
119
lan87xx_config_rgmii_delay(struct phy_device * phydev)120 static int lan87xx_config_rgmii_delay(struct phy_device *phydev)
121 {
122 int rc;
123
124 if (!phy_interface_is_rgmii(phydev))
125 return 0;
126
127 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
128 PHYACC_ATTR_BANK_MISC, LAN87XX_CTRL_1, 0);
129 if (rc < 0)
130 return rc;
131
132 switch (phydev->interface) {
133 case PHY_INTERFACE_MODE_RGMII:
134 rc &= ~LAN87XX_MASK_RGMII_TXC_DLY_EN;
135 rc &= ~LAN87XX_MASK_RGMII_RXC_DLY_EN;
136 break;
137 case PHY_INTERFACE_MODE_RGMII_ID:
138 rc |= LAN87XX_MASK_RGMII_TXC_DLY_EN;
139 rc |= LAN87XX_MASK_RGMII_RXC_DLY_EN;
140 break;
141 case PHY_INTERFACE_MODE_RGMII_RXID:
142 rc &= ~LAN87XX_MASK_RGMII_TXC_DLY_EN;
143 rc |= LAN87XX_MASK_RGMII_RXC_DLY_EN;
144 break;
145 case PHY_INTERFACE_MODE_RGMII_TXID:
146 rc |= LAN87XX_MASK_RGMII_TXC_DLY_EN;
147 rc &= ~LAN87XX_MASK_RGMII_RXC_DLY_EN;
148 break;
149 default:
150 return 0;
151 }
152
153 return access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
154 PHYACC_ATTR_BANK_MISC, LAN87XX_CTRL_1, rc);
155 }
156
lan87xx_phy_init(struct phy_device * phydev)157 static int lan87xx_phy_init(struct phy_device *phydev)
158 {
159 static const struct access_ereg_val init[] = {
160 /* TX Amplitude = 5 */
161 {PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_AFE, 0x0B,
162 0x000A, 0x001E},
163 /* Clear SMI interrupts */
164 {PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI, 0x18,
165 0, 0},
166 /* Clear MISC interrupts */
167 {PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_MISC, 0x08,
168 0, 0},
169 /* Turn on TC10 Ring Oscillator (ROSC) */
170 {PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_MISC, 0x20,
171 0x0020, 0x0020},
172 /* WUR Detect Length to 1.2uS, LPC Detect Length to 1.09uS */
173 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_PCS, 0x20,
174 0x283C, 0},
175 /* Wake_In Debounce Length to 39uS, Wake_Out Length to 79uS */
176 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x21,
177 0x274F, 0},
178 /* Enable Auto Wake Forward to Wake_Out, ROSC on, Sleep,
179 * and Wake_In to wake PHY
180 */
181 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x20,
182 0x80A7, 0},
183 /* Enable WUP Auto Fwd, Enable Wake on MDI, Wakeup Debouncer
184 * to 128 uS
185 */
186 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x24,
187 0xF110, 0},
188 /* Enable HW Init */
189 {PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_SMI, 0x1A,
190 0x0100, 0x0100},
191 };
192 int rc, i;
193
194 /* Start manual initialization procedures in Managed Mode */
195 rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
196 0x1a, 0x0000, 0x0100);
197 if (rc < 0)
198 return rc;
199
200 /* Soft Reset the SMI block */
201 rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
202 0x00, 0x8000, 0x8000);
203 if (rc < 0)
204 return rc;
205
206 /* Check to see if the self-clearing bit is cleared */
207 usleep_range(1000, 2000);
208 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
209 PHYACC_ATTR_BANK_SMI, 0x00, 0);
210 if (rc < 0)
211 return rc;
212 if ((rc & 0x8000) != 0)
213 return -ETIMEDOUT;
214
215 /* PHY Initialization */
216 for (i = 0; i < ARRAY_SIZE(init); i++) {
217 if (init[i].mode == PHYACC_ATTR_MODE_MODIFY) {
218 rc = access_ereg_modify_changed(phydev, init[i].bank,
219 init[i].offset,
220 init[i].val,
221 init[i].mask);
222 } else {
223 rc = access_ereg(phydev, init[i].mode, init[i].bank,
224 init[i].offset, init[i].val);
225 }
226 if (rc < 0)
227 return rc;
228 }
229
230 return lan87xx_config_rgmii_delay(phydev);
231 }
232
lan87xx_phy_config_intr(struct phy_device * phydev)233 static int lan87xx_phy_config_intr(struct phy_device *phydev)
234 {
235 int rc, val = 0;
236
237 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
238 /* unmask all source and clear them before enable */
239 rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, 0x7FFF);
240 rc = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE);
241 val = LAN87XX_MASK_LINK_UP | LAN87XX_MASK_LINK_DOWN;
242 rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val);
243 } else {
244 rc = phy_write(phydev, LAN87XX_INTERRUPT_MASK, val);
245 if (rc)
246 return rc;
247
248 rc = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE);
249 }
250
251 return rc < 0 ? rc : 0;
252 }
253
lan87xx_handle_interrupt(struct phy_device * phydev)254 static irqreturn_t lan87xx_handle_interrupt(struct phy_device *phydev)
255 {
256 int irq_status;
257
258 irq_status = phy_read(phydev, LAN87XX_INTERRUPT_SOURCE);
259 if (irq_status < 0) {
260 phy_error(phydev);
261 return IRQ_NONE;
262 }
263
264 if (irq_status == 0)
265 return IRQ_NONE;
266
267 phy_trigger_machine(phydev);
268
269 return IRQ_HANDLED;
270 }
271
lan87xx_config_init(struct phy_device * phydev)272 static int lan87xx_config_init(struct phy_device *phydev)
273 {
274 int rc = lan87xx_phy_init(phydev);
275
276 return rc < 0 ? rc : 0;
277 }
278
microchip_cable_test_start_common(struct phy_device * phydev)279 static int microchip_cable_test_start_common(struct phy_device *phydev)
280 {
281 int bmcr, bmsr, ret;
282
283 /* If auto-negotiation is enabled, but not complete, the cable
284 * test never completes. So disable auto-neg.
285 */
286 bmcr = phy_read(phydev, MII_BMCR);
287 if (bmcr < 0)
288 return bmcr;
289
290 bmsr = phy_read(phydev, MII_BMSR);
291
292 if (bmsr < 0)
293 return bmsr;
294
295 if (bmcr & BMCR_ANENABLE) {
296 ret = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
297 if (ret < 0)
298 return ret;
299 ret = genphy_soft_reset(phydev);
300 if (ret < 0)
301 return ret;
302 }
303
304 /* If the link is up, allow it some time to go down */
305 if (bmsr & BMSR_LSTATUS)
306 msleep(1500);
307
308 return 0;
309 }
310
lan87xx_cable_test_start(struct phy_device * phydev)311 static int lan87xx_cable_test_start(struct phy_device *phydev)
312 {
313 static const struct access_ereg_val cable_test[] = {
314 /* min wait */
315 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 93,
316 0, 0},
317 /* max wait */
318 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 94,
319 10, 0},
320 /* pulse cycle */
321 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 95,
322 90, 0},
323 /* cable diag thresh */
324 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 92,
325 60, 0},
326 /* max gain */
327 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 79,
328 31, 0},
329 /* clock align for each iteration */
330 {PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_DSP, 55,
331 0, 0x0038},
332 /* max cycle wait config */
333 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 94,
334 70, 0},
335 /* start cable diag*/
336 {PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP, 90,
337 1, 0},
338 };
339 int rc, i;
340
341 rc = microchip_cable_test_start_common(phydev);
342 if (rc < 0)
343 return rc;
344
345 /* start cable diag */
346 /* check if part is alive - if not, return diagnostic error */
347 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI,
348 0x00, 0);
349 if (rc < 0)
350 return rc;
351
352 /* master/slave specific configs */
353 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI,
354 0x0A, 0);
355 if (rc < 0)
356 return rc;
357
358 if ((rc & 0x4000) != 0x4000) {
359 /* DUT is Slave */
360 rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_AFE,
361 0x0E, 0x5, 0x7);
362 if (rc < 0)
363 return rc;
364 rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
365 0x1A, 0x8, 0x8);
366 if (rc < 0)
367 return rc;
368 } else {
369 /* DUT is Master */
370 rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
371 0x10, 0x8, 0x40);
372 if (rc < 0)
373 return rc;
374 }
375
376 for (i = 0; i < ARRAY_SIZE(cable_test); i++) {
377 if (cable_test[i].mode == PHYACC_ATTR_MODE_MODIFY) {
378 rc = access_ereg_modify_changed(phydev,
379 cable_test[i].bank,
380 cable_test[i].offset,
381 cable_test[i].val,
382 cable_test[i].mask);
383 /* wait 50ms */
384 msleep(50);
385 } else {
386 rc = access_ereg(phydev, cable_test[i].mode,
387 cable_test[i].bank,
388 cable_test[i].offset,
389 cable_test[i].val);
390 }
391 if (rc < 0)
392 return rc;
393 }
394 /* cable diag started */
395
396 return 0;
397 }
398
lan87xx_cable_test_report_trans(u32 result)399 static int lan87xx_cable_test_report_trans(u32 result)
400 {
401 switch (result) {
402 case LAN87XX_CABLE_TEST_OK:
403 return ETHTOOL_A_CABLE_RESULT_CODE_OK;
404 case LAN87XX_CABLE_TEST_OPEN:
405 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
406 case LAN87XX_CABLE_TEST_SAME_SHORT:
407 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
408 default:
409 /* DIAGNOSTIC_ERROR */
410 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
411 }
412 }
413
lan87xx_cable_test_report(struct phy_device * phydev)414 static int lan87xx_cable_test_report(struct phy_device *phydev)
415 {
416 int pos_peak_cycle = 0, pos_peak_in_phases = 0, pos_peak_phase = 0;
417 int neg_peak_cycle = 0, neg_peak_in_phases = 0, neg_peak_phase = 0;
418 int noise_margin = 20, time_margin = 89, jitter_var = 30;
419 int min_time_diff = 96, max_time_diff = 96 + time_margin;
420 bool fault = false, check_a = false, check_b = false;
421 int gain_idx = 0, pos_peak = 0, neg_peak = 0;
422 int pos_peak_time = 0, neg_peak_time = 0;
423 int pos_peak_in_phases_hybrid = 0;
424 int detect = -1;
425
426 gain_idx = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
427 PHYACC_ATTR_BANK_DSP, 151, 0);
428 /* read non-hybrid results */
429 pos_peak = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
430 PHYACC_ATTR_BANK_DSP, 153, 0);
431 neg_peak = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
432 PHYACC_ATTR_BANK_DSP, 154, 0);
433 pos_peak_time = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
434 PHYACC_ATTR_BANK_DSP, 156, 0);
435 neg_peak_time = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
436 PHYACC_ATTR_BANK_DSP, 157, 0);
437
438 pos_peak_cycle = (pos_peak_time >> 7) & 0x7F;
439 /* calculate non-hybrid values */
440 pos_peak_phase = pos_peak_time & 0x7F;
441 pos_peak_in_phases = (pos_peak_cycle * 96) + pos_peak_phase;
442 neg_peak_cycle = (neg_peak_time >> 7) & 0x7F;
443 neg_peak_phase = neg_peak_time & 0x7F;
444 neg_peak_in_phases = (neg_peak_cycle * 96) + neg_peak_phase;
445
446 /* process values */
447 check_a =
448 ((pos_peak_in_phases - neg_peak_in_phases) >= min_time_diff) &&
449 ((pos_peak_in_phases - neg_peak_in_phases) < max_time_diff) &&
450 pos_peak_in_phases_hybrid < pos_peak_in_phases &&
451 (pos_peak_in_phases_hybrid < (neg_peak_in_phases + jitter_var));
452 check_b =
453 ((neg_peak_in_phases - pos_peak_in_phases) >= min_time_diff) &&
454 ((neg_peak_in_phases - pos_peak_in_phases) < max_time_diff) &&
455 pos_peak_in_phases_hybrid < neg_peak_in_phases &&
456 (pos_peak_in_phases_hybrid < (pos_peak_in_phases + jitter_var));
457
458 if (pos_peak_in_phases > neg_peak_in_phases && check_a)
459 detect = 2;
460 else if ((neg_peak_in_phases > pos_peak_in_phases) && check_b)
461 detect = 1;
462
463 if (pos_peak > noise_margin && neg_peak > noise_margin &&
464 gain_idx >= 0) {
465 if (detect == 1 || detect == 2)
466 fault = true;
467 }
468
469 if (!fault)
470 detect = 0;
471
472 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
473 lan87xx_cable_test_report_trans(detect));
474
475 return 0;
476 }
477
lan87xx_cable_test_get_status(struct phy_device * phydev,bool * finished)478 static int lan87xx_cable_test_get_status(struct phy_device *phydev,
479 bool *finished)
480 {
481 int rc = 0;
482
483 *finished = false;
484
485 /* check if cable diag was finished */
486 rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_DSP,
487 90, 0);
488 if (rc < 0)
489 return rc;
490
491 if ((rc & 2) == 2) {
492 /* stop cable diag*/
493 rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE,
494 PHYACC_ATTR_BANK_DSP,
495 90, 0);
496 if (rc < 0)
497 return rc;
498
499 *finished = true;
500
501 return lan87xx_cable_test_report(phydev);
502 }
503
504 return 0;
505 }
506
507 static struct phy_driver microchip_t1_phy_driver[] = {
508 {
509 .phy_id = 0x0007c150,
510 .phy_id_mask = 0xfffffff0,
511 .name = "Microchip LAN87xx T1",
512 .flags = PHY_POLL_CABLE_TEST,
513
514 .features = PHY_BASIC_T1_FEATURES,
515
516 .config_init = lan87xx_config_init,
517
518 .config_intr = lan87xx_phy_config_intr,
519 .handle_interrupt = lan87xx_handle_interrupt,
520
521 .suspend = genphy_suspend,
522 .resume = genphy_resume,
523 .cable_test_start = lan87xx_cable_test_start,
524 .cable_test_get_status = lan87xx_cable_test_get_status,
525 }
526 };
527
528 module_phy_driver(microchip_t1_phy_driver);
529
530 static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
531 { 0x0007c150, 0xfffffff0 },
532 { }
533 };
534
535 MODULE_DEVICE_TABLE(mdio, microchip_t1_tbl);
536
537 MODULE_AUTHOR(DRIVER_AUTHOR);
538 MODULE_DESCRIPTION(DRIVER_DESC);
539 MODULE_LICENSE("GPL");
540