1169092Sdeischen/* $NetBSD: tlphy.c,v 1.18 1999/05/14 11:40:28 drochner Exp $ */ 2169092Sdeischen 3169092Sdeischen/*- 4156608Sdeischen * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 5156608Sdeischen * All rights reserved. 6169092Sdeischen * 7156608Sdeischen * This code is derived from software contributed to The NetBSD Foundation 8156608Sdeischen * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9156608Sdeischen * NASA Ames Research Center. 10156608Sdeischen * 11156608Sdeischen * Redistribution and use in source and binary forms, with or without 12169092Sdeischen * modification, are permitted provided that the following conditions 13156608Sdeischen * are met: 14156608Sdeischen * 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/*- 34 * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 */ 56 57#include <sys/cdefs.h> 58__FBSDID("$FreeBSD$"); 59 60/* 61 * Driver for Texas Instruments's ThunderLAN PHYs 62 */ 63 64#include <sys/param.h> 65#include <sys/systm.h> 66#include <sys/kernel.h> 67#include <sys/socket.h> 68#include <sys/errno.h> 69#include <sys/module.h> 70#include <sys/bus.h> 71#include <sys/malloc.h> 72 73#include <machine/bus.h> 74 75#include <net/if.h> 76#include <net/if_media.h> 77 78#include <dev/mii/mii.h> 79#include <dev/mii/miivar.h> 80#include "miidevs.h" 81 82#include <dev/mii/tlphyreg.h> 83 84#include "miibus_if.h" 85 86struct tlphy_softc { 87 struct mii_softc sc_mii; /* generic PHY */ 88 int sc_need_acomp; 89}; 90 91static int tlphy_probe(device_t); 92static int tlphy_attach(device_t); 93 94static device_method_t tlphy_methods[] = { 95 /* device interface */ 96 DEVMETHOD(device_probe, tlphy_probe), 97 DEVMETHOD(device_attach, tlphy_attach), 98 DEVMETHOD(device_detach, mii_phy_detach), 99 DEVMETHOD(device_shutdown, bus_generic_shutdown), 100 DEVMETHOD_END 101}; 102 103static devclass_t tlphy_devclass; 104 105static driver_t tlphy_driver = { 106 "tlphy", 107 tlphy_methods, 108 sizeof(struct tlphy_softc) 109}; 110 111DRIVER_MODULE(tlphy, miibus, tlphy_driver, tlphy_devclass, 0, 0); 112 113static int tlphy_service(struct mii_softc *, struct mii_data *, int); 114static int tlphy_auto(struct tlphy_softc *); 115static void tlphy_acomp(struct tlphy_softc *); 116static void tlphy_status(struct mii_softc *); 117 118static const struct mii_phydesc tlphys[] = { 119 MII_PHY_DESC(TI, TLAN10T), 120 MII_PHY_END 121}; 122 123static const struct mii_phy_funcs tlphy_funcs = { 124 tlphy_service, 125 tlphy_status, 126 mii_phy_reset 127}; 128 129static int 130tlphy_probe(device_t dev) 131{ 132 133 if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), 134 "tl") != 0) 135 return (ENXIO); 136 return (mii_phy_dev_probe(dev, tlphys, BUS_PROBE_DEFAULT)); 137} 138 139static int 140tlphy_attach(device_t dev) 141{ 142 device_t *devlist; 143 struct mii_softc *other, *sc_mii; 144 const char *sep = ""; 145 int capmask, devs, i; 146 147 sc_mii = device_get_softc(dev); 148 149 mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &tlphy_funcs, 0); 150 151 /* 152 * Note that if we're on a device that also supports 100baseTX, 153 * we are not going to want to use the built-in 10baseT port, 154 * since there will be another PHY on the MII wired up to the 155 * UTP connector. 156 */ 157 capmask = BMSR_DEFCAPMASK; 158 if (sc_mii->mii_inst && 159 device_get_children(sc_mii->mii_dev, &devlist, &devs) == 0) { 160 for (i = 0; i < devs; i++) { 161 if (devlist[i] != dev) { 162 other = device_get_softc(devlist[i]); 163 capmask &= ~other->mii_capabilities; 164 break; 165 } 166 } 167 free(devlist, M_TEMP); 168 } 169 170 PHY_RESET(sc_mii); 171 172 sc_mii->mii_capabilities = PHY_READ(sc_mii, MII_BMSR) & capmask; 173 174#define ADD(m, c) \ 175 ifmedia_add(&sc_mii->mii_pdata->mii_media, (m), (c), NULL) 176#define PRINT(s) printf("%s%s", sep, s); sep = ", " 177 178 if ((sc_mii->mii_flags & (MIIF_MACPRIV0 | MIIF_MACPRIV1)) != 0 && 179 (sc_mii->mii_capabilities & BMSR_MEDIAMASK) != 0) 180 device_printf(dev, " "); 181 if ((sc_mii->mii_flags & MIIF_MACPRIV0) != 0) { 182 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc_mii->mii_inst), 183 0); 184 PRINT("10base2/BNC"); 185 } 186 if ((sc_mii->mii_flags & MIIF_MACPRIV1) != 0) { 187 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc_mii->mii_inst), 188 0); 189 PRINT("10base5/AUI"); 190 } 191 if ((sc_mii->mii_capabilities & BMSR_MEDIAMASK) != 0) { 192 printf("%s", sep); 193 mii_phy_add_media(sc_mii); 194 } 195 if ((sc_mii->mii_flags & (MIIF_MACPRIV0 | MIIF_MACPRIV1)) != 0 && 196 (sc_mii->mii_capabilities & BMSR_MEDIAMASK) != 0) 197 printf("\n"); 198#undef ADD 199#undef PRINT 200 201 MIIBUS_MEDIAINIT(sc_mii->mii_dev); 202 return (0); 203} 204 205static int 206tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd) 207{ 208 struct tlphy_softc *sc = (struct tlphy_softc *)self; 209 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 210 int reg; 211 212 if (sc->sc_need_acomp) 213 tlphy_acomp(sc); 214 215 switch (cmd) { 216 case MII_POLLSTAT: 217 break; 218 219 case MII_MEDIACHG: 220 /* 221 * If the interface is not up, don't do anything. 222 */ 223 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 224 break; 225 226 switch (IFM_SUBTYPE(ife->ifm_media)) { 227 case IFM_AUTO: 228 /* 229 * The ThunderLAN PHY doesn't self-configure after 230 * an autonegotiation cycle, so there's no such 231 * thing as "already in auto mode". 232 */ 233 (void)tlphy_auto(sc); 234 break; 235 case IFM_10_2: 236 case IFM_10_5: 237 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); 238 PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL); 239 DELAY(100000); 240 break; 241 default: 242 PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0); 243 DELAY(100000); 244 mii_phy_setmedia(&sc->sc_mii); 245 } 246 break; 247 248 case MII_TICK: 249 /* 250 * Is the interface even up? 251 */ 252 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 253 return (0); 254 255 /* 256 * Only used for autonegotiation. 257 */ 258 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 259 break; 260 261 /* 262 * Check to see if we have link. If we do, we don't 263 * need to restart the autonegotiation process. Read 264 * the BMSR twice in case it's latched. 265 * 266 * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?! 267 */ 268 reg = PHY_READ(&sc->sc_mii, MII_BMSR) | 269 PHY_READ(&sc->sc_mii, MII_BMSR); 270 if (reg & BMSR_LINK) 271 break; 272 273 /* 274 * Only retry autonegotiation every 5 seconds. 275 */ 276 if (++sc->sc_mii.mii_ticks <= MII_ANEGTICKS) 277 break; 278 279 sc->sc_mii.mii_ticks = 0; 280 PHY_RESET(&sc->sc_mii); 281 (void)tlphy_auto(sc); 282 return (0); 283 } 284 285 /* Update the media status. */ 286 PHY_STATUS(self); 287 288 /* Callback if something changed. */ 289 mii_phy_update(&sc->sc_mii, cmd); 290 return (0); 291} 292 293static void 294tlphy_status(struct mii_softc *self) 295{ 296 struct tlphy_softc *sc = (struct tlphy_softc *)self; 297 struct mii_data *mii = sc->sc_mii.mii_pdata; 298 int bmsr, bmcr, tlctrl; 299 300 mii->mii_media_status = IFM_AVALID; 301 mii->mii_media_active = IFM_ETHER; 302 303 bmcr = PHY_READ(&sc->sc_mii, MII_BMCR); 304 if (bmcr & BMCR_ISO) { 305 mii->mii_media_active |= IFM_NONE; 306 mii->mii_media_status = 0; 307 return; 308 } 309 310 tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL); 311 if (tlctrl & CTRL_AUISEL) { 312 mii->mii_media_status = 0; 313 mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media; 314 return; 315 } 316 317 bmsr = PHY_READ(&sc->sc_mii, MII_BMSR) | 318 PHY_READ(&sc->sc_mii, MII_BMSR); 319 if (bmsr & BMSR_LINK) 320 mii->mii_media_status |= IFM_ACTIVE; 321 322 if (bmcr & BMCR_LOOP) 323 mii->mii_media_active |= IFM_LOOP; 324 325 /* 326 * Grr, braindead ThunderLAN PHY doesn't have any way to 327 * tell which media is actually active. (Note it also 328 * doesn't self-configure after autonegotiation.) We 329 * just have to report what's in the BMCR. 330 */ 331 if (bmcr & BMCR_FDX) 332 mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(self); 333 else 334 mii->mii_media_active |= IFM_HDX; 335 mii->mii_media_active |= IFM_10_T; 336} 337 338static int 339tlphy_auto(struct tlphy_softc *sc) 340{ 341 int error; 342 343 switch ((error = mii_phy_auto(&sc->sc_mii))) { 344 case EIO: 345 /* 346 * Just assume we're not in full-duplex mode. 347 * XXX Check link and try AUI/BNC? 348 */ 349 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); 350 break; 351 352 case EJUSTRETURN: 353 /* Flag that we need to program when it completes. */ 354 sc->sc_need_acomp = 1; 355 break; 356 357 default: 358 tlphy_acomp(sc); 359 } 360 361 return (error); 362} 363 364static void 365tlphy_acomp(struct tlphy_softc *sc) 366{ 367 int aner, anlpar; 368 369 sc->sc_need_acomp = 0; 370 371 /* 372 * Grr, braindead ThunderLAN PHY doesn't self-configure 373 * after autonegotiation. We have to do it ourselves 374 * based on the link partner status. 375 */ 376 377 aner = PHY_READ(&sc->sc_mii, MII_ANER); 378 if (aner & ANER_LPAN) { 379 anlpar = PHY_READ(&sc->sc_mii, MII_ANLPAR) & 380 PHY_READ(&sc->sc_mii, MII_ANAR); 381 if (anlpar & ANAR_10_FD) { 382 PHY_WRITE(&sc->sc_mii, MII_BMCR, BMCR_FDX); 383 return; 384 } 385 } 386 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); 387} 388