bmtphy.c revision 213384
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 213384 2010-10-03 17:00:57Z 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 150213364Smarius 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 157213364Smarius sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 15899440Sbenno device_printf(dev, " "); 159164703Smarius mii_phy_add_media(sc); 16099440Sbenno printf("\n"); 16199440Sbenno 16299440Sbenno MIIBUS_MEDIAINIT(sc->mii_dev); 16399440Sbenno 16499440Sbenno return (0); 16599440Sbenno} 16699440Sbenno 16799440Sbennostatic int 16899440Sbennobmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 16999440Sbenno{ 17099440Sbenno 17199440Sbenno switch (cmd) { 17299440Sbenno case MII_POLLSTAT: 17399440Sbenno break; 17499440Sbenno 17599440Sbenno case MII_MEDIACHG: 17699440Sbenno /* 17799440Sbenno * If the interface is not up, don't do anything. 17899440Sbenno */ 17999440Sbenno if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 18099440Sbenno break; 18199440Sbenno 18299440Sbenno mii_phy_setmedia(sc); 18399440Sbenno break; 18499440Sbenno 18599440Sbenno case MII_TICK: 18699440Sbenno if (mii_phy_tick(sc) == EJUSTRETURN) 18799440Sbenno return (0); 18899440Sbenno break; 18999440Sbenno } 19099440Sbenno 19199440Sbenno /* Update the media status. */ 19299440Sbenno bmtphy_status(sc); 19399440Sbenno 19499440Sbenno /* Callback if something changed. */ 19599440Sbenno mii_phy_update(sc, cmd); 19699440Sbenno 19799440Sbenno return (0); 19899440Sbenno} 19999440Sbenno 20099440Sbennostatic void 20199440Sbennobmtphy_status(struct mii_softc *sc) 20299440Sbenno{ 20399440Sbenno struct mii_data *mii; 20499440Sbenno struct ifmedia_entry *ife; 20599440Sbenno int bmsr, bmcr, aux_csr; 20699440Sbenno 20799440Sbenno mii = sc->mii_pdata; 20899440Sbenno ife = mii->mii_media.ifm_cur; 20999440Sbenno 21099440Sbenno mii->mii_media_status = IFM_AVALID; 21199440Sbenno mii->mii_media_active = IFM_ETHER; 21299440Sbenno 21399440Sbenno bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 21499440Sbenno aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); 21599440Sbenno 21699440Sbenno if (bmsr & BMSR_LINK) 21799440Sbenno mii->mii_media_status |= IFM_ACTIVE; 21899440Sbenno 21999440Sbenno bmcr = PHY_READ(sc, MII_BMCR); 22099440Sbenno if (bmcr & BMCR_ISO) { 22199440Sbenno mii->mii_media_active |= IFM_NONE; 22299440Sbenno mii->mii_media_status = 0; 22399440Sbenno return; 22499440Sbenno } 22599440Sbenno 22699440Sbenno if (bmcr & BMCR_LOOP) 22799440Sbenno mii->mii_media_active |= IFM_LOOP; 22899440Sbenno 22999440Sbenno if (bmcr & BMCR_AUTOEN) { 23099440Sbenno /* 23199440Sbenno * The media status bits are only valid if autonegotiation 23299440Sbenno * has completed (or it's disabled). 23399440Sbenno */ 23499440Sbenno if ((bmsr & BMSR_ACOMP) == 0) { 23599440Sbenno /* Erg, still trying, I guess... */ 23699440Sbenno mii->mii_media_active |= IFM_NONE; 23799440Sbenno return; 23899440Sbenno } 23999440Sbenno 24099440Sbenno if (aux_csr & AUX_CSR_SPEED) 24199440Sbenno mii->mii_media_active |= IFM_100_TX; 24299440Sbenno else 24399440Sbenno mii->mii_media_active |= IFM_10_T; 24499440Sbenno if (aux_csr & AUX_CSR_FDX) 24599440Sbenno mii->mii_media_active |= IFM_FDX; 246213384Smarius else 247213384Smarius mii->mii_media_active |= IFM_HDX; 24899440Sbenno } else 24999440Sbenno mii->mii_media_active = ife->ifm_media; 25099440Sbenno} 251