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