19526a692SSemen Ustimenko /*- 29526a692SSemen Ustimenko * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 39526a692SSemen Ustimenko * All rights reserved. 49526a692SSemen Ustimenko * 59526a692SSemen Ustimenko * This code is derived from software contributed to The NetBSD Foundation 69526a692SSemen Ustimenko * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 79526a692SSemen Ustimenko * NASA Ames Research Center. 89526a692SSemen Ustimenko * 99526a692SSemen Ustimenko * Redistribution and use in source and binary forms, with or without 109526a692SSemen Ustimenko * modification, are permitted provided that the following conditions 119526a692SSemen Ustimenko * are met: 129526a692SSemen Ustimenko * 1. Redistributions of source code must retain the above copyright 139526a692SSemen Ustimenko * notice, this list of conditions and the following disclaimer. 149526a692SSemen Ustimenko * 2. Redistributions in binary form must reproduce the above copyright 159526a692SSemen Ustimenko * notice, this list of conditions and the following disclaimer in the 169526a692SSemen Ustimenko * documentation and/or other materials provided with the distribution. 179526a692SSemen Ustimenko * 3. All advertising materials mentioning features or use of this software 189526a692SSemen Ustimenko * must display the following acknowledgement: 199526a692SSemen Ustimenko * This product includes software developed by the NetBSD 209526a692SSemen Ustimenko * Foundation, Inc. and its contributors. 219526a692SSemen Ustimenko * 4. Neither the name of The NetBSD Foundation nor the names of its 229526a692SSemen Ustimenko * contributors may be used to endorse or promote products derived 239526a692SSemen Ustimenko * from this software without specific prior written permission. 249526a692SSemen Ustimenko * 259526a692SSemen Ustimenko * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 269526a692SSemen Ustimenko * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 279526a692SSemen Ustimenko * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 289526a692SSemen Ustimenko * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 299526a692SSemen Ustimenko * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 309526a692SSemen Ustimenko * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 319526a692SSemen Ustimenko * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 329526a692SSemen Ustimenko * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 339526a692SSemen Ustimenko * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 349526a692SSemen Ustimenko * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 359526a692SSemen Ustimenko * POSSIBILITY OF SUCH DAMAGE. 369526a692SSemen Ustimenko */ 379526a692SSemen Ustimenko 389526a692SSemen Ustimenko /* 399526a692SSemen Ustimenko * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 409526a692SSemen Ustimenko * 419526a692SSemen Ustimenko * Redistribution and use in source and binary forms, with or without 429526a692SSemen Ustimenko * modification, are permitted provided that the following conditions 439526a692SSemen Ustimenko * are met: 449526a692SSemen Ustimenko * 1. Redistributions of source code must retain the above copyright 459526a692SSemen Ustimenko * notice, this list of conditions and the following disclaimer. 469526a692SSemen Ustimenko * 2. Redistributions in binary form must reproduce the above copyright 479526a692SSemen Ustimenko * notice, this list of conditions and the following disclaimer in the 489526a692SSemen Ustimenko * documentation and/or other materials provided with the distribution. 499526a692SSemen Ustimenko * 3. All advertising materials mentioning features or use of this software 509526a692SSemen Ustimenko * must display the following acknowledgement: 519526a692SSemen Ustimenko * This product includes software developed by Manuel Bouyer. 529526a692SSemen Ustimenko * 4. The name of the author may not be used to endorse or promote products 539526a692SSemen Ustimenko * derived from this software without specific prior written permission. 549526a692SSemen Ustimenko * 559526a692SSemen Ustimenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 569526a692SSemen Ustimenko * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 579526a692SSemen Ustimenko * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 589526a692SSemen Ustimenko * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 599526a692SSemen Ustimenko * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 609526a692SSemen Ustimenko * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 619526a692SSemen Ustimenko * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 629526a692SSemen Ustimenko * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 639526a692SSemen Ustimenko * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 649526a692SSemen Ustimenko * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 659526a692SSemen Ustimenko */ 669526a692SSemen Ustimenko 679526a692SSemen Ustimenko /* 689526a692SSemen Ustimenko * Driver for Altima AC101 10/100 PHY 699526a692SSemen Ustimenko */ 709526a692SSemen Ustimenko 719526a692SSemen Ustimenko #include <sys/param.h> 729526a692SSemen Ustimenko #include <sys/systm.h> 739526a692SSemen Ustimenko #include <sys/kernel.h> 749526a692SSemen Ustimenko #include <sys/socket.h> 759526a692SSemen Ustimenko #include <sys/errno.h> 769526a692SSemen Ustimenko #include <sys/module.h> 779526a692SSemen Ustimenko #include <sys/bus.h> 789526a692SSemen Ustimenko 799526a692SSemen Ustimenko #include <net/if.h> 809526a692SSemen Ustimenko #include <net/if_media.h> 819526a692SSemen Ustimenko 829526a692SSemen Ustimenko #include <dev/mii/mii.h> 839526a692SSemen Ustimenko #include <dev/mii/miivar.h> 849526a692SSemen Ustimenko #include <dev/mii/miidevs.h> 859526a692SSemen Ustimenko 869526a692SSemen Ustimenko #include <dev/mii/acphyreg.h> 879526a692SSemen Ustimenko 889526a692SSemen Ustimenko #include "miibus_if.h" 899526a692SSemen Ustimenko 909526a692SSemen Ustimenko #if !defined(lint) 919526a692SSemen Ustimenko static const char rcsid[] = 929526a692SSemen Ustimenko "$FreeBSD$"; 939526a692SSemen Ustimenko #endif 949526a692SSemen Ustimenko 95e51a25f8SAlfred Perlstein static int acphy_probe (device_t); 96e51a25f8SAlfred Perlstein static int acphy_attach (device_t); 97e51a25f8SAlfred Perlstein static int acphy_detach (device_t); 989526a692SSemen Ustimenko 999526a692SSemen Ustimenko static device_method_t acphy_methods[] = { 1009526a692SSemen Ustimenko /* device interface */ 1019526a692SSemen Ustimenko DEVMETHOD(device_probe, acphy_probe), 1029526a692SSemen Ustimenko DEVMETHOD(device_attach, acphy_attach), 1039526a692SSemen Ustimenko DEVMETHOD(device_detach, acphy_detach), 1049526a692SSemen Ustimenko DEVMETHOD(device_shutdown, bus_generic_shutdown), 1059526a692SSemen Ustimenko { 0, 0 } 1069526a692SSemen Ustimenko }; 1079526a692SSemen Ustimenko 1089526a692SSemen Ustimenko static devclass_t acphy_devclass; 1099526a692SSemen Ustimenko 1109526a692SSemen Ustimenko static driver_t acphy_driver = { 1119526a692SSemen Ustimenko "acphy", 1129526a692SSemen Ustimenko acphy_methods, 1139526a692SSemen Ustimenko sizeof(struct mii_softc) 1149526a692SSemen Ustimenko }; 1159526a692SSemen Ustimenko 1169526a692SSemen Ustimenko DRIVER_MODULE(acphy, miibus, acphy_driver, acphy_devclass, 0, 0); 1179526a692SSemen Ustimenko 118e51a25f8SAlfred Perlstein static int acphy_service(struct mii_softc *, struct mii_data *, int); 119e51a25f8SAlfred Perlstein static void acphy_reset(struct mii_softc *); 120e51a25f8SAlfred Perlstein static void acphy_status(struct mii_softc *); 1219526a692SSemen Ustimenko 1229526a692SSemen Ustimenko static int acphy_probe(dev) 1239526a692SSemen Ustimenko device_t dev; 1249526a692SSemen Ustimenko { 1259526a692SSemen Ustimenko struct mii_attach_args *ma; 1269526a692SSemen Ustimenko 1279526a692SSemen Ustimenko ma = device_get_ivars(dev); 1289526a692SSemen Ustimenko 1299526a692SSemen Ustimenko if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxALTIMA && 1309526a692SSemen Ustimenko MII_MODEL(ma->mii_id2) == MII_MODEL_xxALTIMA_AC101) { 1319526a692SSemen Ustimenko device_set_desc(dev, MII_STR_xxALTIMA_AC101); 1329526a692SSemen Ustimenko } else 1339526a692SSemen Ustimenko return (ENXIO); 1349526a692SSemen Ustimenko 1359526a692SSemen Ustimenko return (0); 1369526a692SSemen Ustimenko } 1379526a692SSemen Ustimenko 1389526a692SSemen Ustimenko static int acphy_attach(dev) 1399526a692SSemen Ustimenko device_t dev; 1409526a692SSemen Ustimenko { 1419526a692SSemen Ustimenko struct mii_softc *sc; 1429526a692SSemen Ustimenko struct mii_attach_args *ma; 1439526a692SSemen Ustimenko struct mii_data *mii; 1449526a692SSemen Ustimenko 1459526a692SSemen Ustimenko sc = device_get_softc(dev); 1469526a692SSemen Ustimenko ma = device_get_ivars(dev); 1479526a692SSemen Ustimenko sc->mii_dev = device_get_parent(dev); 1489526a692SSemen Ustimenko mii = device_get_softc(sc->mii_dev); 1499526a692SSemen Ustimenko LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 1509526a692SSemen Ustimenko 1519526a692SSemen Ustimenko sc->mii_inst = mii->mii_instance; 1529526a692SSemen Ustimenko sc->mii_phy = ma->mii_phyno; 1539526a692SSemen Ustimenko sc->mii_service = acphy_service; 1549526a692SSemen Ustimenko sc->mii_pdata = mii; 1559526a692SSemen Ustimenko sc->mii_flags |= MIIF_NOISOLATE; 1569526a692SSemen Ustimenko 1579526a692SSemen Ustimenko acphy_reset(sc); 1589526a692SSemen Ustimenko 1599526a692SSemen Ustimenko mii->mii_instance++; 1609526a692SSemen Ustimenko 1619526a692SSemen Ustimenko sc->mii_capabilities = 1629526a692SSemen Ustimenko PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 1639526a692SSemen Ustimenko device_printf(dev, " "); 1649526a692SSemen Ustimenko if (sc->mii_capabilities & BMSR_MEDIAMASK) 1659526a692SSemen Ustimenko mii_add_media(mii, sc->mii_capabilities, 1669526a692SSemen Ustimenko sc->mii_inst); 1679526a692SSemen Ustimenko printf("\n"); 1689526a692SSemen Ustimenko 1699526a692SSemen Ustimenko MIIBUS_MEDIAINIT(sc->mii_dev); 1709526a692SSemen Ustimenko return (0); 1719526a692SSemen Ustimenko } 1729526a692SSemen Ustimenko 1739526a692SSemen Ustimenko static int acphy_detach(dev) 1749526a692SSemen Ustimenko device_t dev; 1759526a692SSemen Ustimenko { 1769526a692SSemen Ustimenko struct mii_softc *sc; 1779526a692SSemen Ustimenko struct mii_data *mii; 1789526a692SSemen Ustimenko 1799526a692SSemen Ustimenko sc = device_get_softc(dev); 1809526a692SSemen Ustimenko mii = device_get_softc(device_get_parent(dev)); 1819526a692SSemen Ustimenko sc->mii_dev = NULL; 1829526a692SSemen Ustimenko LIST_REMOVE(sc, mii_list); 1839526a692SSemen Ustimenko 1849526a692SSemen Ustimenko return(0); 1859526a692SSemen Ustimenko } 1869526a692SSemen Ustimenko 187d9730b8bSJonathan Lemon static int 1889526a692SSemen Ustimenko acphy_service(sc, mii, cmd) 1899526a692SSemen Ustimenko struct mii_softc *sc; 1909526a692SSemen Ustimenko struct mii_data *mii; 1919526a692SSemen Ustimenko int cmd; 1929526a692SSemen Ustimenko { 1939526a692SSemen Ustimenko struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 1949526a692SSemen Ustimenko int reg; 1959526a692SSemen Ustimenko 1969526a692SSemen Ustimenko switch (cmd) { 1979526a692SSemen Ustimenko case MII_POLLSTAT: 1989526a692SSemen Ustimenko /* 1999526a692SSemen Ustimenko * If we're not polling our PHY instance, just return. 2009526a692SSemen Ustimenko */ 2019526a692SSemen Ustimenko if (IFM_INST(ife->ifm_media) != sc->mii_inst) 2029526a692SSemen Ustimenko return (0); 2039526a692SSemen Ustimenko break; 2049526a692SSemen Ustimenko 2059526a692SSemen Ustimenko case MII_MEDIACHG: 2069526a692SSemen Ustimenko /* 2079526a692SSemen Ustimenko * If the media indicates a different PHY instance, 2089526a692SSemen Ustimenko * isolate ourselves. 2099526a692SSemen Ustimenko */ 2109526a692SSemen Ustimenko if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 2119526a692SSemen Ustimenko reg = PHY_READ(sc, MII_BMCR); 2129526a692SSemen Ustimenko PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO | BMCR_PDOWN); 2139526a692SSemen Ustimenko return (0); 2149526a692SSemen Ustimenko } 2159526a692SSemen Ustimenko 2169526a692SSemen Ustimenko /* 2179526a692SSemen Ustimenko * If the interface is not up, don't do anything. 2189526a692SSemen Ustimenko */ 2199526a692SSemen Ustimenko if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 2209526a692SSemen Ustimenko break; 2219526a692SSemen Ustimenko 2229526a692SSemen Ustimenko /* Wake & deisolate up is needed */ 2239526a692SSemen Ustimenko reg = PHY_READ(sc, MII_BMCR); 2249526a692SSemen Ustimenko if (reg & (BMCR_ISO | BMCR_PDOWN)) 2259526a692SSemen Ustimenko PHY_WRITE(sc, MII_BMCR, reg & ~(BMCR_ISO | BMCR_PDOWN)); 2269526a692SSemen Ustimenko 2279526a692SSemen Ustimenko switch (IFM_SUBTYPE(ife->ifm_media)) { 2289526a692SSemen Ustimenko case IFM_AUTO: 2299526a692SSemen Ustimenko /* 2309526a692SSemen Ustimenko * If we're already in auto mode, just return. 2319526a692SSemen Ustimenko */ 2329526a692SSemen Ustimenko if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) 2339526a692SSemen Ustimenko return (0); 2349526a692SSemen Ustimenko 2359526a692SSemen Ustimenko (void) mii_phy_auto(sc, 1); 2369526a692SSemen Ustimenko break; 2379526a692SSemen Ustimenko 2389526a692SSemen Ustimenko default: 2399526a692SSemen Ustimenko /* 2409526a692SSemen Ustimenko * BMCR data is stored in the ifmedia entry. 2419526a692SSemen Ustimenko */ 2429526a692SSemen Ustimenko PHY_WRITE(sc, MII_ANAR, 2439526a692SSemen Ustimenko mii_anar(ife->ifm_media)); 2449526a692SSemen Ustimenko PHY_WRITE(sc, MII_BMCR, ife->ifm_data); 2459526a692SSemen Ustimenko } 2469526a692SSemen Ustimenko break; 2479526a692SSemen Ustimenko 2489526a692SSemen Ustimenko case MII_TICK: 2499526a692SSemen Ustimenko /* 2509526a692SSemen Ustimenko * If we're not currently selected, just return. 2519526a692SSemen Ustimenko */ 2529526a692SSemen Ustimenko if (IFM_INST(ife->ifm_media) != sc->mii_inst) 2539526a692SSemen Ustimenko return (0); 2549526a692SSemen Ustimenko 2559526a692SSemen Ustimenko /* 2569526a692SSemen Ustimenko * Is the interface even up? 2579526a692SSemen Ustimenko */ 2589526a692SSemen Ustimenko if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 2599526a692SSemen Ustimenko return (0); 2609526a692SSemen Ustimenko 2619526a692SSemen Ustimenko /* 262d9730b8bSJonathan Lemon * Only used for autonegotiation. 2639526a692SSemen Ustimenko */ 264d9730b8bSJonathan Lemon if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 265d9730b8bSJonathan Lemon break; 266d9730b8bSJonathan Lemon 267d9730b8bSJonathan Lemon /* 268d9730b8bSJonathan Lemon * check for link. 269d9730b8bSJonathan Lemon * Read the status register twice; BMSR_LINK is latch-low. 270d9730b8bSJonathan Lemon */ 271d9730b8bSJonathan Lemon reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 2729526a692SSemen Ustimenko if (reg & BMSR_LINK) 273d9730b8bSJonathan Lemon break; 2749526a692SSemen Ustimenko 2759526a692SSemen Ustimenko /* 2769526a692SSemen Ustimenko * Only retry autonegotiation every 5 seconds. 2779526a692SSemen Ustimenko */ 2789526a692SSemen Ustimenko if (++sc->mii_ticks != 5) 2799526a692SSemen Ustimenko return (0); 2809526a692SSemen Ustimenko 2819526a692SSemen Ustimenko sc->mii_ticks = 0; 2829526a692SSemen Ustimenko acphy_reset(sc); 2839526a692SSemen Ustimenko if (mii_phy_auto(sc, 0) == EJUSTRETURN) 2849526a692SSemen Ustimenko return (0); 2859526a692SSemen Ustimenko break; 2869526a692SSemen Ustimenko } 2879526a692SSemen Ustimenko 2889526a692SSemen Ustimenko /* Update the media status. */ 2899526a692SSemen Ustimenko acphy_status(sc); 2909526a692SSemen Ustimenko 2919526a692SSemen Ustimenko /* Callback if something changed. */ 292d9730b8bSJonathan Lemon mii_phy_update(sc, cmd); 2939526a692SSemen Ustimenko return (0); 2949526a692SSemen Ustimenko } 2959526a692SSemen Ustimenko 296d9730b8bSJonathan Lemon static void 2979526a692SSemen Ustimenko acphy_status(sc) 2989526a692SSemen Ustimenko struct mii_softc *sc; 2999526a692SSemen Ustimenko { 3009526a692SSemen Ustimenko struct mii_data *mii = sc->mii_pdata; 3019526a692SSemen Ustimenko struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 3029526a692SSemen Ustimenko int bmsr, bmcr, diag; 3039526a692SSemen Ustimenko 3049526a692SSemen Ustimenko mii->mii_media_status = IFM_AVALID; 3059526a692SSemen Ustimenko mii->mii_media_active = IFM_ETHER; 3069526a692SSemen Ustimenko 3079526a692SSemen Ustimenko bmsr = PHY_READ(sc, MII_BMSR) | 3089526a692SSemen Ustimenko PHY_READ(sc, MII_BMSR); 3099526a692SSemen Ustimenko if (bmsr & BMSR_LINK) 3109526a692SSemen Ustimenko mii->mii_media_status |= IFM_ACTIVE; 3119526a692SSemen Ustimenko 3129526a692SSemen Ustimenko bmcr = PHY_READ(sc, MII_BMCR); 3139526a692SSemen Ustimenko if (bmcr & BMCR_ISO) { 3149526a692SSemen Ustimenko mii->mii_media_active |= IFM_NONE; 3159526a692SSemen Ustimenko mii->mii_media_status = 0; 3169526a692SSemen Ustimenko return; 3179526a692SSemen Ustimenko } 3189526a692SSemen Ustimenko 3199526a692SSemen Ustimenko if (bmcr & BMCR_LOOP) 3209526a692SSemen Ustimenko mii->mii_media_active |= IFM_LOOP; 3219526a692SSemen Ustimenko 3229526a692SSemen Ustimenko if (bmcr & BMCR_AUTOEN) { 3239526a692SSemen Ustimenko if ((bmsr & BMSR_ACOMP) == 0) { 3249526a692SSemen Ustimenko /* Erg, still trying, I guess... */ 3259526a692SSemen Ustimenko mii->mii_media_active |= IFM_NONE; 3269526a692SSemen Ustimenko return; 3279526a692SSemen Ustimenko } 3289526a692SSemen Ustimenko diag = PHY_READ(sc, MII_ACPHY_DIAG) | 3299526a692SSemen Ustimenko PHY_READ(sc, MII_ACPHY_DIAG); 3309526a692SSemen Ustimenko if (diag & AC_DIAG_SPEED) 3319526a692SSemen Ustimenko mii->mii_media_active |= IFM_100_TX; 3329526a692SSemen Ustimenko else 3339526a692SSemen Ustimenko mii->mii_media_active |= IFM_10_T; 3349526a692SSemen Ustimenko 3359526a692SSemen Ustimenko if (diag & AC_DIAG_DUPLEX) 3369526a692SSemen Ustimenko mii->mii_media_active |= IFM_FDX; 3379526a692SSemen Ustimenko } else 3389526a692SSemen Ustimenko mii->mii_media_active = ife->ifm_media; 3399526a692SSemen Ustimenko } 3409526a692SSemen Ustimenko 341d9730b8bSJonathan Lemon static void 3429526a692SSemen Ustimenko acphy_reset(sc) 3439526a692SSemen Ustimenko struct mii_softc *sc; 3449526a692SSemen Ustimenko { 3459526a692SSemen Ustimenko 3469526a692SSemen Ustimenko mii_phy_reset(sc); 3479526a692SSemen Ustimenko PHY_WRITE(sc, MII_ACPHY_INT, 0); 3489526a692SSemen Ustimenko } 349