igphy.c revision 1.4 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