igphy.c revision 1.14.4.4 1 1.14.4.4 yamt /* $NetBSD: igphy.c,v 1.14.4.4 2010/03/11 15:03:41 yamt Exp $ */
2 1.1 fvdl
3 1.1 fvdl /*
4 1.1 fvdl * The Intel copyright applies to the analog register setup, and the
5 1.1 fvdl * (currently disabled) SmartSpeed workaround code.
6 1.1 fvdl */
7 1.1 fvdl
8 1.1 fvdl /*******************************************************************************
9 1.1 fvdl
10 1.1 fvdl Copyright (c) 2001-2003, Intel Corporation
11 1.1 fvdl All rights reserved.
12 1.1 fvdl
13 1.1 fvdl Redistribution and use in source and binary forms, with or without
14 1.1 fvdl modification, are permitted provided that the following conditions are met:
15 1.1 fvdl
16 1.1 fvdl 1. Redistributions of source code must retain the above copyright notice,
17 1.1 fvdl this list of conditions and the following disclaimer.
18 1.1 fvdl
19 1.1 fvdl 2. Redistributions in binary form must reproduce the above copyright
20 1.1 fvdl notice, this list of conditions and the following disclaimer in the
21 1.1 fvdl documentation and/or other materials provided with the distribution.
22 1.1 fvdl
23 1.1 fvdl 3. Neither the name of the Intel Corporation nor the names of its
24 1.1 fvdl contributors may be used to endorse or promote products derived from
25 1.1 fvdl this software without specific prior written permission.
26 1.1 fvdl
27 1.1 fvdl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 1.1 fvdl AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 1.1 fvdl IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 1.1 fvdl ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 1.1 fvdl LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 1.1 fvdl CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 1.1 fvdl SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 1.1 fvdl INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 1.1 fvdl CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 1.1 fvdl ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 1.1 fvdl POSSIBILITY OF SUCH DAMAGE.
38 1.1 fvdl
39 1.1 fvdl *******************************************************************************/
40 1.1 fvdl
41 1.1 fvdl
42 1.1 fvdl /*-
43 1.1 fvdl * Copyright (c) 1998, 1999, 2000, 2003 The NetBSD Foundation, Inc.
44 1.1 fvdl * All rights reserved.
45 1.1 fvdl *
46 1.1 fvdl * This code is derived from software contributed to The NetBSD Foundation
47 1.1 fvdl * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
48 1.1 fvdl * NASA Ames Research Center, and by Frank van der Linden.
49 1.1 fvdl *
50 1.1 fvdl * Redistribution and use in source and binary forms, with or without
51 1.1 fvdl * modification, are permitted provided that the following conditions
52 1.1 fvdl * are met:
53 1.1 fvdl * 1. Redistributions of source code must retain the above copyright
54 1.1 fvdl * notice, this list of conditions and the following disclaimer.
55 1.1 fvdl * 2. Redistributions in binary form must reproduce the above copyright
56 1.1 fvdl * notice, this list of conditions and the following disclaimer in the
57 1.1 fvdl * documentation and/or other materials provided with the distribution.
58 1.1 fvdl *
59 1.1 fvdl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
60 1.1 fvdl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61 1.1 fvdl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62 1.1 fvdl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
63 1.1 fvdl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64 1.1 fvdl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65 1.1 fvdl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66 1.1 fvdl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67 1.1 fvdl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68 1.1 fvdl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69 1.1 fvdl * POSSIBILITY OF SUCH DAMAGE.
70 1.1 fvdl */
71 1.1 fvdl
72 1.1 fvdl #include <sys/cdefs.h>
73 1.14.4.4 yamt __KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.14.4.4 2010/03/11 15:03:41 yamt Exp $");
74 1.1 fvdl
75 1.1 fvdl #include "opt_mii.h"
76 1.1 fvdl
77 1.1 fvdl #include <sys/param.h>
78 1.1 fvdl #include <sys/systm.h>
79 1.1 fvdl #include <sys/kernel.h>
80 1.1 fvdl #include <sys/device.h>
81 1.1 fvdl #include <sys/socket.h>
82 1.1 fvdl #include <sys/errno.h>
83 1.1 fvdl
84 1.1 fvdl #include <net/if.h>
85 1.1 fvdl #include <net/if_media.h>
86 1.1 fvdl
87 1.1 fvdl #include <dev/mii/mii.h>
88 1.1 fvdl #include <dev/mii/miivar.h>
89 1.1 fvdl #include <dev/mii/miidevs.h>
90 1.1 fvdl #include <dev/mii/igphyreg.h>
91 1.14.4.4 yamt #include <dev/mii/igphyvar.h>
92 1.14.4.4 yamt #include <dev/pci/if_wmvar.h>
93 1.5 thorpej
94 1.1 fvdl static void igphy_reset(struct mii_softc *);
95 1.1 fvdl static void igphy_load_dspcode(struct mii_softc *);
96 1.14.4.4 yamt static void igphy_load_dspcode_igp3(struct mii_softc *);
97 1.1 fvdl static void igphy_smartspeed_workaround(struct mii_softc *sc);
98 1.1 fvdl
99 1.14.4.1 yamt static int igphymatch(device_t, cfdata_t, void *);
100 1.14.4.1 yamt static void igphyattach(device_t, device_t, void *);
101 1.1 fvdl
102 1.14.4.1 yamt CFATTACH_DECL_NEW(igphy, sizeof(struct igphy_softc),
103 1.1 fvdl igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
104 1.1 fvdl
105 1.4 thorpej static int igphy_service(struct mii_softc *, struct mii_data *, int);
106 1.4 thorpej static void igphy_status(struct mii_softc *);
107 1.1 fvdl
108 1.4 thorpej static const struct mii_phy_funcs igphy_funcs = {
109 1.1 fvdl igphy_service, igphy_status, igphy_reset,
110 1.1 fvdl };
111 1.1 fvdl
112 1.4 thorpej static const struct mii_phydesc igphys[] = {
113 1.1 fvdl { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_IGP01E1000,
114 1.1 fvdl MII_STR_yyINTEL_IGP01E1000 },
115 1.1 fvdl
116 1.14.4.4 yamt { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_I82566,
117 1.14.4.4 yamt MII_STR_yyINTEL_I82566 },
118 1.14.4.4 yamt
119 1.1 fvdl {0, 0,
120 1.1 fvdl NULL },
121 1.1 fvdl };
122 1.1 fvdl
123 1.4 thorpej static int
124 1.14.4.1 yamt igphymatch(device_t parent, cfdata_t match, void *aux)
125 1.1 fvdl {
126 1.1 fvdl struct mii_attach_args *ma = aux;
127 1.1 fvdl
128 1.1 fvdl if (mii_phy_match(ma, igphys) != NULL)
129 1.1 fvdl return 10;
130 1.1 fvdl
131 1.1 fvdl return 0;
132 1.1 fvdl }
133 1.1 fvdl
134 1.4 thorpej static void
135 1.14.4.1 yamt igphyattach(device_t parent, device_t self, void *aux)
136 1.1 fvdl {
137 1.7 thorpej struct mii_softc *sc = device_private(self);
138 1.1 fvdl struct mii_attach_args *ma = aux;
139 1.1 fvdl struct mii_data *mii = ma->mii_data;
140 1.1 fvdl const struct mii_phydesc *mpd;
141 1.14.4.4 yamt struct igphy_softc *igsc = (struct igphy_softc *) sc;
142 1.14.4.4 yamt prop_dictionary_t dict;
143 1.1 fvdl
144 1.1 fvdl mpd = mii_phy_match(ma, igphys);
145 1.1 fvdl aprint_naive(": Media interface\n");
146 1.1 fvdl aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
147 1.1 fvdl
148 1.14.4.4 yamt dict = device_properties(parent);
149 1.14.4.4 yamt if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype))
150 1.14.4.4 yamt aprint_error("WARNING! Failed to get mactype\n");
151 1.14.4.4 yamt if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags))
152 1.14.4.4 yamt aprint_error("WARNING! Failed to get macflags\n");
153 1.14.4.4 yamt
154 1.14.4.1 yamt sc->mii_dev = self;
155 1.1 fvdl sc->mii_inst = mii->mii_instance;
156 1.1 fvdl sc->mii_phy = ma->mii_phyno;
157 1.1 fvdl sc->mii_funcs = &igphy_funcs;
158 1.1 fvdl sc->mii_pdata = mii;
159 1.1 fvdl sc->mii_flags = ma->mii_flags;
160 1.10 christos sc->mii_anegticks = MII_ANEGTICKS_GIGE;
161 1.1 fvdl
162 1.1 fvdl PHY_RESET(sc);
163 1.1 fvdl
164 1.1 fvdl sc->mii_capabilities =
165 1.1 fvdl PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
166 1.1 fvdl if (sc->mii_capabilities & BMSR_EXTSTAT)
167 1.1 fvdl sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
168 1.14.4.1 yamt aprint_normal_dev(self, "");
169 1.1 fvdl if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
170 1.1 fvdl (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
171 1.1 fvdl aprint_error("no media present");
172 1.1 fvdl else
173 1.1 fvdl mii_phy_add_media(sc);
174 1.1 fvdl aprint_normal("\n");
175 1.1 fvdl }
176 1.1 fvdl
177 1.14.4.4 yamt typedef struct {
178 1.14.4.4 yamt int reg;
179 1.14.4.4 yamt uint16_t val;
180 1.14.4.4 yamt } dspcode;
181 1.14.4.4 yamt
182 1.14.4.4 yamt static const dspcode igp1code[] = {
183 1.14.4.4 yamt { 0x1f95, 0x0001 },
184 1.14.4.4 yamt { 0x1f71, 0xbd21 },
185 1.14.4.4 yamt { 0x1f79, 0x0018 },
186 1.14.4.4 yamt { 0x1f30, 0x1600 },
187 1.14.4.4 yamt { 0x1f31, 0x0014 },
188 1.14.4.4 yamt { 0x1f32, 0x161c },
189 1.14.4.4 yamt { 0x1f94, 0x0003 },
190 1.14.4.4 yamt { 0x1f96, 0x003f },
191 1.14.4.4 yamt { 0x2010, 0x0008 },
192 1.14.4.4 yamt { 0, 0 },
193 1.14.4.4 yamt };
194 1.14.4.4 yamt
195 1.14.4.4 yamt static const dspcode igp1code_r2[] = {
196 1.14.4.4 yamt { 0x1f73, 0x0099 },
197 1.14.4.4 yamt { 0, 0 },
198 1.14.4.4 yamt };
199 1.14.4.4 yamt
200 1.14.4.4 yamt static const dspcode igp3code[] = {
201 1.14.4.4 yamt { 0x2f5b, 0x9018},
202 1.14.4.4 yamt { 0x2f52, 0x0000},
203 1.14.4.4 yamt { 0x2fb1, 0x8b24},
204 1.14.4.4 yamt { 0x2fb2, 0xf8f0},
205 1.14.4.4 yamt { 0x2010, 0x10b0},
206 1.14.4.4 yamt { 0x2011, 0x0000},
207 1.14.4.4 yamt { 0x20dd, 0x249a},
208 1.14.4.4 yamt { 0x20de, 0x00d3},
209 1.14.4.4 yamt { 0x28b4, 0x04ce},
210 1.14.4.4 yamt { 0x2f70, 0x29e4},
211 1.14.4.4 yamt { 0x0000, 0x0140},
212 1.14.4.4 yamt { 0x1f30, 0x1606},
213 1.14.4.4 yamt { 0x1f31, 0xb814},
214 1.14.4.4 yamt { 0x1f35, 0x002a},
215 1.14.4.4 yamt { 0x1f3e, 0x0067},
216 1.14.4.4 yamt { 0x1f54, 0x0065},
217 1.14.4.4 yamt { 0x1f55, 0x002a},
218 1.14.4.4 yamt { 0x1f56, 0x002a},
219 1.14.4.4 yamt { 0x1f72, 0x3fb0},
220 1.14.4.4 yamt { 0x1f76, 0xc0ff},
221 1.14.4.4 yamt { 0x1f77, 0x1dec},
222 1.14.4.4 yamt { 0x1f78, 0xf9ef},
223 1.14.4.4 yamt { 0x1f79, 0x0210},
224 1.14.4.4 yamt { 0x1895, 0x0003},
225 1.14.4.4 yamt { 0x1796, 0x0008},
226 1.14.4.4 yamt { 0x1798, 0xd008},
227 1.14.4.4 yamt { 0x1898, 0xd918},
228 1.14.4.4 yamt { 0x187a, 0x0800},
229 1.14.4.4 yamt { 0x0019, 0x008d},
230 1.14.4.4 yamt { 0x001b, 0x2080},
231 1.14.4.4 yamt { 0x0014, 0x0045},
232 1.14.4.4 yamt { 0x0000, 0x1340},
233 1.14.4.4 yamt { 0, 0 },
234 1.14.4.4 yamt };
235 1.14.4.4 yamt
236 1.14.4.4 yamt /* DSP patch for igp1 and igp2 */
237 1.1 fvdl static void
238 1.1 fvdl igphy_load_dspcode(struct mii_softc *sc)
239 1.1 fvdl {
240 1.14.4.4 yamt struct igphy_softc *igsc = (struct igphy_softc *) sc;
241 1.14.4.4 yamt const dspcode *code;
242 1.14.4.4 yamt uint16_t reg;
243 1.1 fvdl int i;
244 1.1 fvdl
245 1.14.4.4 yamt /* This workaround is only for 82541 and 82547 */
246 1.14.4.4 yamt switch (igsc->sc_mactype) {
247 1.14.4.4 yamt case WM_T_82541:
248 1.14.4.4 yamt case WM_T_82547:
249 1.14.4.4 yamt code = igp1code;
250 1.14.4.4 yamt break;
251 1.14.4.4 yamt case WM_T_82541_2:
252 1.14.4.4 yamt case WM_T_82547_2:
253 1.14.4.4 yamt code = igp1code_r2;
254 1.14.4.4 yamt break;
255 1.14.4.4 yamt default:
256 1.14.4.4 yamt return; /* byebye */
257 1.14.4.4 yamt }
258 1.14.4.4 yamt
259 1.14.4.4 yamt /* Delay after phy reset to enable NVM configuration to load */
260 1.14.4.4 yamt delay(20000);
261 1.14.4.4 yamt
262 1.14.4.4 yamt /*
263 1.14.4.4 yamt * Save off the current value of register 0x2F5B to be restored at
264 1.14.4.4 yamt * the end of this routine.
265 1.14.4.4 yamt */
266 1.14.4.4 yamt reg = IGPHY_READ(sc, 0x2f5b);
267 1.14.4.4 yamt
268 1.14.4.4 yamt /* Disabled the PHY transmitter */
269 1.14.4.4 yamt IGPHY_WRITE(sc, 0x2f5b, 0x0003);
270 1.14.4.4 yamt
271 1.14.4.4 yamt delay(20000);
272 1.1 fvdl
273 1.1 fvdl PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
274 1.1 fvdl PHY_WRITE(sc, 0x0000, 0x0140);
275 1.1 fvdl
276 1.14.4.4 yamt delay(5000);
277 1.1 fvdl
278 1.14.4.4 yamt for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
279 1.14.4.4 yamt IGPHY_WRITE(sc, code[i].reg, code[i].val);
280 1.1 fvdl
281 1.1 fvdl PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
282 1.1 fvdl PHY_WRITE(sc, 0x0000, 0x3300);
283 1.14.4.4 yamt
284 1.14.4.4 yamt delay(20000);
285 1.14.4.4 yamt
286 1.14.4.4 yamt /* Now enable the transmitter */
287 1.14.4.4 yamt IGPHY_WRITE(sc, 0x2f5b, reg);
288 1.14.4.4 yamt }
289 1.14.4.4 yamt
290 1.14.4.4 yamt static void
291 1.14.4.4 yamt igphy_load_dspcode_igp3(struct mii_softc *sc)
292 1.14.4.4 yamt {
293 1.14.4.4 yamt const dspcode *code = igp3code;
294 1.14.4.4 yamt int i;
295 1.14.4.4 yamt
296 1.14.4.4 yamt for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
297 1.14.4.4 yamt IGPHY_WRITE(sc, code[i].reg, code[i].val);
298 1.1 fvdl }
299 1.1 fvdl
300 1.1 fvdl static void
301 1.1 fvdl igphy_reset(struct mii_softc *sc)
302 1.1 fvdl {
303 1.14.4.4 yamt struct igphy_softc *igsc = (struct igphy_softc *) sc;
304 1.1 fvdl uint16_t fused, fine, coarse;
305 1.1 fvdl
306 1.1 fvdl mii_phy_reset(sc);
307 1.14.4.4 yamt delay(150);
308 1.14.4.4 yamt
309 1.14.4.4 yamt switch (igsc->sc_mactype) {
310 1.14.4.4 yamt case WM_T_82541:
311 1.14.4.4 yamt case WM_T_82547:
312 1.14.4.4 yamt case WM_T_82541_2:
313 1.14.4.4 yamt case WM_T_82547_2:
314 1.14.4.4 yamt igphy_load_dspcode(sc);
315 1.14.4.4 yamt break;
316 1.14.4.4 yamt case WM_T_ICH8:
317 1.14.4.4 yamt case WM_T_ICH9:
318 1.14.4.4 yamt if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0)
319 1.14.4.4 yamt igphy_load_dspcode_igp3(sc);
320 1.14.4.4 yamt break;
321 1.14.4.4 yamt default: /* Not for ICH10, PCH and 8257[12] */
322 1.14.4.4 yamt break;
323 1.14.4.4 yamt }
324 1.1 fvdl
325 1.14.4.4 yamt if (igsc->sc_mactype == WM_T_82547) {
326 1.14.4.4 yamt fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
327 1.14.4.4 yamt if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
328 1.14.4.4 yamt fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
329 1.14.4.4 yamt
330 1.14.4.4 yamt fine = fused & ANALOG_FUSE_FINE_MASK;
331 1.14.4.4 yamt coarse = fused & ANALOG_FUSE_COARSE_MASK;
332 1.14.4.4 yamt
333 1.14.4.4 yamt if (coarse > ANALOG_FUSE_COARSE_THRESH) {
334 1.14.4.4 yamt coarse -= ANALOG_FUSE_COARSE_10;
335 1.14.4.4 yamt fine -= ANALOG_FUSE_FINE_1;
336 1.14.4.4 yamt } else if (coarse == ANALOG_FUSE_COARSE_THRESH)
337 1.14.4.4 yamt fine -= ANALOG_FUSE_FINE_10;
338 1.14.4.4 yamt
339 1.14.4.4 yamt fused = (fused & ANALOG_FUSE_POLY_MASK) |
340 1.14.4.4 yamt (fine & ANALOG_FUSE_FINE_MASK) |
341 1.14.4.4 yamt (coarse & ANALOG_FUSE_COARSE_MASK);
342 1.14.4.4 yamt
343 1.14.4.4 yamt IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
344 1.14.4.4 yamt IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
345 1.14.4.4 yamt ANALOG_FUSE_ENABLE_SW_CONTROL);
346 1.14.4.4 yamt }
347 1.1 fvdl }
348 1.14.4.4 yamt PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
349 1.1 fvdl }
350 1.1 fvdl
351 1.1 fvdl
352 1.4 thorpej static int
353 1.1 fvdl igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
354 1.1 fvdl {
355 1.1 fvdl struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
356 1.1 fvdl uint16_t reg;
357 1.1 fvdl
358 1.1 fvdl switch (cmd) {
359 1.1 fvdl case MII_POLLSTAT:
360 1.1 fvdl /*
361 1.1 fvdl * If we're not polling our PHY instance, just return.
362 1.1 fvdl */
363 1.1 fvdl if (IFM_INST(ife->ifm_media) != sc->mii_inst)
364 1.1 fvdl return (0);
365 1.1 fvdl break;
366 1.1 fvdl
367 1.1 fvdl case MII_MEDIACHG:
368 1.1 fvdl /*
369 1.1 fvdl * If the media indicates a different PHY instance,
370 1.1 fvdl * isolate ourselves.
371 1.1 fvdl */
372 1.1 fvdl if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
373 1.1 fvdl reg = PHY_READ(sc, MII_BMCR);
374 1.1 fvdl PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
375 1.1 fvdl return (0);
376 1.1 fvdl }
377 1.1 fvdl
378 1.1 fvdl /*
379 1.1 fvdl * If the interface is not up, don't do anything.
380 1.1 fvdl */
381 1.1 fvdl if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
382 1.1 fvdl break;
383 1.1 fvdl
384 1.11 msaitoh reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL);
385 1.11 msaitoh if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
386 1.11 msaitoh reg |= PSCR_AUTO_MDIX;
387 1.11 msaitoh reg &= ~PSCR_FORCE_MDI_MDIX;
388 1.11 msaitoh PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
389 1.11 msaitoh } else {
390 1.11 msaitoh reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
391 1.11 msaitoh PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
392 1.11 msaitoh }
393 1.11 msaitoh
394 1.1 fvdl mii_phy_setmedia(sc);
395 1.1 fvdl break;
396 1.1 fvdl
397 1.1 fvdl case MII_TICK:
398 1.1 fvdl /*
399 1.1 fvdl * If we're not currently selected, just return.
400 1.1 fvdl */
401 1.1 fvdl if (IFM_INST(ife->ifm_media) != sc->mii_inst)
402 1.1 fvdl return (0);
403 1.1 fvdl
404 1.1 fvdl igphy_smartspeed_workaround(sc);
405 1.1 fvdl
406 1.1 fvdl if (mii_phy_tick(sc) == EJUSTRETURN)
407 1.1 fvdl return (0);
408 1.1 fvdl break;
409 1.1 fvdl
410 1.1 fvdl case MII_DOWN:
411 1.1 fvdl mii_phy_down(sc);
412 1.1 fvdl return (0);
413 1.1 fvdl }
414 1.1 fvdl
415 1.1 fvdl /* Update the media status. */
416 1.1 fvdl mii_phy_status(sc);
417 1.1 fvdl
418 1.1 fvdl /* Callback if something changed. */
419 1.1 fvdl mii_phy_update(sc, cmd);
420 1.1 fvdl return (0);
421 1.1 fvdl }
422 1.1 fvdl
423 1.1 fvdl
424 1.4 thorpej static void
425 1.1 fvdl igphy_status(struct mii_softc *sc)
426 1.1 fvdl {
427 1.1 fvdl struct mii_data *mii = sc->mii_pdata;
428 1.1 fvdl struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
429 1.1 fvdl uint16_t bmcr, pssr, gtsr, bmsr;
430 1.1 fvdl
431 1.1 fvdl mii->mii_media_status = IFM_AVALID;
432 1.1 fvdl mii->mii_media_active = IFM_ETHER;
433 1.1 fvdl
434 1.1 fvdl pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
435 1.1 fvdl
436 1.1 fvdl if (pssr & PSSR_LINK_UP)
437 1.1 fvdl mii->mii_media_status |= IFM_ACTIVE;
438 1.1 fvdl
439 1.1 fvdl bmcr = PHY_READ(sc, MII_BMCR);
440 1.1 fvdl if (bmcr & BMCR_ISO) {
441 1.1 fvdl mii->mii_media_active |= IFM_NONE;
442 1.1 fvdl mii->mii_media_status = 0;
443 1.1 fvdl return;
444 1.1 fvdl }
445 1.1 fvdl
446 1.1 fvdl if (bmcr & BMCR_LOOP)
447 1.1 fvdl mii->mii_media_active |= IFM_LOOP;
448 1.1 fvdl
449 1.1 fvdl bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
450 1.1 fvdl
451 1.1 fvdl /*
452 1.1 fvdl * XXX can't check if the info is valid, no
453 1.1 fvdl * 'negotiation done' bit?
454 1.1 fvdl */
455 1.1 fvdl if (bmcr & BMCR_AUTOEN) {
456 1.1 fvdl if ((bmsr & BMSR_ACOMP) == 0) {
457 1.1 fvdl mii->mii_media_active |= IFM_NONE;
458 1.1 fvdl return;
459 1.1 fvdl }
460 1.1 fvdl switch (pssr & PSSR_SPEED_MASK) {
461 1.1 fvdl case PSSR_SPEED_1000MBPS:
462 1.1 fvdl mii->mii_media_active |= IFM_1000_T;
463 1.1 fvdl gtsr = PHY_READ(sc, MII_100T2SR);
464 1.1 fvdl if (gtsr & GTSR_MS_RES)
465 1.1 fvdl mii->mii_media_active |= IFM_ETH_MASTER;
466 1.1 fvdl break;
467 1.1 fvdl
468 1.1 fvdl case PSSR_SPEED_100MBPS:
469 1.1 fvdl mii->mii_media_active |= IFM_100_TX;
470 1.1 fvdl break;
471 1.1 fvdl
472 1.1 fvdl case PSSR_SPEED_10MBPS:
473 1.1 fvdl mii->mii_media_active |= IFM_10_T;
474 1.1 fvdl break;
475 1.1 fvdl
476 1.1 fvdl default:
477 1.1 fvdl mii->mii_media_active |= IFM_NONE;
478 1.1 fvdl mii->mii_media_status = 0;
479 1.1 fvdl return;
480 1.1 fvdl }
481 1.1 fvdl
482 1.1 fvdl if (pssr & PSSR_FULL_DUPLEX)
483 1.2 thorpej mii->mii_media_active |=
484 1.3 thorpej IFM_FDX | mii_phy_flowstatus(sc);
485 1.1 fvdl } else
486 1.1 fvdl mii->mii_media_active = ife->ifm_media;
487 1.1 fvdl }
488 1.1 fvdl
489 1.1 fvdl static void
490 1.1 fvdl igphy_smartspeed_workaround(struct mii_softc *sc)
491 1.1 fvdl {
492 1.5 thorpej struct igphy_softc *igsc = (struct igphy_softc *) sc;
493 1.5 thorpej uint16_t reg, gtsr, gtcr;
494 1.5 thorpej
495 1.14.4.4 yamt
496 1.14.4.4 yamt /* This workaround is only for 82541 and 82547 */
497 1.14.4.4 yamt switch (igsc->sc_mactype) {
498 1.14.4.4 yamt case WM_T_82541:
499 1.14.4.4 yamt case WM_T_82541_2:
500 1.14.4.4 yamt case WM_T_82547:
501 1.14.4.4 yamt case WM_T_82547_2:
502 1.14.4.4 yamt break;
503 1.14.4.4 yamt default:
504 1.14.4.4 yamt /* byebye */
505 1.14.4.4 yamt return;
506 1.14.4.4 yamt }
507 1.14.4.4 yamt
508 1.5 thorpej if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
509 1.5 thorpej return;
510 1.5 thorpej
511 1.5 thorpej /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
512 1.1 fvdl
513 1.1 fvdl reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
514 1.5 thorpej if ((reg & BMSR_LINK) == 0) {
515 1.5 thorpej switch (igsc->sc_smartspeed) {
516 1.1 fvdl case 0:
517 1.1 fvdl gtsr = PHY_READ(sc, MII_100T2SR);
518 1.1 fvdl if (!(gtsr & GTSR_MAN_MS_FLT))
519 1.1 fvdl break;
520 1.1 fvdl gtsr = PHY_READ(sc, MII_100T2SR);
521 1.1 fvdl if (gtsr & GTSR_MAN_MS_FLT) {
522 1.1 fvdl gtcr = PHY_READ(sc, MII_100T2CR);
523 1.1 fvdl if (gtcr & GTCR_MAN_MS) {
524 1.1 fvdl gtcr &= ~GTCR_MAN_MS;
525 1.1 fvdl PHY_WRITE(sc, MII_100T2CR,
526 1.1 fvdl gtcr);
527 1.1 fvdl }
528 1.1 fvdl mii_phy_auto(sc, 0);
529 1.1 fvdl }
530 1.1 fvdl break;
531 1.1 fvdl case IGPHY_TICK_DOWNSHIFT:
532 1.1 fvdl gtcr = PHY_READ(sc, MII_100T2CR);
533 1.1 fvdl gtcr |= GTCR_MAN_MS;
534 1.1 fvdl PHY_WRITE(sc, MII_100T2CR, gtcr);
535 1.1 fvdl mii_phy_auto(sc, 0);
536 1.1 fvdl break;
537 1.1 fvdl default:
538 1.1 fvdl break;
539 1.1 fvdl }
540 1.5 thorpej if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
541 1.5 thorpej igsc->sc_smartspeed = 0;
542 1.5 thorpej } else
543 1.5 thorpej igsc->sc_smartspeed = 0;
544 1.1 fvdl }
545