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