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