172132Ssemenu/* OpenBSD: lxtphy.c,v 1.5 2000/08/26 20:04:17 nate Exp */ 272132Ssemenu/* NetBSD: lxtphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp */ 372132Ssemenu 472132Ssemenu/*- 572132Ssemenu * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 672132Ssemenu * All rights reserved. 772132Ssemenu * 872132Ssemenu * This code is derived from software contributed to The NetBSD Foundation 972132Ssemenu * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 1072132Ssemenu * NASA Ames Research Center. 1172132Ssemenu * 1272132Ssemenu * Redistribution and use in source and binary forms, with or without 1372132Ssemenu * modification, are permitted provided that the following conditions 1472132Ssemenu * are met: 1572132Ssemenu * 1. Redistributions of source code must retain the above copyright 1672132Ssemenu * notice, this list of conditions and the following disclaimer. 1772132Ssemenu * 2. Redistributions in binary form must reproduce the above copyright 1872132Ssemenu * notice, this list of conditions and the following disclaimer in the 1972132Ssemenu * documentation and/or other materials provided with the distribution. 2072132Ssemenu * 2172132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2272132Ssemenu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2372132Ssemenu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2472132Ssemenu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2572132Ssemenu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2672132Ssemenu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2772132Ssemenu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2872132Ssemenu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2972132Ssemenu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3072132Ssemenu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3172132Ssemenu * POSSIBILITY OF SUCH DAMAGE. 3272132Ssemenu */ 33119418Sobrien 34139749Simp/*- 3572132Ssemenu * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 3672132Ssemenu * 3772132Ssemenu * Redistribution and use in source and binary forms, with or without 3872132Ssemenu * modification, are permitted provided that the following conditions 3972132Ssemenu * are met: 4072132Ssemenu * 1. Redistributions of source code must retain the above copyright 4172132Ssemenu * notice, this list of conditions and the following disclaimer. 4272132Ssemenu * 2. Redistributions in binary form must reproduce the above copyright 4372132Ssemenu * notice, this list of conditions and the following disclaimer in the 4472132Ssemenu * documentation and/or other materials provided with the distribution. 4572132Ssemenu * 4672132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4772132Ssemenu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4872132Ssemenu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4972132Ssemenu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 5072132Ssemenu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 5172132Ssemenu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 5272132Ssemenu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5372132Ssemenu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5472132Ssemenu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5572132Ssemenu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5672132Ssemenu */ 5772132Ssemenu 58129844Smarius#include <sys/cdefs.h> 59129844Smarius__FBSDID("$FreeBSD$"); 60129844Smarius 6172132Ssemenu/* 6272132Ssemenu * driver for Level One's LXT-970 ethernet 10/100 PHY 6372132Ssemenu * datasheet from www.level1.com 6472132Ssemenu */ 6572132Ssemenu 6672132Ssemenu#include <sys/param.h> 6772132Ssemenu#include <sys/systm.h> 6872132Ssemenu#include <sys/kernel.h> 6972132Ssemenu#include <sys/socket.h> 7072132Ssemenu#include <sys/errno.h> 7172132Ssemenu#include <sys/module.h> 7272132Ssemenu#include <sys/bus.h> 7372132Ssemenu 7472132Ssemenu#include <net/if.h> 7572132Ssemenu#include <net/if_media.h> 7672132Ssemenu 7772132Ssemenu#include <dev/mii/mii.h> 7872132Ssemenu#include <dev/mii/miivar.h> 79109514Sobrien#include "miidevs.h" 8072132Ssemenu 8172132Ssemenu#include <dev/mii/lxtphyreg.h> 8272132Ssemenu 8372132Ssemenu#include "miibus_if.h" 8472132Ssemenu 85105135Salfredstatic int lxtphy_probe(device_t); 86105135Salfredstatic int lxtphy_attach(device_t); 8772132Ssemenu 8872132Ssemenustatic device_method_t lxtphy_methods[] = { 8972132Ssemenu /* device interface */ 9072132Ssemenu DEVMETHOD(device_probe, lxtphy_probe), 9172132Ssemenu DEVMETHOD(device_attach, lxtphy_attach), 9295722Sphk DEVMETHOD(device_detach, mii_phy_detach), 9372132Ssemenu DEVMETHOD(device_shutdown, bus_generic_shutdown), 94227908Smarius DEVMETHOD_END 9572132Ssemenu}; 9672132Ssemenu 9772132Ssemenustatic devclass_t lxtphy_devclass; 9872132Ssemenu 9972132Ssemenustatic driver_t lxtphy_driver = { 10072132Ssemenu "lxtphy", 10172132Ssemenu lxtphy_methods, 10272132Ssemenu sizeof(struct mii_softc) 10372132Ssemenu}; 10472132Ssemenu 10572132SsemenuDRIVER_MODULE(lxtphy, miibus, lxtphy_driver, lxtphy_devclass, 0, 0); 10672132Ssemenu 10792739Salfredstatic int lxtphy_service(struct mii_softc *, struct mii_data *, int); 10892739Salfredstatic void lxtphy_status(struct mii_softc *); 109221407Smariusstatic void lxtphy_reset(struct mii_softc *); 11092739Salfredstatic void lxtphy_set_tp(struct mii_softc *); 11192739Salfredstatic void lxtphy_set_fx(struct mii_softc *); 11272132Ssemenu 113164827Smariusstatic const struct mii_phydesc lxtphys[] = { 114164827Smarius MII_PHY_DESC(xxLEVEL1, LXT970), 115164827Smarius MII_PHY_END 116164827Smarius}; 117164827Smarius 118221407Smariusstatic const struct mii_phy_funcs lxtphy_funcs = { 119221407Smarius lxtphy_service, 120221407Smarius lxtphy_status, 121221407Smarius lxtphy_reset 122221407Smarius}; 123221407Smarius 124105135Salfredstatic int 125150763Simplxtphy_probe(device_t dev) 12672132Ssemenu{ 12772132Ssemenu 128164827Smarius return (mii_phy_dev_probe(dev, lxtphys, BUS_PROBE_DEFAULT)); 12972132Ssemenu} 13072132Ssemenu 131105135Salfredstatic int 132150763Simplxtphy_attach(device_t dev) 13372132Ssemenu{ 13472132Ssemenu struct mii_softc *sc; 13572132Ssemenu 13672132Ssemenu sc = device_get_softc(dev); 13772132Ssemenu 138221407Smarius mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &lxtphy_funcs, 0); 13972132Ssemenu 140221407Smarius PHY_RESET(sc); 14172132Ssemenu 142221407Smarius sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; 14372132Ssemenu device_printf(dev, " "); 14472132Ssemenu 145221407Smarius#define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL) 14672132Ssemenu ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst), 147165985Smarius MII_MEDIA_100_TX); 14872132Ssemenu printf("100baseFX, "); 14972132Ssemenu ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst), 150165985Smarius MII_MEDIA_100_TX_FDX); 15172132Ssemenu printf("100baseFX-FDX, "); 15272132Ssemenu#undef ADD 15372132Ssemenu 154164706Smarius mii_phy_add_media(sc); 15572132Ssemenu printf("\n"); 15672132Ssemenu 15772132Ssemenu MIIBUS_MEDIAINIT(sc->mii_dev); 158164706Smarius return (0); 15972132Ssemenu} 16072132Ssemenu 16172132Ssemenustatic int 162150763Simplxtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 16372132Ssemenu{ 16472132Ssemenu struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 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 177164706Smarius if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_FX) 178164706Smarius lxtphy_set_fx(sc); 179164706Smarius else 18072132Ssemenu lxtphy_set_tp(sc); 18172132Ssemenu 182164706Smarius mii_phy_setmedia(sc); 18372132Ssemenu break; 18472132Ssemenu 18572132Ssemenu case MII_TICK: 18684145Sjlemon if (mii_phy_tick(sc) == EJUSTRETURN) 18772132Ssemenu return (0); 18872132Ssemenu break; 18972132Ssemenu } 19072132Ssemenu 19172132Ssemenu /* Update the media status. */ 192221407Smarius PHY_STATUS(sc); 19372132Ssemenu 19472132Ssemenu /* Callback if something changed. */ 19584145Sjlemon mii_phy_update(sc, cmd); 19672132Ssemenu return (0); 19772132Ssemenu} 19872132Ssemenu 19972132Ssemenustatic void 200150763Simplxtphy_status(struct mii_softc *sc) 20172132Ssemenu{ 20272132Ssemenu struct mii_data *mii = sc->mii_pdata; 20372132Ssemenu struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 20472132Ssemenu int bmcr, bmsr, csr; 20572132Ssemenu 20672132Ssemenu mii->mii_media_status = IFM_AVALID; 20772132Ssemenu mii->mii_media_active = IFM_ETHER; 20872132Ssemenu 20972132Ssemenu /* 21072132Ssemenu * Get link status from the CSR; we need to read the CSR 21172132Ssemenu * for media type anyhow, and the link status in the CSR 21272132Ssemenu * doens't latch, so fewer register reads are required. 21372132Ssemenu */ 21472132Ssemenu csr = PHY_READ(sc, MII_LXTPHY_CSR); 21572132Ssemenu if (csr & CSR_LINK) 21672132Ssemenu mii->mii_media_status |= IFM_ACTIVE; 21772132Ssemenu 21872132Ssemenu bmcr = PHY_READ(sc, MII_BMCR); 21972132Ssemenu if (bmcr & BMCR_ISO) { 22072132Ssemenu mii->mii_media_active |= IFM_NONE; 22172132Ssemenu mii->mii_media_status = 0; 22272132Ssemenu return; 22372132Ssemenu } 22472132Ssemenu 22572132Ssemenu if (bmcr & BMCR_LOOP) 22672132Ssemenu mii->mii_media_active |= IFM_LOOP; 22772132Ssemenu 22872132Ssemenu if (bmcr & BMCR_AUTOEN) { 22972132Ssemenu bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 23072132Ssemenu if ((bmsr & BMSR_ACOMP) == 0) { 23172132Ssemenu /* Erg, still trying, I guess... */ 23272132Ssemenu mii->mii_media_active |= IFM_NONE; 23372132Ssemenu return; 23472132Ssemenu } 23572132Ssemenu if (csr & CSR_SPEED) 23672132Ssemenu mii->mii_media_active |= IFM_100_TX; 23772132Ssemenu else 23872132Ssemenu mii->mii_media_active |= IFM_10_T; 23972132Ssemenu if (csr & CSR_DUPLEX) 240221407Smarius mii->mii_media_active |= 241221407Smarius IFM_FDX | mii_phy_flowstatus(sc); 242213384Smarius else 243213384Smarius mii->mii_media_active |= IFM_HDX; 24472132Ssemenu } else 24572132Ssemenu mii->mii_media_active = ife->ifm_media; 24672132Ssemenu} 24772132Ssemenu 24872132Ssemenustatic void 249221407Smariuslxtphy_reset(struct mii_softc *sc) 250221407Smarius{ 251221407Smarius 252221407Smarius mii_phy_reset(sc); 253221407Smarius PHY_WRITE(sc, MII_LXTPHY_IER, 254221407Smarius PHY_READ(sc, MII_LXTPHY_IER) & ~IER_INTEN); 255221407Smarius} 256221407Smarius 257221407Smariusstatic void 258150763Simplxtphy_set_tp(struct mii_softc *sc) 25972132Ssemenu{ 26072132Ssemenu int cfg; 26172132Ssemenu 26272132Ssemenu cfg = PHY_READ(sc, MII_LXTPHY_CONFIG); 26372132Ssemenu cfg &= ~CONFIG_100BASEFX; 26472132Ssemenu PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg); 26572132Ssemenu} 26672132Ssemenu 26772132Ssemenustatic void 268150763Simplxtphy_set_fx(struct mii_softc *sc) 26972132Ssemenu{ 27072132Ssemenu int cfg; 27172132Ssemenu 27272132Ssemenu cfg = PHY_READ(sc, MII_LXTPHY_CONFIG); 27372132Ssemenu cfg |= CONFIG_100BASEFX; 27472132Ssemenu PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg); 27572132Ssemenu} 276