xref: /netbsd-src/sys/dev/mii/brgphy.c (revision 10ad5ffa714ce1a679dcc9dd8159648df2d67b5a)
1 /*	$NetBSD: brgphy.c,v 1.48 2009/06/17 15:43:16 tsutsui 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  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *	This product includes software developed by Manuel Bouyer.
47  * 4. The name of the author may not be used to endorse or promote products
48  *    derived from this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
51  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
54  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60  */
61 
62 /*
63  * driver for the Broadcom BCM5400 Gig-E PHY.
64  *
65  * Programming information for this PHY was gleaned from FreeBSD
66  * (they were apparently able to get a datasheet from Broadcom).
67  */
68 
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: brgphy.c,v 1.48 2009/06/17 15:43:16 tsutsui Exp $");
71 
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/kernel.h>
75 #include <sys/device.h>
76 #include <sys/socket.h>
77 #include <sys/errno.h>
78 #include <prop/proplib.h>
79 
80 #include <net/if.h>
81 #include <net/if_media.h>
82 
83 #include <dev/mii/mii.h>
84 #include <dev/mii/miivar.h>
85 #include <dev/mii/miidevs.h>
86 #include <dev/mii/brgphyreg.h>
87 
88 #include <dev/pci/if_bgereg.h>
89 #if 0
90 #include <dev/pci/if_bnxreg.h>
91 #endif
92 
93 static int	brgphymatch(device_t, cfdata_t, void *);
94 static void	brgphyattach(device_t, device_t, void *);
95 
96 struct brgphy_softc {
97 	struct mii_softc sc_mii;
98 	int sc_isbge;
99 	int sc_isbnx;
100 	int sc_bge_flags;
101 	int sc_bnx_flags;
102 };
103 
104 CFATTACH_DECL3_NEW(brgphy, sizeof(struct brgphy_softc),
105     brgphymatch, brgphyattach, mii_phy_detach, mii_phy_activate, NULL, NULL,
106     DVF_DETACH_SHUTDOWN);
107 
108 static int	brgphy_service(struct mii_softc *, struct mii_data *, int);
109 static void	brgphy_status(struct mii_softc *);
110 static int	brgphy_mii_phy_auto(struct mii_softc *);
111 static void	brgphy_loop(struct mii_softc *);
112 static void	brgphy_reset(struct mii_softc *);
113 static void	brgphy_bcm5401_dspcode(struct mii_softc *);
114 static void	brgphy_bcm5411_dspcode(struct mii_softc *);
115 static void	brgphy_bcm5421_dspcode(struct mii_softc *);
116 static void	brgphy_bcm54k2_dspcode(struct mii_softc *);
117 static void	brgphy_adc_bug(struct mii_softc *);
118 static void	brgphy_5704_a0_bug(struct mii_softc *);
119 static void	brgphy_ber_bug(struct mii_softc *);
120 static void	brgphy_crc_bug(struct mii_softc *);
121 
122 
123 static const struct mii_phy_funcs brgphy_funcs = {
124 	brgphy_service, brgphy_status, brgphy_reset,
125 };
126 
127 static const struct mii_phydesc brgphys[] = {
128 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5400,
129 	  MII_STR_BROADCOM_BCM5400 },
130 
131 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5401,
132 	  MII_STR_BROADCOM_BCM5401 },
133 
134 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5411,
135 	  MII_STR_BROADCOM_BCM5411 },
136 
137 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5421,
138 	  MII_STR_BROADCOM_BCM5421 },
139 
140 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM54K2,
141 	  MII_STR_BROADCOM_BCM54K2 },
142 
143 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5462,
144 	  MII_STR_BROADCOM_BCM5462 },
145 
146 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5701,
147 	  MII_STR_BROADCOM_BCM5701 },
148 
149 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5703,
150 	  MII_STR_BROADCOM_BCM5703 },
151 
152 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5704,
153 	  MII_STR_BROADCOM_BCM5704 },
154 
155 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5705,
156 	  MII_STR_BROADCOM_BCM5705 },
157 
158 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5714,
159 	  MII_STR_BROADCOM_BCM5714 },
160 
161 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5750,
162 	  MII_STR_BROADCOM_BCM5750 },
163 
164 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5752,
165 	  MII_STR_BROADCOM_BCM5752 },
166 
167 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5780,
168 	  MII_STR_BROADCOM_BCM5780 },
169 
170 	{ MII_OUI_BROADCOM,		MII_MODEL_BROADCOM_BCM5708C,
171 	  MII_STR_BROADCOM_BCM5708C },
172 
173 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5722,
174 	  MII_STR_BROADCOM2_BCM5722 },
175 
176 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5755,
177 	  MII_STR_BROADCOM2_BCM5755 },
178 
179 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5754,
180 	  MII_STR_BROADCOM2_BCM5754 },
181 
182 	{ MII_OUI_xxBROADCOM_ALT1,	MII_MODEL_xxBROADCOM_ALT1_BCM5906,
183 	  MII_STR_xxBROADCOM_ALT1_BCM5906 },
184 
185 	{ 0,				0,
186 	  NULL },
187 };
188 
189 static int
190 brgphymatch(device_t parent, cfdata_t match, void *aux)
191 {
192 	struct mii_attach_args *ma = aux;
193 
194 	if (mii_phy_match(ma, brgphys) != NULL)
195 		return (10);
196 
197 	return (0);
198 }
199 
200 static void
201 brgphyattach(device_t parent, device_t self, void *aux)
202 {
203 	struct brgphy_softc *bsc = device_private(self);
204 	struct mii_softc *sc = &bsc->sc_mii;
205 	struct mii_attach_args *ma = aux;
206 	struct mii_data *mii = ma->mii_data;
207 	const struct mii_phydesc *mpd;
208 	prop_dictionary_t dict;
209 
210 	mpd = mii_phy_match(ma, brgphys);
211 	aprint_naive(": Media interface\n");
212 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
213 
214 	sc->mii_dev = self;
215 	sc->mii_inst = mii->mii_instance;
216 	sc->mii_phy = ma->mii_phyno;
217 	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
218 	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
219 	sc->mii_pdata = mii;
220 	sc->mii_flags = ma->mii_flags;
221 	sc->mii_anegticks = MII_ANEGTICKS;
222 	sc->mii_funcs = &brgphy_funcs;
223 
224 	PHY_RESET(sc);
225 
226 	sc->mii_capabilities =
227 	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
228 	if (sc->mii_capabilities & BMSR_EXTSTAT)
229 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
230 
231 	aprint_normal_dev(self, "");
232 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
233 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
234 		aprint_error("no media present");
235 	else
236 		mii_phy_add_media(sc);
237 	aprint_normal("\n");
238 
239 	if (device_is_a(parent, "bge")) {
240 		bsc->sc_isbge = 1;
241 		dict = device_properties(parent);
242 		prop_dictionary_get_uint32(dict, "phyflags",
243 		    &bsc->sc_bge_flags);
244 	} else if (device_is_a(parent, "bnx")) {
245 		bsc->sc_isbnx = 1;
246 		dict = device_properties(parent);
247 		prop_dictionary_get_uint32(dict, "phyflags",
248 		    &bsc->sc_bnx_flags);
249 	}
250 }
251 
252 static int
253 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
254 {
255 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
256 	int reg, speed, gig;
257 
258 	switch (cmd) {
259 	case MII_POLLSTAT:
260 		/*
261 		 * If we're not polling our PHY instance, just return.
262 		 */
263 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
264 			return (0);
265 		break;
266 
267 	case MII_MEDIACHG:
268 		/*
269 		 * If the media indicates a different PHY instance,
270 		 * isolate ourselves.
271 		 */
272 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
273 			reg = PHY_READ(sc, MII_BMCR);
274 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
275 			return (0);
276 		}
277 
278 		/*
279 		 * If the interface is not up, don't do anything.
280 		 */
281 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
282 			break;
283 
284 		PHY_RESET(sc); /* XXX hardware bug work-around */
285 
286 		switch (IFM_SUBTYPE(ife->ifm_media)) {
287 		case IFM_AUTO:
288 			(void) brgphy_mii_phy_auto(sc);
289 			break;
290 		case IFM_1000_T:
291 			speed = BMCR_S1000;
292 			goto setit;
293 		case IFM_100_TX:
294 			speed = BMCR_S100;
295 			goto setit;
296 		case IFM_10_T:
297 			speed = BMCR_S10;
298 setit:
299 			brgphy_loop(sc);
300 			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
301 				speed |= BMCR_FDX;
302 				gig = GTCR_ADV_1000TFDX;
303 			} else {
304 				gig = GTCR_ADV_1000THDX;
305 			}
306 
307 			PHY_WRITE(sc, MII_100T2CR, 0);
308 			PHY_WRITE(sc, MII_BMCR, speed);
309 			PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
310 
311 			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
312 				break;
313 
314 			PHY_WRITE(sc, MII_100T2CR, gig);
315 			PHY_WRITE(sc, MII_BMCR,
316 			    speed|BMCR_AUTOEN|BMCR_STARTNEG);
317 
318 			if (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701)
319 				break;
320 
321 			if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
322 				gig |= GTCR_MAN_MS | GTCR_ADV_MS;
323 			PHY_WRITE(sc, MII_100T2CR, gig);
324 			break;
325 		default:
326 			return (EINVAL);
327 		}
328 		break;
329 
330 	case MII_TICK:
331 		/*
332 		 * If we're not currently selected, just return.
333 		 */
334 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
335 			return (0);
336 
337 		if (mii_phy_tick(sc) == EJUSTRETURN)
338 			return (0);
339 		break;
340 
341 	case MII_DOWN:
342 		mii_phy_down(sc);
343 		return (0);
344 	}
345 
346 	/* Update the media status. */
347 	mii_phy_status(sc);
348 
349 	/*
350 	 * Callback if something changed. Note that we need to poke the DSP on
351 	 * the Broadcom PHYs if the media changes.
352 	 */
353 	if (sc->mii_media_active != mii->mii_media_active ||
354 	    sc->mii_media_status != mii->mii_media_status ||
355 	    cmd == MII_MEDIACHG) {
356 		switch (sc->mii_mpd_model) {
357 		case MII_MODEL_BROADCOM_BCM5400:
358 			brgphy_bcm5401_dspcode(sc);
359 			break;
360 		case MII_MODEL_BROADCOM_BCM5401:
361 			if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
362 				brgphy_bcm5401_dspcode(sc);
363 			break;
364 		case MII_MODEL_BROADCOM_BCM5411:
365 			brgphy_bcm5411_dspcode(sc);
366 			break;
367 		}
368 	}
369 
370 	/* Callback if something changed. */
371 	mii_phy_update(sc, cmd);
372 	return (0);
373 }
374 
375 static void
376 brgphy_status(struct mii_softc *sc)
377 {
378 	struct mii_data *mii = sc->mii_pdata;
379 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
380 	int bmcr, auxsts, gtsr;
381 
382 	mii->mii_media_status = IFM_AVALID;
383 	mii->mii_media_active = IFM_ETHER;
384 
385 	auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS);
386 
387 	if (auxsts & BRGPHY_AUXSTS_LINK)
388 		mii->mii_media_status |= IFM_ACTIVE;
389 
390 	bmcr = PHY_READ(sc, MII_BMCR);
391 	if (bmcr & BMCR_ISO) {
392 		mii->mii_media_active |= IFM_NONE;
393 		mii->mii_media_status = 0;
394 		return;
395 	}
396 
397 	if (bmcr & BMCR_LOOP)
398 		mii->mii_media_active |= IFM_LOOP;
399 
400 	if (bmcr & BMCR_AUTOEN) {
401 		/*
402 		 * The media status bits are only valid of autonegotiation
403 		 * has completed (or it's disabled).
404 		 */
405 		if ((auxsts & BRGPHY_AUXSTS_ACOMP) == 0) {
406 			/* Erg, still trying, I guess... */
407 			mii->mii_media_active |= IFM_NONE;
408 			return;
409 		}
410 
411 		switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
412 		case BRGPHY_RES_1000FD:
413 			mii->mii_media_active |= IFM_1000_T|IFM_FDX;
414 			gtsr = PHY_READ(sc, MII_100T2SR);
415 			if (gtsr & GTSR_MS_RES)
416 				mii->mii_media_active |= IFM_ETH_MASTER;
417 			break;
418 
419 		case BRGPHY_RES_1000HD:
420 			mii->mii_media_active |= IFM_1000_T;
421 			gtsr = PHY_READ(sc, MII_100T2SR);
422 			if (gtsr & GTSR_MS_RES)
423 				mii->mii_media_active |= IFM_ETH_MASTER;
424 			break;
425 
426 		case BRGPHY_RES_100FD:
427 			mii->mii_media_active |= IFM_100_TX|IFM_FDX;
428 			break;
429 
430 		case BRGPHY_RES_100T4:
431 			mii->mii_media_active |= IFM_100_T4;
432 			break;
433 
434 		case BRGPHY_RES_100HD:
435 			mii->mii_media_active |= IFM_100_TX;
436 			break;
437 
438 		case BRGPHY_RES_10FD:
439 			mii->mii_media_active |= IFM_10_T|IFM_FDX;
440 			break;
441 
442 		case BRGPHY_RES_10HD:
443 			mii->mii_media_active |= IFM_10_T;
444 			break;
445 
446 		default:
447 			mii->mii_media_active |= IFM_NONE;
448 			mii->mii_media_status = 0;
449 		}
450 		if (mii->mii_media_active & IFM_FDX)
451 			mii->mii_media_active |= mii_phy_flowstatus(sc);
452 	} else
453 		mii->mii_media_active = ife->ifm_media;
454 }
455 
456 int
457 brgphy_mii_phy_auto(struct mii_softc *sc)
458 {
459 	int anar, ktcr = 0;
460 
461 	brgphy_loop(sc);
462 	PHY_RESET(sc);
463 	ktcr = GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX;
464 	if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701)
465 		ktcr |= GTCR_MAN_MS|GTCR_ADV_MS;
466 	PHY_WRITE(sc, MII_100T2CR, ktcr);
467 	ktcr = PHY_READ(sc, MII_100T2CR);
468 	DELAY(1000);
469 	anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
470 	if (sc->mii_flags & MIIF_DOPAUSE)
471 		anar |= ANAR_FC| ANAR_X_PAUSE_ASYM;
472 
473 	PHY_WRITE(sc, MII_ANAR, anar);
474 	DELAY(1000);
475 	PHY_WRITE(sc, MII_BMCR,
476 	    BMCR_AUTOEN | BMCR_STARTNEG);
477 	PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
478 
479 	return (EJUSTRETURN);
480 }
481 
482 void
483 brgphy_loop(struct mii_softc *sc)
484 {
485 	u_int32_t bmsr;
486 	int i;
487 
488 	PHY_WRITE(sc, MII_BMCR, BMCR_LOOP);
489 	for (i = 0; i < 15000; i++) {
490 		bmsr = PHY_READ(sc, MII_BMSR);
491 		if (!(bmsr & BMSR_LINK))
492 			break;
493 		DELAY(10);
494 	}
495 }
496 
497 static void
498 brgphy_reset(struct mii_softc *sc)
499 {
500 	struct brgphy_softc *bsc = (void *)sc;
501 
502 	mii_phy_reset(sc);
503 
504 	switch (sc->mii_mpd_model) {
505 	case MII_MODEL_BROADCOM_BCM5400:
506 		brgphy_bcm5401_dspcode(sc);
507 		break;
508 	case MII_MODEL_BROADCOM_BCM5401:
509 		if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
510 			brgphy_bcm5401_dspcode(sc);
511 		break;
512 	case MII_MODEL_BROADCOM_BCM5411:
513 		brgphy_bcm5411_dspcode(sc);
514 		break;
515 	case MII_MODEL_BROADCOM_BCM5421:
516 		brgphy_bcm5421_dspcode(sc);
517 		break;
518 	case MII_MODEL_BROADCOM_BCM54K2:
519 		brgphy_bcm54k2_dspcode(sc);
520 		break;
521 	}
522 
523 	/* Handle any bge (NetXtreme/NetLink) workarounds. */
524 	if (bsc->sc_isbge != 0) {
525 		if (!(sc->mii_flags & MIIF_HAVEFIBER)) {
526 
527 			if (bsc->sc_bge_flags & BGE_PHY_ADC_BUG)
528 				brgphy_adc_bug(sc);
529 			if (bsc->sc_bge_flags & BGE_PHY_5704_A0_BUG)
530 				brgphy_5704_a0_bug(sc);
531 			if (bsc->sc_bge_flags & BGE_PHY_BER_BUG)
532 				brgphy_ber_bug(sc);
533 			else if (bsc->sc_bge_flags & BGE_PHY_JITTER_BUG) {
534 				PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00);
535 				PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG,
536 				    0x000a);
537 
538 				if (bsc->sc_bge_flags & BGE_PHY_ADJUST_TRIM) {
539 					PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT,
540 					    0x110b);
541 					PHY_WRITE(sc, BRGPHY_TEST1,
542 					    BRGPHY_TEST1_TRIM_EN | 0x4);
543 				} else {
544 					PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT,
545 					    0x010b);
546 				}
547 
548 				PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400);
549 			}
550 			if (bsc->sc_bge_flags & BGE_PHY_CRC_BUG)
551 				brgphy_crc_bug(sc);
552 
553 #if 0
554 			/* Set Jumbo frame settings in the PHY. */
555 			if (bsc->sc_bge_flags & BGE_JUMBO_CAP)
556 				brgphy_jumbo_settings(sc);
557 #endif
558 
559 			/* Adjust output voltage */
560 			if (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5906)
561 				PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12);
562 
563 #if 0
564 			/* Enable Ethernet@Wirespeed */
565 			if (!(bsc->sc_bge_flags & BGE_NO_ETH_WIRE_SPEED))
566 				brgphy_eth_wirespeed(sc);
567 
568 			/* Enable Link LED on Dell boxes */
569 			if (bsc->sc_bge_flags & BGE_NO_3LED) {
570 				PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
571 				PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL)
572 					& ~BRGPHY_PHY_EXTCTL_3_LED);
573 			}
574 #endif
575 		}
576 #if 0 /* not yet */
577 	/* Handle any bnx (NetXtreme II) workarounds. */
578 	} else if (sc->sc_isbnx != 0) {
579 		bnx_sc = sc->mii_pdata->mii_ifp->if_softc;
580 
581 		if (sc->mii_mpd_model == MII_MODEL_xxBROADCOM2_BCM5708S) {
582 			/* Store autoneg capabilities/results in digital block (Page 0) */
583 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2);
584 			PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0,
585 				BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE);
586 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0);
587 
588 			/* Enable fiber mode and autodetection */
589 			PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1,
590 				PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) |
591 				BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN |
592 				BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE);
593 
594 			/* Enable parallel detection */
595 			PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2,
596 				PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) |
597 				BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN);
598 
599 			/* Advertise 2.5G support through next page during autoneg */
600 			if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG)
601 				PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1,
602 					PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) |
603 					BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
604 
605 			/* Increase TX signal amplitude */
606 			if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) ||
607 			    (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) ||
608 			    (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) {
609 				PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
610 					BRGPHY_5708S_TX_MISC_PG5);
611 				PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1,
612 					PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) &
613 					~BRGPHY_5708S_PG5_TXACTL1_VCM);
614 				PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
615 					BRGPHY_5708S_DIG_PG0);
616 			}
617 
618 			/* Backplanes use special driver/pre-driver/pre-emphasis values. */
619 			if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) &&
620 			    (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) {
621 					PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
622 						BRGPHY_5708S_TX_MISC_PG5);
623 					PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3,
624 						bnx_sc->bnx_port_hw_cfg &
625 						BNX_PORT_HW_CFG_CFG_TXCTL3_MASK);
626 					PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
627 						BRGPHY_5708S_DIG_PG0);
628 			}
629 		} else {
630 			if (!(sc->mii_flags & MIIF_HAVEFIBER)) {
631 				brgphy_ber_bug(sc);
632 
633 				/* Set Jumbo frame settings in the PHY. */
634 				brgphy_jumbo_settings(sc);
635 
636 				/* Enable Ethernet@Wirespeed */
637 				brgphy_eth_wirespeed(sc);
638 			}
639 		}
640 #endif
641 	}
642 }
643 
644 /* Turn off tap power management on 5401. */
645 static void
646 brgphy_bcm5401_dspcode(struct mii_softc *sc)
647 {
648 	static const struct {
649 		int		reg;
650 		uint16_t	val;
651 	} dspcode[] = {
652 		{ BRGPHY_MII_AUXCTL,		0x0c20 },
653 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0012 },
654 		{ BRGPHY_MII_DSP_RW_PORT,	0x1804 },
655 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0013 },
656 		{ BRGPHY_MII_DSP_RW_PORT,	0x1204 },
657 		{ BRGPHY_MII_DSP_ADDR_REG,	0x8006 },
658 		{ BRGPHY_MII_DSP_RW_PORT,	0x0132 },
659 		{ BRGPHY_MII_DSP_ADDR_REG,	0x8006 },
660 		{ BRGPHY_MII_DSP_RW_PORT,	0x0232 },
661 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
662 		{ BRGPHY_MII_DSP_RW_PORT,	0x0a20 },
663 		{ 0,				0 },
664 	};
665 	int i;
666 
667 	for (i = 0; dspcode[i].reg != 0; i++)
668 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
669     delay(40);
670 }
671 
672 static void
673 brgphy_bcm5411_dspcode(struct mii_softc *sc)
674 {
675 	static const struct {
676 		int		reg;
677 		uint16_t	val;
678 	} dspcode[] = {
679 		{ 0x1c,				0x8c23 },
680 		{ 0x1c,				0x8ca3 },
681 		{ 0x1c,				0x8c23 },
682 		{ 0,				0 },
683 	};
684 	int i;
685 
686 	for (i = 0; dspcode[i].reg != 0; i++)
687 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
688 }
689 
690 void
691 brgphy_bcm5421_dspcode(struct mii_softc *sc)
692 {
693 	uint16_t data;
694 
695 	/* Set Class A mode */
696 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007);
697 	data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
698 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400);
699 
700 	/* Set FFE gamma override to -0.125 */
701 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007);
702 	data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
703 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800);
704 	PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
705 	data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
706 	PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200);
707 }
708 
709 void
710 brgphy_bcm54k2_dspcode(struct mii_softc *sc)
711 {
712 	static const struct {
713 		int		reg;
714 		uint16_t	val;
715 	} dspcode[] = {
716 		{ 4,				0x01e1 },
717 		{ 9,				0x0300 },
718 		{ 0,				0 },
719 	};
720 	int i;
721 
722 	for (i = 0; dspcode[i].reg != 0; i++)
723 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
724 }
725 
726 static void
727 brgphy_adc_bug(struct mii_softc *sc)
728 {
729 	static const struct {
730 		int		reg;
731 		uint16_t	val;
732 	} dspcode[] = {
733 		{ BRGPHY_MII_AUXCTL,		0x0c00 },
734 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
735 		{ BRGPHY_MII_DSP_RW_PORT,	0x2aaa },
736 		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
737 		{ BRGPHY_MII_DSP_RW_PORT,	0x0323 },
738 		{ BRGPHY_MII_AUXCTL,		0x0400 },
739 		{ 0,				0 },
740 	};
741 	int i;
742 
743 	for (i = 0; dspcode[i].reg != 0; i++)
744 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
745 }
746 
747 static void
748 brgphy_5704_a0_bug(struct mii_softc *sc)
749 {
750 	static const struct {
751 		int		reg;
752 		uint16_t	val;
753 	} dspcode[] = {
754 		{ 0x1c,				0x8d68 },
755 		{ 0x1c,				0x8d68 },
756 		{ 0,				0 },
757 	};
758 	int i;
759 
760 	for (i = 0; dspcode[i].reg != 0; i++)
761 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
762 }
763 
764 static void
765 brgphy_ber_bug(struct mii_softc *sc)
766 {
767 	static const struct {
768 		int		reg;
769 		uint16_t	val;
770 	} dspcode[] = {
771 		{ BRGPHY_MII_AUXCTL,		0x0c00 },
772 		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
773 		{ BRGPHY_MII_DSP_RW_PORT,	0x310b },
774 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
775 		{ BRGPHY_MII_DSP_RW_PORT,	0x9506 },
776 		{ BRGPHY_MII_DSP_ADDR_REG,	0x401f },
777 		{ BRGPHY_MII_DSP_RW_PORT,	0x14e2 },
778 		{ BRGPHY_MII_AUXCTL,		0x0400 },
779 		{ 0,				0 },
780 	};
781 	int i;
782 
783 	for (i = 0; dspcode[i].reg != 0; i++)
784 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
785 }
786 
787 /* BCM5701 A0/B0 CRC bug workaround */
788 void
789 brgphy_crc_bug(struct mii_softc *sc)
790 {
791 	static const struct {
792 		int		reg;
793 		uint16_t	val;
794 	} dspcode[] = {
795 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0a75 },
796 		{ 0x1c,				0x8c68 },
797 		{ 0x1c,				0x8d68 },
798 		{ 0x1c,				0x8c68 },
799 		{ 0,				0 },
800 	};
801 	int i;
802 
803 	for (i = 0; dspcode[i].reg != 0; i++)
804 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
805 }
806