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