FreeBSD/Linux Kernel Cross Reference
sys/dev/mii/igphy.c
1 /* $NetBSD: igphy.c,v 1.1.2.1 2005/01/07 11:42:14 jdc 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.1.2.1 2005/01/07 11:42:14 jdc 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 struct igphy_softc {
101 struct mii_softc sc_mii;
102 int sc_smartspeed;
103 };
104
105 static void igphy_reset(struct mii_softc *);
106 static void igphy_load_dspcode(struct mii_softc *);
107 static void igphy_smartspeed_workaround(struct mii_softc *sc);
108
109 int igphymatch(struct device *, struct cfdata *, void *);
110 void igphyattach(struct device *, struct device *, void *);
111
112 CFATTACH_DECL(igphy, sizeof(struct igphy_softc),
113 igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
114
115 int igphy_service(struct mii_softc *, struct mii_data *, int);
116 void igphy_status(struct mii_softc *);
117
118 const struct mii_phy_funcs igphy_funcs = {
119 igphy_service, igphy_status, igphy_reset,
120 };
121
122 const struct mii_phydesc igphys[] = {
123 { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_IGP01E1000,
124 MII_STR_yyINTEL_IGP01E1000 },
125
126 {0, 0,
127 NULL },
128 };
129
130 int
131 igphymatch(struct device *parent, struct cfdata *match, void *aux)
132 {
133 struct mii_attach_args *ma = aux;
134
135 if (mii_phy_match(ma, igphys) != NULL)
136 return 10;
137
138 return 0;
139 }
140
141 void
142 igphyattach(struct device *parent, struct device *self, void *aux)
143 {
144 struct mii_softc *sc = (struct mii_softc *)self;
145 struct mii_attach_args *ma = aux;
146 struct mii_data *mii = ma->mii_data;
147 const struct mii_phydesc *mpd;
148
149 mpd = mii_phy_match(ma, igphys);
150 aprint_naive(": Media interface\n");
151 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
152
153 sc->mii_inst = mii->mii_instance;
154 sc->mii_phy = ma->mii_phyno;
155 sc->mii_funcs = &igphy_funcs;
156 sc->mii_pdata = mii;
157 sc->mii_flags = ma->mii_flags;
158 sc->mii_anegticks = 10;
159
160 PHY_RESET(sc);
161
162 sc->mii_capabilities =
163 PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
164 if (sc->mii_capabilities & BMSR_EXTSTAT)
165 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
166 aprint_normal("%s: ", sc->mii_dev.dv_xname);
167 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
168 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
169 aprint_error("no media present");
170 else
171 mii_phy_add_media(sc);
172 aprint_normal("\n");
173 }
174
175 static void
176 igphy_load_dspcode(struct mii_softc *sc)
177 {
178 static const struct {
179 int reg;
180 uint16_t val;
181 } dspcode[] = {
182 { 0x1f95, 0x0001 },
183 { 0x1f71, 0xbd21 },
184 { 0x1f79, 0x0018 },
185 { 0x1f30, 0x1600 },
186 { 0x1f31, 0x0014 },
187 { 0x1f32, 0x161c },
188 { 0x1f94, 0x0003 },
189 { 0x1f96, 0x003f },
190 { 0x2010, 0x0008 },
191 { 0, 0 },
192 };
193 int i;
194
195 delay(10);
196
197 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
198 PHY_WRITE(sc, 0x0000, 0x0140);
199
200 delay(5);
201
202 for (i = 0; dspcode[i].reg != 0; i++)
203 IGPHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
204
205 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
206 PHY_WRITE(sc, 0x0000, 0x3300);
207 }
208
209 static void
210 igphy_reset(struct mii_softc *sc)
211 {
212 uint16_t fused, fine, coarse;
213
214 mii_phy_reset(sc);
215 igphy_load_dspcode(sc);
216
217 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
218 if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
219 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
220
221 fine = fused & ANALOG_FUSE_FINE_MASK;
222 coarse = fused & ANALOG_FUSE_COARSE_MASK;
223
224 if (coarse > ANALOG_FUSE_COARSE_THRESH) {
225 coarse -= ANALOG_FUSE_COARSE_10;
226 fine -= ANALOG_FUSE_FINE_1;
227 } else if (coarse == ANALOG_FUSE_COARSE_THRESH)
228 fine -= ANALOG_FUSE_FINE_10;
229
230 fused = (fused & ANALOG_FUSE_POLY_MASK) |
231 (fine & ANALOG_FUSE_FINE_MASK) |
232 (coarse & ANALOG_FUSE_COARSE_MASK);
233
234 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
235 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
236 ANALOG_FUSE_ENABLE_SW_CONTROL);
237 }
238 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
239 }
240
241
242 int
243 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
244 {
245 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
246 uint16_t reg;
247
248 switch (cmd) {
249 case MII_POLLSTAT:
250 /*
251 * If we're not polling our PHY instance, just return.
252 */
253 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
254 return (0);
255 break;
256
257 case MII_MEDIACHG:
258 /*
259 * If the media indicates a different PHY instance,
260 * isolate ourselves.
261 */
262 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
263 reg = PHY_READ(sc, MII_BMCR);
264 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
265 return (0);
266 }
267
268 /*
269 * If the interface is not up, don't do anything.
270 */
271 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
272 break;
273
274 mii_phy_setmedia(sc);
275 break;
276
277 case MII_TICK:
278 /*
279 * If we're not currently selected, just return.
280 */
281 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
282 return (0);
283
284 igphy_smartspeed_workaround(sc);
285
286 if (mii_phy_tick(sc) == EJUSTRETURN)
287 return (0);
288 break;
289
290 case MII_DOWN:
291 mii_phy_down(sc);
292 return (0);
293 }
294
295 /* Update the media status. */
296 mii_phy_status(sc);
297
298 /* Callback if something changed. */
299 mii_phy_update(sc, cmd);
300 return (0);
301 }
302
303
304 void
305 igphy_status(struct mii_softc *sc)
306 {
307 struct mii_data *mii = sc->mii_pdata;
308 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
309 uint16_t bmcr, pssr, gtsr, bmsr;
310
311 mii->mii_media_status = IFM_AVALID;
312 mii->mii_media_active = IFM_ETHER;
313
314 pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
315
316 if (pssr & PSSR_LINK_UP)
317 mii->mii_media_status |= IFM_ACTIVE;
318
319 bmcr = PHY_READ(sc, MII_BMCR);
320 if (bmcr & BMCR_ISO) {
321 mii->mii_media_active |= IFM_NONE;
322 mii->mii_media_status = 0;
323 return;
324 }
325
326 if (bmcr & BMCR_LOOP)
327 mii->mii_media_active |= IFM_LOOP;
328
329 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
330
331 /*
332 * XXX can't check if the info is valid, no
333 * 'negotiation done' bit?
334 */
335 if (bmcr & BMCR_AUTOEN) {
336 if ((bmsr & BMSR_ACOMP) == 0) {
337 mii->mii_media_active |= IFM_NONE;
338 return;
339 }
340 switch (pssr & PSSR_SPEED_MASK) {
341 case PSSR_SPEED_1000MBPS:
342 mii->mii_media_active |= IFM_1000_T;
343 gtsr = PHY_READ(sc, MII_100T2SR);
344 if (gtsr & GTSR_MS_RES)
345 mii->mii_media_active |= IFM_ETH_MASTER;
346 break;
347
348 case PSSR_SPEED_100MBPS:
349 mii->mii_media_active |= IFM_100_TX;
350 break;
351
352 case PSSR_SPEED_10MBPS:
353 mii->mii_media_active |= IFM_10_T;
354 break;
355
356 default:
357 mii->mii_media_active |= IFM_NONE;
358 mii->mii_media_status = 0;
359 return;
360 }
361
362 if (pssr & PSSR_FULL_DUPLEX)
363 mii->mii_media_active |= IFM_FDX;
364 } else
365 mii->mii_media_active = ife->ifm_media;
366 }
367
368 static void
369 igphy_smartspeed_workaround(struct mii_softc *sc)
370 {
371 struct igphy_softc *igsc = (struct igphy_softc *) sc;
372 uint16_t reg, gtsr, gtcr;
373
374 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
375 return;
376
377 /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
378
379 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
380 if ((reg & BMSR_LINK) == 0) {
381 switch (igsc->sc_smartspeed) {
382 case 0:
383 gtsr = PHY_READ(sc, MII_100T2SR);
384 if (!(gtsr & GTSR_MAN_MS_FLT))
385 break;
386 gtsr = PHY_READ(sc, MII_100T2SR);
387 if (gtsr & GTSR_MAN_MS_FLT) {
388 gtcr = PHY_READ(sc, MII_100T2CR);
389 if (gtcr & GTCR_MAN_MS) {
390 gtcr &= ~GTCR_MAN_MS;
391 PHY_WRITE(sc, MII_100T2CR,
392 gtcr);
393 }
394 mii_phy_auto(sc, 0);
395 }
396 break;
397 case IGPHY_TICK_DOWNSHIFT:
398 gtcr = PHY_READ(sc, MII_100T2CR);
399 gtcr |= GTCR_MAN_MS;
400 PHY_WRITE(sc, MII_100T2CR, gtcr);
401 mii_phy_auto(sc, 0);
402 break;
403 default:
404 break;
405 }
406 if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
407 igsc->sc_smartspeed = 0;
408 } else
409 igsc->sc_smartspeed = 0;
410 }
Cache object: 2d55f5a034f0dcb81061a5ba97358cfb
|