1 /* $OpenBSD: brgphy.c,v 1.84 2008/11/08 03:03:50 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 /* 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 int brgphy_mii_phy_auto(struct mii_softc *); 85 void brgphy_loop(struct mii_softc *); 86 void brgphy_reset(struct mii_softc *); 87 void brgphy_bcm5401_dspcode(struct mii_softc *); 88 void brgphy_bcm5411_dspcode(struct mii_softc *); 89 void brgphy_bcm5421_dspcode(struct mii_softc *); 90 void brgphy_bcm54k2_dspcode(struct mii_softc *); 91 void brgphy_adc_bug(struct mii_softc *); 92 void brgphy_5704_a0_bug(struct mii_softc *); 93 void brgphy_ber_bug(struct mii_softc *); 94 void brgphy_crc_bug(struct mii_softc *); 95 void brgphy_jumbo_settings(struct mii_softc *); 96 void brgphy_eth_wirespeed(struct mii_softc *); 97 98 const struct mii_phy_funcs brgphy_copper_funcs = { 99 brgphy_service, brgphy_copper_status, brgphy_reset, 100 }; 101 102 const struct mii_phy_funcs brgphy_fiber_funcs = { 103 brgphy_service, brgphy_fiber_status, brgphy_reset, 104 }; 105 106 const struct mii_phy_funcs brgphy_5708s_funcs = { 107 brgphy_service, brgphy_5708s_status, brgphy_reset, 108 }; 109 110 static const struct mii_phydesc brgphys[] = { 111 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5400, 112 MII_STR_xxBROADCOM_BCM5400 }, 113 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5401, 114 MII_STR_xxBROADCOM_BCM5401 }, 115 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5411, 116 MII_STR_xxBROADCOM_BCM5411 }, 117 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5421, 118 MII_STR_xxBROADCOM_BCM5421 }, 119 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM54K2, 120 MII_STR_xxBROADCOM_BCM54K2 }, 121 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5462, 122 MII_STR_xxBROADCOM_BCM5462 }, 123 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5701, 124 MII_STR_xxBROADCOM_BCM5701 }, 125 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5703, 126 MII_STR_xxBROADCOM_BCM5703 }, 127 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5704, 128 MII_STR_xxBROADCOM_BCM5704 }, 129 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5705, 130 MII_STR_xxBROADCOM_BCM5705 }, 131 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5714, 132 MII_STR_xxBROADCOM_BCM5714 }, 133 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5750, 134 MII_STR_xxBROADCOM_BCM5750 }, 135 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5752, 136 MII_STR_xxBROADCOM_BCM5752 }, 137 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5780, 138 MII_STR_xxBROADCOM_BCM5780 }, 139 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5722, 140 MII_STR_xxBROADCOM2_BCM5722 }, 141 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5755, 142 MII_STR_xxBROADCOM2_BCM5755 }, 143 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5787, 144 MII_STR_xxBROADCOM2_BCM5787 }, 145 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5706, 146 MII_STR_xxBROADCOM_BCM5706 }, 147 { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5708C, 148 MII_STR_xxBROADCOM_BCM5708C }, 149 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5708S, 150 MII_STR_xxBROADCOM2_BCM5708S }, 151 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5906, 152 MII_STR_BROADCOM2_BCM5906 }, 153 154 { 0, 0, 155 NULL }, 156 }; 157 158 int 159 brgphy_probe(struct device *parent, void *match, void *aux) 160 { 161 struct mii_attach_args *ma = aux; 162 163 if (mii_phy_match(ma, brgphys) != NULL) 164 return (10); 165 166 return (0); 167 } 168 169 void 170 brgphy_attach(struct device *parent, struct device *self, void *aux) 171 { 172 struct mii_softc *sc = (struct mii_softc *)self; 173 struct bnx_softc *bnx_sc = NULL; 174 struct mii_attach_args *ma = aux; 175 struct mii_data *mii = ma->mii_data; 176 const struct mii_phydesc *mpd; 177 char *devname; 178 179 devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name; 180 181 mpd = mii_phy_match(ma, brgphys); 182 printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 183 184 sc->mii_inst = mii->mii_instance; 185 sc->mii_phy = ma->mii_phyno; 186 sc->mii_model = MII_MODEL(ma->mii_id2); 187 sc->mii_rev = MII_REV(ma->mii_id2); 188 sc->mii_pdata = mii; 189 sc->mii_flags = ma->mii_flags; 190 if (sc->mii_flags & MIIF_HAVEFIBER) { 191 if (MII_OUI(ma->mii_id1, ma->mii_id2) == 192 MII_OUI_xxBROADCOM && 193 (sc->mii_model == MII_MODEL_xxBROADCOM_BCM5706 || 194 sc->mii_model == MII_MODEL_xxBROADCOM_BCM5714 || 195 sc->mii_model == MII_MODEL_xxBROADCOM_BCM5780)) 196 sc->mii_funcs = &brgphy_fiber_funcs; 197 else if (MII_OUI(ma->mii_id1, ma->mii_id2) == 198 MII_OUI_xxBROADCOM2 && sc->mii_model == 199 MII_MODEL_xxBROADCOM2_BCM5708S) 200 sc->mii_funcs = &brgphy_5708s_funcs; 201 } else 202 sc->mii_funcs = &brgphy_copper_funcs; 203 sc->mii_anegticks = MII_ANEGTICKS; 204 205 sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; 206 207 if (strcmp(devname, "bnx") == 0) 208 bnx_sc = sc->mii_pdata->mii_ifp->if_softc; 209 210 PHY_RESET(sc); 211 212 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 213 if (sc->mii_capabilities & BMSR_EXTSTAT) 214 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 215 216 mii_phy_add_media(sc); 217 218 if (sc->mii_flags & MIIF_HAVEFIBER && bnx_sc && 219 (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG)) { 220 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 221 ifmedia_add(&mii->mii_media, 222 IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, 223 sc->mii_inst), 0, NULL); 224 } 225 } 226 227 int 228 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 229 { 230 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 231 int reg, speed = 0, gig; 232 233 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 234 return (ENXIO); 235 236 switch (cmd) { 237 case MII_POLLSTAT: 238 /* 239 * If we're not polling our PHY instance, just return. 240 */ 241 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 242 return (0); 243 break; 244 245 case MII_MEDIACHG: 246 /* 247 * If the media indicates a different PHY instance, 248 * isolate ourselves. 249 */ 250 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 251 reg = PHY_READ(sc, MII_BMCR); 252 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 253 return (0); 254 } 255 256 /* 257 * If the interface is not up, don't do anything. 258 */ 259 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 260 break; 261 262 PHY_RESET(sc); /* XXX hardware bug work-around */ 263 264 switch (IFM_SUBTYPE(ife->ifm_media)) { 265 case IFM_AUTO: 266 (void) brgphy_mii_phy_auto(sc); 267 break; 268 case IFM_2500_SX: 269 speed = BRGPHY_5708S_BMCR_2500; 270 goto setit; 271 case IFM_1000_T: 272 speed = BRGPHY_S1000; 273 goto setit; 274 case IFM_100_TX: 275 speed = BRGPHY_S100; 276 goto setit; 277 case IFM_10_T: 278 speed = BRGPHY_S10; 279 setit: 280 brgphy_loop(sc); 281 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 282 speed |= BRGPHY_BMCR_FDX; 283 gig = BRGPHY_1000CTL_AFD; 284 } else { 285 gig = BRGPHY_1000CTL_AHD; 286 } 287 288 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); 289 PHY_WRITE(sc, BRGPHY_MII_BMCR, speed); 290 PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); 291 292 if ((IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) && 293 (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_SX) && 294 (IFM_SUBTYPE(ife->ifm_media) != IFM_2500_SX)) 295 break; 296 297 PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); 298 PHY_WRITE(sc, BRGPHY_MII_BMCR, 299 speed|BRGPHY_BMCR_AUTOEN|BRGPHY_BMCR_STARTNEG); 300 301 if (sc->mii_model != MII_MODEL_xxBROADCOM_BCM5701) 302 break; 303 304 if (mii->mii_media.ifm_media & IFM_ETH_MASTER) 305 gig |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC; 306 PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); 307 break; 308 default: 309 return (EINVAL); 310 } 311 break; 312 313 case MII_TICK: 314 /* 315 * If we're not currently selected, just return. 316 */ 317 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 318 return (0); 319 320 /* 321 * Is the interface even up? 322 */ 323 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 324 return (0); 325 326 /* 327 * Only used for autonegotiation. 328 */ 329 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 330 break; 331 332 /* 333 * Check to see if we have link. If we do, we don't 334 * need to restart the autonegotiation process. Read 335 * the BMSR twice in case it's latched. 336 */ 337 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 338 if (reg & BMSR_LINK) 339 break; 340 341 /* 342 * Only retry autonegotiation every mii_anegticks seconds. 343 */ 344 if (++sc->mii_ticks <= sc->mii_anegticks) 345 break; 346 347 sc->mii_ticks = 0; 348 brgphy_mii_phy_auto(sc); 349 break; 350 } 351 352 /* Update the media status. */ 353 mii_phy_status(sc); 354 355 /* 356 * Callback if something changed. Note that we need to poke the DSP on 357 * the Broadcom PHYs if the media changes. 358 */ 359 if (sc->mii_media_active != mii->mii_media_active || 360 sc->mii_media_status != mii->mii_media_status || 361 cmd == MII_MEDIACHG) { 362 switch (sc->mii_model) { 363 case MII_MODEL_BROADCOM_BCM5400: 364 brgphy_bcm5401_dspcode(sc); 365 break; 366 case MII_MODEL_xxBROADCOM_BCM5401: 367 if (sc->mii_rev == 1 || sc->mii_rev == 3) 368 brgphy_bcm5401_dspcode(sc); 369 break; 370 case MII_MODEL_xxBROADCOM_BCM5411: 371 brgphy_bcm5411_dspcode(sc); 372 break; 373 } 374 } 375 376 /* Callback if something changed. */ 377 mii_phy_update(sc, cmd); 378 379 return (0); 380 } 381 382 void 383 brgphy_copper_status(struct mii_softc *sc) 384 { 385 struct mii_data *mii = sc->mii_pdata; 386 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 387 int bmcr, bmsr; 388 389 mii->mii_media_status = IFM_AVALID; 390 mii->mii_media_active = IFM_ETHER; 391 392 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); 393 if (bmsr & BRGPHY_BMSR_LINK) 394 mii->mii_media_status |= IFM_ACTIVE; 395 396 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 397 if (bmcr & BRGPHY_BMCR_LOOP) 398 mii->mii_media_active |= IFM_LOOP; 399 400 if (bmcr & BRGPHY_BMCR_AUTOEN) { 401 int auxsts; 402 403 if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { 404 /* Erg, still trying, I guess... */ 405 mii->mii_media_active |= IFM_NONE; 406 return; 407 } 408 409 auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS); 410 411 switch (auxsts & BRGPHY_AUXSTS_AN_RES) { 412 case BRGPHY_RES_1000FD: 413 mii->mii_media_active |= IFM_1000_T | IFM_FDX; 414 break; 415 case BRGPHY_RES_1000HD: 416 mii->mii_media_active |= IFM_1000_T | IFM_HDX; 417 break; 418 case BRGPHY_RES_100FD: 419 mii->mii_media_active |= IFM_100_TX | IFM_FDX; 420 break; 421 case BRGPHY_RES_100T4: 422 mii->mii_media_active |= IFM_100_T4 | IFM_HDX; 423 break; 424 case BRGPHY_RES_100HD: 425 mii->mii_media_active |= IFM_100_TX | IFM_HDX; 426 break; 427 case BRGPHY_RES_10FD: 428 mii->mii_media_active |= IFM_10_T | IFM_FDX; 429 break; 430 case BRGPHY_RES_10HD: 431 mii->mii_media_active |= IFM_10_T | IFM_HDX; 432 break; 433 default: 434 if (sc->mii_model == MII_MODEL_BROADCOM2_BCM5906) { 435 mii->mii_media_active |= (auxsts & 436 BRGPHY_RES_100) ? IFM_100_TX : IFM_10_T; 437 mii->mii_media_active |= (auxsts & 438 BRGPHY_RES_FULL) ? IFM_FDX : IFM_HDX; 439 break; 440 } 441 mii->mii_media_active |= IFM_NONE; 442 return; 443 } 444 445 if (mii->mii_media_active & IFM_FDX) 446 mii->mii_media_active |= mii_phy_flowstatus(sc); 447 448 if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { 449 if (PHY_READ(sc, BRGPHY_MII_1000STS) & 450 BRGPHY_1000STS_MSR) 451 mii->mii_media_active |= IFM_ETH_MASTER; 452 } 453 } else 454 mii->mii_media_active = ife->ifm_media; 455 } 456 457 void 458 brgphy_fiber_status(struct mii_softc *sc) 459 { 460 struct mii_data *mii = sc->mii_pdata; 461 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 462 int bmcr, bmsr; 463 464 mii->mii_media_status = IFM_AVALID; 465 mii->mii_media_active = IFM_ETHER; 466 467 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); 468 if (bmsr & BRGPHY_BMSR_LINK) 469 mii->mii_media_status |= IFM_ACTIVE; 470 471 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 472 if (bmcr & BRGPHY_BMCR_LOOP) 473 mii->mii_media_active |= IFM_LOOP; 474 475 if (bmcr & BRGPHY_BMCR_AUTOEN) { 476 int val; 477 478 if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { 479 /* Erg, still trying, I guess... */ 480 mii->mii_media_active |= IFM_NONE; 481 return; 482 } 483 484 mii->mii_media_active |= IFM_1000_SX; 485 486 val = PHY_READ(sc, BRGPHY_SERDES_ANAR) & 487 PHY_READ(sc, BRGPHY_SERDES_ANLPAR); 488 489 if (val & BRGPHY_SERDES_ANAR_FDX) 490 mii->mii_media_active |= IFM_FDX; 491 else 492 mii->mii_media_active |= IFM_HDX; 493 494 if (mii->mii_media_active & IFM_FDX) 495 mii->mii_media_active |= mii_phy_flowstatus(sc); 496 } else 497 mii->mii_media_active = ife->ifm_media; 498 } 499 500 void 501 brgphy_5708s_status(struct mii_softc *sc) 502 { 503 struct mii_data *mii = sc->mii_pdata; 504 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 505 int bmcr, bmsr; 506 507 mii->mii_media_status = IFM_AVALID; 508 mii->mii_media_active = IFM_ETHER; 509 510 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); 511 if (bmsr & BRGPHY_BMSR_LINK) 512 mii->mii_media_status |= IFM_ACTIVE; 513 514 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 515 if (bmcr & BRGPHY_BMCR_LOOP) 516 mii->mii_media_active |= IFM_LOOP; 517 518 if (bmcr & BRGPHY_BMCR_AUTOEN) { 519 int xstat; 520 521 if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { 522 /* Erg, still trying, I guess... */ 523 mii->mii_media_active |= IFM_NONE; 524 return; 525 } 526 527 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 528 BRGPHY_5708S_DIG_PG0); 529 530 xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); 531 532 switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { 533 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: 534 mii->mii_media_active |= IFM_10_FL; 535 break; 536 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: 537 mii->mii_media_active |= IFM_100_FX; 538 break; 539 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: 540 mii->mii_media_active |= IFM_1000_SX; 541 break; 542 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: 543 mii->mii_media_active |= IFM_2500_SX; 544 break; 545 } 546 547 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) 548 mii->mii_media_active |= IFM_FDX; 549 else 550 mii->mii_media_active |= IFM_HDX; 551 } else 552 mii->mii_media_active = ife->ifm_media; 553 } 554 555 int 556 brgphy_mii_phy_auto(struct mii_softc *sc) 557 { 558 int anar, ktcr = 0; 559 560 PHY_RESET(sc); 561 562 if (sc->mii_flags & MIIF_HAVEFIBER) { 563 anar = BRGPHY_SERDES_ANAR_FDX | BRGPHY_SERDES_ANAR_HDX; 564 if (sc->mii_flags & MIIF_DOPAUSE) 565 anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE; 566 PHY_WRITE(sc, BRGPHY_SERDES_ANAR, anar); 567 } else { 568 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 569 if (sc->mii_flags & MIIF_DOPAUSE) 570 anar |= BRGPHY_ANAR_ASP | BRGPHY_ANAR_PC; 571 PHY_WRITE(sc, BRGPHY_MII_ANAR, anar); 572 } 573 574 /* Enable speed in the 1000baseT control register */ 575 ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD; 576 if (sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701) 577 ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC; 578 PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr); 579 ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL); 580 581 /* Start autonegotiation */ 582 PHY_WRITE(sc, BRGPHY_MII_BMCR, 583 BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); 584 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); 585 586 return (EJUSTRETURN); 587 } 588 589 /* Enable loopback to force the link down. */ 590 void 591 brgphy_loop(struct mii_softc *sc) 592 { 593 u_int32_t bmsr; 594 int i; 595 596 PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); 597 for (i = 0; i < 15000; i++) { 598 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); 599 if (!(bmsr & BRGPHY_BMSR_LINK)) 600 break; 601 DELAY(10); 602 } 603 } 604 605 void 606 brgphy_reset(struct mii_softc *sc) 607 { 608 struct bge_softc *bge_sc = NULL; 609 struct bnx_softc *bnx_sc = NULL; 610 char *devname; 611 612 devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name; 613 614 mii_phy_reset(sc); 615 616 switch (sc->mii_model) { 617 case MII_MODEL_BROADCOM_BCM5400: 618 brgphy_bcm5401_dspcode(sc); 619 break; 620 case MII_MODEL_BROADCOM_BCM5401: 621 if (sc->mii_rev == 1 || sc->mii_rev == 3) 622 brgphy_bcm5401_dspcode(sc); 623 break; 624 case MII_MODEL_BROADCOM_BCM5411: 625 brgphy_bcm5411_dspcode(sc); 626 break; 627 case MII_MODEL_xxBROADCOM_BCM5421: 628 brgphy_bcm5421_dspcode(sc); 629 break; 630 case MII_MODEL_xxBROADCOM_BCM54K2: 631 brgphy_bcm54k2_dspcode(sc); 632 break; 633 } 634 635 /* Handle any bge (NetXtreme/NetLink) workarounds. */ 636 if (strcmp(devname, "bge") == 0) { 637 if (!(sc->mii_flags & MIIF_HAVEFIBER)) { 638 bge_sc = sc->mii_pdata->mii_ifp->if_softc; 639 640 if (bge_sc->bge_flags & BGE_PHY_ADC_BUG) 641 brgphy_adc_bug(sc); 642 if (bge_sc->bge_flags & BGE_PHY_5704_A0_BUG) 643 brgphy_5704_a0_bug(sc); 644 if (bge_sc->bge_flags & BGE_PHY_BER_BUG) 645 brgphy_ber_bug(sc); 646 else if (bge_sc->bge_flags & BGE_PHY_JITTER_BUG) { 647 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00); 648 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 649 0x000a); 650 651 if (bge_sc->bge_flags & BGE_PHY_ADJUST_TRIM) { 652 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 653 0x110b); 654 PHY_WRITE(sc, BRGPHY_TEST1, 655 BRGPHY_TEST1_TRIM_EN | 0x4); 656 } else { 657 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 658 0x010b); 659 } 660 661 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400); 662 } 663 if (bge_sc->bge_flags & BGE_PHY_CRC_BUG) 664 brgphy_crc_bug(sc); 665 666 /* Set Jumbo frame settings in the PHY. */ 667 if (bge_sc->bge_flags & BGE_JUMBO_CAP) 668 brgphy_jumbo_settings(sc); 669 670 /* Adjust output voltage */ 671 if (sc->mii_model == MII_MODEL_BROADCOM2_BCM5906) 672 PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); 673 674 /* Enable Ethernet@Wirespeed */ 675 if (!(bge_sc->bge_flags & BGE_NO_ETH_WIRE_SPEED)) 676 brgphy_eth_wirespeed(sc); 677 678 /* Enable Link LED on Dell boxes */ 679 if (bge_sc->bge_flags & BGE_NO_3LED) { 680 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 681 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) 682 & ~BRGPHY_PHY_EXTCTL_3_LED); 683 } 684 } 685 /* Handle any bnx (NetXtreme II) workarounds. */ 686 } else if (strcmp(devname, "bnx") == 0) { 687 bnx_sc = sc->mii_pdata->mii_ifp->if_softc; 688 689 if (sc->mii_model == MII_MODEL_xxBROADCOM2_BCM5708S) { 690 /* Store autoneg capabilities/results in digital block (Page 0) */ 691 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); 692 PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, 693 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); 694 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); 695 696 /* Enable fiber mode and autodetection */ 697 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, 698 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | 699 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | 700 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); 701 702 /* Enable parallel detection */ 703 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, 704 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | 705 BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); 706 707 /* Advertise 2.5G support through next page during autoneg */ 708 if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) 709 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, 710 PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | 711 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); 712 713 /* Increase TX signal amplitude */ 714 if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) || 715 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) || 716 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) { 717 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 718 BRGPHY_5708S_TX_MISC_PG5); 719 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, 720 PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & 721 ~BRGPHY_5708S_PG5_TXACTL1_VCM); 722 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 723 BRGPHY_5708S_DIG_PG0); 724 } 725 726 /* Backplanes use special driver/pre-driver/pre-emphasis values. */ 727 if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) && 728 (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) { 729 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 730 BRGPHY_5708S_TX_MISC_PG5); 731 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, 732 bnx_sc->bnx_port_hw_cfg & 733 BNX_PORT_HW_CFG_CFG_TXCTL3_MASK); 734 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, 735 BRGPHY_5708S_DIG_PG0); 736 } 737 } else { 738 if (!(sc->mii_flags & MIIF_HAVEFIBER)) { 739 brgphy_ber_bug(sc); 740 741 /* Set Jumbo frame settings in the PHY. */ 742 brgphy_jumbo_settings(sc); 743 744 /* Enable Ethernet@Wirespeed */ 745 brgphy_eth_wirespeed(sc); 746 } 747 } 748 } 749 } 750 751 /* Disable tap power management */ 752 void 753 brgphy_bcm5401_dspcode(struct mii_softc *sc) 754 { 755 static const struct { 756 int reg; 757 uint16_t val; 758 } dspcode[] = { 759 { BRGPHY_MII_AUXCTL, 0x0c20 }, 760 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 761 { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 762 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 763 { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 764 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 765 { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 766 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 767 { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 768 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 769 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 770 { 0, 0 }, 771 }; 772 int i; 773 774 for (i = 0; dspcode[i].reg != 0; i++) 775 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 776 DELAY(40); 777 } 778 779 /* Setting some undocumented voltage */ 780 void 781 brgphy_bcm5411_dspcode(struct mii_softc *sc) 782 { 783 static const struct { 784 int reg; 785 uint16_t val; 786 } dspcode[] = { 787 { 0x1c, 0x8c23 }, 788 { 0x1c, 0x8ca3 }, 789 { 0x1c, 0x8c23 }, 790 { 0, 0 }, 791 }; 792 int i; 793 794 for (i = 0; dspcode[i].reg != 0; i++) 795 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 796 } 797 798 void 799 brgphy_bcm5421_dspcode(struct mii_softc *sc) 800 { 801 uint16_t data; 802 803 /* Set Class A mode */ 804 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007); 805 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 806 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400); 807 808 /* Set FFE gamma override to -0.125 */ 809 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007); 810 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 811 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800); 812 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 813 data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 814 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200); 815 } 816 817 void 818 brgphy_bcm54k2_dspcode(struct mii_softc *sc) 819 { 820 static const struct { 821 int reg; 822 uint16_t val; 823 } dspcode[] = { 824 { 4, 0x01e1 }, 825 { 9, 0x0300 }, 826 { 0, 0 }, 827 }; 828 int i; 829 830 for (i = 0; dspcode[i].reg != 0; i++) 831 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 832 } 833 834 void 835 brgphy_adc_bug(struct mii_softc *sc) 836 { 837 static const struct { 838 int reg; 839 uint16_t val; 840 } dspcode[] = { 841 { BRGPHY_MII_AUXCTL, 0x0c00 }, 842 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 843 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 844 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 845 { BRGPHY_MII_DSP_RW_PORT, 0x0323 }, 846 { BRGPHY_MII_AUXCTL, 0x0400 }, 847 { 0, 0 }, 848 }; 849 int i; 850 851 for (i = 0; dspcode[i].reg != 0; i++) 852 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 853 } 854 855 void 856 brgphy_5704_a0_bug(struct mii_softc *sc) 857 { 858 static const struct { 859 int reg; 860 uint16_t val; 861 } dspcode[] = { 862 { 0x1c, 0x8d68 }, 863 { 0x1c, 0x8d68 }, 864 { 0, 0 }, 865 }; 866 int i; 867 868 for (i = 0; dspcode[i].reg != 0; i++) 869 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 870 } 871 872 void 873 brgphy_ber_bug(struct mii_softc *sc) 874 { 875 static const struct { 876 int reg; 877 uint16_t val; 878 } dspcode[] = { 879 { BRGPHY_MII_AUXCTL, 0x0c00 }, 880 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 881 { BRGPHY_MII_DSP_RW_PORT, 0x310b }, 882 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 883 { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, 884 { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, 885 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, 886 { BRGPHY_MII_AUXCTL, 0x0400 }, 887 { 0, 0 }, 888 }; 889 int i; 890 891 for (i = 0; dspcode[i].reg != 0; i++) 892 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 893 } 894 895 /* BCM5701 A0/B0 CRC bug workaround */ 896 void 897 brgphy_crc_bug(struct mii_softc *sc) 898 { 899 static const struct { 900 int reg; 901 uint16_t val; 902 } dspcode[] = { 903 { BRGPHY_MII_DSP_ADDR_REG, 0x0a75 }, 904 { 0x1c, 0x8c68 }, 905 { 0x1c, 0x8d68 }, 906 { 0x1c, 0x8c68 }, 907 { 0, 0 }, 908 }; 909 int i; 910 911 for (i = 0; dspcode[i].reg != 0; i++) 912 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 913 } 914 915 void 916 brgphy_jumbo_settings(struct mii_softc *sc) 917 { 918 u_int32_t val; 919 920 /* Set Jumbo frame settings in the PHY. */ 921 if (sc->mii_model == MII_MODEL_BROADCOM_BCM5401) { 922 /* Cannot do read-modify-write on the BCM5401 */ 923 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); 924 } else { 925 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); 926 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 927 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 928 val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); 929 } 930 931 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); 932 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 933 val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); 934 } 935 936 void 937 brgphy_eth_wirespeed(struct mii_softc *sc) 938 { 939 u_int32_t val; 940 941 /* Enable Ethernet@Wirespeed */ 942 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 943 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 944 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 945 (val | (1 << 15) | (1 << 4))); 946 } 947