]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cxgb/common/cxgb_aq100x.c
MFV r353143 (phillip):
[FreeBSD/FreeBSD.git] / sys / dev / cxgb / common / cxgb_aq100x.c
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 celcius, 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 }