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