xref: /netbsd-src/sys/dev/mii/igphy.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: igphy.c,v 1.21 2010/03/07 07:53:37 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.21 2010/03/07 07:53:37 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/mii/igphyvar.h>
92 #include <dev/pci/if_wmvar.h>
93 
94 static void igphy_reset(struct mii_softc *);
95 static void igphy_load_dspcode(struct mii_softc *);
96 static void igphy_load_dspcode_igp3(struct mii_softc *);
97 static void igphy_smartspeed_workaround(struct mii_softc *sc);
98 
99 static int	igphymatch(device_t, cfdata_t, void *);
100 static void	igphyattach(device_t, device_t, void *);
101 
102 CFATTACH_DECL_NEW(igphy, sizeof(struct igphy_softc),
103     igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
104 
105 static int	igphy_service(struct mii_softc *, struct mii_data *, int);
106 static void	igphy_status(struct mii_softc *);
107 
108 static const struct mii_phy_funcs igphy_funcs = {
109 	igphy_service, igphy_status, igphy_reset,
110 };
111 
112 static const struct mii_phydesc igphys[] = {
113 	{ MII_OUI_yyINTEL,		MII_MODEL_yyINTEL_IGP01E1000,
114 	  MII_STR_yyINTEL_IGP01E1000 },
115 
116 	{ MII_OUI_yyINTEL,		MII_MODEL_yyINTEL_I82566,
117 	  MII_STR_yyINTEL_I82566 },
118 
119 	{0,				0,
120 	 NULL },
121 };
122 
123 static int
124 igphymatch(device_t parent, cfdata_t match, void *aux)
125 {
126 	struct mii_attach_args *ma = aux;
127 
128 	if (mii_phy_match(ma, igphys) != NULL)
129 		return 10;
130 
131 	return 0;
132 }
133 
134 static void
135 igphyattach(device_t parent, device_t self, void *aux)
136 {
137 	struct mii_softc *sc = device_private(self);
138 	struct mii_attach_args *ma = aux;
139 	struct mii_data *mii = ma->mii_data;
140 	const struct mii_phydesc *mpd;
141 	struct igphy_softc *igsc = (struct igphy_softc *) sc;
142 	prop_dictionary_t dict;
143 
144 	mpd = mii_phy_match(ma, igphys);
145 	aprint_naive(": Media interface\n");
146 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
147 
148 	dict = device_properties(parent);
149 	if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype))
150 		aprint_error("WARNING! Failed to get mactype\n");
151 	if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags))
152 		aprint_error("WARNING! Failed to get macflags\n");
153 
154 	sc->mii_dev = self;
155 	sc->mii_inst = mii->mii_instance;
156 	sc->mii_phy = ma->mii_phyno;
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 	sc->mii_capabilities =
165 	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
166 	if (sc->mii_capabilities & BMSR_EXTSTAT)
167 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
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 	reg = 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, MII_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, MII_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 		fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
327 		if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
328 			fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
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, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
344 			IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
345 			    ANALOG_FUSE_ENABLE_SW_CONTROL);
346 		}
347 	}
348 	PHY_WRITE(sc, MII_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 		/*
361 		 * If we're not polling our PHY instance, just return.
362 		 */
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 			reg = PHY_READ(sc, MII_BMCR);
374 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
375 			return (0);
376 		}
377 
378 		/*
379 		 * If the interface is not up, don't do anything.
380 		 */
381 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
382 			break;
383 
384 		reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL);
385 		if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
386 			reg |= PSCR_AUTO_MDIX;
387 			reg &= ~PSCR_FORCE_MDI_MDIX;
388 			PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
389 		} else {
390 			reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
391 			PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
392 		}
393 
394 		mii_phy_setmedia(sc);
395 		break;
396 
397 	case MII_TICK:
398 		/*
399 		 * If we're not currently selected, just return.
400 		 */
401 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
402 			return (0);
403 
404 		igphy_smartspeed_workaround(sc);
405 
406 		if (mii_phy_tick(sc) == EJUSTRETURN)
407 			return (0);
408 		break;
409 
410 	case MII_DOWN:
411 		mii_phy_down(sc);
412 		return (0);
413 	}
414 
415 	/* Update the media status. */
416 	mii_phy_status(sc);
417 
418 	/* Callback if something changed. */
419 	mii_phy_update(sc, cmd);
420 	return (0);
421 }
422 
423 
424 static void
425 igphy_status(struct mii_softc *sc)
426 {
427 	struct mii_data *mii = sc->mii_pdata;
428 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
429 	uint16_t bmcr, pssr, gtsr, bmsr;
430 
431 	mii->mii_media_status = IFM_AVALID;
432 	mii->mii_media_active = IFM_ETHER;
433 
434 	pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
435 
436 	if (pssr & PSSR_LINK_UP)
437 		mii->mii_media_status |= IFM_ACTIVE;
438 
439 	bmcr = PHY_READ(sc, MII_BMCR);
440 	if (bmcr & BMCR_ISO) {
441 		mii->mii_media_active |= IFM_NONE;
442 		mii->mii_media_status = 0;
443 		return;
444 	}
445 
446 	if (bmcr & BMCR_LOOP)
447 		mii->mii_media_active |= IFM_LOOP;
448 
449 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
450 
451 	/*
452 	 * XXX can't check if the info is valid, no
453 	 * 'negotiation done' bit?
454 	 */
455 	if (bmcr & BMCR_AUTOEN) {
456 		if ((bmsr & BMSR_ACOMP) == 0) {
457 			mii->mii_media_active |= IFM_NONE;
458 			return;
459 		}
460 		switch (pssr & PSSR_SPEED_MASK) {
461 		case PSSR_SPEED_1000MBPS:
462 			mii->mii_media_active |= IFM_1000_T;
463 			gtsr = PHY_READ(sc, MII_100T2SR);
464 			if (gtsr & GTSR_MS_RES)
465 				mii->mii_media_active |= IFM_ETH_MASTER;
466 			break;
467 
468 		case PSSR_SPEED_100MBPS:
469 			mii->mii_media_active |= IFM_100_TX;
470 			break;
471 
472 		case PSSR_SPEED_10MBPS:
473 			mii->mii_media_active |= IFM_10_T;
474 			break;
475 
476 		default:
477 			mii->mii_media_active |= IFM_NONE;
478 			mii->mii_media_status = 0;
479 			return;
480 		}
481 
482 		if (pssr & PSSR_FULL_DUPLEX)
483 			mii->mii_media_active |=
484 			    IFM_FDX | mii_phy_flowstatus(sc);
485 	} else
486 		mii->mii_media_active = ife->ifm_media;
487 }
488 
489 static void
490 igphy_smartspeed_workaround(struct mii_softc *sc)
491 {
492 	struct igphy_softc *igsc = (struct igphy_softc *) sc;
493 	uint16_t reg, gtsr, gtcr;
494 
495 
496 	/* This workaround is only for 82541 and 82547 */
497 	switch (igsc->sc_mactype) {
498 	case WM_T_82541:
499 	case WM_T_82541_2:
500 	case WM_T_82547:
501 	case WM_T_82547_2:
502 		break;
503 	default:
504 		/* byebye */
505 		return;
506 	}
507 
508 	if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
509 		return;
510 
511 	/* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
512 
513 	reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
514 	if ((reg & BMSR_LINK) == 0) {
515 		switch (igsc->sc_smartspeed) {
516 		case 0:
517 			gtsr = PHY_READ(sc, MII_100T2SR);
518 			if (!(gtsr & GTSR_MAN_MS_FLT))
519 				break;
520 			gtsr = PHY_READ(sc, MII_100T2SR);
521 			if (gtsr & GTSR_MAN_MS_FLT) {
522 				gtcr = PHY_READ(sc, MII_100T2CR);
523 				if (gtcr & GTCR_MAN_MS) {
524 					gtcr &= ~GTCR_MAN_MS;
525 					PHY_WRITE(sc, MII_100T2CR,
526 					    gtcr);
527 				}
528 				mii_phy_auto(sc, 0);
529 			}
530 			break;
531 		case IGPHY_TICK_DOWNSHIFT:
532 			gtcr = PHY_READ(sc, MII_100T2CR);
533 			gtcr |= GTCR_MAN_MS;
534 			PHY_WRITE(sc, MII_100T2CR, gtcr);
535 			mii_phy_auto(sc, 0);
536 			break;
537 		default:
538 			break;
539 		}
540 		if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
541 			igsc->sc_smartspeed = 0;
542 	} else
543 		igsc->sc_smartspeed = 0;
544 }
545