xref: /freebsd/sys/dev/cxgb/common/cxgb_aq100x.c (revision 4e8d558c)
1 /**************************************************************************
2 SPDX-License-Identifier: BSD-2-Clause
3 
4 Copyright (c) 2009 Chelsio Inc.
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10  1. Redistributions of source code must retain the above copyright notice,
11     this list of conditions and the following disclaimer.
12 
13  2. Neither the name of the Chelsio Corporation nor the names of its
14     contributors may be used to endorse or promote products derived from
15     this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 POSSIBILITY OF SUCH DAMAGE.
28 
29 ***************************************************************************/
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <cxgb_include.h>
35 
36 #undef msleep
37 #define msleep t3_os_sleep
38 
39 enum {
40 	/* MDIO_DEV_PMA_PMD registers */
41 	AQ_LINK_STAT	= 0xe800,
42 
43 	/* MDIO_DEV_XGXS registers */
44 	AQ_XAUI_RX_CFG	= 0xc400,
45 	AQ_XAUI_KX_CFG	= 0xc440,
46 	AQ_XAUI_TX_CFG	= 0xe400,
47 
48 	/* MDIO_DEV_ANEG registers */
49 	AQ_100M_CTRL	= 0x0010,
50 	AQ_10G_CTRL	= 0x0020,
51 	AQ_1G_CTRL	= 0xc400,
52 	AQ_ANEG_STAT	= 0xc800,
53 
54 	/* MDIO_DEV_VEND1 registers */
55 	AQ_FW_VERSION	= 0x0020,
56 	AQ_THERMAL_THR	= 0xc421,
57 	AQ_THERMAL1	= 0xc820,
58 	AQ_THERMAL2	= 0xc821,
59 	AQ_IFLAG_GLOBAL	= 0xfc00,
60 	AQ_IMASK_GLOBAL	= 0xff00,
61 };
62 
63 #define AQBIT(x)	(1 << (0x##x))
64 #define ADV_1G_FULL	AQBIT(f)
65 #define ADV_1G_HALF	AQBIT(e)
66 #define ADV_10G_FULL	AQBIT(c)
67 
68 #define AQ_WRITE_REGS(phy, regs) do { \
69 	int i; \
70 	for (i = 0; i < ARRAY_SIZE(regs); i++) { \
71 		(void) mdio_write(phy, regs[i].mmd, regs[i].reg, regs[i].val); \
72 	} \
73 } while (0)
74 #define AQ_READ_REGS(phy, regs) do { \
75 	unsigned i, v; \
76 	for (i = 0; i < ARRAY_SIZE(regs); i++) { \
77 		(void) mdio_read(phy, regs[i].mmd, regs[i].reg, &v); \
78 	} \
79 } while (0)
80 
81 /*
82  * Return value is temperature in celsius, 0xffff for error or don't know.
83  */
84 static int
85 aq100x_temperature(struct cphy *phy)
86 {
87 	unsigned int v;
88 
89 	if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL2, &v) ||
90 	    v == 0xffff || (v & 1) != 1)
91 		return (0xffff);
92 
93 	if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL1, &v))
94 		return (0xffff);
95 
96 	return ((int)((signed char)(v >> 8)));
97 }
98 
99 static int
100 aq100x_set_defaults(struct cphy *phy)
101 {
102 	return mdio_write(phy, MDIO_DEV_VEND1, AQ_THERMAL_THR, 0x6c00);
103 }
104 
105 static int
106 aq100x_reset(struct cphy *phy, int wait)
107 {
108 	int err;
109 	err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
110 	if (!err)
111 		err = aq100x_set_defaults(phy);
112 	return (err);
113 }
114 
115 static int
116 aq100x_intr_enable(struct cphy *phy)
117 {
118 	struct {
119 		int mmd;
120 		int reg;
121 		int val;
122 	} imasks[] = {
123 		{MDIO_DEV_VEND1, 0xd400, AQBIT(e)},
124 		{MDIO_DEV_VEND1, 0xff01, AQBIT(2)},
125 		{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, AQBIT(0)}
126 	};
127 
128 	AQ_WRITE_REGS(phy, imasks);
129 
130 	return (0);
131 }
132 
133 static int
134 aq100x_intr_disable(struct cphy *phy)
135 {
136 	struct {
137 		int mmd;
138 		int reg;
139 		int val;
140 	} imasks[] = {
141 		{MDIO_DEV_VEND1, 0xd400, 0},
142 		{MDIO_DEV_VEND1, 0xff01, 0},
143 		{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, 0}
144 	};
145 
146 	AQ_WRITE_REGS(phy, imasks);
147 
148 	return (0);
149 }
150 
151 static int
152 aq100x_intr_clear(struct cphy *phy)
153 {
154 	struct {
155 		int mmd;
156 		int reg;
157 	} iclr[] = {
158 		{MDIO_DEV_VEND1, 0xcc00},
159 		{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL} /* needed? */
160 	};
161 
162 	AQ_READ_REGS(phy, iclr);
163 
164 	return (0);
165 }
166 
167 static int
168 aq100x_vendor_intr(struct cphy *phy, int *rc)
169 {
170 	int err;
171 	unsigned int cause, v;
172 
173 	err = mdio_read(phy, MDIO_DEV_VEND1, 0xfc01, &cause);
174 	if (err)
175 		return (err);
176 
177 	if (cause & AQBIT(2)) {
178 		err = mdio_read(phy, MDIO_DEV_VEND1, 0xcc00, &v);
179 		if (err)
180 			return (err);
181 
182 		if (v & AQBIT(e)) {
183 			CH_WARN(phy->adapter, "PHY%d: temperature is now %dC\n",
184 			    phy->addr, aq100x_temperature(phy));
185 
186 			t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN,
187 			    phy->addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL, 0);
188 
189 			*rc |= cphy_cause_alarm;
190 		}
191 
192 		cause &= ~4;
193 	}
194 
195 	if (cause)
196 		CH_WARN(phy->adapter, "PHY%d: unhandled vendor interrupt"
197 		    " (0x%x)\n", phy->addr, cause);
198 
199 	return (0);
200 
201 }
202 
203 static int
204 aq100x_intr_handler(struct cphy *phy)
205 {
206 	int err, rc = 0;
207 	unsigned int cause;
208 
209 	err = mdio_read(phy, MDIO_DEV_VEND1, AQ_IFLAG_GLOBAL, &cause);
210 	if (err)
211 		return (err);
212 
213 	if (cause & AQBIT(0)) {
214 		err = aq100x_vendor_intr(phy, &rc);
215 		if (err)
216 			return (err);
217 		cause &= ~AQBIT(0);
218 	}
219 
220 	if (cause)
221 		CH_WARN(phy->adapter, "PHY%d: unhandled interrupt (0x%x)\n",
222 		    phy->addr, cause);
223 
224 	return (rc);
225 }
226 
227 static int
228 aq100x_power_down(struct cphy *phy, int off)
229 {
230 	int err, wait = 500;
231 	unsigned int v;
232 
233 	err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, BMCR_PDOWN,
234 	    off ? BMCR_PDOWN : 0);
235 	if (err || off)
236 		return (err);
237 
238 	msleep(300);
239 	do {
240 		err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
241 		if (err)
242 			return (err);
243 		v &= BMCR_RESET;
244 		if (v)
245 			msleep(10);
246 	} while (v && --wait);
247 	if (v) {
248 		CH_WARN(phy->adapter, "PHY%d: power-up timed out (0x%x).\n",
249 		    phy->addr, v);
250 		return (ETIMEDOUT);
251 	}
252 
253 	return (0);
254 }
255 
256 static int
257 aq100x_autoneg_enable(struct cphy *phy)
258 {
259 	int err;
260 
261 	err = aq100x_power_down(phy, 0);
262 	if (!err)
263 		err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
264 		    BMCR_RESET, BMCR_ANENABLE | BMCR_ANRESTART);
265 
266 	return (err);
267 }
268 
269 static int
270 aq100x_autoneg_restart(struct cphy *phy)
271 {
272 	return aq100x_autoneg_enable(phy);
273 }
274 
275 static int
276 aq100x_advertise(struct cphy *phy, unsigned int advertise_map)
277 {
278 	unsigned int adv;
279 	int err;
280 
281 	/* 10G advertisement */
282 	adv = 0;
283 	if (advertise_map & ADVERTISED_10000baseT_Full)
284 		adv |= ADV_10G_FULL;
285 	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_10G_CTRL,
286 				  ADV_10G_FULL, adv);
287 	if (err)
288 		return (err);
289 
290 	/* 1G advertisement */
291 	adv = 0;
292 	if (advertise_map & ADVERTISED_1000baseT_Full)
293 		adv |= ADV_1G_FULL;
294 	if (advertise_map & ADVERTISED_1000baseT_Half)
295 		adv |= ADV_1G_HALF;
296 	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_1G_CTRL,
297 				  ADV_1G_FULL | ADV_1G_HALF, adv);
298 	if (err)
299 		return (err);
300 
301 	/* 100M, pause advertisement */
302 	adv = 0;
303 	if (advertise_map & ADVERTISED_100baseT_Half)
304 		adv |= ADVERTISE_100HALF;
305 	if (advertise_map & ADVERTISED_100baseT_Full)
306 		adv |= ADVERTISE_100FULL;
307 	if (advertise_map & ADVERTISED_Pause)
308 		adv |= ADVERTISE_PAUSE_CAP;
309 	if (advertise_map & ADVERTISED_Asym_Pause)
310 		adv |= ADVERTISE_PAUSE_ASYM;
311 	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_100M_CTRL, 0xfe0, adv);
312 
313 	return (err);
314 }
315 
316 static int
317 aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable)
318 {
319 	return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
320 				   BMCR_LOOPBACK, enable ? BMCR_LOOPBACK : 0);
321 }
322 
323 static int
324 aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
325 {
326 	int err, set;
327 
328 	if (speed == SPEED_100)
329 		set = BMCR_SPEED100;
330 	else if (speed == SPEED_1000)
331 		set = BMCR_SPEED1000;
332 	else if (speed == SPEED_10000)
333 		set = BMCR_SPEED1000 | BMCR_SPEED100;
334 	else
335 		return (EINVAL);
336 
337 	if (duplex != DUPLEX_FULL)
338 		return (EINVAL);
339 
340 	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
341 	    BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART, 0);
342 	if (err)
343 		return (err);
344 
345 	err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
346 	    BMCR_SPEED1000 | BMCR_SPEED100, set);
347 	if (err)
348 		return (err);
349 
350 	return (0);
351 }
352 
353 static int
354 aq100x_get_link_status(struct cphy *phy, int *link_state, int *speed, int *duplex,
355 		       int *fc)
356 {
357 	int err;
358 	unsigned int v, link = 0;
359 
360 	err = mdio_read(phy, MDIO_DEV_PMA_PMD, AQ_LINK_STAT, &v);
361 	if (err)
362 		return (err);
363 	if (v == 0xffff || !(v & 1))
364 		goto done;
365 
366 	err = mdio_read(phy, MDIO_DEV_ANEG, MII_BMCR, &v);
367 	if (err)
368 		return (err);
369 	if (v & 0x8000)
370 		goto done;
371 	if (v & BMCR_ANENABLE) {
372 
373 		err = mdio_read(phy, MDIO_DEV_ANEG, 1, &v);
374 		if (err)
375 			return (err);
376 		if ((v & 0x20) == 0)
377 			goto done;
378 
379 		err = mdio_read(phy, MDIO_DEV_ANEG, AQ_ANEG_STAT, &v);
380 		if (err)
381 			return (err);
382 
383 		if (speed) {
384 			switch (v & 0x6) {
385 			case 0x6: *speed = SPEED_10000;
386 				break;
387 			case 0x4: *speed = SPEED_1000;
388 				break;
389 			case 0x2: *speed = SPEED_100;
390 				break;
391 			case 0x0: *speed = SPEED_10;
392 				break;
393 			}
394 		}
395 
396 		if (duplex)
397 			*duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF;
398 
399 		if (fc) {
400 			unsigned int lpa, adv;
401 			err = mdio_read(phy, MDIO_DEV_ANEG, 0x13, &lpa);
402 			if (!err)
403 				err = mdio_read(phy, MDIO_DEV_ANEG,
404 				    AQ_100M_CTRL, &adv);
405 			if (err)
406 				return err;
407 
408 			if (lpa & adv & ADVERTISE_PAUSE_CAP)
409 				*fc = PAUSE_RX | PAUSE_TX;
410 			else if (lpa & ADVERTISE_PAUSE_CAP &&
411 			    lpa & ADVERTISE_PAUSE_ASYM &&
412 			    adv & ADVERTISE_PAUSE_ASYM)
413 				*fc = PAUSE_TX;
414 			else if (lpa & ADVERTISE_PAUSE_ASYM &&
415 			    adv & ADVERTISE_PAUSE_CAP)
416 				*fc = PAUSE_RX;
417 			else
418 				*fc = 0;
419 		}
420 
421 	} else {
422 		err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
423 		if (err)
424 			return (err);
425 
426 		v &= BMCR_SPEED1000 | BMCR_SPEED100;
427 		if (speed) {
428 			if (v == (BMCR_SPEED1000 | BMCR_SPEED100))
429 				*speed = SPEED_10000;
430 			else if (v == BMCR_SPEED1000)
431 				*speed = SPEED_1000;
432 			else if (v == BMCR_SPEED100)
433 				*speed = SPEED_100;
434 			else
435 				*speed = SPEED_10;
436 		}
437 
438 		if (duplex)
439 			*duplex = DUPLEX_FULL;
440 	}
441 
442 	link = 1;
443 done:
444 	if (link_state)
445 		*link_state = link ? PHY_LINK_UP : PHY_LINK_DOWN;
446 	return (0);
447 }
448 
449 static struct cphy_ops aq100x_ops = {
450 	.reset             = aq100x_reset,
451 	.intr_enable       = aq100x_intr_enable,
452 	.intr_disable      = aq100x_intr_disable,
453 	.intr_clear        = aq100x_intr_clear,
454 	.intr_handler      = aq100x_intr_handler,
455 	.autoneg_enable    = aq100x_autoneg_enable,
456 	.autoneg_restart   = aq100x_autoneg_restart,
457 	.advertise         = aq100x_advertise,
458 	.set_loopback      = aq100x_set_loopback,
459 	.set_speed_duplex  = aq100x_set_speed_duplex,
460 	.get_link_status   = aq100x_get_link_status,
461 	.power_down        = aq100x_power_down,
462 };
463 
464 int
465 t3_aq100x_phy_prep(pinfo_t *pinfo, int phy_addr,
466 		       const struct mdio_ops *mdio_ops)
467 {
468 	struct cphy *phy = &pinfo->phy;
469 	unsigned int v, v2, gpio, wait;
470 	int err;
471 	adapter_t *adapter = pinfo->adapter;
472 
473 	cphy_init(&pinfo->phy, adapter, pinfo, phy_addr, &aq100x_ops, mdio_ops,
474 		  SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
475 		  SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI |
476 		  SUPPORTED_MISC_IRQ, "1000/10GBASE-T");
477 
478 	/*
479 	 * Hard reset the PHY.
480 	 */
481 	gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL;
482 	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0);
483 	msleep(1);
484 	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio);
485 
486 	/*
487 	 * Give it enough time to load the firmware and get ready for mdio.
488 	 */
489 	msleep(1000);
490 	wait = 500; /* in 10ms increments */
491 	do {
492 		err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
493 		if (err || v == 0xffff) {
494 
495 			/* Allow prep_adapter to succeed when ffff is read */
496 
497 			CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n",
498 				phy_addr, err, v);
499 			goto done;
500 		}
501 
502 		v &= BMCR_RESET;
503 		if (v)
504 			msleep(10);
505 	} while (v && --wait);
506 	if (v) {
507 		CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n",
508 			phy_addr, v);
509 
510 		goto done; /* let prep_adapter succeed */
511 	}
512 
513 	/* Firmware version check. */
514 	(void) mdio_read(phy, MDIO_DEV_VEND1, AQ_FW_VERSION, &v);
515 	if (v < 0x115)
516 		CH_WARN(adapter, "PHY%d: unknown firmware %d.%d\n", phy_addr,
517 		    v >> 8, v & 0xff);
518 
519 	/* The PHY should start in really-low-power mode. */
520 	(void) mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
521 	if ((v & BMCR_PDOWN) == 0)
522 		CH_WARN(adapter, "PHY%d does not start in low power mode.\n",
523 			phy_addr);
524 
525 	/*
526 	 * Verify XAUI and 1000-X settings, but let prep succeed no matter what.
527 	 */
528 	v = v2 = 0;
529 	(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_RX_CFG, &v);
530 	(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_TX_CFG, &v2);
531 	if (v != 0x1b || v2 != 0x1b)
532 		CH_WARN(adapter, "PHY%d: incorrect XAUI settings "
533 		    "(0x%x, 0x%x).\n", phy_addr, v, v2);
534 	v = 0;
535 	(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_KX_CFG, &v);
536 	if ((v & 0xf) != 0xf)
537 		CH_WARN(adapter, "PHY%d: incorrect 1000-X settings "
538 		    "(0x%x).\n", phy_addr, v);
539 
540 	(void) aq100x_set_defaults(phy);
541 done:
542 	return (err);
543 }
544