igphy.c revision 1.23.4.1 1 /* $NetBSD: igphy.c,v 1.23.4.1 2015/09/22 12:05:58 skrll 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.23.4.1 2015/09/22 12:05:58 skrll Exp $");
74
75 #ifdef _KERNEL_OPT
76 #include "opt_mii.h"
77 #endif
78
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/kernel.h>
82 #include <sys/device.h>
83 #include <sys/socket.h>
84 #include <sys/errno.h>
85
86 #include <net/if.h>
87 #include <net/if_media.h>
88
89 #include <dev/mii/mii.h>
90 #include <dev/mii/miivar.h>
91 #include <dev/mii/miidevs.h>
92 #include <dev/mii/igphyreg.h>
93 #include <dev/mii/igphyvar.h>
94 #include <dev/pci/if_wmvar.h>
95
96 static void igphy_reset(struct mii_softc *);
97 static void igphy_load_dspcode(struct mii_softc *);
98 static void igphy_load_dspcode_igp3(struct mii_softc *);
99 static void igphy_smartspeed_workaround(struct mii_softc *sc);
100
101 static int igphymatch(device_t, cfdata_t, void *);
102 static void igphyattach(device_t, device_t, void *);
103
104 CFATTACH_DECL_NEW(igphy, sizeof(struct igphy_softc),
105 igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
106
107 static int igphy_service(struct mii_softc *, struct mii_data *, int);
108 static void igphy_status(struct mii_softc *);
109
110 static const struct mii_phy_funcs igphy_funcs = {
111 igphy_service, igphy_status, igphy_reset,
112 };
113
114 static const struct mii_phydesc igphys[] = {
115 { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_IGP01E1000,
116 MII_STR_yyINTEL_IGP01E1000 },
117
118 { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_I82566,
119 MII_STR_yyINTEL_I82566 },
120
121 {0, 0,
122 NULL },
123 };
124
125 static int
126 igphymatch(device_t parent, cfdata_t match, void *aux)
127 {
128 struct mii_attach_args *ma = aux;
129
130 if (mii_phy_match(ma, igphys) != NULL)
131 return 10;
132
133 return 0;
134 }
135
136 static void
137 igphyattach(device_t parent, device_t self, void *aux)
138 {
139 struct mii_softc *sc = device_private(self);
140 struct mii_attach_args *ma = aux;
141 struct mii_data *mii = ma->mii_data;
142 const struct mii_phydesc *mpd;
143 struct igphy_softc *igsc = (struct igphy_softc *) sc;
144 prop_dictionary_t dict;
145
146 mpd = mii_phy_match(ma, igphys);
147 aprint_naive(": Media interface\n");
148 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
149
150 dict = device_properties(parent);
151 if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype))
152 aprint_error("WARNING! Failed to get mactype\n");
153 if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags))
154 aprint_error("WARNING! Failed to get macflags\n");
155
156 sc->mii_dev = self;
157 sc->mii_inst = mii->mii_instance;
158 sc->mii_phy = ma->mii_phyno;
159 sc->mii_funcs = &igphy_funcs;
160 sc->mii_pdata = mii;
161 sc->mii_flags = ma->mii_flags;
162 sc->mii_anegticks = MII_ANEGTICKS_GIGE;
163
164 PHY_RESET(sc);
165
166 sc->mii_capabilities =
167 PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
168 if (sc->mii_capabilities & BMSR_EXTSTAT)
169 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
170 aprint_normal_dev(self, "");
171 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
172 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
173 aprint_error("no media present");
174 else
175 mii_phy_add_media(sc);
176 aprint_normal("\n");
177 }
178
179 typedef struct {
180 int reg;
181 uint16_t val;
182 } dspcode;
183
184 static const dspcode igp1code[] = {
185 { 0x1f95, 0x0001 },
186 { 0x1f71, 0xbd21 },
187 { 0x1f79, 0x0018 },
188 { 0x1f30, 0x1600 },
189 { 0x1f31, 0x0014 },
190 { 0x1f32, 0x161c },
191 { 0x1f94, 0x0003 },
192 { 0x1f96, 0x003f },
193 { 0x2010, 0x0008 },
194 { 0, 0 },
195 };
196
197 static const dspcode igp1code_r2[] = {
198 { 0x1f73, 0x0099 },
199 { 0, 0 },
200 };
201
202 static const dspcode igp3code[] = {
203 { 0x2f5b, 0x9018},
204 { 0x2f52, 0x0000},
205 { 0x2fb1, 0x8b24},
206 { 0x2fb2, 0xf8f0},
207 { 0x2010, 0x10b0},
208 { 0x2011, 0x0000},
209 { 0x20dd, 0x249a},
210 { 0x20de, 0x00d3},
211 { 0x28b4, 0x04ce},
212 { 0x2f70, 0x29e4},
213 { 0x0000, 0x0140},
214 { 0x1f30, 0x1606},
215 { 0x1f31, 0xb814},
216 { 0x1f35, 0x002a},
217 { 0x1f3e, 0x0067},
218 { 0x1f54, 0x0065},
219 { 0x1f55, 0x002a},
220 { 0x1f56, 0x002a},
221 { 0x1f72, 0x3fb0},
222 { 0x1f76, 0xc0ff},
223 { 0x1f77, 0x1dec},
224 { 0x1f78, 0xf9ef},
225 { 0x1f79, 0x0210},
226 { 0x1895, 0x0003},
227 { 0x1796, 0x0008},
228 { 0x1798, 0xd008},
229 { 0x1898, 0xd918},
230 { 0x187a, 0x0800},
231 { 0x0019, 0x008d},
232 { 0x001b, 0x2080},
233 { 0x0014, 0x0045},
234 { 0x0000, 0x1340},
235 { 0, 0 },
236 };
237
238 /* DSP patch for igp1 and igp2 */
239 static void
240 igphy_load_dspcode(struct mii_softc *sc)
241 {
242 struct igphy_softc *igsc = (struct igphy_softc *) sc;
243 const dspcode *code;
244 uint16_t reg;
245 int i;
246
247 /* This workaround is only for 82541 and 82547 */
248 switch (igsc->sc_mactype) {
249 case WM_T_82541:
250 case WM_T_82547:
251 code = igp1code;
252 break;
253 case WM_T_82541_2:
254 case WM_T_82547_2:
255 code = igp1code_r2;
256 break;
257 default:
258 return; /* byebye */
259 }
260
261 /* Delay after phy reset to enable NVM configuration to load */
262 delay(20000);
263
264 /*
265 * Save off the current value of register 0x2F5B to be restored at
266 * the end of this routine.
267 */
268 reg = IGPHY_READ(sc, 0x2f5b);
269
270 /* Disabled the PHY transmitter */
271 IGPHY_WRITE(sc, 0x2f5b, 0x0003);
272
273 delay(20000);
274
275 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
276 PHY_WRITE(sc, 0x0000, 0x0140);
277
278 delay(5000);
279
280 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
281 IGPHY_WRITE(sc, code[i].reg, code[i].val);
282
283 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
284 PHY_WRITE(sc, 0x0000, 0x3300);
285
286 delay(20000);
287
288 /* Now enable the transmitter */
289 IGPHY_WRITE(sc, 0x2f5b, reg);
290 }
291
292 static void
293 igphy_load_dspcode_igp3(struct mii_softc *sc)
294 {
295 const dspcode *code = igp3code;
296 int i;
297
298 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
299 IGPHY_WRITE(sc, code[i].reg, code[i].val);
300 }
301
302 static void
303 igphy_reset(struct mii_softc *sc)
304 {
305 struct igphy_softc *igsc = (struct igphy_softc *) sc;
306 uint16_t fused, fine, coarse;
307
308 mii_phy_reset(sc);
309 delay(150);
310
311 switch (igsc->sc_mactype) {
312 case WM_T_82541:
313 case WM_T_82547:
314 case WM_T_82541_2:
315 case WM_T_82547_2:
316 igphy_load_dspcode(sc);
317 break;
318 case WM_T_ICH8:
319 case WM_T_ICH9:
320 if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0)
321 igphy_load_dspcode_igp3(sc);
322 break;
323 default: /* Not for ICH10, PCH and 8257[12] */
324 break;
325 }
326
327 if (igsc->sc_mactype == WM_T_82547) {
328 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
329 if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
330 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
331
332 fine = fused & ANALOG_FUSE_FINE_MASK;
333 coarse = fused & ANALOG_FUSE_COARSE_MASK;
334
335 if (coarse > ANALOG_FUSE_COARSE_THRESH) {
336 coarse -= ANALOG_FUSE_COARSE_10;
337 fine -= ANALOG_FUSE_FINE_1;
338 } else if (coarse == ANALOG_FUSE_COARSE_THRESH)
339 fine -= ANALOG_FUSE_FINE_10;
340
341 fused = (fused & ANALOG_FUSE_POLY_MASK) |
342 (fine & ANALOG_FUSE_FINE_MASK) |
343 (coarse & ANALOG_FUSE_COARSE_MASK);
344
345 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
346 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
347 ANALOG_FUSE_ENABLE_SW_CONTROL);
348 }
349 }
350 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
351 }
352
353
354 static int
355 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
356 {
357 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
358 uint16_t reg;
359
360 switch (cmd) {
361 case MII_POLLSTAT:
362 /*
363 * If we're not polling our PHY instance, just return.
364 */
365 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
366 return (0);
367 break;
368
369 case MII_MEDIACHG:
370 /*
371 * If the media indicates a different PHY instance,
372 * isolate ourselves.
373 */
374 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
375 reg = PHY_READ(sc, MII_BMCR);
376 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
377 return (0);
378 }
379
380 /*
381 * If the interface is not up, don't do anything.
382 */
383 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
384 break;
385
386 reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL);
387 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
388 reg |= PSCR_AUTO_MDIX;
389 reg &= ~PSCR_FORCE_MDI_MDIX;
390 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
391 } else {
392 reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
393 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
394 }
395
396 mii_phy_setmedia(sc);
397 break;
398
399 case MII_TICK:
400 /*
401 * If we're not currently selected, just return.
402 */
403 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
404 return (0);
405
406 igphy_smartspeed_workaround(sc);
407
408 if (mii_phy_tick(sc) == EJUSTRETURN)
409 return (0);
410 break;
411
412 case MII_DOWN:
413 mii_phy_down(sc);
414 return (0);
415 }
416
417 /* Update the media status. */
418 mii_phy_status(sc);
419
420 /* Callback if something changed. */
421 mii_phy_update(sc, cmd);
422 return (0);
423 }
424
425
426 static void
427 igphy_status(struct mii_softc *sc)
428 {
429 struct mii_data *mii = sc->mii_pdata;
430 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
431 uint16_t bmcr, pssr, gtsr, bmsr;
432
433 mii->mii_media_status = IFM_AVALID;
434 mii->mii_media_active = IFM_ETHER;
435
436 pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
437
438 if (pssr & PSSR_LINK_UP)
439 mii->mii_media_status |= IFM_ACTIVE;
440
441 bmcr = PHY_READ(sc, MII_BMCR);
442 if (bmcr & BMCR_ISO) {
443 mii->mii_media_active |= IFM_NONE;
444 mii->mii_media_status = 0;
445 return;
446 }
447
448 if (bmcr & BMCR_LOOP)
449 mii->mii_media_active |= IFM_LOOP;
450
451 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
452
453 /*
454 * XXX can't check if the info is valid, no
455 * 'negotiation done' bit?
456 */
457 if (bmcr & BMCR_AUTOEN) {
458 if ((bmsr & BMSR_ACOMP) == 0) {
459 mii->mii_media_active |= IFM_NONE;
460 return;
461 }
462 switch (pssr & PSSR_SPEED_MASK) {
463 case PSSR_SPEED_1000MBPS:
464 mii->mii_media_active |= IFM_1000_T;
465 gtsr = PHY_READ(sc, MII_100T2SR);
466 if (gtsr & GTSR_MS_RES)
467 mii->mii_media_active |= IFM_ETH_MASTER;
468 break;
469
470 case PSSR_SPEED_100MBPS:
471 mii->mii_media_active |= IFM_100_TX;
472 break;
473
474 case PSSR_SPEED_10MBPS:
475 mii->mii_media_active |= IFM_10_T;
476 break;
477
478 default:
479 mii->mii_media_active |= IFM_NONE;
480 mii->mii_media_status = 0;
481 return;
482 }
483
484 if (pssr & PSSR_FULL_DUPLEX)
485 mii->mii_media_active |=
486 IFM_FDX | mii_phy_flowstatus(sc);
487 else
488 mii->mii_media_active |= IFM_HDX;
489 } else
490 mii->mii_media_active = ife->ifm_media;
491 }
492
493 static void
494 igphy_smartspeed_workaround(struct mii_softc *sc)
495 {
496 struct igphy_softc *igsc = (struct igphy_softc *) sc;
497 uint16_t reg, gtsr, gtcr;
498
499 /* This workaround is only for 82541 and 82547 */
500 switch (igsc->sc_mactype) {
501 case WM_T_82541:
502 case WM_T_82541_2:
503 case WM_T_82547:
504 case WM_T_82547_2:
505 break;
506 default:
507 /* byebye */
508 return;
509 }
510
511 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
512 return;
513
514 /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
515
516 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
517 if ((reg & BMSR_LINK) == 0) {
518 switch (igsc->sc_smartspeed) {
519 case 0:
520 gtsr = PHY_READ(sc, MII_100T2SR);
521 if (!(gtsr & GTSR_MAN_MS_FLT))
522 break;
523 gtsr = PHY_READ(sc, MII_100T2SR);
524 if (gtsr & GTSR_MAN_MS_FLT) {
525 gtcr = PHY_READ(sc, MII_100T2CR);
526 if (gtcr & GTCR_MAN_MS) {
527 gtcr &= ~GTCR_MAN_MS;
528 PHY_WRITE(sc, MII_100T2CR,
529 gtcr);
530 }
531 mii_phy_auto(sc, 0);
532 }
533 break;
534 case IGPHY_TICK_DOWNSHIFT:
535 gtcr = PHY_READ(sc, MII_100T2CR);
536 gtcr |= GTCR_MAN_MS;
537 PHY_WRITE(sc, MII_100T2CR, gtcr);
538 mii_phy_auto(sc, 0);
539 break;
540 default:
541 break;
542 }
543 if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
544 igsc->sc_smartspeed = 0;
545 } else
546 igsc->sc_smartspeed = 0;
547 }
548