1 /* $OpenBSD: brgphy.c,v 1.48 2006/05/20 23:03:53 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: src/sys/dev/mii/brgphy.c,v 1.1.2.7 2003/05/11 18:00:55 ps Exp $ 35 * $DragonFly: src/sys/dev/netif/mii_layer/brgphy.c,v 1.15 2006/12/22 23:26:20 swildner Exp $ 36 */ 37 38 /* 39 * Driver for the Broadcom BCR5400 1000baseTX PHY. Speed is always 40 * 1000mbps; all we need to negotiate here is full or half duplex. 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/socket.h> 47 #include <sys/bus.h> 48 49 #include <machine/clock.h> 50 51 #include <net/if.h> 52 #include <net/if_media.h> 53 #include <net/if_arp.h> 54 55 #include "mii.h" 56 #include "miivar.h" 57 #include "miidevs.h" 58 59 #include "brgphyreg.h" 60 #include <dev/netif/bge/if_bgereg.h> 61 62 #include "miibus_if.h" 63 64 static int brgphy_probe(device_t); 65 static int brgphy_attach(device_t); 66 67 static const struct mii_phydesc brgphys[] = { 68 MII_PHYDESC(xxBROADCOM, BCM5400), 69 MII_PHYDESC(xxBROADCOM, BCM5401), 70 MII_PHYDESC(xxBROADCOM, BCM5411), 71 MII_PHYDESC(xxBROADCOM, BCM5421), 72 MII_PHYDESC(xxBROADCOM, BCM54K2), 73 MII_PHYDESC(xxBROADCOM, BCM5462), 74 75 MII_PHYDESC(xxBROADCOM, BCM5701), 76 MII_PHYDESC(xxBROADCOM, BCM5703), 77 MII_PHYDESC(xxBROADCOM, BCM5704), 78 MII_PHYDESC(xxBROADCOM, BCM5705), 79 80 MII_PHYDESC(xxBROADCOM, BCM5714), 81 MII_PHYDESC(xxBROADCOM, BCM5750), 82 MII_PHYDESC(xxBROADCOM, BCM5752), 83 MII_PHYDESC(xxBROADCOM, BCM5780), 84 85 MII_PHYDESC(xxBROADCOM, BCM5706C), 86 MII_PHYDESC(xxBROADCOM, BCM5708C), 87 88 MII_PHYDESC_NULL 89 }; 90 91 static device_method_t brgphy_methods[] = { 92 /* device interface */ 93 DEVMETHOD(device_probe, brgphy_probe), 94 DEVMETHOD(device_attach, brgphy_attach), 95 DEVMETHOD(device_detach, ukphy_detach), 96 DEVMETHOD(device_shutdown, bus_generic_shutdown), 97 { 0, 0 } 98 }; 99 100 static devclass_t brgphy_devclass; 101 102 static driver_t brgphy_driver = { 103 "brgphy", 104 brgphy_methods, 105 sizeof(struct mii_softc) 106 }; 107 108 DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0); 109 110 static int brgphy_service(struct mii_softc *, struct mii_data *, int); 111 static void brgphy_status(struct mii_softc *); 112 static int brgphy_mii_phy_auto(struct mii_softc *, int); 113 static void brgphy_reset(struct mii_softc *); 114 static void brgphy_loop(struct mii_softc *); 115 116 static void brgphy_load_dspcode(struct mii_softc *); 117 static void brgphy_bcm5401_dspcode(struct mii_softc *); 118 static void brgphy_bcm5411_dspcode(struct mii_softc *); 119 static void brgphy_bcm5421_dspcode(struct mii_softc *); 120 static void brgphy_bcm54k2_dspcode(struct mii_softc *); 121 static void brgphy_bcm5703_dspcode(struct mii_softc *); 122 static void brgphy_bcm5704_dspcode(struct mii_softc *); 123 static void brgphy_bcm5750_dspcode(struct mii_softc *); 124 125 static int 126 brgphy_probe(device_t dev) 127 { 128 struct mii_attach_args *ma = device_get_ivars(dev); 129 const struct mii_phydesc *mpd; 130 131 mpd = mii_phy_match(ma, brgphys); 132 if (mpd != NULL) { 133 device_set_desc(dev, mpd->mpd_name); 134 return (0); 135 } 136 return(ENXIO); 137 } 138 139 static int 140 brgphy_attach(device_t dev) 141 { 142 struct mii_softc *sc; 143 struct mii_attach_args *ma; 144 struct mii_data *mii; 145 146 sc = device_get_softc(dev); 147 ma = device_get_ivars(dev); 148 mii_softc_init(sc, ma); 149 sc->mii_dev = device_get_parent(dev); 150 mii = device_get_softc(sc->mii_dev); 151 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 152 153 sc->mii_inst = mii->mii_instance; 154 sc->mii_service = brgphy_service; 155 sc->mii_reset = brgphy_reset; 156 sc->mii_pdata = mii; 157 158 sc->mii_flags |= MIIF_NOISOLATE; 159 mii->mii_instance++; 160 161 brgphy_reset(sc); 162 163 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 164 165 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 166 MII_MEDIA_NONE); 167 #if 0 168 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), 169 MII_MEDIA_100_TX); 170 #endif 171 172 #undef ADD 173 174 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 175 if (sc->mii_capabilities & BMSR_EXTSTAT) 176 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 177 178 device_printf(dev, " "); 179 if ((sc->mii_capabilities & BMSR_MEDIAMASK) || 180 (sc->mii_extcapabilities & EXTSR_MEDIAMASK)) 181 mii_phy_add_media(sc); 182 else 183 kprintf("no media present"); 184 kprintf("\n"); 185 186 MIIBUS_MEDIAINIT(sc->mii_dev); 187 return(0); 188 } 189 190 static int 191 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 192 { 193 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 194 int reg, speed, gig; 195 196 switch (cmd) { 197 case MII_POLLSTAT: 198 /* 199 * If we're not polling our PHY instance, just return. 200 */ 201 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 202 return (0); 203 break; 204 205 case MII_MEDIACHG: 206 /* 207 * If the media indicates a different PHY instance, 208 * isolate ourselves. 209 */ 210 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 211 reg = PHY_READ(sc, MII_BMCR); 212 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 213 return (0); 214 } 215 216 /* 217 * If the interface is not up, don't do anything. 218 */ 219 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 220 break; 221 222 brgphy_reset(sc); /* XXX hardware bug work-around */ 223 224 switch (IFM_SUBTYPE(ife->ifm_media)) { 225 case IFM_AUTO: 226 #ifdef foo 227 /* 228 * If we're already in auto mode, just return. 229 */ 230 if (PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_AUTOEN) 231 return (0); 232 #endif 233 brgphy_mii_phy_auto(sc, 1); 234 break; 235 case IFM_1000_T: 236 speed = BRGPHY_S1000; 237 goto setit; 238 case IFM_100_TX: 239 speed = BRGPHY_S100; 240 goto setit; 241 case IFM_10_T: 242 speed = BRGPHY_S10; 243 setit: 244 brgphy_loop(sc); 245 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 246 speed |= BRGPHY_BMCR_FDX; 247 gig = BRGPHY_1000CTL_AFD; 248 } else { 249 gig = BRGPHY_1000CTL_AHD; 250 } 251 252 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); 253 PHY_WRITE(sc, BRGPHY_MII_BMCR, speed); 254 PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); 255 256 if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) 257 break; 258 259 PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); 260 PHY_WRITE(sc, BRGPHY_MII_BMCR, 261 speed|BRGPHY_BMCR_AUTOEN|BRGPHY_BMCR_STARTNEG); 262 263 if (sc->mii_model != MII_MODEL_xxBROADCOM_BCM5701) 264 break; 265 266 /* 267 * When settning the link manually, one side must 268 * be the master and the other the slave. However 269 * ifmedia doesn't give us a good way to specify 270 * this, so we fake it by using one of the LINK 271 * flags. If LINK0 is set, we program the PHY to 272 * be a master, otherwise it's a slave. 273 */ 274 if ((mii->mii_ifp->if_flags & IFF_LINK0)) { 275 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 276 gig|BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC); 277 } else { 278 PHY_WRITE(sc, BRGPHY_MII_1000CTL, 279 gig|BRGPHY_1000CTL_MSE); 280 } 281 break; 282 #ifdef foo 283 case IFM_NONE: 284 PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN); 285 break; 286 #endif 287 case IFM_100_T4: 288 default: 289 return (EINVAL); 290 } 291 break; 292 293 case MII_TICK: 294 /* 295 * If we're not currently selected, just return. 296 */ 297 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 298 return (0); 299 300 /* 301 * Is the interface even up? 302 */ 303 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 304 return (0); 305 306 /* 307 * Only used for autonegotiation. 308 */ 309 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 310 break; 311 312 /* 313 * Check to see if we have link. If we do, we don't 314 * need to restart the autonegotiation process. Read 315 * the BMSR twice in case it's latched. 316 */ 317 reg = PHY_READ(sc, BRGPHY_MII_AUXSTS); 318 if (reg & BRGPHY_AUXSTS_LINK) 319 break; 320 321 /* 322 * Only retry autonegotiation every 5 seconds. 323 */ 324 if (++sc->mii_ticks <= sc->mii_anegticks) 325 break; 326 327 sc->mii_ticks = 0; 328 if (brgphy_mii_phy_auto(sc, 0) == EJUSTRETURN) 329 return (0); 330 break; 331 } 332 333 /* Update the media status. */ 334 brgphy_status(sc); 335 336 /* 337 * Callback if something changed. Note that we need to poke 338 * the DSP on the Broadcom PHYs if the media changes. 339 */ 340 if (sc->mii_media_active != mii->mii_media_active || 341 sc->mii_media_status != mii->mii_media_status || 342 cmd == MII_MEDIACHG) { 343 switch (sc->mii_model) { 344 case MII_MODEL_BROADCOM_BCM5400: 345 case MII_MODEL_xxBROADCOM_BCM5401: 346 case MII_MODEL_xxBROADCOM_BCM5411: 347 brgphy_load_dspcode(sc); 348 break; 349 } 350 } 351 mii_phy_update(sc, cmd); 352 return (0); 353 } 354 355 static void 356 brgphy_status(struct mii_softc *sc) 357 { 358 struct mii_data *mii = sc->mii_pdata; 359 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 360 int bmsr, bmcr; 361 362 mii->mii_media_status = IFM_AVALID; 363 mii->mii_media_active = IFM_ETHER; 364 365 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); 366 if (PHY_READ(sc, BRGPHY_MII_AUXSTS) & BRGPHY_AUXSTS_LINK) 367 mii->mii_media_status |= IFM_ACTIVE; 368 369 bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); 370 371 if (bmcr & BRGPHY_BMCR_LOOP) 372 mii->mii_media_active |= IFM_LOOP; 373 374 if (bmcr & BRGPHY_BMCR_AUTOEN) { 375 if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { 376 /* Erg, still trying, I guess... */ 377 mii->mii_media_active |= IFM_NONE; 378 return; 379 } 380 381 switch (PHY_READ(sc, BRGPHY_MII_AUXSTS) & 382 BRGPHY_AUXSTS_AN_RES) { 383 case BRGPHY_RES_1000FD: 384 mii->mii_media_active |= IFM_1000_T | IFM_FDX; 385 break; 386 case BRGPHY_RES_1000HD: 387 mii->mii_media_active |= IFM_1000_T | IFM_HDX; 388 break; 389 case BRGPHY_RES_100FD: 390 mii->mii_media_active |= IFM_100_TX | IFM_FDX; 391 break; 392 case BRGPHY_RES_100T4: 393 mii->mii_media_active |= IFM_100_T4; 394 break; 395 case BRGPHY_RES_100HD: 396 mii->mii_media_active |= IFM_100_TX | IFM_HDX; 397 break; 398 case BRGPHY_RES_10FD: 399 mii->mii_media_active |= IFM_10_T | IFM_FDX; 400 break; 401 case BRGPHY_RES_10HD: 402 mii->mii_media_active |= IFM_10_T | IFM_HDX; 403 break; 404 default: 405 mii->mii_media_active |= IFM_NONE; 406 break; 407 } 408 return; 409 } 410 411 mii->mii_media_active = ife->ifm_media; 412 } 413 414 415 static int 416 brgphy_mii_phy_auto(struct mii_softc *sc, int waitfor) 417 { 418 int bmsr, ktcr = 0, i; 419 420 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { 421 brgphy_loop(sc); 422 brgphy_reset(sc); 423 ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD; 424 if (sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701) 425 ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC; 426 PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr); 427 ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL); 428 DELAY(1000); 429 PHY_WRITE(sc, BRGPHY_MII_ANAR, 430 BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA); 431 DELAY(1000); 432 PHY_WRITE(sc, BRGPHY_MII_BMCR, 433 BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); 434 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); 435 } 436 437 if (waitfor) { 438 /* Wait 500ms for it to complete. */ 439 for (i = 0; i < 500; i++) { 440 if ((bmsr = PHY_READ(sc, BRGPHY_MII_BMSR)) & 441 BRGPHY_BMSR_ACOMP) 442 return (0); 443 DELAY(1000); 444 } 445 446 /* 447 * Don't need to worry about clearing MIIF_DOINGAUTO. 448 * If that's set, a timeout is pending, and it will 449 * clear the flag. 450 */ 451 return (EIO); 452 } 453 454 /* 455 * Just let it finish asynchronously. This is for the benefit of 456 * the tick handler driving autonegotiation. Don't want 500ms 457 * delays all the time while the system is running! 458 */ 459 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { 460 sc->mii_flags |= MIIF_DOINGAUTO; 461 callout_reset(&sc->mii_auto_ch, hz >> 1, 462 mii_phy_auto_timeout, sc); 463 } 464 465 return (EJUSTRETURN); 466 } 467 468 static void 469 brgphy_loop(struct mii_softc *sc) 470 { 471 uint32_t bmsr; 472 int i; 473 474 PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); 475 for (i = 0; i < 15000; i++) { 476 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); 477 if (!(bmsr & BRGPHY_BMSR_LINK)) 478 break; 479 DELAY(10); 480 } 481 } 482 483 static void 484 brgphy_reset(struct mii_softc *sc) 485 { 486 u_int32_t val; 487 struct ifnet *ifp; 488 struct bge_softc *bge_sc; 489 490 mii_phy_reset(sc); 491 492 ifp = sc->mii_pdata->mii_ifp; 493 bge_sc = ifp->if_softc; 494 495 brgphy_load_dspcode(sc); 496 497 /* 498 * Don't enable Ethernet@WireSpeed for the 5700 or 5705 499 * other than A0 and A1 chips. Make sure we only do this 500 * test on "bge" NICs, since other drivers may use this 501 * same PHY subdriver. 502 */ 503 if (strncmp(ifp->if_xname, "bge", 3) == 0 && 504 (bge_sc->bge_asicrev == BGE_ASICREV_BCM5700 || 505 (bge_sc->bge_asicrev == BGE_ASICREV_BCM5705 && 506 (bge_sc->bge_chipid != BGE_CHIPID_BCM5705_A0 && 507 bge_sc->bge_chipid != BGE_CHIPID_BCM5705_A1)))) 508 return; 509 510 /* Enable Ethernet@WireSpeed. */ 511 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); 512 val = PHY_READ(sc, BRGPHY_MII_AUXCTL); 513 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4)); 514 515 /* Enable Link LED on Dell boxes */ 516 if (bge_sc->bge_no_3_led) { 517 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 518 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) 519 & ~BRGPHY_PHY_EXTCTL_3_LED); 520 } 521 } 522 523 /* Turn off tap power management on 5401. */ 524 static void 525 brgphy_bcm5401_dspcode(struct mii_softc *sc) 526 { 527 static const struct { 528 int reg; 529 uint16_t val; 530 } dspcode[] = { 531 { BRGPHY_MII_AUXCTL, 0x0c20 }, 532 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, 533 { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, 534 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, 535 { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, 536 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 537 { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, 538 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, 539 { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, 540 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 541 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, 542 { 0, 0 }, 543 }; 544 int i; 545 546 for (i = 0; dspcode[i].reg != 0; i++) 547 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 548 DELAY(40); 549 } 550 551 /* Setting some undocumented voltage */ 552 static void 553 brgphy_bcm5411_dspcode(struct mii_softc *sc) 554 { 555 static const struct { 556 int reg; 557 uint16_t val; 558 } dspcode[] = { 559 { 0x1c, 0x8c23 }, 560 { 0x1c, 0x8ca3 }, 561 { 0x1c, 0x8c23 }, 562 { 0, 0 }, 563 }; 564 int i; 565 566 for (i = 0; dspcode[i].reg != 0; i++) 567 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 568 } 569 570 static void 571 brgphy_bcm5421_dspcode(struct mii_softc *sc) 572 { 573 uint16_t data; 574 575 /* Set Class A mode */ 576 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007); 577 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 578 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400); 579 580 /* Set FFE gamma override to -0.125 */ 581 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007); 582 data = PHY_READ(sc, BRGPHY_MII_AUXCTL); 583 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800); 584 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); 585 data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); 586 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200); 587 } 588 589 static void 590 brgphy_bcm54k2_dspcode(struct mii_softc *sc) 591 { 592 static const struct { 593 int reg; 594 uint16_t val; 595 } dspcode[] = { 596 { 4, 0x01e1 }, 597 { 9, 0x0300 }, 598 { 0, 0 }, 599 }; 600 int i; 601 602 for (i = 0; dspcode[i].reg != 0; i++) 603 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 604 } 605 606 static void 607 brgphy_bcm5703_dspcode(struct mii_softc *sc) 608 { 609 static const struct { 610 int reg; 611 uint16_t val; 612 } dspcode[] = { 613 { BRGPHY_MII_AUXCTL, 0x0c00 }, 614 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 615 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 616 { 0, 0 }, 617 }; 618 int i; 619 620 for (i = 0; dspcode[i].reg != 0; i++) 621 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 622 } 623 624 static void 625 brgphy_bcm5704_dspcode(struct mii_softc *sc) 626 { 627 static const struct { 628 int reg; 629 u_int16_t val; 630 } dspcode[] = { 631 { BRGPHY_MII_AUXCTL, 0x0c00 }, 632 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 633 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, 634 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 635 { BRGPHY_MII_DSP_RW_PORT, 0x0323 }, 636 { BRGPHY_MII_AUXCTL, 0x0400 }, 637 { 0x1c, 0x8d68 }, 638 { 0x1c, 0x8d68 }, 639 { 0, 0 }, 640 }; 641 int i; 642 643 for (i = 0; dspcode[i].reg != 0; i++) 644 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 645 } 646 647 static void 648 brgphy_bcm5750_dspcode(struct mii_softc *sc) 649 { 650 static const struct { 651 int reg; 652 uint16_t val; 653 } dspcode[] = { 654 { BRGPHY_MII_AUXCTL, 0x0c00 }, 655 { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, 656 { BRGPHY_MII_DSP_RW_PORT, 0x310b }, 657 { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, 658 { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, 659 { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, 660 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, 661 { BRGPHY_MII_AUXCTL, 0x0400 }, 662 { 0, 0 }, 663 }; 664 int i; 665 666 for (i = 0; dspcode[i].reg != 0; i++) 667 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); 668 } 669 670 static void 671 brgphy_load_dspcode(struct mii_softc *sc) 672 { 673 switch (sc->mii_model) { 674 case MII_MODEL_BROADCOM_BCM5400: 675 brgphy_bcm5401_dspcode(sc); 676 break; 677 case MII_MODEL_BROADCOM_BCM5401: 678 if (sc->mii_rev == 1 || sc->mii_rev == 3) 679 brgphy_bcm5401_dspcode(sc); 680 break; 681 case MII_MODEL_BROADCOM_BCM5411: 682 brgphy_bcm5411_dspcode(sc); 683 break; 684 case MII_MODEL_xxBROADCOM_BCM5421: 685 brgphy_bcm5421_dspcode(sc); 686 break; 687 case MII_MODEL_xxBROADCOM_BCM54K2: 688 brgphy_bcm54k2_dspcode(sc); 689 break; 690 case MII_MODEL_xxBROADCOM_BCM5703: 691 brgphy_bcm5703_dspcode(sc); 692 break; 693 case MII_MODEL_xxBROADCOM_BCM5704: 694 brgphy_bcm5704_dspcode(sc); 695 break; 696 case MII_MODEL_xxBROADCOM_BCM5705: 697 case MII_MODEL_xxBROADCOM_BCM5750: 698 case MII_MODEL_xxBROADCOM_BCM5714: 699 case MII_MODEL_xxBROADCOM_BCM5780: 700 case MII_MODEL_xxBROADCOM_BCM5752: 701 case MII_MODEL_xxBROADCOM_BCM5706C: 702 case MII_MODEL_xxBROADCOM_BCM5708C: 703 brgphy_bcm5750_dspcode(sc); 704 break; 705 } 706 } 707