1 /* $OpenBSD: eephy.c,v 1.9 2003/05/14 05:09:43 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 80 if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxMARVELL && 81 (MII_MODEL(ma->mii_id2) == MII_MODEL_xxMARVELL_E1000_3 || 82 MII_MODEL(ma->mii_id2) == MII_MODEL_xxMARVELL_E1000_5 )) 83 return (10); 84 85 if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_MARVELL && 86 (MII_MODEL(ma->mii_id2) == MII_MODEL_MARVELL_E1000 || 87 MII_MODEL(ma->mii_id2) == MII_MODEL_MARVELL_E1000_3 || 88 MII_MODEL(ma->mii_id2) == MII_MODEL_MARVELL_E1000_4 || 89 MII_MODEL(ma->mii_id2) == MII_MODEL_MARVELL_E1000_5 || 90 MII_MODEL(ma->mii_id2) == MII_MODEL_MARVELL_E1000_6)) 91 return (10); 92 93 return(0); 94 } 95 96 void 97 eephyattach(struct device *parent, struct device *self, void *aux) 98 { 99 struct mii_softc *sc = (struct mii_softc *)self; 100 struct mii_attach_args *ma = aux; 101 struct mii_data *mii = ma->mii_data; 102 char *sep; 103 104 sep = ""; 105 printf(": %s\n", MII_STR_MARVELL_E1000); 106 107 sc->mii_inst = mii->mii_instance; 108 sc->mii_phy = ma->mii_phyno; 109 sc->mii_service = eephy_service; 110 sc->mii_status = eephy_status; 111 sc->mii_pdata = mii; 112 sc->mii_flags = mii->mii_flags; 113 sc->mii_anegticks = 10; 114 115 eephy_reset(sc); 116 117 sc->mii_flags |= MIIF_NOISOLATE; 118 119 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 120 #ifdef __OpenBSD__ 121 #define PRINT(s) 122 #else 123 #define PRINT(s) printf("%s%s", sep, s); sep = ", " 124 #endif 125 126 #ifndef __OpenBSD__ 127 printf("%s: ", sc->mii_dev.dv_xname); 128 #endif 129 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), 130 E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); 131 PRINT("1000baseTX-FDX"); 132 /* 133 TODO - apparently 1000BT-simplex not supported? 134 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), 135 E1000_CR_SPEED_1000); 136 PRINT("1000baseTX"); 137 */ 138 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), 139 E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX); 140 PRINT("100baseTX-FDX"); 141 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), 142 E1000_CR_SPEED_100); 143 PRINT("100baseTX"); 144 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), 145 E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX); 146 PRINT("10baseTX-FDX"); 147 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 148 E1000_CR_SPEED_10); 149 PRINT("10baseTX"); 150 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); 151 PRINT("auto"); 152 153 #ifndef __OpenBSD__ 154 printf("\n"); 155 #endif 156 #undef ADD 157 #undef PRINT 158 159 } 160 161 static void 162 eephy_reset(struct mii_softc *sc) 163 { 164 u_int32_t reg; 165 int i; 166 167 /* initialize custom E1000 registers to magic values */ 168 reg = PHY_READ(sc, E1000_SCR); 169 reg &= ~E1000_SCR_AUTO_X_MODE; 170 PHY_WRITE(sc, E1000_SCR, reg); 171 172 /* normal PHY reset */ 173 /*mii_phy_reset(sc);*/ 174 reg = PHY_READ(sc, E1000_CR); 175 reg |= E1000_CR_RESET; 176 PHY_WRITE(sc, E1000_CR, reg); 177 178 for (i = 0; i < 500; i++) { 179 DELAY(1); 180 reg = PHY_READ(sc, E1000_CR); 181 if (!(reg & E1000_CR_RESET)) 182 break; 183 } 184 185 /* set more custom E1000 registers to magic values */ 186 reg = PHY_READ(sc, E1000_SCR); 187 reg |= E1000_SCR_ASSERT_CRS_ON_TX; 188 PHY_WRITE(sc, E1000_SCR, reg); 189 190 reg = PHY_READ(sc, E1000_ESCR); 191 reg |= E1000_ESCR_TX_CLK_25; 192 PHY_WRITE(sc, E1000_ESCR, reg); 193 194 /* even more magic to reset DSP? */ 195 PHY_WRITE(sc, 29, 0x1d); 196 PHY_WRITE(sc, 30, 0xc1); 197 PHY_WRITE(sc, 30, 0x00); 198 } 199 200 int 201 eephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 202 { 203 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 204 int reg; 205 206 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 207 return (ENXIO); 208 209 switch (cmd) { 210 case MII_POLLSTAT: 211 /* 212 * If we're not polling our PHY instance, just return. 213 */ 214 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 215 return (0); 216 break; 217 218 case MII_MEDIACHG: 219 /* 220 * If the media indicates a different PHY instance, 221 * isolate ourselves. 222 */ 223 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 224 reg = PHY_READ(sc, E1000_CR); 225 PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE); 226 return (0); 227 } 228 229 /* 230 * If the interface is not up, don't do anything. 231 */ 232 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { 233 break; 234 } 235 236 switch (IFM_SUBTYPE(ife->ifm_media)) { 237 case IFM_AUTO: 238 /* 239 * If we're already in auto mode, just return. 240 */ 241 if (sc->mii_flags & MIIF_DOINGAUTO) { 242 return (0); 243 } 244 eephy_reset(sc); 245 (void)eephy_mii_phy_auto(sc, 1); 246 break; 247 248 case IFM_1000_T: 249 if (sc->mii_flags & MIIF_DOINGAUTO) 250 return (0); 251 252 eephy_reset(sc); 253 254 /* TODO - any other way to force 1000BT? */ 255 (void)eephy_mii_phy_auto(sc, 1); 256 break; 257 258 case IFM_100_TX: 259 eephy_reset(sc); 260 261 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 262 PHY_WRITE(sc, E1000_CR, 263 E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_100); 264 PHY_WRITE(sc, E1000_AR, E1000_AR_100TX_FD); 265 } else { 266 PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_100); 267 PHY_WRITE(sc, E1000_AR, E1000_AR_100TX); 268 } 269 break; 270 271 case IFM_10_T: 272 eephy_reset(sc); 273 274 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 275 PHY_WRITE(sc, E1000_CR, 276 E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_10); 277 PHY_WRITE(sc, E1000_AR, E1000_AR_10T_FD); 278 } else { 279 PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_10); 280 PHY_WRITE(sc, E1000_AR, E1000_AR_10T); 281 } 282 283 break; 284 285 default: 286 return (EINVAL); 287 } 288 289 break; 290 291 case MII_TICK: 292 /* 293 * If we're not currently selected, just return. 294 */ 295 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 296 return (0); 297 } 298 299 /* 300 * Only used for autonegotiation. 301 */ 302 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 303 return (0); 304 } 305 306 /* 307 * Is the interface even up? 308 */ 309 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { 310 return (0); 311 } 312 313 /* 314 * Only retry autonegotiation every 5 seconds. 315 */ 316 if (++(sc->mii_ticks) != sc->mii_anegticks) { 317 return (0); 318 } 319 sc->mii_ticks = 0; 320 321 /* 322 * Check to see if we have link. If we do, we don't 323 * need to restart the autonegotiation process. Read 324 * the BMSR twice in case it's latched. 325 */ 326 reg = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); 327 328 if (reg & E1000_SR_LINK_STATUS) 329 break; 330 331 eephy_reset(sc); 332 333 if (eephy_mii_phy_auto(sc, 0) == EJUSTRETURN) { 334 return(0); 335 } 336 337 break; 338 } 339 340 /* Update the media status. */ 341 eephy_status(sc); 342 343 /* Callback if something changed. */ 344 mii_phy_update(sc, cmd); 345 346 return (0); 347 } 348 349 void 350 eephy_status(struct mii_softc *sc) 351 { 352 struct mii_data *mii = sc->mii_pdata; 353 int bmsr, bmcr, esr, ssr, isr, ar, lpar; 354 355 mii->mii_media_status = IFM_AVALID; 356 mii->mii_media_active = IFM_ETHER; 357 358 bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); 359 esr = PHY_READ(sc, E1000_ESR); 360 bmcr = PHY_READ(sc, E1000_CR); 361 ssr = PHY_READ(sc, E1000_SSR); 362 isr = PHY_READ(sc, E1000_ISR); 363 ar = PHY_READ(sc, E1000_AR); 364 lpar = PHY_READ(sc, E1000_LPAR); 365 366 if (bmsr & E1000_SR_LINK_STATUS) 367 mii->mii_media_status |= IFM_ACTIVE; 368 369 if (bmcr & E1000_CR_LOOPBACK) 370 mii->mii_media_active |= IFM_LOOP; 371 372 if ((sc->mii_flags & MIIF_DOINGAUTO) && 373 (!(bmsr & E1000_SR_AUTO_NEG_COMPLETE) || !(ssr & E1000_SSR_LINK) || 374 !(ssr & E1000_SSR_SPD_DPLX_RESOLVED))) { 375 /* Erg, still trying, I guess... */ 376 mii->mii_media_active |= IFM_NONE; 377 return; 378 } 379 380 if (ssr & E1000_SSR_1000MBS) 381 mii->mii_media_active |= IFM_1000_T; 382 else if (ssr & E1000_SSR_100MBS) 383 mii->mii_media_active |= IFM_100_TX; 384 else 385 mii->mii_media_active |= IFM_10_T; 386 387 if (ssr & E1000_SSR_DUPLEX) 388 mii->mii_media_active |= IFM_FDX; 389 else 390 mii->mii_media_active |= IFM_HDX; 391 392 /* FLAG0==rx-flow-control FLAG1==tx-flow-control */ 393 if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) { 394 mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; 395 } else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && 396 (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { 397 mii->mii_media_active |= IFM_FLAG1; 398 } else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && 399 !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { 400 mii->mii_media_active |= IFM_FLAG0; 401 } 402 } 403 404 static int 405 eephy_mii_phy_auto(struct mii_softc *sc, int waitfor) 406 { 407 int bmsr, i; 408 409 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { 410 PHY_WRITE(sc, E1000_AR, E1000_AR_10T | E1000_AR_10T_FD | 411 E1000_AR_100TX | E1000_AR_100TX_FD | 412 E1000_AR_PAUSE | E1000_AR_ASM_DIR); 413 PHY_WRITE(sc, E1000_1GCR, E1000_1GCR_1000T_FD); 414 PHY_WRITE(sc, E1000_CR, 415 E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG); 416 } 417 418 if (waitfor) { 419 /* Wait 500ms for it to complete. */ 420 for (i = 0; i < 500; i++) { 421 bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); 422 423 if (bmsr & E1000_SR_AUTO_NEG_COMPLETE) { 424 return (0); 425 } 426 DELAY(1000); 427 } 428 429 /* 430 * Don't need to worry about clearing MIIF_DOINGAUTO. 431 * If that's set, a timeout is pending, and it will 432 * clear the flag. [do it anyway] 433 */ 434 return (EIO); 435 } 436 437 /* 438 * Just let it finish asynchronously. This is for the benefit of 439 * the tick handler driving autonegotiation. Don't want 500ms 440 * delays all the time while the system is running! 441 */ 442 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { 443 sc->mii_flags |= MIIF_DOINGAUTO; 444 sc->mii_ticks = 0; 445 timeout_set(&sc->mii_phy_timo, mii_phy_auto_timeout, sc); 446 timeout_add(&sc->mii_phy_timo, hz >> 1); 447 } 448 return (EJUSTRETURN); 449 } 450