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