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