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