1 /* $NetBSD: brgphy.c,v 1.59 2011/06/07 10:10:44 cegger 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.59 2011/06/07 10:10:44 cegger 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_BROADCOM2, MII_MODEL_BROADCOM2_BCM5785, 206 MII_STR_BROADCOM2_BCM5785 }, 207 208 { MII_OUI_xxBROADCOM_ALT1, MII_MODEL_xxBROADCOM_ALT1_BCM5906, 209 MII_STR_xxBROADCOM_ALT1_BCM5906 }, 210 211 { 0, 0, 212 NULL }, 213 }; 214 215 static int 216 brgphymatch(device_t parent, cfdata_t match, void *aux) 217 { 218 struct mii_attach_args *ma = aux; 219 220 if (mii_phy_match(ma, brgphys) != NULL) 221 return (10); 222 223 return (0); 224 } 225 226 static void 227 brgphyattach(device_t parent, device_t self, void *aux) 228 { 229 struct brgphy_softc *bsc = device_private(self); 230 struct mii_softc *sc = &bsc->sc_mii; 231 struct mii_attach_args *ma = aux; 232 struct mii_data *mii = ma->mii_data; 233 const struct mii_phydesc *mpd; 234 prop_dictionary_t dict; 235 236 mpd = mii_phy_match(ma, brgphys); 237 aprint_naive(": Media interface\n"); 238 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 239 240 sc->mii_dev = self; 241 sc->mii_inst = mii->mii_instance; 242 sc->mii_phy = ma->mii_phyno; 243 sc->mii_mpd_model = MII_MODEL(ma->mii_id2); 244 sc->mii_mpd_rev = MII_REV(ma->mii_id2); 245 sc->mii_pdata = mii; 246 sc->mii_flags = ma->mii_flags; 247 sc->mii_anegticks = MII_ANEGTICKS; 248 sc->mii_funcs = &brgphy_funcs; 249 250 PHY_RESET(sc); 251 252 sc->mii_capabilities = 253 PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 254 if (sc->mii_capabilities & BMSR_EXTSTAT) 255 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 256 257 258 if (device_is_a(parent, "bge")) 259 bsc->sc_isbge = true; 260 else if (device_is_a(parent, "bnx")) 261 bsc->sc_isbnx = true; 262 263 if (bsc->sc_isbge || bsc->sc_isbnx) { 264 dict = device_properties(parent); 265 if (!prop_dictionary_get_uint32(dict, "phyflags", 266 &bsc->sc_phyflags)) 267 aprint_error_dev(self, "failed to get phyflags\n"); 268 if (!prop_dictionary_get_uint32(dict, "chipid", 269 &bsc->sc_chipid)) 270 aprint_error_dev(self, "failed to get chipid\n"); 271 } 272 273 aprint_normal_dev(self, ""); 274 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && 275 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) 276 aprint_error("no media present"); 277 else { 278 if (sc->mii_flags & MIIF_HAVEFIBER) { 279 sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; 280 281 /* 282 * Set the proper bits for capabilities so that the 283 * correct media get selected by mii_phy_add_media() 284 */ 285 sc->mii_capabilities |= BMSR_ANEG; 286 sc->mii_capabilities &= ~BMSR_100T4; 287 sc->mii_extcapabilities |= EXTSR_1000XFDX; 288 289 if (bsc->sc_isbnx) { 290 /* 291 * 2.5Gb support is a software enabled feature 292 * on the BCM5708S and BCM5709S controllers. 293 */ 294 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 295 if (bsc->sc_phyflags 296 & BNX_PHY_2_5G_CAPABLE_FLAG) { 297 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, 298 IFM_FDX, sc->mii_inst), 0); 299 aprint_normal("2500baseSX-FDX, "); 300 #undef ADD 301 } 302 } 303 } 304 mii_phy_add_media(sc); 305 } 306 aprint_normal("\n"); 307 308 } 309 310 static int 311 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 312 { 313 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 314 int reg, speed, gig; 315 316 switch (cmd) { 317 case MII_POLLSTAT: 318 /* 319 * If we're not polling our PHY instance, just return. 320 */ 321 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 322 return (0); 323 break; 324 325 case MII_MEDIACHG: 326 /* 327 * If the media indicates a different PHY instance, 328 * isolate ourselves. 329 */ 330 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 331 reg = PHY_READ(sc, MII_BMCR); 332 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 333 return (0); 334 } 335 336 /* 337 * If the interface is not up, don't do anything. 338 */ 339 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 340 break; 341 342 PHY_RESET(sc); /* XXX hardware bug work-around */ 343 344 switch (IFM_SUBTYPE(ife->ifm_media)) { 345 case IFM_AUTO: 346 (void) brgphy_mii_phy_auto(sc); 347 break; 348 case IFM_1000_T: 349 speed = BMCR_S1000; 350 goto setit; 351 case IFM_100_TX: 352 speed = BMCR_S100; 353 goto setit; 354 case IFM_10_T: 355 speed = BMCR_S10; 356 setit: 357 brgphy_loop(sc); 358 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 359 speed |= BMCR_FDX; 360 gig = GTCR_ADV_1000TFDX; 361 } else { 362 gig = GTCR_ADV_1000THDX; 363 } 364 365 PHY_WRITE(sc, MII_100T2CR, 0); 366 PHY_WRITE(sc, MII_ANAR, ANAR_CSMA); 367 PHY_WRITE(sc, MII_BMCR, speed); 368 369 if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) 370 break; 371 372 PHY_WRITE(sc, MII_100T2CR, gig); 373 PHY_WRITE(sc, MII_BMCR, 374 speed|BMCR_AUTOEN|BMCR_STARTNEG); 375 376 if (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701) 377 break; 378 379 if (mii->mii_media.ifm_media & IFM_ETH_MASTER) 380 gig |= GTCR_MAN_MS | GTCR_ADV_MS; 381 PHY_WRITE(sc, MII_100T2CR, gig); 382 break; 383 default: 384 return (EINVAL); 385 } 386 break; 387 388 case MII_TICK: 389 /* 390 * If we're not currently selected, just return. 391 */ 392 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 393 return (0); 394 395 if (mii_phy_tick(sc) == EJUSTRETURN) 396 return (0); 397 break; 398 399 case MII_DOWN: 400 mii_phy_down(sc); 401 return (0); 402 } 403 404 /* Update the media status. */ 405 mii_phy_status(sc); 406 407 /* 408 * Callback if something changed. Note that we need to poke the DSP on 409 * the Broadcom PHYs if the media changes. 410 */ 411 if (sc->mii_media_active != mii->mii_media_active || 412 sc->mii_media_status != mii->mii_media_status || 413 cmd == MII_MEDIACHG) { 414 switch (sc->mii_mpd_model) { 415 case MII_MODEL_BROADCOM_BCM5400: 416 brgphy_bcm5401_dspcode(sc); 417 break; 418 case MII_MODEL_BROADCOM_BCM5401: 419 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) 420 brgphy_bcm5401_dspcode(sc); 421 break; 422 case MII_MODEL_BROADCOM_BCM5411: 423 brgphy_bcm5411_dspcode(sc); 424 break; 425 } 426 } 427 428 /* Callback if something changed. */ 429 mii_phy_update(sc, cmd); 430 return (0); 431 } 432 433 static void 434 brgphy_status(struct mii_softc *sc) 435 { 436 struct mii_data *mii = sc->mii_pdata; 437 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 438 int bmcr, bmsr, auxsts, gtsr; 439 440 mii->mii_media_status = IFM_AVALID; 441 mii->mii_media_active = IFM_ETHER; 442 443 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 444 if (bmsr & BMSR_LINK) 445 mii->mii_media_status |= IFM_ACTIVE; 446 447 bmcr = PHY_READ(sc, MII_BMCR); 448 if (bmcr & BMCR_ISO) { 449 mii->mii_media_active |= IFM_NONE; 450 mii->mii_media_status = 0; 451 return; 452 } 453 454 if (bmcr & BMCR_LOOP) 455 mii->mii_media_active |= IFM_LOOP; 456 457 if (bmcr & BMCR_AUTOEN) { 458 /* 459 * The media status bits are only valid of autonegotiation 460 * has completed (or it's disabled). 461 */ 462 if ((bmsr & BMSR_ACOMP) == 0) { 463 /* Erg, still trying, I guess... */ 464 mii->mii_media_active |= IFM_NONE; 465 return; 466 } 467 468 if (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S) { 469 470 /* 5709S has its own general purpose status registers */ 471 472 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 473 BRGPHY_BLOCK_ADDR_GP_STATUS); 474 475 auxsts = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); 476 477 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 478 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 479 480 switch (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { 481 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: 482 mii->mii_media_active |= IFM_10_FL; 483 break; 484 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: 485 mii->mii_media_active |= IFM_100_FX; 486 break; 487 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: 488 mii->mii_media_active |= IFM_1000_SX; 489 break; 490 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: 491 mii->mii_media_active |= IFM_2500_SX; 492 break; 493 default: 494 mii->mii_media_active |= IFM_NONE; 495 mii->mii_media_status = 0; 496 break; 497 } 498 499 if (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_FDX) 500 mii->mii_media_active |= IFM_FDX; 501 else 502 mii->mii_media_active |= IFM_HDX; 503 504 } else { 505 auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS); 506 507 switch (auxsts & BRGPHY_AUXSTS_AN_RES) { 508 case BRGPHY_RES_1000FD: 509 mii->mii_media_active |= IFM_1000_T|IFM_FDX; 510 gtsr = PHY_READ(sc, MII_100T2SR); 511 if (gtsr & GTSR_MS_RES) 512 mii->mii_media_active |= IFM_ETH_MASTER; 513 break; 514 515 case BRGPHY_RES_1000HD: 516 mii->mii_media_active |= IFM_1000_T; 517 gtsr = PHY_READ(sc, MII_100T2SR); 518 if (gtsr & GTSR_MS_RES) 519 mii->mii_media_active |= IFM_ETH_MASTER; 520 break; 521 522 case BRGPHY_RES_100FD: 523 mii->mii_media_active |= IFM_100_TX|IFM_FDX; 524 break; 525 526 case BRGPHY_RES_100T4: 527 mii->mii_media_active |= IFM_100_T4; 528 break; 529 530 case BRGPHY_RES_100HD: 531 mii->mii_media_active |= IFM_100_TX; 532 break; 533 534 case BRGPHY_RES_10FD: 535 mii->mii_media_active |= IFM_10_T|IFM_FDX; 536 break; 537 538 case BRGPHY_RES_10HD: 539 mii->mii_media_active |= IFM_10_T; 540 break; 541 542 default: 543 mii->mii_media_active |= IFM_NONE; 544 mii->mii_media_status = 0; 545 } 546 } 547 548 if (mii->mii_media_active & IFM_FDX) 549 mii->mii_media_active |= mii_phy_flowstatus(sc); 550 551 } else 552 mii->mii_media_active = ife->ifm_media; 553 } 554 555 int 556 brgphy_mii_phy_auto(struct mii_softc *sc) 557 { 558 int anar, ktcr = 0; 559 560 brgphy_loop(sc); 561 PHY_RESET(sc); 562 563 ktcr = GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX; 564 if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701) 565 ktcr |= GTCR_MAN_MS|GTCR_ADV_MS; 566 PHY_WRITE(sc, MII_100T2CR, ktcr); 567 ktcr = PHY_READ(sc, MII_100T2CR); 568 DELAY(1000); 569 570 if (sc->mii_flags & MIIF_HAVEFIBER) { 571 anar = ANAR_X_FD | ANAR_X_HD; 572 if (sc->mii_flags & MIIF_DOPAUSE) 573 anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE; 574 } else { 575 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 576 if (sc->mii_flags & MIIF_DOPAUSE) 577 anar |= ANAR_FC | ANAR_X_PAUSE_ASYM; 578 } 579 PHY_WRITE(sc, MII_ANAR, anar); 580 DELAY(1000); 581 582 /* Start autonegotiation */ 583 PHY_WRITE(sc, MII_BMCR, 584 BMCR_AUTOEN | BMCR_STARTNEG); 585 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); 586 587 return (EJUSTRETURN); 588 } 589 590 void 591 brgphy_loop(struct mii_softc *sc) 592 { 593 u_int32_t bmsr; 594 int i; 595 596 PHY_WRITE(sc, MII_BMCR, BMCR_LOOP); 597 for (i = 0; i < 15000; i++) { 598 bmsr = PHY_READ(sc, MII_BMSR); 599 if (!(bmsr & BMSR_LINK)) 600 break; 601 DELAY(10); 602 } 603 } 604 605 static void 606 brgphy_reset(struct mii_softc *sc) 607 { 608 struct brgphy_softc *bsc = device_private(sc->mii_dev); 609 610 mii_phy_reset(sc); 611 612 switch (sc->mii_mpd_model) { 613 case MII_MODEL_BROADCOM_BCM5400: 614 brgphy_bcm5401_dspcode(sc); 615 break; 616 case MII_MODEL_BROADCOM_BCM5401: 617 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) 618 brgphy_bcm5401_dspcode(sc); 619 break; 620 case MII_MODEL_BROADCOM_BCM5411: 621 brgphy_bcm5411_dspcode(sc); 622 break; 623 case MII_MODEL_BROADCOM_BCM5421: 624 brgphy_bcm5421_dspcode(sc); 625 break; 626 case MII_MODEL_BROADCOM_BCM54K2: 627 brgphy_bcm54k2_dspcode(sc); 628 break; 629 } 630 631 /* Handle any bge (NetXtreme/NetLink) workarounds. */ 632 if (bsc->sc_isbge) { 633 if (!(sc->mii_flags & MIIF_HAVEFIBER)) { 634 635 if (bsc->sc_phyflags & BGE_PHY_ADC_BUG) 636 brgphy_adc_bug(sc); 637 if (bsc->sc_phyflags & BGE_PHY_5704_A0_BUG) 638 brgphy_5704_a0_bug(sc); 639 if (bsc->sc_phyflags & BGE_PHY_BER_BUG) 640 brgphy_ber_bug(sc); 641 else if (bsc->sc_phyflags & BGE_PHY_JITTER_BUG) { 642 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00); 643 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 644 0x000a); 645 646 if (bsc->sc_phyflags 647 & BGE_PHY_ADJUST_TRIM) { 648 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 649 0x110b); 650 PHY_WRITE(sc, BRGPHY_TEST1, 651 BRGPHY_TEST1_TRIM_EN | 0x4); 652 } else { 653 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 654 0x010b); 655 } 656 657 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400); 658 } 659 if (bsc->sc_phyflags & BGE_PHY_CRC_BUG) 660 brgphy_crc_bug(sc); 661 662 /* Set Jumbo frame settings in the PHY. */ 663 if (bsc->sc_phyflags & BGE_JUMBO_CAPABLE) 664 brgphy_jumbo_settings(sc); 665 666 /* Adjust output voltage */ 667 if (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5906) 668 PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); 669 670 /* Enable Ethernet@Wirespeed */ 671 if (!(bsc->sc_phyflags & BGE_NO_ETH_WIRE_SPEED)) 672 brgphy_eth_wirespeed(sc); 673 674 #if 0 675 /* Enable Link LED on Dell boxes */ 676 if (bsc->sc_phyflags & BGE_NO_3LED) { 677 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 678 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) 679 & ~BRGPHY_PHY_EXTCTL_3_LED); 680 } 681 #endif 682 } 683 /* Handle any bnx (NetXtreme II) workarounds. */ 684 } else if (bsc->sc_isbnx) { 685 #if 0 /* not yet */ 686 if (sc->mii_mpd_model == MII_MODEL_xxBROADCOM2_BCM5708S) { 687 /* Store autoneg capabilities/results in digital block (Page 0) */ 688 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); 689 PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, 690 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); 691 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); 692 693 /* Enable fiber mode and autodetection */ 694 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, 695 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | 696 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | 697 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); 698 699 /* Enable parallel detection */ 700 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, 701 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | 702 BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); 703 704 /* Advertise 2.5G support through next page during autoneg */ 705 if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) 706 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, 707 PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | 708 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 709 710 /* Increase TX signal amplitude */ 711 if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) || 712 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) || 713 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) { 714 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 715 BRGPHY_5708S_TX_MISC_PG5); 716 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, 717 PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & 718 ~BRGPHY_5708S_PG5_TXACTL1_VCM); 719 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 720 BRGPHY_5708S_DIG_PG0); 721 } 722 723 /* Backplanes use special driver/pre-driver/pre-emphasis values. */ 724 if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) && 725 (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) { 726 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 727 BRGPHY_5708S_TX_MISC_PG5); 728 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, 729 bnx_sc->bnx_port_hw_cfg & 730 BNX_PORT_HW_CFG_CFG_TXCTL3_MASK); 731 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 732 BRGPHY_5708S_DIG_PG0); 733 } 734 } else 735 #endif 736 if (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S) { 737 /* Select the SerDes Digital block of the AN MMD. */ 738 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 739 BRGPHY_BLOCK_ADDR_SERDES_DIG); 740 741 PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, 742 (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) & 743 ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) | 744 BRGPHY_SD_DIG_1000X_CTL1_FIBER); 745 746 if (bsc->sc_phyflags & BNX_PHY_2_5G_CAPABLE_FLAG) { 747 /* Select the Over 1G block of the AN MMD. */ 748 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 749 BRGPHY_BLOCK_ADDR_OVER_1G); 750 751 /* 752 * Enable autoneg "Next Page" to advertise 753 * 2.5G support. 754 */ 755 PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, 756 PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) | 757 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 758 } 759 760 /* 761 * Select the Multi-Rate Backplane Ethernet block of 762 * the AN MMD. 763 */ 764 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 765 BRGPHY_BLOCK_ADDR_MRBE); 766 767 /* Enable MRBE speed autoneg. */ 768 PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, 769 PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) | 770 BRGPHY_MRBE_MSG_PG5_NP_MBRE | 771 BRGPHY_MRBE_MSG_PG5_NP_T2); 772 773 /* Select the Clause 73 User B0 block of the AN MMD. */ 774 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 775 BRGPHY_BLOCK_ADDR_CL73_USER_B0); 776 777 /* Enable MRBE speed autoneg. */ 778 PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, 779 BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | 780 BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | 781 BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); 782 783 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 784 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 785 786 } else if (_BNX_CHIP_NUM(bsc->sc_chipid) == BNX_CHIP_NUM_5709) { 787 if (_BNX_CHIP_REV(bsc->sc_chipid) == BNX_CHIP_REV_Ax || 788 _BNX_CHIP_REV(bsc->sc_chipid) == BNX_CHIP_REV_Bx) 789 brgphy_disable_early_dac(sc); 790 791 /* Set Jumbo frame settings in the PHY. */ 792 brgphy_jumbo_settings(sc); 793 794 /* Enable Ethernet@Wirespeed */ 795 brgphy_eth_wirespeed(sc); 796 } else { 797 if (!(sc->mii_flags & MIIF_HAVEFIBER)) { 798 brgphy_ber_bug(sc); 799 800 /* Set Jumbo frame settings in the PHY. */ 801 brgphy_jumbo_settings(sc); 802 803 /* Enable Ethernet@Wirespeed */ 804 brgphy_eth_wirespeed(sc); 805 } 806 } 807 } 808 } 809 810 /* Turn off tap power management on 5401. */ 811 static void 812 brgphy_bcm5401_dspcode(struct mii_softc *sc) 813 { 814 static const struct { 815 int reg; 816 uint16_t val; 817 } dspcode[] = { 818 { BRGPHY_MII_AUXCTL, 0x0c20 }, 819 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 820 { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 821 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 822 { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 823 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 824 { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 825 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 826 { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 827 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 828 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 829 { 0, 0 }, 830 }; 831 int i; 832 833 for (i = 0; dspcode[i].reg != 0; i++) 834 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 835 delay(40); 836 } 837 838 static void 839 brgphy_bcm5411_dspcode(struct mii_softc *sc) 840 { 841 static const struct { 842 int reg; 843 uint16_t val; 844 } dspcode[] = { 845 { 0x1c, 0x8c23 }, 846 { 0x1c, 0x8ca3 }, 847 { 0x1c, 0x8c23 }, 848 { 0, 0 }, 849 }; 850 int i; 851 852 for (i = 0; dspcode[i].reg != 0; i++) 853 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 854 } 855 856 void 857 brgphy_bcm5421_dspcode(struct mii_softc *sc) 858 { 859 uint16_t data; 860 861 /* Set Class A mode */ 862 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007); 863 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 864 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400); 865 866 /* Set FFE gamma override to -0.125 */ 867 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007); 868 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 869 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800); 870 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 871 data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 872 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200); 873 } 874 875 void 876 brgphy_bcm54k2_dspcode(struct mii_softc *sc) 877 { 878 static const struct { 879 int reg; 880 uint16_t val; 881 } dspcode[] = { 882 { 4, 0x01e1 }, 883 { 9, 0x0300 }, 884 { 0, 0 }, 885 }; 886 int i; 887 888 for (i = 0; dspcode[i].reg != 0; i++) 889 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 890 } 891 892 static void 893 brgphy_adc_bug(struct mii_softc *sc) 894 { 895 static const struct { 896 int reg; 897 uint16_t val; 898 } dspcode[] = { 899 { BRGPHY_MII_AUXCTL, 0x0c00 }, 900 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 901 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 902 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 903 { BRGPHY_MII_DSP_RW_PORT, 0x0323 }, 904 { BRGPHY_MII_AUXCTL, 0x0400 }, 905 { 0, 0 }, 906 }; 907 int i; 908 909 for (i = 0; dspcode[i].reg != 0; i++) 910 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 911 } 912 913 static void 914 brgphy_5704_a0_bug(struct mii_softc *sc) 915 { 916 static const struct { 917 int reg; 918 uint16_t val; 919 } dspcode[] = { 920 { 0x1c, 0x8d68 }, 921 { 0x1c, 0x8d68 }, 922 { 0, 0 }, 923 }; 924 int i; 925 926 for (i = 0; dspcode[i].reg != 0; i++) 927 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 928 } 929 930 static void 931 brgphy_ber_bug(struct mii_softc *sc) 932 { 933 static const struct { 934 int reg; 935 uint16_t val; 936 } dspcode[] = { 937 { BRGPHY_MII_AUXCTL, 0x0c00 }, 938 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 939 { BRGPHY_MII_DSP_RW_PORT, 0x310b }, 940 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 941 { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, 942 { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, 943 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, 944 { BRGPHY_MII_AUXCTL, 0x0400 }, 945 { 0, 0 }, 946 }; 947 int i; 948 949 for (i = 0; dspcode[i].reg != 0; i++) 950 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 951 } 952 953 /* BCM5701 A0/B0 CRC bug workaround */ 954 void 955 brgphy_crc_bug(struct mii_softc *sc) 956 { 957 static const struct { 958 int reg; 959 uint16_t val; 960 } dspcode[] = { 961 { BRGPHY_MII_DSP_ADDR_REG, 0x0a75 }, 962 { 0x1c, 0x8c68 }, 963 { 0x1c, 0x8d68 }, 964 { 0x1c, 0x8c68 }, 965 { 0, 0 }, 966 }; 967 int i; 968 969 for (i = 0; dspcode[i].reg != 0; i++) 970 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 971 } 972 973 static void 974 brgphy_disable_early_dac(struct mii_softc *sc) 975 { 976 uint32_t val; 977 978 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08); 979 val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 980 val &= ~(1 << 8); 981 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val); 982 983 } 984 985 static void 986 brgphy_jumbo_settings(struct mii_softc *sc) 987 { 988 u_int32_t val; 989 990 /* Set Jumbo frame settings in the PHY. */ 991 if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5401) { 992 /* Cannot do read-modify-write on the BCM5401 */ 993 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); 994 } else { 995 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 996 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 997 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 998 val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); 999 } 1000 1001 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 1002 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 1003 val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); 1004 } 1005 1006 static void 1007 brgphy_eth_wirespeed(struct mii_softc *sc) 1008 { 1009 u_int32_t val; 1010 1011 /* Enable Ethernet@Wirespeed */ 1012 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 1013 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1014 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 1015 (val | (1 << 15) | (1 << 4))); 1016 } 1017