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
aq100x_temperature(struct cphy * phy)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
aq100x_set_defaults(struct cphy * phy)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
aq100x_reset(struct cphy * phy,int wait)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
aq100x_intr_enable(struct cphy * phy)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
aq100x_intr_disable(struct cphy * phy)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
aq100x_intr_clear(struct cphy * phy)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
aq100x_vendor_intr(struct cphy * phy,int * rc)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
aq100x_intr_handler(struct cphy * phy)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
aq100x_power_down(struct cphy * phy,int off)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
aq100x_autoneg_enable(struct cphy * phy)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
aq100x_autoneg_restart(struct cphy * phy)268 aq100x_autoneg_restart(struct cphy *phy)
269 {
270 return aq100x_autoneg_enable(phy);
271 }
272
273 static int
aq100x_advertise(struct cphy * phy,unsigned int advertise_map)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
aq100x_set_loopback(struct cphy * phy,int mmd,int dir,int enable)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
aq100x_set_speed_duplex(struct cphy * phy,int speed,int duplex)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
aq100x_get_link_status(struct cphy * phy,int * link_state,int * speed,int * duplex,int * fc)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
t3_aq100x_phy_prep(pinfo_t * pinfo,int phy_addr,const struct mdio_ops * mdio_ops)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