1 /* $NetBSD: igphy.c,v 1.37 2020/11/04 09:15:10 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.37 2020/11/04 09:15:10 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_PHY_DESC(yyINTEL, IGP01E1000),
116 MII_PHY_DESC(yyINTEL, I82566),
117 MII_PHY_END,
118 };
119
120 static int
igphymatch(device_t parent,cfdata_t match,void * aux)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
igphyattach(device_t parent,device_t self,void * aux)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
161 mii_lock(mii);
162
163 PHY_RESET(sc);
164
165 PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
166 sc->mii_capabilities &= ma->mii_capmask;
167 if (sc->mii_capabilities & BMSR_EXTSTAT)
168 PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
169
170 mii_unlock(mii);
171
172 mii_phy_add_media(sc);
173 }
174
175 typedef struct {
176 int reg;
177 uint16_t val;
178 } dspcode;
179
180 static const dspcode igp1code[] = {
181 { 0x1f95, 0x0001 },
182 { 0x1f71, 0xbd21 },
183 { 0x1f79, 0x0018 },
184 { 0x1f30, 0x1600 },
185 { 0x1f31, 0x0014 },
186 { 0x1f32, 0x161c },
187 { 0x1f94, 0x0003 },
188 { 0x1f96, 0x003f },
189 { 0x2010, 0x0008 },
190 { 0, 0 },
191 };
192
193 static const dspcode igp1code_r2[] = {
194 { 0x1f73, 0x0099 },
195 { 0, 0 },
196 };
197
198 static const dspcode igp3code[] = {
199 { 0x2f5b, 0x9018},
200 { 0x2f52, 0x0000},
201 { 0x2fb1, 0x8b24},
202 { 0x2fb2, 0xf8f0},
203 { 0x2010, 0x10b0},
204 { 0x2011, 0x0000},
205 { 0x20dd, 0x249a},
206 { 0x20de, 0x00d3},
207 { 0x28b4, 0x04ce},
208 { 0x2f70, 0x29e4},
209 { 0x0000, 0x0140},
210 { 0x1f30, 0x1606},
211 { 0x1f31, 0xb814},
212 { 0x1f35, 0x002a},
213 { 0x1f3e, 0x0067},
214 { 0x1f54, 0x0065},
215 { 0x1f55, 0x002a},
216 { 0x1f56, 0x002a},
217 { 0x1f72, 0x3fb0},
218 { 0x1f76, 0xc0ff},
219 { 0x1f77, 0x1dec},
220 { 0x1f78, 0xf9ef},
221 { 0x1f79, 0x0210},
222 { 0x1895, 0x0003},
223 { 0x1796, 0x0008},
224 { 0x1798, 0xd008},
225 { 0x1898, 0xd918},
226 { 0x187a, 0x0800},
227 { 0x0019, 0x008d},
228 { 0x001b, 0x2080},
229 { 0x0014, 0x0045},
230 { 0x0000, 0x1340},
231 { 0, 0 },
232 };
233
234 /* DSP patch for igp1 and igp2 */
235 static void
igphy_load_dspcode(struct mii_softc * sc)236 igphy_load_dspcode(struct mii_softc *sc)
237 {
238 struct igphy_softc *igsc = (struct igphy_softc *)sc;
239 const dspcode *code;
240 uint16_t reg;
241 int i;
242
243 /* This workaround is only for 82541 and 82547 */
244 switch (igsc->sc_mactype) {
245 case WM_T_82541:
246 case WM_T_82547:
247 code = igp1code;
248 break;
249 case WM_T_82541_2:
250 case WM_T_82547_2:
251 code = igp1code_r2;
252 break;
253 default:
254 return; /* byebye */
255 }
256
257 /* Delay after phy reset to enable NVM configuration to load */
258 delay(20000);
259
260 /*
261 * Save off the current value of register 0x2F5B to be restored at
262 * the end of this routine.
263 */
264 IGPHY_READ(sc, 0x2f5b, ®);
265
266 /* Disabled the PHY transmitter */
267 IGPHY_WRITE(sc, 0x2f5b, 0x0003);
268
269 delay(20000);
270
271 PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
272 PHY_WRITE(sc, 0x0000, 0x0140);
273
274 delay(5000);
275
276 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
277 IGPHY_WRITE(sc, code[i].reg, code[i].val);
278
279 PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
280 PHY_WRITE(sc, 0x0000, 0x3300);
281
282 delay(20000);
283
284 /* Now enable the transmitter */
285 IGPHY_WRITE(sc, 0x2f5b, reg);
286 }
287
288 static void
igphy_load_dspcode_igp3(struct mii_softc * sc)289 igphy_load_dspcode_igp3(struct mii_softc *sc)
290 {
291 const dspcode *code = igp3code;
292 int i;
293
294 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
295 IGPHY_WRITE(sc, code[i].reg, code[i].val);
296 }
297
298 static void
igphy_reset(struct mii_softc * sc)299 igphy_reset(struct mii_softc *sc)
300 {
301 struct igphy_softc *igsc = (struct igphy_softc *)sc;
302 uint16_t fused, fine, coarse;
303
304 KASSERT(mii_locked(sc->mii_pdata));
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
igphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)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 KASSERT(mii_locked(mii));
359
360 switch (cmd) {
361 case MII_POLLSTAT:
362 /* If we're not polling our PHY instance, just return. */
363 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
364 return 0;
365 break;
366
367 case MII_MEDIACHG:
368 /*
369 * If the media indicates a different PHY instance,
370 * isolate ourselves.
371 */
372 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
373 PHY_READ(sc, MII_BMCR, ®);
374 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
375 return 0;
376 }
377
378 /* If the interface is not up, don't do anything. */
379 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
380 break;
381
382 PHY_READ(sc, IGPHY_PORT_CTRL, ®);
383 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
384 reg |= PSCR_AUTO_MDIX;
385 reg &= ~PSCR_FORCE_MDI_MDIX;
386 PHY_WRITE(sc, IGPHY_PORT_CTRL, reg);
387 } else {
388 reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
389 PHY_WRITE(sc, IGPHY_PORT_CTRL, reg);
390 }
391
392 mii_phy_setmedia(sc);
393 break;
394
395 case MII_TICK:
396 /* If we're not currently selected, just return. */
397 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
398 return 0;
399
400 igphy_smartspeed_workaround(sc);
401
402 if (mii_phy_tick(sc) == EJUSTRETURN)
403 return 0;
404 break;
405
406 case MII_DOWN:
407 mii_phy_down(sc);
408 return 0;
409 }
410
411 /* Update the media status. */
412 mii_phy_status(sc);
413
414 /* Callback if something changed. */
415 mii_phy_update(sc, cmd);
416 return 0;
417 }
418
419
420 static void
igphy_status(struct mii_softc * sc)421 igphy_status(struct mii_softc *sc)
422 {
423 struct mii_data *mii = sc->mii_pdata;
424 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
425 uint16_t bmcr, pssr, gtsr, bmsr;
426
427 KASSERT(mii_locked(mii));
428
429 mii->mii_media_status = IFM_AVALID;
430 mii->mii_media_active = IFM_ETHER;
431
432 PHY_READ(sc, IGPHY_PORT_STATUS, &pssr);
433
434 if (pssr & IGPHY_PSSR_LINK_UP)
435 mii->mii_media_status |= IFM_ACTIVE;
436
437 PHY_READ(sc, MII_BMCR, &bmcr);
438 if (bmcr & BMCR_ISO) {
439 mii->mii_media_active |= IFM_NONE;
440 return;
441 }
442
443 if (bmcr & BMCR_LOOP)
444 mii->mii_media_active |= IFM_LOOP;
445
446 PHY_READ(sc, MII_BMSR, &bmsr);
447 PHY_READ(sc, MII_BMSR, &bmsr);
448
449 /* XXX can't check if the info is valid, no 'negotiation done' bit? */
450 if (bmcr & BMCR_AUTOEN) {
451 if ((bmsr & BMSR_ACOMP) == 0) {
452 mii->mii_media_active |= IFM_NONE;
453 return;
454 }
455 switch (pssr & IGPHY_PSSR_SPEED_MASK) {
456 case IGPHY_PSSR_SPEED_1000MBPS:
457 mii->mii_media_active |= IFM_1000_T;
458 PHY_READ(sc, MII_100T2SR, >sr);
459 if (gtsr & GTSR_MS_RES)
460 mii->mii_media_active |= IFM_ETH_MASTER;
461 break;
462
463 case IGPHY_PSSR_SPEED_100MBPS:
464 mii->mii_media_active |= IFM_100_TX;
465 break;
466
467 case IGPHY_PSSR_SPEED_10MBPS:
468 mii->mii_media_active |= IFM_10_T;
469 break;
470
471 default:
472 mii->mii_media_active |= IFM_NONE;
473 mii->mii_media_status = 0;
474 return;
475 }
476
477 if (pssr & IGPHY_PSSR_FULL_DUPLEX)
478 mii->mii_media_active |=
479 IFM_FDX | mii_phy_flowstatus(sc);
480 else
481 mii->mii_media_active |= IFM_HDX;
482 } else
483 mii->mii_media_active = ife->ifm_media;
484 }
485
486 static void
igphy_smartspeed_workaround(struct mii_softc * sc)487 igphy_smartspeed_workaround(struct mii_softc *sc)
488 {
489 struct igphy_softc *igsc = (struct igphy_softc *)sc;
490 uint16_t reg, gtsr, gtcr;
491
492 /* This workaround is only for 82541 and 82547 */
493 switch (igsc->sc_mactype) {
494 case WM_T_82541:
495 case WM_T_82541_2:
496 case WM_T_82547:
497 case WM_T_82547_2:
498 break;
499 default:
500 /* byebye */
501 return;
502 }
503
504 PHY_READ(sc, MII_BMCR, ®);
505 if ((reg & BMCR_AUTOEN) == 0)
506 return;
507
508 /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
509
510 PHY_READ(sc, MII_BMSR, ®);
511 PHY_READ(sc, MII_BMSR, ®);
512 if ((reg & BMSR_LINK) == 0) {
513 switch (igsc->sc_smartspeed) {
514 case 0:
515 PHY_READ(sc, MII_100T2SR, >sr);
516 if (!(gtsr & GTSR_MAN_MS_FLT))
517 break;
518 PHY_READ(sc, MII_100T2SR, >sr);
519 if (gtsr & GTSR_MAN_MS_FLT) {
520 PHY_READ(sc, MII_100T2CR, >cr);
521 if (gtcr & GTCR_MAN_MS) {
522 gtcr &= ~GTCR_MAN_MS;
523 PHY_WRITE(sc, MII_100T2CR, gtcr);
524 }
525 mii_phy_auto(sc);
526 }
527 break;
528 case IGPHY_TICK_DOWNSHIFT:
529 PHY_READ(sc, MII_100T2CR, >cr);
530 gtcr |= GTCR_MAN_MS;
531 PHY_WRITE(sc, MII_100T2CR, gtcr);
532 mii_phy_auto(sc);
533 break;
534 default:
535 break;
536 }
537 if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
538 igsc->sc_smartspeed = 0;
539 } else
540 igsc->sc_smartspeed = 0;
541 }
542