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