1 /* $OpenBSD: nsgphy.c,v 1.9 2002/11/26 06:01:28 nate Exp $ */ 2 /* 3 * Copyright (c) 2001 Wind River Systems 4 * Copyright (c) 2001 5 * Bill Paul <wpaul@bsdi.com>. 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, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bill Paul. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * $FreeBSD$ 35 */ 36 37 /* 38 * Driver for the National Semiconductor DP83891 and DP83861 39 * 10/100/1000 PHYs. 40 * Datasheet available at: http://www.national.com/ds/DP/DP83861.pdf 41 * 42 * The DP83891 is the older NatSemi gigE PHY which isn't being sold 43 * anymore. The DP83861 is its replacement, which is an 'enhanced' 44 * firmware driven component. The major difference between the 45 * two is that the 83891 can't generate interrupts, while the 46 * 83861 can. (I think it wasn't originally designed to do this, but 47 * it can now thanks to firmware updates.) The 83861 also allows 48 * access to its internal RAM via indirect register access. 49 */ 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/kernel.h> 54 #include <sys/device.h> 55 #include <sys/malloc.h> 56 #include <sys/socket.h> 57 58 #include <net/if.h> 59 #include <net/if_media.h> 60 61 #include <dev/mii/mii.h> 62 #include <dev/mii/miivar.h> 63 #include <dev/mii/miidevs.h> 64 65 #include <dev/mii/nsgphyreg.h> 66 67 int nsgphymatch(struct device*, void *, void *); 68 void nsgphyattach(struct device *, struct device *, void *); 69 70 struct cfattach nsgphy_ca = { 71 sizeof(struct mii_softc), nsgphymatch, nsgphyattach, mii_phy_detach, 72 mii_phy_activate 73 }; 74 75 struct cfdriver nsgphy_cd = { 76 NULL, "nsgphy", DV_DULL 77 }; 78 79 int nsgphy_service(struct mii_softc *, struct mii_data *, int); 80 void nsgphy_status(struct mii_softc *); 81 82 static int nsgphy_mii_phy_auto(struct mii_softc *, int); 83 extern void mii_phy_auto_timeout(void *); 84 85 int 86 87 nsgphymatch(parent, match, aux) 88 struct device *parent; 89 void *match; 90 void *aux; 91 { 92 struct mii_attach_args *ma = aux; 93 94 if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_NATSEMI && 95 (MII_MODEL(ma->mii_id2) == MII_MODEL_NATSEMI_DP83891 || 96 MII_MODEL(ma->mii_id2) == MII_MODEL_NATSEMI_DP83861)) 97 return (10); 98 99 return (0); 100 } 101 102 void 103 nsgphyattach(parent, self, aux) 104 struct device *parent; 105 struct device *self; 106 void *aux; 107 { 108 struct mii_softc *sc = (struct mii_softc *)self; 109 struct mii_attach_args *ma = aux; 110 struct mii_data *mii = ma->mii_data; 111 112 switch(MII_MODEL(ma->mii_id2)) { 113 case MII_MODEL_NATSEMI_DP83861: 114 printf(": %s, rev. %d\n", MII_STR_NATSEMI_DP83861, 115 MII_REV(ma->mii_id2)); 116 break; 117 118 case MII_MODEL_NATSEMI_DP83891: 119 printf(": %s, rev. %d\n", MII_STR_NATSEMI_DP83891, 120 MII_REV(ma->mii_id2)); 121 break; 122 } 123 124 sc->mii_inst = mii->mii_instance; 125 sc->mii_phy = ma->mii_phyno; 126 sc->mii_service = nsgphy_service; 127 sc->mii_status = nsgphy_status; 128 sc->mii_pdata = mii; 129 sc->mii_flags = mii->mii_flags; 130 sc->mii_anegticks = 10; 131 132 mii_phy_reset(sc); 133 134 sc->mii_capabilities = 135 PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 136 if (sc->mii_capabilities & BMSR_EXTSTAT) 137 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 138 if ((sc->mii_capabilities & BMSR_MEDIAMASK) || 139 (sc->mii_extcapabilities & EXTSR_MEDIAMASK)) 140 mii_phy_add_media(sc); 141 142 #if 0 143 strap = PHY_READ(sc, MII_GPHYTER_STRAP); 144 printf("%s: strapped to %s mode", sc->mii_dev.dv_xname, 145 (strap & STRAP_MS_VAL) ? "master" : "slave"); 146 if (strap & STRAP_NC_MODE) 147 printf(", pre-C5 BCM5400 compat enabled"); 148 printf("\n"); 149 #endif 150 } 151 152 int 153 nsgphy_service(sc, mii, cmd) 154 struct mii_softc *sc; 155 struct mii_data *mii; 156 int cmd; 157 { 158 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 159 int reg; 160 161 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 162 return (ENXIO); 163 164 switch (cmd) { 165 case MII_POLLSTAT: 166 /* 167 * If we're not polling our PHY instance, just return. 168 */ 169 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 170 return (0); 171 break; 172 173 case MII_MEDIACHG: 174 /* 175 * If the media indicates a different PHY instance, 176 * isolate ourselves. 177 */ 178 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 179 reg = PHY_READ(sc, MII_BMCR); 180 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 181 return (0); 182 } 183 184 /* 185 * If the interface is not up, don't do anything. 186 */ 187 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 188 break; 189 190 switch (IFM_SUBTYPE(ife->ifm_media)) { 191 case IFM_AUTO: 192 (void) nsgphy_mii_phy_auto(sc, 0); 193 break; 194 case IFM_1000_T: 195 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { 196 PHY_WRITE(sc, NSGPHY_MII_BMCR, 197 NSGPHY_BMCR_FDX|NSGPHY_BMCR_SPD1); 198 } else { 199 PHY_WRITE(sc, NSGPHY_MII_BMCR, 200 NSGPHY_BMCR_SPD1); 201 } 202 PHY_WRITE(sc, NSGPHY_MII_ANAR, NSGPHY_SEL_TYPE); 203 204 /* 205 * When setting the link manually, one side must 206 * be the master and the other the slave. However 207 * ifmedia doesn't give us a good way to specify 208 * this, so we fake it by using one of the LINK 209 * flags. If LINK0 is set, we program the PHY to 210 * be a master, otherwise it's a slave. 211 */ 212 if ((mii->mii_ifp->if_flags & IFF_LINK0)) { 213 PHY_WRITE(sc, NSGPHY_MII_1000CTL, 214 NSGPHY_1000CTL_MSE|NSGPHY_1000CTL_MSC); 215 } else { 216 PHY_WRITE(sc, NSGPHY_MII_1000CTL, 217 NSGPHY_1000CTL_MSE); 218 } 219 break; 220 case IFM_100_T4: 221 /* 222 * XXX Not supported as a manual setting right now. 223 */ 224 return (EINVAL); 225 case IFM_NONE: 226 PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN); 227 break; 228 default: 229 /* 230 * BMCR data is stored in the ifmedia entry. 231 */ 232 PHY_WRITE(sc, MII_ANAR, 233 mii_anar(ife->ifm_media)); 234 PHY_WRITE(sc, MII_BMCR, ife->ifm_data); 235 break; 236 } 237 break; 238 239 case MII_TICK: 240 /* 241 * If we're not currently selected, just return. 242 */ 243 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 244 return (0); 245 246 /* 247 * Only used for autonegotiation. 248 */ 249 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 250 return (0); 251 252 /* 253 * Is the interface even up? 254 */ 255 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 256 return (0); 257 258 /* 259 * Only retry autonegotiation if we've hit the timeout. 260 */ 261 if (++sc->mii_ticks != sc->mii_anegticks) 262 return (0); 263 264 sc->mii_ticks = 0; 265 266 /* 267 * Check to see if we have link. 268 */ 269 reg = PHY_READ(sc, NSGPHY_MII_PHYSUP); 270 if (reg & NSGPHY_PHYSUP_LNKSTS) 271 break; 272 273 mii_phy_reset(sc); 274 if (nsgphy_mii_phy_auto(sc, 0) == EJUSTRETURN) 275 return(0); 276 break; 277 case MII_DOWN: 278 mii_phy_down(sc); 279 return (0); 280 } 281 282 /* Update the media status. */ 283 mii_phy_status(sc); 284 285 /* Callback if something changed. */ 286 mii_phy_update(sc, cmd); 287 return (0); 288 } 289 290 void 291 nsgphy_status(sc) 292 struct mii_softc *sc; 293 { 294 struct mii_data *mii = sc->mii_pdata; 295 int bmsr, bmcr, physup, anlpar, gstat; 296 297 mii->mii_media_status = IFM_AVALID; 298 mii->mii_media_active = IFM_ETHER; 299 300 bmsr = PHY_READ(sc, NSGPHY_MII_BMSR) | PHY_READ(sc, NSGPHY_MII_BMSR); 301 physup = PHY_READ(sc, NSGPHY_MII_PHYSUP); 302 if (physup & NSGPHY_PHYSUP_LNKSTS) 303 mii->mii_media_status |= IFM_ACTIVE; 304 305 bmcr = PHY_READ(sc, NSGPHY_MII_BMCR); 306 307 if (bmcr & NSGPHY_BMCR_LOOP) 308 mii->mii_media_active |= IFM_LOOP; 309 310 if (bmcr & NSGPHY_BMCR_AUTOEN) { 311 if ((bmsr & NSGPHY_BMSR_ACOMP) == 0) { 312 /* Erg, still trying, I guess... */ 313 mii->mii_media_active |= IFM_NONE; 314 return; 315 } 316 anlpar = PHY_READ(sc, NSGPHY_MII_ANLPAR); 317 gstat = PHY_READ(sc, NSGPHY_MII_1000STS); 318 if (gstat & NSGPHY_1000STS_LPFD) 319 mii->mii_media_active |= IFM_1000_T|IFM_FDX; 320 else if (gstat & NSGPHY_1000STS_LPHD) 321 mii->mii_media_active |= IFM_1000_T|IFM_HDX; 322 else if (anlpar & NSGPHY_ANLPAR_100T4) 323 mii->mii_media_active |= IFM_100_T4; 324 else if (anlpar & NSGPHY_ANLPAR_100FDX) 325 mii->mii_media_active |= IFM_100_TX|IFM_FDX; 326 else if (anlpar & NSGPHY_ANLPAR_100HDX) 327 mii->mii_media_active |= IFM_100_TX; 328 else if (anlpar & NSGPHY_ANLPAR_10FDX) 329 mii->mii_media_active |= IFM_10_T|IFM_FDX; 330 else if (anlpar & NSGPHY_ANLPAR_10HDX) 331 mii->mii_media_active |= IFM_10_T|IFM_HDX; 332 else 333 mii->mii_media_active |= IFM_NONE; 334 return; 335 } 336 337 switch(bmcr & (NSGPHY_BMCR_SPD1|NSGPHY_BMCR_SPD0)) { 338 case NSGPHY_S1000: 339 mii->mii_media_active |= IFM_1000_T; 340 break; 341 case NSGPHY_S100: 342 mii->mii_media_active |= IFM_100_TX; 343 break; 344 case NSGPHY_S10: 345 mii->mii_media_active |= IFM_10_T; 346 break; 347 default: 348 break; 349 } 350 351 if (bmcr & NSGPHY_BMCR_FDX) 352 mii->mii_media_active |= IFM_FDX; 353 else 354 mii->mii_media_active |= IFM_HDX; 355 356 return; 357 } 358 359 360 static int 361 nsgphy_mii_phy_auto(mii, waitfor) 362 struct mii_softc *mii; 363 int waitfor; 364 { 365 int bmsr, ktcr = 0, i; 366 367 if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) { 368 mii_phy_reset(mii); 369 PHY_WRITE(mii, NSGPHY_MII_BMCR, 0); 370 DELAY(1000); 371 ktcr = PHY_READ(mii, NSGPHY_MII_1000CTL); 372 PHY_WRITE(mii, NSGPHY_MII_1000CTL, ktcr | 373 (NSGPHY_1000CTL_AFD|NSGPHY_1000CTL_AHD)); 374 ktcr = PHY_READ(mii, NSGPHY_MII_1000CTL); 375 DELAY(1000); 376 PHY_WRITE(mii, NSGPHY_MII_ANAR, 377 BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA); 378 DELAY(1000); 379 PHY_WRITE(mii, NSGPHY_MII_BMCR, 380 NSGPHY_BMCR_AUTOEN | NSGPHY_BMCR_STARTNEG); 381 } 382 383 if (waitfor) { 384 /* Wait 500ms for it to complete. */ 385 for (i = 0; i < 500; i++) { 386 if ((bmsr = PHY_READ(mii, NSGPHY_MII_BMSR)) & 387 NSGPHY_BMSR_ACOMP) 388 return (0); 389 DELAY(1000); 390 #if 0 391 if ((bmsr & BMSR_ACOMP) == 0) 392 printf("%s: autonegotiation failed to complete\n", 393 mii->mii_dev.dv_xname); 394 #endif 395 } 396 397 /* 398 * Don't need to worry about clearing MIIF_DOINGAUTO. 399 * If that's set, a timeout is pending, and it will 400 * clear the flag. 401 */ 402 return (EIO); 403 } 404 405 /* 406 * Just let it finish asynchronously. This is for the benefit of 407 * the tick handler driving autonegotiation. Don't want 500ms 408 * delays all the time while the system is running! 409 */ 410 if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) { 411 mii->mii_flags |= MIIF_DOINGAUTO; 412 timeout_set(&mii->mii_phy_timo, mii_phy_auto_timeout, mii); 413 timeout_add(&mii->mii_phy_timo, hz >> 1); 414 } 415 return (EJUSTRETURN); 416 } 417