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