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