smcphy.c revision 229093
1179592Sbenno/*- 2179592Sbenno * Copyright (c) 2006 Benno Rice. All rights reserved. 3179592Sbenno * 4179592Sbenno * Redistribution and use in source and binary forms, with or without 5179592Sbenno * modification, are permitted provided that the following conditions 6179592Sbenno * are met: 7179592Sbenno * 1. Redistributions of source code must retain the above copyright 8179592Sbenno * notice, this list of conditions and the following disclaimer. 9179592Sbenno * 2. Redistributions in binary form must reproduce the above copyright 10179592Sbenno * notice, this list of conditions and the following disclaimer in the 11179592Sbenno * documentation and/or other materials provided with the distribution. 12179592Sbenno * 13179592Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14179592Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15179592Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16179592Sbenno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17179592Sbenno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18179592Sbenno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19179592Sbenno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20179592Sbenno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21179592Sbenno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22179592Sbenno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23179592Sbenno */ 24179592Sbenno 25179592Sbenno#include <sys/cdefs.h> 26179592Sbenno__FBSDID("$FreeBSD: stable/9/sys/dev/mii/smcphy.c 229093 2011-12-31 14:12:12Z hselasky $"); 27179592Sbenno 28179592Sbenno/* 29179592Sbenno * Driver for the internal PHY on the SMSC LAN91C111. 30179592Sbenno */ 31179592Sbenno 32179592Sbenno#include <sys/param.h> 33179592Sbenno#include <sys/systm.h> 34179592Sbenno#include <sys/kernel.h> 35179592Sbenno#include <sys/socket.h> 36179592Sbenno#include <sys/errno.h> 37179592Sbenno#include <sys/module.h> 38179592Sbenno#include <sys/bus.h> 39179592Sbenno#include <sys/malloc.h> 40179592Sbenno 41179592Sbenno#include <machine/bus.h> 42179592Sbenno 43179592Sbenno#include <net/if.h> 44179592Sbenno#include <net/if_media.h> 45179592Sbenno 46179592Sbenno#include <dev/mii/mii.h> 47179592Sbenno#include <dev/mii/miivar.h> 48179592Sbenno#include "miidevs.h" 49179592Sbenno 50179592Sbenno#include "miibus_if.h" 51179592Sbenno 52179592Sbennostatic int smcphy_probe(device_t); 53179592Sbennostatic int smcphy_attach(device_t); 54179592Sbenno 55179592Sbennostatic int smcphy_service(struct mii_softc *, struct mii_data *, int); 56221407Smariusstatic void smcphy_reset(struct mii_softc *); 57215297Smariusstatic void smcphy_auto(struct mii_softc *, int); 58179592Sbenno 59179592Sbennostatic device_method_t smcphy_methods[] = { 60179592Sbenno /* device interface */ 61179592Sbenno DEVMETHOD(device_probe, smcphy_probe), 62179592Sbenno DEVMETHOD(device_attach, smcphy_attach), 63179592Sbenno DEVMETHOD(device_detach, mii_phy_detach), 64179592Sbenno DEVMETHOD(device_shutdown, bus_generic_shutdown), 65229093Shselasky DEVMETHOD_END 66179592Sbenno}; 67179592Sbenno 68179592Sbennostatic devclass_t smcphy_devclass; 69179592Sbenno 70179592Sbennostatic driver_t smcphy_driver = { 71179592Sbenno "smcphy", 72179592Sbenno smcphy_methods, 73179592Sbenno sizeof(struct mii_softc) 74179592Sbenno}; 75179592Sbenno 76179592SbennoDRIVER_MODULE(smcphy, miibus, smcphy_driver, smcphy_devclass, 0, 0); 77179592Sbenno 78214262Smariusstatic const struct mii_phydesc smcphys[] = { 79221407Smarius MII_PHY_DESC(SEEQ, 84220), 80214262Smarius MII_PHY_END 81214262Smarius}; 82214262Smarius 83221407Smariusstatic const struct mii_phy_funcs smcphy_funcs = { 84221407Smarius smcphy_service, 85221407Smarius ukphy_status, 86221407Smarius smcphy_reset 87221407Smarius}; 88221407Smarius 89179592Sbennostatic int 90179592Sbennosmcphy_probe(device_t dev) 91179592Sbenno{ 92179592Sbenno 93214262Smarius return (mii_phy_dev_probe(dev, smcphys, BUS_PROBE_DEFAULT)); 94179592Sbenno} 95179592Sbenno 96179592Sbennostatic int 97179592Sbennosmcphy_attach(device_t dev) 98179592Sbenno{ 99221407Smarius struct mii_softc *sc; 100179592Sbenno 101179592Sbenno sc = device_get_softc(dev); 102179592Sbenno 103221407Smarius mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 104221407Smarius &smcphy_funcs, 1); 105179592Sbenno mii_phy_setmedia(sc); 106179592Sbenno 107179592Sbenno return (0); 108179592Sbenno} 109179592Sbenno 110179592Sbennostatic int 111179592Sbennosmcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 112179592Sbenno{ 113179592Sbenno struct ifmedia_entry *ife; 114179592Sbenno int reg; 115179592Sbenno 116179592Sbenno ife = mii->mii_media.ifm_cur; 117179592Sbenno 118179592Sbenno switch (cmd) { 119179592Sbenno case MII_POLLSTAT: 120179592Sbenno break; 121179592Sbenno 122179592Sbenno case MII_MEDIACHG: 123179592Sbenno /* 124179592Sbenno * If the interface is not up, don't do anything. 125179592Sbenno */ 126179592Sbenno if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 127179592Sbenno break; 128179592Sbenno 129179592Sbenno switch (IFM_SUBTYPE(ife->ifm_media)) { 130179592Sbenno case IFM_AUTO: 131215297Smarius smcphy_auto(sc, ife->ifm_media); 132179592Sbenno break; 133179592Sbenno 134179592Sbenno default: 135179592Sbenno mii_phy_setmedia(sc); 136179592Sbenno break; 137179592Sbenno } 138179592Sbenno 139179592Sbenno break; 140179592Sbenno 141179592Sbenno case MII_TICK: 142179592Sbenno if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { 143179592Sbenno return (0); 144179592Sbenno } 145179592Sbenno 146179592Sbenno if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 147179592Sbenno break; 148179592Sbenno } 149179592Sbenno 150179592Sbenno /* I have no idea why BMCR_ISO gets set. */ 151179592Sbenno reg = PHY_READ(sc, MII_BMCR); 152179592Sbenno if (reg & BMCR_ISO) { 153179592Sbenno PHY_WRITE(sc, MII_BMCR, reg & ~BMCR_ISO); 154179592Sbenno } 155179592Sbenno 156179592Sbenno reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 157179592Sbenno if (reg & BMSR_LINK) { 158179592Sbenno sc->mii_ticks = 0; 159179592Sbenno break; 160179592Sbenno } 161179592Sbenno 162179592Sbenno if (++sc->mii_ticks <= MII_ANEGTICKS) { 163179592Sbenno break; 164179592Sbenno } 165179592Sbenno 166179592Sbenno sc->mii_ticks = 0; 167221407Smarius PHY_RESET(sc); 168215297Smarius smcphy_auto(sc, ife->ifm_media); 169179592Sbenno break; 170179592Sbenno } 171179592Sbenno 172179592Sbenno /* Update the media status. */ 173221407Smarius PHY_STATUS(sc); 174179592Sbenno 175179592Sbenno /* Callback if something changed. */ 176179592Sbenno mii_phy_update(sc, cmd); 177179592Sbenno return (0); 178179592Sbenno} 179179592Sbenno 180221407Smariusstatic void 181179592Sbennosmcphy_reset(struct mii_softc *sc) 182179592Sbenno{ 183179592Sbenno u_int bmcr; 184179592Sbenno int timeout; 185179592Sbenno 186179592Sbenno PHY_WRITE(sc, MII_BMCR, BMCR_RESET); 187179592Sbenno 188179592Sbenno for (timeout = 2; timeout > 0; timeout--) { 189179592Sbenno DELAY(50000); 190179592Sbenno bmcr = PHY_READ(sc, MII_BMCR); 191179592Sbenno if ((bmcr & BMCR_RESET) == 0) 192179592Sbenno break; 193179592Sbenno } 194179592Sbenno 195221407Smarius if (bmcr & BMCR_RESET) 196221407Smarius device_printf(sc->mii_dev, "reset failed\n"); 197179592Sbenno 198179592Sbenno PHY_WRITE(sc, MII_BMCR, 0x3000); 199221407Smarius 200221407Smarius /* Mask interrupts, we poll instead. */ 201221407Smarius PHY_WRITE(sc, 0x1e, 0xffc0); 202179592Sbenno} 203179592Sbenno 204179592Sbennostatic void 205215297Smariussmcphy_auto(struct mii_softc *sc, int media) 206179592Sbenno{ 207179592Sbenno uint16_t anar; 208179592Sbenno 209229093Shselasky anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 210215297Smarius if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 211179592Sbenno anar |= ANAR_FC; 212179592Sbenno PHY_WRITE(sc, MII_ANAR, anar); 213179592Sbenno /* Apparently this helps. */ 214179592Sbenno anar = PHY_READ(sc, MII_ANAR); 215179592Sbenno PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); 216179592Sbenno} 217