1 /**************************************************************************
2 SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 }
Cache object: 50475f128c2fa30686f48f3ccbdc0f01
|