1 /*- 2 * Copyright (c) 2000 3 * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 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 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 /* 37 * Driver for the Broadcom BCM54xx/57xx 1000baseTX PHY. 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/module.h> 44 #include <sys/socket.h> 45 #include <sys/bus.h> 46 47 #include <net/if.h> 48 #include <net/ethernet.h> 49 #include <net/if_media.h> 50 51 #include <dev/mii/mii.h> 52 #include <dev/mii/miivar.h> 53 #include "miidevs.h" 54 55 #include <dev/mii/brgphyreg.h> 56 #include <net/if_arp.h> 57 #include <machine/bus.h> 58 #include <dev/bge/if_bgereg.h> 59 #include <dev/bce/if_bcereg.h> 60 61 #include <dev/pci/pcireg.h> 62 #include <dev/pci/pcivar.h> 63 64 #include "miibus_if.h" 65 66 static int brgphy_probe(device_t); 67 static int brgphy_attach(device_t); 68 69 struct brgphy_softc { 70 struct mii_softc mii_sc; 71 int mii_model; 72 int mii_rev; 73 }; 74 75 static device_method_t brgphy_methods[] = { 76 /* device interface */ 77 DEVMETHOD(device_probe, brgphy_probe), 78 DEVMETHOD(device_attach, brgphy_attach), 79 DEVMETHOD(device_detach, mii_phy_detach), 80 DEVMETHOD(device_shutdown, bus_generic_shutdown), 81 { 0, 0 } 82 }; 83 84 static devclass_t brgphy_devclass; 85 86 static driver_t brgphy_driver = { 87 "brgphy", 88 brgphy_methods, 89 sizeof(struct brgphy_softc) 90 }; 91 92 DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0); 93 94 static int brgphy_service(struct mii_softc *, struct mii_data *, int); 95 static void brgphy_setmedia(struct mii_softc *, int, int); 96 static void brgphy_status(struct mii_softc *); 97 static int brgphy_mii_phy_auto(struct mii_softc *); 98 static void brgphy_reset(struct mii_softc *); 99 static void brgphy_loop(struct mii_softc *); 100 static int bcm5706_is_tbi(device_t); 101 static void bcm5401_load_dspcode(struct mii_softc *); 102 static void bcm5411_load_dspcode(struct mii_softc *); 103 static void brgphy_fixup_5704_a0_bug(struct mii_softc *); 104 static void brgphy_fixup_adc_bug(struct mii_softc *); 105 static void brgphy_fixup_adjust_trim(struct mii_softc *); 106 static void brgphy_fixup_ber_bug(struct mii_softc *); 107 static void brgphy_fixup_crc_bug(struct mii_softc *); 108 static void brgphy_fixup_jitter_bug(struct mii_softc *); 109 static void brgphy_ethernet_wirespeed(struct mii_softc *); 110 static void brgphy_jumbo_settings(struct mii_softc *, u_long); 111 112 static const struct mii_phydesc brgphys[] = { 113 MII_PHY_DESC(xxBROADCOM, BCM5400), 114 MII_PHY_DESC(xxBROADCOM, BCM5401), 115 MII_PHY_DESC(xxBROADCOM, BCM5411), 116 MII_PHY_DESC(xxBROADCOM, BCM5701), 117 MII_PHY_DESC(xxBROADCOM, BCM5703), 118 MII_PHY_DESC(xxBROADCOM, BCM5704), 119 MII_PHY_DESC(xxBROADCOM, BCM5705), 120 MII_PHY_DESC(xxBROADCOM, BCM5706C), 121 MII_PHY_DESC(xxBROADCOM, BCM5714), 122 MII_PHY_DESC(xxBROADCOM, BCM5750), 123 MII_PHY_DESC(xxBROADCOM, BCM5752), 124 MII_PHY_DESC(xxBROADCOM, BCM5754), 125 MII_PHY_DESC(xxBROADCOM, BCM5780), 126 MII_PHY_DESC(xxBROADCOM, BCM5708C), 127 MII_PHY_DESC(xxBROADCOM_ALT1, BCM5755), 128 MII_PHY_DESC(xxBROADCOM_ALT1, BCM5787), 129 MII_PHY_END 130 }; 131 132 static int 133 brgphy_probe(device_t dev) 134 { 135 struct mii_attach_args *ma; 136 int error; 137 138 error = mii_phy_dev_probe(dev, brgphys, BUS_PROBE_DEFAULT); 139 if (error != BUS_PROBE_DEFAULT) 140 return (error); 141 142 ma = device_get_ivars(dev); 143 if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM && 144 MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5706C) { 145 /* 146 * Broadcom uses the same MII model ID on two 147 * different types of phys. The first is found on the 148 * BCM 5706 and is supported by this driver. The 149 * other is found on the BCM 5706S and 5708S and is 150 * supported by the gentbi(4) driver, so we check to 151 * see if this phy is supported by gentbi(4) and fail 152 * the probe if so. 153 */ 154 if (bcm5706_is_tbi(dev)) 155 return (ENXIO); 156 } 157 return (error); 158 } 159 160 static int 161 brgphy_attach(device_t dev) 162 { 163 struct brgphy_softc *bsc; 164 struct mii_softc *sc; 165 struct mii_attach_args *ma; 166 struct mii_data *mii; 167 168 bsc = device_get_softc(dev); 169 sc = &bsc->mii_sc; 170 ma = device_get_ivars(dev); 171 sc->mii_dev = device_get_parent(dev); 172 mii = device_get_softc(sc->mii_dev); 173 174 /* 175 * At least some variants wedge when isolating, so never allow 176 * non-zero instances! At least some also don't support loopback. 177 */ 178 if (mii->mii_instance != 0) 179 panic("%s: ignoring this PHY, non-zero instance", __func__); 180 181 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 182 183 sc->mii_inst = mii->mii_instance; 184 sc->mii_phy = ma->mii_phyno; 185 sc->mii_service = brgphy_service; 186 sc->mii_pdata = mii; 187 188 sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; 189 mii->mii_instance++; 190 191 bsc->mii_model = MII_MODEL(ma->mii_id2); 192 bsc->mii_rev = MII_REV(ma->mii_id2); 193 brgphy_reset(sc); 194 195 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 196 if (sc->mii_capabilities & BMSR_EXTSTAT) 197 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 198 device_printf(dev, " "); 199 mii_phy_add_media(sc); 200 printf("\n"); 201 202 MIIBUS_MEDIAINIT(sc->mii_dev); 203 return (0); 204 } 205 206 static int 207 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 208 { 209 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 210 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 211 212 switch (cmd) { 213 case MII_POLLSTAT: 214 /* If we're not polling our PHY instance, just return. */ 215 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 216 return (0); 217 break; 218 case MII_MEDIACHG: 219 /* If the interface is not up, don't do anything. */ 220 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 221 break; 222 223 brgphy_reset(sc); /* XXX hardware bug work-around */ 224 225 switch (IFM_SUBTYPE(ife->ifm_media)) { 226 case IFM_AUTO: 227 #ifdef foo 228 /* If we're already in auto mode, just return. */ 229 if (PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_AUTOEN) 230 return (0); 231 #endif 232 (void)brgphy_mii_phy_auto(sc); 233 break; 234 case IFM_1000_T: 235 case IFM_100_TX: 236 case IFM_10_T: 237 brgphy_setmedia(sc, ife->ifm_media, 238 mii->mii_ifp->if_flags & IFF_LINK0); 239 break; 240 default: 241 return (EINVAL); 242 } 243 break; 244 case MII_TICK: 245 /* If we're not currently selected, just return. */ 246 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 247 return (0); 248 249 /* Is the interface even up? */ 250 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 251 return (0); 252 253 /* Only used for autonegotiation. */ 254 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 255 sc->mii_ticks = 0; /* Reset autoneg timer. */ 256 break; 257 } 258 259 /* 260 * Check to see if we have link. If we do, we don't 261 * need to restart the autonegotiation process. 262 */ 263 if (PHY_READ(sc, BRGPHY_MII_AUXSTS) & BRGPHY_AUXSTS_LINK) { 264 sc->mii_ticks = 0; /* Reset autoneg timer. */ 265 break; 266 } 267 268 /* Announce link loss right after it happens. */ 269 if (sc->mii_ticks++ == 0) 270 break; 271 272 /* Only retry autonegotiation every mii_anegticks seconds. */ 273 if (sc->mii_ticks <= sc->mii_anegticks) 274 return (0); 275 276 sc->mii_ticks = 0; 277 (void)brgphy_mii_phy_auto(sc); 278 break; 279 } 280 281 /* Update the media status. */ 282 brgphy_status(sc); 283 284 /* 285 * Callback if something changed. Note that we need to poke 286 * the DSP on the Broadcom PHYs if the media changes. 287 */ 288 if (sc->mii_media_active != mii->mii_media_active || 289 sc->mii_media_status != mii->mii_media_status || 290 cmd == MII_MEDIACHG) { 291 switch (bsc->mii_model) { 292 case MII_MODEL_xxBROADCOM_BCM5400: 293 bcm5401_load_dspcode(sc); 294 break; 295 case MII_MODEL_xxBROADCOM_BCM5401: 296 if (bsc->mii_rev == 1 || bsc->mii_rev == 3) 297 bcm5401_load_dspcode(sc); 298 break; 299 case MII_MODEL_xxBROADCOM_BCM5411: 300 bcm5411_load_dspcode(sc); 301 break; 302 } 303 } 304 mii_phy_update(sc, cmd); 305 return (0); 306 } 307 308 static void 309 brgphy_setmedia(struct mii_softc *sc, int media, int master) 310 { 311 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 312 int bmcr, gig; 313 314 switch (IFM_SUBTYPE(media)) { 315 case IFM_1000_T: 316 bmcr = BRGPHY_S1000; 317 break; 318 case IFM_100_TX: 319 bmcr = BRGPHY_S100; 320 break; 321 case IFM_10_T: 322 default: 323 bmcr = BRGPHY_S10; 324 break; 325 } 326 if ((media & IFM_GMASK) == IFM_FDX) { 327 bmcr |= BRGPHY_BMCR_FDX; 328 gig = BRGPHY_1000CTL_AFD; 329 } else { 330 gig = BRGPHY_1000CTL_AHD; 331 } 332 333 brgphy_loop(sc); 334 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); 335 PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr); 336 PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); 337 338 if (IFM_SUBTYPE(media) != IFM_1000_T) 339 return; 340 341 PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); 342 PHY_WRITE(sc, BRGPHY_MII_BMCR, 343 bmcr | BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); 344 345 if (bsc->mii_model != MII_MODEL_xxBROADCOM_BCM5701) 346 return; 347 348 /* 349 * When setting the link manually, one side must be the master and 350 * the other the slave. However ifmedia doesn't give us a good way 351 * to specify this, so we fake it by using one of the LINK flags. 352 * If LINK0 is set, we program the PHY to be a master, otherwise 353 * it's a slave. 354 */ 355 if (master) { 356 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 357 gig | BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC); 358 } else { 359 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 360 gig | BRGPHY_1000CTL_MSE); 361 } 362 } 363 364 static void 365 brgphy_status(struct mii_softc *sc) 366 { 367 struct mii_data *mii = sc->mii_pdata; 368 int aux, bmcr, bmsr; 369 370 mii->mii_media_status = IFM_AVALID; 371 mii->mii_media_active = IFM_ETHER; 372 373 aux = PHY_READ(sc, BRGPHY_MII_AUXSTS); 374 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 375 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); 376 377 if (aux & BRGPHY_AUXSTS_LINK) 378 mii->mii_media_status |= IFM_ACTIVE; 379 380 if (bmcr & BRGPHY_BMCR_LOOP) 381 mii->mii_media_active |= IFM_LOOP; 382 383 if ((bmcr & BRGPHY_BMCR_AUTOEN) && 384 (bmsr & BRGPHY_BMSR_ACOMP) == 0) { 385 /* Erg, still trying, I guess... */ 386 mii->mii_media_active |= IFM_NONE; 387 return; 388 } 389 390 if (aux & BRGPHY_AUXSTS_LINK) { 391 switch (aux & BRGPHY_AUXSTS_AN_RES) { 392 case BRGPHY_RES_1000FD: 393 mii->mii_media_active |= IFM_1000_T | IFM_FDX; 394 break; 395 case BRGPHY_RES_1000HD: 396 mii->mii_media_active |= IFM_1000_T | IFM_HDX; 397 break; 398 case BRGPHY_RES_100FD: 399 mii->mii_media_active |= IFM_100_TX | IFM_FDX; 400 break; 401 case BRGPHY_RES_100T4: 402 mii->mii_media_active |= IFM_100_T4; 403 break; 404 case BRGPHY_RES_100HD: 405 mii->mii_media_active |= IFM_100_TX | IFM_HDX; 406 break; 407 case BRGPHY_RES_10FD: 408 mii->mii_media_active |= IFM_10_T | IFM_FDX; 409 break; 410 case BRGPHY_RES_10HD: 411 mii->mii_media_active |= IFM_10_T | IFM_HDX; 412 break; 413 default: 414 mii->mii_media_active |= IFM_NONE; 415 break; 416 } 417 } else 418 mii->mii_media_active |= IFM_NONE; 419 } 420 421 static int 422 brgphy_mii_phy_auto(struct mii_softc *sc) 423 { 424 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 425 int ktcr = 0; 426 427 brgphy_loop(sc); 428 brgphy_reset(sc); 429 ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD; 430 if (bsc->mii_model == MII_MODEL_xxBROADCOM_BCM5701) 431 ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC; 432 PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr); 433 ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL); 434 DELAY(1000); 435 PHY_WRITE(sc, BRGPHY_MII_ANAR, 436 BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA); 437 DELAY(1000); 438 PHY_WRITE(sc, BRGPHY_MII_BMCR, 439 BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); 440 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); 441 return (EJUSTRETURN); 442 } 443 444 static void 445 brgphy_loop(struct mii_softc *sc) 446 { 447 int i; 448 449 PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); 450 for (i = 0; i < 15000; i++) { 451 if (!(PHY_READ(sc, BRGPHY_MII_BMSR) & BRGPHY_BMSR_LINK)) { 452 #if 0 453 device_printf(sc->mii_dev, "looped %d\n", i); 454 #endif 455 break; 456 } 457 DELAY(10); 458 } 459 } 460 461 /* 462 * Check to see if a 5706 phy is really a SerDes phy. Copied from 463 * gentbi_probe(). 464 */ 465 static int 466 bcm5706_is_tbi(device_t dev) 467 { 468 device_t parent; 469 struct mii_attach_args *ma; 470 int bmsr, extsr; 471 472 parent = device_get_parent(dev); 473 ma = device_get_ivars(dev); 474 475 bmsr = MIIBUS_READREG(parent, ma->mii_phyno, MII_BMSR); 476 if ((bmsr & BMSR_EXTSTAT) == 0 || (bmsr & BMSR_MEDIAMASK) != 0) 477 return (0); 478 479 extsr = MIIBUS_READREG(parent, ma->mii_phyno, MII_EXTSR); 480 if (extsr & (EXTSR_1000TFDX|EXTSR_1000THDX)) 481 return (0); 482 483 if (extsr & (EXTSR_1000XFDX|EXTSR_1000XHDX)) 484 return (1); 485 486 return (0); 487 } 488 489 /* Turn off tap power management on 5401. */ 490 static void 491 bcm5401_load_dspcode(struct mii_softc *sc) 492 { 493 static const struct { 494 int reg; 495 uint16_t val; 496 } dspcode[] = { 497 { BRGPHY_MII_AUXCTL, 0x0c20 }, 498 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 499 { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 500 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 501 { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 502 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 503 { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 504 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 505 { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 506 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 507 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 508 { 0, 0 }, 509 }; 510 int i; 511 512 for (i = 0; dspcode[i].reg != 0; i++) 513 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 514 DELAY(40); 515 } 516 517 static void 518 bcm5411_load_dspcode(struct mii_softc *sc) 519 { 520 static const struct { 521 int reg; 522 uint16_t val; 523 } dspcode[] = { 524 { 0x1c, 0x8c23 }, 525 { 0x1c, 0x8ca3 }, 526 { 0x1c, 0x8c23 }, 527 { 0, 0 }, 528 }; 529 int i; 530 531 for (i = 0; dspcode[i].reg != 0; i++) 532 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 533 } 534 535 static void 536 brgphy_fixup_5704_a0_bug(struct mii_softc *sc) 537 { 538 static const struct { 539 int reg; 540 uint16_t val; 541 } dspcode[] = { 542 { 0x1c, 0x8d68 }, 543 { 0x1c, 0x8d68 }, 544 { 0, 0 }, 545 }; 546 int i; 547 548 for (i = 0; dspcode[i].reg != 0; i++) 549 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 550 } 551 552 static void 553 brgphy_fixup_adc_bug(struct mii_softc *sc) 554 { 555 static const struct { 556 int reg; 557 uint16_t val; 558 } dspcode[] = { 559 { BRGPHY_MII_AUXCTL, 0x0c00 }, 560 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 561 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 562 { 0, 0 }, 563 }; 564 int i; 565 566 for (i = 0; dspcode[i].reg != 0; i++) 567 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 568 } 569 570 static void 571 brgphy_fixup_adjust_trim(struct mii_softc *sc) 572 { 573 static const struct { 574 int reg; 575 uint16_t val; 576 } dspcode[] = { 577 { BRGPHY_MII_AUXCTL, 0x0c00 }, 578 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 579 { BRGPHY_MII_DSP_RW_PORT, 0x110b }, 580 { BRGPHY_MII_TEST1, 0x0014 }, 581 { BRGPHY_MII_AUXCTL, 0x0400 }, 582 { 0, 0 }, 583 }; 584 int i; 585 586 for (i = 0; dspcode[i].reg != 0; i++) 587 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 588 } 589 590 static void 591 brgphy_fixup_ber_bug(struct mii_softc *sc) 592 { 593 static const struct { 594 int reg; 595 uint16_t val; 596 } dspcode[] = { 597 { BRGPHY_MII_AUXCTL, 0x0c00 }, 598 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 599 { BRGPHY_MII_DSP_RW_PORT, 0x310b }, 600 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 601 { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, 602 { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, 603 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, 604 { BRGPHY_MII_AUXCTL, 0x0400 }, 605 { 0, 0 }, 606 }; 607 int i; 608 609 for (i = 0; dspcode[i].reg != 0; i++) 610 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 611 } 612 613 static void 614 brgphy_fixup_crc_bug(struct mii_softc *sc) 615 { 616 static const struct { 617 int reg; 618 uint16_t val; 619 } dspcode[] = { 620 { BRGPHY_MII_DSP_RW_PORT, 0x0a75 }, 621 { 0x1c, 0x8c68 }, 622 { 0x1c, 0x8d68 }, 623 { 0x1c, 0x8c68 }, 624 { 0, 0 }, 625 }; 626 int i; 627 628 for (i = 0; dspcode[i].reg != 0; i++) 629 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 630 } 631 632 static void 633 brgphy_fixup_jitter_bug(struct mii_softc *sc) 634 { 635 static const struct { 636 int reg; 637 uint16_t val; 638 } dspcode[] = { 639 { BRGPHY_MII_AUXCTL, 0x0c00 }, 640 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 641 { BRGPHY_MII_DSP_RW_PORT, 0x010b }, 642 { BRGPHY_MII_AUXCTL, 0x0400 }, 643 { 0, 0 }, 644 }; 645 int i; 646 647 for (i = 0; dspcode[i].reg != 0; i++) 648 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 649 } 650 651 static void 652 brgphy_ethernet_wirespeed(struct mii_softc *sc) 653 { 654 uint32_t val; 655 656 /* Enable Ethernet@WireSpeed. */ 657 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 658 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 659 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4)); 660 } 661 662 static void 663 brgphy_jumbo_settings(struct mii_softc *sc, u_long mtu) 664 { 665 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 666 uint32_t val; 667 668 /* Set or clear jumbo frame settings in the PHY. */ 669 if (mtu > ETHER_MAX_LEN) { 670 if (bsc->mii_model == MII_MODEL_xxBROADCOM_BCM5401) { 671 /* BCM5401 PHY cannot read-modify-write. */ 672 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); 673 } else { 674 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 675 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 676 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 677 val | BRGPHY_AUXCTL_LONG_PKT); 678 } 679 680 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 681 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 682 val | BRGPHY_PHY_EXTCTL_HIGH_LA); 683 } else { 684 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 685 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 686 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 687 val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); 688 689 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 690 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 691 val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); 692 } 693 } 694 695 static void 696 brgphy_reset(struct mii_softc *sc) 697 { 698 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 699 struct bge_softc *bge_sc = NULL; 700 struct bce_softc *bce_sc = NULL; 701 struct ifnet *ifp; 702 703 mii_phy_reset(sc); 704 705 switch (bsc->mii_model) { 706 case MII_MODEL_xxBROADCOM_BCM5400: 707 bcm5401_load_dspcode(sc); 708 break; 709 case MII_MODEL_xxBROADCOM_BCM5401: 710 if (bsc->mii_rev == 1 || bsc->mii_rev == 3) 711 bcm5401_load_dspcode(sc); 712 break; 713 case MII_MODEL_xxBROADCOM_BCM5411: 714 bcm5411_load_dspcode(sc); 715 break; 716 } 717 718 ifp = sc->mii_pdata->mii_ifp; 719 720 /* Find the driver associated with this PHY. */ 721 if (strcmp(ifp->if_dname, "bge") == 0) { 722 bge_sc = ifp->if_softc; 723 } else if (strcmp(ifp->if_dname, "bce") == 0) { 724 bce_sc = ifp->if_softc; 725 } 726 727 /* Handle any NetXtreme/bge workarounds. */ 728 if (bge_sc) { 729 /* Fix up various bugs */ 730 if (bge_sc->bge_flags & BGE_FLAG_5704_A0_BUG) 731 brgphy_fixup_5704_a0_bug(sc); 732 if (bge_sc->bge_flags & BGE_FLAG_ADC_BUG) 733 brgphy_fixup_adc_bug(sc); 734 if (bge_sc->bge_flags & BGE_FLAG_ADJUST_TRIM) 735 brgphy_fixup_adjust_trim(sc); 736 if (bge_sc->bge_flags & BGE_FLAG_BER_BUG) 737 brgphy_fixup_ber_bug(sc); 738 if (bge_sc->bge_flags & BGE_FLAG_CRC_BUG) 739 brgphy_fixup_crc_bug(sc); 740 if (bge_sc->bge_flags & BGE_FLAG_JITTER_BUG) 741 brgphy_fixup_jitter_bug(sc); 742 743 brgphy_jumbo_settings(sc, ifp->if_mtu); 744 745 /* 746 * Don't enable Ethernet@WireSpeed for the 5700 or the 747 * 5705 A1 and A2 chips. 748 */ 749 if (bge_sc->bge_asicrev != BGE_ASICREV_BCM5700 && 750 bge_sc->bge_chipid != BGE_CHIPID_BCM5705_A1 && 751 bge_sc->bge_chipid != BGE_CHIPID_BCM5705_A2) 752 brgphy_ethernet_wirespeed(sc); 753 754 /* Enable Link LED on Dell boxes */ 755 if (bge_sc->bge_flags & BGE_FLAG_NO_3LED) { 756 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 757 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) & 758 ~BRGPHY_PHY_EXTCTL_3_LED); 759 } 760 } else if (bce_sc) { 761 brgphy_fixup_ber_bug(sc); 762 brgphy_jumbo_settings(sc, ifp->if_mtu); 763 brgphy_ethernet_wirespeed(sc); 764 } 765 } 766