1 /* $NetBSD: igphy.c,v 1.21 2010/03/07 07:53:37 msaitoh Exp $ */ 2 3 /* 4 * The Intel copyright applies to the analog register setup, and the 5 * (currently disabled) SmartSpeed workaround code. 6 */ 7 8 /******************************************************************************* 9 10 Copyright (c) 2001-2003, Intel Corporation 11 All rights reserved. 12 13 Redistribution and use in source and binary forms, with or without 14 modification, are permitted provided that the following conditions are met: 15 16 1. Redistributions of source code must retain the above copyright notice, 17 this list of conditions and the following disclaimer. 18 19 2. Redistributions in binary form must reproduce the above copyright 20 notice, this list of conditions and the following disclaimer in the 21 documentation and/or other materials provided with the distribution. 22 23 3. Neither the name of the Intel Corporation nor the names of its 24 contributors may be used to endorse or promote products derived from 25 this software without specific prior written permission. 26 27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 31 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 POSSIBILITY OF SUCH DAMAGE. 38 39 *******************************************************************************/ 40 41 42 /*- 43 * Copyright (c) 1998, 1999, 2000, 2003 The NetBSD Foundation, Inc. 44 * All rights reserved. 45 * 46 * This code is derived from software contributed to The NetBSD Foundation 47 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 48 * NASA Ames Research Center, and by Frank van der Linden. 49 * 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 1. Redistributions of source code must retain the above copyright 54 * notice, this list of conditions and the following disclaimer. 55 * 2. Redistributions in binary form must reproduce the above copyright 56 * notice, this list of conditions and the following disclaimer in the 57 * documentation and/or other materials provided with the distribution. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 60 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 62 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 63 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 64 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 65 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 66 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 67 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 68 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 69 * POSSIBILITY OF SUCH DAMAGE. 70 */ 71 72 #include <sys/cdefs.h> 73 __KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.21 2010/03/07 07:53:37 msaitoh Exp $"); 74 75 #include "opt_mii.h" 76 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/kernel.h> 80 #include <sys/device.h> 81 #include <sys/socket.h> 82 #include <sys/errno.h> 83 84 #include <net/if.h> 85 #include <net/if_media.h> 86 87 #include <dev/mii/mii.h> 88 #include <dev/mii/miivar.h> 89 #include <dev/mii/miidevs.h> 90 #include <dev/mii/igphyreg.h> 91 #include <dev/mii/igphyvar.h> 92 #include <dev/pci/if_wmvar.h> 93 94 static void igphy_reset(struct mii_softc *); 95 static void igphy_load_dspcode(struct mii_softc *); 96 static void igphy_load_dspcode_igp3(struct mii_softc *); 97 static void igphy_smartspeed_workaround(struct mii_softc *sc); 98 99 static int igphymatch(device_t, cfdata_t, void *); 100 static void igphyattach(device_t, device_t, void *); 101 102 CFATTACH_DECL_NEW(igphy, sizeof(struct igphy_softc), 103 igphymatch, igphyattach, mii_phy_detach, mii_phy_activate); 104 105 static int igphy_service(struct mii_softc *, struct mii_data *, int); 106 static void igphy_status(struct mii_softc *); 107 108 static const struct mii_phy_funcs igphy_funcs = { 109 igphy_service, igphy_status, igphy_reset, 110 }; 111 112 static const struct mii_phydesc igphys[] = { 113 { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_IGP01E1000, 114 MII_STR_yyINTEL_IGP01E1000 }, 115 116 { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_I82566, 117 MII_STR_yyINTEL_I82566 }, 118 119 {0, 0, 120 NULL }, 121 }; 122 123 static int 124 igphymatch(device_t parent, cfdata_t match, void *aux) 125 { 126 struct mii_attach_args *ma = aux; 127 128 if (mii_phy_match(ma, igphys) != NULL) 129 return 10; 130 131 return 0; 132 } 133 134 static void 135 igphyattach(device_t parent, device_t self, void *aux) 136 { 137 struct mii_softc *sc = device_private(self); 138 struct mii_attach_args *ma = aux; 139 struct mii_data *mii = ma->mii_data; 140 const struct mii_phydesc *mpd; 141 struct igphy_softc *igsc = (struct igphy_softc *) sc; 142 prop_dictionary_t dict; 143 144 mpd = mii_phy_match(ma, igphys); 145 aprint_naive(": Media interface\n"); 146 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 147 148 dict = device_properties(parent); 149 if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype)) 150 aprint_error("WARNING! Failed to get mactype\n"); 151 if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags)) 152 aprint_error("WARNING! Failed to get macflags\n"); 153 154 sc->mii_dev = self; 155 sc->mii_inst = mii->mii_instance; 156 sc->mii_phy = ma->mii_phyno; 157 sc->mii_funcs = &igphy_funcs; 158 sc->mii_pdata = mii; 159 sc->mii_flags = ma->mii_flags; 160 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 161 162 PHY_RESET(sc); 163 164 sc->mii_capabilities = 165 PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 166 if (sc->mii_capabilities & BMSR_EXTSTAT) 167 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 168 aprint_normal_dev(self, ""); 169 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && 170 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) 171 aprint_error("no media present"); 172 else 173 mii_phy_add_media(sc); 174 aprint_normal("\n"); 175 } 176 177 typedef struct { 178 int reg; 179 uint16_t val; 180 } dspcode; 181 182 static const dspcode igp1code[] = { 183 { 0x1f95, 0x0001 }, 184 { 0x1f71, 0xbd21 }, 185 { 0x1f79, 0x0018 }, 186 { 0x1f30, 0x1600 }, 187 { 0x1f31, 0x0014 }, 188 { 0x1f32, 0x161c }, 189 { 0x1f94, 0x0003 }, 190 { 0x1f96, 0x003f }, 191 { 0x2010, 0x0008 }, 192 { 0, 0 }, 193 }; 194 195 static const dspcode igp1code_r2[] = { 196 { 0x1f73, 0x0099 }, 197 { 0, 0 }, 198 }; 199 200 static const dspcode igp3code[] = { 201 { 0x2f5b, 0x9018}, 202 { 0x2f52, 0x0000}, 203 { 0x2fb1, 0x8b24}, 204 { 0x2fb2, 0xf8f0}, 205 { 0x2010, 0x10b0}, 206 { 0x2011, 0x0000}, 207 { 0x20dd, 0x249a}, 208 { 0x20de, 0x00d3}, 209 { 0x28b4, 0x04ce}, 210 { 0x2f70, 0x29e4}, 211 { 0x0000, 0x0140}, 212 { 0x1f30, 0x1606}, 213 { 0x1f31, 0xb814}, 214 { 0x1f35, 0x002a}, 215 { 0x1f3e, 0x0067}, 216 { 0x1f54, 0x0065}, 217 { 0x1f55, 0x002a}, 218 { 0x1f56, 0x002a}, 219 { 0x1f72, 0x3fb0}, 220 { 0x1f76, 0xc0ff}, 221 { 0x1f77, 0x1dec}, 222 { 0x1f78, 0xf9ef}, 223 { 0x1f79, 0x0210}, 224 { 0x1895, 0x0003}, 225 { 0x1796, 0x0008}, 226 { 0x1798, 0xd008}, 227 { 0x1898, 0xd918}, 228 { 0x187a, 0x0800}, 229 { 0x0019, 0x008d}, 230 { 0x001b, 0x2080}, 231 { 0x0014, 0x0045}, 232 { 0x0000, 0x1340}, 233 { 0, 0 }, 234 }; 235 236 /* DSP patch for igp1 and igp2 */ 237 static void 238 igphy_load_dspcode(struct mii_softc *sc) 239 { 240 struct igphy_softc *igsc = (struct igphy_softc *) sc; 241 const dspcode *code; 242 uint16_t reg; 243 int i; 244 245 /* This workaround is only for 82541 and 82547 */ 246 switch (igsc->sc_mactype) { 247 case WM_T_82541: 248 case WM_T_82547: 249 code = igp1code; 250 break; 251 case WM_T_82541_2: 252 case WM_T_82547_2: 253 code = igp1code_r2; 254 break; 255 default: 256 return; /* byebye */ 257 } 258 259 /* Delay after phy reset to enable NVM configuration to load */ 260 delay(20000); 261 262 /* 263 * Save off the current value of register 0x2F5B to be restored at 264 * the end of this routine. 265 */ 266 reg = IGPHY_READ(sc, 0x2f5b); 267 268 /* Disabled the PHY transmitter */ 269 IGPHY_WRITE(sc, 0x2f5b, 0x0003); 270 271 delay(20000); 272 273 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000); 274 PHY_WRITE(sc, 0x0000, 0x0140); 275 276 delay(5000); 277 278 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++) 279 IGPHY_WRITE(sc, code[i].reg, code[i].val); 280 281 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000); 282 PHY_WRITE(sc, 0x0000, 0x3300); 283 284 delay(20000); 285 286 /* Now enable the transmitter */ 287 IGPHY_WRITE(sc, 0x2f5b, reg); 288 } 289 290 static void 291 igphy_load_dspcode_igp3(struct mii_softc *sc) 292 { 293 const dspcode *code = igp3code; 294 int i; 295 296 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++) 297 IGPHY_WRITE(sc, code[i].reg, code[i].val); 298 } 299 300 static void 301 igphy_reset(struct mii_softc *sc) 302 { 303 struct igphy_softc *igsc = (struct igphy_softc *) sc; 304 uint16_t fused, fine, coarse; 305 306 mii_phy_reset(sc); 307 delay(150); 308 309 switch (igsc->sc_mactype) { 310 case WM_T_82541: 311 case WM_T_82547: 312 case WM_T_82541_2: 313 case WM_T_82547_2: 314 igphy_load_dspcode(sc); 315 break; 316 case WM_T_ICH8: 317 case WM_T_ICH9: 318 if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0) 319 igphy_load_dspcode_igp3(sc); 320 break; 321 default: /* Not for ICH10, PCH and 8257[12] */ 322 break; 323 } 324 325 if (igsc->sc_mactype == WM_T_82547) { 326 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS); 327 if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) { 328 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS); 329 330 fine = fused & ANALOG_FUSE_FINE_MASK; 331 coarse = fused & ANALOG_FUSE_COARSE_MASK; 332 333 if (coarse > ANALOG_FUSE_COARSE_THRESH) { 334 coarse -= ANALOG_FUSE_COARSE_10; 335 fine -= ANALOG_FUSE_FINE_1; 336 } else if (coarse == ANALOG_FUSE_COARSE_THRESH) 337 fine -= ANALOG_FUSE_FINE_10; 338 339 fused = (fused & ANALOG_FUSE_POLY_MASK) | 340 (fine & ANALOG_FUSE_FINE_MASK) | 341 (coarse & ANALOG_FUSE_COARSE_MASK); 342 343 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused); 344 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS, 345 ANALOG_FUSE_ENABLE_SW_CONTROL); 346 } 347 } 348 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000); 349 } 350 351 352 static int 353 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 354 { 355 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 356 uint16_t reg; 357 358 switch (cmd) { 359 case MII_POLLSTAT: 360 /* 361 * If we're not polling our PHY instance, just return. 362 */ 363 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 364 return (0); 365 break; 366 367 case MII_MEDIACHG: 368 /* 369 * If the media indicates a different PHY instance, 370 * isolate ourselves. 371 */ 372 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 373 reg = PHY_READ(sc, MII_BMCR); 374 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 375 return (0); 376 } 377 378 /* 379 * If the interface is not up, don't do anything. 380 */ 381 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 382 break; 383 384 reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL); 385 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 386 reg |= PSCR_AUTO_MDIX; 387 reg &= ~PSCR_FORCE_MDI_MDIX; 388 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg); 389 } else { 390 reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX); 391 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg); 392 } 393 394 mii_phy_setmedia(sc); 395 break; 396 397 case MII_TICK: 398 /* 399 * If we're not currently selected, just return. 400 */ 401 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 402 return (0); 403 404 igphy_smartspeed_workaround(sc); 405 406 if (mii_phy_tick(sc) == EJUSTRETURN) 407 return (0); 408 break; 409 410 case MII_DOWN: 411 mii_phy_down(sc); 412 return (0); 413 } 414 415 /* Update the media status. */ 416 mii_phy_status(sc); 417 418 /* Callback if something changed. */ 419 mii_phy_update(sc, cmd); 420 return (0); 421 } 422 423 424 static void 425 igphy_status(struct mii_softc *sc) 426 { 427 struct mii_data *mii = sc->mii_pdata; 428 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 429 uint16_t bmcr, pssr, gtsr, bmsr; 430 431 mii->mii_media_status = IFM_AVALID; 432 mii->mii_media_active = IFM_ETHER; 433 434 pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS); 435 436 if (pssr & PSSR_LINK_UP) 437 mii->mii_media_status |= IFM_ACTIVE; 438 439 bmcr = PHY_READ(sc, MII_BMCR); 440 if (bmcr & BMCR_ISO) { 441 mii->mii_media_active |= IFM_NONE; 442 mii->mii_media_status = 0; 443 return; 444 } 445 446 if (bmcr & BMCR_LOOP) 447 mii->mii_media_active |= IFM_LOOP; 448 449 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 450 451 /* 452 * XXX can't check if the info is valid, no 453 * 'negotiation done' bit? 454 */ 455 if (bmcr & BMCR_AUTOEN) { 456 if ((bmsr & BMSR_ACOMP) == 0) { 457 mii->mii_media_active |= IFM_NONE; 458 return; 459 } 460 switch (pssr & PSSR_SPEED_MASK) { 461 case PSSR_SPEED_1000MBPS: 462 mii->mii_media_active |= IFM_1000_T; 463 gtsr = PHY_READ(sc, MII_100T2SR); 464 if (gtsr & GTSR_MS_RES) 465 mii->mii_media_active |= IFM_ETH_MASTER; 466 break; 467 468 case PSSR_SPEED_100MBPS: 469 mii->mii_media_active |= IFM_100_TX; 470 break; 471 472 case PSSR_SPEED_10MBPS: 473 mii->mii_media_active |= IFM_10_T; 474 break; 475 476 default: 477 mii->mii_media_active |= IFM_NONE; 478 mii->mii_media_status = 0; 479 return; 480 } 481 482 if (pssr & PSSR_FULL_DUPLEX) 483 mii->mii_media_active |= 484 IFM_FDX | mii_phy_flowstatus(sc); 485 } else 486 mii->mii_media_active = ife->ifm_media; 487 } 488 489 static void 490 igphy_smartspeed_workaround(struct mii_softc *sc) 491 { 492 struct igphy_softc *igsc = (struct igphy_softc *) sc; 493 uint16_t reg, gtsr, gtcr; 494 495 496 /* This workaround is only for 82541 and 82547 */ 497 switch (igsc->sc_mactype) { 498 case WM_T_82541: 499 case WM_T_82541_2: 500 case WM_T_82547: 501 case WM_T_82547_2: 502 break; 503 default: 504 /* byebye */ 505 return; 506 } 507 508 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0) 509 return; 510 511 /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */ 512 513 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 514 if ((reg & BMSR_LINK) == 0) { 515 switch (igsc->sc_smartspeed) { 516 case 0: 517 gtsr = PHY_READ(sc, MII_100T2SR); 518 if (!(gtsr & GTSR_MAN_MS_FLT)) 519 break; 520 gtsr = PHY_READ(sc, MII_100T2SR); 521 if (gtsr & GTSR_MAN_MS_FLT) { 522 gtcr = PHY_READ(sc, MII_100T2CR); 523 if (gtcr & GTCR_MAN_MS) { 524 gtcr &= ~GTCR_MAN_MS; 525 PHY_WRITE(sc, MII_100T2CR, 526 gtcr); 527 } 528 mii_phy_auto(sc, 0); 529 } 530 break; 531 case IGPHY_TICK_DOWNSHIFT: 532 gtcr = PHY_READ(sc, MII_100T2CR); 533 gtcr |= GTCR_MAN_MS; 534 PHY_WRITE(sc, MII_100T2CR, gtcr); 535 mii_phy_auto(sc, 0); 536 break; 537 default: 538 break; 539 } 540 if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX) 541 igsc->sc_smartspeed = 0; 542 } else 543 igsc->sc_smartspeed = 0; 544 } 545