1 /* $NetBSD: igphy.c,v 1.25 2015/10/30 07:35:30 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.25 2015/10/30 07:35:30 msaitoh Exp $"); 74 75 #ifdef _KERNEL_OPT 76 #include "opt_mii.h" 77 #endif 78 79 #include <sys/param.h> 80 #include <sys/systm.h> 81 #include <sys/kernel.h> 82 #include <sys/device.h> 83 #include <sys/socket.h> 84 #include <sys/errno.h> 85 86 #include <net/if.h> 87 #include <net/if_media.h> 88 89 #include <dev/mii/mii.h> 90 #include <dev/mii/miivar.h> 91 #include <dev/mii/miidevs.h> 92 #include <dev/mii/igphyreg.h> 93 #include <dev/mii/igphyvar.h> 94 #include <dev/pci/if_wmvar.h> 95 96 static void igphy_reset(struct mii_softc *); 97 static void igphy_load_dspcode(struct mii_softc *); 98 static void igphy_load_dspcode_igp3(struct mii_softc *); 99 static void igphy_smartspeed_workaround(struct mii_softc *sc); 100 101 static int igphymatch(device_t, cfdata_t, void *); 102 static void igphyattach(device_t, device_t, void *); 103 104 CFATTACH_DECL_NEW(igphy, sizeof(struct igphy_softc), 105 igphymatch, igphyattach, mii_phy_detach, mii_phy_activate); 106 107 static int igphy_service(struct mii_softc *, struct mii_data *, int); 108 static void igphy_status(struct mii_softc *); 109 110 static const struct mii_phy_funcs igphy_funcs = { 111 igphy_service, igphy_status, igphy_reset, 112 }; 113 114 static const struct mii_phydesc igphys[] = { 115 { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_IGP01E1000, 116 MII_STR_yyINTEL_IGP01E1000 }, 117 118 { MII_OUI_yyINTEL, MII_MODEL_yyINTEL_I82566, 119 MII_STR_yyINTEL_I82566 }, 120 121 {0, 0, 122 NULL }, 123 }; 124 125 static int 126 igphymatch(device_t parent, cfdata_t match, void *aux) 127 { 128 struct mii_attach_args *ma = aux; 129 130 if (mii_phy_match(ma, igphys) != NULL) 131 return 10; 132 133 return 0; 134 } 135 136 static void 137 igphyattach(device_t parent, device_t self, void *aux) 138 { 139 struct mii_softc *sc = device_private(self); 140 struct mii_attach_args *ma = aux; 141 struct mii_data *mii = ma->mii_data; 142 const struct mii_phydesc *mpd; 143 struct igphy_softc *igsc = (struct igphy_softc *) sc; 144 prop_dictionary_t dict; 145 146 mpd = mii_phy_match(ma, igphys); 147 aprint_naive(": Media interface\n"); 148 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 149 150 dict = device_properties(parent); 151 if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype)) 152 aprint_error("WARNING! Failed to get mactype\n"); 153 if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags)) 154 aprint_error("WARNING! Failed to get macflags\n"); 155 156 sc->mii_dev = self; 157 sc->mii_inst = mii->mii_instance; 158 sc->mii_phy = ma->mii_phyno; 159 sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); 160 sc->mii_mpd_model = MII_MODEL(ma->mii_id2); 161 sc->mii_mpd_rev = MII_REV(ma->mii_id2); 162 sc->mii_funcs = &igphy_funcs; 163 sc->mii_pdata = mii; 164 sc->mii_flags = ma->mii_flags; 165 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 166 167 PHY_RESET(sc); 168 169 sc->mii_capabilities = 170 PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 171 if (sc->mii_capabilities & BMSR_EXTSTAT) 172 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 173 aprint_normal_dev(self, ""); 174 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && 175 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) 176 aprint_error("no media present"); 177 else 178 mii_phy_add_media(sc); 179 aprint_normal("\n"); 180 } 181 182 typedef struct { 183 int reg; 184 uint16_t val; 185 } dspcode; 186 187 static const dspcode igp1code[] = { 188 { 0x1f95, 0x0001 }, 189 { 0x1f71, 0xbd21 }, 190 { 0x1f79, 0x0018 }, 191 { 0x1f30, 0x1600 }, 192 { 0x1f31, 0x0014 }, 193 { 0x1f32, 0x161c }, 194 { 0x1f94, 0x0003 }, 195 { 0x1f96, 0x003f }, 196 { 0x2010, 0x0008 }, 197 { 0, 0 }, 198 }; 199 200 static const dspcode igp1code_r2[] = { 201 { 0x1f73, 0x0099 }, 202 { 0, 0 }, 203 }; 204 205 static const dspcode igp3code[] = { 206 { 0x2f5b, 0x9018}, 207 { 0x2f52, 0x0000}, 208 { 0x2fb1, 0x8b24}, 209 { 0x2fb2, 0xf8f0}, 210 { 0x2010, 0x10b0}, 211 { 0x2011, 0x0000}, 212 { 0x20dd, 0x249a}, 213 { 0x20de, 0x00d3}, 214 { 0x28b4, 0x04ce}, 215 { 0x2f70, 0x29e4}, 216 { 0x0000, 0x0140}, 217 { 0x1f30, 0x1606}, 218 { 0x1f31, 0xb814}, 219 { 0x1f35, 0x002a}, 220 { 0x1f3e, 0x0067}, 221 { 0x1f54, 0x0065}, 222 { 0x1f55, 0x002a}, 223 { 0x1f56, 0x002a}, 224 { 0x1f72, 0x3fb0}, 225 { 0x1f76, 0xc0ff}, 226 { 0x1f77, 0x1dec}, 227 { 0x1f78, 0xf9ef}, 228 { 0x1f79, 0x0210}, 229 { 0x1895, 0x0003}, 230 { 0x1796, 0x0008}, 231 { 0x1798, 0xd008}, 232 { 0x1898, 0xd918}, 233 { 0x187a, 0x0800}, 234 { 0x0019, 0x008d}, 235 { 0x001b, 0x2080}, 236 { 0x0014, 0x0045}, 237 { 0x0000, 0x1340}, 238 { 0, 0 }, 239 }; 240 241 /* DSP patch for igp1 and igp2 */ 242 static void 243 igphy_load_dspcode(struct mii_softc *sc) 244 { 245 struct igphy_softc *igsc = (struct igphy_softc *) sc; 246 const dspcode *code; 247 uint16_t reg; 248 int i; 249 250 /* This workaround is only for 82541 and 82547 */ 251 switch (igsc->sc_mactype) { 252 case WM_T_82541: 253 case WM_T_82547: 254 code = igp1code; 255 break; 256 case WM_T_82541_2: 257 case WM_T_82547_2: 258 code = igp1code_r2; 259 break; 260 default: 261 return; /* byebye */ 262 } 263 264 /* Delay after phy reset to enable NVM configuration to load */ 265 delay(20000); 266 267 /* 268 * Save off the current value of register 0x2F5B to be restored at 269 * the end of this routine. 270 */ 271 reg = IGPHY_READ(sc, 0x2f5b); 272 273 /* Disabled the PHY transmitter */ 274 IGPHY_WRITE(sc, 0x2f5b, 0x0003); 275 276 delay(20000); 277 278 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000); 279 PHY_WRITE(sc, 0x0000, 0x0140); 280 281 delay(5000); 282 283 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++) 284 IGPHY_WRITE(sc, code[i].reg, code[i].val); 285 286 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000); 287 PHY_WRITE(sc, 0x0000, 0x3300); 288 289 delay(20000); 290 291 /* Now enable the transmitter */ 292 IGPHY_WRITE(sc, 0x2f5b, reg); 293 } 294 295 static void 296 igphy_load_dspcode_igp3(struct mii_softc *sc) 297 { 298 const dspcode *code = igp3code; 299 int i; 300 301 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++) 302 IGPHY_WRITE(sc, code[i].reg, code[i].val); 303 } 304 305 static void 306 igphy_reset(struct mii_softc *sc) 307 { 308 struct igphy_softc *igsc = (struct igphy_softc *) sc; 309 uint16_t fused, fine, coarse; 310 311 mii_phy_reset(sc); 312 delay(150); 313 314 switch (igsc->sc_mactype) { 315 case WM_T_82541: 316 case WM_T_82547: 317 case WM_T_82541_2: 318 case WM_T_82547_2: 319 igphy_load_dspcode(sc); 320 break; 321 case WM_T_ICH8: 322 case WM_T_ICH9: 323 if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0) 324 igphy_load_dspcode_igp3(sc); 325 break; 326 default: /* Not for ICH10, PCH and 8257[12] */ 327 break; 328 } 329 330 if (igsc->sc_mactype == WM_T_82547) { 331 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS); 332 if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) { 333 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS); 334 335 fine = fused & ANALOG_FUSE_FINE_MASK; 336 coarse = fused & ANALOG_FUSE_COARSE_MASK; 337 338 if (coarse > ANALOG_FUSE_COARSE_THRESH) { 339 coarse -= ANALOG_FUSE_COARSE_10; 340 fine -= ANALOG_FUSE_FINE_1; 341 } else if (coarse == ANALOG_FUSE_COARSE_THRESH) 342 fine -= ANALOG_FUSE_FINE_10; 343 344 fused = (fused & ANALOG_FUSE_POLY_MASK) | 345 (fine & ANALOG_FUSE_FINE_MASK) | 346 (coarse & ANALOG_FUSE_COARSE_MASK); 347 348 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused); 349 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS, 350 ANALOG_FUSE_ENABLE_SW_CONTROL); 351 } 352 } 353 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000); 354 } 355 356 357 static int 358 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 359 { 360 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 361 uint16_t reg; 362 363 switch (cmd) { 364 case MII_POLLSTAT: 365 /* 366 * If we're not polling our PHY instance, just return. 367 */ 368 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 369 return (0); 370 break; 371 372 case MII_MEDIACHG: 373 /* 374 * If the media indicates a different PHY instance, 375 * isolate ourselves. 376 */ 377 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 378 reg = PHY_READ(sc, MII_BMCR); 379 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 380 return (0); 381 } 382 383 /* 384 * If the interface is not up, don't do anything. 385 */ 386 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 387 break; 388 389 reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL); 390 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 391 reg |= PSCR_AUTO_MDIX; 392 reg &= ~PSCR_FORCE_MDI_MDIX; 393 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg); 394 } else { 395 reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX); 396 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg); 397 } 398 399 mii_phy_setmedia(sc); 400 break; 401 402 case MII_TICK: 403 /* 404 * If we're not currently selected, just return. 405 */ 406 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 407 return (0); 408 409 igphy_smartspeed_workaround(sc); 410 411 if (mii_phy_tick(sc) == EJUSTRETURN) 412 return (0); 413 break; 414 415 case MII_DOWN: 416 mii_phy_down(sc); 417 return (0); 418 } 419 420 /* Update the media status. */ 421 mii_phy_status(sc); 422 423 /* Callback if something changed. */ 424 mii_phy_update(sc, cmd); 425 return (0); 426 } 427 428 429 static void 430 igphy_status(struct mii_softc *sc) 431 { 432 struct mii_data *mii = sc->mii_pdata; 433 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 434 uint16_t bmcr, pssr, gtsr, bmsr; 435 436 mii->mii_media_status = IFM_AVALID; 437 mii->mii_media_active = IFM_ETHER; 438 439 pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS); 440 441 if (pssr & PSSR_LINK_UP) 442 mii->mii_media_status |= IFM_ACTIVE; 443 444 bmcr = PHY_READ(sc, MII_BMCR); 445 if (bmcr & BMCR_ISO) { 446 mii->mii_media_active |= IFM_NONE; 447 mii->mii_media_status = 0; 448 return; 449 } 450 451 if (bmcr & BMCR_LOOP) 452 mii->mii_media_active |= IFM_LOOP; 453 454 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 455 456 /* 457 * XXX can't check if the info is valid, no 458 * 'negotiation done' bit? 459 */ 460 if (bmcr & BMCR_AUTOEN) { 461 if ((bmsr & BMSR_ACOMP) == 0) { 462 mii->mii_media_active |= IFM_NONE; 463 return; 464 } 465 switch (pssr & PSSR_SPEED_MASK) { 466 case PSSR_SPEED_1000MBPS: 467 mii->mii_media_active |= IFM_1000_T; 468 gtsr = PHY_READ(sc, MII_100T2SR); 469 if (gtsr & GTSR_MS_RES) 470 mii->mii_media_active |= IFM_ETH_MASTER; 471 break; 472 473 case PSSR_SPEED_100MBPS: 474 mii->mii_media_active |= IFM_100_TX; 475 break; 476 477 case PSSR_SPEED_10MBPS: 478 mii->mii_media_active |= IFM_10_T; 479 break; 480 481 default: 482 mii->mii_media_active |= IFM_NONE; 483 mii->mii_media_status = 0; 484 return; 485 } 486 487 if (pssr & PSSR_FULL_DUPLEX) 488 mii->mii_media_active |= 489 IFM_FDX | mii_phy_flowstatus(sc); 490 else 491 mii->mii_media_active |= IFM_HDX; 492 } else 493 mii->mii_media_active = ife->ifm_media; 494 } 495 496 static void 497 igphy_smartspeed_workaround(struct mii_softc *sc) 498 { 499 struct igphy_softc *igsc = (struct igphy_softc *) sc; 500 uint16_t reg, gtsr, gtcr; 501 502 /* This workaround is only for 82541 and 82547 */ 503 switch (igsc->sc_mactype) { 504 case WM_T_82541: 505 case WM_T_82541_2: 506 case WM_T_82547: 507 case WM_T_82547_2: 508 break; 509 default: 510 /* byebye */ 511 return; 512 } 513 514 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0) 515 return; 516 517 /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */ 518 519 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 520 if ((reg & BMSR_LINK) == 0) { 521 switch (igsc->sc_smartspeed) { 522 case 0: 523 gtsr = PHY_READ(sc, MII_100T2SR); 524 if (!(gtsr & GTSR_MAN_MS_FLT)) 525 break; 526 gtsr = PHY_READ(sc, MII_100T2SR); 527 if (gtsr & GTSR_MAN_MS_FLT) { 528 gtcr = PHY_READ(sc, MII_100T2CR); 529 if (gtcr & GTCR_MAN_MS) { 530 gtcr &= ~GTCR_MAN_MS; 531 PHY_WRITE(sc, MII_100T2CR, 532 gtcr); 533 } 534 mii_phy_auto(sc, 0); 535 } 536 break; 537 case IGPHY_TICK_DOWNSHIFT: 538 gtcr = PHY_READ(sc, MII_100T2CR); 539 gtcr |= GTCR_MAN_MS; 540 PHY_WRITE(sc, MII_100T2CR, gtcr); 541 mii_phy_auto(sc, 0); 542 break; 543 default: 544 break; 545 } 546 if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX) 547 igsc->sc_smartspeed = 0; 548 } else 549 igsc->sc_smartspeed = 0; 550 } 551