1 /* $OpenBSD: eephy.c,v 1.3 2001/10/05 18:26:48 nate Exp $ */ 2 /* 3 * Principal Author: Parag Patel 4 * Copyright (c) 2001 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * Additonal Copyright (c) 2001 by Traakan Software under same licence. 30 * Secondary Author: Matthew Jacob 31 */ 32 33 /* 34 * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/device.h> 41 #include <sys/malloc.h> 42 #include <sys/socket.h> 43 44 #include <net/if.h> 45 #include <net/if_media.h> 46 47 #include <dev/mii/mii.h> 48 #include <dev/mii/miivar.h> 49 #include <dev/mii/miidevs.h> 50 51 #include <dev/mii/eephyreg.h> 52 53 54 int eephy_service(struct mii_softc *, struct mii_data *, int); 55 void eephy_status(struct mii_softc *); 56 int eephymatch(struct device *, void *, void *); 57 void eephyattach(struct device *, struct device *, void *); 58 59 struct cfattach eephy_ca = { 60 sizeof (struct mii_softc), eephymatch, eephyattach, 61 mii_phy_detach, mii_phy_activate 62 }; 63 64 struct cfdriver eephy_cd = { 65 NULL, "eephy", DV_DULL 66 }; 67 68 int eephy_service(struct mii_softc *, struct mii_data *, int); 69 void eephy_status(struct mii_softc *); 70 static int eephy_mii_phy_auto(struct mii_softc *, int); 71 extern void mii_phy_auto_timeout(void *); 72 static void eephy_reset(struct mii_softc *); 73 74 75 int 76 eephymatch(struct device *parent, void *match, void *aux) 77 { 78 struct mii_attach_args *ma = aux; 79 u_int32_t id; 80 81 id = ((ma->mii_id1 << 16) | ma->mii_id2) & E1000_ID_MASK; 82 if (id == E1000_ID_88E1000 || id == E1000_ID_88E1000S) { 83 return(10); 84 } 85 return(0); 86 } 87 88 void 89 eephyattach(struct device *parent, struct device *self, void *aux) 90 { 91 struct mii_softc *sc = (struct mii_softc *)self; 92 struct mii_attach_args *ma = aux; 93 struct mii_data *mii = ma->mii_data; 94 char *sep; 95 96 sep = ""; 97 printf(": %s\n", MII_STR_MARVELL_E1000); 98 99 sc->mii_inst = mii->mii_instance; 100 sc->mii_phy = ma->mii_phyno; 101 sc->mii_service = eephy_service; 102 sc->mii_status = eephy_status; 103 sc->mii_pdata = mii; 104 sc->mii_flags = mii->mii_flags; 105 sc->mii_anegticks = 5; 106 107 eephy_reset(sc); 108 109 sc->mii_flags |= MIIF_NOISOLATE; 110 111 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 112 #ifdef __OpenBSD__ 113 #define PRINT(s) 114 #else 115 #define PRINT(s) printf("%s%s", sep, s); sep = ", " 116 #endif 117 118 #ifndef __OpenBSD__ 119 printf("%s: ", sc->mii_dev.dv_xname); 120 #endif 121 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_TX, IFM_FDX, sc->mii_inst), 122 E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); 123 PRINT("1000baseTX-FDX"); 124 /* 125 TODO - apparently 1000BT-simplex not supported? 126 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_TX, 0, sc->mii_inst), 127 E1000_CR_SPEED_1000); 128 PRINT("1000baseTX"); 129 */ 130 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), 131 E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX); 132 PRINT("100baseTX-FDX"); 133 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), 134 E1000_CR_SPEED_100); 135 PRINT("100baseTX"); 136 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), 137 E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX); 138 PRINT("10baseTX-FDX"); 139 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 140 E1000_CR_SPEED_10); 141 PRINT("10baseTX"); 142 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); 143 PRINT("auto"); 144 145 #ifndef __OpenBSD__ 146 printf("\n"); 147 #endif 148 #undef ADD 149 #undef PRINT 150 151 } 152 153 static void 154 eephy_reset(struct mii_softc *sc) 155 { 156 u_int32_t reg; 157 int i; 158 159 /* initialize custom E1000 registers to magic values */ 160 reg = PHY_READ(sc, E1000_SCR); 161 reg &= ~E1000_SCR_AUTO_X_MODE; 162 PHY_WRITE(sc, E1000_SCR, reg); 163 164 /* normal PHY reset */ 165 /*mii_phy_reset(sc);*/ 166 reg = PHY_READ(sc, E1000_CR); 167 reg |= E1000_CR_RESET; 168 PHY_WRITE(sc, E1000_CR, reg); 169 170 for (i = 0; i < 500; i++) { 171 DELAY(1); 172 reg = PHY_READ(sc, E1000_CR); 173 if (!(reg & E1000_CR_RESET)) 174 break; 175 } 176 177 /* set more custom E1000 registers to magic values */ 178 reg = PHY_READ(sc, E1000_SCR); 179 reg |= E1000_SCR_ASSERT_CRS_ON_TX; 180 PHY_WRITE(sc, E1000_SCR, reg); 181 182 reg = PHY_READ(sc, E1000_ESCR); 183 reg |= E1000_ESCR_TX_CLK_25; 184 PHY_WRITE(sc, E1000_ESCR, reg); 185 186 /* even more magic to reset DSP? */ 187 PHY_WRITE(sc, 29, 0x1d); 188 PHY_WRITE(sc, 30, 0xc1); 189 PHY_WRITE(sc, 30, 0x00); 190 } 191 192 int 193 eephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 194 { 195 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 196 int reg; 197 198 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 199 return (ENXIO); 200 201 switch (cmd) { 202 case MII_POLLSTAT: 203 /* 204 * If we're not polling our PHY instance, just return. 205 */ 206 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 207 return (0); 208 break; 209 210 case MII_MEDIACHG: 211 /* 212 * If the media indicates a different PHY instance, 213 * isolate ourselves. 214 */ 215 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 216 reg = PHY_READ(sc, E1000_CR); 217 PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE); 218 return (0); 219 } 220 221 /* 222 * If the interface is not up, don't do anything. 223 */ 224 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { 225 break; 226 } 227 228 switch (IFM_SUBTYPE(ife->ifm_media)) { 229 case IFM_AUTO: 230 /* 231 * If we're already in auto mode, just return. 232 */ 233 if (sc->mii_flags & MIIF_DOINGAUTO) { 234 return (0); 235 } 236 eephy_reset(sc); 237 (void)eephy_mii_phy_auto(sc, 1); 238 break; 239 240 case IFM_1000_TX: 241 if (sc->mii_flags & MIIF_DOINGAUTO) 242 return (0); 243 244 eephy_reset(sc); 245 246 /* TODO - any other way to force 1000BT? */ 247 (void)eephy_mii_phy_auto(sc, 1); 248 break; 249 250 case IFM_100_TX: 251 eephy_reset(sc); 252 253 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 254 PHY_WRITE(sc, E1000_CR, 255 E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_100); 256 PHY_WRITE(sc, E1000_AR, E1000_AR_100TX_FD); 257 } else { 258 PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_100); 259 PHY_WRITE(sc, E1000_AR, E1000_AR_100TX); 260 } 261 break; 262 263 case IFM_10_T: 264 eephy_reset(sc); 265 266 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 267 PHY_WRITE(sc, E1000_CR, 268 E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_10); 269 PHY_WRITE(sc, E1000_AR, E1000_AR_10T_FD); 270 } else { 271 PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_10); 272 PHY_WRITE(sc, E1000_AR, E1000_AR_10T); 273 } 274 275 break; 276 277 default: 278 return (EINVAL); 279 } 280 281 break; 282 283 case MII_TICK: 284 /* 285 * If we're not currently selected, just return. 286 */ 287 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 288 return (0); 289 } 290 291 /* 292 * Only used for autonegotiation. 293 */ 294 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 295 return (0); 296 } 297 298 /* 299 * Is the interface even up? 300 */ 301 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { 302 return (0); 303 } 304 305 /* 306 * Only retry autonegotiation every 5 seconds. 307 */ 308 if (++(sc->mii_ticks) != sc->mii_anegticks) { 309 return (0); 310 } 311 sc->mii_ticks = 0; 312 313 /* 314 * Check to see if we have link. If we do, we don't 315 * need to restart the autonegotiation process. Read 316 * the BMSR twice in case it's latched. 317 */ 318 reg = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); 319 320 if (reg & E1000_SR_LINK_STATUS) 321 break; 322 323 eephy_reset(sc); 324 325 if (eephy_mii_phy_auto(sc, 0) == EJUSTRETURN) { 326 return(0); 327 } 328 329 break; 330 } 331 332 /* Update the media status. */ 333 eephy_status(sc); 334 335 /* Callback if something changed. */ 336 mii_phy_update(sc, cmd); 337 338 return (0); 339 } 340 341 void 342 eephy_status(struct mii_softc *sc) 343 { 344 struct mii_data *mii = sc->mii_pdata; 345 int bmsr, bmcr, esr, ssr, isr, ar, lpar; 346 347 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 348 return; 349 350 mii->mii_media_status = IFM_AVALID; 351 mii->mii_media_active = IFM_ETHER; 352 353 bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); 354 esr = PHY_READ(sc, E1000_ESR); 355 bmcr = PHY_READ(sc, E1000_CR); 356 ssr = PHY_READ(sc, E1000_SSR); 357 isr = PHY_READ(sc, E1000_ISR); 358 ar = PHY_READ(sc, E1000_AR); 359 lpar = PHY_READ(sc, E1000_LPAR); 360 361 if (bmsr & E1000_SR_LINK_STATUS) 362 mii->mii_media_status |= IFM_ACTIVE; 363 364 if (bmcr & E1000_CR_LOOPBACK) 365 mii->mii_media_active |= IFM_LOOP; 366 367 if ((sc->mii_flags & MIIF_DOINGAUTO) && 368 (!(bmsr & E1000_SR_AUTO_NEG_COMPLETE) || !(ssr & E1000_SSR_LINK) || 369 !(ssr & E1000_SSR_SPD_DPLX_RESOLVED))) { 370 /* Erg, still trying, I guess... */ 371 mii->mii_media_active |= IFM_NONE; 372 return; 373 } 374 375 if (ssr & E1000_SSR_1000MBS) 376 mii->mii_media_active |= IFM_1000_TX; 377 else if (ssr & E1000_SSR_100MBS) 378 mii->mii_media_active |= IFM_100_TX; 379 else 380 mii->mii_media_active |= IFM_10_T; 381 382 if (ssr & E1000_SSR_DUPLEX) 383 mii->mii_media_active |= IFM_FDX; 384 else 385 mii->mii_media_active |= IFM_HDX; 386 387 /* FLAG0==rx-flow-control FLAG1==tx-flow-control */ 388 if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) { 389 mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; 390 } else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && 391 (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { 392 mii->mii_media_active |= IFM_FLAG1; 393 } else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && 394 !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { 395 mii->mii_media_active |= IFM_FLAG0; 396 } 397 } 398 399 static int 400 eephy_mii_phy_auto(struct mii_softc *sc, int waitfor) 401 { 402 int bmsr, i; 403 404 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { 405 PHY_WRITE(sc, E1000_AR, E1000_AR_10T | E1000_AR_10T_FD | 406 E1000_AR_100TX | E1000_AR_100TX_FD | 407 E1000_AR_PAUSE | E1000_AR_ASM_DIR); 408 PHY_WRITE(sc, E1000_1GCR, E1000_1GCR_1000T_FD); 409 PHY_WRITE(sc, E1000_CR, 410 E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG); 411 } 412 413 if (waitfor) { 414 /* Wait 500ms for it to complete. */ 415 for (i = 0; i < 500; i++) { 416 bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); 417 418 if (bmsr & E1000_SR_AUTO_NEG_COMPLETE) { 419 return (0); 420 } 421 DELAY(1000); 422 } 423 424 /* 425 * Don't need to worry about clearing MIIF_DOINGAUTO. 426 * If that's set, a timeout is pending, and it will 427 * clear the flag. [do it anyway] 428 */ 429 return (EIO); 430 } 431 432 /* 433 * Just let it finish asynchronously. This is for the benefit of 434 * the tick handler driving autonegotiation. Don't want 500ms 435 * delays all the time while the system is running! 436 */ 437 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { 438 sc->mii_flags |= MIIF_DOINGAUTO; 439 sc->mii_ticks = 0; 440 timeout_set(&sc->mii_phy_timo, mii_phy_auto_timeout, sc); 441 timeout_add(&sc->mii_phy_timo, hz >> 1); 442 } 443 return (EJUSTRETURN); 444 } 445