bmtphy.c revision 129876
1235783Skib/* 2235783Skib * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. 3235783Skib * All rights reserved. 4235783Skib * 5235783Skib * This code is derived from software contributed to The NetBSD Foundation 6235783Skib * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 7235783Skib * NASA Ames Research Center. 8235783Skib * 9235783Skib * Redistribution and use in source and binary forms, with or without 10235783Skib * modification, are permitted provided that the following conditions 11235783Skib * are met: 12235783Skib * 1. Redistributions of source code must retain the above copyright 13235783Skib * notice, this list of conditions and the following disclaimer. 14235783Skib * 2. Redistributions in binary form must reproduce the above copyright 15235783Skib * notice, this list of conditions and the following disclaimer in the 16235783Skib * documentation and/or other materials provided with the distribution. 17235783Skib * 3. All advertising materials mentioning features or use of this software 18235783Skib * must display the following acknowledgement: 19235783Skib * This product includes software developed by the NetBSD 20235783Skib * Foundation, Inc. and its contributors. 21235783Skib * 4. Neither the name of The NetBSD Foundation nor the names of its 22235783Skib * contributors may be used to endorse or promote products derived 23235783Skib * from this software without specific prior written permission. 24235783Skib * 25235783Skib * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26235783Skib * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27235783Skib * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28235783Skib * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29235783Skib * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30235783Skib * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31235783Skib * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32235783Skib * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33235783Skib * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34235783Skib * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35235783Skib * POSSIBILITY OF SUCH DAMAGE. 36235783Skib */ 37235783Skib 38235783Skib/* 39235783Skib * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 40235783Skib * 41235783Skib * Redistribution and use in source and binary forms, with or without 42235783Skib * modification, are permitted provided that the following conditions 43235783Skib * are met: 44235783Skib * 1. Redistributions of source code must retain the above copyright 45235783Skib * notice, this list of conditions and the following disclaimer. 46235783Skib * 2. Redistributions in binary form must reproduce the above copyright 47235783Skib * notice, this list of conditions and the following disclaimer in the 48235783Skib * documentation and/or other materials provided with the distribution. 49235783Skib * 3. All advertising materials mentioning features or use of this software 50235783Skib * must display the following acknowledgement: 51235783Skib * This product includes software developed by Manuel Bouyer. 52235783Skib * 4. The name of the author may not be used to endorse or promote products 53235783Skib * derived from this software without specific prior written permission. 54235783Skib * 55235783Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 56235783Skib * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 57235783Skib * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 58235783Skib * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 59235783Skib * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 60235783Skib * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 61235783Skib * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 62235783Skib * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 63235783Skib * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 64235783Skib * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 65235783Skib * 66235783Skib * from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp 67235783Skib * 68235783Skib */ 69235783Skib 70235783Skib#include <sys/cdefs.h> 71235783Skib__FBSDID("$FreeBSD: head/sys/dev/mii/bmtphy.c 129876 2004-05-30 17:57:46Z phk $"); 72235783Skib 73235783Skib/* 74235783Skib * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also 75235783Skib * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in 76235783Skib * the 3c905C data sheet. 77235783Skib */ 78235783Skib 79235783Skib#include <sys/param.h> 80235783Skib#include <sys/systm.h> 81235783Skib#include <sys/kernel.h> 82235783Skib#include <sys/module.h> 83235783Skib#include <sys/socket.h> 84235783Skib#include <sys/bus.h> 85235783Skib 86235783Skib#include <net/if.h> 87235783Skib#include <net/if_media.h> 88235783Skib 89235783Skib#include <dev/mii/mii.h> 90235783Skib#include <dev/mii/miivar.h> 91235783Skib#include "miidevs.h" 92235783Skib 93235783Skib#include <dev/mii/bmtphyreg.h> 94235783Skib 95235783Skib#include "miibus_if.h" 96235783Skib 97235783Skibstatic int bmtphy_probe(device_t); 98235783Skibstatic int bmtphy_attach(device_t); 99235783Skib 100235783Skibstatic device_method_t bmtphy_methods[] = { 101235783Skib /* Device interface */ 102235783Skib DEVMETHOD(device_probe, bmtphy_probe), 103235783Skib DEVMETHOD(device_attach, bmtphy_attach), 104235783Skib DEVMETHOD(device_detach, mii_phy_detach), 105235783Skib DEVMETHOD(device_shutdown, bus_generic_shutdown), 106235783Skib 107235783Skib { 0, 0 } 108235783Skib}; 109235783Skib 110235783Skibstatic devclass_t bmtphy_devclass; 111235783Skib 112235783Skibstatic driver_t bmtphy_driver = { 113235783Skib "bmtphy", 114235783Skib bmtphy_methods, 115235783Skib sizeof(struct mii_softc) 116235783Skib}; 117235783Skib 118235783SkibDRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0); 119235783Skib 120235783Skibstatic int bmtphy_service(struct mii_softc *, struct mii_data *, int); 121235783Skibstatic void bmtphy_status(struct mii_softc *); 122235783Skib 123235783Skibstatic int 124235783Skibbmtphy_probe(device_t dev) 125235783Skib{ 126235783Skib struct mii_attach_args *ma; 127235783Skib int rval; 128235783Skib 129235783Skib ma = device_get_ivars(dev); 130235783Skib rval = 0; 131235783Skib 132235783Skib if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM) 133235783Skib return (ENXIO); 134235783Skib 135235783Skib switch (MII_MODEL(ma->mii_id2)) { 136235783Skib case MII_MODEL_BROADCOM_3C905B: 137235783Skib device_set_desc(dev, MII_STR_BROADCOM_3C905B); 138235783Skib rval = -10; /* Let exphy take precedence. */ 139235783Skib break; 140235783Skib case MII_MODEL_BROADCOM_3C905C: 141235783Skib device_set_desc(dev, MII_STR_BROADCOM_3C905C); 142235783Skib rval = -10; /* Let exphy take precedence. */ 143235783Skib break; 144235783Skib case MII_MODEL_BROADCOM_BCM5201: 145235783Skib device_set_desc(dev, MII_STR_BROADCOM_BCM5201); 146235783Skib break; 147235783Skib case MII_MODEL_BROADCOM_BCM5221: 148235783Skib device_set_desc(dev, MII_STR_BROADCOM_BCM5221); 149235783Skib break; 150235783Skib case MII_MODEL_BROADCOM_BCM4401: 151235783Skib device_set_desc(dev, MII_STR_BROADCOM_BCM4401); 152235783Skib break; 153235783Skib default: 154235783Skib return (ENXIO); 155235783Skib } 156235783Skib 157235783Skib return (rval); 158235783Skib} 159235783Skib 160235783Skibstatic int 161235783Skibbmtphy_attach(device_t dev) 162235783Skib{ 163235783Skib struct mii_softc *sc; 164235783Skib struct mii_attach_args *ma; 165235783Skib struct mii_data *mii; 166235783Skib 167235783Skib sc = device_get_softc(dev); 168235783Skib ma = device_get_ivars(dev); 169235783Skib sc->mii_dev = device_get_parent(dev); 170235783Skib mii = device_get_softc(sc->mii_dev); 171235783Skib LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 172235783Skib 173261632Sdumbbell sc->mii_inst = mii->mii_instance; 174261632Sdumbbell sc->mii_phy = ma->mii_phyno; 175261632Sdumbbell sc->mii_service = bmtphy_service; 176235783Skib sc->mii_pdata = mii; 177235783Skib 178235783Skib mii_phy_reset(sc); 179235783Skib 180235783Skib mii->mii_instance++; 181235783Skib 182235783Skib sc->mii_capabilities = 183235783Skib PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 184235783Skib device_printf(dev, " "); 185235783Skib if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 186235783Skib printf("no media present"); 187235783Skib else 188235783Skib mii_phy_add_media(sc); 189235783Skib 190235783Skib printf("\n"); 191235783Skib 192235783Skib MIIBUS_MEDIAINIT(sc->mii_dev); 193235783Skib 194235783Skib return (0); 195235783Skib} 196235783Skib 197235783Skibstatic int 198235783Skibbmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 199235783Skib{ 200235783Skib struct ifmedia_entry *ife; 201235783Skib int reg; 202235783Skib 203235783Skib ife = mii->mii_media.ifm_cur; 204235783Skib 205235783Skib switch (cmd) { 206235783Skib case MII_POLLSTAT: 207235783Skib /* 208235783Skib * If we're not polling our PHY instance, just return. 209235783Skib */ 210235783Skib if (IFM_INST(ife->ifm_media) != sc->mii_inst) 211235783Skib return (0); 212235783Skib break; 213235783Skib 214235783Skib case MII_MEDIACHG: 215235783Skib /* 216235783Skib * If the media indicates a different PHY instance, 217235783Skib * isolate ourselves. 218235783Skib */ 219235783Skib if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 220235783Skib reg = PHY_READ(sc, MII_BMCR); 221235783Skib PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 222235783Skib return (0); 223235783Skib } 224235783Skib 225235783Skib /* 226235783Skib * If the interface is not up, don't do anything. 227235783Skib */ 228235783Skib if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 229235783Skib break; 230235783Skib 231235783Skib mii_phy_setmedia(sc); 232235783Skib break; 233235783Skib 234235783Skib case MII_TICK: 235235783Skib /* 236235783Skib * If we're not currently selected, just return. 237235783Skib */ 238235783Skib if (IFM_INST(ife->ifm_media) != sc->mii_inst) 239235783Skib return (0); 240235783Skib if (mii_phy_tick(sc) == EJUSTRETURN) 241235783Skib return (0); 242235783Skib break; 243235783Skib } 244235783Skib 245235783Skib /* Update the media status. */ 246235783Skib bmtphy_status(sc); 247235783Skib 248235783Skib /* Callback if something changed. */ 249235783Skib mii_phy_update(sc, cmd); 250235783Skib 251235783Skib return (0); 252235783Skib} 253235783Skib 254235783Skibstatic void 255235783Skibbmtphy_status(struct mii_softc *sc) 256235783Skib{ 257235783Skib struct mii_data *mii; 258235783Skib struct ifmedia_entry *ife; 259235783Skib int bmsr, bmcr, aux_csr; 260235783Skib 261235783Skib mii = sc->mii_pdata; 262235783Skib ife = mii->mii_media.ifm_cur; 263235783Skib 264235783Skib mii->mii_media_status = IFM_AVALID; 265235783Skib mii->mii_media_active = IFM_ETHER; 266235783Skib 267235783Skib bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 268235783Skib aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); 269235783Skib 270235783Skib if (bmsr & BMSR_LINK) 271235783Skib mii->mii_media_status |= IFM_ACTIVE; 272235783Skib 273235783Skib bmcr = PHY_READ(sc, MII_BMCR); 274235783Skib if (bmcr & BMCR_ISO) { 275235783Skib mii->mii_media_active |= IFM_NONE; 276235783Skib mii->mii_media_status = 0; 277235783Skib return; 278235783Skib } 279235783Skib 280235783Skib if (bmcr & BMCR_LOOP) 281235783Skib mii->mii_media_active |= IFM_LOOP; 282235783Skib 283235783Skib if (bmcr & BMCR_AUTOEN) { 284235783Skib /* 285235783Skib * The media status bits are only valid if autonegotiation 286235783Skib * has completed (or it's disabled). 287235783Skib */ 288235783Skib if ((bmsr & BMSR_ACOMP) == 0) { 289235783Skib /* Erg, still trying, I guess... */ 290235783Skib mii->mii_media_active |= IFM_NONE; 291235783Skib return; 292235783Skib } 293235783Skib 294235783Skib if (aux_csr & AUX_CSR_SPEED) 295235783Skib mii->mii_media_active |= IFM_100_TX; 296235783Skib else 297235783Skib mii->mii_media_active |= IFM_10_T; 298235783Skib if (aux_csr & AUX_CSR_FDX) 299235783Skib mii->mii_media_active |= IFM_FDX; 300235783Skib } else 301235783Skib mii->mii_media_active = ife->ifm_media; 302235783Skib} 303235783Skib