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