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