xref: /openbsd-src/sys/dev/mii/brgphy.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: brgphy.c,v 1.105 2015/07/19 06:28:12 yuo Exp $	*/
2 
3 /*
4  * Copyright (c) 2000
5  *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Bill Paul.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $FreeBSD: brgphy.c,v 1.8 2002/03/22 06:38:52 wpaul Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/socket.h>
42 #include <sys/errno.h>
43 
44 #include <machine/bus.h>
45 
46 #include <net/if.h>
47 #include <net/if_media.h>
48 
49 #include <netinet/in.h>
50 #include <netinet/if_ether.h>
51 
52 #include <dev/pci/pcivar.h>
53 
54 #include <dev/mii/mii.h>
55 #include <dev/mii/miivar.h>
56 #include <dev/mii/miidevs.h>
57 
58 #include <dev/mii/brgphyreg.h>
59 
60 #include <dev/pci/if_bgereg.h>
61 #include <dev/pci/if_bnxreg.h>
62 
63 int brgphy_probe(struct device *, void *, void *);
64 void brgphy_attach(struct device *, struct device *, void *);
65 
66 struct cfattach brgphy_ca = {
67 	sizeof(struct mii_softc), brgphy_probe, brgphy_attach, mii_phy_detach
68 };
69 
70 struct cfdriver brgphy_cd = {
71 	NULL, "brgphy", DV_DULL
72 };
73 
74 int	brgphy_service(struct mii_softc *, struct mii_data *, int);
75 void	brgphy_copper_status(struct mii_softc *);
76 void	brgphy_fiber_status(struct mii_softc *);
77 void	brgphy_5708s_status(struct mii_softc *);
78 void	brgphy_5709s_status(struct mii_softc *);
79 int	brgphy_mii_phy_auto(struct mii_softc *);
80 void	brgphy_loop(struct mii_softc *);
81 void	brgphy_reset(struct mii_softc *);
82 void	brgphy_reset_bge(struct mii_softc *);
83 void	brgphy_reset_bnx(struct mii_softc *);
84 void	brgphy_bcm5401_dspcode(struct mii_softc *);
85 void	brgphy_bcm5411_dspcode(struct mii_softc *);
86 void	brgphy_bcm5421_dspcode(struct mii_softc *);
87 void	brgphy_bcm54k2_dspcode(struct mii_softc *);
88 void	brgphy_adc_bug(struct mii_softc *);
89 void	brgphy_5704_a0_bug(struct mii_softc *);
90 void	brgphy_ber_bug(struct mii_softc *);
91 void	brgphy_crc_bug(struct mii_softc *);
92 void	brgphy_disable_early_dac(struct mii_softc *sc);
93 void	brgphy_jumbo_settings(struct mii_softc *);
94 void	brgphy_eth_wirespeed(struct mii_softc *);
95 
96 const struct mii_phy_funcs brgphy_copper_funcs = {
97 	brgphy_service, brgphy_copper_status, brgphy_reset,
98 };
99 
100 const struct mii_phy_funcs brgphy_fiber_funcs = {
101 	brgphy_service, brgphy_fiber_status, brgphy_reset,
102 };
103 
104 const struct mii_phy_funcs brgphy_5708s_funcs = {
105 	brgphy_service, brgphy_5708s_status, brgphy_reset,
106 };
107 
108 const struct mii_phy_funcs brgphy_5709s_funcs = {
109 	brgphy_service, brgphy_5709s_status, brgphy_reset,
110 };
111 
112 static const struct mii_phydesc brgphys[] = {
113 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5400,
114 	  MII_STR_xxBROADCOM_BCM5400 },
115 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5401,
116 	  MII_STR_xxBROADCOM_BCM5401 },
117 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5411,
118 	  MII_STR_xxBROADCOM_BCM5411 },
119 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5421,
120 	  MII_STR_xxBROADCOM_BCM5421 },
121 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM54K2,
122 	  MII_STR_xxBROADCOM_BCM54K2 },
123 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5461,
124 	  MII_STR_xxBROADCOM_BCM5461 },
125 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5462,
126 	  MII_STR_xxBROADCOM_BCM5462 },
127 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5464,
128 	  MII_STR_xxBROADCOM_BCM5464 },
129 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5701,
130 	  MII_STR_xxBROADCOM_BCM5701 },
131 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5703,
132 	  MII_STR_xxBROADCOM_BCM5703 },
133 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5704,
134 	  MII_STR_xxBROADCOM_BCM5704 },
135 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5705,
136 	  MII_STR_xxBROADCOM_BCM5705 },
137 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5714,
138 	  MII_STR_xxBROADCOM_BCM5714 },
139 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5750,
140 	  MII_STR_xxBROADCOM_BCM5750 },
141 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5752,
142 	  MII_STR_xxBROADCOM_BCM5752 },
143 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5780,
144 	  MII_STR_xxBROADCOM_BCM5780 },
145 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM54XX,
146 	  MII_STR_xxBROADCOM2_BCM54XX },
147 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5481,
148 	  MII_STR_xxBROADCOM2_BCM5481 },
149 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5482,
150 	  MII_STR_xxBROADCOM2_BCM5482 },
151 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5722,
152 	  MII_STR_xxBROADCOM2_BCM5722 },
153 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5755,
154 	  MII_STR_xxBROADCOM2_BCM5755 },
155 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5761,
156 	  MII_STR_xxBROADCOM2_BCM5761 },
157 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5784,
158 	  MII_STR_xxBROADCOM2_BCM5784 },
159 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5787,
160 	  MII_STR_xxBROADCOM2_BCM5787 },
161 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5706,
162 	  MII_STR_xxBROADCOM_BCM5706 },
163 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5708C,
164 	  MII_STR_xxBROADCOM_BCM5708C },
165 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5708S,
166 	  MII_STR_xxBROADCOM2_BCM5708S },
167 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5709C,
168 	  MII_STR_xxBROADCOM2_BCM5709C },
169 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5709S,
170 	  MII_STR_xxBROADCOM2_BCM5709S },
171 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5709CAX,
172 	  MII_STR_xxBROADCOM2_BCM5709CAX },
173 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM5717C,
174 	  MII_STR_xxBROADCOM3_BCM5717C },
175 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM5719C,
176 	  MII_STR_xxBROADCOM3_BCM5719C },
177 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM5720C,
178 	  MII_STR_xxBROADCOM3_BCM5720C },
179 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM57765,
180 	  MII_STR_xxBROADCOM3_BCM57765 },
181 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM57780,
182 	  MII_STR_xxBROADCOM3_BCM57780 },
183 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5906,
184 	  MII_STR_BROADCOM2_BCM5906 },
185 
186 	{ 0,				0,
187 	  NULL },
188 };
189 
190 int
191 brgphy_probe(struct device *parent, void *match, void *aux)
192 {
193 	struct mii_attach_args *ma = aux;
194 
195 	if (mii_phy_match(ma, brgphys) != NULL)
196 		return (10);
197 
198 	return (0);
199 }
200 
201 void
202 brgphy_attach(struct device *parent, struct device *self, void *aux)
203 {
204 	struct mii_softc *sc = (struct mii_softc *)self;
205 	struct bge_softc *bge_sc = NULL;
206 	struct bnx_softc *bnx_sc = NULL;
207 	struct mii_attach_args *ma = aux;
208 	struct mii_data *mii = ma->mii_data;
209 	const struct mii_phydesc *mpd;
210 	char *devname;
211 	int fast_ether = 0;
212 
213 	devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name;
214 
215 	if (strcmp(devname, "bge") == 0) {
216 		bge_sc = mii->mii_ifp->if_softc;
217 
218 		if (bge_sc->bge_phy_flags & BGE_PHY_10_100_ONLY)
219 			fast_ether = 1;
220 	} else if (strcmp(devname, "bnx") == 0)
221 		bnx_sc = mii->mii_ifp->if_softc;
222 
223 	mpd = mii_phy_match(ma, brgphys);
224 	printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
225 
226 	sc->mii_inst = mii->mii_instance;
227 	sc->mii_phy = ma->mii_phyno;
228 	sc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
229 	sc->mii_model = MII_MODEL(ma->mii_id2);
230 	sc->mii_rev = MII_REV(ma->mii_id2);
231 	sc->mii_pdata = mii;
232 	sc->mii_flags = ma->mii_flags;
233 
234 	if (sc->mii_flags & MIIF_HAVEFIBER) {
235 		if (strcmp(devname, "bnx") == 0) {
236 			if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5708)
237 				sc->mii_funcs = &brgphy_5708s_funcs;
238 			else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709)
239 				sc->mii_funcs = &brgphy_5709s_funcs;
240 			else
241 				sc->mii_funcs = &brgphy_fiber_funcs;
242 		} else
243 			sc->mii_funcs = &brgphy_fiber_funcs;
244 	} else
245 		sc->mii_funcs = &brgphy_copper_funcs;
246 
247 	if (fast_ether == 1)
248 		sc->mii_anegticks = MII_ANEGTICKS;
249 	else
250 		sc->mii_anegticks = MII_ANEGTICKS_GIGE;
251 
252 	sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
253 
254 	PHY_RESET(sc);
255 
256 	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
257 	if (sc->mii_capabilities & BMSR_EXTSTAT)
258 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
259 
260 #define ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
261 
262 	/* Create an instance of Ethernet media. */
263 	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), BMCR_ISO);
264 
265 	/* Add the supported media types */
266 	if (sc->mii_flags & MIIF_HAVEFIBER) {
267 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
268 		    BMCR_S1000 | BMCR_FDX);
269 
270 		/*
271 		 * 2.5Gb support is a software enabled feature on the
272 		 * BCM5708S and BCM5709S controllers.
273 		 */
274 		if (strcmp(devname, "bnx") == 0) {
275 			if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG)
276 				ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX,
277 				    IFM_FDX, sc->mii_inst), 0);
278 		}
279 	} else {
280 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
281 		    BMCR_S10);
282 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
283 		    BMCR_S10 | BMCR_FDX);
284 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
285 		    BMCR_S100);
286 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
287 		    BMCR_S100 | BMCR_FDX);
288 
289 		if (fast_ether == 0) {
290 			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
291 			    sc->mii_inst), BMCR_S1000);
292 			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
293 			    sc->mii_inst), BMCR_S1000 | BMCR_FDX);
294 		}
295 	}
296 
297 	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
298 
299 #undef ADD
300 }
301 
302 int
303 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
304 {
305 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
306 	int reg, speed = 0, gig;
307 
308 	if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
309 		return (ENXIO);
310 
311 	switch (cmd) {
312 	case MII_POLLSTAT:
313 		/*
314 		 * If we're not polling our PHY instance, just return.
315 		 */
316 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
317 			return (0);
318 		break;
319 
320 	case MII_MEDIACHG:
321 		/*
322 		 * If the media indicates a different PHY instance,
323 		 * isolate ourselves.
324 		 */
325 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
326 			reg = PHY_READ(sc, MII_BMCR);
327 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
328 			return (0);
329 		}
330 
331 		/*
332 		 * If the interface is not up, don't do anything.
333 		 */
334 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
335 			break;
336 
337 		PHY_RESET(sc); /* XXX hardware bug work-around */
338 
339 		switch (IFM_SUBTYPE(ife->ifm_media)) {
340 		case IFM_AUTO:
341 			(void) brgphy_mii_phy_auto(sc);
342 			break;
343 		case IFM_2500_SX:
344 			speed = BRGPHY_5708S_BMCR_2500;
345 			goto setit;
346 		case IFM_1000_T:
347 			speed = BMCR_S1000;
348 			goto setit;
349 		case IFM_100_TX:
350 			speed = BMCR_S100;
351 			goto setit;
352 		case IFM_10_T:
353 			speed = BMCR_S10;
354 setit:
355 			brgphy_loop(sc);
356 			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
357 				speed |= BMCR_FDX;
358 				gig = GTCR_ADV_1000TFDX;
359 			} else {
360 				gig = GTCR_ADV_1000THDX;
361 			}
362 
363 			PHY_WRITE(sc, MII_100T2CR, 0);
364 			PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
365 			PHY_WRITE(sc, MII_BMCR, speed);
366 
367 			if ((IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) &&
368 			    (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_SX) &&
369 			    (IFM_SUBTYPE(ife->ifm_media) != IFM_2500_SX))
370 				break;
371 
372 			PHY_WRITE(sc, MII_100T2CR, gig);
373 			PHY_WRITE(sc, MII_BMCR,
374 			    speed|BMCR_AUTOEN|BMCR_STARTNEG);
375 
376 			if (sc->mii_oui != MII_OUI_xxBROADCOM ||
377 			    sc->mii_model != MII_MODEL_xxBROADCOM_BCM5701)
378  				break;
379 
380 			if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
381 				gig |= GTCR_MAN_MS|GTCR_ADV_MS;
382 			PHY_WRITE(sc, MII_100T2CR, gig);
383 			break;
384 		default:
385 			return (EINVAL);
386 		}
387 		break;
388 
389 	case MII_TICK:
390 		/*
391 		 * If we're not currently selected, just return.
392 		 */
393 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
394 			return (0);
395 
396 		/*
397 		 * Is the interface even up?
398 		 */
399 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
400 			return (0);
401 
402 		/*
403 		 * Only used for autonegotiation.
404 		 */
405 		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
406 			break;
407 
408 		/*
409 		 * Check to see if we have link.  If we do, we don't
410 		 * need to restart the autonegotiation process.  Read
411 		 * the BMSR twice in case it's latched.
412 		 */
413 		reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
414 		if (reg & BMSR_LINK) {
415 			sc->mii_ticks = 0;	/* Reset autoneg timer. */
416 			break;
417 		}
418 
419 		/*
420 		 * Only retry autonegotiation every mii_anegticks seconds.
421 		 */
422 		if (++sc->mii_ticks <= sc->mii_anegticks)
423 			break;
424 
425 		sc->mii_ticks = 0;
426 		brgphy_mii_phy_auto(sc);
427 		break;
428 	}
429 
430 	/* Update the media status. */
431 	mii_phy_status(sc);
432 
433 	/*
434 	 * Callback if something changed. Note that we need to poke the DSP on
435 	 * the Broadcom PHYs if the media changes.
436 	 */
437 	if (sc->mii_media_active != mii->mii_media_active ||
438 	    sc->mii_media_status != mii->mii_media_status ||
439 	    cmd == MII_MEDIACHG) {
440 		switch (sc->mii_oui) {
441 		case MII_OUI_BROADCOM:
442 			switch (sc->mii_model) {
443 			case MII_MODEL_BROADCOM_BCM5400:
444 				brgphy_bcm5401_dspcode(sc);
445 				break;
446 			}
447 			break;
448 		case MII_OUI_xxBROADCOM:
449 			switch (sc->mii_model) {
450 			case MII_MODEL_xxBROADCOM_BCM5401:
451 				if (sc->mii_rev == 1 || sc->mii_rev == 3)
452 					brgphy_bcm5401_dspcode(sc);
453 				break;
454 			case MII_MODEL_xxBROADCOM_BCM5411:
455 				brgphy_bcm5411_dspcode(sc);
456 				break;
457 			}
458 			break;
459 		}
460 	}
461 
462 	/* Callback if something changed. */
463 	mii_phy_update(sc, cmd);
464 
465 	return (0);
466 }
467 
468 void
469 brgphy_copper_status(struct mii_softc *sc)
470 {
471 	struct mii_data *mii = sc->mii_pdata;
472 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
473 	int bmcr, bmsr;
474 
475 	mii->mii_media_status = IFM_AVALID;
476 	mii->mii_media_active = IFM_ETHER;
477 
478 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
479 	if (bmsr & BMSR_LINK)
480 		mii->mii_media_status |= IFM_ACTIVE;
481 
482 	bmcr = PHY_READ(sc, MII_BMCR);
483 	if (bmcr & BMCR_LOOP)
484 		mii->mii_media_active |= IFM_LOOP;
485 
486 	if (bmcr & BMCR_AUTOEN) {
487 		int auxsts;
488 
489 		if ((bmsr & BMSR_ACOMP) == 0) {
490 			/* Erg, still trying, I guess... */
491 			mii->mii_media_active |= IFM_NONE;
492 			return;
493 		}
494 
495 		auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS);
496 
497 		switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
498 		case BRGPHY_RES_1000FD:
499 			mii->mii_media_active |= IFM_1000_T | IFM_FDX;
500 			break;
501 		case BRGPHY_RES_1000HD:
502 			mii->mii_media_active |= IFM_1000_T | IFM_HDX;
503 			break;
504 		case BRGPHY_RES_100FD:
505 			mii->mii_media_active |= IFM_100_TX | IFM_FDX;
506 			break;
507 		case BRGPHY_RES_100T4:
508 			mii->mii_media_active |= IFM_100_T4 | IFM_HDX;
509 			break;
510 		case BRGPHY_RES_100HD:
511 			mii->mii_media_active |= IFM_100_TX | IFM_HDX;
512 			break;
513 		case BRGPHY_RES_10FD:
514 			mii->mii_media_active |= IFM_10_T | IFM_FDX;
515 			break;
516 		case BRGPHY_RES_10HD:
517 			mii->mii_media_active |= IFM_10_T | IFM_HDX;
518 			break;
519 		default:
520 			if (sc->mii_oui == MII_OUI_BROADCOM2 &&
521 			    sc->mii_model == MII_MODEL_BROADCOM2_BCM5906) {
522 				mii->mii_media_active |= (auxsts &
523 				    BRGPHY_RES_100) ? IFM_100_TX : IFM_10_T;
524 				mii->mii_media_active |= (auxsts &
525 				    BRGPHY_RES_FULL) ? IFM_FDX : IFM_HDX;
526 				break;
527 			}
528 			mii->mii_media_active |= IFM_NONE;
529 			return;
530 		}
531 
532 		if (mii->mii_media_active & IFM_FDX)
533 			mii->mii_media_active |= mii_phy_flowstatus(sc);
534 
535 		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
536 			if (PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES)
537 				mii->mii_media_active |= IFM_ETH_MASTER;
538 		}
539 	} else
540 		mii->mii_media_active = ife->ifm_media;
541 }
542 
543 void
544 brgphy_fiber_status(struct mii_softc *sc)
545 {
546 	struct mii_data *mii = sc->mii_pdata;
547 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
548 	int bmcr, bmsr;
549 
550 	mii->mii_media_status = IFM_AVALID;
551 	mii->mii_media_active = IFM_ETHER;
552 
553 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
554 	if (bmsr & BMSR_LINK)
555 		mii->mii_media_status |= IFM_ACTIVE;
556 
557 	bmcr = PHY_READ(sc, MII_BMCR);
558 	if (bmcr & BMCR_LOOP)
559 		mii->mii_media_active |= IFM_LOOP;
560 
561 	if (bmcr & BMCR_AUTOEN) {
562 		int val;
563 
564 		if ((bmsr & BMSR_ACOMP) == 0) {
565 			/* Erg, still trying, I guess... */
566 			mii->mii_media_active |= IFM_NONE;
567 			return;
568 		}
569 
570 		mii->mii_media_active |= IFM_1000_SX;
571 
572 		val = PHY_READ(sc, MII_ANAR) & PHY_READ(sc, MII_ANLPAR);
573 
574 		if (val & ANAR_X_FD)
575 			mii->mii_media_active |= IFM_FDX;
576 		else
577 			mii->mii_media_active |= IFM_HDX;
578 
579 		if (mii->mii_media_active & IFM_FDX)
580 			mii->mii_media_active |= mii_phy_flowstatus(sc);
581 	} else
582 		mii->mii_media_active = ife->ifm_media;
583 }
584 
585 void
586 brgphy_5708s_status(struct mii_softc *sc)
587 {
588 	struct mii_data *mii = sc->mii_pdata;
589 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
590 	int bmcr, bmsr;
591 
592 	mii->mii_media_status = IFM_AVALID;
593 	mii->mii_media_active = IFM_ETHER;
594 
595 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
596 	if (bmsr & BMSR_LINK)
597 		mii->mii_media_status |= IFM_ACTIVE;
598 
599 	bmcr = PHY_READ(sc, MII_BMCR);
600 	if (bmcr & BMCR_LOOP)
601 		mii->mii_media_active |= IFM_LOOP;
602 
603 	if (bmcr & BMCR_AUTOEN) {
604 		int xstat;
605 
606 		if ((bmsr & BMSR_ACOMP) == 0) {
607 			/* Erg, still trying, I guess... */
608 			mii->mii_media_active |= IFM_NONE;
609 			return;
610 		}
611 
612 		PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
613 		    BRGPHY_5708S_DIG_PG0);
614 
615 		xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1);
616 
617 		switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) {
618 		case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10:
619 			mii->mii_media_active |= IFM_10_FL;
620 			break;
621 		case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100:
622 			mii->mii_media_active |= IFM_100_FX;
623 			break;
624 		case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G:
625 			mii->mii_media_active |= IFM_1000_SX;
626 			break;
627 		case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G:
628 			mii->mii_media_active |= IFM_2500_SX;
629 			break;
630 		}
631 
632 		if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX)
633 			mii->mii_media_active |= IFM_FDX;
634 		else
635 			mii->mii_media_active |= IFM_HDX;
636 
637 		if (mii->mii_media_active & IFM_FDX) {
638 			if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_TX_PAUSE)
639 				mii->mii_media_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
640 			if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_RX_PAUSE)
641 				mii->mii_media_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
642 		}
643 	} else
644 		mii->mii_media_active = ife->ifm_media;
645 }
646 
647 void
648 brgphy_5709s_status(struct mii_softc *sc)
649 {
650 	struct mii_data *mii = sc->mii_pdata;
651 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
652 	int bmcr, bmsr;
653 
654 	mii->mii_media_status = IFM_AVALID;
655 	mii->mii_media_active = IFM_ETHER;
656 
657         bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
658         if (bmsr & BMSR_LINK)
659                 mii->mii_media_status |= IFM_ACTIVE;
660 
661         bmcr = PHY_READ(sc, MII_BMCR);
662         if (bmcr & BMCR_LOOP)
663                 mii->mii_media_active |= IFM_LOOP;
664 
665         if (bmcr & BMCR_AUTOEN) {
666                 int xstat;
667 
668                 if ((bmsr & BMSR_ACOMP) == 0) {
669                         /* Erg, still trying, I guess... */
670                         mii->mii_media_active |= IFM_NONE;
671                         return;
672                 }
673 
674                 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
675                     BRGPHY_BLOCK_ADDR_GP_STATUS);
676 
677                 xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS);
678 
679                 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
680                     BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
681 
682                 switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) {
683                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10:
684                         mii->mii_media_active |= IFM_10_FL;
685                         break;
686                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100:
687                         mii->mii_media_active |= IFM_100_FX;
688                         break;
689                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G:
690                         mii->mii_media_active |= IFM_1000_SX;
691                         break;
692                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G:
693                         mii->mii_media_active |= IFM_2500_SX;
694                         break;
695                 }
696 
697                 if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX)
698                         mii->mii_media_active |= IFM_FDX;
699                 else
700                         mii->mii_media_active |= IFM_HDX;
701 
702 		if (mii->mii_media_active & IFM_FDX)
703 			mii->mii_media_active |= mii_phy_flowstatus(sc);
704 	} else
705 		mii->mii_media_active = ife->ifm_media;
706 }
707 
708 int
709 brgphy_mii_phy_auto(struct mii_softc *sc)
710 {
711 	int anar, ktcr = 0;
712 
713 	PHY_RESET(sc);
714 
715 	if (sc->mii_flags & MIIF_HAVEFIBER) {
716 		anar = ANAR_X_FD | ANAR_X_HD;
717 		if (sc->mii_flags & MIIF_DOPAUSE)
718 			anar |= ANAR_X_PAUSE_TOWARDS;
719 		PHY_WRITE(sc, MII_ANAR, anar);
720 	} else {
721 		anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
722 		if (sc->mii_flags & MIIF_DOPAUSE)
723 			anar |= ANAR_PAUSE_ASYM | ANAR_FC;
724 		PHY_WRITE(sc, MII_ANAR, anar);
725 	}
726 
727 	/* Enable speed in the 1000baseT control register */
728 	ktcr = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
729 	if (sc->mii_oui == MII_OUI_xxBROADCOM &&
730 	    sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701)
731 		ktcr |= GTCR_MAN_MS | GTCR_ADV_MS;
732 	PHY_WRITE(sc, MII_100T2CR, ktcr);
733 	ktcr = PHY_READ(sc, MII_100T2CR);
734 
735 	/* Start autonegotiation */
736 	PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
737 	PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
738 
739 	return (EJUSTRETURN);
740 }
741 
742 /* Enable loopback to force the link down. */
743 void
744 brgphy_loop(struct mii_softc *sc)
745 {
746 	u_int32_t bmsr;
747 	int i;
748 
749 	PHY_WRITE(sc, MII_BMCR, BMCR_LOOP);
750 	for (i = 0; i < 15000; i++) {
751 		bmsr = PHY_READ(sc, MII_BMSR);
752 		if (!(bmsr & BMSR_LINK))
753 			break;
754 		DELAY(10);
755 	}
756 }
757 
758 void
759 brgphy_reset(struct mii_softc *sc)
760 {
761 	char *devname;
762 
763 	devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name;
764 
765 	mii_phy_reset(sc);
766 
767 	switch (sc->mii_oui) {
768 	case MII_OUI_BROADCOM:
769 		switch (sc->mii_model) {
770 		case MII_MODEL_BROADCOM_BCM5400:
771 			brgphy_bcm5401_dspcode(sc);
772 			break;
773 		case MII_MODEL_BROADCOM_BCM5401:
774 			if (sc->mii_rev == 1 || sc->mii_rev == 3)
775 				brgphy_bcm5401_dspcode(sc);
776 			break;
777 		case MII_MODEL_BROADCOM_BCM5411:
778 			brgphy_bcm5411_dspcode(sc);
779 			break;
780 		}
781 		break;
782 	case MII_OUI_xxBROADCOM:
783 		switch (sc->mii_model) {
784 		case MII_MODEL_xxBROADCOM_BCM5421:
785 			brgphy_bcm5421_dspcode(sc);
786 			break;
787 		case MII_MODEL_xxBROADCOM_BCM54K2:
788 			brgphy_bcm54k2_dspcode(sc);
789 			break;
790 		}
791 		break;
792 	}
793 
794 	/* Handle any bge (NetXtreme/NetLink) workarounds. */
795 	if (strcmp(devname, "bge") == 0)
796 		brgphy_reset_bge(sc);
797 	/* Handle any bnx (NetXtreme II) workarounds. */
798 	else if (strcmp(devname, "bnx") == 0)
799 		brgphy_reset_bnx(sc);
800 }
801 
802 void
803 brgphy_reset_bge(struct mii_softc *sc)
804 {
805 	struct bge_softc *bge_sc = sc->mii_pdata->mii_ifp->if_softc;
806 
807 	if (sc->mii_flags & MIIF_HAVEFIBER)
808 		return;
809 
810 	switch (sc->mii_oui) {
811 	case MII_OUI_xxBROADCOM3:
812 		switch (sc->mii_model) {
813 		case MII_MODEL_xxBROADCOM3_BCM5717C:
814 		case MII_MODEL_xxBROADCOM3_BCM5719C:
815 		case MII_MODEL_xxBROADCOM3_BCM5720C:
816 		case MII_MODEL_xxBROADCOM3_BCM57765:
817 			return;
818 		}
819 	}
820 
821 	if (bge_sc->bge_phy_flags & BGE_PHY_ADC_BUG)
822 		brgphy_adc_bug(sc);
823 	if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG)
824 		brgphy_5704_a0_bug(sc);
825 	if (bge_sc->bge_phy_flags & BGE_PHY_BER_BUG)
826 		brgphy_ber_bug(sc);
827 	else if (bge_sc->bge_phy_flags & BGE_PHY_JITTER_BUG) {
828 	    PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00);
829 		PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
830 
831 		if (bge_sc->bge_phy_flags & BGE_PHY_ADJUST_TRIM) {
832 			PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x110b);
833 			PHY_WRITE(sc, BRGPHY_TEST1, BRGPHY_TEST1_TRIM_EN |
834 			    0x4);
835 		} else
836 			PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x010b);
837 
838 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400);
839 	}
840 
841 	if (bge_sc->bge_phy_flags & BGE_PHY_CRC_BUG)
842 		brgphy_crc_bug(sc);
843 
844 	/* Set Jumbo frame settings in the PHY. */
845 	if (bge_sc->bge_flags & BGE_JUMBO_CAPABLE)
846 		brgphy_jumbo_settings(sc);
847 
848 	/* Adjust output voltage */
849 	if (sc->mii_oui == MII_OUI_BROADCOM2 &&
850 	    sc->mii_model == MII_MODEL_BROADCOM2_BCM5906)
851 		PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12);
852 
853 	/* Enable Ethernet@Wirespeed */
854 	if (!(bge_sc->bge_phy_flags & BGE_PHY_NO_WIRESPEED))
855 		brgphy_eth_wirespeed(sc);
856 
857 	/* Enable Link LED on Dell boxes */
858 	if (bge_sc->bge_phy_flags & BGE_PHY_NO_3LED) {
859 		PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
860 		    PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL)
861 		    & ~BRGPHY_PHY_EXTCTL_3_LED);
862 	}
863 }
864 
865 void
866 brgphy_reset_bnx(struct mii_softc *sc)
867 {
868 	struct bnx_softc *bnx_sc = sc->mii_pdata->mii_ifp->if_softc;
869 
870 	if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5708 &&
871 	    sc->mii_flags & MIIF_HAVEFIBER) {
872 		/* Store autoneg capabilities/results in digital block (Page 0) */
873 		PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2);
874 		PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0,
875 		    BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE);
876 		PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0);
877 
878 		/* Enable fiber mode and autodetection */
879 		PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1,
880 		    PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) |
881 		    BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN |
882 		    BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE);
883 
884 		/* Enable parallel detection */
885 		PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2,
886 		    PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) |
887 		    BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN);
888 
889 		/* Advertise 2.5G support through next page during autoneg */
890 		if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) {
891 			PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1,
892 			    PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) |
893 			    BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
894 		}
895 
896 		/* Increase TX signal amplitude */
897 		if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) ||
898 		    (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) ||
899 		    (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) {
900 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
901 			    BRGPHY_5708S_TX_MISC_PG5);
902 			PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1,
903 			    PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) &
904 			    ~BRGPHY_5708S_PG5_TXACTL1_VCM);
905 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
906 			    BRGPHY_5708S_DIG_PG0);
907 		}
908 
909 		/* Backplanes use special driver/pre-driver/pre-emphasis values. */
910 		if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) &&
911 		    (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) {
912 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
913 			    BRGPHY_5708S_TX_MISC_PG5);
914 			PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3,
915 			    bnx_sc->bnx_port_hw_cfg &
916 			    BNX_PORT_HW_CFG_CFG_TXCTL3_MASK);
917 			    PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
918 			    BRGPHY_5708S_DIG_PG0);
919 		}
920 	} else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709 &&
921 	    sc->mii_flags & MIIF_HAVEFIBER) {
922 		/* Select the SerDes Digital block of the AN MMD. */
923 		PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG);
924 
925 		PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1,
926 		    (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) &
927 		    ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) |
928 		    BRGPHY_SD_DIG_1000X_CTL1_FIBER);
929 
930 		if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) {
931 			/* Select the Over 1G block of the AN MMD. */
932 			PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
933 			    BRGPHY_BLOCK_ADDR_OVER_1G);
934 
935 			/*
936 			 * Enable autoneg "Next Page" to advertise
937 			 * 2.5G support.
938 			 */
939 			PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1,
940 			    PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) |
941 			    BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
942 		}
943 
944 		/*
945 		 * Select the Multi-Rate Backplane Ethernet block of
946 		 * the AN MMD.
947 		 */
948 		PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_MRBE);
949 
950 		/* Enable MRBE speed autoneg. */
951 		PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP,
952 		    PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) |
953 		    BRGPHY_MRBE_MSG_PG5_NP_MBRE |
954 		    BRGPHY_MRBE_MSG_PG5_NP_T2);
955 
956 		/* Select the Clause 73 User B0 block of the AN MMD. */
957 		PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
958 		    BRGPHY_BLOCK_ADDR_CL73_USER_B0);
959 
960 		/* Enable MRBE speed autoneg. */
961 		PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1,
962 		    BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP |
963 		    BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR |
964 		    BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG);
965 
966 		PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
967 		    BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
968 	} else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709) {
969 		if (BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Ax ||
970 		    BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Bx)
971 			brgphy_disable_early_dac(sc);
972 
973 		/* Set Jumbo frame settings in the PHY. */
974 		brgphy_jumbo_settings(sc);
975 
976 		/* Enable Ethernet@Wirespeed */
977 		brgphy_eth_wirespeed(sc);
978 	} else if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
979 		brgphy_ber_bug(sc);
980 
981 		/* Set Jumbo frame settings in the PHY. */
982 		brgphy_jumbo_settings(sc);
983 
984 		/* Enable Ethernet@Wirespeed */
985 		brgphy_eth_wirespeed(sc);
986 	}
987 }
988 
989 /* Disable tap power management */
990 void
991 brgphy_bcm5401_dspcode(struct mii_softc *sc)
992 {
993 	static const struct {
994 		int		reg;
995 		uint16_t	val;
996 	} dspcode[] = {
997 		{ BRGPHY_MII_AUXCTL,		0x0c20 },
998 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0012 },
999 		{ BRGPHY_MII_DSP_RW_PORT,	0x1804 },
1000 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0013 },
1001 		{ BRGPHY_MII_DSP_RW_PORT,	0x1204 },
1002 		{ BRGPHY_MII_DSP_ADDR_REG,	0x8006 },
1003 		{ BRGPHY_MII_DSP_RW_PORT,	0x0132 },
1004 		{ BRGPHY_MII_DSP_ADDR_REG,	0x8006 },
1005 		{ BRGPHY_MII_DSP_RW_PORT,	0x0232 },
1006 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
1007 		{ BRGPHY_MII_DSP_RW_PORT,	0x0a20 },
1008 		{ 0,				0 },
1009 	};
1010 	int i;
1011 
1012 	for (i = 0; dspcode[i].reg != 0; i++)
1013 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1014 	DELAY(40);
1015 }
1016 
1017 /* Setting some undocumented voltage */
1018 void
1019 brgphy_bcm5411_dspcode(struct mii_softc *sc)
1020 {
1021 	static const struct {
1022 		int		reg;
1023 		uint16_t	val;
1024 	} dspcode[] = {
1025 		{ 0x1c,				0x8c23 },
1026 		{ 0x1c,				0x8ca3 },
1027 		{ 0x1c,				0x8c23 },
1028 		{ 0,				0 },
1029 	};
1030 	int i;
1031 
1032 	for (i = 0; dspcode[i].reg != 0; i++)
1033 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1034 }
1035 
1036 void
1037 brgphy_bcm5421_dspcode(struct mii_softc *sc)
1038 {
1039 	uint16_t data;
1040 
1041 	/* Set Class A mode */
1042 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007);
1043 	data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
1044 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400);
1045 
1046 	/* Set FFE gamma override to -0.125 */
1047 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007);
1048 	data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
1049 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800);
1050 	PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
1051 	data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
1052 	PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200);
1053 }
1054 
1055 void
1056 brgphy_bcm54k2_dspcode(struct mii_softc *sc)
1057 {
1058 	static const struct {
1059 		int		reg;
1060 		uint16_t	val;
1061 	} dspcode[] = {
1062 		{ 4,				0x01e1 },
1063 		{ 9,				0x0300 },
1064 		{ 0,				0 },
1065 	};
1066 	int i;
1067 
1068 	for (i = 0; dspcode[i].reg != 0; i++)
1069 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1070 }
1071 
1072 void
1073 brgphy_adc_bug(struct mii_softc *sc)
1074 {
1075 	static const struct {
1076 		int		reg;
1077 		uint16_t	val;
1078 	} dspcode[] = {
1079 		{ BRGPHY_MII_AUXCTL,		0x0c00 },
1080 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
1081 		{ BRGPHY_MII_DSP_RW_PORT,	0x2aaa },
1082 		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
1083 		{ BRGPHY_MII_DSP_RW_PORT,	0x0323 },
1084 		{ BRGPHY_MII_AUXCTL,		0x0400 },
1085 		{ 0,				0 },
1086 	};
1087 	int i;
1088 
1089 	for (i = 0; dspcode[i].reg != 0; i++)
1090 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1091 }
1092 
1093 void
1094 brgphy_5704_a0_bug(struct mii_softc *sc)
1095 {
1096 	static const struct {
1097 		int		reg;
1098 		uint16_t	val;
1099 	} dspcode[] = {
1100 		{ 0x1c,				0x8d68 },
1101 		{ 0x1c,				0x8d68 },
1102 		{ 0,				0 },
1103 	};
1104 	int i;
1105 
1106 	for (i = 0; dspcode[i].reg != 0; i++)
1107 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1108 }
1109 
1110 void
1111 brgphy_ber_bug(struct mii_softc *sc)
1112 {
1113 	static const struct {
1114 		int		reg;
1115 		uint16_t	val;
1116 	} dspcode[] = {
1117 		{ BRGPHY_MII_AUXCTL,		0x0c00 },
1118 		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
1119 		{ BRGPHY_MII_DSP_RW_PORT,	0x310b },
1120 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
1121 		{ BRGPHY_MII_DSP_RW_PORT,	0x9506 },
1122 		{ BRGPHY_MII_DSP_ADDR_REG,	0x401f },
1123 		{ BRGPHY_MII_DSP_RW_PORT,	0x14e2 },
1124 		{ BRGPHY_MII_AUXCTL,		0x0400 },
1125 		{ 0,				0 },
1126 	};
1127 	int i;
1128 
1129 	for (i = 0; dspcode[i].reg != 0; i++)
1130 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1131 }
1132 
1133 /* BCM5701 A0/B0 CRC bug workaround */
1134 void
1135 brgphy_crc_bug(struct mii_softc *sc)
1136 {
1137 	static const struct {
1138 		int		reg;
1139 		uint16_t	val;
1140 	} dspcode[] = {
1141 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0a75 },
1142 		{ 0x1c,				0x8c68 },
1143 		{ 0x1c,				0x8d68 },
1144 		{ 0x1c,				0x8c68 },
1145 		{ 0,				0 },
1146 	};
1147 	int i;
1148 
1149 	for (i = 0; dspcode[i].reg != 0; i++)
1150 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1151 }
1152 
1153 void
1154 brgphy_disable_early_dac(struct mii_softc *sc)
1155 {
1156 	uint32_t val;
1157 
1158 	PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08);
1159 	val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
1160 	val &= ~(1 << 8);
1161 	PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val);
1162 
1163 }
1164 
1165 void
1166 brgphy_jumbo_settings(struct mii_softc *sc)
1167 {
1168 	u_int32_t val;
1169 
1170 	/* Set Jumbo frame settings in the PHY. */
1171 	if (sc->mii_oui == MII_OUI_BROADCOM &&
1172 	    sc->mii_model == MII_MODEL_BROADCOM_BCM5401) {
1173 		/* Cannot do read-modify-write on the BCM5401 */
1174 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20);
1175 	} else {
1176 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
1177 		val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
1178 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
1179 			val | BRGPHY_AUXCTL_LONG_PKT);
1180 	}
1181 
1182 	val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
1183 	PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
1184 		val | BRGPHY_PHY_EXTCTL_HIGH_LA);
1185 }
1186 
1187 void
1188 brgphy_eth_wirespeed(struct mii_softc *sc)
1189 {
1190 	u_int32_t val;
1191 
1192 	/* Enable Ethernet@Wirespeed */
1193 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007);
1194 	val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
1195 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
1196 		(val | (1 << 15) | (1 << 4)));
1197 }
1198