xref: /netbsd-src/sys/dev/mii/igphy.c (revision de1dfb1250df962f1ff3a011772cf58e605aed11)
1 /*	$NetBSD: igphy.c,v 1.4 2004/08/23 06:16:06 thorpej 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  * 3. All advertising materials mentioning features or use of this software
59  *    must display the following acknowledgement:
60  *	This product includes software developed by the NetBSD
61  *	Foundation, Inc. and its contributors.
62  * 4. Neither the name of The NetBSD Foundation nor the names of its
63  *    contributors may be used to endorse or promote products derived
64  *    from this software without specific prior written permission.
65  *
66  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
67  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
68  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
69  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
70  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
71  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
72  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
73  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
74  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
75  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
76  * POSSIBILITY OF SUCH DAMAGE.
77  */
78 
79 #include <sys/cdefs.h>
80 __KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.4 2004/08/23 06:16:06 thorpej Exp $");
81 
82 #include "opt_mii.h"
83 
84 #include <sys/param.h>
85 #include <sys/systm.h>
86 #include <sys/kernel.h>
87 #include <sys/device.h>
88 #include <sys/socket.h>
89 #include <sys/errno.h>
90 
91 #include <net/if.h>
92 #include <net/if_media.h>
93 
94 #include <dev/mii/mii.h>
95 #include <dev/mii/miivar.h>
96 #include <dev/mii/miidevs.h>
97 
98 #include <dev/mii/igphyreg.h>
99 
100 static void igphy_reset(struct mii_softc *);
101 static void igphy_load_dspcode(struct mii_softc *);
102 #if 0
103 static void igphy_smartspeed_workaround(struct mii_softc *sc);
104 #endif
105 
106 static int	igphymatch(struct device *, struct cfdata *, void *);
107 static void	igphyattach(struct device *, struct device *, void *);
108 
109 CFATTACH_DECL(igphy, sizeof(struct mii_softc),
110     igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
111 
112 static int	igphy_service(struct mii_softc *, struct mii_data *, int);
113 static void	igphy_status(struct mii_softc *);
114 
115 static const struct mii_phy_funcs igphy_funcs = {
116 	igphy_service, igphy_status, igphy_reset,
117 };
118 
119 static const struct mii_phydesc igphys[] = {
120 	{ MII_OUI_yyINTEL,		MII_MODEL_yyINTEL_IGP01E1000,
121 	  MII_STR_yyINTEL_IGP01E1000 },
122 
123 	{0,				0,
124 	 NULL },
125 };
126 
127 static int
128 igphymatch(struct device *parent, struct cfdata *match, void *aux)
129 {
130 	struct mii_attach_args *ma = aux;
131 
132 	if (mii_phy_match(ma, igphys) != NULL)
133 		return 10;
134 
135 	return 0;
136 }
137 
138 static void
139 igphyattach(struct device *parent, struct device *self, void *aux)
140 {
141 	struct mii_softc *sc = (struct mii_softc *)self;
142 	struct mii_attach_args *ma = aux;
143 	struct mii_data *mii = ma->mii_data;
144 	const struct mii_phydesc *mpd;
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 	sc->mii_inst = mii->mii_instance;
151 	sc->mii_phy = ma->mii_phyno;
152 	sc->mii_funcs = &igphy_funcs;
153 	sc->mii_pdata = mii;
154 	sc->mii_flags = ma->mii_flags;
155 	sc->mii_anegticks = 10;
156 
157 	PHY_RESET(sc);
158 
159 	sc->mii_capabilities =
160 	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
161 	if (sc->mii_capabilities & BMSR_EXTSTAT)
162 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
163 	aprint_normal("%s: ", sc->mii_dev.dv_xname);
164 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
165 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
166 		aprint_error("no media present");
167 	else
168 		mii_phy_add_media(sc);
169 	aprint_normal("\n");
170 }
171 
172 static void
173 igphy_load_dspcode(struct mii_softc *sc)
174 {
175 	static const struct {
176 		int reg;
177 		uint16_t val;
178 	} dspcode[] = {
179 		{ 0x1f95, 0x0001 },
180 		{ 0x1f71, 0xbd21 },
181 		{ 0x1f79, 0x0018 },
182 		{ 0x1f30, 0x1600 },
183 		{ 0x1f31, 0x0014 },
184 		{ 0x1f32, 0x161c },
185 		{ 0x1f94, 0x0003 },
186 		{ 0x1f96, 0x003f },
187 		{ 0x2010, 0x0008 },
188 		{ 0, 0 },
189 	};
190 	int i;
191 
192 	delay(10);
193 
194 	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
195 	PHY_WRITE(sc, 0x0000, 0x0140);
196 
197 	delay(5);
198 
199 	for (i = 0; dspcode[i].reg != 0; i++)
200 		IGPHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
201 
202 	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
203 	PHY_WRITE(sc, 0x0000, 0x3300);
204 }
205 
206 static void
207 igphy_reset(struct mii_softc *sc)
208 {
209 	uint16_t fused, fine, coarse;
210 
211 	mii_phy_reset(sc);
212 	igphy_load_dspcode(sc);
213 
214 	fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
215 	if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
216 		fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
217 
218 		fine = fused & ANALOG_FUSE_FINE_MASK;
219 		coarse = fused & ANALOG_FUSE_COARSE_MASK;
220 
221 		if (coarse > ANALOG_FUSE_COARSE_THRESH) {
222 			coarse -= ANALOG_FUSE_COARSE_10;
223 			fine -= ANALOG_FUSE_FINE_1;
224 		} else if (coarse == ANALOG_FUSE_COARSE_THRESH)
225 			fine -= ANALOG_FUSE_FINE_10;
226 
227 		fused = (fused & ANALOG_FUSE_POLY_MASK) |
228 			(fine & ANALOG_FUSE_FINE_MASK) |
229 			(coarse & ANALOG_FUSE_COARSE_MASK);
230 
231 		IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
232 		IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
233 		    ANALOG_FUSE_ENABLE_SW_CONTROL);
234 	}
235 	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
236 }
237 
238 
239 static int
240 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
241 {
242 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
243 	uint16_t reg;
244 
245 	switch (cmd) {
246 	case MII_POLLSTAT:
247 		/*
248 		 * If we're not polling our PHY instance, just return.
249 		 */
250 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
251 			return (0);
252 		break;
253 
254 	case MII_MEDIACHG:
255 		/*
256 		 * If the media indicates a different PHY instance,
257 		 * isolate ourselves.
258 		 */
259 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
260 			reg = PHY_READ(sc, MII_BMCR);
261 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
262 			return (0);
263 		}
264 
265 		/*
266 		 * If the interface is not up, don't do anything.
267 		 */
268 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
269 			break;
270 
271 		mii_phy_setmedia(sc);
272 		break;
273 
274 	case MII_TICK:
275 		/*
276 		 * If we're not currently selected, just return.
277 		 */
278 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
279 			return (0);
280 
281 #if 0
282 		igphy_smartspeed_workaround(sc);
283 #endif
284 
285 		if (mii_phy_tick(sc) == EJUSTRETURN)
286 			return (0);
287 		break;
288 
289 	case MII_DOWN:
290 		mii_phy_down(sc);
291 		return (0);
292 	}
293 
294 	/* Update the media status. */
295 	mii_phy_status(sc);
296 
297 	/* Callback if something changed. */
298 	mii_phy_update(sc, cmd);
299 	return (0);
300 }
301 
302 
303 static void
304 igphy_status(struct mii_softc *sc)
305 {
306 	struct mii_data *mii = sc->mii_pdata;
307 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
308 	uint16_t bmcr, pssr, gtsr, bmsr;
309 
310 	mii->mii_media_status = IFM_AVALID;
311 	mii->mii_media_active = IFM_ETHER;
312 
313 	pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
314 
315 	if (pssr & PSSR_LINK_UP)
316 		mii->mii_media_status |= IFM_ACTIVE;
317 
318 	bmcr = PHY_READ(sc, MII_BMCR);
319 	if (bmcr & BMCR_ISO) {
320 		mii->mii_media_active |= IFM_NONE;
321 		mii->mii_media_status = 0;
322 		return;
323 	}
324 
325 	if (bmcr & BMCR_LOOP)
326 		mii->mii_media_active |= IFM_LOOP;
327 
328 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
329 
330 	/*
331 	 * XXX can't check if the info is valid, no
332 	 * 'negotiation done' bit?
333 	 */
334 	if (bmcr & BMCR_AUTOEN) {
335 		if ((bmsr & BMSR_ACOMP) == 0) {
336 			mii->mii_media_active |= IFM_NONE;
337 			return;
338 		}
339 		switch (pssr & PSSR_SPEED_MASK) {
340 		case PSSR_SPEED_1000MBPS:
341 			mii->mii_media_active |= IFM_1000_T;
342 			gtsr = PHY_READ(sc, MII_100T2SR);
343 			if (gtsr & GTSR_MS_RES)
344 				mii->mii_media_active |= IFM_ETH_MASTER;
345 			break;
346 
347 		case PSSR_SPEED_100MBPS:
348 			mii->mii_media_active |= IFM_100_TX;
349 			break;
350 
351 		case PSSR_SPEED_10MBPS:
352 			mii->mii_media_active |= IFM_10_T;
353 			break;
354 
355 		default:
356 			mii->mii_media_active |= IFM_NONE;
357 			mii->mii_media_status = 0;
358 			return;
359 		}
360 
361 		if (pssr & PSSR_FULL_DUPLEX)
362 			mii->mii_media_active |=
363 			    IFM_FDX | mii_phy_flowstatus(sc);
364 	} else
365 		mii->mii_media_active = ife->ifm_media;
366 }
367 
368 #if 0
369 static void
370 igphy_smartspeed_workaround(struct mii_softc *sc)
371 {
372 	uint16_t reg, gtsr, gctr;
373 
374 	reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
375 	if (!(reg & BMSR_LINK)) {
376 		switch (sc->mii_ticks) {
377 		case 0:
378 			gtsr = PHY_READ(sc, MII_100T2SR);
379 			if (!(gtsr & GTSR_MAN_MS_FLT))
380 				break;
381 			gtsr = PHY_READ(sc, MII_100T2SR);
382 			if (gtsr & GTSR_MAN_MS_FLT) {
383 				gtcr = PHY_READ(sc, MII_100T2CR);
384 				if (gtcr & GTCR_MAN_MS) {
385 					gtcr &= ~GTCR_MAN_MS;
386 					PHY_WRITE(sc, MII_100T2CR,
387 					    gtcr);
388 				}
389 				mii_phy_auto(sc, 0);
390 				sc->mii_ticks++;
391 			}
392 			break;
393 		case IGPHY_TICK_DOWNSHIFT:
394 			gtcr = PHY_READ(sc, MII_100T2CR);
395 			gtcr |= GTCR_MAN_MS;
396 			PHY_WRITE(sc, MII_100T2CR, gtcr);
397 			mii_phy_auto(sc, 0);
398 			break;
399 		default:
400 			break;
401 		}
402 	}
403 }
404 #endif
405