1 /* $OpenBSD: brgphy.c,v 1.104 2014/02/01 01:51:27 brad 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 BRGPHY_S1000 | BRGPHY_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 BRGPHY_S10); 282 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), 283 BRGPHY_S10 | BRGPHY_BMCR_FDX); 284 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), 285 BRGPHY_S100); 286 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), 287 BRGPHY_S100 | BRGPHY_BMCR_FDX); 288 289 if (fast_ether == 0) { 290 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, 291 sc->mii_inst), BRGPHY_S1000); 292 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, 293 sc->mii_inst), BRGPHY_S1000 | BRGPHY_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 = BRGPHY_S1000; 348 goto setit; 349 case IFM_100_TX: 350 speed = BRGPHY_S100; 351 goto setit; 352 case IFM_10_T: 353 speed = BRGPHY_S10; 354 setit: 355 brgphy_loop(sc); 356 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 357 speed |= BRGPHY_BMCR_FDX; 358 gig = BRGPHY_1000CTL_AFD; 359 } else { 360 gig = BRGPHY_1000CTL_AHD; 361 } 362 363 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); 364 PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); 365 PHY_WRITE(sc, BRGPHY_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, BRGPHY_MII_1000CTL, gig); 373 PHY_WRITE(sc, BRGPHY_MII_BMCR, 374 speed|BRGPHY_BMCR_AUTOEN|BRGPHY_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 |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC; 382 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 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, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); 479 if (bmsr & BRGPHY_BMSR_LINK) 480 mii->mii_media_status |= IFM_ACTIVE; 481 482 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 483 if (bmcr & BRGPHY_BMCR_LOOP) 484 mii->mii_media_active |= IFM_LOOP; 485 486 if (bmcr & BRGPHY_BMCR_AUTOEN) { 487 int auxsts; 488 489 if ((bmsr & BRGPHY_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, BRGPHY_MII_1000STS) & 537 BRGPHY_1000STS_MSR) 538 mii->mii_media_active |= IFM_ETH_MASTER; 539 } 540 } else 541 mii->mii_media_active = ife->ifm_media; 542 } 543 544 void 545 brgphy_fiber_status(struct mii_softc *sc) 546 { 547 struct mii_data *mii = sc->mii_pdata; 548 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 549 int bmcr, bmsr; 550 551 mii->mii_media_status = IFM_AVALID; 552 mii->mii_media_active = IFM_ETHER; 553 554 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); 555 if (bmsr & BRGPHY_BMSR_LINK) 556 mii->mii_media_status |= IFM_ACTIVE; 557 558 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 559 if (bmcr & BRGPHY_BMCR_LOOP) 560 mii->mii_media_active |= IFM_LOOP; 561 562 if (bmcr & BRGPHY_BMCR_AUTOEN) { 563 int val; 564 565 if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { 566 /* Erg, still trying, I guess... */ 567 mii->mii_media_active |= IFM_NONE; 568 return; 569 } 570 571 mii->mii_media_active |= IFM_1000_SX; 572 573 val = PHY_READ(sc, BRGPHY_SERDES_ANAR) & 574 PHY_READ(sc, BRGPHY_SERDES_ANLPAR); 575 576 if (val & BRGPHY_SERDES_ANAR_FDX) 577 mii->mii_media_active |= IFM_FDX; 578 else 579 mii->mii_media_active |= IFM_HDX; 580 581 if (mii->mii_media_active & IFM_FDX) 582 mii->mii_media_active |= mii_phy_flowstatus(sc); 583 } else 584 mii->mii_media_active = ife->ifm_media; 585 } 586 587 void 588 brgphy_5708s_status(struct mii_softc *sc) 589 { 590 struct mii_data *mii = sc->mii_pdata; 591 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 592 int bmcr, bmsr; 593 594 mii->mii_media_status = IFM_AVALID; 595 mii->mii_media_active = IFM_ETHER; 596 597 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); 598 if (bmsr & BRGPHY_BMSR_LINK) 599 mii->mii_media_status |= IFM_ACTIVE; 600 601 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 602 if (bmcr & BRGPHY_BMCR_LOOP) 603 mii->mii_media_active |= IFM_LOOP; 604 605 if (bmcr & BRGPHY_BMCR_AUTOEN) { 606 int xstat; 607 608 if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { 609 /* Erg, still trying, I guess... */ 610 mii->mii_media_active |= IFM_NONE; 611 return; 612 } 613 614 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 615 BRGPHY_5708S_DIG_PG0); 616 617 xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); 618 619 switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { 620 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: 621 mii->mii_media_active |= IFM_10_FL; 622 break; 623 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: 624 mii->mii_media_active |= IFM_100_FX; 625 break; 626 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: 627 mii->mii_media_active |= IFM_1000_SX; 628 break; 629 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: 630 mii->mii_media_active |= IFM_2500_SX; 631 break; 632 } 633 634 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) 635 mii->mii_media_active |= IFM_FDX; 636 else 637 mii->mii_media_active |= IFM_HDX; 638 639 if (mii->mii_media_active & IFM_FDX) { 640 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_TX_PAUSE) 641 mii->mii_media_active |= IFM_FLOW | IFM_ETH_TXPAUSE; 642 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_RX_PAUSE) 643 mii->mii_media_active |= IFM_FLOW | IFM_ETH_RXPAUSE; 644 } 645 } else 646 mii->mii_media_active = ife->ifm_media; 647 } 648 649 void 650 brgphy_5709s_status(struct mii_softc *sc) 651 { 652 struct mii_data *mii = sc->mii_pdata; 653 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 654 int bmcr, bmsr; 655 656 mii->mii_media_status = IFM_AVALID; 657 mii->mii_media_active = IFM_ETHER; 658 659 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); 660 if (bmsr & BRGPHY_BMSR_LINK) 661 mii->mii_media_status |= IFM_ACTIVE; 662 663 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 664 if (bmcr & BRGPHY_BMCR_LOOP) 665 mii->mii_media_active |= IFM_LOOP; 666 667 if (bmcr & BRGPHY_BMCR_AUTOEN) { 668 int xstat; 669 670 if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { 671 /* Erg, still trying, I guess... */ 672 mii->mii_media_active |= IFM_NONE; 673 return; 674 } 675 676 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 677 BRGPHY_BLOCK_ADDR_GP_STATUS); 678 679 xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); 680 681 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 682 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 683 684 switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { 685 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: 686 mii->mii_media_active |= IFM_10_FL; 687 break; 688 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: 689 mii->mii_media_active |= IFM_100_FX; 690 break; 691 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: 692 mii->mii_media_active |= IFM_1000_SX; 693 break; 694 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: 695 mii->mii_media_active |= IFM_2500_SX; 696 break; 697 } 698 699 if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX) 700 mii->mii_media_active |= IFM_FDX; 701 else 702 mii->mii_media_active |= IFM_HDX; 703 704 if (mii->mii_media_active & IFM_FDX) 705 mii->mii_media_active |= mii_phy_flowstatus(sc); 706 } else 707 mii->mii_media_active = ife->ifm_media; 708 } 709 710 int 711 brgphy_mii_phy_auto(struct mii_softc *sc) 712 { 713 int anar, ktcr = 0; 714 715 PHY_RESET(sc); 716 717 if (sc->mii_flags & MIIF_HAVEFIBER) { 718 anar = BRGPHY_SERDES_ANAR_FDX | BRGPHY_SERDES_ANAR_HDX; 719 if (sc->mii_flags & MIIF_DOPAUSE) 720 anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE; 721 PHY_WRITE(sc, BRGPHY_SERDES_ANAR, anar); 722 } else { 723 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 724 if (sc->mii_flags & MIIF_DOPAUSE) 725 anar |= BRGPHY_ANAR_ASP | BRGPHY_ANAR_PC; 726 PHY_WRITE(sc, BRGPHY_MII_ANAR, anar); 727 } 728 729 /* Enable speed in the 1000baseT control register */ 730 ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD; 731 if (sc->mii_oui == MII_OUI_xxBROADCOM && 732 sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701) 733 ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC; 734 PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr); 735 ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL); 736 737 /* Start autonegotiation */ 738 PHY_WRITE(sc, BRGPHY_MII_BMCR, 739 BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); 740 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); 741 742 return (EJUSTRETURN); 743 } 744 745 /* Enable loopback to force the link down. */ 746 void 747 brgphy_loop(struct mii_softc *sc) 748 { 749 u_int32_t bmsr; 750 int i; 751 752 PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); 753 for (i = 0; i < 15000; i++) { 754 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); 755 if (!(bmsr & BRGPHY_BMSR_LINK)) 756 break; 757 DELAY(10); 758 } 759 } 760 761 void 762 brgphy_reset(struct mii_softc *sc) 763 { 764 char *devname; 765 766 devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name; 767 768 mii_phy_reset(sc); 769 770 switch (sc->mii_oui) { 771 case MII_OUI_BROADCOM: 772 switch (sc->mii_model) { 773 case MII_MODEL_BROADCOM_BCM5400: 774 brgphy_bcm5401_dspcode(sc); 775 break; 776 case MII_MODEL_BROADCOM_BCM5401: 777 if (sc->mii_rev == 1 || sc->mii_rev == 3) 778 brgphy_bcm5401_dspcode(sc); 779 break; 780 case MII_MODEL_BROADCOM_BCM5411: 781 brgphy_bcm5411_dspcode(sc); 782 break; 783 } 784 break; 785 case MII_OUI_xxBROADCOM: 786 switch (sc->mii_model) { 787 case MII_MODEL_xxBROADCOM_BCM5421: 788 brgphy_bcm5421_dspcode(sc); 789 break; 790 case MII_MODEL_xxBROADCOM_BCM54K2: 791 brgphy_bcm54k2_dspcode(sc); 792 break; 793 } 794 break; 795 } 796 797 /* Handle any bge (NetXtreme/NetLink) workarounds. */ 798 if (strcmp(devname, "bge") == 0) 799 brgphy_reset_bge(sc); 800 /* Handle any bnx (NetXtreme II) workarounds. */ 801 else if (strcmp(devname, "bnx") == 0) 802 brgphy_reset_bnx(sc); 803 } 804 805 void 806 brgphy_reset_bge(struct mii_softc *sc) 807 { 808 struct bge_softc *bge_sc = sc->mii_pdata->mii_ifp->if_softc; 809 810 if (sc->mii_flags & MIIF_HAVEFIBER) 811 return; 812 813 switch (sc->mii_oui) { 814 case MII_OUI_xxBROADCOM3: 815 switch (sc->mii_model) { 816 case MII_MODEL_xxBROADCOM3_BCM5717C: 817 case MII_MODEL_xxBROADCOM3_BCM5719C: 818 case MII_MODEL_xxBROADCOM3_BCM5720C: 819 case MII_MODEL_xxBROADCOM3_BCM57765: 820 return; 821 } 822 } 823 824 if (bge_sc->bge_phy_flags & BGE_PHY_ADC_BUG) 825 brgphy_adc_bug(sc); 826 if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG) 827 brgphy_5704_a0_bug(sc); 828 if (bge_sc->bge_phy_flags & BGE_PHY_BER_BUG) 829 brgphy_ber_bug(sc); 830 else if (bge_sc->bge_phy_flags & BGE_PHY_JITTER_BUG) { 831 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00); 832 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 833 834 if (bge_sc->bge_phy_flags & BGE_PHY_ADJUST_TRIM) { 835 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x110b); 836 PHY_WRITE(sc, BRGPHY_TEST1, BRGPHY_TEST1_TRIM_EN | 837 0x4); 838 } else 839 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x010b); 840 841 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400); 842 } 843 844 if (bge_sc->bge_phy_flags & BGE_PHY_CRC_BUG) 845 brgphy_crc_bug(sc); 846 847 /* Set Jumbo frame settings in the PHY. */ 848 if (bge_sc->bge_flags & BGE_JUMBO_CAPABLE) 849 brgphy_jumbo_settings(sc); 850 851 /* Adjust output voltage */ 852 if (sc->mii_oui == MII_OUI_BROADCOM2 && 853 sc->mii_model == MII_MODEL_BROADCOM2_BCM5906) 854 PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); 855 856 /* Enable Ethernet@Wirespeed */ 857 if (!(bge_sc->bge_phy_flags & BGE_PHY_NO_WIRESPEED)) 858 brgphy_eth_wirespeed(sc); 859 860 /* Enable Link LED on Dell boxes */ 861 if (bge_sc->bge_phy_flags & BGE_PHY_NO_3LED) { 862 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 863 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) 864 & ~BRGPHY_PHY_EXTCTL_3_LED); 865 } 866 } 867 868 void 869 brgphy_reset_bnx(struct mii_softc *sc) 870 { 871 struct bnx_softc *bnx_sc = sc->mii_pdata->mii_ifp->if_softc; 872 873 if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5708 && 874 sc->mii_flags & MIIF_HAVEFIBER) { 875 /* Store autoneg capabilities/results in digital block (Page 0) */ 876 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); 877 PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, 878 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); 879 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); 880 881 /* Enable fiber mode and autodetection */ 882 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, 883 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | 884 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | 885 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); 886 887 /* Enable parallel detection */ 888 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, 889 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | 890 BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); 891 892 /* Advertise 2.5G support through next page during autoneg */ 893 if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) { 894 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, 895 PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | 896 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 897 } 898 899 /* Increase TX signal amplitude */ 900 if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) || 901 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) || 902 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) { 903 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 904 BRGPHY_5708S_TX_MISC_PG5); 905 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, 906 PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & 907 ~BRGPHY_5708S_PG5_TXACTL1_VCM); 908 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 909 BRGPHY_5708S_DIG_PG0); 910 } 911 912 /* Backplanes use special driver/pre-driver/pre-emphasis values. */ 913 if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) && 914 (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) { 915 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 916 BRGPHY_5708S_TX_MISC_PG5); 917 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, 918 bnx_sc->bnx_port_hw_cfg & 919 BNX_PORT_HW_CFG_CFG_TXCTL3_MASK); 920 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 921 BRGPHY_5708S_DIG_PG0); 922 } 923 } else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709 && 924 sc->mii_flags & MIIF_HAVEFIBER) { 925 /* Select the SerDes Digital block of the AN MMD. */ 926 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG); 927 928 PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, 929 (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) & 930 ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) | 931 BRGPHY_SD_DIG_1000X_CTL1_FIBER); 932 933 if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) { 934 /* Select the Over 1G block of the AN MMD. */ 935 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 936 BRGPHY_BLOCK_ADDR_OVER_1G); 937 938 /* 939 * Enable autoneg "Next Page" to advertise 940 * 2.5G support. 941 */ 942 PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, 943 PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) | 944 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 945 } 946 947 /* 948 * Select the Multi-Rate Backplane Ethernet block of 949 * the AN MMD. 950 */ 951 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_MRBE); 952 953 /* Enable MRBE speed autoneg. */ 954 PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, 955 PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) | 956 BRGPHY_MRBE_MSG_PG5_NP_MBRE | 957 BRGPHY_MRBE_MSG_PG5_NP_T2); 958 959 /* Select the Clause 73 User B0 block of the AN MMD. */ 960 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 961 BRGPHY_BLOCK_ADDR_CL73_USER_B0); 962 963 /* Enable MRBE speed autoneg. */ 964 PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, 965 BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | 966 BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | 967 BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); 968 969 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, 970 BRGPHY_BLOCK_ADDR_COMBO_IEEE0); 971 } else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709) { 972 if (BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Ax || 973 BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Bx) 974 brgphy_disable_early_dac(sc); 975 976 /* Set Jumbo frame settings in the PHY. */ 977 brgphy_jumbo_settings(sc); 978 979 /* Enable Ethernet@Wirespeed */ 980 brgphy_eth_wirespeed(sc); 981 } else if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { 982 brgphy_ber_bug(sc); 983 984 /* Set Jumbo frame settings in the PHY. */ 985 brgphy_jumbo_settings(sc); 986 987 /* Enable Ethernet@Wirespeed */ 988 brgphy_eth_wirespeed(sc); 989 } 990 } 991 992 /* Disable tap power management */ 993 void 994 brgphy_bcm5401_dspcode(struct mii_softc *sc) 995 { 996 static const struct { 997 int reg; 998 uint16_t val; 999 } dspcode[] = { 1000 { BRGPHY_MII_AUXCTL, 0x0c20 }, 1001 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 1002 { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 1003 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 1004 { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 1005 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 1006 { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 1007 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 1008 { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 1009 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 1010 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 1011 { 0, 0 }, 1012 }; 1013 int i; 1014 1015 for (i = 0; dspcode[i].reg != 0; i++) 1016 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1017 DELAY(40); 1018 } 1019 1020 /* Setting some undocumented voltage */ 1021 void 1022 brgphy_bcm5411_dspcode(struct mii_softc *sc) 1023 { 1024 static const struct { 1025 int reg; 1026 uint16_t val; 1027 } dspcode[] = { 1028 { 0x1c, 0x8c23 }, 1029 { 0x1c, 0x8ca3 }, 1030 { 0x1c, 0x8c23 }, 1031 { 0, 0 }, 1032 }; 1033 int i; 1034 1035 for (i = 0; dspcode[i].reg != 0; i++) 1036 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1037 } 1038 1039 void 1040 brgphy_bcm5421_dspcode(struct mii_softc *sc) 1041 { 1042 uint16_t data; 1043 1044 /* Set Class A mode */ 1045 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007); 1046 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1047 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400); 1048 1049 /* Set FFE gamma override to -0.125 */ 1050 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007); 1051 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1052 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800); 1053 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 1054 data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 1055 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200); 1056 } 1057 1058 void 1059 brgphy_bcm54k2_dspcode(struct mii_softc *sc) 1060 { 1061 static const struct { 1062 int reg; 1063 uint16_t val; 1064 } dspcode[] = { 1065 { 4, 0x01e1 }, 1066 { 9, 0x0300 }, 1067 { 0, 0 }, 1068 }; 1069 int i; 1070 1071 for (i = 0; dspcode[i].reg != 0; i++) 1072 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1073 } 1074 1075 void 1076 brgphy_adc_bug(struct mii_softc *sc) 1077 { 1078 static const struct { 1079 int reg; 1080 uint16_t val; 1081 } dspcode[] = { 1082 { BRGPHY_MII_AUXCTL, 0x0c00 }, 1083 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 1084 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 1085 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 1086 { BRGPHY_MII_DSP_RW_PORT, 0x0323 }, 1087 { BRGPHY_MII_AUXCTL, 0x0400 }, 1088 { 0, 0 }, 1089 }; 1090 int i; 1091 1092 for (i = 0; dspcode[i].reg != 0; i++) 1093 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1094 } 1095 1096 void 1097 brgphy_5704_a0_bug(struct mii_softc *sc) 1098 { 1099 static const struct { 1100 int reg; 1101 uint16_t val; 1102 } dspcode[] = { 1103 { 0x1c, 0x8d68 }, 1104 { 0x1c, 0x8d68 }, 1105 { 0, 0 }, 1106 }; 1107 int i; 1108 1109 for (i = 0; dspcode[i].reg != 0; i++) 1110 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1111 } 1112 1113 void 1114 brgphy_ber_bug(struct mii_softc *sc) 1115 { 1116 static const struct { 1117 int reg; 1118 uint16_t val; 1119 } dspcode[] = { 1120 { BRGPHY_MII_AUXCTL, 0x0c00 }, 1121 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 1122 { BRGPHY_MII_DSP_RW_PORT, 0x310b }, 1123 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 1124 { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, 1125 { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, 1126 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, 1127 { BRGPHY_MII_AUXCTL, 0x0400 }, 1128 { 0, 0 }, 1129 }; 1130 int i; 1131 1132 for (i = 0; dspcode[i].reg != 0; i++) 1133 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1134 } 1135 1136 /* BCM5701 A0/B0 CRC bug workaround */ 1137 void 1138 brgphy_crc_bug(struct mii_softc *sc) 1139 { 1140 static const struct { 1141 int reg; 1142 uint16_t val; 1143 } dspcode[] = { 1144 { BRGPHY_MII_DSP_ADDR_REG, 0x0a75 }, 1145 { 0x1c, 0x8c68 }, 1146 { 0x1c, 0x8d68 }, 1147 { 0x1c, 0x8c68 }, 1148 { 0, 0 }, 1149 }; 1150 int i; 1151 1152 for (i = 0; dspcode[i].reg != 0; i++) 1153 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 1154 } 1155 1156 void 1157 brgphy_disable_early_dac(struct mii_softc *sc) 1158 { 1159 uint32_t val; 1160 1161 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08); 1162 val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 1163 val &= ~(1 << 8); 1164 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val); 1165 1166 } 1167 1168 void 1169 brgphy_jumbo_settings(struct mii_softc *sc) 1170 { 1171 u_int32_t val; 1172 1173 /* Set Jumbo frame settings in the PHY. */ 1174 if (sc->mii_oui == MII_OUI_BROADCOM && 1175 sc->mii_model == MII_MODEL_BROADCOM_BCM5401) { 1176 /* Cannot do read-modify-write on the BCM5401 */ 1177 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); 1178 } else { 1179 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 1180 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1181 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 1182 val | BRGPHY_AUXCTL_LONG_PKT); 1183 } 1184 1185 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 1186 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 1187 val | BRGPHY_PHY_EXTCTL_HIGH_LA); 1188 } 1189 1190 void 1191 brgphy_eth_wirespeed(struct mii_softc *sc) 1192 { 1193 u_int32_t val; 1194 1195 /* Enable Ethernet@Wirespeed */ 1196 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 1197 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 1198 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 1199 (val | (1 << 15) | (1 << 4))); 1200 } 1201