1 /* $OpenBSD: brgphy.c,v 1.105 2015/07/19 06:28:12 yuo Exp $ */ 2 3 /* 4 * Copyright (c) 2000 5 * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bill Paul. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * $FreeBSD: brgphy.c,v 1.8 2002/03/22 06:38:52 wpaul Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/device.h> 41 #include <sys/socket.h> 42 #include <sys/errno.h> 43 44 #include <machine/bus.h> 45 46 #include <net/if.h> 47 #include <net/if_media.h> 48 49 #include <netinet/in.h> 50 #include <netinet/if_ether.h> 51 52 #include <dev/pci/pcivar.h> 53 54 #include <dev/mii/mii.h> 55 #include <dev/mii/miivar.h> 56 #include <dev/mii/miidevs.h> 57 58 #include <dev/mii/brgphyreg.h> 59 60 #include <dev/pci/if_bgereg.h> 61 #include <dev/pci/if_bnxreg.h> 62 63 int brgphy_probe(struct device *, void *, void *); 64 void brgphy_attach(struct device *, struct device *, void *); 65 66 struct cfattach brgphy_ca = { 67 sizeof(struct mii_softc), brgphy_probe, brgphy_attach, mii_phy_detach 68 }; 69 70 struct cfdriver brgphy_cd = { 71 NULL, "brgphy", DV_DULL 72 }; 73 74 int brgphy_service(struct mii_softc *, struct mii_data *, int); 75 void brgphy_copper_status(struct mii_softc *); 76 void brgphy_fiber_status(struct mii_softc *); 77 void brgphy_5708s_status(struct mii_softc *); 78 void brgphy_5709s_status(struct mii_softc *); 79 int brgphy_mii_phy_auto(struct mii_softc *); 80 void brgphy_loop(struct mii_softc *); 81 void brgphy_reset(struct mii_softc *); 82 void brgphy_reset_bge(struct mii_softc *); 83 void brgphy_reset_bnx(struct mii_softc *); 84 void brgphy_bcm5401_dspcode(struct mii_softc *); 85 void brgphy_bcm5411_dspcode(struct mii_softc *); 86 void brgphy_bcm5421_dspcode(struct mii_softc *); 87 void brgphy_bcm54k2_dspcode(struct mii_softc *); 88 void brgphy_adc_bug(struct mii_softc *); 89 void brgphy_5704_a0_bug(struct mii_softc *); 90 void brgphy_ber_bug(struct mii_softc *); 91 void brgphy_crc_bug(struct mii_softc *); 92 void brgphy_disable_early_dac(struct mii_softc *sc); 93 void brgphy_jumbo_settings(struct mii_softc *); 94 void brgphy_eth_wirespeed(struct mii_softc *); 95 96 const struct mii_phy_funcs brgphy_copper_funcs = { 97 brgphy_service, brgphy_copper_status, brgphy_reset, 98 }; 99 100 const struct mii_phy_funcs brgphy_fiber_funcs = { 101 brgphy_service, brgphy_fiber_status, brgphy_reset, 102 }; 103 104 const struct mii_phy_funcs brgphy_5708s_funcs = { 105 brgphy_service, brgphy_5708s_status, brgphy_reset, 106 }; 107 108 const struct mii_phy_funcs brgphy_5709s_funcs = { 109 brgphy_service, brgphy_5709s_status, brgphy_reset, 110 }; 111 112 static const struct mii_phydesc brgphys[] = { 113 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5400, 114 MII_STR_xxBROADCOM_BCM5400 }, 115 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5401, 116 MII_STR_xxBROADCOM_BCM5401 }, 117 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5411, 118 MII_STR_xxBROADCOM_BCM5411 }, 119 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5421, 120 MII_STR_xxBROADCOM_BCM5421 }, 121 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM54K2, 122 MII_STR_xxBROADCOM_BCM54K2 }, 123 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5461, 124 MII_STR_xxBROADCOM_BCM5461 }, 125 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5462, 126 MII_STR_xxBROADCOM_BCM5462 }, 127 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5464, 128 MII_STR_xxBROADCOM_BCM5464 }, 129 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5701, 130 MII_STR_xxBROADCOM_BCM5701 }, 131 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5703, 132 MII_STR_xxBROADCOM_BCM5703 }, 133 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5704, 134 MII_STR_xxBROADCOM_BCM5704 }, 135 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5705, 136 MII_STR_xxBROADCOM_BCM5705 }, 137 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5714, 138 MII_STR_xxBROADCOM_BCM5714 }, 139 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5750, 140 MII_STR_xxBROADCOM_BCM5750 }, 141 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5752, 142 MII_STR_xxBROADCOM_BCM5752 }, 143 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5780, 144 MII_STR_xxBROADCOM_BCM5780 }, 145 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM54XX, 146 MII_STR_xxBROADCOM2_BCM54XX }, 147 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5481, 148 MII_STR_xxBROADCOM2_BCM5481 }, 149 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5482, 150 MII_STR_xxBROADCOM2_BCM5482 }, 151 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5722, 152 MII_STR_xxBROADCOM2_BCM5722 }, 153 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5755, 154 MII_STR_xxBROADCOM2_BCM5755 }, 155 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5761, 156 MII_STR_xxBROADCOM2_BCM5761 }, 157 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5784, 158 MII_STR_xxBROADCOM2_BCM5784 }, 159 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5787, 160 MII_STR_xxBROADCOM2_BCM5787 }, 161 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5706, 162 MII_STR_xxBROADCOM_BCM5706 }, 163 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5708C, 164 MII_STR_xxBROADCOM_BCM5708C }, 165 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5708S, 166 MII_STR_xxBROADCOM2_BCM5708S }, 167 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5709C, 168 MII_STR_xxBROADCOM2_BCM5709C }, 169 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5709S, 170 MII_STR_xxBROADCOM2_BCM5709S }, 171 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5709CAX, 172 MII_STR_xxBROADCOM2_BCM5709CAX }, 173 { MII_OUI_xxBROADCOM3, MII_MODEL_xxBROADCOM3_BCM5717C, 174 MII_STR_xxBROADCOM3_BCM5717C }, 175 { MII_OUI_xxBROADCOM3, MII_MODEL_xxBROADCOM3_BCM5719C, 176 MII_STR_xxBROADCOM3_BCM5719C }, 177 { MII_OUI_xxBROADCOM3, MII_MODEL_xxBROADCOM3_BCM5720C, 178 MII_STR_xxBROADCOM3_BCM5720C }, 179 { MII_OUI_xxBROADCOM3, MII_MODEL_xxBROADCOM3_BCM57765, 180 MII_STR_xxBROADCOM3_BCM57765 }, 181 { MII_OUI_xxBROADCOM3, MII_MODEL_xxBROADCOM3_BCM57780, 182 MII_STR_xxBROADCOM3_BCM57780 }, 183 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5906, 184 MII_STR_BROADCOM2_BCM5906 }, 185 186 { 0, 0, 187 NULL }, 188 }; 189 190 int 191 brgphy_probe(struct device *parent, void *match, void *aux) 192 { 193 struct mii_attach_args *ma = aux; 194 195 if (mii_phy_match(ma, brgphys) != NULL) 196 return (10); 197 198 return (0); 199 } 200 201 void 202 brgphy_attach(struct device *parent, struct device *self, void *aux) 203 { 204 struct mii_softc *sc = (struct mii_softc *)self; 205 struct bge_softc *bge_sc = NULL; 206 struct bnx_softc *bnx_sc = NULL; 207 struct mii_attach_args *ma = aux; 208 struct mii_data *mii = ma->mii_data; 209 const struct mii_phydesc *mpd; 210 char *devname; 211 int fast_ether = 0; 212 213 devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name; 214 215 if (strcmp(devname, "bge") == 0) { 216 bge_sc = mii->mii_ifp->if_softc; 217 218 if (bge_sc->bge_phy_flags & BGE_PHY_10_100_ONLY) 219 fast_ether = 1; 220 } else if (strcmp(devname, "bnx") == 0) 221 bnx_sc = mii->mii_ifp->if_softc; 222 223 mpd = mii_phy_match(ma, brgphys); 224 printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 225 226 sc->mii_inst = mii->mii_instance; 227 sc->mii_phy = ma->mii_phyno; 228 sc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2); 229 sc->mii_model = MII_MODEL(ma->mii_id2); 230 sc->mii_rev = MII_REV(ma->mii_id2); 231 sc->mii_pdata = mii; 232 sc->mii_flags = ma->mii_flags; 233 234 if (sc->mii_flags & MIIF_HAVEFIBER) { 235 if (strcmp(devname, "bnx") == 0) { 236 if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5708) 237 sc->mii_funcs = &brgphy_5708s_funcs; 238 else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709) 239 sc->mii_funcs = &brgphy_5709s_funcs; 240 else 241 sc->mii_funcs = &brgphy_fiber_funcs; 242 } else 243 sc->mii_funcs = &brgphy_fiber_funcs; 244 } else 245 sc->mii_funcs = &brgphy_copper_funcs; 246 247 if (fast_ether == 1) 248 sc->mii_anegticks = MII_ANEGTICKS; 249 else 250 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 251 252 sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; 253 254 PHY_RESET(sc); 255 256 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 257 if (sc->mii_capabilities & BMSR_EXTSTAT) 258 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 259 260 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 261 262 /* Create an instance of Ethernet media. */ 263 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), BMCR_ISO); 264 265 /* Add the supported media types */ 266 if (sc->mii_flags & MIIF_HAVEFIBER) { 267 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 268 BMCR_S1000 | BMCR_FDX); 269 270 /* 271 * 2.5Gb support is a software enabled feature on the 272 * BCM5708S and BCM5709S controllers. 273 */ 274 if (strcmp(devname, "bnx") == 0) { 275 if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) 276 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, 277 IFM_FDX, sc->mii_inst), 0); 278 } 279 } else { 280 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 281 BMCR_S10); 282 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), 283 BMCR_S10 | BMCR_FDX); 284 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), 285 BMCR_S100); 286 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), 287 BMCR_S100 | BMCR_FDX); 288 289 if (fast_ether == 0) { 290 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, 291 sc->mii_inst), BMCR_S1000); 292 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, 293 sc->mii_inst), BMCR_S1000 | BMCR_FDX); 294 } 295 } 296 297 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); 298 299 #undef ADD 300 } 301 302 int 303 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 304 { 305 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 306 int reg, speed = 0, gig; 307 308 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 309 return (ENXIO); 310 311 switch (cmd) { 312 case MII_POLLSTAT: 313 /* 314 * If we're not polling our PHY instance, just return. 315 */ 316 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 317 return (0); 318 break; 319 320 case MII_MEDIACHG: 321 /* 322 * If the media indicates a different PHY instance, 323 * isolate ourselves. 324 */ 325 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 326 reg = PHY_READ(sc, MII_BMCR); 327 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 328 return (0); 329 } 330 331 /* 332 * If the interface is not up, don't do anything. 333 */ 334 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 335 break; 336 337 PHY_RESET(sc); /* XXX hardware bug work-around */ 338 339 switch (IFM_SUBTYPE(ife->ifm_media)) { 340 case IFM_AUTO: 341 (void) brgphy_mii_phy_auto(sc); 342 break; 343 case IFM_2500_SX: 344 speed = BRGPHY_5708S_BMCR_2500; 345 goto setit; 346 case IFM_1000_T: 347 speed = BMCR_S1000; 348 goto setit; 349 case IFM_100_TX: 350 speed = BMCR_S100; 351 goto setit; 352 case IFM_10_T: 353 speed = BMCR_S10; 354 setit: 355 brgphy_loop(sc); 356 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 357 speed |= BMCR_FDX; 358 gig = GTCR_ADV_1000TFDX; 359 } else { 360 gig = GTCR_ADV_1000THDX; 361 } 362 363 PHY_WRITE(sc, MII_100T2CR, 0); 364 PHY_WRITE(sc, MII_ANAR, ANAR_CSMA); 365 PHY_WRITE(sc, MII_BMCR, speed); 366 367 if ((IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) && 368 (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_SX) && 369 (IFM_SUBTYPE(ife->ifm_media) != IFM_2500_SX)) 370 break; 371 372 PHY_WRITE(sc, MII_100T2CR, gig); 373 PHY_WRITE(sc, MII_BMCR, 374 speed|BMCR_AUTOEN|BMCR_STARTNEG); 375 376 if (sc->mii_oui != MII_OUI_xxBROADCOM || 377 sc->mii_model != MII_MODEL_xxBROADCOM_BCM5701) 378 break; 379 380 if (mii->mii_media.ifm_media & IFM_ETH_MASTER) 381 gig |= GTCR_MAN_MS|GTCR_ADV_MS; 382 PHY_WRITE(sc, MII_100T2CR, gig); 383 break; 384 default: 385 return (EINVAL); 386 } 387 break; 388 389 case MII_TICK: 390 /* 391 * If we're not currently selected, just return. 392 */ 393 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 394 return (0); 395 396 /* 397 * Is the interface even up? 398 */ 399 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 400 return (0); 401 402 /* 403 * Only used for autonegotiation. 404 */ 405 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 406 break; 407 408 /* 409 * Check to see if we have link. If we do, we don't 410 * need to restart the autonegotiation process. Read 411 * the BMSR twice in case it's latched. 412 */ 413 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 414 if (reg & BMSR_LINK) { 415 sc->mii_ticks = 0; /* Reset autoneg timer. */ 416 break; 417 } 418 419 /* 420 * Only retry autonegotiation every mii_anegticks seconds. 421 */ 422 if (++sc->mii_ticks <= sc->mii_anegticks) 423 break; 424 425 sc->mii_ticks = 0; 426 brgphy_mii_phy_auto(sc); 427 break; 428 } 429 430 /* Update the media status. */ 431 mii_phy_status(sc); 432 433 /* 434 * Callback if something changed. Note that we need to poke the DSP on 435 * the Broadcom PHYs if the media changes. 436 */ 437 if (sc->mii_media_active != mii->mii_media_active || 438 sc->mii_media_status != mii->mii_media_status || 439 cmd == MII_MEDIACHG) { 440 switch (sc->mii_oui) { 441 case MII_OUI_BROADCOM: 442 switch (sc->mii_model) { 443 case MII_MODEL_BROADCOM_BCM5400: 444 brgphy_bcm5401_dspcode(sc); 445 break; 446 } 447 break; 448 case MII_OUI_xxBROADCOM: 449 switch (sc->mii_model) { 450 case MII_MODEL_xxBROADCOM_BCM5401: 451 if (sc->mii_rev == 1 || sc->mii_rev == 3) 452 brgphy_bcm5401_dspcode(sc); 453 break; 454 case MII_MODEL_xxBROADCOM_BCM5411: 455 brgphy_bcm5411_dspcode(sc); 456 break; 457 } 458 break; 459 } 460 } 461 462 /* Callback if something changed. */ 463 mii_phy_update(sc, cmd); 464 465 return (0); 466 } 467 468 void 469 brgphy_copper_status(struct mii_softc *sc) 470 { 471 struct mii_data *mii = sc->mii_pdata; 472 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 473 int bmcr, bmsr; 474 475 mii->mii_media_status = IFM_AVALID; 476 mii->mii_media_active = IFM_ETHER; 477 478 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 479 if (bmsr & BMSR_LINK) 480 mii->mii_media_status |= IFM_ACTIVE; 481 482 bmcr = PHY_READ(sc, MII_BMCR); 483 if (bmcr & BMCR_LOOP) 484 mii->mii_media_active |= IFM_LOOP; 485 486 if (bmcr & BMCR_AUTOEN) { 487 int auxsts; 488 489 if ((bmsr & BMSR_ACOMP) == 0) { 490 /* Erg, still trying, I guess... */ 491 mii->mii_media_active |= IFM_NONE; 492 return; 493 } 494 495 auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS); 496 497 switch (auxsts & BRGPHY_AUXSTS_AN_RES) { 498 case BRGPHY_RES_1000FD: 499 mii->mii_media_active |= IFM_1000_T | IFM_FDX; 500 break; 501 case BRGPHY_RES_1000HD: 502 mii->mii_media_active |= IFM_1000_T | IFM_HDX; 503 break; 504 case BRGPHY_RES_100FD: 505 mii->mii_media_active |= IFM_100_TX | IFM_FDX; 506 break; 507 case BRGPHY_RES_100T4: 508 mii->mii_media_active |= IFM_100_T4 | IFM_HDX; 509 break; 510 case BRGPHY_RES_100HD: 511 mii->mii_media_active |= IFM_100_TX | IFM_HDX; 512 break; 513 case BRGPHY_RES_10FD: 514 mii->mii_media_active |= IFM_10_T | IFM_FDX; 515 break; 516 case BRGPHY_RES_10HD: 517 mii->mii_media_active |= IFM_10_T | IFM_HDX; 518 break; 519 default: 520 if (sc->mii_oui == MII_OUI_BROADCOM2 && 521 sc->mii_model == MII_MODEL_BROADCOM2_BCM5906) { 522 mii->mii_media_active |= (auxsts & 523 BRGPHY_RES_100) ? IFM_100_TX : IFM_10_T; 524 mii->mii_media_active |= (auxsts & 525 BRGPHY_RES_FULL) ? IFM_FDX : IFM_HDX; 526 break; 527 } 528 mii->mii_media_active |= IFM_NONE; 529 return; 530 } 531 532 if (mii->mii_media_active & IFM_FDX) 533 mii->mii_media_active |= mii_phy_flowstatus(sc); 534 535 if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { 536 if (PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) 537 mii->mii_media_active |= IFM_ETH_MASTER; 538 } 539 } else 540 mii->mii_media_active = ife->ifm_media; 541 } 542 543 void 544 brgphy_fiber_status(struct mii_softc *sc) 545 { 546 struct mii_data *mii = sc->mii_pdata; 547 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 548 int bmcr, bmsr; 549 550 mii->mii_media_status = IFM_AVALID; 551 mii->mii_media_active = IFM_ETHER; 552 553 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 554 if (bmsr & BMSR_LINK) 555 mii->mii_media_status |= IFM_ACTIVE; 556 557 bmcr = PHY_READ(sc, MII_BMCR); 558 if (bmcr & BMCR_LOOP) 559 mii->mii_media_active |= IFM_LOOP; 560 561 if (bmcr & BMCR_AUTOEN) { 562 int val; 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 mii->mii_media_active |= IFM_1000_SX; 571 572 val = PHY_READ(sc, MII_ANAR) & PHY_READ(sc, MII_ANLPAR); 573 574 if (val & ANAR_X_FD) 575 mii->mii_media_active |= IFM_FDX; 576 else 577 mii->mii_media_active |= IFM_HDX; 578 579 if (mii->mii_media_active & IFM_FDX) 580 mii->mii_media_active |= mii_phy_flowstatus(sc); 581 } else 582 mii->mii_media_active = ife->ifm_media; 583 } 584 585 void 586 brgphy_5708s_status(struct mii_softc *sc) 587 { 588 struct mii_data *mii = sc->mii_pdata; 589 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 590 int bmcr, bmsr; 591 592 mii->mii_media_status = IFM_AVALID; 593 mii->mii_media_active = IFM_ETHER; 594 595 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 596 if (bmsr & BMSR_LINK) 597 mii->mii_media_status |= IFM_ACTIVE; 598 599 bmcr = PHY_READ(sc, MII_BMCR); 600 if (bmcr & BMCR_LOOP) 601 mii->mii_media_active |= IFM_LOOP; 602 603 if (bmcr & BMCR_AUTOEN) { 604 int xstat; 605 606 if ((bmsr & BMSR_ACOMP) == 0) { 607 /* Erg, still trying, I guess... */ 608 mii->mii_media_active |= IFM_NONE; 609 return; 610 } 611 612 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 613 BRGPHY_5708S_DIG_PG0); 614 615 xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); 616 617 switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { 618 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: 619 mii->mii_media_active |= IFM_10_FL; 620 break; 621 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: 622 mii->mii_media_active |= IFM_100_FX; 623 break; 624 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: 625 mii->mii_media_active |= IFM_1000_SX; 626 break; 627 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: 628 mii->mii_media_active |= IFM_2500_SX; 629 break; 630 } 631 632 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) 633 mii->mii_media_active |= IFM_FDX; 634 else 635 mii->mii_media_active |= IFM_HDX; 636 637 if (mii->mii_media_active & IFM_FDX) { 638 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_TX_PAUSE) 639 mii->mii_media_active |= IFM_FLOW | IFM_ETH_TXPAUSE; 640 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_RX_PAUSE) 641 mii->mii_media_active |= IFM_FLOW | IFM_ETH_RXPAUSE; 642 } 643 } else 644 mii->mii_media_active = ife->ifm_media; 645 } 646 647 void 648 brgphy_5709s_status(struct mii_softc *sc) 649 { 650 struct mii_data *mii = sc->mii_pdata; 651 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 652 int bmcr, bmsr; 653 654 mii->mii_media_status = IFM_AVALID; 655 mii->mii_media_active = IFM_ETHER; 656 657 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 658 if (bmsr & BMSR_LINK) 659 mii->mii_media_status |= IFM_ACTIVE; 660 661 bmcr = PHY_READ(sc, MII_BMCR); 662 if (bmcr & BMCR_LOOP) 663 mii->mii_media_active |= IFM_LOOP; 664 665 if (bmcr & BMCR_AUTOEN) { 666 int xstat; 667 668 if ((bmsr & BMSR_ACOMP) == 0) { 669 /* Erg, still trying, I guess... */ 670 mii->mii_media_active |= IFM_NONE; 671 return; 672 } 673 674 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 675 BRGPHY_BLOCK_ADDR_GP_STATUS); 676 677 xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); 678 679 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 680 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 681 682 switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { 683 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: 684 mii->mii_media_active |= IFM_10_FL; 685 break; 686 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: 687 mii->mii_media_active |= IFM_100_FX; 688 break; 689 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: 690 mii->mii_media_active |= IFM_1000_SX; 691 break; 692 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: 693 mii->mii_media_active |= IFM_2500_SX; 694 break; 695 } 696 697 if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX) 698 mii->mii_media_active |= IFM_FDX; 699 else 700 mii->mii_media_active |= IFM_HDX; 701 702 if (mii->mii_media_active & IFM_FDX) 703 mii->mii_media_active |= mii_phy_flowstatus(sc); 704 } else 705 mii->mii_media_active = ife->ifm_media; 706 } 707 708 int 709 brgphy_mii_phy_auto(struct mii_softc *sc) 710 { 711 int anar, ktcr = 0; 712 713 PHY_RESET(sc); 714 715 if (sc->mii_flags & MIIF_HAVEFIBER) { 716 anar = ANAR_X_FD | ANAR_X_HD; 717 if (sc->mii_flags & MIIF_DOPAUSE) 718 anar |= ANAR_X_PAUSE_TOWARDS; 719 PHY_WRITE(sc, MII_ANAR, anar); 720 } else { 721 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 722 if (sc->mii_flags & MIIF_DOPAUSE) 723 anar |= ANAR_PAUSE_ASYM | ANAR_FC; 724 PHY_WRITE(sc, MII_ANAR, anar); 725 } 726 727 /* Enable speed in the 1000baseT control register */ 728 ktcr = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; 729 if (sc->mii_oui == MII_OUI_xxBROADCOM && 730 sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701) 731 ktcr |= GTCR_MAN_MS | GTCR_ADV_MS; 732 PHY_WRITE(sc, MII_100T2CR, ktcr); 733 ktcr = PHY_READ(sc, MII_100T2CR); 734 735 /* Start autonegotiation */ 736 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); 737 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); 738 739 return (EJUSTRETURN); 740 } 741 742 /* Enable loopback to force the link down. */ 743 void 744 brgphy_loop(struct mii_softc *sc) 745 { 746 u_int32_t bmsr; 747 int i; 748 749 PHY_WRITE(sc, MII_BMCR, BMCR_LOOP); 750 for (i = 0; i < 15000; i++) { 751 bmsr = PHY_READ(sc, MII_BMSR); 752 if (!(bmsr & BMSR_LINK)) 753 break; 754 DELAY(10); 755 } 756 } 757 758 void 759 brgphy_reset(struct mii_softc *sc) 760 { 761 char *devname; 762 763 devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name; 764 765 mii_phy_reset(sc); 766 767 switch (sc->mii_oui) { 768 case MII_OUI_BROADCOM: 769 switch (sc->mii_model) { 770 case MII_MODEL_BROADCOM_BCM5400: 771 brgphy_bcm5401_dspcode(sc); 772 break; 773 case MII_MODEL_BROADCOM_BCM5401: 774 if (sc->mii_rev == 1 || sc->mii_rev == 3) 775 brgphy_bcm5401_dspcode(sc); 776 break; 777 case MII_MODEL_BROADCOM_BCM5411: 778 brgphy_bcm5411_dspcode(sc); 779 break; 780 } 781 break; 782 case MII_OUI_xxBROADCOM: 783 switch (sc->mii_model) { 784 case MII_MODEL_xxBROADCOM_BCM5421: 785 brgphy_bcm5421_dspcode(sc); 786 break; 787 case MII_MODEL_xxBROADCOM_BCM54K2: 788 brgphy_bcm54k2_dspcode(sc); 789 break; 790 } 791 break; 792 } 793 794 /* Handle any bge (NetXtreme/NetLink) workarounds. */ 795 if (strcmp(devname, "bge") == 0) 796 brgphy_reset_bge(sc); 797 /* Handle any bnx (NetXtreme II) workarounds. */ 798 else if (strcmp(devname, "bnx") == 0) 799 brgphy_reset_bnx(sc); 800 } 801 802 void 803 brgphy_reset_bge(struct mii_softc *sc) 804 { 805 struct bge_softc *bge_sc = sc->mii_pdata->mii_ifp->if_softc; 806 807 if (sc->mii_flags & MIIF_HAVEFIBER) 808 return; 809 810 switch (sc->mii_oui) { 811 case MII_OUI_xxBROADCOM3: 812 switch (sc->mii_model) { 813 case MII_MODEL_xxBROADCOM3_BCM5717C: 814 case MII_MODEL_xxBROADCOM3_BCM5719C: 815 case MII_MODEL_xxBROADCOM3_BCM5720C: 816 case MII_MODEL_xxBROADCOM3_BCM57765: 817 return; 818 } 819 } 820 821 if (bge_sc->bge_phy_flags & BGE_PHY_ADC_BUG) 822 brgphy_adc_bug(sc); 823 if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG) 824 brgphy_5704_a0_bug(sc); 825 if (bge_sc->bge_phy_flags & BGE_PHY_BER_BUG) 826 brgphy_ber_bug(sc); 827 else if (bge_sc->bge_phy_flags & BGE_PHY_JITTER_BUG) { 828 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00); 829 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 830 831 if (bge_sc->bge_phy_flags & BGE_PHY_ADJUST_TRIM) { 832 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x110b); 833 PHY_WRITE(sc, BRGPHY_TEST1, BRGPHY_TEST1_TRIM_EN | 834 0x4); 835 } else 836 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x010b); 837 838 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400); 839 } 840 841 if (bge_sc->bge_phy_flags & BGE_PHY_CRC_BUG) 842 brgphy_crc_bug(sc); 843 844 /* Set Jumbo frame settings in the PHY. */ 845 if (bge_sc->bge_flags & BGE_JUMBO_CAPABLE) 846 brgphy_jumbo_settings(sc); 847 848 /* Adjust output voltage */ 849 if (sc->mii_oui == MII_OUI_BROADCOM2 && 850 sc->mii_model == MII_MODEL_BROADCOM2_BCM5906) 851 PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); 852 853 /* Enable Ethernet@Wirespeed */ 854 if (!(bge_sc->bge_phy_flags & BGE_PHY_NO_WIRESPEED)) 855 brgphy_eth_wirespeed(sc); 856 857 /* Enable Link LED on Dell boxes */ 858 if (bge_sc->bge_phy_flags & BGE_PHY_NO_3LED) { 859 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 860 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) 861 & ~BRGPHY_PHY_EXTCTL_3_LED); 862 } 863 } 864 865 void 866 brgphy_reset_bnx(struct mii_softc *sc) 867 { 868 struct bnx_softc *bnx_sc = sc->mii_pdata->mii_ifp->if_softc; 869 870 if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5708 && 871 sc->mii_flags & MIIF_HAVEFIBER) { 872 /* Store autoneg capabilities/results in digital block (Page 0) */ 873 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); 874 PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, 875 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); 876 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); 877 878 /* Enable fiber mode and autodetection */ 879 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, 880 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | 881 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | 882 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); 883 884 /* Enable parallel detection */ 885 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, 886 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | 887 BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); 888 889 /* Advertise 2.5G support through next page during autoneg */ 890 if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) { 891 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, 892 PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | 893 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 894 } 895 896 /* Increase TX signal amplitude */ 897 if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) || 898 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) || 899 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) { 900 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 901 BRGPHY_5708S_TX_MISC_PG5); 902 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, 903 PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & 904 ~BRGPHY_5708S_PG5_TXACTL1_VCM); 905 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 906 BRGPHY_5708S_DIG_PG0); 907 } 908 909 /* Backplanes use special driver/pre-driver/pre-emphasis values. */ 910 if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) && 911 (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) { 912 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 913 BRGPHY_5708S_TX_MISC_PG5); 914 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, 915 bnx_sc->bnx_port_hw_cfg & 916 BNX_PORT_HW_CFG_CFG_TXCTL3_MASK); 917 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 918 BRGPHY_5708S_DIG_PG0); 919 } 920 } else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709 && 921 sc->mii_flags & MIIF_HAVEFIBER) { 922 /* Select the SerDes Digital block of the AN MMD. */ 923 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG); 924 925 PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, 926 (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) & 927 ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) | 928 BRGPHY_SD_DIG_1000X_CTL1_FIBER); 929 930 if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) { 931 /* Select the Over 1G block of the AN MMD. */ 932 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 933 BRGPHY_BLOCK_ADDR_OVER_1G); 934 935 /* 936 * Enable autoneg "Next Page" to advertise 937 * 2.5G support. 938 */ 939 PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, 940 PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) | 941 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 942 } 943 944 /* 945 * Select the Multi-Rate Backplane Ethernet block of 946 * the AN MMD. 947 */ 948 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_MRBE); 949 950 /* Enable MRBE speed autoneg. */ 951 PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, 952 PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) | 953 BRGPHY_MRBE_MSG_PG5_NP_MBRE | 954 BRGPHY_MRBE_MSG_PG5_NP_T2); 955 956 /* Select the Clause 73 User B0 block of the AN MMD. */ 957 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 958 BRGPHY_BLOCK_ADDR_CL73_USER_B0); 959 960 /* Enable MRBE speed autoneg. */ 961 PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, 962 BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | 963 BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | 964 BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); 965 966 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 967 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 968 } else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709) { 969 if (BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Ax || 970 BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Bx) 971 brgphy_disable_early_dac(sc); 972 973 /* Set Jumbo frame settings in the PHY. */ 974 brgphy_jumbo_settings(sc); 975 976 /* Enable Ethernet@Wirespeed */ 977 brgphy_eth_wirespeed(sc); 978 } else if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 979 brgphy_ber_bug(sc); 980 981 /* Set Jumbo frame settings in the PHY. */ 982 brgphy_jumbo_settings(sc); 983 984 /* Enable Ethernet@Wirespeed */ 985 brgphy_eth_wirespeed(sc); 986 } 987 } 988 989 /* Disable tap power management */ 990 void 991 brgphy_bcm5401_dspcode(struct mii_softc *sc) 992 { 993 static const struct { 994 int reg; 995 uint16_t val; 996 } dspcode[] = { 997 { BRGPHY_MII_AUXCTL, 0x0c20 }, 998 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 999 { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 1000 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 1001 { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 1002 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 1003 { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 1004 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 1005 { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 1006 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 1007 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 1008 { 0, 0 }, 1009 }; 1010 int i; 1011 1012 for (i = 0; dspcode[i].reg != 0; i++) 1013 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1014 DELAY(40); 1015 } 1016 1017 /* Setting some undocumented voltage */ 1018 void 1019 brgphy_bcm5411_dspcode(struct mii_softc *sc) 1020 { 1021 static const struct { 1022 int reg; 1023 uint16_t val; 1024 } dspcode[] = { 1025 { 0x1c, 0x8c23 }, 1026 { 0x1c, 0x8ca3 }, 1027 { 0x1c, 0x8c23 }, 1028 { 0, 0 }, 1029 }; 1030 int i; 1031 1032 for (i = 0; dspcode[i].reg != 0; i++) 1033 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1034 } 1035 1036 void 1037 brgphy_bcm5421_dspcode(struct mii_softc *sc) 1038 { 1039 uint16_t data; 1040 1041 /* Set Class A mode */ 1042 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007); 1043 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1044 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400); 1045 1046 /* Set FFE gamma override to -0.125 */ 1047 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007); 1048 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1049 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800); 1050 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 1051 data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 1052 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200); 1053 } 1054 1055 void 1056 brgphy_bcm54k2_dspcode(struct mii_softc *sc) 1057 { 1058 static const struct { 1059 int reg; 1060 uint16_t val; 1061 } dspcode[] = { 1062 { 4, 0x01e1 }, 1063 { 9, 0x0300 }, 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 } 1071 1072 void 1073 brgphy_adc_bug(struct mii_softc *sc) 1074 { 1075 static const struct { 1076 int reg; 1077 uint16_t val; 1078 } dspcode[] = { 1079 { BRGPHY_MII_AUXCTL, 0x0c00 }, 1080 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 1081 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 1082 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 1083 { BRGPHY_MII_DSP_RW_PORT, 0x0323 }, 1084 { BRGPHY_MII_AUXCTL, 0x0400 }, 1085 { 0, 0 }, 1086 }; 1087 int i; 1088 1089 for (i = 0; dspcode[i].reg != 0; i++) 1090 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1091 } 1092 1093 void 1094 brgphy_5704_a0_bug(struct mii_softc *sc) 1095 { 1096 static const struct { 1097 int reg; 1098 uint16_t val; 1099 } dspcode[] = { 1100 { 0x1c, 0x8d68 }, 1101 { 0x1c, 0x8d68 }, 1102 { 0, 0 }, 1103 }; 1104 int i; 1105 1106 for (i = 0; dspcode[i].reg != 0; i++) 1107 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1108 } 1109 1110 void 1111 brgphy_ber_bug(struct mii_softc *sc) 1112 { 1113 static const struct { 1114 int reg; 1115 uint16_t val; 1116 } dspcode[] = { 1117 { BRGPHY_MII_AUXCTL, 0x0c00 }, 1118 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 1119 { BRGPHY_MII_DSP_RW_PORT, 0x310b }, 1120 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 1121 { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, 1122 { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, 1123 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, 1124 { BRGPHY_MII_AUXCTL, 0x0400 }, 1125 { 0, 0 }, 1126 }; 1127 int i; 1128 1129 for (i = 0; dspcode[i].reg != 0; i++) 1130 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1131 } 1132 1133 /* BCM5701 A0/B0 CRC bug workaround */ 1134 void 1135 brgphy_crc_bug(struct mii_softc *sc) 1136 { 1137 static const struct { 1138 int reg; 1139 uint16_t val; 1140 } dspcode[] = { 1141 { BRGPHY_MII_DSP_ADDR_REG, 0x0a75 }, 1142 { 0x1c, 0x8c68 }, 1143 { 0x1c, 0x8d68 }, 1144 { 0x1c, 0x8c68 }, 1145 { 0, 0 }, 1146 }; 1147 int i; 1148 1149 for (i = 0; dspcode[i].reg != 0; i++) 1150 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1151 } 1152 1153 void 1154 brgphy_disable_early_dac(struct mii_softc *sc) 1155 { 1156 uint32_t val; 1157 1158 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08); 1159 val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 1160 val &= ~(1 << 8); 1161 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val); 1162 1163 } 1164 1165 void 1166 brgphy_jumbo_settings(struct mii_softc *sc) 1167 { 1168 u_int32_t val; 1169 1170 /* Set Jumbo frame settings in the PHY. */ 1171 if (sc->mii_oui == MII_OUI_BROADCOM && 1172 sc->mii_model == MII_MODEL_BROADCOM_BCM5401) { 1173 /* Cannot do read-modify-write on the BCM5401 */ 1174 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); 1175 } else { 1176 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 1177 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1178 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 1179 val | BRGPHY_AUXCTL_LONG_PKT); 1180 } 1181 1182 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 1183 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 1184 val | BRGPHY_PHY_EXTCTL_HIGH_LA); 1185 } 1186 1187 void 1188 brgphy_eth_wirespeed(struct mii_softc *sc) 1189 { 1190 u_int32_t val; 1191 1192 /* Enable Ethernet@Wirespeed */ 1193 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 1194 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1195 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 1196 (val | (1 << 15) | (1 << 4))); 1197 } 1198