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_oui; 72 int mii_model; 73 int mii_rev; 74 int serdes_flags; /* Keeps track of the serdes type used */ 75 #define BRGPHY_5706S 0x0001 76 #define BRGPHY_5708S 0x0002 77 int bce_phy_flags; /* PHY flags transferred from the MAC driver */ 78 }; 79 80 static device_method_t brgphy_methods[] = { 81 /* device interface */ 82 DEVMETHOD(device_probe, brgphy_probe), 83 DEVMETHOD(device_attach, brgphy_attach), 84 DEVMETHOD(device_detach, mii_phy_detach), 85 DEVMETHOD(device_shutdown, bus_generic_shutdown), 86 { 0, 0 } 87 }; 88 89 static devclass_t brgphy_devclass; 90 91 static driver_t brgphy_driver = { 92 "brgphy", 93 brgphy_methods, 94 sizeof(struct brgphy_softc) 95 }; 96 97 DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0); 98 99 static int brgphy_service(struct mii_softc *, struct mii_data *, int); 100 static void brgphy_setmedia(struct mii_softc *, int, int); 101 static void brgphy_status(struct mii_softc *); 102 static void brgphy_mii_phy_auto(struct mii_softc *); 103 static void brgphy_reset(struct mii_softc *); 104 static void brgphy_enable_loopback(struct mii_softc *); 105 static void bcm5401_load_dspcode(struct mii_softc *); 106 static void bcm5411_load_dspcode(struct mii_softc *); 107 static void brgphy_fixup_5704_a0_bug(struct mii_softc *); 108 static void brgphy_fixup_adc_bug(struct mii_softc *); 109 static void brgphy_fixup_adjust_trim(struct mii_softc *); 110 static void brgphy_fixup_ber_bug(struct mii_softc *); 111 static void brgphy_fixup_crc_bug(struct mii_softc *); 112 static void brgphy_fixup_jitter_bug(struct mii_softc *); 113 static void brgphy_ethernet_wirespeed(struct mii_softc *); 114 static void brgphy_jumbo_settings(struct mii_softc *, u_long); 115 116 static const struct mii_phydesc brgphys[] = { 117 MII_PHY_DESC(xxBROADCOM, BCM5400), 118 MII_PHY_DESC(xxBROADCOM, BCM5401), 119 MII_PHY_DESC(xxBROADCOM, BCM5411), 120 MII_PHY_DESC(xxBROADCOM, BCM5701), 121 MII_PHY_DESC(xxBROADCOM, BCM5703), 122 MII_PHY_DESC(xxBROADCOM, BCM5704), 123 MII_PHY_DESC(xxBROADCOM, BCM5705), 124 MII_PHY_DESC(xxBROADCOM, BCM5706), 125 MII_PHY_DESC(xxBROADCOM, BCM5714), 126 MII_PHY_DESC(xxBROADCOM, BCM5750), 127 MII_PHY_DESC(xxBROADCOM, BCM5752), 128 MII_PHY_DESC(xxBROADCOM, BCM5754), 129 MII_PHY_DESC(xxBROADCOM, BCM5780), 130 MII_PHY_DESC(xxBROADCOM, BCM5708C), 131 MII_PHY_DESC(xxBROADCOM_ALT1, BCM5755), 132 MII_PHY_DESC(xxBROADCOM_ALT1, BCM5787), 133 MII_PHY_DESC(xxBROADCOM_ALT1, BCM5708S), 134 MII_PHY_END 135 }; 136 137 138 /* Search for our PHY in the list of known PHYs */ 139 static int 140 brgphy_probe(device_t dev) 141 { 142 return (mii_phy_dev_probe(dev, brgphys, BUS_PROBE_DEFAULT)); 143 } 144 145 /* Attach the PHY to the MII bus */ 146 static int 147 brgphy_attach(device_t dev) 148 { 149 struct brgphy_softc *bsc; 150 struct bge_softc *bge_sc = NULL; 151 struct bce_softc *bce_sc = NULL; 152 struct mii_softc *sc; 153 struct mii_attach_args *ma; 154 struct mii_data *mii; 155 struct ifnet *ifp; 156 int fast_ether; 157 158 bsc = device_get_softc(dev); 159 sc = &bsc->mii_sc; 160 ma = device_get_ivars(dev); 161 sc->mii_dev = device_get_parent(dev); 162 mii = device_get_softc(sc->mii_dev); 163 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 164 165 /* Initialize mii_softc structure */ 166 sc->mii_inst = mii->mii_instance; 167 sc->mii_phy = ma->mii_phyno; 168 sc->mii_service = brgphy_service; 169 sc->mii_pdata = mii; 170 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 171 sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; 172 mii->mii_instance++; 173 174 /* Initialize brgphy_softc structure */ 175 bsc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2); 176 bsc->mii_model = MII_MODEL(ma->mii_id2); 177 bsc->mii_rev = MII_REV(ma->mii_id2); 178 bsc->serdes_flags = 0; 179 180 fast_ether = 0; 181 182 if (bootverbose) 183 device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n", 184 bsc->mii_oui, bsc->mii_model, bsc->mii_rev); 185 186 /* Handle any special cases based on the PHY ID */ 187 switch (bsc->mii_oui) { 188 case MII_OUI_BROADCOM: 189 break; 190 case MII_OUI_xxBROADCOM: 191 switch (bsc->mii_model) { 192 case MII_MODEL_xxBROADCOM_BCM5706: 193 /* 194 * The 5464 PHY used in the 5706 supports both copper 195 * and fiber interfaces over GMII. Need to check the 196 * shadow registers to see which mode is actually 197 * in effect, and therefore whether we have 5706C or 198 * 5706S. 199 */ 200 PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, 201 BRGPHY_SHADOW_1C_MODE_CTRL); 202 if (PHY_READ(sc, BRGPHY_MII_SHADOW_1C) & 203 BRGPHY_SHADOW_1C_ENA_1000X) { 204 bsc->serdes_flags |= BRGPHY_5706S; 205 sc->mii_flags |= MIIF_HAVEFIBER; 206 } 207 break; 208 } break; 209 case MII_OUI_xxBROADCOM_ALT1: 210 switch (bsc->mii_model) { 211 case MII_MODEL_xxBROADCOM_ALT1_BCM5708S: 212 bsc->serdes_flags |= BRGPHY_5708S; 213 sc->mii_flags |= MIIF_HAVEFIBER; 214 break; 215 } break; 216 default: 217 device_printf(dev, "Unrecognized OUI for PHY!\n"); 218 } 219 220 ifp = sc->mii_pdata->mii_ifp; 221 222 /* Find the MAC driver associated with this PHY. */ 223 if (strcmp(ifp->if_dname, "bge") == 0) { 224 bge_sc = ifp->if_softc; 225 } else if (strcmp(ifp->if_dname, "bce") == 0) { 226 bce_sc = ifp->if_softc; 227 } 228 229 /* Todo: Need to add additional controllers such as 5906 & 5787F */ 230 /* The 590x chips are 10/100 only. */ 231 if (bge_sc && 232 pci_get_vendor(bge_sc->bge_dev) == BCOM_VENDORID && 233 (pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901 || 234 pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2)) { 235 fast_ether = 1; 236 sc->mii_anegticks = MII_ANEGTICKS; 237 } 238 239 brgphy_reset(sc); 240 241 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 242 if (sc->mii_capabilities & BMSR_EXTSTAT) 243 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 244 device_printf(dev, " "); 245 246 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 247 248 /* Create an instance of Ethernet media. */ 249 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), BMCR_ISO); 250 251 /* Add the supported media types */ 252 if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 253 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 254 BRGPHY_S10); 255 printf("10baseT, "); 256 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), 257 BRGPHY_S10 | BRGPHY_BMCR_FDX); 258 printf("10baseT-FDX, "); 259 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), 260 BRGPHY_S100); 261 printf("100baseTX, "); 262 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), 263 BRGPHY_S100 | BRGPHY_BMCR_FDX); 264 printf("100baseTX-FDX, "); 265 if (fast_ether == 0) { 266 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), 267 BRGPHY_S1000); 268 printf("1000baseT, "); 269 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), 270 BRGPHY_S1000 | BRGPHY_BMCR_FDX); 271 printf("1000baseT-FDX, "); 272 } 273 } else { 274 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 275 BRGPHY_S1000 | BRGPHY_BMCR_FDX); 276 printf("1000baseSX-FDX, "); 277 /* 2.5G support is a software enabled feature on the 5708S */ 278 if (bce_sc && (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) { 279 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, sc->mii_inst), 0); 280 printf("2500baseSX-FDX, "); 281 } 282 } 283 284 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); 285 printf("auto\n"); 286 287 #undef ADD 288 MIIBUS_MEDIAINIT(sc->mii_dev); 289 return (0); 290 } 291 292 static int 293 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 294 { 295 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 296 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 297 int error = 0; 298 int val; 299 300 switch (cmd) { 301 case MII_POLLSTAT: 302 /* If we're not polling our PHY instance, just return. */ 303 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 304 goto brgphy_service_exit; 305 break; 306 case MII_MEDIACHG: 307 /* 308 * If the media indicates a different PHY instance, 309 * isolate ourselves. 310 */ 311 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 312 PHY_WRITE(sc, MII_BMCR, 313 PHY_READ(sc, MII_BMCR) | BMCR_ISO); 314 goto brgphy_service_exit; 315 } 316 317 /* If the interface is not up, don't do anything. */ 318 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 319 break; 320 321 /* Todo: Why is this here? Is it really needed? */ 322 brgphy_reset(sc); /* XXX hardware bug work-around */ 323 324 switch (IFM_SUBTYPE(ife->ifm_media)) { 325 case IFM_AUTO: 326 brgphy_mii_phy_auto(sc); 327 break; 328 case IFM_2500_SX: 329 case IFM_1000_SX: 330 case IFM_1000_T: 331 case IFM_100_TX: 332 case IFM_10_T: 333 brgphy_setmedia(sc, ife->ifm_media, 334 mii->mii_ifp->if_flags & IFF_LINK0); 335 break; 336 default: 337 error = EINVAL; 338 goto brgphy_service_exit; 339 } 340 break; 341 case MII_TICK: 342 /* Bail if we're not currently selected. */ 343 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 344 goto brgphy_service_exit; 345 346 /* Bail if the interface isn't up. */ 347 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 348 goto brgphy_service_exit; 349 350 351 /* Bail if autoneg isn't in process. */ 352 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 353 sc->mii_ticks = 0; 354 break; 355 } 356 357 /* 358 * Check to see if we have link. If we do, we don't 359 * need to restart the autonegotiation process. 360 */ 361 val = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 362 if (val & BMSR_LINK) { 363 sc->mii_ticks = 0; /* Reset autoneg timer. */ 364 break; 365 } 366 367 #if 0 368 /* Todo: Is this correct? */ 369 /* Announce link loss right after it happens. */ 370 if (sc->mii_ticks++ == 0) 371 break; 372 #endif 373 374 /* Only retry autonegotiation every mii_anegticks seconds. */ 375 if (sc->mii_ticks <= sc->mii_anegticks) 376 goto brgphy_service_exit; 377 378 379 /* Retry autonegotiation */ 380 sc->mii_ticks = 0; 381 brgphy_mii_phy_auto(sc); 382 break; 383 } 384 385 /* Update the media status. */ 386 brgphy_status(sc); 387 388 /* 389 * Callback if something changed. Note that we need to poke 390 * the DSP on the Broadcom PHYs if the media changes. 391 */ 392 if (sc->mii_media_active != mii->mii_media_active || 393 sc->mii_media_status != mii->mii_media_status || 394 cmd == MII_MEDIACHG) { 395 switch (bsc->mii_oui) { 396 case MII_OUI_BROADCOM: 397 break; 398 case MII_OUI_xxBROADCOM: 399 switch (bsc->mii_model) { 400 case MII_MODEL_xxBROADCOM_BCM5400: 401 bcm5401_load_dspcode(sc); 402 break; 403 case MII_MODEL_xxBROADCOM_BCM5401: 404 if (bsc->mii_rev == 1 || bsc->mii_rev == 3) 405 bcm5401_load_dspcode(sc); 406 break; 407 case MII_MODEL_xxBROADCOM_BCM5411: 408 bcm5411_load_dspcode(sc); 409 break; 410 } 411 break; 412 case MII_OUI_xxBROADCOM_ALT1: 413 break; 414 } 415 } 416 mii_phy_update(sc, cmd); 417 brgphy_service_exit: 418 return (error); 419 } 420 421 static void 422 brgphy_setmedia(struct mii_softc *sc, int media, int master) 423 { 424 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 425 int bmcr = 0, gig; 426 427 switch (IFM_SUBTYPE(media)) { 428 case IFM_2500_SX: 429 break; 430 case IFM_1000_SX: 431 case IFM_1000_T: 432 bmcr = BRGPHY_S1000; 433 break; 434 case IFM_100_TX: 435 bmcr = BRGPHY_S100; 436 break; 437 case IFM_10_T: 438 default: 439 bmcr = BRGPHY_S10; 440 break; 441 } 442 if ((media & IFM_GMASK) == IFM_FDX) { 443 bmcr |= BRGPHY_BMCR_FDX; 444 gig = BRGPHY_1000CTL_AFD; 445 } else { 446 gig = BRGPHY_1000CTL_AHD; 447 } 448 449 brgphy_enable_loopback(sc); 450 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); 451 PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr); 452 PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); 453 454 if ((IFM_SUBTYPE(media) != IFM_1000_T) && (IFM_SUBTYPE(media) != IFM_1000_SX)) 455 goto brgphy_setmedia_exit; 456 457 PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); 458 PHY_WRITE(sc, BRGPHY_MII_BMCR, 459 bmcr | BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); 460 461 if (bsc->mii_model != MII_MODEL_xxBROADCOM_BCM5701) 462 goto brgphy_setmedia_exit; 463 464 /* 465 * When setting the link manually, one side must be the master and 466 * the other the slave. However ifmedia doesn't give us a good way 467 * to specify this, so we fake it by using one of the LINK flags. 468 * If LINK0 is set, we program the PHY to be a master, otherwise 469 * it's a slave. 470 */ 471 if (master) { 472 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 473 gig | BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC); 474 } else { 475 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 476 gig | BRGPHY_1000CTL_MSE); 477 } 478 brgphy_setmedia_exit: 479 return; 480 } 481 482 /* Set the media status based on the PHY settings. */ 483 /* IFM_FLAG0 = 0 (RX flow control disabled | 1 (enabled) */ 484 /* IFM_FLAG1 = 0 (TX flow control disabled | 1 (enabled) */ 485 static void 486 brgphy_status(struct mii_softc *sc) 487 { 488 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 489 struct mii_data *mii = sc->mii_pdata; 490 int aux, bmcr, bmsr, anar, anlpar, xstat, val; 491 492 493 mii->mii_media_status = IFM_AVALID; 494 mii->mii_media_active = IFM_ETHER; 495 496 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); 497 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 498 anar = PHY_READ(sc, BRGPHY_MII_ANAR); 499 anlpar = PHY_READ(sc, BRGPHY_MII_ANLPAR); 500 501 /* Loopback is enabled. */ 502 if (bmcr & BRGPHY_BMCR_LOOP) { 503 504 mii->mii_media_active |= IFM_LOOP; 505 } 506 507 /* Autoneg is still in progress. */ 508 if ((bmcr & BRGPHY_BMCR_AUTOEN) && 509 (bmsr & BRGPHY_BMSR_ACOMP) == 0) { 510 /* Erg, still trying, I guess... */ 511 mii->mii_media_active |= IFM_NONE; 512 goto brgphy_status_exit; 513 } 514 515 /* Autoneg is enabled and complete, link should be up. */ 516 if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 517 aux = PHY_READ(sc, BRGPHY_MII_AUXSTS); 518 519 /* If copper link is up, get the negotiated speed/duplex. */ 520 if (aux & BRGPHY_AUXSTS_LINK) { 521 mii->mii_media_status |= IFM_ACTIVE; 522 switch (aux & BRGPHY_AUXSTS_AN_RES) { 523 case BRGPHY_RES_1000FD: 524 mii->mii_media_active |= IFM_1000_T | IFM_FDX; break; 525 case BRGPHY_RES_1000HD: 526 mii->mii_media_active |= IFM_1000_T | IFM_HDX; break; 527 case BRGPHY_RES_100FD: 528 mii->mii_media_active |= IFM_100_TX | IFM_FDX; break; 529 case BRGPHY_RES_100T4: 530 mii->mii_media_active |= IFM_100_T4; break; 531 case BRGPHY_RES_100HD: 532 mii->mii_media_active |= IFM_100_TX | IFM_HDX; break; 533 case BRGPHY_RES_10FD: 534 mii->mii_media_active |= IFM_10_T | IFM_FDX; break; 535 case BRGPHY_RES_10HD: 536 mii->mii_media_active |= IFM_10_T | IFM_HDX; break; 537 default: 538 mii->mii_media_active |= IFM_NONE; break; 539 } 540 } 541 } else { 542 /* If serdes link is up, get the negotiated speed/duplex. */ 543 if (bmsr & BRGPHY_BMSR_LINK) { 544 mii->mii_media_status |= IFM_ACTIVE; 545 } 546 547 /* Check the link speed/duplex based on the PHY type. */ 548 if (bsc->serdes_flags & BRGPHY_5706S) { 549 mii->mii_media_active |= IFM_1000_SX; 550 551 /* If autoneg enabled, read negotiated duplex settings */ 552 if (bmcr & BRGPHY_BMCR_AUTOEN) { 553 val = PHY_READ(sc, BRGPHY_SERDES_ANAR) & PHY_READ(sc, BRGPHY_SERDES_ANLPAR); 554 if (val & BRGPHY_SERDES_ANAR_FDX) 555 mii->mii_media_active |= IFM_FDX; 556 else 557 mii->mii_media_active |= IFM_HDX; 558 } 559 560 } else if (bsc->serdes_flags & BRGPHY_5708S) { 561 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); 562 xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); 563 564 /* Todo: Create #defines for hard coded values */ 565 switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { 566 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: 567 mii->mii_media_active |= IFM_10_FL; break; 568 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: 569 mii->mii_media_active |= IFM_100_FX; break; 570 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: 571 mii->mii_media_active |= IFM_1000_SX; break; 572 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: 573 mii->mii_media_active |= IFM_2500_SX; break; 574 } 575 576 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) 577 mii->mii_media_active |= IFM_FDX; 578 else 579 mii->mii_media_active |= IFM_HDX; 580 } 581 } 582 583 #if 0 584 /* Todo: Change bge/bce to use these settings. */ 585 586 /* Fetch flow control settings from the PHY */ 587 if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 588 /* Set FLAG0 is RX is enabled and FLAG1 if TX is enabled */ 589 if ((anar & BRGPHY_ANAR_PC) && (anlpar & BRGPHY_ANLPAR_PC)) { 590 mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; 591 } else if (!(anar & BRGPHY_ANAR_PC) && (anlpar & BRGPHY_ANAR_ASP) && 592 (anlpar & BRPHY_ANLPAR_PC) && (anlpar & BRGPHY_ANLPAR_ASP)) { 593 mii->mii_media_active |= IFM_FLAG1; 594 } else if ((anar & BRGPHY_ANAR_PC) && (anar & BRGPHY_ANAR_ASP) && 595 !(anlpar & BRGPHY_ANLPAR_PC) && (anlpar & BRGPHY_ANLPAR_ASP)) { 596 mii->mii_media_active |= IFM_FLAG0; 597 } 598 } 599 /* Todo: Add support for fiber settings too. */ 600 #endif 601 602 603 brgphy_status_exit: 604 return; 605 } 606 607 static void 608 brgphy_mii_phy_auto(struct mii_softc *sc) 609 { 610 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 611 int ktcr = 0; 612 613 brgphy_reset(sc); 614 615 /* Enable flow control in the advertisement register. */ 616 if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 617 /* Pause capability advertisement (pause capable & asymmetric) */ 618 PHY_WRITE(sc, BRGPHY_MII_ANAR, 619 BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA | 620 BRGPHY_ANAR_ASP | BRGPHY_ANAR_PC); 621 } else { 622 PHY_WRITE(sc, BRGPHY_SERDES_ANAR, BRGPHY_SERDES_ANAR_FDX | 623 BRGPHY_SERDES_ANAR_HDX | BRGPHY_SERDES_ANAR_BOTH_PAUSE); 624 } 625 626 /* Enable speed in the 1000baseT control register */ 627 ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD; 628 if (bsc->mii_model == MII_MODEL_xxBROADCOM_BCM5701) 629 ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC; 630 PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr); 631 ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL); 632 633 /* Start autonegotiation */ 634 PHY_WRITE(sc, BRGPHY_MII_BMCR,BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); 635 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); 636 637 } 638 639 /* Enable loopback to force the link down. */ 640 static void 641 brgphy_enable_loopback(struct mii_softc *sc) 642 { 643 int i; 644 645 PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); 646 for (i = 0; i < 15000; i++) { 647 if (!(PHY_READ(sc, BRGPHY_MII_BMSR) & BRGPHY_BMSR_LINK)) 648 break; 649 DELAY(10); 650 } 651 } 652 653 /* Turn off tap power management on 5401. */ 654 static void 655 bcm5401_load_dspcode(struct mii_softc *sc) 656 { 657 static const struct { 658 int reg; 659 uint16_t val; 660 } dspcode[] = { 661 { BRGPHY_MII_AUXCTL, 0x0c20 }, 662 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 663 { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 664 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 665 { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 666 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 667 { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 668 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 669 { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 670 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 671 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 672 { 0, 0 }, 673 }; 674 int i; 675 676 for (i = 0; dspcode[i].reg != 0; i++) 677 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 678 DELAY(40); 679 } 680 681 static void 682 bcm5411_load_dspcode(struct mii_softc *sc) 683 { 684 static const struct { 685 int reg; 686 uint16_t val; 687 } dspcode[] = { 688 { 0x1c, 0x8c23 }, 689 { 0x1c, 0x8ca3 }, 690 { 0x1c, 0x8c23 }, 691 { 0, 0 }, 692 }; 693 int i; 694 695 for (i = 0; dspcode[i].reg != 0; i++) 696 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 697 } 698 699 static void 700 brgphy_fixup_5704_a0_bug(struct mii_softc *sc) 701 { 702 static const struct { 703 int reg; 704 uint16_t val; 705 } dspcode[] = { 706 { 0x1c, 0x8d68 }, 707 { 0x1c, 0x8d68 }, 708 { 0, 0 }, 709 }; 710 int i; 711 712 for (i = 0; dspcode[i].reg != 0; i++) 713 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 714 } 715 716 static void 717 brgphy_fixup_adc_bug(struct mii_softc *sc) 718 { 719 static const struct { 720 int reg; 721 uint16_t val; 722 } dspcode[] = { 723 { BRGPHY_MII_AUXCTL, 0x0c00 }, 724 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 725 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 726 { 0, 0 }, 727 }; 728 int i; 729 730 for (i = 0; dspcode[i].reg != 0; i++) 731 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 732 } 733 734 static void 735 brgphy_fixup_adjust_trim(struct mii_softc *sc) 736 { 737 static const struct { 738 int reg; 739 uint16_t val; 740 } dspcode[] = { 741 { BRGPHY_MII_AUXCTL, 0x0c00 }, 742 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 743 { BRGPHY_MII_DSP_RW_PORT, 0x110b }, 744 { BRGPHY_MII_TEST1, 0x0014 }, 745 { BRGPHY_MII_AUXCTL, 0x0400 }, 746 { 0, 0 }, 747 }; 748 int i; 749 750 for (i = 0; dspcode[i].reg != 0; i++) 751 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 752 } 753 754 static void 755 brgphy_fixup_ber_bug(struct mii_softc *sc) 756 { 757 static const struct { 758 int reg; 759 uint16_t val; 760 } dspcode[] = { 761 { BRGPHY_MII_AUXCTL, 0x0c00 }, 762 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 763 { BRGPHY_MII_DSP_RW_PORT, 0x310b }, 764 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 765 { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, 766 { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, 767 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, 768 { BRGPHY_MII_AUXCTL, 0x0400 }, 769 { 0, 0 }, 770 }; 771 int i; 772 773 for (i = 0; dspcode[i].reg != 0; i++) 774 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 775 } 776 777 static void 778 brgphy_fixup_crc_bug(struct mii_softc *sc) 779 { 780 static const struct { 781 int reg; 782 uint16_t val; 783 } dspcode[] = { 784 { BRGPHY_MII_DSP_RW_PORT, 0x0a75 }, 785 { 0x1c, 0x8c68 }, 786 { 0x1c, 0x8d68 }, 787 { 0x1c, 0x8c68 }, 788 { 0, 0 }, 789 }; 790 int i; 791 792 for (i = 0; dspcode[i].reg != 0; i++) 793 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 794 } 795 796 static void 797 brgphy_fixup_jitter_bug(struct mii_softc *sc) 798 { 799 static const struct { 800 int reg; 801 uint16_t val; 802 } dspcode[] = { 803 { BRGPHY_MII_AUXCTL, 0x0c00 }, 804 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 805 { BRGPHY_MII_DSP_RW_PORT, 0x010b }, 806 { BRGPHY_MII_AUXCTL, 0x0400 }, 807 { 0, 0 }, 808 }; 809 int i; 810 811 for (i = 0; dspcode[i].reg != 0; i++) 812 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 813 } 814 815 static void 816 brgphy_ethernet_wirespeed(struct mii_softc *sc) 817 { 818 uint32_t val; 819 820 /* Enable Ethernet@WireSpeed. */ 821 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 822 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 823 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4)); 824 } 825 826 static void 827 brgphy_jumbo_settings(struct mii_softc *sc, u_long mtu) 828 { 829 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 830 uint32_t val; 831 832 /* Set or clear jumbo frame settings in the PHY. */ 833 if (mtu > ETHER_MAX_LEN) { 834 if (bsc->mii_model == MII_MODEL_xxBROADCOM_BCM5401) { 835 /* BCM5401 PHY cannot read-modify-write. */ 836 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); 837 } else { 838 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 839 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 840 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 841 val | BRGPHY_AUXCTL_LONG_PKT); 842 } 843 844 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 845 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 846 val | BRGPHY_PHY_EXTCTL_HIGH_LA); 847 } else { 848 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 849 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 850 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 851 val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); 852 853 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 854 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 855 val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); 856 } 857 } 858 859 static void 860 brgphy_reset(struct mii_softc *sc) 861 { 862 struct brgphy_softc *bsc = (struct brgphy_softc *)sc; 863 struct bge_softc *bge_sc = NULL; 864 struct bce_softc *bce_sc = NULL; 865 struct ifnet *ifp; 866 867 mii_phy_reset(sc); 868 869 /* Handle any PHY specific procedures to finish the reset. */ 870 switch (bsc->mii_oui) { 871 case MII_OUI_BROADCOM: 872 break; 873 case MII_OUI_xxBROADCOM: 874 switch (bsc->mii_model) { 875 case MII_MODEL_xxBROADCOM_BCM5400: 876 bcm5401_load_dspcode(sc); 877 break; 878 case MII_MODEL_xxBROADCOM_BCM5401: 879 if (bsc->mii_rev == 1 || bsc->mii_rev == 3) 880 bcm5401_load_dspcode(sc); 881 break; 882 case MII_MODEL_xxBROADCOM_BCM5411: 883 bcm5411_load_dspcode(sc); 884 break; 885 } 886 break; 887 case MII_OUI_xxBROADCOM_ALT1: 888 break; 889 } 890 891 ifp = sc->mii_pdata->mii_ifp; 892 893 /* Find the driver associated with this PHY. */ 894 if (strcmp(ifp->if_dname, "bge") == 0) { 895 bge_sc = ifp->if_softc; 896 } else if (strcmp(ifp->if_dname, "bce") == 0) { 897 bce_sc = ifp->if_softc; 898 } 899 900 /* Handle any bge (NetXtreme/NetLink) workarounds. */ 901 if (bge_sc) { 902 /* Fix up various bugs */ 903 if (bge_sc->bge_flags & BGE_FLAG_5704_A0_BUG) 904 brgphy_fixup_5704_a0_bug(sc); 905 if (bge_sc->bge_flags & BGE_FLAG_ADC_BUG) 906 brgphy_fixup_adc_bug(sc); 907 if (bge_sc->bge_flags & BGE_FLAG_ADJUST_TRIM) 908 brgphy_fixup_adjust_trim(sc); 909 if (bge_sc->bge_flags & BGE_FLAG_BER_BUG) 910 brgphy_fixup_ber_bug(sc); 911 if (bge_sc->bge_flags & BGE_FLAG_CRC_BUG) 912 brgphy_fixup_crc_bug(sc); 913 if (bge_sc->bge_flags & BGE_FLAG_JITTER_BUG) 914 brgphy_fixup_jitter_bug(sc); 915 916 brgphy_jumbo_settings(sc, ifp->if_mtu); 917 918 /* 919 * Don't enable Ethernet@WireSpeed for the 5700 or the 920 * 5705 A1 and A2 chips. 921 */ 922 if (bge_sc->bge_asicrev != BGE_ASICREV_BCM5700 && 923 bge_sc->bge_chipid != BGE_CHIPID_BCM5705_A1 && 924 bge_sc->bge_chipid != BGE_CHIPID_BCM5705_A2) 925 brgphy_ethernet_wirespeed(sc); 926 927 /* Enable Link LED on Dell boxes */ 928 if (bge_sc->bge_flags & BGE_FLAG_NO_3LED) { 929 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 930 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) & 931 ~BRGPHY_PHY_EXTCTL_3_LED); 932 } 933 /* Handle any bce (NetXtreme II) workarounds. */ 934 } else if (bce_sc) { 935 936 if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5708 && 937 BCE_CHIP_BOND_ID(bce_sc) & BCE_CHIP_BOND_ID_SERDES_BIT) { 938 939 /* Store autoneg capabilities/results in digital block (Page 0) */ 940 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); 941 PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, 942 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); 943 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); 944 945 /* Enable fiber mode and autodetection */ 946 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, 947 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | 948 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | 949 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); 950 951 /* Enable parallel detection */ 952 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, 953 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | 954 BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); 955 956 /* Advertise 2.5G support through next page during autoneg */ 957 if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) 958 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, 959 PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | 960 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 961 962 /* Increase TX signal amplitude */ 963 if ((BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_A0) || 964 (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B0) || 965 (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B1)) { 966 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 967 BRGPHY_5708S_TX_MISC_PG5); 968 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, 969 PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & ~0x30); 970 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 971 BRGPHY_5708S_DIG_PG0); 972 } 973 974 /* Backplanes use special driver/pre-driver/pre-emphasis values. */ 975 if ((bce_sc->bce_shared_hw_cfg & BCE_SHARED_HW_CFG_PHY_BACKPLANE) && 976 (bce_sc->bce_port_hw_cfg & BCE_PORT_HW_CFG_CFG_TXCTL3_MASK)) { 977 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 978 BRGPHY_5708S_TX_MISC_PG5); 979 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, 980 bce_sc->bce_port_hw_cfg & 981 BCE_PORT_HW_CFG_CFG_TXCTL3_MASK); 982 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 983 BRGPHY_5708S_DIG_PG0); 984 } 985 } else { 986 brgphy_fixup_ber_bug(sc); 987 brgphy_jumbo_settings(sc, ifp->if_mtu); 988 brgphy_ethernet_wirespeed(sc); 989 } 990 991 } 992 } 993 994