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