bmtphy.c revision 164827
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 * 3. All advertising materials mentioning features or use of this software 1899440Sbenno * must display the following acknowledgement: 1999440Sbenno * This product includes software developed by the NetBSD 2099440Sbenno * Foundation, Inc. and its contributors. 2199440Sbenno * 4. Neither the name of The NetBSD Foundation nor the names of its 2299440Sbenno * contributors may be used to endorse or promote products derived 2399440Sbenno * from this software without specific prior written permission. 2499440Sbenno * 2599440Sbenno * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2699440Sbenno * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2799440Sbenno * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2899440Sbenno * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2999440Sbenno * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3099440Sbenno * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3199440Sbenno * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3299440Sbenno * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3399440Sbenno * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3499440Sbenno * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3599440Sbenno * POSSIBILITY OF SUCH DAMAGE. 3699440Sbenno */ 3799440Sbenno 3899440Sbenno/* 3999440Sbenno * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 4099440Sbenno * 4199440Sbenno * Redistribution and use in source and binary forms, with or without 4299440Sbenno * modification, are permitted provided that the following conditions 4399440Sbenno * are met: 4499440Sbenno * 1. Redistributions of source code must retain the above copyright 4599440Sbenno * notice, this list of conditions and the following disclaimer. 4699440Sbenno * 2. Redistributions in binary form must reproduce the above copyright 4799440Sbenno * notice, this list of conditions and the following disclaimer in the 4899440Sbenno * documentation and/or other materials provided with the distribution. 4999440Sbenno * 3. All advertising materials mentioning features or use of this software 5099440Sbenno * must display the following acknowledgement: 5199440Sbenno * This product includes software developed by Manuel Bouyer. 5299440Sbenno * 4. The name of the author may not be used to endorse or promote products 5399440Sbenno * derived from this software without specific prior written permission. 5499440Sbenno * 5599440Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 5699440Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 5799440Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 5899440Sbenno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 5999440Sbenno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 6099440Sbenno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 6199440Sbenno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 6299440Sbenno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 6399440Sbenno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 6499440Sbenno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6599440Sbenno * 6699440Sbenno * from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp 6799440Sbenno * 6899440Sbenno */ 6999440Sbenno 70129844Smarius#include <sys/cdefs.h> 71129844Smarius__FBSDID("$FreeBSD: head/sys/dev/mii/bmtphy.c 164827 2006-12-02 15:32:34Z marius $"); 72129844Smarius 7399440Sbenno/* 7499440Sbenno * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also 7599440Sbenno * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in 7699440Sbenno * the 3c905C data sheet. 7799440Sbenno */ 7899440Sbenno 7999440Sbenno#include <sys/param.h> 8099440Sbenno#include <sys/systm.h> 8199440Sbenno#include <sys/kernel.h> 82129876Sphk#include <sys/module.h> 8399440Sbenno#include <sys/socket.h> 8499440Sbenno#include <sys/bus.h> 8599440Sbenno 8699440Sbenno#include <net/if.h> 8799440Sbenno#include <net/if_media.h> 8899440Sbenno 8999440Sbenno#include <dev/mii/mii.h> 9099440Sbenno#include <dev/mii/miivar.h> 91109514Sobrien#include "miidevs.h" 9299440Sbenno 9399440Sbenno#include <dev/mii/bmtphyreg.h> 9499440Sbenno 9599440Sbenno#include "miibus_if.h" 9699440Sbenno 9799440Sbennostatic int bmtphy_probe(device_t); 9899440Sbennostatic int bmtphy_attach(device_t); 9999440Sbenno 10099440Sbennostatic device_method_t bmtphy_methods[] = { 10199440Sbenno /* Device interface */ 10299440Sbenno DEVMETHOD(device_probe, bmtphy_probe), 10399440Sbenno DEVMETHOD(device_attach, bmtphy_attach), 10499440Sbenno DEVMETHOD(device_detach, mii_phy_detach), 10599440Sbenno DEVMETHOD(device_shutdown, bus_generic_shutdown), 10699440Sbenno 10799440Sbenno { 0, 0 } 10899440Sbenno}; 10999440Sbenno 11099440Sbennostatic devclass_t bmtphy_devclass; 11199440Sbenno 11299440Sbennostatic driver_t bmtphy_driver = { 11399440Sbenno "bmtphy", 11499440Sbenno bmtphy_methods, 11599440Sbenno sizeof(struct mii_softc) 11699440Sbenno}; 11799440Sbenno 11899440SbennoDRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0); 11999440Sbenno 12099440Sbennostatic int bmtphy_service(struct mii_softc *, struct mii_data *, int); 12199440Sbennostatic void bmtphy_status(struct mii_softc *); 12299440Sbenno 123164827Smariusstatic const struct mii_phydesc bmtphys_dp[] = { 124164827Smarius MII_PHY_DESC(BROADCOM, BCM4401), 125164827Smarius MII_PHY_DESC(BROADCOM, BCM5201), 126164827Smarius MII_PHY_DESC(BROADCOM, BCM5221), 127164827Smarius MII_PHY_END 128164827Smarius}; 129164827Smarius 130164827Smariusstatic const struct mii_phydesc bmtphys_lp[] = { 131164827Smarius MII_PHY_DESC(BROADCOM, 3C905B), 132164827Smarius MII_PHY_DESC(BROADCOM, 3C905C), 133164827Smarius MII_PHY_END 134164827Smarius}; 135164827Smarius 13699440Sbennostatic int 13799440Sbennobmtphy_probe(device_t dev) 13899440Sbenno{ 13999440Sbenno int rval; 14099440Sbenno 141164827Smarius /* Let exphy(4) take precedence for these. */ 142164827Smarius rval = mii_phy_dev_probe(dev, bmtphys_lp, BUS_PROBE_LOW_PRIORITY); 143164827Smarius if (rval <= 0) 144164827Smarius return (rval); 14599440Sbenno 146164827Smarius return (mii_phy_dev_probe(dev, bmtphys_dp, BUS_PROBE_DEFAULT)); 14799440Sbenno} 14899440Sbenno 14999440Sbennostatic int 15099440Sbennobmtphy_attach(device_t dev) 15199440Sbenno{ 15299440Sbenno struct mii_softc *sc; 15399440Sbenno struct mii_attach_args *ma; 15499440Sbenno struct mii_data *mii; 15599440Sbenno 15699440Sbenno sc = device_get_softc(dev); 15799440Sbenno ma = device_get_ivars(dev); 15899440Sbenno sc->mii_dev = device_get_parent(dev); 15999440Sbenno mii = device_get_softc(sc->mii_dev); 16099440Sbenno LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 16199440Sbenno 16299440Sbenno sc->mii_inst = mii->mii_instance; 16399440Sbenno sc->mii_phy = ma->mii_phyno; 16499440Sbenno sc->mii_service = bmtphy_service; 16599440Sbenno sc->mii_pdata = mii; 16699440Sbenno 16799440Sbenno mii_phy_reset(sc); 16899440Sbenno 16999440Sbenno mii->mii_instance++; 17099440Sbenno 17199440Sbenno sc->mii_capabilities = 17299440Sbenno PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 17399440Sbenno device_printf(dev, " "); 174164703Smarius mii_phy_add_media(sc); 17599440Sbenno printf("\n"); 17699440Sbenno 17799440Sbenno MIIBUS_MEDIAINIT(sc->mii_dev); 17899440Sbenno 17999440Sbenno return (0); 18099440Sbenno} 18199440Sbenno 18299440Sbennostatic int 18399440Sbennobmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 18499440Sbenno{ 18599440Sbenno struct ifmedia_entry *ife; 18699440Sbenno int reg; 18799440Sbenno 18899440Sbenno ife = mii->mii_media.ifm_cur; 18999440Sbenno 19099440Sbenno switch (cmd) { 19199440Sbenno case MII_POLLSTAT: 19299440Sbenno /* 19399440Sbenno * If we're not polling our PHY instance, just return. 19499440Sbenno */ 19599440Sbenno if (IFM_INST(ife->ifm_media) != sc->mii_inst) 19699440Sbenno return (0); 19799440Sbenno break; 19899440Sbenno 19999440Sbenno case MII_MEDIACHG: 20099440Sbenno /* 20199440Sbenno * If the media indicates a different PHY instance, 20299440Sbenno * isolate ourselves. 20399440Sbenno */ 20499440Sbenno if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 20599440Sbenno reg = PHY_READ(sc, MII_BMCR); 20699440Sbenno PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 20799440Sbenno return (0); 20899440Sbenno } 20999440Sbenno 21099440Sbenno /* 21199440Sbenno * If the interface is not up, don't do anything. 21299440Sbenno */ 21399440Sbenno if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 21499440Sbenno break; 21599440Sbenno 21699440Sbenno mii_phy_setmedia(sc); 21799440Sbenno break; 21899440Sbenno 21999440Sbenno case MII_TICK: 22099440Sbenno /* 22199440Sbenno * If we're not currently selected, just return. 22299440Sbenno */ 22399440Sbenno if (IFM_INST(ife->ifm_media) != sc->mii_inst) 22499440Sbenno return (0); 22599440Sbenno if (mii_phy_tick(sc) == EJUSTRETURN) 22699440Sbenno return (0); 22799440Sbenno break; 22899440Sbenno } 22999440Sbenno 23099440Sbenno /* Update the media status. */ 23199440Sbenno bmtphy_status(sc); 23299440Sbenno 23399440Sbenno /* Callback if something changed. */ 23499440Sbenno mii_phy_update(sc, cmd); 23599440Sbenno 23699440Sbenno return (0); 23799440Sbenno} 23899440Sbenno 23999440Sbennostatic void 24099440Sbennobmtphy_status(struct mii_softc *sc) 24199440Sbenno{ 24299440Sbenno struct mii_data *mii; 24399440Sbenno struct ifmedia_entry *ife; 24499440Sbenno int bmsr, bmcr, aux_csr; 24599440Sbenno 24699440Sbenno mii = sc->mii_pdata; 24799440Sbenno ife = mii->mii_media.ifm_cur; 24899440Sbenno 24999440Sbenno mii->mii_media_status = IFM_AVALID; 25099440Sbenno mii->mii_media_active = IFM_ETHER; 25199440Sbenno 25299440Sbenno bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 25399440Sbenno aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); 25499440Sbenno 25599440Sbenno if (bmsr & BMSR_LINK) 25699440Sbenno mii->mii_media_status |= IFM_ACTIVE; 25799440Sbenno 25899440Sbenno bmcr = PHY_READ(sc, MII_BMCR); 25999440Sbenno if (bmcr & BMCR_ISO) { 26099440Sbenno mii->mii_media_active |= IFM_NONE; 26199440Sbenno mii->mii_media_status = 0; 26299440Sbenno return; 26399440Sbenno } 26499440Sbenno 26599440Sbenno if (bmcr & BMCR_LOOP) 26699440Sbenno mii->mii_media_active |= IFM_LOOP; 26799440Sbenno 26899440Sbenno if (bmcr & BMCR_AUTOEN) { 26999440Sbenno /* 27099440Sbenno * The media status bits are only valid if autonegotiation 27199440Sbenno * has completed (or it's disabled). 27299440Sbenno */ 27399440Sbenno if ((bmsr & BMSR_ACOMP) == 0) { 27499440Sbenno /* Erg, still trying, I guess... */ 27599440Sbenno mii->mii_media_active |= IFM_NONE; 27699440Sbenno return; 27799440Sbenno } 27899440Sbenno 27999440Sbenno if (aux_csr & AUX_CSR_SPEED) 28099440Sbenno mii->mii_media_active |= IFM_100_TX; 28199440Sbenno else 28299440Sbenno mii->mii_media_active |= IFM_10_T; 28399440Sbenno if (aux_csr & AUX_CSR_FDX) 28499440Sbenno mii->mii_media_active |= IFM_FDX; 28599440Sbenno } else 28699440Sbenno mii->mii_media_active = ife->ifm_media; 28799440Sbenno} 288