1 /* $NetBSD: igphy.c,v 1.26 2016/07/07 06:55:41 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.26 2016/07/07 06:55:41 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 = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 170 if (sc->mii_capabilities & BMSR_EXTSTAT) 171 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 172 aprint_normal_dev(self, ""); 173 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && 174 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) 175 aprint_error("no media present"); 176 else 177 mii_phy_add_media(sc); 178 aprint_normal("\n"); 179 } 180 181 typedef struct { 182 int reg; 183 uint16_t val; 184 } dspcode; 185 186 static const dspcode igp1code[] = { 187 { 0x1f95, 0x0001 }, 188 { 0x1f71, 0xbd21 }, 189 { 0x1f79, 0x0018 }, 190 { 0x1f30, 0x1600 }, 191 { 0x1f31, 0x0014 }, 192 { 0x1f32, 0x161c }, 193 { 0x1f94, 0x0003 }, 194 { 0x1f96, 0x003f }, 195 { 0x2010, 0x0008 }, 196 { 0, 0 }, 197 }; 198 199 static const dspcode igp1code_r2[] = { 200 { 0x1f73, 0x0099 }, 201 { 0, 0 }, 202 }; 203 204 static const dspcode igp3code[] = { 205 { 0x2f5b, 0x9018}, 206 { 0x2f52, 0x0000}, 207 { 0x2fb1, 0x8b24}, 208 { 0x2fb2, 0xf8f0}, 209 { 0x2010, 0x10b0}, 210 { 0x2011, 0x0000}, 211 { 0x20dd, 0x249a}, 212 { 0x20de, 0x00d3}, 213 { 0x28b4, 0x04ce}, 214 { 0x2f70, 0x29e4}, 215 { 0x0000, 0x0140}, 216 { 0x1f30, 0x1606}, 217 { 0x1f31, 0xb814}, 218 { 0x1f35, 0x002a}, 219 { 0x1f3e, 0x0067}, 220 { 0x1f54, 0x0065}, 221 { 0x1f55, 0x002a}, 222 { 0x1f56, 0x002a}, 223 { 0x1f72, 0x3fb0}, 224 { 0x1f76, 0xc0ff}, 225 { 0x1f77, 0x1dec}, 226 { 0x1f78, 0xf9ef}, 227 { 0x1f79, 0x0210}, 228 { 0x1895, 0x0003}, 229 { 0x1796, 0x0008}, 230 { 0x1798, 0xd008}, 231 { 0x1898, 0xd918}, 232 { 0x187a, 0x0800}, 233 { 0x0019, 0x008d}, 234 { 0x001b, 0x2080}, 235 { 0x0014, 0x0045}, 236 { 0x0000, 0x1340}, 237 { 0, 0 }, 238 }; 239 240 /* DSP patch for igp1 and igp2 */ 241 static void 242 igphy_load_dspcode(struct mii_softc *sc) 243 { 244 struct igphy_softc *igsc = (struct igphy_softc *) sc; 245 const dspcode *code; 246 uint16_t reg; 247 int i; 248 249 /* This workaround is only for 82541 and 82547 */ 250 switch (igsc->sc_mactype) { 251 case WM_T_82541: 252 case WM_T_82547: 253 code = igp1code; 254 break; 255 case WM_T_82541_2: 256 case WM_T_82547_2: 257 code = igp1code_r2; 258 break; 259 default: 260 return; /* byebye */ 261 } 262 263 /* Delay after phy reset to enable NVM configuration to load */ 264 delay(20000); 265 266 /* 267 * Save off the current value of register 0x2F5B to be restored at 268 * the end of this routine. 269 */ 270 reg = IGPHY_READ(sc, 0x2f5b); 271 272 /* Disabled the PHY transmitter */ 273 IGPHY_WRITE(sc, 0x2f5b, 0x0003); 274 275 delay(20000); 276 277 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000); 278 PHY_WRITE(sc, 0x0000, 0x0140); 279 280 delay(5000); 281 282 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++) 283 IGPHY_WRITE(sc, code[i].reg, code[i].val); 284 285 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000); 286 PHY_WRITE(sc, 0x0000, 0x3300); 287 288 delay(20000); 289 290 /* Now enable the transmitter */ 291 IGPHY_WRITE(sc, 0x2f5b, reg); 292 } 293 294 static void 295 igphy_load_dspcode_igp3(struct mii_softc *sc) 296 { 297 const dspcode *code = igp3code; 298 int i; 299 300 for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++) 301 IGPHY_WRITE(sc, code[i].reg, code[i].val); 302 } 303 304 static void 305 igphy_reset(struct mii_softc *sc) 306 { 307 struct igphy_softc *igsc = (struct igphy_softc *) sc; 308 uint16_t fused, fine, coarse; 309 310 mii_phy_reset(sc); 311 delay(150); 312 313 switch (igsc->sc_mactype) { 314 case WM_T_82541: 315 case WM_T_82547: 316 case WM_T_82541_2: 317 case WM_T_82547_2: 318 igphy_load_dspcode(sc); 319 break; 320 case WM_T_ICH8: 321 case WM_T_ICH9: 322 if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0) 323 igphy_load_dspcode_igp3(sc); 324 break; 325 default: /* Not for ICH10, PCH and 8257[12] */ 326 break; 327 } 328 329 if (igsc->sc_mactype == WM_T_82547) { 330 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS); 331 if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) { 332 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS); 333 334 fine = fused & ANALOG_FUSE_FINE_MASK; 335 coarse = fused & ANALOG_FUSE_COARSE_MASK; 336 337 if (coarse > ANALOG_FUSE_COARSE_THRESH) { 338 coarse -= ANALOG_FUSE_COARSE_10; 339 fine -= ANALOG_FUSE_FINE_1; 340 } else if (coarse == ANALOG_FUSE_COARSE_THRESH) 341 fine -= ANALOG_FUSE_FINE_10; 342 343 fused = (fused & ANALOG_FUSE_POLY_MASK) | 344 (fine & ANALOG_FUSE_FINE_MASK) | 345 (coarse & ANALOG_FUSE_COARSE_MASK); 346 347 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused); 348 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS, 349 ANALOG_FUSE_ENABLE_SW_CONTROL); 350 } 351 } 352 PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000); 353 } 354 355 356 static int 357 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 358 { 359 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 360 uint16_t reg; 361 362 switch (cmd) { 363 case MII_POLLSTAT: 364 /* 365 * If we're not polling our PHY instance, just return. 366 */ 367 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 368 return (0); 369 break; 370 371 case MII_MEDIACHG: 372 /* 373 * If the media indicates a different PHY instance, 374 * isolate ourselves. 375 */ 376 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 377 reg = PHY_READ(sc, MII_BMCR); 378 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 379 return (0); 380 } 381 382 /* 383 * If the interface is not up, don't do anything. 384 */ 385 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 386 break; 387 388 reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL); 389 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 390 reg |= PSCR_AUTO_MDIX; 391 reg &= ~PSCR_FORCE_MDI_MDIX; 392 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg); 393 } else { 394 reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX); 395 PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg); 396 } 397 398 mii_phy_setmedia(sc); 399 break; 400 401 case MII_TICK: 402 /* 403 * If we're not currently selected, just return. 404 */ 405 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 406 return (0); 407 408 igphy_smartspeed_workaround(sc); 409 410 if (mii_phy_tick(sc) == EJUSTRETURN) 411 return (0); 412 break; 413 414 case MII_DOWN: 415 mii_phy_down(sc); 416 return (0); 417 } 418 419 /* Update the media status. */ 420 mii_phy_status(sc); 421 422 /* Callback if something changed. */ 423 mii_phy_update(sc, cmd); 424 return (0); 425 } 426 427 428 static void 429 igphy_status(struct mii_softc *sc) 430 { 431 struct mii_data *mii = sc->mii_pdata; 432 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 433 uint16_t bmcr, pssr, gtsr, bmsr; 434 435 mii->mii_media_status = IFM_AVALID; 436 mii->mii_media_active = IFM_ETHER; 437 438 pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS); 439 440 if (pssr & PSSR_LINK_UP) 441 mii->mii_media_status |= IFM_ACTIVE; 442 443 bmcr = PHY_READ(sc, MII_BMCR); 444 if (bmcr & BMCR_ISO) { 445 mii->mii_media_active |= IFM_NONE; 446 mii->mii_media_status = 0; 447 return; 448 } 449 450 if (bmcr & BMCR_LOOP) 451 mii->mii_media_active |= IFM_LOOP; 452 453 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 454 455 /* 456 * XXX can't check if the info is valid, no 457 * 'negotiation done' bit? 458 */ 459 if (bmcr & BMCR_AUTOEN) { 460 if ((bmsr & BMSR_ACOMP) == 0) { 461 mii->mii_media_active |= IFM_NONE; 462 return; 463 } 464 switch (pssr & PSSR_SPEED_MASK) { 465 case PSSR_SPEED_1000MBPS: 466 mii->mii_media_active |= IFM_1000_T; 467 gtsr = PHY_READ(sc, MII_100T2SR); 468 if (gtsr & GTSR_MS_RES) 469 mii->mii_media_active |= IFM_ETH_MASTER; 470 break; 471 472 case PSSR_SPEED_100MBPS: 473 mii->mii_media_active |= IFM_100_TX; 474 break; 475 476 case PSSR_SPEED_10MBPS: 477 mii->mii_media_active |= IFM_10_T; 478 break; 479 480 default: 481 mii->mii_media_active |= IFM_NONE; 482 mii->mii_media_status = 0; 483 return; 484 } 485 486 if (pssr & PSSR_FULL_DUPLEX) 487 mii->mii_media_active |= 488 IFM_FDX | mii_phy_flowstatus(sc); 489 else 490 mii->mii_media_active |= IFM_HDX; 491 } else 492 mii->mii_media_active = ife->ifm_media; 493 } 494 495 static void 496 igphy_smartspeed_workaround(struct mii_softc *sc) 497 { 498 struct igphy_softc *igsc = (struct igphy_softc *) sc; 499 uint16_t reg, gtsr, gtcr; 500 501 /* This workaround is only for 82541 and 82547 */ 502 switch (igsc->sc_mactype) { 503 case WM_T_82541: 504 case WM_T_82541_2: 505 case WM_T_82547: 506 case WM_T_82547_2: 507 break; 508 default: 509 /* byebye */ 510 return; 511 } 512 513 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0) 514 return; 515 516 /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */ 517 518 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 519 if ((reg & BMSR_LINK) == 0) { 520 switch (igsc->sc_smartspeed) { 521 case 0: 522 gtsr = PHY_READ(sc, MII_100T2SR); 523 if (!(gtsr & GTSR_MAN_MS_FLT)) 524 break; 525 gtsr = PHY_READ(sc, MII_100T2SR); 526 if (gtsr & GTSR_MAN_MS_FLT) { 527 gtcr = PHY_READ(sc, MII_100T2CR); 528 if (gtcr & GTCR_MAN_MS) { 529 gtcr &= ~GTCR_MAN_MS; 530 PHY_WRITE(sc, MII_100T2CR, 531 gtcr); 532 } 533 mii_phy_auto(sc, 0); 534 } 535 break; 536 case IGPHY_TICK_DOWNSHIFT: 537 gtcr = PHY_READ(sc, MII_100T2CR); 538 gtcr |= GTCR_MAN_MS; 539 PHY_WRITE(sc, MII_100T2CR, gtcr); 540 mii_phy_auto(sc, 0); 541 break; 542 default: 543 break; 544 } 545 if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX) 546 igsc->sc_smartspeed = 0; 547 } else 548 igsc->sc_smartspeed = 0; 549 } 550