xref: /openbmc/linux/drivers/net/phy/microchip_t1.c (revision ee8ec048)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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