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