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