xref: /netbsd-src/sys/dev/mii/brgphy.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: brgphy.c,v 1.68 2013/10/31 04:26:40 msaitoh Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55  */
56 
57 /*
58  * driver for the Broadcom BCM5400 and BCM5700 Gig-E PHYs.
59  *
60  * Programming information for this PHY was gleaned from FreeBSD
61  * (they were apparently able to get a datasheet from Broadcom).
62  */
63 
64 #include <sys/cdefs.h>
65 __KERNEL_RCSID(0, "$NetBSD: brgphy.c,v 1.68 2013/10/31 04:26:40 msaitoh Exp $");
66 
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/device.h>
71 #include <sys/socket.h>
72 #include <sys/errno.h>
73 #include <prop/proplib.h>
74 
75 #include <net/if.h>
76 #include <net/if_media.h>
77 
78 #include <dev/mii/mii.h>
79 #include <dev/mii/miivar.h>
80 #include <dev/mii/miidevs.h>
81 #include <dev/mii/brgphyreg.h>
82 
83 #include <dev/pci/if_bgereg.h>
84 #include <dev/pci/if_bnxreg.h>
85 
86 static int	brgphymatch(device_t, cfdata_t, void *);
87 static void	brgphyattach(device_t, device_t, void *);
88 
89 struct brgphy_softc {
90 	struct mii_softc sc_mii;
91 	bool sc_isbge;
92 	bool sc_isbnx;
93 	uint32_t sc_chipid;    /* parent's chipid */
94 	uint32_t sc_phyflags;  /* parent's phyflags */
95 };
96 
97 CFATTACH_DECL3_NEW(brgphy, sizeof(struct brgphy_softc),
98     brgphymatch, brgphyattach, mii_phy_detach, mii_phy_activate, NULL, NULL,
99     DVF_DETACH_SHUTDOWN);
100 
101 static int	brgphy_service(struct mii_softc *, struct mii_data *, int);
102 static void	brgphy_status(struct mii_softc *);
103 static int	brgphy_mii_phy_auto(struct mii_softc *);
104 static void	brgphy_loop(struct mii_softc *);
105 static void	brgphy_reset(struct mii_softc *);
106 static void	brgphy_bcm5401_dspcode(struct mii_softc *);
107 static void	brgphy_bcm5411_dspcode(struct mii_softc *);
108 static void	brgphy_bcm5421_dspcode(struct mii_softc *);
109 static void	brgphy_bcm54k2_dspcode(struct mii_softc *);
110 static void	brgphy_adc_bug(struct mii_softc *);
111 static void	brgphy_5704_a0_bug(struct mii_softc *);
112 static void	brgphy_ber_bug(struct mii_softc *);
113 static void	brgphy_crc_bug(struct mii_softc *);
114 static void	brgphy_disable_early_dac(struct mii_softc *);
115 static void	brgphy_jumbo_settings(struct mii_softc *);
116 static void	brgphy_eth_wirespeed(struct mii_softc *);
117 
118 
119 static const struct mii_phy_funcs brgphy_funcs = {
120 	brgphy_service, brgphy_status, brgphy_reset,
121 };
122 
123 static const struct mii_phydesc brgphys[] = {
124 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5400,
125 	  MII_STR_BROADCOM_BCM5400 },
126 
127 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5401,
128 	  MII_STR_BROADCOM_BCM5401 },
129 
130 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5411,
131 	  MII_STR_BROADCOM_BCM5411 },
132 
133 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5421,
134 	  MII_STR_BROADCOM_BCM5421 },
135 
136 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5462,
137 	  MII_STR_BROADCOM_BCM5462 },
138 
139 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5461,
140 	  MII_STR_BROADCOM_BCM5461 },
141 
142 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM54K2,
143 	  MII_STR_BROADCOM_BCM54K2 },
144 
145 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5464,
146 	  MII_STR_BROADCOM_BCM5464 },
147 
148 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5701,
149 	  MII_STR_BROADCOM_BCM5701 },
150 
151 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5703,
152 	  MII_STR_BROADCOM_BCM5703 },
153 
154 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5704,
155 	  MII_STR_BROADCOM_BCM5704 },
156 
157 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5705,
158 	  MII_STR_BROADCOM_BCM5705 },
159 
160 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5714,
161 	  MII_STR_BROADCOM_BCM5714 },
162 
163 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5750,
164 	  MII_STR_BROADCOM_BCM5750 },
165 
166 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5752,
167 	  MII_STR_BROADCOM_BCM5752 },
168 
169 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5780,
170 	  MII_STR_BROADCOM_BCM5780 },
171 
172 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5708C,
173 	  MII_STR_BROADCOM_BCM5708C },
174 
175 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5481,
176 	  MII_STR_BROADCOM2_BCM5481 },
177 
178 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5482,
179 	  MII_STR_BROADCOM2_BCM5482 },
180 
181 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5709C,
182 	  MII_STR_BROADCOM2_BCM5709C },
183 
184 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5709S,
185 	  MII_STR_BROADCOM2_BCM5709S },
186 
187 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5709CAX,
188 	  MII_STR_BROADCOM2_BCM5709CAX },
189 
190 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5722,
191 	  MII_STR_BROADCOM2_BCM5722 },
192 
193 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5754,
194 	  MII_STR_BROADCOM2_BCM5754 },
195 
196 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5755,
197 	  MII_STR_BROADCOM2_BCM5755 },
198 
199 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5756,
200 	  MII_STR_BROADCOM2_BCM5756 },
201 
202 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5761,
203 	  MII_STR_BROADCOM2_BCM5761 },
204 
205 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5784,
206 	  MII_STR_BROADCOM2_BCM5784 },
207 
208 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5785,
209 	  MII_STR_BROADCOM2_BCM5785 },
210 
211 	{ MII_OUI_BROADCOM3,		MII_MODEL_BROADCOM3_BCM5717C,
212 	  MII_STR_BROADCOM3_BCM5717C },
213 
214 	{ MII_OUI_BROADCOM3,		MII_MODEL_BROADCOM3_BCM5719C,
215 	  MII_STR_BROADCOM3_BCM5719C },
216 
217 	{ MII_OUI_BROADCOM3,		MII_MODEL_BROADCOM3_BCM5720C,
218 	  MII_STR_BROADCOM3_BCM5720C },
219 
220 	{ MII_OUI_BROADCOM3,		MII_MODEL_BROADCOM3_BCM57765,
221 	  MII_STR_BROADCOM3_BCM57765 },
222 
223 	{ MII_OUI_BROADCOM3,		MII_MODEL_BROADCOM3_BCM57780,
224 	  MII_STR_BROADCOM3_BCM57780 },
225 
226 	{ MII_OUI_xxBROADCOM_ALT1,	MII_MODEL_xxBROADCOM_ALT1_BCM5906,
227 	  MII_STR_xxBROADCOM_ALT1_BCM5906 },
228 
229 	{ 0,				0,
230 	  NULL },
231 };
232 
233 static int
234 brgphymatch(device_t parent, cfdata_t match, void *aux)
235 {
236 	struct mii_attach_args *ma = aux;
237 
238 	if (mii_phy_match(ma, brgphys) != NULL)
239 		return (10);
240 
241 	return (0);
242 }
243 
244 static void
245 brgphyattach(device_t parent, device_t self, void *aux)
246 {
247 	struct brgphy_softc *bsc = device_private(self);
248 	struct mii_softc *sc = &bsc->sc_mii;
249 	struct mii_attach_args *ma = aux;
250 	struct mii_data *mii = ma->mii_data;
251 	const struct mii_phydesc *mpd;
252 	prop_dictionary_t dict;
253 
254 	mpd = mii_phy_match(ma, brgphys);
255 	aprint_naive(": Media interface\n");
256 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
257 
258 	sc->mii_dev = self;
259 	sc->mii_inst = mii->mii_instance;
260 	sc->mii_phy = ma->mii_phyno;
261 	sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
262 	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
263 	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
264 	sc->mii_pdata = mii;
265 	sc->mii_flags = ma->mii_flags;
266 	sc->mii_anegticks = MII_ANEGTICKS;
267 	sc->mii_funcs = &brgphy_funcs;
268 
269 	if (device_is_a(parent, "bge"))
270 		bsc->sc_isbge = true;
271 	else if (device_is_a(parent, "bnx"))
272 		bsc->sc_isbnx = true;
273 
274 	if (bsc->sc_isbge || bsc->sc_isbnx) {
275 		dict = device_properties(parent);
276 		if (!prop_dictionary_get_uint32(dict, "phyflags",
277 		    &bsc->sc_phyflags))
278 			aprint_error_dev(self, "failed to get phyflags\n");
279 		if (!prop_dictionary_get_uint32(dict, "chipid",
280 		    &bsc->sc_chipid))
281 			aprint_error_dev(self, "failed to get chipid\n");
282 	}
283 
284 	PHY_RESET(sc);
285 
286 	sc->mii_capabilities =
287 	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
288 	if (sc->mii_capabilities & BMSR_EXTSTAT)
289 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
290 
291 	aprint_normal_dev(self, "");
292 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
293 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
294 		aprint_error("no media present");
295 	else {
296 		if (sc->mii_flags & MIIF_HAVEFIBER) {
297 			sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
298 
299 			/*
300 			 * Set the proper bits for capabilities so that the
301 			 * correct media get selected by mii_phy_add_media()
302 			 */
303 			sc->mii_capabilities |= BMSR_ANEG;
304 			sc->mii_capabilities &= ~BMSR_100T4;
305 			sc->mii_extcapabilities |= EXTSR_1000XFDX;
306 
307 			if (bsc->sc_isbnx) {
308 				/*
309 				 * 2.5Gb support is a software enabled feature
310 				 * on the BCM5708S and BCM5709S controllers.
311 				 */
312 #define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
313 				if (bsc->sc_phyflags
314 				    & BNX_PHY_2_5G_CAPABLE_FLAG) {
315 					ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX,
316 					    IFM_FDX, sc->mii_inst), 0);
317 					aprint_normal("2500baseSX-FDX, ");
318 #undef ADD
319 				}
320 			}
321 		}
322 		mii_phy_add_media(sc);
323 	}
324 	aprint_normal("\n");
325 
326 }
327 
328 static int
329 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
330 {
331 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
332 	int reg, speed, gig;
333 
334 	switch (cmd) {
335 	case MII_POLLSTAT:
336 		/*
337 		 * If we're not polling our PHY instance, just return.
338 		 */
339 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
340 			return (0);
341 		break;
342 
343 	case MII_MEDIACHG:
344 		/*
345 		 * If the media indicates a different PHY instance,
346 		 * isolate ourselves.
347 		 */
348 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
349 			reg = PHY_READ(sc, MII_BMCR);
350 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
351 			return (0);
352 		}
353 
354 		/*
355 		 * If the interface is not up, don't do anything.
356 		 */
357 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
358 			break;
359 
360 		PHY_RESET(sc); /* XXX hardware bug work-around */
361 
362 		switch (IFM_SUBTYPE(ife->ifm_media)) {
363 		case IFM_AUTO:
364 			(void) brgphy_mii_phy_auto(sc);
365 			break;
366 		case IFM_1000_T:
367 			speed = BMCR_S1000;
368 			goto setit;
369 		case IFM_100_TX:
370 			speed = BMCR_S100;
371 			goto setit;
372 		case IFM_10_T:
373 			speed = BMCR_S10;
374 setit:
375 			brgphy_loop(sc);
376 			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
377 				speed |= BMCR_FDX;
378 				gig = GTCR_ADV_1000TFDX;
379 			} else {
380 				gig = GTCR_ADV_1000THDX;
381 			}
382 
383 			PHY_WRITE(sc, MII_100T2CR, 0);
384 			PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
385 			PHY_WRITE(sc, MII_BMCR, speed);
386 
387 			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
388 				break;
389 
390 			PHY_WRITE(sc, MII_100T2CR, gig);
391 			PHY_WRITE(sc, MII_BMCR,
392 			    speed | BMCR_AUTOEN | BMCR_STARTNEG);
393 
394 			if ((sc->mii_mpd_oui != MII_OUI_BROADCOM)
395 			    || (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701))
396 				break;
397 
398 			if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
399 				gig |= GTCR_MAN_MS | GTCR_ADV_MS;
400 			PHY_WRITE(sc, MII_100T2CR, gig);
401 			break;
402 		default:
403 			return (EINVAL);
404 		}
405 		break;
406 
407 	case MII_TICK:
408 		/*
409 		 * If we're not currently selected, just return.
410 		 */
411 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
412 			return (0);
413 
414 		/*
415 		 * Is the interface even up?
416 		 */
417 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
418 			return 0;
419 
420 		/*
421 		 * Only used for autonegotiation.
422 		 */
423 		if ((IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) &&
424 		    (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)) {
425 			sc->mii_ticks = 0;
426 			break;
427 		}
428 
429 		/*
430 		 * Check for link.
431 		 * Read the status register twice; BMSR_LINK is latch-low.
432 		 */
433 		reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
434 		if (reg & BMSR_LINK) {
435 			sc->mii_ticks = 0;
436 			break;
437 		}
438 
439 		/*
440 		 * mii_ticks == 0 means it's the first tick after changing the
441 		 * media or the link became down since the last tick
442 		 * (see above), so break to update the status.
443 		 */
444 		if (sc->mii_ticks++ == 0)
445 			break;
446 
447 		/*
448 		 * Only retry autonegotiation every mii_anegticks seconds.
449 		 */
450 		KASSERT(sc->mii_anegticks != 0);
451 		if (sc->mii_ticks <= sc->mii_anegticks)
452 			break;
453 
454 		brgphy_mii_phy_auto(sc);
455 		break;
456 
457 	case MII_DOWN:
458 		mii_phy_down(sc);
459 		return (0);
460 	}
461 
462 	/* Update the media status. */
463 	mii_phy_status(sc);
464 
465 	/*
466 	 * Callback if something changed. Note that we need to poke the DSP on
467 	 * the Broadcom PHYs if the media changes.
468 	 */
469 	if (sc->mii_media_active != mii->mii_media_active ||
470 	    sc->mii_media_status != mii->mii_media_status ||
471 	    cmd == MII_MEDIACHG) {
472 		switch (sc->mii_mpd_oui) {
473 		case MII_OUI_BROADCOM:
474 			switch (sc->mii_mpd_model) {
475 			case MII_MODEL_BROADCOM_BCM5400:
476 				brgphy_bcm5401_dspcode(sc);
477 				break;
478 			case MII_MODEL_BROADCOM_BCM5401:
479 				if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
480 					brgphy_bcm5401_dspcode(sc);
481 				break;
482 			case MII_MODEL_BROADCOM_BCM5411:
483 				brgphy_bcm5411_dspcode(sc);
484 				break;
485 			}
486 			break;
487 		}
488 	}
489 
490 	/* Callback if something changed. */
491 	mii_phy_update(sc, cmd);
492 	return (0);
493 }
494 
495 static void
496 brgphy_status(struct mii_softc *sc)
497 {
498 	struct mii_data *mii = sc->mii_pdata;
499 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
500 	int bmcr, bmsr, auxsts, gtsr;
501 
502 	mii->mii_media_status = IFM_AVALID;
503 	mii->mii_media_active = IFM_ETHER;
504 
505 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
506 	if (bmsr & BMSR_LINK)
507 		mii->mii_media_status |= IFM_ACTIVE;
508 
509 	bmcr = PHY_READ(sc, MII_BMCR);
510 	if (bmcr & BMCR_ISO) {
511 		mii->mii_media_active |= IFM_NONE;
512 		mii->mii_media_status = 0;
513 		return;
514 	}
515 
516 	if (bmcr & BMCR_LOOP)
517 		mii->mii_media_active |= IFM_LOOP;
518 
519 	if (bmcr & BMCR_AUTOEN) {
520 		/*
521 		 * The media status bits are only valid of autonegotiation
522 		 * has completed (or it's disabled).
523 		 */
524 		if ((bmsr & BMSR_ACOMP) == 0) {
525 			/* Erg, still trying, I guess... */
526 			mii->mii_media_active |= IFM_NONE;
527 			return;
528 		}
529 
530 		if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2)
531 		    && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S)) {
532 			/*
533 			 * 5709S has its own general purpose status registers
534 			 */
535 			PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
536 			    BRGPHY_BLOCK_ADDR_GP_STATUS);
537 
538 			auxsts = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS);
539 
540 			PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
541 			    BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
542 
543 			switch (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) {
544 			case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10:
545 				mii->mii_media_active |= IFM_10_FL;
546 				break;
547 			case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100:
548 				mii->mii_media_active |= IFM_100_FX;
549 				break;
550 			case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G:
551 				mii->mii_media_active |= IFM_1000_SX;
552 				break;
553 			case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G:
554 				mii->mii_media_active |= IFM_2500_SX;
555 				break;
556 			default:
557 				mii->mii_media_active |= IFM_NONE;
558 				mii->mii_media_status = 0;
559 				break;
560 			}
561 
562 			if (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_FDX)
563 				mii->mii_media_active |= IFM_FDX;
564 			else
565 				mii->mii_media_active |= IFM_HDX;
566 
567 		} else {
568 			auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS);
569 
570 			switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
571 			case BRGPHY_RES_1000FD:
572 				mii->mii_media_active |= IFM_1000_T | IFM_FDX;
573 				gtsr = PHY_READ(sc, MII_100T2SR);
574 				if (gtsr & GTSR_MS_RES)
575 					mii->mii_media_active |= IFM_ETH_MASTER;
576 				break;
577 
578 			case BRGPHY_RES_1000HD:
579 				mii->mii_media_active |= IFM_1000_T;
580 				gtsr = PHY_READ(sc, MII_100T2SR);
581 				if (gtsr & GTSR_MS_RES)
582 					mii->mii_media_active |= IFM_ETH_MASTER;
583 				break;
584 
585 			case BRGPHY_RES_100FD:
586 				mii->mii_media_active |= IFM_100_TX | IFM_FDX;
587 				break;
588 
589 			case BRGPHY_RES_100T4:
590 				mii->mii_media_active |= IFM_100_T4;
591 				break;
592 
593 			case BRGPHY_RES_100HD:
594 				mii->mii_media_active |= IFM_100_TX;
595 				break;
596 
597 			case BRGPHY_RES_10FD:
598 				mii->mii_media_active |= IFM_10_T | IFM_FDX;
599 				break;
600 
601 			case BRGPHY_RES_10HD:
602 				mii->mii_media_active |= IFM_10_T;
603 				break;
604 
605 			default:
606 				mii->mii_media_active |= IFM_NONE;
607 				mii->mii_media_status = 0;
608 			}
609 		}
610 
611 		if (mii->mii_media_active & IFM_FDX)
612 			mii->mii_media_active |= mii_phy_flowstatus(sc);
613 
614 	} else
615 		mii->mii_media_active = ife->ifm_media;
616 }
617 
618 int
619 brgphy_mii_phy_auto(struct mii_softc *sc)
620 {
621 	int anar, ktcr = 0;
622 
623 	sc->mii_ticks = 0;
624 	brgphy_loop(sc);
625 	PHY_RESET(sc);
626 
627 	ktcr = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
628 	if ((sc->mii_mpd_oui == MII_OUI_BROADCOM)
629 	    && (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701))
630 		ktcr |= GTCR_MAN_MS | GTCR_ADV_MS;
631 	PHY_WRITE(sc, MII_100T2CR, ktcr);
632 	ktcr = PHY_READ(sc, MII_100T2CR);
633 	DELAY(1000);
634 
635 	if (sc->mii_flags & MIIF_HAVEFIBER) {
636 		anar = ANAR_X_FD | ANAR_X_HD;
637 		if (sc->mii_flags & MIIF_DOPAUSE)
638 			anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE;
639 	} else {
640 		anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
641 		if (sc->mii_flags & MIIF_DOPAUSE)
642 			anar |= ANAR_FC | ANAR_PAUSE_ASYM;
643 	}
644 	PHY_WRITE(sc, MII_ANAR, anar);
645 	DELAY(1000);
646 
647 	/* Start autonegotiation */
648 	PHY_WRITE(sc, MII_BMCR,
649 	    BMCR_AUTOEN | BMCR_STARTNEG);
650 	PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
651 
652 	return (EJUSTRETURN);
653 }
654 
655 void
656 brgphy_loop(struct mii_softc *sc)
657 {
658 	u_int32_t bmsr;
659 	int i;
660 
661 	PHY_WRITE(sc, MII_BMCR, BMCR_LOOP);
662 	for (i = 0; i < 15000; i++) {
663 		bmsr = PHY_READ(sc, MII_BMSR);
664 		if (!(bmsr & BMSR_LINK))
665 			break;
666 		DELAY(10);
667 	}
668 }
669 
670 static void
671 brgphy_reset(struct mii_softc *sc)
672 {
673 	struct brgphy_softc *bsc = device_private(sc->mii_dev);
674 
675 	mii_phy_reset(sc);
676 	switch (sc->mii_mpd_oui) {
677 	case MII_OUI_BROADCOM:
678 		switch (sc->mii_mpd_model) {
679 		case MII_MODEL_BROADCOM_BCM5400:
680 			brgphy_bcm5401_dspcode(sc);
681 			break;
682 		case MII_MODEL_BROADCOM_BCM5401:
683 			if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
684 				brgphy_bcm5401_dspcode(sc);
685 			break;
686 		case MII_MODEL_BROADCOM_BCM5411:
687 			brgphy_bcm5411_dspcode(sc);
688 			break;
689 		case MII_MODEL_BROADCOM_BCM5421:
690 			brgphy_bcm5421_dspcode(sc);
691 			break;
692 		case MII_MODEL_BROADCOM_BCM54K2:
693 			brgphy_bcm54k2_dspcode(sc);
694 			break;
695 		}
696 		break;
697 	case MII_OUI_BROADCOM3:
698 		switch (sc->mii_mpd_model) {
699 		case MII_MODEL_BROADCOM3_BCM5717C:
700 		case MII_MODEL_BROADCOM3_BCM5719C:
701 		case MII_MODEL_BROADCOM3_BCM5720C:
702 		case MII_MODEL_BROADCOM3_BCM57765:
703 			return;
704 		}
705 		break;
706 	default:
707 		break;
708 	}
709 
710 	/* Handle any bge (NetXtreme/NetLink) workarounds. */
711 	if (bsc->sc_isbge) {
712 		if (!(sc->mii_flags & MIIF_HAVEFIBER)) {
713 
714 			if (bsc->sc_phyflags & BGEPHYF_ADC_BUG)
715 				brgphy_adc_bug(sc);
716 			if (bsc->sc_phyflags & BGEPHYF_5704_A0_BUG)
717 				brgphy_5704_a0_bug(sc);
718 			if (bsc->sc_phyflags & BGEPHYF_BER_BUG)
719 				brgphy_ber_bug(sc);
720 			else if (bsc->sc_phyflags & BGEPHYF_JITTER_BUG) {
721 				PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00);
722 				PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG,
723 				    0x000a);
724 
725 				if (bsc->sc_phyflags
726 				    & BGEPHYF_ADJUST_TRIM) {
727 					PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT,
728 					    0x110b);
729 					PHY_WRITE(sc, BRGPHY_TEST1,
730 					    BRGPHY_TEST1_TRIM_EN | 0x4);
731 				} else {
732 					PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT,
733 					    0x010b);
734 				}
735 
736 				PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400);
737 			}
738 			if (bsc->sc_phyflags & BGEPHYF_CRC_BUG)
739 				brgphy_crc_bug(sc);
740 
741 			/* Set Jumbo frame settings in the PHY. */
742 			if (bsc->sc_phyflags & BGEPHYF_JUMBO_CAPABLE)
743 				brgphy_jumbo_settings(sc);
744 
745 			/* Adjust output voltage */
746 			if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2)
747 			    && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5906))
748 				PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12);
749 
750 			/* Enable Ethernet@Wirespeed */
751 			if (!(bsc->sc_phyflags & BGEPHYF_NO_WIRESPEED))
752 				brgphy_eth_wirespeed(sc);
753 
754 #if 0
755 			/* Enable Link LED on Dell boxes */
756 			if (bsc->sc_phyflags & BGEPHYF_NO_3LED) {
757 				PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
758 				PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL)
759 					& ~BRGPHY_PHY_EXTCTL_3_LED);
760 			}
761 #endif
762 		}
763 	/* Handle any bnx (NetXtreme II) workarounds. */
764 	} else if (bsc->sc_isbnx) {
765 #if 0 /* not yet */
766 		if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2)
767 		    && sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5708S) {
768 			/* Store autoneg capabilities/results in digital block (Page 0) */
769 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2);
770 			PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0,
771 				BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE);
772 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0);
773 
774 			/* Enable fiber mode and autodetection */
775 			PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1,
776 				PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) |
777 				BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN |
778 				BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE);
779 
780 			/* Enable parallel detection */
781 			PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2,
782 				PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) |
783 				BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN);
784 
785 			/* Advertise 2.5G support through next page during autoneg */
786 			if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG)
787 				PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1,
788 					PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) |
789 					BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
790 
791 			/* Increase TX signal amplitude */
792 			if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) ||
793 			    (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) ||
794 			    (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) {
795 				PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
796 					BRGPHY_5708S_TX_MISC_PG5);
797 				PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1,
798 					PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) &
799 					~BRGPHY_5708S_PG5_TXACTL1_VCM);
800 				PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
801 					BRGPHY_5708S_DIG_PG0);
802 			}
803 
804 			/* Backplanes use special driver/pre-driver/pre-emphasis values. */
805 			if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) &&
806 			    (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) {
807 					PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
808 						BRGPHY_5708S_TX_MISC_PG5);
809 					PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3,
810 						bnx_sc->bnx_port_hw_cfg &
811 						BNX_PORT_HW_CFG_CFG_TXCTL3_MASK);
812 					PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
813 						BRGPHY_5708S_DIG_PG0);
814 			}
815 		} else
816 #endif
817 		if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2)
818 		    && (sc->mii_mpd_model ==  MII_MODEL_BROADCOM2_BCM5709S)) {
819 			/* Select the SerDes Digital block of the AN MMD. */
820 			PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
821 			    BRGPHY_BLOCK_ADDR_SERDES_DIG);
822 
823 			PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1,
824 			    (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) &
825 			    ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) |
826 			    BRGPHY_SD_DIG_1000X_CTL1_FIBER);
827 
828 			if (bsc->sc_phyflags & BNX_PHY_2_5G_CAPABLE_FLAG) {
829 				/* Select the Over 1G block of the AN MMD. */
830 				PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
831 				    BRGPHY_BLOCK_ADDR_OVER_1G);
832 
833 				/*
834 				 * Enable autoneg "Next Page" to advertise
835 				 * 2.5G support.
836 				 */
837 				PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1,
838 				    PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) |
839 				    BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
840 			}
841 
842                         /*
843                          * Select the Multi-Rate Backplane Ethernet block of
844                          * the AN MMD.
845                          */
846                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
847                             BRGPHY_BLOCK_ADDR_MRBE);
848 
849                         /* Enable MRBE speed autoneg. */
850                         PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP,
851                             PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) |
852                             BRGPHY_MRBE_MSG_PG5_NP_MBRE |
853                             BRGPHY_MRBE_MSG_PG5_NP_T2);
854 
855                         /* Select the Clause 73 User B0 block of the AN MMD. */
856                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
857                             BRGPHY_BLOCK_ADDR_CL73_USER_B0);
858 
859                         /* Enable MRBE speed autoneg. */
860                         PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1,
861                             BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP |
862                             BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR |
863                             BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG);
864 
865                         PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
866                             BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
867 
868 		} else if (_BNX_CHIP_NUM(bsc->sc_chipid) == BNX_CHIP_NUM_5709) {
869 			if (_BNX_CHIP_REV(bsc->sc_chipid) == BNX_CHIP_REV_Ax ||
870 			    _BNX_CHIP_REV(bsc->sc_chipid) == BNX_CHIP_REV_Bx)
871 				brgphy_disable_early_dac(sc);
872 
873 			/* Set Jumbo frame settings in the PHY. */
874 			brgphy_jumbo_settings(sc);
875 
876 			/* Enable Ethernet@Wirespeed */
877 			brgphy_eth_wirespeed(sc);
878 		} else {
879 			if (!(sc->mii_flags & MIIF_HAVEFIBER)) {
880 				brgphy_ber_bug(sc);
881 
882 				/* Set Jumbo frame settings in the PHY. */
883 				brgphy_jumbo_settings(sc);
884 
885 				/* Enable Ethernet@Wirespeed */
886 				brgphy_eth_wirespeed(sc);
887 			}
888 		}
889 	}
890 }
891 
892 /* Turn off tap power management on 5401. */
893 static void
894 brgphy_bcm5401_dspcode(struct mii_softc *sc)
895 {
896 	static const struct {
897 		int		reg;
898 		uint16_t	val;
899 	} dspcode[] = {
900 		{ BRGPHY_MII_AUXCTL,		0x0c20 },
901 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0012 },
902 		{ BRGPHY_MII_DSP_RW_PORT,	0x1804 },
903 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0013 },
904 		{ BRGPHY_MII_DSP_RW_PORT,	0x1204 },
905 		{ BRGPHY_MII_DSP_ADDR_REG,	0x8006 },
906 		{ BRGPHY_MII_DSP_RW_PORT,	0x0132 },
907 		{ BRGPHY_MII_DSP_ADDR_REG,	0x8006 },
908 		{ BRGPHY_MII_DSP_RW_PORT,	0x0232 },
909 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
910 		{ BRGPHY_MII_DSP_RW_PORT,	0x0a20 },
911 		{ 0,				0 },
912 	};
913 	int i;
914 
915 	for (i = 0; dspcode[i].reg != 0; i++)
916 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
917 	delay(40);
918 }
919 
920 static void
921 brgphy_bcm5411_dspcode(struct mii_softc *sc)
922 {
923 	static const struct {
924 		int		reg;
925 		uint16_t	val;
926 	} dspcode[] = {
927 		{ 0x1c,				0x8c23 },
928 		{ 0x1c,				0x8ca3 },
929 		{ 0x1c,				0x8c23 },
930 		{ 0,				0 },
931 	};
932 	int i;
933 
934 	for (i = 0; dspcode[i].reg != 0; i++)
935 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
936 }
937 
938 void
939 brgphy_bcm5421_dspcode(struct mii_softc *sc)
940 {
941 	uint16_t data;
942 
943 	/* Set Class A mode */
944 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007);
945 	data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
946 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400);
947 
948 	/* Set FFE gamma override to -0.125 */
949 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007);
950 	data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
951 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800);
952 	PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
953 	data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
954 	PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200);
955 }
956 
957 void
958 brgphy_bcm54k2_dspcode(struct mii_softc *sc)
959 {
960 	static const struct {
961 		int		reg;
962 		uint16_t	val;
963 	} dspcode[] = {
964 		{ 4,				0x01e1 },
965 		{ 9,				0x0300 },
966 		{ 0,				0 },
967 	};
968 	int i;
969 
970 	for (i = 0; dspcode[i].reg != 0; i++)
971 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
972 }
973 
974 static void
975 brgphy_adc_bug(struct mii_softc *sc)
976 {
977 	static const struct {
978 		int		reg;
979 		uint16_t	val;
980 	} dspcode[] = {
981 		{ BRGPHY_MII_AUXCTL,		0x0c00 },
982 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
983 		{ BRGPHY_MII_DSP_RW_PORT,	0x2aaa },
984 		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
985 		{ BRGPHY_MII_DSP_RW_PORT,	0x0323 },
986 		{ BRGPHY_MII_AUXCTL,		0x0400 },
987 		{ 0,				0 },
988 	};
989 	int i;
990 
991 	for (i = 0; dspcode[i].reg != 0; i++)
992 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
993 }
994 
995 static void
996 brgphy_5704_a0_bug(struct mii_softc *sc)
997 {
998 	static const struct {
999 		int		reg;
1000 		uint16_t	val;
1001 	} dspcode[] = {
1002 		{ 0x1c,				0x8d68 },
1003 		{ 0x1c,				0x8d68 },
1004 		{ 0,				0 },
1005 	};
1006 	int i;
1007 
1008 	for (i = 0; dspcode[i].reg != 0; i++)
1009 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1010 }
1011 
1012 static void
1013 brgphy_ber_bug(struct mii_softc *sc)
1014 {
1015 	static const struct {
1016 		int		reg;
1017 		uint16_t	val;
1018 	} dspcode[] = {
1019 		{ BRGPHY_MII_AUXCTL,		0x0c00 },
1020 		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
1021 		{ BRGPHY_MII_DSP_RW_PORT,	0x310b },
1022 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
1023 		{ BRGPHY_MII_DSP_RW_PORT,	0x9506 },
1024 		{ BRGPHY_MII_DSP_ADDR_REG,	0x401f },
1025 		{ BRGPHY_MII_DSP_RW_PORT,	0x14e2 },
1026 		{ BRGPHY_MII_AUXCTL,		0x0400 },
1027 		{ 0,				0 },
1028 	};
1029 	int i;
1030 
1031 	for (i = 0; dspcode[i].reg != 0; i++)
1032 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1033 }
1034 
1035 /* BCM5701 A0/B0 CRC bug workaround */
1036 void
1037 brgphy_crc_bug(struct mii_softc *sc)
1038 {
1039 	static const struct {
1040 		int		reg;
1041 		uint16_t	val;
1042 	} dspcode[] = {
1043 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0a75 },
1044 		{ 0x1c,				0x8c68 },
1045 		{ 0x1c,				0x8d68 },
1046 		{ 0x1c,				0x8c68 },
1047 		{ 0,				0 },
1048 	};
1049 	int i;
1050 
1051 	for (i = 0; dspcode[i].reg != 0; i++)
1052 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1053 }
1054 
1055 static void
1056 brgphy_disable_early_dac(struct mii_softc *sc)
1057 {
1058 	uint32_t val;
1059 
1060 	PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08);
1061 	val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
1062 	val &= ~(1 << 8);
1063 	PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val);
1064 
1065 }
1066 
1067 static void
1068 brgphy_jumbo_settings(struct mii_softc *sc)
1069 {
1070 	u_int32_t val;
1071 
1072 	/* Set Jumbo frame settings in the PHY. */
1073 	if ((sc->mii_mpd_oui == MII_OUI_BROADCOM)
1074 	    && (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5401)) {
1075 		/* Cannot do read-modify-write on the BCM5401 */
1076 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20);
1077 	} else {
1078 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
1079 		val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
1080 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
1081 			val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7));
1082 	}
1083 
1084 	val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
1085 	PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
1086 		val & ~BRGPHY_PHY_EXTCTL_HIGH_LA);
1087 }
1088 
1089 static void
1090 brgphy_eth_wirespeed(struct mii_softc *sc)
1091 {
1092 	u_int32_t val;
1093 
1094 	/* Enable Ethernet@Wirespeed */
1095 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007);
1096 	val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
1097 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
1098 		(val | (1 << 15) | (1 << 4)));
1099 }
1100