bmtphy.c revision 213229
1139749Simp/*- 299440Sbenno * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. 399440Sbenno * All rights reserved. 499440Sbenno * 599440Sbenno * This code is derived from software contributed to The NetBSD Foundation 699440Sbenno * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 799440Sbenno * NASA Ames Research Center. 899440Sbenno * 999440Sbenno * Redistribution and use in source and binary forms, with or without 1099440Sbenno * modification, are permitted provided that the following conditions 1199440Sbenno * are met: 1299440Sbenno * 1. Redistributions of source code must retain the above copyright 1399440Sbenno * notice, this list of conditions and the following disclaimer. 1499440Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1599440Sbenno * notice, this list of conditions and the following disclaimer in the 1699440Sbenno * documentation and/or other materials provided with the distribution. 1799440Sbenno * 1899440Sbenno * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 1999440Sbenno * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2099440Sbenno * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2199440Sbenno * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2299440Sbenno * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2399440Sbenno * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2499440Sbenno * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2599440Sbenno * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2699440Sbenno * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2799440Sbenno * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2899440Sbenno * POSSIBILITY OF SUCH DAMAGE. 2999440Sbenno */ 3099440Sbenno 3199440Sbenno/* 3299440Sbenno * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 3399440Sbenno * 3499440Sbenno * Redistribution and use in source and binary forms, with or without 3599440Sbenno * modification, are permitted provided that the following conditions 3699440Sbenno * are met: 3799440Sbenno * 1. Redistributions of source code must retain the above copyright 3899440Sbenno * notice, this list of conditions and the following disclaimer. 3999440Sbenno * 2. Redistributions in binary form must reproduce the above copyright 4099440Sbenno * notice, this list of conditions and the following disclaimer in the 4199440Sbenno * documentation and/or other materials provided with the distribution. 4299440Sbenno * 4399440Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4499440Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4599440Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4699440Sbenno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 4799440Sbenno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4899440Sbenno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 4999440Sbenno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5099440Sbenno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5199440Sbenno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5299440Sbenno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5399440Sbenno * 5499440Sbenno * from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp 5599440Sbenno * 5699440Sbenno */ 5799440Sbenno 58129844Smarius#include <sys/cdefs.h> 59129844Smarius__FBSDID("$FreeBSD: head/sys/dev/mii/bmtphy.c 213229 2010-09-27 20:31:03Z marius $"); 60129844Smarius 6199440Sbenno/* 6299440Sbenno * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also 6399440Sbenno * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in 6499440Sbenno * the 3c905C data sheet. 6599440Sbenno */ 6699440Sbenno 6799440Sbenno#include <sys/param.h> 6899440Sbenno#include <sys/systm.h> 6999440Sbenno#include <sys/kernel.h> 70129876Sphk#include <sys/module.h> 7199440Sbenno#include <sys/socket.h> 7299440Sbenno#include <sys/bus.h> 7399440Sbenno 7499440Sbenno#include <net/if.h> 7599440Sbenno#include <net/if_media.h> 7699440Sbenno 7799440Sbenno#include <dev/mii/mii.h> 7899440Sbenno#include <dev/mii/miivar.h> 79109514Sobrien#include "miidevs.h" 8099440Sbenno 8199440Sbenno#include <dev/mii/bmtphyreg.h> 8299440Sbenno 8399440Sbenno#include "miibus_if.h" 8499440Sbenno 8599440Sbennostatic int bmtphy_probe(device_t); 8699440Sbennostatic int bmtphy_attach(device_t); 8799440Sbenno 8899440Sbennostatic device_method_t bmtphy_methods[] = { 8999440Sbenno /* Device interface */ 9099440Sbenno DEVMETHOD(device_probe, bmtphy_probe), 9199440Sbenno DEVMETHOD(device_attach, bmtphy_attach), 9299440Sbenno DEVMETHOD(device_detach, mii_phy_detach), 9399440Sbenno DEVMETHOD(device_shutdown, bus_generic_shutdown), 9499440Sbenno 9599440Sbenno { 0, 0 } 9699440Sbenno}; 9799440Sbenno 9899440Sbennostatic devclass_t bmtphy_devclass; 9999440Sbenno 10099440Sbennostatic driver_t bmtphy_driver = { 10199440Sbenno "bmtphy", 10299440Sbenno bmtphy_methods, 10399440Sbenno sizeof(struct mii_softc) 10499440Sbenno}; 10599440Sbenno 10699440SbennoDRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0); 10799440Sbenno 10899440Sbennostatic int bmtphy_service(struct mii_softc *, struct mii_data *, int); 10999440Sbennostatic void bmtphy_status(struct mii_softc *); 11099440Sbenno 111164827Smariusstatic const struct mii_phydesc bmtphys_dp[] = { 112164827Smarius MII_PHY_DESC(BROADCOM, BCM4401), 113164827Smarius MII_PHY_DESC(BROADCOM, BCM5201), 114164827Smarius MII_PHY_DESC(BROADCOM, BCM5221), 115164827Smarius MII_PHY_END 116164827Smarius}; 117164827Smarius 118164827Smariusstatic const struct mii_phydesc bmtphys_lp[] = { 119164827Smarius MII_PHY_DESC(BROADCOM, 3C905B), 120164827Smarius MII_PHY_DESC(BROADCOM, 3C905C), 121164827Smarius MII_PHY_END 122164827Smarius}; 123164827Smarius 12499440Sbennostatic int 12599440Sbennobmtphy_probe(device_t dev) 12699440Sbenno{ 12799440Sbenno int rval; 12899440Sbenno 129164827Smarius /* Let exphy(4) take precedence for these. */ 130164827Smarius rval = mii_phy_dev_probe(dev, bmtphys_lp, BUS_PROBE_LOW_PRIORITY); 131164827Smarius if (rval <= 0) 132164827Smarius return (rval); 13399440Sbenno 134164827Smarius return (mii_phy_dev_probe(dev, bmtphys_dp, BUS_PROBE_DEFAULT)); 13599440Sbenno} 13699440Sbenno 13799440Sbennostatic int 13899440Sbennobmtphy_attach(device_t dev) 13999440Sbenno{ 14099440Sbenno struct mii_softc *sc; 14199440Sbenno struct mii_attach_args *ma; 14299440Sbenno struct mii_data *mii; 14399440Sbenno 14499440Sbenno sc = device_get_softc(dev); 14599440Sbenno ma = device_get_ivars(dev); 14699440Sbenno sc->mii_dev = device_get_parent(dev); 147213229Smarius mii = ma->mii_data; 14899440Sbenno LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 14999440Sbenno 15099440Sbenno sc->mii_inst = mii->mii_instance; 15199440Sbenno sc->mii_phy = ma->mii_phyno; 15299440Sbenno sc->mii_service = bmtphy_service; 15399440Sbenno sc->mii_pdata = mii; 15499440Sbenno 15599440Sbenno mii_phy_reset(sc); 15699440Sbenno 15799440Sbenno mii->mii_instance++; 15899440Sbenno 15999440Sbenno sc->mii_capabilities = 16099440Sbenno PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 16199440Sbenno device_printf(dev, " "); 162164703Smarius mii_phy_add_media(sc); 16399440Sbenno printf("\n"); 16499440Sbenno 16599440Sbenno MIIBUS_MEDIAINIT(sc->mii_dev); 16699440Sbenno 16799440Sbenno return (0); 16899440Sbenno} 16999440Sbenno 17099440Sbennostatic int 17199440Sbennobmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 17299440Sbenno{ 17399440Sbenno struct ifmedia_entry *ife; 17499440Sbenno int reg; 17599440Sbenno 17699440Sbenno ife = mii->mii_media.ifm_cur; 17799440Sbenno 17899440Sbenno switch (cmd) { 17999440Sbenno case MII_POLLSTAT: 18099440Sbenno /* 18199440Sbenno * If we're not polling our PHY instance, just return. 18299440Sbenno */ 18399440Sbenno if (IFM_INST(ife->ifm_media) != sc->mii_inst) 18499440Sbenno return (0); 18599440Sbenno break; 18699440Sbenno 18799440Sbenno case MII_MEDIACHG: 18899440Sbenno /* 18999440Sbenno * If the media indicates a different PHY instance, 19099440Sbenno * isolate ourselves. 19199440Sbenno */ 19299440Sbenno if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 19399440Sbenno reg = PHY_READ(sc, MII_BMCR); 19499440Sbenno PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 19599440Sbenno return (0); 19699440Sbenno } 19799440Sbenno 19899440Sbenno /* 19999440Sbenno * If the interface is not up, don't do anything. 20099440Sbenno */ 20199440Sbenno if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 20299440Sbenno break; 20399440Sbenno 20499440Sbenno mii_phy_setmedia(sc); 20599440Sbenno break; 20699440Sbenno 20799440Sbenno case MII_TICK: 20899440Sbenno /* 20999440Sbenno * If we're not currently selected, just return. 21099440Sbenno */ 21199440Sbenno if (IFM_INST(ife->ifm_media) != sc->mii_inst) 21299440Sbenno return (0); 21399440Sbenno if (mii_phy_tick(sc) == EJUSTRETURN) 21499440Sbenno return (0); 21599440Sbenno break; 21699440Sbenno } 21799440Sbenno 21899440Sbenno /* Update the media status. */ 21999440Sbenno bmtphy_status(sc); 22099440Sbenno 22199440Sbenno /* Callback if something changed. */ 22299440Sbenno mii_phy_update(sc, cmd); 22399440Sbenno 22499440Sbenno return (0); 22599440Sbenno} 22699440Sbenno 22799440Sbennostatic void 22899440Sbennobmtphy_status(struct mii_softc *sc) 22999440Sbenno{ 23099440Sbenno struct mii_data *mii; 23199440Sbenno struct ifmedia_entry *ife; 23299440Sbenno int bmsr, bmcr, aux_csr; 23399440Sbenno 23499440Sbenno mii = sc->mii_pdata; 23599440Sbenno ife = mii->mii_media.ifm_cur; 23699440Sbenno 23799440Sbenno mii->mii_media_status = IFM_AVALID; 23899440Sbenno mii->mii_media_active = IFM_ETHER; 23999440Sbenno 24099440Sbenno bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 24199440Sbenno aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); 24299440Sbenno 24399440Sbenno if (bmsr & BMSR_LINK) 24499440Sbenno mii->mii_media_status |= IFM_ACTIVE; 24599440Sbenno 24699440Sbenno bmcr = PHY_READ(sc, MII_BMCR); 24799440Sbenno if (bmcr & BMCR_ISO) { 24899440Sbenno mii->mii_media_active |= IFM_NONE; 24999440Sbenno mii->mii_media_status = 0; 25099440Sbenno return; 25199440Sbenno } 25299440Sbenno 25399440Sbenno if (bmcr & BMCR_LOOP) 25499440Sbenno mii->mii_media_active |= IFM_LOOP; 25599440Sbenno 25699440Sbenno if (bmcr & BMCR_AUTOEN) { 25799440Sbenno /* 25899440Sbenno * The media status bits are only valid if autonegotiation 25999440Sbenno * has completed (or it's disabled). 26099440Sbenno */ 26199440Sbenno if ((bmsr & BMSR_ACOMP) == 0) { 26299440Sbenno /* Erg, still trying, I guess... */ 26399440Sbenno mii->mii_media_active |= IFM_NONE; 26499440Sbenno return; 26599440Sbenno } 26699440Sbenno 26799440Sbenno if (aux_csr & AUX_CSR_SPEED) 26899440Sbenno mii->mii_media_active |= IFM_100_TX; 26999440Sbenno else 27099440Sbenno mii->mii_media_active |= IFM_10_T; 27199440Sbenno if (aux_csr & AUX_CSR_FDX) 27299440Sbenno mii->mii_media_active |= IFM_FDX; 27399440Sbenno } else 27499440Sbenno mii->mii_media_active = ife->ifm_media; 27599440Sbenno} 276