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