1 /* $NetBSD: brgphy.c,v 1.58 2011/05/02 09:03:10 jym Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 */ 56 57 /* 58 * driver for the Broadcom BCM5400 and BCM5700 Gig-E PHYs. 59 * 60 * Programming information for this PHY was gleaned from FreeBSD 61 * (they were apparently able to get a datasheet from Broadcom). 62 */ 63 64 #include <sys/cdefs.h> 65 __KERNEL_RCSID(0, "$NetBSD: brgphy.c,v 1.58 2011/05/02 09:03:10 jym Exp $"); 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/kernel.h> 70 #include <sys/device.h> 71 #include <sys/socket.h> 72 #include <sys/errno.h> 73 #include <prop/proplib.h> 74 75 #include <net/if.h> 76 #include <net/if_media.h> 77 78 #include <dev/mii/mii.h> 79 #include <dev/mii/miivar.h> 80 #include <dev/mii/miidevs.h> 81 #include <dev/mii/brgphyreg.h> 82 83 #include <dev/pci/if_bgereg.h> 84 #include <dev/pci/if_bnxreg.h> 85 86 static int brgphymatch(device_t, cfdata_t, void *); 87 static void brgphyattach(device_t, device_t, void *); 88 89 struct brgphy_softc { 90 struct mii_softc sc_mii; 91 bool sc_isbge; 92 bool sc_isbnx; 93 uint32_t sc_chipid; /* parent's chipid */ 94 uint32_t sc_phyflags; /* parent's phyflags */ 95 }; 96 97 CFATTACH_DECL3_NEW(brgphy, sizeof(struct brgphy_softc), 98 brgphymatch, brgphyattach, mii_phy_detach, mii_phy_activate, NULL, NULL, 99 DVF_DETACH_SHUTDOWN); 100 101 static int brgphy_service(struct mii_softc *, struct mii_data *, int); 102 static void brgphy_status(struct mii_softc *); 103 static int brgphy_mii_phy_auto(struct mii_softc *); 104 static void brgphy_loop(struct mii_softc *); 105 static void brgphy_reset(struct mii_softc *); 106 static void brgphy_bcm5401_dspcode(struct mii_softc *); 107 static void brgphy_bcm5411_dspcode(struct mii_softc *); 108 static void brgphy_bcm5421_dspcode(struct mii_softc *); 109 static void brgphy_bcm54k2_dspcode(struct mii_softc *); 110 static void brgphy_adc_bug(struct mii_softc *); 111 static void brgphy_5704_a0_bug(struct mii_softc *); 112 static void brgphy_ber_bug(struct mii_softc *); 113 static void brgphy_crc_bug(struct mii_softc *); 114 static void brgphy_disable_early_dac(struct mii_softc *); 115 static void brgphy_jumbo_settings(struct mii_softc *); 116 static void brgphy_eth_wirespeed(struct mii_softc *); 117 118 119 static const struct mii_phy_funcs brgphy_funcs = { 120 brgphy_service, brgphy_status, brgphy_reset, 121 }; 122 123 static const struct mii_phydesc brgphys[] = { 124 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5400, 125 MII_STR_BROADCOM_BCM5400 }, 126 127 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5401, 128 MII_STR_BROADCOM_BCM5401 }, 129 130 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5411, 131 MII_STR_BROADCOM_BCM5411 }, 132 133 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5421, 134 MII_STR_BROADCOM_BCM5421 }, 135 136 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5462, 137 MII_STR_BROADCOM_BCM5462 }, 138 139 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5461, 140 MII_STR_BROADCOM_BCM5461 }, 141 142 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM54K2, 143 MII_STR_BROADCOM_BCM54K2 }, 144 145 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5464, 146 MII_STR_BROADCOM_BCM5464 }, 147 148 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5701, 149 MII_STR_BROADCOM_BCM5701 }, 150 151 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5703, 152 MII_STR_BROADCOM_BCM5703 }, 153 154 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5704, 155 MII_STR_BROADCOM_BCM5704 }, 156 157 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5705, 158 MII_STR_BROADCOM_BCM5705 }, 159 160 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5714, 161 MII_STR_BROADCOM_BCM5714 }, 162 163 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5750, 164 MII_STR_BROADCOM_BCM5750 }, 165 166 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5752, 167 MII_STR_BROADCOM_BCM5752 }, 168 169 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5780, 170 MII_STR_BROADCOM_BCM5780 }, 171 172 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5708C, 173 MII_STR_BROADCOM_BCM5708C }, 174 175 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5481, 176 MII_STR_BROADCOM2_BCM5481 }, 177 178 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5482, 179 MII_STR_BROADCOM2_BCM5482 }, 180 181 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5709C, 182 MII_STR_BROADCOM2_BCM5709C }, 183 184 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5709S, 185 MII_STR_BROADCOM2_BCM5709S }, 186 187 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5709CAX, 188 MII_STR_BROADCOM2_BCM5709CAX }, 189 190 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5722, 191 MII_STR_BROADCOM2_BCM5722 }, 192 193 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5754, 194 MII_STR_BROADCOM2_BCM5754 }, 195 196 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5755, 197 MII_STR_BROADCOM2_BCM5755 }, 198 199 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5761, 200 MII_STR_BROADCOM2_BCM5761 }, 201 202 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5784, 203 MII_STR_BROADCOM2_BCM5784 }, 204 205 { MII_OUI_xxBROADCOM_ALT1, MII_MODEL_xxBROADCOM_ALT1_BCM5906, 206 MII_STR_xxBROADCOM_ALT1_BCM5906 }, 207 208 { 0, 0, 209 NULL }, 210 }; 211 212 static int 213 brgphymatch(device_t parent, cfdata_t match, void *aux) 214 { 215 struct mii_attach_args *ma = aux; 216 217 if (mii_phy_match(ma, brgphys) != NULL) 218 return (10); 219 220 return (0); 221 } 222 223 static void 224 brgphyattach(device_t parent, device_t self, void *aux) 225 { 226 struct brgphy_softc *bsc = device_private(self); 227 struct mii_softc *sc = &bsc->sc_mii; 228 struct mii_attach_args *ma = aux; 229 struct mii_data *mii = ma->mii_data; 230 const struct mii_phydesc *mpd; 231 prop_dictionary_t dict; 232 233 mpd = mii_phy_match(ma, brgphys); 234 aprint_naive(": Media interface\n"); 235 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 236 237 sc->mii_dev = self; 238 sc->mii_inst = mii->mii_instance; 239 sc->mii_phy = ma->mii_phyno; 240 sc->mii_mpd_model = MII_MODEL(ma->mii_id2); 241 sc->mii_mpd_rev = MII_REV(ma->mii_id2); 242 sc->mii_pdata = mii; 243 sc->mii_flags = ma->mii_flags; 244 sc->mii_anegticks = MII_ANEGTICKS; 245 sc->mii_funcs = &brgphy_funcs; 246 247 PHY_RESET(sc); 248 249 sc->mii_capabilities = 250 PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 251 if (sc->mii_capabilities & BMSR_EXTSTAT) 252 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 253 254 255 if (device_is_a(parent, "bge")) 256 bsc->sc_isbge = true; 257 else if (device_is_a(parent, "bnx")) 258 bsc->sc_isbnx = true; 259 260 if (bsc->sc_isbge || bsc->sc_isbnx) { 261 dict = device_properties(parent); 262 if (!prop_dictionary_get_uint32(dict, "phyflags", 263 &bsc->sc_phyflags)) 264 aprint_error_dev(self, "failed to get phyflags\n"); 265 if (!prop_dictionary_get_uint32(dict, "chipid", 266 &bsc->sc_chipid)) 267 aprint_error_dev(self, "failed to get chipid\n"); 268 } 269 270 aprint_normal_dev(self, ""); 271 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && 272 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) 273 aprint_error("no media present"); 274 else { 275 if (sc->mii_flags & MIIF_HAVEFIBER) { 276 sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; 277 278 /* 279 * Set the proper bits for capabilities so that the 280 * correct media get selected by mii_phy_add_media() 281 */ 282 sc->mii_capabilities |= BMSR_ANEG; 283 sc->mii_capabilities &= ~BMSR_100T4; 284 sc->mii_extcapabilities |= EXTSR_1000XFDX; 285 286 if (bsc->sc_isbnx) { 287 /* 288 * 2.5Gb support is a software enabled feature 289 * on the BCM5708S and BCM5709S controllers. 290 */ 291 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 292 if (bsc->sc_phyflags 293 & BNX_PHY_2_5G_CAPABLE_FLAG) { 294 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, 295 IFM_FDX, sc->mii_inst), 0); 296 aprint_normal("2500baseSX-FDX, "); 297 #undef ADD 298 } 299 } 300 } 301 mii_phy_add_media(sc); 302 } 303 aprint_normal("\n"); 304 305 } 306 307 static int 308 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 309 { 310 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 311 int reg, speed, gig; 312 313 switch (cmd) { 314 case MII_POLLSTAT: 315 /* 316 * If we're not polling our PHY instance, just return. 317 */ 318 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 319 return (0); 320 break; 321 322 case MII_MEDIACHG: 323 /* 324 * If the media indicates a different PHY instance, 325 * isolate ourselves. 326 */ 327 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 328 reg = PHY_READ(sc, MII_BMCR); 329 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 330 return (0); 331 } 332 333 /* 334 * If the interface is not up, don't do anything. 335 */ 336 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 337 break; 338 339 PHY_RESET(sc); /* XXX hardware bug work-around */ 340 341 switch (IFM_SUBTYPE(ife->ifm_media)) { 342 case IFM_AUTO: 343 (void) brgphy_mii_phy_auto(sc); 344 break; 345 case IFM_1000_T: 346 speed = BMCR_S1000; 347 goto setit; 348 case IFM_100_TX: 349 speed = BMCR_S100; 350 goto setit; 351 case IFM_10_T: 352 speed = BMCR_S10; 353 setit: 354 brgphy_loop(sc); 355 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 356 speed |= BMCR_FDX; 357 gig = GTCR_ADV_1000TFDX; 358 } else { 359 gig = GTCR_ADV_1000THDX; 360 } 361 362 PHY_WRITE(sc, MII_100T2CR, 0); 363 PHY_WRITE(sc, MII_ANAR, ANAR_CSMA); 364 PHY_WRITE(sc, MII_BMCR, speed); 365 366 if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) 367 break; 368 369 PHY_WRITE(sc, MII_100T2CR, gig); 370 PHY_WRITE(sc, MII_BMCR, 371 speed|BMCR_AUTOEN|BMCR_STARTNEG); 372 373 if (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701) 374 break; 375 376 if (mii->mii_media.ifm_media & IFM_ETH_MASTER) 377 gig |= GTCR_MAN_MS | GTCR_ADV_MS; 378 PHY_WRITE(sc, MII_100T2CR, gig); 379 break; 380 default: 381 return (EINVAL); 382 } 383 break; 384 385 case MII_TICK: 386 /* 387 * If we're not currently selected, just return. 388 */ 389 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 390 return (0); 391 392 if (mii_phy_tick(sc) == EJUSTRETURN) 393 return (0); 394 break; 395 396 case MII_DOWN: 397 mii_phy_down(sc); 398 return (0); 399 } 400 401 /* Update the media status. */ 402 mii_phy_status(sc); 403 404 /* 405 * Callback if something changed. Note that we need to poke the DSP on 406 * the Broadcom PHYs if the media changes. 407 */ 408 if (sc->mii_media_active != mii->mii_media_active || 409 sc->mii_media_status != mii->mii_media_status || 410 cmd == MII_MEDIACHG) { 411 switch (sc->mii_mpd_model) { 412 case MII_MODEL_BROADCOM_BCM5400: 413 brgphy_bcm5401_dspcode(sc); 414 break; 415 case MII_MODEL_BROADCOM_BCM5401: 416 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) 417 brgphy_bcm5401_dspcode(sc); 418 break; 419 case MII_MODEL_BROADCOM_BCM5411: 420 brgphy_bcm5411_dspcode(sc); 421 break; 422 } 423 } 424 425 /* Callback if something changed. */ 426 mii_phy_update(sc, cmd); 427 return (0); 428 } 429 430 static void 431 brgphy_status(struct mii_softc *sc) 432 { 433 struct mii_data *mii = sc->mii_pdata; 434 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 435 int bmcr, bmsr, auxsts, gtsr; 436 437 mii->mii_media_status = IFM_AVALID; 438 mii->mii_media_active = IFM_ETHER; 439 440 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 441 if (bmsr & BMSR_LINK) 442 mii->mii_media_status |= IFM_ACTIVE; 443 444 bmcr = PHY_READ(sc, MII_BMCR); 445 if (bmcr & BMCR_ISO) { 446 mii->mii_media_active |= IFM_NONE; 447 mii->mii_media_status = 0; 448 return; 449 } 450 451 if (bmcr & BMCR_LOOP) 452 mii->mii_media_active |= IFM_LOOP; 453 454 if (bmcr & BMCR_AUTOEN) { 455 /* 456 * The media status bits are only valid of autonegotiation 457 * has completed (or it's disabled). 458 */ 459 if ((bmsr & BMSR_ACOMP) == 0) { 460 /* Erg, still trying, I guess... */ 461 mii->mii_media_active |= IFM_NONE; 462 return; 463 } 464 465 if (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S) { 466 467 /* 5709S has its own general purpose status registers */ 468 469 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 470 BRGPHY_BLOCK_ADDR_GP_STATUS); 471 472 auxsts = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); 473 474 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 475 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 476 477 switch (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { 478 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: 479 mii->mii_media_active |= IFM_10_FL; 480 break; 481 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: 482 mii->mii_media_active |= IFM_100_FX; 483 break; 484 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: 485 mii->mii_media_active |= IFM_1000_SX; 486 break; 487 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: 488 mii->mii_media_active |= IFM_2500_SX; 489 break; 490 default: 491 mii->mii_media_active |= IFM_NONE; 492 mii->mii_media_status = 0; 493 break; 494 } 495 496 if (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_FDX) 497 mii->mii_media_active |= IFM_FDX; 498 else 499 mii->mii_media_active |= IFM_HDX; 500 501 } else { 502 auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS); 503 504 switch (auxsts & BRGPHY_AUXSTS_AN_RES) { 505 case BRGPHY_RES_1000FD: 506 mii->mii_media_active |= IFM_1000_T|IFM_FDX; 507 gtsr = PHY_READ(sc, MII_100T2SR); 508 if (gtsr & GTSR_MS_RES) 509 mii->mii_media_active |= IFM_ETH_MASTER; 510 break; 511 512 case BRGPHY_RES_1000HD: 513 mii->mii_media_active |= IFM_1000_T; 514 gtsr = PHY_READ(sc, MII_100T2SR); 515 if (gtsr & GTSR_MS_RES) 516 mii->mii_media_active |= IFM_ETH_MASTER; 517 break; 518 519 case BRGPHY_RES_100FD: 520 mii->mii_media_active |= IFM_100_TX|IFM_FDX; 521 break; 522 523 case BRGPHY_RES_100T4: 524 mii->mii_media_active |= IFM_100_T4; 525 break; 526 527 case BRGPHY_RES_100HD: 528 mii->mii_media_active |= IFM_100_TX; 529 break; 530 531 case BRGPHY_RES_10FD: 532 mii->mii_media_active |= IFM_10_T|IFM_FDX; 533 break; 534 535 case BRGPHY_RES_10HD: 536 mii->mii_media_active |= IFM_10_T; 537 break; 538 539 default: 540 mii->mii_media_active |= IFM_NONE; 541 mii->mii_media_status = 0; 542 } 543 } 544 545 if (mii->mii_media_active & IFM_FDX) 546 mii->mii_media_active |= mii_phy_flowstatus(sc); 547 548 } else 549 mii->mii_media_active = ife->ifm_media; 550 } 551 552 int 553 brgphy_mii_phy_auto(struct mii_softc *sc) 554 { 555 int anar, ktcr = 0; 556 557 brgphy_loop(sc); 558 PHY_RESET(sc); 559 560 ktcr = GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX; 561 if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701) 562 ktcr |= GTCR_MAN_MS|GTCR_ADV_MS; 563 PHY_WRITE(sc, MII_100T2CR, ktcr); 564 ktcr = PHY_READ(sc, MII_100T2CR); 565 DELAY(1000); 566 567 if (sc->mii_flags & MIIF_HAVEFIBER) { 568 anar = ANAR_X_FD | ANAR_X_HD; 569 if (sc->mii_flags & MIIF_DOPAUSE) 570 anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE; 571 } else { 572 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 573 if (sc->mii_flags & MIIF_DOPAUSE) 574 anar |= ANAR_FC | ANAR_X_PAUSE_ASYM; 575 } 576 PHY_WRITE(sc, MII_ANAR, anar); 577 DELAY(1000); 578 579 /* Start autonegotiation */ 580 PHY_WRITE(sc, MII_BMCR, 581 BMCR_AUTOEN | BMCR_STARTNEG); 582 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); 583 584 return (EJUSTRETURN); 585 } 586 587 void 588 brgphy_loop(struct mii_softc *sc) 589 { 590 u_int32_t bmsr; 591 int i; 592 593 PHY_WRITE(sc, MII_BMCR, BMCR_LOOP); 594 for (i = 0; i < 15000; i++) { 595 bmsr = PHY_READ(sc, MII_BMSR); 596 if (!(bmsr & BMSR_LINK)) 597 break; 598 DELAY(10); 599 } 600 } 601 602 static void 603 brgphy_reset(struct mii_softc *sc) 604 { 605 struct brgphy_softc *bsc = device_private(sc->mii_dev); 606 607 mii_phy_reset(sc); 608 609 switch (sc->mii_mpd_model) { 610 case MII_MODEL_BROADCOM_BCM5400: 611 brgphy_bcm5401_dspcode(sc); 612 break; 613 case MII_MODEL_BROADCOM_BCM5401: 614 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) 615 brgphy_bcm5401_dspcode(sc); 616 break; 617 case MII_MODEL_BROADCOM_BCM5411: 618 brgphy_bcm5411_dspcode(sc); 619 break; 620 case MII_MODEL_BROADCOM_BCM5421: 621 brgphy_bcm5421_dspcode(sc); 622 break; 623 case MII_MODEL_BROADCOM_BCM54K2: 624 brgphy_bcm54k2_dspcode(sc); 625 break; 626 } 627 628 /* Handle any bge (NetXtreme/NetLink) workarounds. */ 629 if (bsc->sc_isbge) { 630 if (!(sc->mii_flags & MIIF_HAVEFIBER)) { 631 632 if (bsc->sc_phyflags & BGE_PHY_ADC_BUG) 633 brgphy_adc_bug(sc); 634 if (bsc->sc_phyflags & BGE_PHY_5704_A0_BUG) 635 brgphy_5704_a0_bug(sc); 636 if (bsc->sc_phyflags & BGE_PHY_BER_BUG) 637 brgphy_ber_bug(sc); 638 else if (bsc->sc_phyflags & BGE_PHY_JITTER_BUG) { 639 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00); 640 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 641 0x000a); 642 643 if (bsc->sc_phyflags 644 & BGE_PHY_ADJUST_TRIM) { 645 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 646 0x110b); 647 PHY_WRITE(sc, BRGPHY_TEST1, 648 BRGPHY_TEST1_TRIM_EN | 0x4); 649 } else { 650 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 651 0x010b); 652 } 653 654 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400); 655 } 656 if (bsc->sc_phyflags & BGE_PHY_CRC_BUG) 657 brgphy_crc_bug(sc); 658 659 /* Set Jumbo frame settings in the PHY. */ 660 if (bsc->sc_phyflags & BGE_JUMBO_CAPABLE) 661 brgphy_jumbo_settings(sc); 662 663 /* Adjust output voltage */ 664 if (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5906) 665 PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); 666 667 /* Enable Ethernet@Wirespeed */ 668 if (!(bsc->sc_phyflags & BGE_NO_ETH_WIRE_SPEED)) 669 brgphy_eth_wirespeed(sc); 670 671 #if 0 672 /* Enable Link LED on Dell boxes */ 673 if (bsc->sc_phyflags & BGE_NO_3LED) { 674 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 675 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) 676 & ~BRGPHY_PHY_EXTCTL_3_LED); 677 } 678 #endif 679 } 680 /* Handle any bnx (NetXtreme II) workarounds. */ 681 } else if (bsc->sc_isbnx) { 682 #if 0 /* not yet */ 683 if (sc->mii_mpd_model == MII_MODEL_xxBROADCOM2_BCM5708S) { 684 /* Store autoneg capabilities/results in digital block (Page 0) */ 685 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); 686 PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, 687 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); 688 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); 689 690 /* Enable fiber mode and autodetection */ 691 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, 692 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | 693 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | 694 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); 695 696 /* Enable parallel detection */ 697 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, 698 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | 699 BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); 700 701 /* Advertise 2.5G support through next page during autoneg */ 702 if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) 703 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, 704 PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | 705 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 706 707 /* Increase TX signal amplitude */ 708 if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) || 709 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) || 710 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) { 711 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 712 BRGPHY_5708S_TX_MISC_PG5); 713 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, 714 PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & 715 ~BRGPHY_5708S_PG5_TXACTL1_VCM); 716 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 717 BRGPHY_5708S_DIG_PG0); 718 } 719 720 /* Backplanes use special driver/pre-driver/pre-emphasis values. */ 721 if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) && 722 (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) { 723 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 724 BRGPHY_5708S_TX_MISC_PG5); 725 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, 726 bnx_sc->bnx_port_hw_cfg & 727 BNX_PORT_HW_CFG_CFG_TXCTL3_MASK); 728 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 729 BRGPHY_5708S_DIG_PG0); 730 } 731 } else 732 #endif 733 if (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S) { 734 /* Select the SerDes Digital block of the AN MMD. */ 735 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 736 BRGPHY_BLOCK_ADDR_SERDES_DIG); 737 738 PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, 739 (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) & 740 ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) | 741 BRGPHY_SD_DIG_1000X_CTL1_FIBER); 742 743 if (bsc->sc_phyflags & BNX_PHY_2_5G_CAPABLE_FLAG) { 744 /* Select the Over 1G block of the AN MMD. */ 745 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 746 BRGPHY_BLOCK_ADDR_OVER_1G); 747 748 /* 749 * Enable autoneg "Next Page" to advertise 750 * 2.5G support. 751 */ 752 PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, 753 PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) | 754 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 755 } 756 757 /* 758 * Select the Multi-Rate Backplane Ethernet block of 759 * the AN MMD. 760 */ 761 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 762 BRGPHY_BLOCK_ADDR_MRBE); 763 764 /* Enable MRBE speed autoneg. */ 765 PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, 766 PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) | 767 BRGPHY_MRBE_MSG_PG5_NP_MBRE | 768 BRGPHY_MRBE_MSG_PG5_NP_T2); 769 770 /* Select the Clause 73 User B0 block of the AN MMD. */ 771 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 772 BRGPHY_BLOCK_ADDR_CL73_USER_B0); 773 774 /* Enable MRBE speed autoneg. */ 775 PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, 776 BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | 777 BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | 778 BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); 779 780 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 781 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 782 783 } else if (_BNX_CHIP_NUM(bsc->sc_chipid) == BNX_CHIP_NUM_5709) { 784 if (_BNX_CHIP_REV(bsc->sc_chipid) == BNX_CHIP_REV_Ax || 785 _BNX_CHIP_REV(bsc->sc_chipid) == BNX_CHIP_REV_Bx) 786 brgphy_disable_early_dac(sc); 787 788 /* Set Jumbo frame settings in the PHY. */ 789 brgphy_jumbo_settings(sc); 790 791 /* Enable Ethernet@Wirespeed */ 792 brgphy_eth_wirespeed(sc); 793 } else { 794 if (!(sc->mii_flags & MIIF_HAVEFIBER)) { 795 brgphy_ber_bug(sc); 796 797 /* Set Jumbo frame settings in the PHY. */ 798 brgphy_jumbo_settings(sc); 799 800 /* Enable Ethernet@Wirespeed */ 801 brgphy_eth_wirespeed(sc); 802 } 803 } 804 } 805 } 806 807 /* Turn off tap power management on 5401. */ 808 static void 809 brgphy_bcm5401_dspcode(struct mii_softc *sc) 810 { 811 static const struct { 812 int reg; 813 uint16_t val; 814 } dspcode[] = { 815 { BRGPHY_MII_AUXCTL, 0x0c20 }, 816 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 817 { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 818 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 819 { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 820 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 821 { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 822 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 823 { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 824 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 825 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 826 { 0, 0 }, 827 }; 828 int i; 829 830 for (i = 0; dspcode[i].reg != 0; i++) 831 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 832 delay(40); 833 } 834 835 static void 836 brgphy_bcm5411_dspcode(struct mii_softc *sc) 837 { 838 static const struct { 839 int reg; 840 uint16_t val; 841 } dspcode[] = { 842 { 0x1c, 0x8c23 }, 843 { 0x1c, 0x8ca3 }, 844 { 0x1c, 0x8c23 }, 845 { 0, 0 }, 846 }; 847 int i; 848 849 for (i = 0; dspcode[i].reg != 0; i++) 850 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 851 } 852 853 void 854 brgphy_bcm5421_dspcode(struct mii_softc *sc) 855 { 856 uint16_t data; 857 858 /* Set Class A mode */ 859 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007); 860 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 861 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400); 862 863 /* Set FFE gamma override to -0.125 */ 864 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007); 865 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 866 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800); 867 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 868 data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 869 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200); 870 } 871 872 void 873 brgphy_bcm54k2_dspcode(struct mii_softc *sc) 874 { 875 static const struct { 876 int reg; 877 uint16_t val; 878 } dspcode[] = { 879 { 4, 0x01e1 }, 880 { 9, 0x0300 }, 881 { 0, 0 }, 882 }; 883 int i; 884 885 for (i = 0; dspcode[i].reg != 0; i++) 886 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 887 } 888 889 static void 890 brgphy_adc_bug(struct mii_softc *sc) 891 { 892 static const struct { 893 int reg; 894 uint16_t val; 895 } dspcode[] = { 896 { BRGPHY_MII_AUXCTL, 0x0c00 }, 897 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 898 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 899 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 900 { BRGPHY_MII_DSP_RW_PORT, 0x0323 }, 901 { BRGPHY_MII_AUXCTL, 0x0400 }, 902 { 0, 0 }, 903 }; 904 int i; 905 906 for (i = 0; dspcode[i].reg != 0; i++) 907 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 908 } 909 910 static void 911 brgphy_5704_a0_bug(struct mii_softc *sc) 912 { 913 static const struct { 914 int reg; 915 uint16_t val; 916 } dspcode[] = { 917 { 0x1c, 0x8d68 }, 918 { 0x1c, 0x8d68 }, 919 { 0, 0 }, 920 }; 921 int i; 922 923 for (i = 0; dspcode[i].reg != 0; i++) 924 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 925 } 926 927 static void 928 brgphy_ber_bug(struct mii_softc *sc) 929 { 930 static const struct { 931 int reg; 932 uint16_t val; 933 } dspcode[] = { 934 { BRGPHY_MII_AUXCTL, 0x0c00 }, 935 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 936 { BRGPHY_MII_DSP_RW_PORT, 0x310b }, 937 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 938 { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, 939 { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, 940 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, 941 { BRGPHY_MII_AUXCTL, 0x0400 }, 942 { 0, 0 }, 943 }; 944 int i; 945 946 for (i = 0; dspcode[i].reg != 0; i++) 947 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 948 } 949 950 /* BCM5701 A0/B0 CRC bug workaround */ 951 void 952 brgphy_crc_bug(struct mii_softc *sc) 953 { 954 static const struct { 955 int reg; 956 uint16_t val; 957 } dspcode[] = { 958 { BRGPHY_MII_DSP_ADDR_REG, 0x0a75 }, 959 { 0x1c, 0x8c68 }, 960 { 0x1c, 0x8d68 }, 961 { 0x1c, 0x8c68 }, 962 { 0, 0 }, 963 }; 964 int i; 965 966 for (i = 0; dspcode[i].reg != 0; i++) 967 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 968 } 969 970 static void 971 brgphy_disable_early_dac(struct mii_softc *sc) 972 { 973 uint32_t val; 974 975 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08); 976 val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 977 val &= ~(1 << 8); 978 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val); 979 980 } 981 982 static void 983 brgphy_jumbo_settings(struct mii_softc *sc) 984 { 985 u_int32_t val; 986 987 /* Set Jumbo frame settings in the PHY. */ 988 if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5401) { 989 /* Cannot do read-modify-write on the BCM5401 */ 990 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); 991 } else { 992 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 993 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 994 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 995 val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); 996 } 997 998 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 999 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 1000 val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); 1001 } 1002 1003 static void 1004 brgphy_eth_wirespeed(struct mii_softc *sc) 1005 { 1006 u_int32_t val; 1007 1008 /* Enable Ethernet@Wirespeed */ 1009 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 1010 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1011 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 1012 (val | (1 << 15) | (1 << 4))); 1013 } 1014