1 /* $NetBSD: brgphy.c,v 1.90 2020/05/25 19:48:38 jmcneill 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.90 2020/05/25 19:48:38 jmcneill 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 uint32_t sc_shared_hwcfg; /* shared hw config */ 96 uint32_t sc_port_hwcfg; /* port specific hw config */ 97 }; 98 99 CFATTACH_DECL_NEW(brgphy, sizeof(struct brgphy_softc), 100 brgphymatch, brgphyattach, mii_phy_detach, mii_phy_activate); 101 102 static int brgphy_service(struct mii_softc *, struct mii_data *, int); 103 static void brgphy_copper_status(struct mii_softc *); 104 static void brgphy_fiber_status(struct mii_softc *); 105 static void brgphy_5708s_status(struct mii_softc *); 106 static void brgphy_5709s_status(struct mii_softc *); 107 static int brgphy_mii_phy_auto(struct mii_softc *); 108 static void brgphy_loop(struct mii_softc *); 109 static void brgphy_reset(struct mii_softc *); 110 static void brgphy_bcm5401_dspcode(struct mii_softc *); 111 static void brgphy_bcm5411_dspcode(struct mii_softc *); 112 static void brgphy_bcm5421_dspcode(struct mii_softc *); 113 static void brgphy_bcm54k2_dspcode(struct mii_softc *); 114 static void brgphy_adc_bug(struct mii_softc *); 115 static void brgphy_5704_a0_bug(struct mii_softc *); 116 static void brgphy_ber_bug(struct mii_softc *); 117 static void brgphy_crc_bug(struct mii_softc *); 118 static void brgphy_disable_early_dac(struct mii_softc *); 119 static void brgphy_jumbo_settings(struct mii_softc *); 120 static void brgphy_eth_wirespeed(struct mii_softc *); 121 static void brgphy_bcm54xx_clock_delay(struct mii_softc *); 122 123 static const struct mii_phy_funcs brgphy_copper_funcs = { 124 brgphy_service, brgphy_copper_status, brgphy_reset, 125 }; 126 127 static const struct mii_phy_funcs brgphy_fiber_funcs = { 128 brgphy_service, brgphy_fiber_status, brgphy_reset, 129 }; 130 131 static const struct mii_phy_funcs brgphy_5708s_funcs = { 132 brgphy_service, brgphy_5708s_status, brgphy_reset, 133 }; 134 135 static const struct mii_phy_funcs brgphy_5709s_funcs = { 136 brgphy_service, brgphy_5709s_status, brgphy_reset, 137 }; 138 139 static const struct mii_phydesc brgphys[] = { 140 MII_PHY_DESC(BROADCOM, BCM5400), 141 MII_PHY_DESC(BROADCOM, BCM5401), 142 MII_PHY_DESC(BROADCOM, BCM5402), 143 MII_PHY_DESC(BROADCOM, BCM5404), 144 MII_PHY_DESC(BROADCOM, BCM5411), 145 MII_PHY_DESC(BROADCOM, BCM5421), 146 MII_PHY_DESC(BROADCOM, BCM5424), 147 MII_PHY_DESC(BROADCOM, BCM5461), 148 MII_PHY_DESC(BROADCOM, BCM5462), 149 MII_PHY_DESC(BROADCOM, BCM5464), 150 MII_PHY_DESC(BROADCOM, BCM5466), 151 MII_PHY_DESC(BROADCOM, BCM54K2), 152 MII_PHY_DESC(BROADCOM, BCM5701), 153 MII_PHY_DESC(BROADCOM, BCM5703), 154 MII_PHY_DESC(BROADCOM, BCM5704), 155 MII_PHY_DESC(BROADCOM, BCM5705), 156 MII_PHY_DESC(BROADCOM, BCM5706), 157 MII_PHY_DESC(BROADCOM, BCM5714), 158 MII_PHY_DESC(BROADCOM, BCM5750), 159 MII_PHY_DESC(BROADCOM, BCM5752), 160 MII_PHY_DESC(BROADCOM, BCM5780), 161 MII_PHY_DESC(BROADCOM, BCM5708C), 162 MII_PHY_DESC(BROADCOM2, BCM5481), 163 MII_PHY_DESC(BROADCOM2, BCM5482), 164 MII_PHY_DESC(BROADCOM2, BCM5708S), 165 MII_PHY_DESC(BROADCOM2, BCM5709C), 166 MII_PHY_DESC(BROADCOM2, BCM5709S), 167 MII_PHY_DESC(BROADCOM2, BCM5709CAX), 168 MII_PHY_DESC(BROADCOM2, BCM5722), 169 MII_PHY_DESC(BROADCOM2, BCM5754), 170 MII_PHY_DESC(BROADCOM2, BCM5755), 171 MII_PHY_DESC(BROADCOM2, BCM5756), 172 MII_PHY_DESC(BROADCOM2, BCM5761), 173 MII_PHY_DESC(BROADCOM2, BCM5784), 174 MII_PHY_DESC(BROADCOM2, BCM5785), 175 MII_PHY_DESC(BROADCOM3, BCM5717C), 176 MII_PHY_DESC(BROADCOM3, BCM5719C), 177 MII_PHY_DESC(BROADCOM3, BCM5720C), 178 MII_PHY_DESC(BROADCOM3, BCM57765), 179 MII_PHY_DESC(BROADCOM3, BCM57780), 180 MII_PHY_DESC(BROADCOM4, BCM54213PE), 181 MII_PHY_DESC(BROADCOM4, BCM5725C), 182 MII_PHY_DESC(xxBROADCOM_ALT1, BCM5906), 183 MII_PHY_END, 184 }; 185 186 static int 187 brgphymatch(device_t parent, cfdata_t match, void *aux) 188 { 189 struct mii_attach_args *ma = aux; 190 191 if (mii_phy_match(ma, brgphys) != NULL) 192 return 10; 193 194 return 0; 195 } 196 197 static void 198 brgphyattach(device_t parent, device_t self, void *aux) 199 { 200 struct brgphy_softc *bsc = device_private(self); 201 struct mii_softc *sc = &bsc->sc_mii; 202 struct mii_attach_args *ma = aux; 203 struct mii_data *mii = ma->mii_data; 204 const struct mii_phydesc *mpd; 205 prop_dictionary_t dict; 206 207 mpd = mii_phy_match(ma, brgphys); 208 aprint_naive(": Media interface\n"); 209 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 210 211 sc->mii_dev = self; 212 sc->mii_inst = mii->mii_instance; 213 sc->mii_phy = ma->mii_phyno; 214 sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); 215 sc->mii_mpd_model = MII_MODEL(ma->mii_id2); 216 sc->mii_mpd_rev = MII_REV(ma->mii_id2); 217 sc->mii_pdata = mii; 218 sc->mii_flags = ma->mii_flags; 219 220 if (device_is_a(parent, "bge")) 221 bsc->sc_isbge = true; 222 else if (device_is_a(parent, "bnx")) 223 bsc->sc_isbnx = true; 224 225 dict = device_properties(parent); 226 if (bsc->sc_isbge || bsc->sc_isbnx) { 227 if (!prop_dictionary_get_uint32(dict, "phyflags", 228 &bsc->sc_phyflags)) 229 aprint_error_dev(self, "failed to get phyflags\n"); 230 if (!prop_dictionary_get_uint32(dict, "chipid", 231 &bsc->sc_chipid)) 232 aprint_error_dev(self, "failed to get chipid\n"); 233 } 234 235 if (bsc->sc_isbnx) { 236 /* Currently, only bnx use sc_shared_hwcfg and sc_port_hwcfg */ 237 if (!prop_dictionary_get_uint32(dict, "shared_hwcfg", 238 &bsc->sc_shared_hwcfg)) 239 aprint_error_dev(self, "failed to get shared_hwcfg\n"); 240 if (!prop_dictionary_get_uint32(dict, "port_hwcfg", 241 &bsc->sc_port_hwcfg)) 242 aprint_error_dev(self, "failed to get port_hwcfg\n"); 243 } 244 245 if (sc->mii_flags & MIIF_HAVEFIBER) { 246 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) 247 && sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5708S) 248 sc->mii_funcs = &brgphy_5708s_funcs; 249 else if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) 250 && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S)) { 251 if (bsc->sc_isbnx) 252 sc->mii_funcs = &brgphy_5709s_funcs; 253 else { 254 /* 255 * XXX 256 * 5720S and 5709S shares the same PHY id. 257 * Assume 5720S PHY if parent device is bge(4). 258 */ 259 sc->mii_funcs = &brgphy_5708s_funcs; 260 } 261 } else 262 sc->mii_funcs = &brgphy_fiber_funcs; 263 } else 264 sc->mii_funcs = &brgphy_copper_funcs; 265 266 mii_lock(mii); 267 268 PHY_RESET(sc); 269 270 PHY_READ(sc, MII_BMSR, &sc->mii_capabilities); 271 sc->mii_capabilities &= ma->mii_capmask; 272 if (sc->mii_capabilities & BMSR_EXTSTAT) 273 PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities); 274 275 mii_unlock(mii); 276 277 if (sc->mii_flags & MIIF_HAVEFIBER) { 278 mii_lock(mii); 279 sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; 280 281 /* 282 * Set the proper bits for capabilities so that the 283 * correct media get selected by mii_phy_add_media() 284 */ 285 sc->mii_capabilities |= BMSR_ANEG; 286 sc->mii_capabilities &= ~BMSR_100T4; 287 sc->mii_extcapabilities |= EXTSR_1000XFDX; 288 mii_unlock(mii); 289 290 if (bsc->sc_isbnx) { 291 /* 292 * 2.5Gb support is a software enabled feature 293 * on the BCM5708S and BCM5709S controllers. 294 */ 295 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 296 if (bsc->sc_phyflags 297 & BNX_PHY_2_5G_CAPABLE_FLAG) { 298 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, 299 IFM_FDX, sc->mii_inst), 0); 300 aprint_normal_dev(self, "2500baseSX-FDX\n"); 301 #undef ADD 302 } 303 } 304 } 305 mii_phy_add_media(sc); 306 } 307 308 static int 309 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 310 { 311 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 312 uint16_t reg, speed, gig; 313 314 KASSERT(mii_locked(mii)); 315 316 switch (cmd) { 317 case MII_POLLSTAT: 318 /* If we're not polling our PHY instance, just return. */ 319 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 320 return 0; 321 break; 322 323 case MII_MEDIACHG: 324 /* 325 * If the media indicates a different PHY instance, 326 * isolate ourselves. 327 */ 328 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 329 PHY_READ(sc, MII_BMCR, ®); 330 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 331 return 0; 332 } 333 334 /* If the interface is not up, don't do anything. */ 335 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 336 break; 337 338 PHY_RESET(sc); /* XXX hardware bug work-around */ 339 340 switch (IFM_SUBTYPE(ife->ifm_media)) { 341 case IFM_AUTO: 342 (void) brgphy_mii_phy_auto(sc); 343 break; 344 case IFM_2500_SX: 345 speed = BRGPHY_5708S_BMCR_2500; 346 goto setit; 347 case IFM_1000_SX: 348 case IFM_1000_T: 349 speed = BMCR_S1000; 350 goto setit; 351 case IFM_100_TX: 352 speed = BMCR_S100; 353 goto setit; 354 case IFM_10_T: 355 speed = BMCR_S10; 356 setit: 357 brgphy_loop(sc); 358 if ((ife->ifm_media & IFM_FDX) != 0) { 359 speed |= BMCR_FDX; 360 gig = GTCR_ADV_1000TFDX; 361 } else 362 gig = GTCR_ADV_1000THDX; 363 364 PHY_WRITE(sc, MII_100T2CR, 0); 365 PHY_WRITE(sc, MII_ANAR, ANAR_CSMA); 366 PHY_WRITE(sc, MII_BMCR, speed); 367 368 if ((IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) && 369 (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_SX) && 370 (IFM_SUBTYPE(ife->ifm_media) != IFM_2500_SX)) 371 break; 372 373 PHY_WRITE(sc, MII_100T2CR, gig); 374 PHY_WRITE(sc, MII_BMCR, 375 speed | BMCR_AUTOEN | BMCR_STARTNEG); 376 377 if ((sc->mii_mpd_oui != MII_OUI_BROADCOM) 378 || (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701)) 379 break; 380 381 if (mii->mii_media.ifm_media & IFM_ETH_MASTER) 382 gig |= GTCR_MAN_MS | GTCR_ADV_MS; 383 PHY_WRITE(sc, MII_100T2CR, gig); 384 break; 385 default: 386 return EINVAL; 387 } 388 break; 389 390 case MII_TICK: 391 /* If we're not currently selected, just return. */ 392 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 393 return 0; 394 395 /* Is the interface even up? */ 396 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 397 return 0; 398 399 /* Only used for autonegotiation. */ 400 if ((IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) && 401 (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)) { 402 sc->mii_ticks = 0; 403 break; 404 } 405 406 /* 407 * Check for link. 408 * Read the status register twice; BMSR_LINK is latch-low. 409 */ 410 PHY_READ(sc, MII_BMSR, ®); 411 PHY_READ(sc, MII_BMSR, ®); 412 if (reg & BMSR_LINK) { 413 sc->mii_ticks = 0; 414 break; 415 } 416 417 /* 418 * mii_ticks == 0 means it's the first tick after changing the 419 * media or the link became down since the last tick 420 * (see above), so break to update the status. 421 */ 422 if (sc->mii_ticks++ == 0) 423 break; 424 425 /* Only retry autonegotiation every mii_anegticks seconds. */ 426 KASSERT(sc->mii_anegticks != 0); 427 if (sc->mii_ticks <= sc->mii_anegticks) 428 break; 429 430 brgphy_mii_phy_auto(sc); 431 break; 432 433 case MII_DOWN: 434 mii_phy_down(sc); 435 return 0; 436 } 437 438 /* Update the media status. */ 439 mii_phy_status(sc); 440 441 /* 442 * Callback if something changed. Note that we need to poke the DSP on 443 * the Broadcom PHYs if the media changes. 444 */ 445 if (sc->mii_media_active != mii->mii_media_active || 446 sc->mii_media_status != mii->mii_media_status || 447 cmd == MII_MEDIACHG) { 448 switch (sc->mii_mpd_oui) { 449 case MII_OUI_BROADCOM: 450 switch (sc->mii_mpd_model) { 451 case MII_MODEL_BROADCOM_BCM5400: 452 brgphy_bcm5401_dspcode(sc); 453 break; 454 case MII_MODEL_BROADCOM_BCM5401: 455 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) 456 brgphy_bcm5401_dspcode(sc); 457 break; 458 case MII_MODEL_BROADCOM_BCM5411: 459 brgphy_bcm5411_dspcode(sc); 460 break; 461 } 462 break; 463 case MII_OUI_BROADCOM4: 464 switch (sc->mii_mpd_model) { 465 case MII_MODEL_BROADCOM4_BCM54213PE: 466 brgphy_bcm54xx_clock_delay(sc); 467 break; 468 } 469 } 470 } 471 472 /* Callback if something changed. */ 473 mii_phy_update(sc, cmd); 474 return 0; 475 } 476 477 static void 478 brgphy_copper_status(struct mii_softc *sc) 479 { 480 struct mii_data *mii = sc->mii_pdata; 481 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 482 uint16_t bmcr, bmsr, auxsts, gtsr; 483 484 KASSERT(mii_locked(mii)); 485 486 mii->mii_media_status = IFM_AVALID; 487 mii->mii_media_active = IFM_ETHER; 488 489 PHY_READ(sc, MII_BMSR, &bmsr); 490 PHY_READ(sc, MII_BMSR, &bmsr); 491 if (bmsr & BMSR_LINK) 492 mii->mii_media_status |= IFM_ACTIVE; 493 494 PHY_READ(sc, MII_BMCR, &bmcr); 495 if (bmcr & BMCR_ISO) { 496 mii->mii_media_active |= IFM_NONE; 497 mii->mii_media_status = 0; 498 return; 499 } 500 501 if (bmcr & BMCR_LOOP) 502 mii->mii_media_active |= IFM_LOOP; 503 504 if (bmcr & BMCR_AUTOEN) { 505 /* 506 * The media status bits are only valid if autonegotiation 507 * has completed (or it's disabled). 508 */ 509 if ((bmsr & BMSR_ACOMP) == 0) { 510 /* Erg, still trying, I guess... */ 511 mii->mii_media_active |= IFM_NONE; 512 return; 513 } 514 515 PHY_READ(sc, BRGPHY_MII_AUXSTS, &auxsts); 516 517 switch (auxsts & BRGPHY_AUXSTS_AN_RES) { 518 case BRGPHY_RES_1000FD: 519 mii->mii_media_active |= IFM_1000_T | IFM_FDX; 520 PHY_READ(sc, MII_100T2SR, >sr); 521 if (gtsr & GTSR_MS_RES) 522 mii->mii_media_active |= IFM_ETH_MASTER; 523 break; 524 525 case BRGPHY_RES_1000HD: 526 mii->mii_media_active |= IFM_1000_T | IFM_HDX; 527 PHY_READ(sc, MII_100T2SR, >sr); 528 if (gtsr & GTSR_MS_RES) 529 mii->mii_media_active |= IFM_ETH_MASTER; 530 break; 531 532 case BRGPHY_RES_100FD: 533 mii->mii_media_active |= IFM_100_TX | IFM_FDX; 534 break; 535 536 case BRGPHY_RES_100T4: 537 mii->mii_media_active |= IFM_100_T4 | IFM_HDX; 538 break; 539 540 case BRGPHY_RES_100HD: 541 mii->mii_media_active |= IFM_100_TX | IFM_HDX; 542 break; 543 544 case BRGPHY_RES_10FD: 545 mii->mii_media_active |= IFM_10_T | IFM_FDX; 546 break; 547 548 case BRGPHY_RES_10HD: 549 mii->mii_media_active |= IFM_10_T | IFM_HDX; 550 break; 551 552 default: 553 mii->mii_media_active |= IFM_NONE; 554 mii->mii_media_status = 0; 555 } 556 557 if (mii->mii_media_active & IFM_FDX) 558 mii->mii_media_active |= mii_phy_flowstatus(sc); 559 560 } else 561 mii->mii_media_active = ife->ifm_media; 562 } 563 564 void 565 brgphy_fiber_status(struct mii_softc *sc) 566 { 567 struct mii_data *mii = sc->mii_pdata; 568 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 569 uint16_t bmcr, bmsr, anar, anlpar, result; 570 571 KASSERT(mii_locked(mii)); 572 573 mii->mii_media_status = IFM_AVALID; 574 mii->mii_media_active = IFM_ETHER; 575 576 PHY_READ(sc, MII_BMSR, &bmsr); 577 PHY_READ(sc, MII_BMSR, &bmsr); 578 if (bmsr & BMSR_LINK) 579 mii->mii_media_status |= IFM_ACTIVE; 580 581 PHY_READ(sc, MII_BMCR, &bmcr); 582 if (bmcr & BMCR_LOOP) 583 mii->mii_media_active |= IFM_LOOP; 584 585 if (bmcr & BMCR_AUTOEN) { 586 if ((bmsr & BMSR_ACOMP) == 0) { 587 /* Erg, still trying, I guess... */ 588 mii->mii_media_active |= IFM_NONE; 589 return; 590 } 591 592 mii->mii_media_active |= IFM_1000_SX; 593 594 PHY_READ(sc, MII_ANAR, &anar); 595 PHY_READ(sc, MII_ANLPAR, &anlpar); 596 result = anar & anlpar; 597 598 if (result & ANAR_X_FD) 599 mii->mii_media_active |= IFM_FDX; 600 else 601 mii->mii_media_active |= IFM_HDX; 602 603 if (mii->mii_media_active & IFM_FDX) 604 mii->mii_media_active |= mii_phy_flowstatus(sc); 605 } else 606 mii->mii_media_active = ife->ifm_media; 607 } 608 609 void 610 brgphy_5708s_status(struct mii_softc *sc) 611 { 612 struct mii_data *mii = sc->mii_pdata; 613 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 614 uint16_t bmcr, bmsr; 615 616 KASSERT(mii_locked(mii)); 617 618 mii->mii_media_status = IFM_AVALID; 619 mii->mii_media_active = IFM_ETHER; 620 621 PHY_READ(sc, MII_BMSR, &bmsr); 622 PHY_READ(sc, MII_BMSR, &bmsr); 623 if (bmsr & BMSR_LINK) 624 mii->mii_media_status |= IFM_ACTIVE; 625 626 PHY_READ(sc, MII_BMCR, &bmcr); 627 if (bmcr & BMCR_LOOP) 628 mii->mii_media_active |= IFM_LOOP; 629 630 if (bmcr & BMCR_AUTOEN) { 631 uint16_t xstat; 632 633 if ((bmsr & BMSR_ACOMP) == 0) { 634 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 635 BRGPHY_5708S_DIG_PG0); 636 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1, &xstat); 637 if ((xstat & BRGPHY_5708S_PG0_1000X_STAT1_LINK) == 0) { 638 /* Erg, still trying, I guess... */ 639 mii->mii_media_active |= IFM_NONE; 640 return; 641 } 642 } 643 644 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 645 BRGPHY_5708S_DIG_PG0); 646 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1, &xstat); 647 648 switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { 649 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: 650 mii->mii_media_active |= IFM_10_FL; 651 break; 652 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: 653 mii->mii_media_active |= IFM_100_FX; 654 break; 655 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: 656 mii->mii_media_active |= IFM_1000_SX; 657 break; 658 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: 659 mii->mii_media_active |= IFM_2500_SX; 660 break; 661 } 662 663 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) 664 mii->mii_media_active |= IFM_FDX; 665 else 666 mii->mii_media_active |= IFM_HDX; 667 668 if (mii->mii_media_active & IFM_FDX) { 669 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_TX_PAUSE) 670 mii->mii_media_active 671 |= IFM_FLOW | IFM_ETH_TXPAUSE; 672 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_RX_PAUSE) 673 mii->mii_media_active 674 |= IFM_FLOW | IFM_ETH_RXPAUSE; 675 } 676 } else 677 mii->mii_media_active = ife->ifm_media; 678 } 679 680 static void 681 brgphy_5709s_status(struct mii_softc *sc) 682 { 683 struct mii_data *mii = sc->mii_pdata; 684 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 685 uint16_t bmcr, bmsr, auxsts; 686 687 KASSERT(mii_locked(mii)); 688 689 mii->mii_media_status = IFM_AVALID; 690 mii->mii_media_active = IFM_ETHER; 691 692 PHY_READ(sc, MII_BMSR, &bmsr); 693 PHY_READ(sc, MII_BMSR, &bmsr); 694 if (bmsr & BMSR_LINK) 695 mii->mii_media_status |= IFM_ACTIVE; 696 697 PHY_READ(sc, MII_BMCR, &bmcr); 698 if (bmcr & BMCR_ISO) { 699 mii->mii_media_active |= IFM_NONE; 700 mii->mii_media_status = 0; 701 return; 702 } 703 704 if (bmcr & BMCR_LOOP) 705 mii->mii_media_active |= IFM_LOOP; 706 707 if (bmcr & BMCR_AUTOEN) { 708 /* 709 * The media status bits are only valid of autonegotiation 710 * has completed (or it's disabled). 711 */ 712 if ((bmsr & BMSR_ACOMP) == 0) { 713 /* Erg, still trying, I guess... */ 714 mii->mii_media_active |= IFM_NONE; 715 return; 716 } 717 718 /* 5709S has its own general purpose status registers */ 719 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_GP_STATUS); 720 PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS, &auxsts); 721 722 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 723 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 724 725 switch (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { 726 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: 727 mii->mii_media_active |= IFM_10_FL; 728 break; 729 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: 730 mii->mii_media_active |= IFM_100_FX; 731 break; 732 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: 733 mii->mii_media_active |= IFM_1000_SX; 734 break; 735 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: 736 mii->mii_media_active |= IFM_2500_SX; 737 break; 738 default: 739 mii->mii_media_active |= IFM_NONE; 740 mii->mii_media_status = 0; 741 break; 742 } 743 744 if (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_FDX) 745 mii->mii_media_active |= IFM_FDX; 746 else 747 mii->mii_media_active |= IFM_HDX; 748 749 if (mii->mii_media_active & IFM_FDX) 750 mii->mii_media_active |= mii_phy_flowstatus(sc); 751 } else 752 mii->mii_media_active = ife->ifm_media; 753 } 754 755 static int 756 brgphy_mii_phy_auto(struct mii_softc *sc) 757 { 758 uint16_t anar, ktcr = 0; 759 760 KASSERT(mii_locked(sc->mii_pdata)); 761 762 sc->mii_ticks = 0; 763 brgphy_loop(sc); 764 PHY_RESET(sc); 765 766 if (sc->mii_flags & MIIF_HAVEFIBER) { 767 anar = ANAR_X_FD | ANAR_X_HD; 768 if (sc->mii_flags & MIIF_DOPAUSE) 769 anar |= ANAR_X_PAUSE_TOWARDS; 770 } else { 771 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 772 if (sc->mii_flags & MIIF_DOPAUSE) 773 anar |= ANAR_FC | ANAR_PAUSE_ASYM; 774 ktcr = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; 775 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM) 776 && (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701)) 777 ktcr |= GTCR_MAN_MS | GTCR_ADV_MS; 778 PHY_WRITE(sc, MII_100T2CR, ktcr); 779 } 780 PHY_WRITE(sc, MII_ANAR, anar); 781 782 /* Start autonegotiation */ 783 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); 784 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); 785 786 return EJUSTRETURN; 787 } 788 789 static void 790 brgphy_loop(struct mii_softc *sc) 791 { 792 uint16_t bmsr; 793 int i; 794 795 KASSERT(mii_locked(sc->mii_pdata)); 796 797 PHY_WRITE(sc, MII_BMCR, BMCR_LOOP); 798 for (i = 0; i < 15000; i++) { 799 PHY_READ(sc, MII_BMSR, &bmsr); 800 if (!(bmsr & BMSR_LINK)) 801 break; 802 DELAY(10); 803 } 804 } 805 806 static void 807 brgphy_reset(struct mii_softc *sc) 808 { 809 struct brgphy_softc *bsc = device_private(sc->mii_dev); 810 uint16_t reg; 811 812 KASSERT(mii_locked(sc->mii_pdata)); 813 814 mii_phy_reset(sc); 815 switch (sc->mii_mpd_oui) { 816 case MII_OUI_BROADCOM: 817 switch (sc->mii_mpd_model) { 818 case MII_MODEL_BROADCOM_BCM5400: 819 brgphy_bcm5401_dspcode(sc); 820 break; 821 case MII_MODEL_BROADCOM_BCM5401: 822 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) 823 brgphy_bcm5401_dspcode(sc); 824 break; 825 case MII_MODEL_BROADCOM_BCM5411: 826 brgphy_bcm5411_dspcode(sc); 827 break; 828 case MII_MODEL_BROADCOM_BCM5421: 829 brgphy_bcm5421_dspcode(sc); 830 break; 831 case MII_MODEL_BROADCOM_BCM54K2: 832 brgphy_bcm54k2_dspcode(sc); 833 break; 834 } 835 break; 836 case MII_OUI_BROADCOM3: 837 switch (sc->mii_mpd_model) { 838 case MII_MODEL_BROADCOM3_BCM5717C: 839 case MII_MODEL_BROADCOM3_BCM5719C: 840 case MII_MODEL_BROADCOM3_BCM5720C: 841 case MII_MODEL_BROADCOM3_BCM57765: 842 return; 843 } 844 break; 845 default: 846 break; 847 } 848 849 /* Handle any bge (NetXtreme/NetLink) workarounds. */ 850 if (bsc->sc_isbge) { 851 if (!(sc->mii_flags & MIIF_HAVEFIBER)) { 852 853 if (bsc->sc_phyflags & BGEPHYF_ADC_BUG) 854 brgphy_adc_bug(sc); 855 if (bsc->sc_phyflags & BGEPHYF_5704_A0_BUG) 856 brgphy_5704_a0_bug(sc); 857 if (bsc->sc_phyflags & BGEPHYF_BER_BUG) 858 brgphy_ber_bug(sc); 859 else if (bsc->sc_phyflags & BGEPHYF_JITTER_BUG) { 860 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00); 861 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 862 863 if (bsc->sc_phyflags 864 & BGEPHYF_ADJUST_TRIM) { 865 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 866 0x110b); 867 PHY_WRITE(sc, BRGPHY_TEST1, 868 BRGPHY_TEST1_TRIM_EN | 0x4); 869 } else { 870 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 871 0x010b); 872 } 873 874 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400); 875 } 876 if (bsc->sc_phyflags & BGEPHYF_CRC_BUG) 877 brgphy_crc_bug(sc); 878 879 /* Set Jumbo frame settings in the PHY. */ 880 if (bsc->sc_phyflags & BGEPHYF_JUMBO_CAPABLE) 881 brgphy_jumbo_settings(sc); 882 883 /* Adjust output voltage */ 884 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) 885 && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5906)) 886 PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); 887 888 /* Enable Ethernet@Wirespeed */ 889 if (!(bsc->sc_phyflags & BGEPHYF_NO_WIRESPEED)) 890 brgphy_eth_wirespeed(sc); 891 892 #if 0 893 /* Enable Link LED on Dell boxes */ 894 if (bsc->sc_phyflags & BGEPHYF_NO_3LED) { 895 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL, ®); 896 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 897 reg & ~BRGPHY_PHY_EXTCTL_3_LED); 898 } 899 #endif 900 } 901 /* Handle any bnx (NetXtreme II) workarounds. */ 902 } else if (bsc->sc_isbnx) { 903 uint32_t chip_num = _BNX_CHIP_NUM(bsc->sc_chipid); 904 uint32_t chip_id = _BNX_CHIP_ID(bsc->sc_chipid); 905 uint32_t chip_rev = _BNX_CHIP_REV(bsc->sc_chipid); 906 907 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) 908 && sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5708S) { 909 /* 910 * Store autoneg capabilities/results in digital block 911 * (Page 0) 912 */ 913 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 914 BRGPHY_5708S_DIG3_PG2); 915 PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, 916 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); 917 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 918 BRGPHY_5708S_DIG_PG0); 919 920 /* Enable fiber mode and autodetection */ 921 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1, ®); 922 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, reg | 923 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | 924 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); 925 926 /* Enable parallel detection */ 927 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2, ®); 928 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, 929 reg | BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); 930 931 /* 932 * Advertise 2.5G support through next page during 933 * autoneg 934 */ 935 if (bsc->sc_phyflags & BNX_PHY_2_5G_CAPABLE_FLAG) { 936 PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, 937 ®); 938 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, 939 reg | BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 940 } 941 942 /* Increase TX signal amplitude */ 943 if ((chip_id == BNX_CHIP_ID_5708_A0) || 944 (chip_id == BNX_CHIP_ID_5708_B0) || 945 (chip_id == BNX_CHIP_ID_5708_B1)) { 946 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 947 BRGPHY_5708S_TX_MISC_PG5); 948 PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1, ®); 949 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, 950 reg & ~BRGPHY_5708S_PG5_TXACTL1_VCM); 951 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 952 BRGPHY_5708S_DIG_PG0); 953 } 954 955 /* 956 * Backplanes use special 957 * driver/pre-driver/pre-emphasis values. 958 */ 959 if ((bsc->sc_shared_hwcfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) && 960 (bsc->sc_port_hwcfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) { 961 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 962 BRGPHY_5708S_TX_MISC_PG5); 963 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, 964 bsc->sc_port_hwcfg & 965 BNX_PORT_HW_CFG_CFG_TXCTL3_MASK); 966 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 967 BRGPHY_5708S_DIG_PG0); 968 } 969 } else if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) 970 && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S)) { 971 /* Select the SerDes Digital block of the AN MMD. */ 972 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 973 BRGPHY_BLOCK_ADDR_SERDES_DIG); 974 975 PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1, ®); 976 PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, 977 (reg & ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) | 978 BRGPHY_SD_DIG_1000X_CTL1_FIBER); 979 980 if (bsc->sc_phyflags & BNX_PHY_2_5G_CAPABLE_FLAG) { 981 /* Select the Over 1G block of the AN MMD. */ 982 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 983 BRGPHY_BLOCK_ADDR_OVER_1G); 984 985 /* 986 * Enable autoneg "Next Page" to advertise 987 * 2.5G support. 988 */ 989 PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, 990 ®); 991 PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, 992 reg | BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 993 } 994 995 /* 996 * Select the Multi-Rate Backplane Ethernet block of 997 * the AN MMD. 998 */ 999 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 1000 BRGPHY_BLOCK_ADDR_MRBE); 1001 1002 /* Enable MRBE speed autoneg. */ 1003 PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP, ®); 1004 PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, 1005 reg | BRGPHY_MRBE_MSG_PG5_NP_MBRE | 1006 BRGPHY_MRBE_MSG_PG5_NP_T2); 1007 1008 /* Select the Clause 73 User B0 block of the AN MMD. */ 1009 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 1010 BRGPHY_BLOCK_ADDR_CL73_USER_B0); 1011 1012 /* Enable MRBE speed autoneg. */ 1013 PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, 1014 BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | 1015 BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | 1016 BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); 1017 1018 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 1019 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 1020 1021 } else if (chip_num == BNX_CHIP_NUM_5709) { 1022 if ((chip_rev == BNX_CHIP_REV_Ax) || 1023 (chip_rev == BNX_CHIP_REV_Bx)) 1024 brgphy_disable_early_dac(sc); 1025 1026 /* Set Jumbo frame settings in the PHY. */ 1027 brgphy_jumbo_settings(sc); 1028 1029 /* Enable Ethernet@Wirespeed */ 1030 brgphy_eth_wirespeed(sc); 1031 } else { 1032 if (!(sc->mii_flags & MIIF_HAVEFIBER)) { 1033 brgphy_ber_bug(sc); 1034 1035 /* Set Jumbo frame settings in the PHY. */ 1036 brgphy_jumbo_settings(sc); 1037 1038 /* Enable Ethernet@Wirespeed */ 1039 brgphy_eth_wirespeed(sc); 1040 } 1041 } 1042 } 1043 } 1044 1045 /* Turn off tap power management on 5401. */ 1046 static void 1047 brgphy_bcm5401_dspcode(struct mii_softc *sc) 1048 { 1049 static const struct { 1050 int reg; 1051 uint16_t val; 1052 } dspcode[] = { 1053 { BRGPHY_MII_AUXCTL, 0x0c20 }, 1054 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 1055 { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 1056 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 1057 { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 1058 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 1059 { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 1060 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 1061 { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 1062 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 1063 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 1064 { 0, 0 }, 1065 }; 1066 int i; 1067 1068 for (i = 0; dspcode[i].reg != 0; i++) 1069 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1070 delay(40); 1071 } 1072 1073 static void 1074 brgphy_bcm5411_dspcode(struct mii_softc *sc) 1075 { 1076 static const struct { 1077 int reg; 1078 uint16_t val; 1079 } dspcode[] = { 1080 { 0x1c, 0x8c23 }, 1081 { 0x1c, 0x8ca3 }, 1082 { 0x1c, 0x8c23 }, 1083 { 0, 0 }, 1084 }; 1085 int i; 1086 1087 for (i = 0; dspcode[i].reg != 0; i++) 1088 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1089 } 1090 1091 static void 1092 brgphy_bcm5421_dspcode(struct mii_softc *sc) 1093 { 1094 uint16_t data; 1095 1096 /* Set Class A mode */ 1097 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007); 1098 PHY_READ(sc, BRGPHY_MII_AUXCTL, &data); 1099 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400); 1100 1101 /* Set FFE gamma override to -0.125 */ 1102 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007); 1103 PHY_READ(sc, BRGPHY_MII_AUXCTL, &data); 1104 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800); 1105 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 1106 PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT, &data); 1107 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200); 1108 } 1109 1110 static void 1111 brgphy_bcm54k2_dspcode(struct mii_softc *sc) 1112 { 1113 static const struct { 1114 int reg; 1115 uint16_t val; 1116 } dspcode[] = { 1117 { 4, 0x01e1 }, 1118 { 9, 0x0300 }, 1119 { 0, 0 }, 1120 }; 1121 int i; 1122 1123 for (i = 0; dspcode[i].reg != 0; i++) 1124 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1125 } 1126 1127 static void 1128 brgphy_adc_bug(struct mii_softc *sc) 1129 { 1130 static const struct { 1131 int reg; 1132 uint16_t val; 1133 } dspcode[] = { 1134 { BRGPHY_MII_AUXCTL, 0x0c00 }, 1135 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 1136 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 1137 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 1138 { BRGPHY_MII_DSP_RW_PORT, 0x0323 }, 1139 { BRGPHY_MII_AUXCTL, 0x0400 }, 1140 { 0, 0 }, 1141 }; 1142 int i; 1143 1144 for (i = 0; dspcode[i].reg != 0; i++) 1145 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1146 } 1147 1148 static void 1149 brgphy_5704_a0_bug(struct mii_softc *sc) 1150 { 1151 static const struct { 1152 int reg; 1153 uint16_t val; 1154 } dspcode[] = { 1155 { 0x1c, 0x8d68 }, 1156 { 0x1c, 0x8d68 }, 1157 { 0, 0 }, 1158 }; 1159 int i; 1160 1161 for (i = 0; dspcode[i].reg != 0; i++) 1162 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1163 } 1164 1165 static void 1166 brgphy_ber_bug(struct mii_softc *sc) 1167 { 1168 static const struct { 1169 int reg; 1170 uint16_t val; 1171 } dspcode[] = { 1172 { BRGPHY_MII_AUXCTL, 0x0c00 }, 1173 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 1174 { BRGPHY_MII_DSP_RW_PORT, 0x310b }, 1175 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 1176 { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, 1177 { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, 1178 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, 1179 { BRGPHY_MII_AUXCTL, 0x0400 }, 1180 { 0, 0 }, 1181 }; 1182 int i; 1183 1184 for (i = 0; dspcode[i].reg != 0; i++) 1185 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1186 } 1187 1188 /* BCM5701 A0/B0 CRC bug workaround */ 1189 static void 1190 brgphy_crc_bug(struct mii_softc *sc) 1191 { 1192 static const struct { 1193 int reg; 1194 uint16_t val; 1195 } dspcode[] = { 1196 { BRGPHY_MII_DSP_ADDR_REG, 0x0a75 }, 1197 { 0x1c, 0x8c68 }, 1198 { 0x1c, 0x8d68 }, 1199 { 0x1c, 0x8c68 }, 1200 { 0, 0 }, 1201 }; 1202 int i; 1203 1204 for (i = 0; dspcode[i].reg != 0; i++) 1205 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1206 } 1207 1208 static void 1209 brgphy_disable_early_dac(struct mii_softc *sc) 1210 { 1211 uint16_t val; 1212 1213 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08); 1214 PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT, &val); 1215 val &= ~(1 << 8); 1216 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val); 1217 1218 } 1219 1220 static void 1221 brgphy_jumbo_settings(struct mii_softc *sc) 1222 { 1223 uint16_t val; 1224 1225 /* Set Jumbo frame settings in the PHY. */ 1226 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM) 1227 && (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5401)) { 1228 /* Cannot do read-modify-write on the BCM5401 */ 1229 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); 1230 } else { 1231 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 1232 PHY_READ(sc, BRGPHY_MII_AUXCTL, &val); 1233 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 1234 val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); 1235 } 1236 1237 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL, &val); 1238 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); 1239 } 1240 1241 static void 1242 brgphy_eth_wirespeed(struct mii_softc *sc) 1243 { 1244 uint16_t val; 1245 1246 /* Enable Ethernet@Wirespeed */ 1247 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 1248 PHY_READ(sc, BRGPHY_MII_AUXCTL, &val); 1249 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4)); 1250 } 1251 1252 static void 1253 brgphy_bcm54xx_clock_delay(struct mii_softc *sc) 1254 { 1255 uint16_t val; 1256 1257 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_SHADOW_MISC | 1258 BRGPHY_AUXCTL_SHADOW_MISC << BRGPHY_AUXCTL_MISC_READ_SHIFT); 1259 PHY_READ(sc, BRGPHY_MII_AUXCTL, &val); 1260 val &= BRGPHY_AUXCTL_MISC_DATA_MASK; 1261 if (sc->mii_flags & MIIF_RXID) 1262 val |= BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; 1263 else 1264 val &= ~BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; 1265 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_MISC_WRITE_EN | 1266 BRGPHY_AUXCTL_SHADOW_MISC | val); 1267 1268 PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_CLK_CTRL); 1269 PHY_READ(sc, BRGPHY_MII_SHADOW_1C, &val); 1270 val &= BRGPHY_SHADOW_1C_DATA_MASK; 1271 if (sc->mii_flags & MIIF_TXID) 1272 val |= BRGPHY_SHADOW_1C_GTXCLK_EN; 1273 else 1274 val &= ~BRGPHY_SHADOW_1C_GTXCLK_EN; 1275 PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_WRITE_EN | 1276 BRGPHY_SHADOW_1C_CLK_CTRL | val); 1277 } 1278