acphy.c revision 119418
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 * 3. All advertising materials mentioning features or use of this software 1872132Ssemenu * must display the following acknowledgement: 1972132Ssemenu * This product includes software developed by the NetBSD 2072132Ssemenu * Foundation, Inc. and its contributors. 2172132Ssemenu * 4. Neither the name of The NetBSD Foundation nor the names of its 2272132Ssemenu * contributors may be used to endorse or promote products derived 2372132Ssemenu * from this software without specific prior written permission. 2472132Ssemenu * 2572132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2672132Ssemenu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2772132Ssemenu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2872132Ssemenu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2972132Ssemenu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3072132Ssemenu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3172132Ssemenu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3272132Ssemenu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3372132Ssemenu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3472132Ssemenu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3572132Ssemenu * POSSIBILITY OF SUCH DAMAGE. 3672132Ssemenu */ 37119418Sobrien 38119418Sobrien#include <sys/cdefs.h> 39119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/mii/acphy.c 119418 2003-08-24 17:55:58Z obrien $"); 4072132Ssemenu 4172132Ssemenu/* 4272132Ssemenu * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 4372132Ssemenu * 4472132Ssemenu * Redistribution and use in source and binary forms, with or without 4572132Ssemenu * modification, are permitted provided that the following conditions 4672132Ssemenu * are met: 4772132Ssemenu * 1. Redistributions of source code must retain the above copyright 4872132Ssemenu * notice, this list of conditions and the following disclaimer. 4972132Ssemenu * 2. Redistributions in binary form must reproduce the above copyright 5072132Ssemenu * notice, this list of conditions and the following disclaimer in the 5172132Ssemenu * documentation and/or other materials provided with the distribution. 5272132Ssemenu * 3. All advertising materials mentioning features or use of this software 5372132Ssemenu * must display the following acknowledgement: 5472132Ssemenu * This product includes software developed by Manuel Bouyer. 5572132Ssemenu * 4. The name of the author may not be used to endorse or promote products 5672132Ssemenu * derived from this software without specific prior written permission. 5772132Ssemenu * 5872132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 5972132Ssemenu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 6072132Ssemenu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 6172132Ssemenu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 6272132Ssemenu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 6372132Ssemenu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 6472132Ssemenu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 6572132Ssemenu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 6672132Ssemenu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 6772132Ssemenu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6872132Ssemenu */ 6972132Ssemenu 7072132Ssemenu/* 7172132Ssemenu * Driver for Altima AC101 10/100 PHY 7272132Ssemenu */ 7372132Ssemenu 74113038Sobrien#include <sys/cdefs.h> 75113038Sobrien__FBSDID("$FreeBSD: head/sys/dev/mii/acphy.c 119418 2003-08-24 17:55:58Z obrien $"); 76113038Sobrien 7772132Ssemenu#include <sys/param.h> 7872132Ssemenu#include <sys/systm.h> 7972132Ssemenu#include <sys/kernel.h> 8072132Ssemenu#include <sys/socket.h> 8172132Ssemenu#include <sys/errno.h> 8272132Ssemenu#include <sys/module.h> 8372132Ssemenu#include <sys/bus.h> 8472132Ssemenu 8572132Ssemenu#include <net/if.h> 8672132Ssemenu#include <net/if_media.h> 8772132Ssemenu 8872132Ssemenu#include <dev/mii/mii.h> 8972132Ssemenu#include <dev/mii/miivar.h> 90109514Sobrien#include "miidevs.h" 9172132Ssemenu 9272132Ssemenu#include <dev/mii/acphyreg.h> 9372132Ssemenu 9472132Ssemenu#include "miibus_if.h" 9572132Ssemenu 96105135Salfredstatic int acphy_probe(device_t); 97105135Salfredstatic int acphy_attach(device_t); 9872132Ssemenu 9972132Ssemenustatic device_method_t acphy_methods[] = { 10072132Ssemenu /* device interface */ 10172132Ssemenu DEVMETHOD(device_probe, acphy_probe), 10272132Ssemenu DEVMETHOD(device_attach, acphy_attach), 10395722Sphk DEVMETHOD(device_detach, mii_phy_detach), 10472132Ssemenu DEVMETHOD(device_shutdown, bus_generic_shutdown), 10572132Ssemenu { 0, 0 } 10672132Ssemenu}; 10772132Ssemenu 10872132Ssemenustatic devclass_t acphy_devclass; 10972132Ssemenu 11072132Ssemenustatic driver_t acphy_driver = { 11172132Ssemenu "acphy", 11272132Ssemenu acphy_methods, 11372132Ssemenu sizeof(struct mii_softc) 11472132Ssemenu}; 11572132Ssemenu 11672132SsemenuDRIVER_MODULE(acphy, miibus, acphy_driver, acphy_devclass, 0, 0); 11772132Ssemenu 11892739Salfredstatic int acphy_service(struct mii_softc *, struct mii_data *, int); 11992739Salfredstatic void acphy_reset(struct mii_softc *); 12092739Salfredstatic void acphy_status(struct mii_softc *); 12172132Ssemenu 122105135Salfredstatic int 123105135Salfredacphy_probe(dev) 12472132Ssemenu device_t dev; 12572132Ssemenu{ 12672132Ssemenu struct mii_attach_args *ma; 12772132Ssemenu 12872132Ssemenu ma = device_get_ivars(dev); 12972132Ssemenu 13072132Ssemenu if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxALTIMA && 13172132Ssemenu MII_MODEL(ma->mii_id2) == MII_MODEL_xxALTIMA_AC101) { 13272132Ssemenu device_set_desc(dev, MII_STR_xxALTIMA_AC101); 133109147Sobrien } else if(MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxALTIMA && 134109147Sobrien MII_MODEL(ma->mii_id2) == MII_MODEL_xxALTIMA_AC101L) { 135109147Sobrien device_set_desc(dev, MII_STR_xxALTIMA_AC101L); 13672132Ssemenu } else 13772132Ssemenu return (ENXIO); 13872132Ssemenu 13972132Ssemenu return (0); 14072132Ssemenu} 14172132Ssemenu 142105135Salfredstatic int 143105135Salfredacphy_attach(dev) 14472132Ssemenu device_t dev; 14572132Ssemenu{ 14672132Ssemenu struct mii_softc *sc; 14772132Ssemenu struct mii_attach_args *ma; 14872132Ssemenu struct mii_data *mii; 14972132Ssemenu 15072132Ssemenu sc = device_get_softc(dev); 15172132Ssemenu ma = device_get_ivars(dev); 15272132Ssemenu sc->mii_dev = device_get_parent(dev); 15372132Ssemenu mii = device_get_softc(sc->mii_dev); 15472132Ssemenu LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 15572132Ssemenu 15672132Ssemenu sc->mii_inst = mii->mii_instance; 15772132Ssemenu sc->mii_phy = ma->mii_phyno; 15872132Ssemenu sc->mii_service = acphy_service; 15972132Ssemenu sc->mii_pdata = mii; 16072132Ssemenu sc->mii_flags |= MIIF_NOISOLATE; 16172132Ssemenu 16272132Ssemenu acphy_reset(sc); 16372132Ssemenu 16472132Ssemenu mii->mii_instance++; 16572132Ssemenu 16672132Ssemenu sc->mii_capabilities = 16772132Ssemenu PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 16872132Ssemenu device_printf(dev, " "); 16995667Sphk mii_add_media(sc); 17072132Ssemenu printf("\n"); 17172132Ssemenu 17272132Ssemenu MIIBUS_MEDIAINIT(sc->mii_dev); 17372132Ssemenu return (0); 17472132Ssemenu} 17572132Ssemenu 17684145Sjlemonstatic int 17772132Ssemenuacphy_service(sc, mii, cmd) 17872132Ssemenu struct mii_softc *sc; 17972132Ssemenu struct mii_data *mii; 18072132Ssemenu int cmd; 18172132Ssemenu{ 18272132Ssemenu struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 18372132Ssemenu int reg; 18472132Ssemenu 18595877Ssemenu /* 18695877Ssemenu * If we're not selected, then do nothing, just isolate and power 18795877Ssemenu * down, if changing media. 18895877Ssemenu */ 18995877Ssemenu if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 19095877Ssemenu if (cmd == MII_MEDIACHG) { 19195877Ssemenu reg = PHY_READ(sc, MII_BMCR); 19295877Ssemenu PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO | BMCR_PDOWN); 19395877Ssemenu } 19495877Ssemenu 19595877Ssemenu return (0); 19695877Ssemenu } 19795877Ssemenu 19872132Ssemenu switch (cmd) { 19972132Ssemenu case MII_POLLSTAT: 20072132Ssemenu break; 20172132Ssemenu 20272132Ssemenu case MII_MEDIACHG: 20372132Ssemenu /* 20472132Ssemenu * If the interface is not up, don't do anything. 20572132Ssemenu */ 20672132Ssemenu if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 20772132Ssemenu break; 20872132Ssemenu 20995877Ssemenu /* Wake & deisolate up if necessary */ 21072132Ssemenu reg = PHY_READ(sc, MII_BMCR); 21172132Ssemenu if (reg & (BMCR_ISO | BMCR_PDOWN)) 21272132Ssemenu PHY_WRITE(sc, MII_BMCR, reg & ~(BMCR_ISO | BMCR_PDOWN)); 21372132Ssemenu 21472132Ssemenu switch (IFM_SUBTYPE(ife->ifm_media)) { 21572132Ssemenu case IFM_AUTO: 21672132Ssemenu /* 21772132Ssemenu * If we're already in auto mode, just return. 21872132Ssemenu */ 21972132Ssemenu if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) 22072132Ssemenu return (0); 22172132Ssemenu 22296026Sphk (void) mii_phy_auto(sc); 22372132Ssemenu break; 22472132Ssemenu 22572132Ssemenu default: 22672132Ssemenu /* 22772132Ssemenu * BMCR data is stored in the ifmedia entry. 22872132Ssemenu */ 22972132Ssemenu PHY_WRITE(sc, MII_ANAR, 23072132Ssemenu mii_anar(ife->ifm_media)); 23172132Ssemenu PHY_WRITE(sc, MII_BMCR, ife->ifm_data); 23272132Ssemenu } 23372132Ssemenu break; 23472132Ssemenu 23572132Ssemenu case MII_TICK: 23672132Ssemenu /* 23784145Sjlemon * Is the interface even up? 23872132Ssemenu */ 23984145Sjlemon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 24072132Ssemenu return (0); 24172132Ssemenu 24272132Ssemenu /* 24384145Sjlemon * Only used for autonegotiation. 24472132Ssemenu */ 24584145Sjlemon if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 24684145Sjlemon break; 24772132Ssemenu 24872132Ssemenu /* 24995877Ssemenu * This PHY's autonegotiation doesn't need to be kicked. 25072132Ssemenu */ 25172132Ssemenu break; 25272132Ssemenu } 25372132Ssemenu 25472132Ssemenu /* Update the media status. */ 25572132Ssemenu acphy_status(sc); 25672132Ssemenu 25772132Ssemenu /* Callback if something changed. */ 25884145Sjlemon mii_phy_update(sc, cmd); 25972132Ssemenu return (0); 26072132Ssemenu} 26172132Ssemenu 26284145Sjlemonstatic void 26372132Ssemenuacphy_status(sc) 26472132Ssemenu struct mii_softc *sc; 26572132Ssemenu{ 26672132Ssemenu struct mii_data *mii = sc->mii_pdata; 26772132Ssemenu struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 26872132Ssemenu int bmsr, bmcr, diag; 26972132Ssemenu 27072132Ssemenu mii->mii_media_status = IFM_AVALID; 27172132Ssemenu mii->mii_media_active = IFM_ETHER; 27272132Ssemenu 27372132Ssemenu bmsr = PHY_READ(sc, MII_BMSR) | 27472132Ssemenu PHY_READ(sc, MII_BMSR); 27572132Ssemenu if (bmsr & BMSR_LINK) 27672132Ssemenu mii->mii_media_status |= IFM_ACTIVE; 27772132Ssemenu 27872132Ssemenu bmcr = PHY_READ(sc, MII_BMCR); 27972132Ssemenu if (bmcr & BMCR_ISO) { 28072132Ssemenu mii->mii_media_active |= IFM_NONE; 28172132Ssemenu mii->mii_media_status = 0; 28272132Ssemenu return; 28372132Ssemenu } 28472132Ssemenu 28572132Ssemenu if (bmcr & BMCR_LOOP) 28672132Ssemenu mii->mii_media_active |= IFM_LOOP; 28772132Ssemenu 28872132Ssemenu if (bmcr & BMCR_AUTOEN) { 28972132Ssemenu if ((bmsr & BMSR_ACOMP) == 0) { 29072132Ssemenu /* Erg, still trying, I guess... */ 29172132Ssemenu mii->mii_media_active |= IFM_NONE; 29272132Ssemenu return; 29372132Ssemenu } 29495877Ssemenu diag = PHY_READ(sc, MII_ACPHY_DIAG); 29572132Ssemenu if (diag & AC_DIAG_SPEED) 29672132Ssemenu mii->mii_media_active |= IFM_100_TX; 29772132Ssemenu else 29872132Ssemenu mii->mii_media_active |= IFM_10_T; 29972132Ssemenu 30072132Ssemenu if (diag & AC_DIAG_DUPLEX) 30172132Ssemenu mii->mii_media_active |= IFM_FDX; 30272132Ssemenu } else 30372132Ssemenu mii->mii_media_active = ife->ifm_media; 30472132Ssemenu} 30572132Ssemenu 30684145Sjlemonstatic void 30772132Ssemenuacphy_reset(sc) 30872132Ssemenu struct mii_softc *sc; 30972132Ssemenu{ 31072132Ssemenu 31172132Ssemenu mii_phy_reset(sc); 31272132Ssemenu PHY_WRITE(sc, MII_ACPHY_INT, 0); 31372132Ssemenu} 314