igphy.c revision 1.21.16.2 1 /* $NetBSD: igphy.c,v 1.21.16.2 2016/05/06 18:43:34 snj Exp $ */
2
3 /*
4 * The Intel copyright applies to the analog register setup, and the
5 * (currently disabled) SmartSpeed workaround code.
6 */
7
8 /*******************************************************************************
9
10 Copyright (c) 2001-2003, Intel Corporation
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are met:
15
16 1. Redistributions of source code must retain the above copyright notice,
17 this list of conditions and the following disclaimer.
18
19 2. Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in the
21 documentation and/or other materials provided with the distribution.
22
23 3. Neither the name of the Intel Corporation nor the names of its
24 contributors may be used to endorse or promote products derived from
25 this software without specific prior written permission.
26
27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 POSSIBILITY OF SUCH DAMAGE.
38
39 *******************************************************************************/
40
41
42 /*-
43 * Copyright (c) 1998, 1999, 2000, 2003 The NetBSD Foundation, Inc.
44 * All rights reserved.
45 *
46 * This code is derived from software contributed to The NetBSD Foundation
47 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
48 * NASA Ames Research Center, and by Frank van der Linden.
49 *
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 * 1. Redistributions of source code must retain the above copyright
54 * notice, this list of conditions and the following disclaimer.
55 * 2. Redistributions in binary form must reproduce the above copyright
56 * notice, this list of conditions and the following disclaimer in the
57 * documentation and/or other materials provided with the distribution.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
60 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
63 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69 * POSSIBILITY OF SUCH DAMAGE.
70 */
71
72 #include <sys/cdefs.h>
73 __KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.21.16.2 2016/05/06 18:43:34 snj Exp $");
74
75 #include "opt_mii.h"
76
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/kernel.h>
80 #include <sys/device.h>
81 #include <sys/socket.h>
82 #include <sys/errno.h>
83
84 #include <net/if.h>
85 #include <net/if_media.h>
86
87 #include <dev/mii/mii.h>
88 #include <dev/mii/miivar.h>
89 #include <dev/mii/miidevs.h>
90 #include <dev/mii/igphyreg.h>
91 #include <dev/mii/igphyvar.h>
92 #include <dev/pci/if_wmvar.h>
93
94 static void igphy_reset(struct mii_softc *);
95 static void igphy_load_dspcode(struct mii_softc *);
96 static void igphy_load_dspcode_igp3(struct mii_softc *);
97 static void igphy_smartspeed_workaround(struct mii_softc *sc);
98
99 static int igphymatch(device_t, cfdata_t, void *);
100 static void igphyattach(device_t, device_t, void *);
101
102 CFATTACH_DECL_NEW(igphy, sizeof(struct igphy_softc),
103 igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
104
105 static int igphy_service(struct mii_softc *, struct mii_data *, int);
106 static void igphy_status(struct mii_softc *);
107
108 static const struct mii_phy_funcs igphy_funcs = {
109 igphy_service, igphy_status, igphy_reset,
110 };
111
112 static const struct mii_phydesc igphys[] = {
113 { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_IGP01E1000,
114 MII_STR_yyINTEL_IGP01E1000 },
115
116 { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_I82566,
117 MII_STR_yyINTEL_I82566 },
118
119 {0, 0,
120 NULL },
121 };
122
123 static int
124 igphymatch(device_t parent, cfdata_t match, void *aux)
125 {
126 struct mii_attach_args *ma = aux;
127
128 if (mii_phy_match(ma, igphys) != NULL)
129 return 10;
130
131 return 0;
132 }
133
134 static void
135 igphyattach(device_t parent, device_t self, void *aux)
136 {
137 struct mii_softc *sc = device_private(self);
138 struct mii_attach_args *ma = aux;
139 struct mii_data *mii = ma->mii_data;
140 const struct mii_phydesc *mpd;
141 struct igphy_softc *igsc = (struct igphy_softc *) sc;
142 prop_dictionary_t dict;
143
144 mpd = mii_phy_match(ma, igphys);
145 aprint_naive(": Media interface\n");
146 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
147
148 dict = device_properties(parent);
149 if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype))
150 aprint_error("WARNING! Failed to get mactype\n");
151 if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags))
152 aprint_error("WARNING! Failed to get macflags\n");
153
154 sc->mii_dev = self;
155 sc->mii_inst = mii->mii_instance;
156 sc->mii_phy = ma->mii_phyno;
157 sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
158 sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
159 sc->mii_mpd_rev = MII_REV(ma->mii_id2);
160 sc->mii_funcs = &igphy_funcs;
161 sc->mii_pdata = mii;
162 sc->mii_flags = ma->mii_flags;
163 sc->mii_anegticks = MII_ANEGTICKS_GIGE;
164
165 PHY_RESET(sc);
166
167 sc->mii_capabilities =
168 PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
169 if (sc->mii_capabilities & BMSR_EXTSTAT)
170 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
171 aprint_normal_dev(self, "");
172 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
173 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
174 aprint_error("no media present");
175 else
176 mii_phy_add_media(sc);
177 aprint_normal("\n");
178 }
179
180 typedef struct {
181 int reg;
182 uint16_t val;
183 } dspcode;
184
185 static const dspcode igp1code[] = {
186 { 0x1f95, 0x0001 },
187 { 0x1f71, 0xbd21 },
188 { 0x1f79, 0x0018 },
189 { 0x1f30, 0x1600 },
190 { 0x1f31, 0x0014 },
191 { 0x1f32, 0x161c },
192 { 0x1f94, 0x0003 },
193 { 0x1f96, 0x003f },
194 { 0x2010, 0x0008 },
195 { 0, 0 },
196 };
197
198 static const dspcode igp1code_r2[] = {
199 { 0x1f73, 0x0099 },
200 { 0, 0 },
201 };
202
203 static const dspcode igp3code[] = {
204 { 0x2f5b, 0x9018},
205 { 0x2f52, 0x0000},
206 { 0x2fb1, 0x8b24},
207 { 0x2fb2, 0xf8f0},
208 { 0x2010, 0x10b0},
209 { 0x2011, 0x0000},
210 { 0x20dd, 0x249a},
211 { 0x20de, 0x00d3},
212 { 0x28b4, 0x04ce},
213 { 0x2f70, 0x29e4},
214 { 0x0000, 0x0140},
215 { 0x1f30, 0x1606},
216 { 0x1f31, 0xb814},
217 { 0x1f35, 0x002a},
218 { 0x1f3e, 0x0067},
219 { 0x1f54, 0x0065},
220 { 0x1f55, 0x002a},
221 { 0x1f56, 0x002a},
222 { 0x1f72, 0x3fb0},
223 { 0x1f76, 0xc0ff},
224 { 0x1f77, 0x1dec},
225 { 0x1f78, 0xf9ef},
226 { 0x1f79, 0x0210},
227 { 0x1895, 0x0003},
228 { 0x1796, 0x0008},
229 { 0x1798, 0xd008},
230 { 0x1898, 0xd918},
231 { 0x187a, 0x0800},
232 { 0x0019, 0x008d},
233 { 0x001b, 0x2080},
234 { 0x0014, 0x0045},
235 { 0x0000, 0x1340},
236 { 0, 0 },
237 };
238
239 /* DSP patch for igp1 and igp2 */
240 static void
241 igphy_load_dspcode(struct mii_softc *sc)
242 {
243 struct igphy_softc *igsc = (struct igphy_softc *) sc;
244 const dspcode *code;
245 uint16_t reg;
246 int i;
247
248 /* This workaround is only for 82541 and 82547 */
249 switch (igsc->sc_mactype) {
250 case WM_T_82541:
251 case WM_T_82547:
252 code = igp1code;
253 break;
254 case WM_T_82541_2:
255 case WM_T_82547_2:
256 code = igp1code_r2;
257 break;
258 default:
259 return; /* byebye */
260 }
261
262 /* Delay after phy reset to enable NVM configuration to load */
263 delay(20000);
264
265 /*
266 * Save off the current value of register 0x2F5B to be restored at
267 * the end of this routine.
268 */
269 reg = IGPHY_READ(sc, 0x2f5b);
270
271 /* Disabled the PHY transmitter */
272 IGPHY_WRITE(sc, 0x2f5b, 0x0003);
273
274 delay(20000);
275
276 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
277 PHY_WRITE(sc, 0x0000, 0x0140);
278
279 delay(5000);
280
281 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
282 IGPHY_WRITE(sc, code[i].reg, code[i].val);
283
284 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
285 PHY_WRITE(sc, 0x0000, 0x3300);
286
287 delay(20000);
288
289 /* Now enable the transmitter */
290 IGPHY_WRITE(sc, 0x2f5b, reg);
291 }
292
293 static void
294 igphy_load_dspcode_igp3(struct mii_softc *sc)
295 {
296 const dspcode *code = igp3code;
297 int i;
298
299 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
300 IGPHY_WRITE(sc, code[i].reg, code[i].val);
301 }
302
303 static void
304 igphy_reset(struct mii_softc *sc)
305 {
306 struct igphy_softc *igsc = (struct igphy_softc *) sc;
307 uint16_t fused, fine, coarse;
308
309 mii_phy_reset(sc);
310 delay(150);
311
312 switch (igsc->sc_mactype) {
313 case WM_T_82541:
314 case WM_T_82547:
315 case WM_T_82541_2:
316 case WM_T_82547_2:
317 igphy_load_dspcode(sc);
318 break;
319 case WM_T_ICH8:
320 case WM_T_ICH9:
321 if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0)
322 igphy_load_dspcode_igp3(sc);
323 break;
324 default: /* Not for ICH10, PCH and 8257[12] */
325 break;
326 }
327
328 if (igsc->sc_mactype == WM_T_82547) {
329 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
330 if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
331 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
332
333 fine = fused & ANALOG_FUSE_FINE_MASK;
334 coarse = fused & ANALOG_FUSE_COARSE_MASK;
335
336 if (coarse > ANALOG_FUSE_COARSE_THRESH) {
337 coarse -= ANALOG_FUSE_COARSE_10;
338 fine -= ANALOG_FUSE_FINE_1;
339 } else if (coarse == ANALOG_FUSE_COARSE_THRESH)
340 fine -= ANALOG_FUSE_FINE_10;
341
342 fused = (fused & ANALOG_FUSE_POLY_MASK) |
343 (fine & ANALOG_FUSE_FINE_MASK) |
344 (coarse & ANALOG_FUSE_COARSE_MASK);
345
346 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
347 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
348 ANALOG_FUSE_ENABLE_SW_CONTROL);
349 }
350 }
351 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
352 }
353
354
355 static int
356 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
357 {
358 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
359 uint16_t reg;
360
361 switch (cmd) {
362 case MII_POLLSTAT:
363 /*
364 * If we're not polling our PHY instance, just return.
365 */
366 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
367 return (0);
368 break;
369
370 case MII_MEDIACHG:
371 /*
372 * If the media indicates a different PHY instance,
373 * isolate ourselves.
374 */
375 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
376 reg = PHY_READ(sc, MII_BMCR);
377 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
378 return (0);
379 }
380
381 /*
382 * If the interface is not up, don't do anything.
383 */
384 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
385 break;
386
387 reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL);
388 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
389 reg |= PSCR_AUTO_MDIX;
390 reg &= ~PSCR_FORCE_MDI_MDIX;
391 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
392 } else {
393 reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
394 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
395 }
396
397 mii_phy_setmedia(sc);
398 break;
399
400 case MII_TICK:
401 /*
402 * If we're not currently selected, just return.
403 */
404 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
405 return (0);
406
407 igphy_smartspeed_workaround(sc);
408
409 if (mii_phy_tick(sc) == EJUSTRETURN)
410 return (0);
411 break;
412
413 case MII_DOWN:
414 mii_phy_down(sc);
415 return (0);
416 }
417
418 /* Update the media status. */
419 mii_phy_status(sc);
420
421 /* Callback if something changed. */
422 mii_phy_update(sc, cmd);
423 return (0);
424 }
425
426
427 static void
428 igphy_status(struct mii_softc *sc)
429 {
430 struct mii_data *mii = sc->mii_pdata;
431 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
432 uint16_t bmcr, pssr, gtsr, bmsr;
433
434 mii->mii_media_status = IFM_AVALID;
435 mii->mii_media_active = IFM_ETHER;
436
437 pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
438
439 if (pssr & PSSR_LINK_UP)
440 mii->mii_media_status |= IFM_ACTIVE;
441
442 bmcr = PHY_READ(sc, MII_BMCR);
443 if (bmcr & BMCR_ISO) {
444 mii->mii_media_active |= IFM_NONE;
445 mii->mii_media_status = 0;
446 return;
447 }
448
449 if (bmcr & BMCR_LOOP)
450 mii->mii_media_active |= IFM_LOOP;
451
452 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
453
454 /*
455 * XXX can't check if the info is valid, no
456 * 'negotiation done' bit?
457 */
458 if (bmcr & BMCR_AUTOEN) {
459 if ((bmsr & BMSR_ACOMP) == 0) {
460 mii->mii_media_active |= IFM_NONE;
461 return;
462 }
463 switch (pssr & PSSR_SPEED_MASK) {
464 case PSSR_SPEED_1000MBPS:
465 mii->mii_media_active |= IFM_1000_T;
466 gtsr = PHY_READ(sc, MII_100T2SR);
467 if (gtsr & GTSR_MS_RES)
468 mii->mii_media_active |= IFM_ETH_MASTER;
469 break;
470
471 case PSSR_SPEED_100MBPS:
472 mii->mii_media_active |= IFM_100_TX;
473 break;
474
475 case PSSR_SPEED_10MBPS:
476 mii->mii_media_active |= IFM_10_T;
477 break;
478
479 default:
480 mii->mii_media_active |= IFM_NONE;
481 mii->mii_media_status = 0;
482 return;
483 }
484
485 if (pssr & PSSR_FULL_DUPLEX)
486 mii->mii_media_active |=
487 IFM_FDX | mii_phy_flowstatus(sc);
488 else
489 mii->mii_media_active |= IFM_HDX;
490 } else
491 mii->mii_media_active = ife->ifm_media;
492 }
493
494 static void
495 igphy_smartspeed_workaround(struct mii_softc *sc)
496 {
497 struct igphy_softc *igsc = (struct igphy_softc *) sc;
498 uint16_t reg, gtsr, gtcr;
499
500
501 /* This workaround is only for 82541 and 82547 */
502 switch (igsc->sc_mactype) {
503 case WM_T_82541:
504 case WM_T_82541_2:
505 case WM_T_82547:
506 case WM_T_82547_2:
507 break;
508 default:
509 /* byebye */
510 return;
511 }
512
513 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
514 return;
515
516 /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
517
518 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
519 if ((reg & BMSR_LINK) == 0) {
520 switch (igsc->sc_smartspeed) {
521 case 0:
522 gtsr = PHY_READ(sc, MII_100T2SR);
523 if (!(gtsr & GTSR_MAN_MS_FLT))
524 break;
525 gtsr = PHY_READ(sc, MII_100T2SR);
526 if (gtsr & GTSR_MAN_MS_FLT) {
527 gtcr = PHY_READ(sc, MII_100T2CR);
528 if (gtcr & GTCR_MAN_MS) {
529 gtcr &= ~GTCR_MAN_MS;
530 PHY_WRITE(sc, MII_100T2CR,
531 gtcr);
532 }
533 mii_phy_auto(sc, 0);
534 }
535 break;
536 case IGPHY_TICK_DOWNSHIFT:
537 gtcr = PHY_READ(sc, MII_100T2CR);
538 gtcr |= GTCR_MAN_MS;
539 PHY_WRITE(sc, MII_100T2CR, gtcr);
540 mii_phy_auto(sc, 0);
541 break;
542 default:
543 break;
544 }
545 if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
546 igsc->sc_smartspeed = 0;
547 } else
548 igsc->sc_smartspeed = 0;
549 }
550