bmtphy.c revision 164703
1110130Sjake/*- 2110130Sjake * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. 3144328Sjoerg * All rights reserved. 4110130Sjake * 5110130Sjake * This code is derived from software contributed to The NetBSD Foundation 6110130Sjake * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 7110130Sjake * NASA Ames Research Center. 8110130Sjake * 9110130Sjake * Redistribution and use in source and binary forms, with or without 10110130Sjake * modification, are permitted provided that the following conditions 11110130Sjake * are met: 12110130Sjake * 1. Redistributions of source code must retain the above copyright 13110130Sjake * notice, this list of conditions and the following disclaimer. 14110130Sjake * 2. Redistributions in binary form must reproduce the above copyright 15110130Sjake * notice, this list of conditions and the following disclaimer in the 16110130Sjake * documentation and/or other materials provided with the distribution. 17110130Sjake * 3. All advertising materials mentioning features or use of this software 18110130Sjake * must display the following acknowledgement: 19110130Sjake * This product includes software developed by the NetBSD 20110130Sjake * Foundation, Inc. and its contributors. 21110130Sjake * 4. Neither the name of The NetBSD Foundation nor the names of its 22110130Sjake * contributors may be used to endorse or promote products derived 23110130Sjake * from this software without specific prior written permission. 24110130Sjake * 25110130Sjake * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26110130Sjake * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27110130Sjake * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28110130Sjake * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29110130Sjake * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30110130Sjake * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31110130Sjake * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32110130Sjake * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33110130Sjake * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34110130Sjake * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35110130Sjake * POSSIBILITY OF SUCH DAMAGE. 36110130Sjake */ 37110130Sjake 38110130Sjake/* 39110130Sjake * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 40110130Sjake * 41110130Sjake * Redistribution and use in source and binary forms, with or without 42110130Sjake * modification, are permitted provided that the following conditions 43110130Sjake * are met: 44110130Sjake * 1. Redistributions of source code must retain the above copyright 45110130Sjake * notice, this list of conditions and the following disclaimer. 46110130Sjake * 2. Redistributions in binary form must reproduce the above copyright 47110130Sjake * notice, this list of conditions and the following disclaimer in the 48110130Sjake * documentation and/or other materials provided with the distribution. 49110130Sjake * 3. All advertising materials mentioning features or use of this software 50110130Sjake * must display the following acknowledgement: 51110130Sjake * This product includes software developed by Manuel Bouyer. 52110130Sjake * 4. The name of the author may not be used to endorse or promote products 53110130Sjake * derived from this software without specific prior written permission. 54110130Sjake * 55110130Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 56110130Sjake * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 57110130Sjake * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 58110130Sjake * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 59110130Sjake * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 60110130Sjake * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 61110130Sjake * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 62110130Sjake * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 63110130Sjake * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 64110130Sjake * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 65110130Sjake * 66110130Sjake * from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp 67110130Sjake * 68110130Sjake */ 69110130Sjake 70110130Sjake#include <sys/cdefs.h> 71110130Sjake__FBSDID("$FreeBSD: head/sys/dev/mii/bmtphy.c 164703 2006-11-27 23:50:19Z marius $"); 72110130Sjake 73110130Sjake/* 74113538Sjake * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also 75113538Sjake * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in 76110130Sjake * the 3c905C data sheet. 77110130Sjake */ 78110130Sjake 79128916Sjoerg#include <sys/param.h> 80110130Sjake#include <sys/systm.h> 81110130Sjake#include <sys/kernel.h> 82110130Sjake#include <sys/module.h> 83113896Sphk#include <sys/socket.h> 84110130Sjake#include <sys/bus.h> 85110130Sjake 86110130Sjake#include <net/if.h> 87110130Sjake#include <net/if_media.h> 88110130Sjake 89110130Sjake#include <dev/mii/mii.h> 90110130Sjake#include <dev/mii/miivar.h> 91110130Sjake#include "miidevs.h" 92110130Sjake 93110130Sjake#include <dev/mii/bmtphyreg.h> 94110130Sjake 95129965Sjoerg#include "miibus_if.h" 96110130Sjake 97129965Sjoergstatic int bmtphy_probe(device_t); 98110130Sjakestatic int bmtphy_attach(device_t); 99110130Sjake 100110130Sjakestatic device_method_t bmtphy_methods[] = { 101110130Sjake /* Device interface */ 102129965Sjoerg DEVMETHOD(device_probe, bmtphy_probe), 103129965Sjoerg DEVMETHOD(device_attach, bmtphy_attach), 104129965Sjoerg DEVMETHOD(device_detach, mii_phy_detach), 105129965Sjoerg DEVMETHOD(device_shutdown, bus_generic_shutdown), 106129965Sjoerg 107129965Sjoerg { 0, 0 } 108129965Sjoerg}; 109129965Sjoerg 110110130Sjakestatic devclass_t bmtphy_devclass; 111110130Sjake 112110130Sjakestatic driver_t bmtphy_driver = { 113110130Sjake "bmtphy", 114129965Sjoerg bmtphy_methods, 115110130Sjake sizeof(struct mii_softc) 116110130Sjake}; 117110130Sjake 118110130SjakeDRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0); 119110130Sjake 120110130Sjakestatic int bmtphy_service(struct mii_softc *, struct mii_data *, int); 121110130Sjakestatic void bmtphy_status(struct mii_softc *); 122129965Sjoerg 123129965Sjoergstatic int 124129965Sjoergbmtphy_probe(device_t dev) 125129965Sjoerg{ 126129965Sjoerg struct mii_attach_args *ma; 127129965Sjoerg int rval; 128129965Sjoerg 129129965Sjoerg ma = device_get_ivars(dev); 130110130Sjake rval = BUS_PROBE_DEFAULT; 131110130Sjake 132110130Sjake if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM) 133110130Sjake return (ENXIO); 134129965Sjoerg 135129965Sjoerg switch (MII_MODEL(ma->mii_id2)) { 136129965Sjoerg case MII_MODEL_BROADCOM_3C905B: 137129965Sjoerg device_set_desc(dev, MII_STR_BROADCOM_3C905B); 138129965Sjoerg rval = BUS_PROBE_LOW_PRIORITY; /* Let exphy take precedence. */ 139129965Sjoerg break; 140129965Sjoerg case MII_MODEL_BROADCOM_3C905C: 141129965Sjoerg device_set_desc(dev, MII_STR_BROADCOM_3C905C); 142129965Sjoerg rval = BUS_PROBE_LOW_PRIORITY; /* Let exphy take precedence. */ 143129965Sjoerg break; 144129965Sjoerg case MII_MODEL_BROADCOM_BCM5201: 145129965Sjoerg device_set_desc(dev, MII_STR_BROADCOM_BCM5201); 146129965Sjoerg break; 147129965Sjoerg case MII_MODEL_BROADCOM_BCM5221: 148129965Sjoerg device_set_desc(dev, MII_STR_BROADCOM_BCM5221); 149129965Sjoerg break; 150129965Sjoerg case MII_MODEL_BROADCOM_BCM4401: 151129965Sjoerg device_set_desc(dev, MII_STR_BROADCOM_BCM4401); 152129965Sjoerg break; 153129965Sjoerg default: 154129965Sjoerg return (ENXIO); 155129965Sjoerg } 156129965Sjoerg 157110130Sjake return (rval); 158110130Sjake} 159110130Sjake 160110130Sjakestatic int 161110130Sjakebmtphy_attach(device_t dev) 162110130Sjake{ 163110130Sjake struct mii_softc *sc; 164110130Sjake struct mii_attach_args *ma; 165110130Sjake struct mii_data *mii; 166110130Sjake 167110130Sjake sc = device_get_softc(dev); 168110130Sjake ma = device_get_ivars(dev); 169110130Sjake sc->mii_dev = device_get_parent(dev); 170129965Sjoerg mii = device_get_softc(sc->mii_dev); 171110130Sjake LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 172110130Sjake 173110130Sjake sc->mii_inst = mii->mii_instance; 174110130Sjake sc->mii_phy = ma->mii_phyno; 175110130Sjake sc->mii_service = bmtphy_service; 176110130Sjake sc->mii_pdata = mii; 177110130Sjake 178110130Sjake mii_phy_reset(sc); 179129965Sjoerg 180129965Sjoerg mii->mii_instance++; 181129965Sjoerg 182110130Sjake sc->mii_capabilities = 183110130Sjake PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 184110130Sjake device_printf(dev, " "); 185129965Sjoerg mii_phy_add_media(sc); 186129965Sjoerg printf("\n"); 187129965Sjoerg 188110130Sjake MIIBUS_MEDIAINIT(sc->mii_dev); 189110130Sjake 190110130Sjake return (0); 191110130Sjake} 192113896Sphk 193110130Sjakestatic int 194110130Sjakebmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 195110130Sjake{ 196110130Sjake struct ifmedia_entry *ife; 197110130Sjake int reg; 198110130Sjake 199110130Sjake ife = mii->mii_media.ifm_cur; 200110130Sjake 201110130Sjake switch (cmd) { 202110130Sjake case MII_POLLSTAT: 203110130Sjake /* 204110130Sjake * If we're not polling our PHY instance, just return. 205110130Sjake */ 206110130Sjake if (IFM_INST(ife->ifm_media) != sc->mii_inst) 207110130Sjake return (0); 208110130Sjake break; 209110130Sjake 210129965Sjoerg case MII_MEDIACHG: 211129965Sjoerg /* 212110130Sjake * If the media indicates a different PHY instance, 213110130Sjake * isolate ourselves. 214110130Sjake */ 215110130Sjake if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 216110130Sjake reg = PHY_READ(sc, MII_BMCR); 217110130Sjake PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 218110130Sjake return (0); 219110130Sjake } 220110130Sjake 221110130Sjake /* 222110130Sjake * If the interface is not up, don't do anything. 223113824Sphk */ 224113824Sphk if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 225110130Sjake break; 226110130Sjake 227110130Sjake mii_phy_setmedia(sc); 228110130Sjake break; 229110130Sjake 230110130Sjake case MII_TICK: 231110130Sjake /* 232110130Sjake * If we're not currently selected, just return. 233129965Sjoerg */ 234110130Sjake if (IFM_INST(ife->ifm_media) != sc->mii_inst) 235110130Sjake return (0); 236110130Sjake if (mii_phy_tick(sc) == EJUSTRETURN) 237110130Sjake return (0); 238110130Sjake break; 239113538Sjake } 240113538Sjake 241110130Sjake /* Update the media status. */ 242110130Sjake bmtphy_status(sc); 243110130Sjake 244110130Sjake /* Callback if something changed. */ 245110130Sjake mii_phy_update(sc, cmd); 246110130Sjake 247110130Sjake return (0); 248110130Sjake} 249110130Sjake 250110130Sjakestatic void 251110130Sjakebmtphy_status(struct mii_softc *sc) 252110130Sjake{ 253110130Sjake struct mii_data *mii; 254110130Sjake struct ifmedia_entry *ife; 255110130Sjake int bmsr, bmcr, aux_csr; 256110130Sjake 257110130Sjake mii = sc->mii_pdata; 258110130Sjake ife = mii->mii_media.ifm_cur; 259110130Sjake 260110130Sjake mii->mii_media_status = IFM_AVALID; 261110130Sjake mii->mii_media_active = IFM_ETHER; 262110130Sjake 263110130Sjake bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 264129965Sjoerg aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); 265129965Sjoerg 266110130Sjake if (bmsr & BMSR_LINK) 267110130Sjake mii->mii_media_status |= IFM_ACTIVE; 268110130Sjake 269129965Sjoerg bmcr = PHY_READ(sc, MII_BMCR); 270129965Sjoerg if (bmcr & BMCR_ISO) { 271110130Sjake mii->mii_media_active |= IFM_NONE; 272113824Sphk mii->mii_media_status = 0; 273113824Sphk return; 274113538Sjake } 275113538Sjake 276113538Sjake if (bmcr & BMCR_LOOP) 277113538Sjake mii->mii_media_active |= IFM_LOOP; 278129965Sjoerg 279129965Sjoerg if (bmcr & BMCR_AUTOEN) { 280129965Sjoerg /* 281129965Sjoerg * The media status bits are only valid if autonegotiation 282113824Sphk * has completed (or it's disabled). 283110130Sjake */ 284110130Sjake if ((bmsr & BMSR_ACOMP) == 0) { 285110130Sjake /* Erg, still trying, I guess... */ 286110130Sjake mii->mii_media_active |= IFM_NONE; 287110130Sjake return; 288110130Sjake } 289110130Sjake 290110130Sjake if (aux_csr & AUX_CSR_SPEED) 291110130Sjake mii->mii_media_active |= IFM_100_TX; 292110130Sjake else 293129965Sjoerg mii->mii_media_active |= IFM_10_T; 294129965Sjoerg if (aux_csr & AUX_CSR_FDX) 295129965Sjoerg mii->mii_media_active |= IFM_FDX; 296130692Sjoerg } else 297129965Sjoerg mii->mii_media_active = ife->ifm_media; 298129965Sjoerg} 299129965Sjoerg