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