]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/cxgb/common/cxgb_aq100x.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / cxgb / common / cxgb_aq100x.c
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 (err);
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 }