172132Ssemenu/*- 272132Ssemenu * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 372132Ssemenu * All rights reserved. 472132Ssemenu * 572132Ssemenu * This code is derived from software contributed to The NetBSD Foundation 672132Ssemenu * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 772132Ssemenu * NASA Ames Research Center. 872132Ssemenu * 972132Ssemenu * Redistribution and use in source and binary forms, with or without 1072132Ssemenu * modification, are permitted provided that the following conditions 1172132Ssemenu * are met: 1272132Ssemenu * 1. Redistributions of source code must retain the above copyright 1372132Ssemenu * notice, this list of conditions and the following disclaimer. 1472132Ssemenu * 2. Redistributions in binary form must reproduce the above copyright 1572132Ssemenu * notice, this list of conditions and the following disclaimer in the 1672132Ssemenu * documentation and/or other materials provided with the distribution. 1772132Ssemenu * 1872132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 1972132Ssemenu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2072132Ssemenu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2172132Ssemenu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2272132Ssemenu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2372132Ssemenu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2472132Ssemenu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2572132Ssemenu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2672132Ssemenu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2772132Ssemenu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2872132Ssemenu * POSSIBILITY OF SUCH DAMAGE. 2972132Ssemenu */ 30119418Sobrien 31139749Simp/*- 3272132Ssemenu * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 3372132Ssemenu * 3472132Ssemenu * Redistribution and use in source and binary forms, with or without 3572132Ssemenu * modification, are permitted provided that the following conditions 3672132Ssemenu * are met: 3772132Ssemenu * 1. Redistributions of source code must retain the above copyright 3872132Ssemenu * notice, this list of conditions and the following disclaimer. 3972132Ssemenu * 2. Redistributions in binary form must reproduce the above copyright 4072132Ssemenu * notice, this list of conditions and the following disclaimer in the 4172132Ssemenu * documentation and/or other materials provided with the distribution. 4272132Ssemenu * 4372132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4472132Ssemenu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4572132Ssemenu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4672132Ssemenu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 4772132Ssemenu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4872132Ssemenu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 4972132Ssemenu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5072132Ssemenu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5172132Ssemenu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5272132Ssemenu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5372132Ssemenu */ 5472132Ssemenu 55129844Smarius#include <sys/cdefs.h> 56129844Smarius__FBSDID("$FreeBSD$"); 57129844Smarius 5872132Ssemenu/* 5972132Ssemenu * Driver for Altima AC101 10/100 PHY 6072132Ssemenu */ 6172132Ssemenu 6272132Ssemenu#include <sys/param.h> 6372132Ssemenu#include <sys/systm.h> 6472132Ssemenu#include <sys/kernel.h> 6572132Ssemenu#include <sys/socket.h> 6672132Ssemenu#include <sys/errno.h> 6772132Ssemenu#include <sys/module.h> 6872132Ssemenu#include <sys/bus.h> 6972132Ssemenu 7072132Ssemenu#include <net/if.h> 7172132Ssemenu#include <net/if_media.h> 7272132Ssemenu 7372132Ssemenu#include <dev/mii/mii.h> 7472132Ssemenu#include <dev/mii/miivar.h> 75109514Sobrien#include "miidevs.h" 7672132Ssemenu 7772132Ssemenu#include <dev/mii/acphyreg.h> 7872132Ssemenu 7972132Ssemenu#include "miibus_if.h" 8072132Ssemenu 81105135Salfredstatic int acphy_probe(device_t); 82105135Salfredstatic int acphy_attach(device_t); 8372132Ssemenu 8472132Ssemenustatic device_method_t acphy_methods[] = { 8572132Ssemenu /* device interface */ 8672132Ssemenu DEVMETHOD(device_probe, acphy_probe), 8772132Ssemenu DEVMETHOD(device_attach, acphy_attach), 8895722Sphk DEVMETHOD(device_detach, mii_phy_detach), 8972132Ssemenu DEVMETHOD(device_shutdown, bus_generic_shutdown), 90227908Smarius DEVMETHOD_END 9172132Ssemenu}; 9272132Ssemenu 9372132Ssemenustatic devclass_t acphy_devclass; 9472132Ssemenu 9572132Ssemenustatic driver_t acphy_driver = { 9672132Ssemenu "acphy", 9772132Ssemenu acphy_methods, 9872132Ssemenu sizeof(struct mii_softc) 9972132Ssemenu}; 10072132Ssemenu 10172132SsemenuDRIVER_MODULE(acphy, miibus, acphy_driver, acphy_devclass, 0, 0); 10272132Ssemenu 10392739Salfredstatic int acphy_service(struct mii_softc *, struct mii_data *, int); 10492739Salfredstatic void acphy_reset(struct mii_softc *); 10592739Salfredstatic void acphy_status(struct mii_softc *); 10672132Ssemenu 107164827Smariusstatic const struct mii_phydesc acphys[] = { 108221407Smarius MII_PHY_DESC(ALTIMA, AC101), 109221407Smarius MII_PHY_DESC(ALTIMA, AC101L), 110164834Smarius /* XXX This is reported to work, but it's not from any data sheet. */ 111221407Smarius MII_PHY_DESC(ALTIMA, ACXXX), 112164827Smarius MII_PHY_END 113164827Smarius}; 114164827Smarius 115221407Smariusstatic const struct mii_phy_funcs acphy_funcs = { 116221407Smarius acphy_service, 117221407Smarius acphy_status, 118221407Smarius acphy_reset 119221407Smarius}; 120221407Smarius 121105135Salfredstatic int 122150763Simpacphy_probe(device_t dev) 12372132Ssemenu{ 12472132Ssemenu 125164827Smarius return (mii_phy_dev_probe(dev, acphys, BUS_PROBE_DEFAULT)); 12672132Ssemenu} 12772132Ssemenu 128105135Salfredstatic int 129150763Simpacphy_attach(device_t dev) 13072132Ssemenu{ 13172132Ssemenu struct mii_softc *sc; 13272132Ssemenu 13372132Ssemenu sc = device_get_softc(dev); 13472132Ssemenu 135221407Smarius mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &acphy_funcs, 0); 13672132Ssemenu 137221407Smarius PHY_RESET(sc); 13872132Ssemenu 139221407Smarius sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; 14072132Ssemenu device_printf(dev, " "); 141165987Smarius 142221407Smarius#define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL) 143165987Smarius if ((PHY_READ(sc, MII_ACPHY_MCTL) & AC_MCTL_FX_SEL) != 0) { 144165987Smarius sc->mii_flags |= MIIF_HAVEFIBER; 145165987Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst), 146165987Smarius MII_MEDIA_100_TX); 147165987Smarius printf("100baseFX, "); 148165987Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst), 149165987Smarius MII_MEDIA_100_TX_FDX); 150165987Smarius printf("100baseFX-FDX, "); 151165987Smarius } 152165987Smarius#undef ADD 153165987Smarius 154164834Smarius mii_phy_add_media(sc); 15572132Ssemenu printf("\n"); 15672132Ssemenu 15772132Ssemenu MIIBUS_MEDIAINIT(sc->mii_dev); 15872132Ssemenu return (0); 15972132Ssemenu} 16072132Ssemenu 16184145Sjlemonstatic int 162150763Simpacphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 16372132Ssemenu{ 16472132Ssemenu int reg; 16572132Ssemenu 16672132Ssemenu switch (cmd) { 16772132Ssemenu case MII_POLLSTAT: 16872132Ssemenu break; 16972132Ssemenu 17072132Ssemenu case MII_MEDIACHG: 17172132Ssemenu /* 17272132Ssemenu * If the interface is not up, don't do anything. 17372132Ssemenu */ 17472132Ssemenu if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 17572132Ssemenu break; 17672132Ssemenu 17795877Ssemenu /* Wake & deisolate up if necessary */ 17872132Ssemenu reg = PHY_READ(sc, MII_BMCR); 179164834Smarius if (reg & (BMCR_ISO | BMCR_PDOWN)) 18072132Ssemenu PHY_WRITE(sc, MII_BMCR, reg & ~(BMCR_ISO | BMCR_PDOWN)); 18172132Ssemenu 182164834Smarius mii_phy_setmedia(sc); 18372132Ssemenu break; 18472132Ssemenu 18572132Ssemenu case MII_TICK: 18672132Ssemenu /* 18784145Sjlemon * Is the interface even up? 18872132Ssemenu */ 18984145Sjlemon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 19072132Ssemenu return (0); 19172132Ssemenu 19272132Ssemenu /* 19395877Ssemenu * This PHY's autonegotiation doesn't need to be kicked. 19472132Ssemenu */ 19572132Ssemenu break; 19672132Ssemenu } 19772132Ssemenu 19872132Ssemenu /* Update the media status. */ 199221407Smarius PHY_STATUS(sc); 20072132Ssemenu 20172132Ssemenu /* Callback if something changed. */ 20284145Sjlemon mii_phy_update(sc, cmd); 20372132Ssemenu return (0); 20472132Ssemenu} 20572132Ssemenu 20684145Sjlemonstatic void 207150763Simpacphy_status(struct mii_softc *sc) 20872132Ssemenu{ 20972132Ssemenu struct mii_data *mii = sc->mii_pdata; 21072132Ssemenu struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 21172132Ssemenu int bmsr, bmcr, diag; 21272132Ssemenu 21372132Ssemenu mii->mii_media_status = IFM_AVALID; 21472132Ssemenu mii->mii_media_active = IFM_ETHER; 21572132Ssemenu 21672132Ssemenu bmsr = PHY_READ(sc, MII_BMSR) | 21772132Ssemenu PHY_READ(sc, MII_BMSR); 21872132Ssemenu if (bmsr & BMSR_LINK) 21972132Ssemenu mii->mii_media_status |= IFM_ACTIVE; 22072132Ssemenu 22172132Ssemenu bmcr = PHY_READ(sc, MII_BMCR); 22272132Ssemenu if (bmcr & BMCR_ISO) { 22372132Ssemenu mii->mii_media_active |= IFM_NONE; 22472132Ssemenu mii->mii_media_status = 0; 22572132Ssemenu return; 22672132Ssemenu } 22772132Ssemenu 22872132Ssemenu if (bmcr & BMCR_LOOP) 22972132Ssemenu mii->mii_media_active |= IFM_LOOP; 23072132Ssemenu 23172132Ssemenu if (bmcr & BMCR_AUTOEN) { 23272132Ssemenu if ((bmsr & BMSR_ACOMP) == 0) { 23372132Ssemenu /* Erg, still trying, I guess... */ 23472132Ssemenu mii->mii_media_active |= IFM_NONE; 23572132Ssemenu return; 23672132Ssemenu } 23795877Ssemenu diag = PHY_READ(sc, MII_ACPHY_DIAG); 23872132Ssemenu if (diag & AC_DIAG_SPEED) 23972132Ssemenu mii->mii_media_active |= IFM_100_TX; 24072132Ssemenu else 24172132Ssemenu mii->mii_media_active |= IFM_10_T; 24272132Ssemenu 24372132Ssemenu if (diag & AC_DIAG_DUPLEX) 244221407Smarius mii->mii_media_active |= 245221407Smarius IFM_FDX | mii_phy_flowstatus(sc); 246213384Smarius else 247213384Smarius mii->mii_media_active |= IFM_HDX; 24872132Ssemenu } else 24972132Ssemenu mii->mii_media_active = ife->ifm_media; 25072132Ssemenu} 25172132Ssemenu 25284145Sjlemonstatic void 253150763Simpacphy_reset(struct mii_softc *sc) 25472132Ssemenu{ 25572132Ssemenu 25672132Ssemenu mii_phy_reset(sc); 25772132Ssemenu PHY_WRITE(sc, MII_ACPHY_INT, 0); 25872132Ssemenu} 259