bmtphy.c revision 213364
1115013Smarcel/*- 2160157Smarcel * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. 3121642Smarcel * All rights reserved. 4121642Smarcel * 5121642Smarcel * This code is derived from software contributed to The NetBSD Foundation 6121642Smarcel * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 7121642Smarcel * NASA Ames Research Center. 8121642Smarcel * 9121642Smarcel * Redistribution and use in source and binary forms, with or without 10121642Smarcel * modification, are permitted provided that the following conditions 11115013Smarcel * are met: 12121642Smarcel * 1. Redistributions of source code must retain the above copyright 13121642Smarcel * notice, this list of conditions and the following disclaimer. 14121642Smarcel * 2. Redistributions in binary form must reproduce the above copyright 15121642Smarcel * notice, this list of conditions and the following disclaimer in the 16121642Smarcel * documentation and/or other materials provided with the distribution. 17121642Smarcel * 18121642Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19121642Smarcel * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20121642Smarcel * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21121642Smarcel * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22121642Smarcel * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23121642Smarcel * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24121642Smarcel * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25115013Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26115013Smarcel * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27115013Smarcel * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28115013Smarcel * POSSIBILITY OF SUCH DAMAGE. 29115013Smarcel */ 30115013Smarcel 31115013Smarcel/* 32115013Smarcel * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 33115013Smarcel * 34115013Smarcel * Redistribution and use in source and binary forms, with or without 35115013Smarcel * modification, are permitted provided that the following conditions 36115013Smarcel * are met: 37115013Smarcel * 1. Redistributions of source code must retain the above copyright 38115013Smarcel * notice, this list of conditions and the following disclaimer. 39115013Smarcel * 2. Redistributions in binary form must reproduce the above copyright 40115013Smarcel * notice, this list of conditions and the following disclaimer in the 41115013Smarcel * documentation and/or other materials provided with the distribution. 42115013Smarcel * 43115013Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 44115013Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45129059Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46115013Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 47115013Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 48115013Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49115013Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50115013Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51115013Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 52115013Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53129059Smarcel * 54115013Smarcel * from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp 55115013Smarcel * 56115013Smarcel */ 57115013Smarcel 58115013Smarcel#include <sys/cdefs.h> 59115013Smarcel__FBSDID("$FreeBSD: head/sys/dev/mii/bmtphy.c 213364 2010-10-02 18:53:12Z marius $"); 60115013Smarcel 61115013Smarcel/* 62115013Smarcel * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also 63115013Smarcel * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in 64129059Smarcel * the 3c905C data sheet. 65115013Smarcel */ 66115013Smarcel 67115013Smarcel#include <sys/param.h> 68129059Smarcel#include <sys/systm.h> 69115013Smarcel#include <sys/kernel.h> 70129059Smarcel#include <sys/module.h> 71129059Smarcel#include <sys/socket.h> 72115013Smarcel#include <sys/bus.h> 73115013Smarcel 74115013Smarcel#include <net/if.h> 75115013Smarcel#include <net/if_media.h> 76115013Smarcel 77115013Smarcel#include <dev/mii/mii.h> 78115013Smarcel#include <dev/mii/miivar.h> 79115013Smarcel#include "miidevs.h" 80115013Smarcel 81115013Smarcel#include <dev/mii/bmtphyreg.h> 82115013Smarcel 83115013Smarcel#include "miibus_if.h" 84160157Smarcel 85115013Smarcelstatic int bmtphy_probe(device_t); 86115013Smarcelstatic int bmtphy_attach(device_t); 87115013Smarcel 88115013Smarcelstatic device_method_t bmtphy_methods[] = { 89115013Smarcel /* Device interface */ 90115013Smarcel DEVMETHOD(device_probe, bmtphy_probe), 91115013Smarcel DEVMETHOD(device_attach, bmtphy_attach), 92115013Smarcel DEVMETHOD(device_detach, mii_phy_detach), 93115013Smarcel DEVMETHOD(device_shutdown, bus_generic_shutdown), 94115013Smarcel 95115013Smarcel { 0, 0 } 96115013Smarcel}; 97160157Smarcel 98160157Smarcelstatic devclass_t bmtphy_devclass; 99160157Smarcel 100115013Smarcelstatic driver_t bmtphy_driver = { 101115013Smarcel "bmtphy", 102115013Smarcel bmtphy_methods, 103115013Smarcel sizeof(struct mii_softc) 104115013Smarcel}; 105115013Smarcel 106115013SmarcelDRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0); 107115013Smarcel 108115013Smarcelstatic int bmtphy_service(struct mii_softc *, struct mii_data *, int); 109115013Smarcelstatic void bmtphy_status(struct mii_softc *); 110115013Smarcel 111115013Smarcelstatic const struct mii_phydesc bmtphys_dp[] = { 112115013Smarcel MII_PHY_DESC(BROADCOM, BCM4401), 113115013Smarcel MII_PHY_DESC(BROADCOM, BCM5201), 114115013Smarcel MII_PHY_DESC(BROADCOM, BCM5221), 115115013Smarcel MII_PHY_END 116129059Smarcel}; 117115013Smarcel 118115013Smarcelstatic const struct mii_phydesc bmtphys_lp[] = { 119115013Smarcel MII_PHY_DESC(BROADCOM, 3C905B), 120115013Smarcel MII_PHY_DESC(BROADCOM, 3C905C), 121115013Smarcel MII_PHY_END 122115013Smarcel}; 123129059Smarcel 124115013Smarcelstatic int 125115013Smarcelbmtphy_probe(device_t dev) 126115013Smarcel{ 127115013Smarcel int rval; 128115013Smarcel 129115013Smarcel /* Let exphy(4) take precedence for these. */ 130115013Smarcel rval = mii_phy_dev_probe(dev, bmtphys_lp, BUS_PROBE_LOW_PRIORITY); 131115013Smarcel if (rval <= 0) 132115013Smarcel return (rval); 133115013Smarcel 134115013Smarcel return (mii_phy_dev_probe(dev, bmtphys_dp, BUS_PROBE_DEFAULT)); 135115013Smarcel} 136115013Smarcel 137160157Smarcelstatic int 138160157Smarcelbmtphy_attach(device_t dev) 139115013Smarcel{ 140115013Smarcel struct mii_softc *sc; 141129059Smarcel struct mii_attach_args *ma; 142115013Smarcel struct mii_data *mii; 143115013Smarcel 144115013Smarcel sc = device_get_softc(dev); 145115013Smarcel ma = device_get_ivars(dev); 146115013Smarcel sc->mii_dev = device_get_parent(dev); 147160157Smarcel mii = ma->mii_data; 148115013Smarcel LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 149115013Smarcel 150129059Smarcel sc->mii_inst = mii->mii_instance++; 151115013Smarcel sc->mii_phy = ma->mii_phyno; 152115013Smarcel sc->mii_service = bmtphy_service; 153115013Smarcel sc->mii_pdata = mii; 154115013Smarcel 155115013Smarcel mii_phy_reset(sc); 156115013Smarcel 157115013Smarcel sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 158115013Smarcel device_printf(dev, " "); 159129059Smarcel mii_phy_add_media(sc); 160115013Smarcel printf("\n"); 161115013Smarcel 162115013Smarcel MIIBUS_MEDIAINIT(sc->mii_dev); 163115013Smarcel 164115013Smarcel return (0); 165115013Smarcel} 166115013Smarcel 167115013Smarcelstatic int 168115013Smarcelbmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 169115013Smarcel{ 170160157Smarcel 171115013Smarcel switch (cmd) { 172160157Smarcel case MII_POLLSTAT: 173115013Smarcel break; 174115013Smarcel 175115013Smarcel case MII_MEDIACHG: 176115013Smarcel /* 177115013Smarcel * If the interface is not up, don't do anything. 178115013Smarcel */ 179115013Smarcel if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 180115013Smarcel break; 181115013Smarcel 182115013Smarcel mii_phy_setmedia(sc); 183115013Smarcel break; 184115013Smarcel 185115013Smarcel case MII_TICK: 186115013Smarcel if (mii_phy_tick(sc) == EJUSTRETURN) 187115013Smarcel return (0); 188115013Smarcel break; 189115013Smarcel } 190160157Smarcel 191115013Smarcel /* Update the media status. */ 192115013Smarcel bmtphy_status(sc); 193115013Smarcel 194115013Smarcel /* Callback if something changed. */ 195160157Smarcel mii_phy_update(sc, cmd); 196160157Smarcel 197160157Smarcel return (0); 198160157Smarcel} 199115013Smarcel 200115013Smarcelstatic void 201115013Smarcelbmtphy_status(struct mii_softc *sc) 202115013Smarcel{ 203115013Smarcel struct mii_data *mii; 204115013Smarcel struct ifmedia_entry *ife; 205115013Smarcel int bmsr, bmcr, aux_csr; 206115013Smarcel 207160157Smarcel mii = sc->mii_pdata; 208115013Smarcel ife = mii->mii_media.ifm_cur; 209160157Smarcel 210115013Smarcel mii->mii_media_status = IFM_AVALID; 211115013Smarcel mii->mii_media_active = IFM_ETHER; 212115013Smarcel 213129059Smarcel bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 214115013Smarcel aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); 215115013Smarcel 216115013Smarcel if (bmsr & BMSR_LINK) 217115013Smarcel mii->mii_media_status |= IFM_ACTIVE; 218115013Smarcel 219160157Smarcel bmcr = PHY_READ(sc, MII_BMCR); 220115013Smarcel if (bmcr & BMCR_ISO) { 221115013Smarcel mii->mii_media_active |= IFM_NONE; 222129059Smarcel mii->mii_media_status = 0; 223115013Smarcel return; 224115013Smarcel } 225115013Smarcel 226115013Smarcel if (bmcr & BMCR_LOOP) 227115013Smarcel mii->mii_media_active |= IFM_LOOP; 228115013Smarcel 229115013Smarcel if (bmcr & BMCR_AUTOEN) { 230115013Smarcel /* 231129059Smarcel * The media status bits are only valid if autonegotiation 232115013Smarcel * has completed (or it's disabled). 233115013Smarcel */ 234115013Smarcel if ((bmsr & BMSR_ACOMP) == 0) { 235115013Smarcel /* Erg, still trying, I guess... */ 236115013Smarcel mii->mii_media_active |= IFM_NONE; 237115013Smarcel return; 238115013Smarcel } 239115013Smarcel 240115013Smarcel if (aux_csr & AUX_CSR_SPEED) 241115013Smarcel mii->mii_media_active |= IFM_100_TX; 242115013Smarcel else 243115013Smarcel mii->mii_media_active |= IFM_10_T; 244115013Smarcel if (aux_csr & AUX_CSR_FDX) 245115013Smarcel mii->mii_media_active |= IFM_FDX; 246115013Smarcel } else 247115013Smarcel mii->mii_media_active = ife->ifm_media; 248115013Smarcel} 249115013Smarcel