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