1 /* $NetBSD: tlphy.c,v 1.18 1999/05/14 11:40:28 drochner Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE 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 * $FreeBSD: src/sys/dev/mii/tlphy.c,v 1.2.2.2 2001/07/29 22:48:37 kris Exp $ 40 * $DragonFly: src/sys/dev/netif/mii_layer/tlphy.c,v 1.5 2004/09/18 19:32:59 dillon Exp $ 41 */ 42 43 /* 44 * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. All advertising materials mentioning features or use of this software 55 * must display the following acknowledgement: 56 * This product includes software developed by Manuel Bouyer. 57 * 4. The name of the author may not be used to endorse or promote products 58 * derived from this software without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 61 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 62 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 63 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 64 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 65 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 66 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 67 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 68 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 69 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 70 */ 71 72 /* 73 * Driver for Texas Instruments's ThunderLAN PHYs 74 */ 75 76 #include <sys/param.h> 77 #include <sys/systm.h> 78 #include <sys/kernel.h> 79 #include <sys/socket.h> 80 #include <sys/errno.h> 81 #include <sys/module.h> 82 #include <sys/bus.h> 83 #include <sys/malloc.h> 84 85 #include <machine/bus.h> 86 #include <machine/clock.h> 87 88 #include <net/if.h> 89 #include <net/if_media.h> 90 91 #include "mii.h" 92 #include "miivar.h" 93 #include "miidevs.h" 94 95 #include "tlphyreg.h" 96 97 #include "miibus_if.h" 98 99 struct tlphy_softc { 100 struct mii_softc sc_mii; /* generic PHY */ 101 int sc_need_acomp; 102 }; 103 104 static int tlphy_probe (device_t); 105 static int tlphy_attach (device_t); 106 static int tlphy_detach (device_t); 107 108 static device_method_t tlphy_methods[] = { 109 /* device interface */ 110 DEVMETHOD(device_probe, tlphy_probe), 111 DEVMETHOD(device_attach, tlphy_attach), 112 DEVMETHOD(device_detach, tlphy_detach), 113 DEVMETHOD(device_shutdown, bus_generic_shutdown), 114 { 0, 0 } 115 }; 116 117 static devclass_t tlphy_devclass; 118 119 static driver_t tlphy_driver = { 120 "tlphy", 121 tlphy_methods, 122 sizeof(struct tlphy_softc) 123 }; 124 125 DRIVER_MODULE(tlphy, miibus, tlphy_driver, tlphy_devclass, 0, 0); 126 127 int tlphy_service (struct mii_softc *, struct mii_data *, int); 128 int tlphy_auto (struct tlphy_softc *, int); 129 void tlphy_acomp (struct tlphy_softc *); 130 void tlphy_status (struct tlphy_softc *); 131 132 static int tlphy_probe(dev) 133 device_t dev; 134 { 135 struct mii_attach_args *ma; 136 137 ma = device_get_ivars(dev); 138 139 if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_xxTI || 140 MII_MODEL(ma->mii_id2) != MII_MODEL_xxTI_TLAN10T) 141 return (ENXIO); 142 143 device_set_desc(dev, MII_STR_xxTI_TLAN10T); 144 145 return (0); 146 } 147 148 static int tlphy_attach(dev) 149 device_t dev; 150 { 151 struct tlphy_softc *sc; 152 struct mii_attach_args *ma; 153 struct mii_data *mii; 154 const char *sep = ""; 155 int capmask = 0xFFFFFFFF; 156 157 sc = device_get_softc(dev); 158 ma = device_get_ivars(dev); 159 mii_softc_init(&sc->sc_mii); 160 sc->sc_mii.mii_dev = device_get_parent(dev); 161 mii = device_get_softc(sc->sc_mii.mii_dev); 162 LIST_INSERT_HEAD(&mii->mii_phys, &sc->sc_mii, mii_list); 163 164 sc->sc_mii.mii_inst = mii->mii_instance; 165 sc->sc_mii.mii_phy = ma->mii_phyno; 166 sc->sc_mii.mii_service = tlphy_service; 167 sc->sc_mii.mii_pdata = mii; 168 169 if (mii->mii_instance) { 170 struct mii_softc *other; 171 device_t *devlist; 172 int devs, i; 173 174 device_get_children(sc->sc_mii.mii_dev, &devlist, &devs); 175 for (i = 0; i < devs; i++) { 176 if (strcmp(device_get_name(devlist[i]), "tlphy")) { 177 other = device_get_softc(devlist[i]); 178 capmask &= ~other->mii_capabilities; 179 break; 180 } 181 } 182 free(devlist, M_TEMP); 183 } 184 185 mii->mii_instance++; 186 187 sc->sc_mii.mii_flags &= ~MIIF_NOISOLATE; 188 mii_phy_reset(&sc->sc_mii); 189 sc->sc_mii.mii_flags |= MIIF_NOISOLATE; 190 191 /* 192 * Note that if we're on a device that also supports 100baseTX, 193 * we are not going to want to use the built-in 10baseT port, 194 * since there will be another PHY on the MII wired up to the 195 * UTP connector. The parent indicates this to us by specifying 196 * the TLPHY_MEDIA_NO_10_T bit. 197 */ 198 sc->sc_mii.mii_capabilities = 199 PHY_READ(&sc->sc_mii, MII_BMSR) & capmask /*ma->mii_capmask*/; 200 201 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 202 203 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->sc_mii.mii_inst), 204 BMCR_ISO); 205 206 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_LOOP, 207 sc->sc_mii.mii_inst), BMCR_LOOP); 208 209 #define PRINT(s) printf("%s%s", sep, s); sep = ", " 210 211 device_printf(dev, " "); 212 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc->sc_mii.mii_inst), 0); 213 PRINT("10base2/BNC"); 214 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc->sc_mii.mii_inst), 0); 215 PRINT("10base5/AUI"); 216 217 if (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) { 218 printf("%s", sep); 219 mii_add_media(mii, sc->sc_mii.mii_capabilities, 220 sc->sc_mii.mii_inst); 221 } 222 223 printf("\n"); 224 #undef ADD 225 #undef PRINT 226 MIIBUS_MEDIAINIT(sc->sc_mii.mii_dev); 227 return(0); 228 } 229 230 static int tlphy_detach(dev) 231 device_t dev; 232 { 233 struct tlphy_softc *sc; 234 struct mii_data *mii; 235 236 sc = device_get_softc(dev); 237 mii = device_get_softc(device_get_parent(dev)); 238 sc->sc_mii.mii_dev = NULL; 239 LIST_REMOVE(&sc->sc_mii, mii_list); 240 241 return(0); 242 } 243 244 int 245 tlphy_service(self, mii, cmd) 246 struct mii_softc *self; 247 struct mii_data *mii; 248 int cmd; 249 { 250 struct tlphy_softc *sc = (struct tlphy_softc *)self; 251 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 252 int reg; 253 254 if ((sc->sc_mii.mii_flags & MIIF_DOINGAUTO) == 0 && sc->sc_need_acomp) 255 tlphy_acomp(sc); 256 257 switch (cmd) { 258 case MII_POLLSTAT: 259 /* 260 * If we're not polling our PHY instance, just return. 261 */ 262 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) 263 return (0); 264 break; 265 266 case MII_MEDIACHG: 267 /* 268 * If the media indicates a different PHY instance, 269 * isolate ourselves. 270 */ 271 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) { 272 reg = PHY_READ(&sc->sc_mii, MII_BMCR); 273 PHY_WRITE(&sc->sc_mii, MII_BMCR, reg | BMCR_ISO); 274 return (0); 275 } 276 277 /* 278 * If the interface is not up, don't do anything. 279 */ 280 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 281 break; 282 283 switch (IFM_SUBTYPE(ife->ifm_media)) { 284 case IFM_AUTO: 285 /* 286 * The ThunderLAN PHY doesn't self-configure after 287 * an autonegotiation cycle, so there's no such 288 * thing as "already in auto mode". 289 */ 290 (void) tlphy_auto(sc, 1); 291 break; 292 case IFM_10_2: 293 case IFM_10_5: 294 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); 295 PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL); 296 DELAY(100000); 297 break; 298 default: 299 PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0); 300 DELAY(100000); 301 PHY_WRITE(&sc->sc_mii, MII_ANAR, 302 mii_anar(ife->ifm_media)); 303 PHY_WRITE(&sc->sc_mii, MII_BMCR, ife->ifm_data); 304 } 305 break; 306 307 case MII_TICK: 308 /* 309 * If we're not currently selected, just return. 310 */ 311 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) 312 return (0); 313 314 /* 315 * Only used for autonegotiation. 316 */ 317 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 318 return (0); 319 320 /* 321 * Is the interface even up? 322 */ 323 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 324 return (0); 325 326 /* 327 * Check to see if we have link. If we do, we don't 328 * need to restart the autonegotiation process. Read 329 * the BMSR twice in case it's latched. 330 * 331 * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?! 332 */ 333 reg = PHY_READ(&sc->sc_mii, MII_BMSR) | 334 PHY_READ(&sc->sc_mii, MII_BMSR); 335 if (reg & BMSR_LINK) 336 return (0); 337 338 /* 339 * Only retry autonegotiation every 5 seconds. 340 */ 341 if (++sc->sc_mii.mii_ticks != 5) 342 return (0); 343 344 sc->sc_mii.mii_ticks = 0; 345 mii_phy_reset(&sc->sc_mii); 346 if (tlphy_auto(sc, 0) == EJUSTRETURN) 347 return (0); 348 break; 349 } 350 351 /* Update the media status. */ 352 tlphy_status(sc); 353 354 /* Callback if something changed. */ 355 if (sc->sc_mii.mii_active != mii->mii_media_active || 356 cmd == MII_MEDIACHG) { 357 MIIBUS_STATCHG(sc->sc_mii.mii_dev); 358 sc->sc_mii.mii_active = mii->mii_media_active; 359 } 360 return (0); 361 } 362 363 void 364 tlphy_status(sc) 365 struct tlphy_softc *sc; 366 { 367 struct mii_data *mii = sc->sc_mii.mii_pdata; 368 int bmsr, bmcr, tlctrl; 369 370 mii->mii_media_status = IFM_AVALID; 371 mii->mii_media_active = IFM_ETHER; 372 373 bmcr = PHY_READ(&sc->sc_mii, MII_BMCR); 374 if (bmcr & BMCR_ISO) { 375 mii->mii_media_active |= IFM_NONE; 376 mii->mii_media_status = 0; 377 return; 378 } 379 380 tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL); 381 if (tlctrl & CTRL_AUISEL) { 382 mii->mii_media_status = 0; 383 mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media; 384 return; 385 } 386 387 bmsr = PHY_READ(&sc->sc_mii, MII_BMSR) | 388 PHY_READ(&sc->sc_mii, MII_BMSR); 389 if (bmsr & BMSR_LINK) 390 mii->mii_media_status |= IFM_ACTIVE; 391 392 if (bmcr & BMCR_LOOP) 393 mii->mii_media_active |= IFM_LOOP; 394 395 /* 396 * Grr, braindead ThunderLAN PHY doesn't have any way to 397 * tell which media is actually active. (Note it also 398 * doesn't self-configure after autonegotiation.) We 399 * just have to report what's in the BMCR. 400 */ 401 if (bmcr & BMCR_FDX) 402 mii->mii_media_active |= IFM_FDX; 403 mii->mii_media_active |= IFM_10_T; 404 } 405 406 int 407 tlphy_auto(sc, waitfor) 408 struct tlphy_softc *sc; 409 int waitfor; 410 { 411 int error; 412 413 switch ((error = mii_phy_auto(&sc->sc_mii, waitfor))) { 414 case EIO: 415 /* 416 * Just assume we're not in full-duplex mode. 417 * XXX Check link and try AUI/BNC? 418 */ 419 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); 420 break; 421 422 case EJUSTRETURN: 423 /* Flag that we need to program when it completes. */ 424 sc->sc_need_acomp = 1; 425 break; 426 427 default: 428 tlphy_acomp(sc); 429 } 430 431 return (error); 432 } 433 434 void 435 tlphy_acomp(sc) 436 struct tlphy_softc *sc; 437 { 438 int aner, anlpar; 439 440 sc->sc_need_acomp = 0; 441 442 /* 443 * Grr, braindead ThunderLAN PHY doesn't self-configure 444 * after autonegotiation. We have to do it ourselves 445 * based on the link partner status. 446 */ 447 448 aner = PHY_READ(&sc->sc_mii, MII_ANER); 449 if (aner & ANER_LPAN) { 450 anlpar = PHY_READ(&sc->sc_mii, MII_ANLPAR) & 451 PHY_READ(&sc->sc_mii, MII_ANAR); 452 if (anlpar & ANAR_10_FD) { 453 PHY_WRITE(&sc->sc_mii, MII_BMCR, BMCR_FDX); 454 return; 455 } 456 } 457 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); 458 } 459