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