igphy.c revision 1.20 1 /* $NetBSD: igphy.c,v 1.20 2009/12/16 14:37:26 msaitoh 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.20 2009/12/16 14:37:26 msaitoh 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
183 typedef struct {
184 int reg;
185 uint16_t val;
186 } dspcode;
187
188 static const dspcode igp1code[] = {
189 { 0x1f95, 0x0001 },
190 { 0x1f71, 0xbd21 },
191 { 0x1f79, 0x0018 },
192 { 0x1f30, 0x1600 },
193 { 0x1f31, 0x0014 },
194 { 0x1f32, 0x161c },
195 { 0x1f94, 0x0003 },
196 { 0x1f96, 0x003f },
197 { 0x2010, 0x0008 },
198 { 0, 0 },
199 };
200
201 static const dspcode igp1code_r2[] = {
202 { 0x1f73, 0x0099 },
203 { 0, 0 },
204 };
205
206 static const dspcode igp3code[] = {
207 { 0x2f5b, 0x9018},
208 { 0x2f52, 0x0000},
209 { 0x2fb1, 0x8b24},
210 { 0x2fb2, 0xf8f0},
211 { 0x2010, 0x10b0},
212 { 0x2011, 0x0000},
213 { 0x20dd, 0x249a},
214 { 0x20de, 0x00d3},
215 { 0x28b4, 0x04ce},
216 { 0x2f70, 0x29e4},
217 { 0x0000, 0x0140},
218 { 0x1f30, 0x1606},
219 { 0x1f31, 0xb814},
220 { 0x1f35, 0x002a},
221 { 0x1f3e, 0x0067},
222 { 0x1f54, 0x0065},
223 { 0x1f55, 0x002a},
224 { 0x1f56, 0x002a},
225 { 0x1f72, 0x3fb0},
226 { 0x1f76, 0xc0ff},
227 { 0x1f77, 0x1dec},
228 { 0x1f78, 0xf9ef},
229 { 0x1f79, 0x0210},
230 { 0x1895, 0x0003},
231 { 0x1796, 0x0008},
232 { 0x1798, 0xd008},
233 { 0x1898, 0xd918},
234 { 0x187a, 0x0800},
235 { 0x0019, 0x008d},
236 { 0x001b, 0x2080},
237 { 0x0014, 0x0045},
238 { 0x0000, 0x1340},
239 { 0, 0 },
240 };
241
242 /* DSP patch for igp1 and igp2 */
243 static void
244 igphy_load_dspcode(struct mii_softc *sc)
245 {
246 struct igphy_softc *igsc = (struct igphy_softc *) sc;
247 const dspcode *code;
248 uint16_t reg;
249 int i;
250
251 /* This workaround is only for 82541 and 82547 */
252 switch (igsc->sc_mactype) {
253 case WM_T_82541:
254 case WM_T_82547:
255 code = igp1code;
256 break;
257 case WM_T_82541_2:
258 case WM_T_82547_2:
259 code = igp1code_r2;
260 break;
261 default:
262 return; /* byebye */
263 }
264
265 /* Delay after phy reset to enable NVM configuration to load */
266 delay(20000);
267
268 /*
269 * Save off the current value of register 0x2F5B to be restored at
270 * the end of this routine.
271 */
272 reg = IGPHY_READ(sc, 0x2f5b);
273
274 /* Disabled the PHY transmitter */
275 IGPHY_WRITE(sc, 0x2f5b, 0x0003);
276
277 delay(20000);
278
279 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
280 PHY_WRITE(sc, 0x0000, 0x0140);
281
282 delay(5000);
283
284 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
285 IGPHY_WRITE(sc, code[i].reg, code[i].val);
286
287 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
288 PHY_WRITE(sc, 0x0000, 0x3300);
289
290 delay(20000);
291
292 /* Now enable the transmitter */
293 IGPHY_WRITE(sc, 0x2f5b, reg);
294 }
295
296 static void
297 igphy_load_dspcode_igp3(struct mii_softc *sc)
298 {
299 const dspcode *code = igp3code;
300 int i;
301
302 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
303 IGPHY_WRITE(sc, code[i].reg, code[i].val);
304 }
305
306 static void
307 igphy_reset(struct mii_softc *sc)
308 {
309 struct igphy_softc *igsc = (struct igphy_softc *) sc;
310 uint16_t fused, fine, coarse;
311
312 mii_phy_reset(sc);
313 delay(150);
314
315 switch (igsc->sc_mactype) {
316 case WM_T_82541:
317 case WM_T_82547:
318 case WM_T_82541_2:
319 case WM_T_82547_2:
320 igphy_load_dspcode(sc);
321 break;
322 case WM_T_ICH8:
323 case WM_T_ICH9:
324 if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0)
325 igphy_load_dspcode_igp3(sc);
326 break;
327 default: /* Not for ICH10, PCH and 8257[12] */
328 break;
329 }
330
331 if (igsc->sc_mactype == WM_T_82547) {
332 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
333 if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
334 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
335
336 fine = fused & ANALOG_FUSE_FINE_MASK;
337 coarse = fused & ANALOG_FUSE_COARSE_MASK;
338
339 if (coarse > ANALOG_FUSE_COARSE_THRESH) {
340 coarse -= ANALOG_FUSE_COARSE_10;
341 fine -= ANALOG_FUSE_FINE_1;
342 } else if (coarse == ANALOG_FUSE_COARSE_THRESH)
343 fine -= ANALOG_FUSE_FINE_10;
344
345 fused = (fused & ANALOG_FUSE_POLY_MASK) |
346 (fine & ANALOG_FUSE_FINE_MASK) |
347 (coarse & ANALOG_FUSE_COARSE_MASK);
348
349 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
350 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
351 ANALOG_FUSE_ENABLE_SW_CONTROL);
352 }
353 }
354 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
355 }
356
357
358 static int
359 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
360 {
361 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
362 uint16_t reg;
363
364 switch (cmd) {
365 case MII_POLLSTAT:
366 /*
367 * If we're not polling our PHY instance, just return.
368 */
369 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
370 return (0);
371 break;
372
373 case MII_MEDIACHG:
374 /*
375 * If the media indicates a different PHY instance,
376 * isolate ourselves.
377 */
378 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
379 reg = PHY_READ(sc, MII_BMCR);
380 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
381 return (0);
382 }
383
384 /*
385 * If the interface is not up, don't do anything.
386 */
387 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
388 break;
389
390 reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL);
391 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
392 reg |= PSCR_AUTO_MDIX;
393 reg &= ~PSCR_FORCE_MDI_MDIX;
394 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
395 } else {
396 reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
397 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
398 }
399
400 mii_phy_setmedia(sc);
401 break;
402
403 case MII_TICK:
404 /*
405 * If we're not currently selected, just return.
406 */
407 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
408 return (0);
409
410 igphy_smartspeed_workaround(sc);
411
412 if (mii_phy_tick(sc) == EJUSTRETURN)
413 return (0);
414 break;
415
416 case MII_DOWN:
417 mii_phy_down(sc);
418 return (0);
419 }
420
421 /* Update the media status. */
422 mii_phy_status(sc);
423
424 /* Callback if something changed. */
425 mii_phy_update(sc, cmd);
426 return (0);
427 }
428
429
430 static void
431 igphy_status(struct mii_softc *sc)
432 {
433 struct mii_data *mii = sc->mii_pdata;
434 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
435 uint16_t bmcr, pssr, gtsr, bmsr;
436
437 mii->mii_media_status = IFM_AVALID;
438 mii->mii_media_active = IFM_ETHER;
439
440 pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
441
442 if (pssr & PSSR_LINK_UP)
443 mii->mii_media_status |= IFM_ACTIVE;
444
445 bmcr = PHY_READ(sc, MII_BMCR);
446 if (bmcr & BMCR_ISO) {
447 mii->mii_media_active |= IFM_NONE;
448 mii->mii_media_status = 0;
449 return;
450 }
451
452 if (bmcr & BMCR_LOOP)
453 mii->mii_media_active |= IFM_LOOP;
454
455 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
456
457 /*
458 * XXX can't check if the info is valid, no
459 * 'negotiation done' bit?
460 */
461 if (bmcr & BMCR_AUTOEN) {
462 if ((bmsr & BMSR_ACOMP) == 0) {
463 mii->mii_media_active |= IFM_NONE;
464 return;
465 }
466 switch (pssr & PSSR_SPEED_MASK) {
467 case PSSR_SPEED_1000MBPS:
468 mii->mii_media_active |= IFM_1000_T;
469 gtsr = PHY_READ(sc, MII_100T2SR);
470 if (gtsr & GTSR_MS_RES)
471 mii->mii_media_active |= IFM_ETH_MASTER;
472 break;
473
474 case PSSR_SPEED_100MBPS:
475 mii->mii_media_active |= IFM_100_TX;
476 break;
477
478 case PSSR_SPEED_10MBPS:
479 mii->mii_media_active |= IFM_10_T;
480 break;
481
482 default:
483 mii->mii_media_active |= IFM_NONE;
484 mii->mii_media_status = 0;
485 return;
486 }
487
488 if (pssr & PSSR_FULL_DUPLEX)
489 mii->mii_media_active |=
490 IFM_FDX | mii_phy_flowstatus(sc);
491 } else
492 mii->mii_media_active = ife->ifm_media;
493 }
494
495 static void
496 igphy_smartspeed_workaround(struct mii_softc *sc)
497 {
498 struct igphy_softc *igsc = (struct igphy_softc *) sc;
499 uint16_t reg, gtsr, gtcr;
500
501
502 /* This workaround is only for 82541 and 82547 */
503 switch (igsc->sc_mactype) {
504 case WM_T_82541:
505 case WM_T_82541_2:
506 case WM_T_82547:
507 case WM_T_82547_2:
508 break;
509 default:
510 /* byebye */
511 return;
512 }
513
514 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
515 return;
516
517 /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
518
519 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
520 if ((reg & BMSR_LINK) == 0) {
521 switch (igsc->sc_smartspeed) {
522 case 0:
523 gtsr = PHY_READ(sc, MII_100T2SR);
524 if (!(gtsr & GTSR_MAN_MS_FLT))
525 break;
526 gtsr = PHY_READ(sc, MII_100T2SR);
527 if (gtsr & GTSR_MAN_MS_FLT) {
528 gtcr = PHY_READ(sc, MII_100T2CR);
529 if (gtcr & GTCR_MAN_MS) {
530 gtcr &= ~GTCR_MAN_MS;
531 PHY_WRITE(sc, MII_100T2CR,
532 gtcr);
533 }
534 mii_phy_auto(sc, 0);
535 }
536 break;
537 case IGPHY_TICK_DOWNSHIFT:
538 gtcr = PHY_READ(sc, MII_100T2CR);
539 gtcr |= GTCR_MAN_MS;
540 PHY_WRITE(sc, MII_100T2CR, gtcr);
541 mii_phy_auto(sc, 0);
542 break;
543 default:
544 break;
545 }
546 if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
547 igsc->sc_smartspeed = 0;
548 } else
549 igsc->sc_smartspeed = 0;
550 }
551