smcphy.c revision 221407
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: head/sys/dev/mii/smcphy.c 221407 2011-05-03 19:51:29Z marius $"); 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); 56179592Sbennostatic void smcphy_reset(struct mii_softc *); 57179592Sbennostatic 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), 65179592Sbenno 66179592Sbenno { 0, 0 } 67179592Sbenno}; 68179592Sbenno 69179592Sbennostatic devclass_t smcphy_devclass; 70179592Sbenno 71179592Sbennostatic driver_t smcphy_driver = { 72179592Sbenno "smcphy", 73179592Sbenno smcphy_methods, 74179592Sbenno sizeof(struct mii_softc) 75179592Sbenno}; 76179592Sbenno 77179592SbennoDRIVER_MODULE(smcphy, miibus, smcphy_driver, smcphy_devclass, 0, 0); 78179592Sbenno 79214262Smariusstatic const struct mii_phydesc smcphys[] = { 80214262Smarius MII_PHY_DESC(SEEQ, 84220), 81214262Smarius MII_PHY_END 82214262Smarius}; 83214262Smarius 84179592Sbennostatic const struct mii_phy_funcs smcphy_funcs = { 85179592Sbenno smcphy_service, 86179592Sbenno ukphy_status, 87179592Sbenno smcphy_reset 88214262Smarius}; 89179592Sbenno 90179592Sbennostatic int 91179592Sbennosmcphy_probe(device_t dev) 92179592Sbenno{ 93179592Sbenno 94179592Sbenno return (mii_phy_dev_probe(dev, smcphys, BUS_PROBE_DEFAULT)); 95179592Sbenno} 96179592Sbenno 97179592Sbennostatic int 98179592Sbennosmcphy_attach(device_t dev) 99179592Sbenno{ 100179592Sbenno struct mii_softc *sc; 101213229Smarius 102179592Sbenno sc = device_get_softc(dev); 103179592Sbenno 104213893Smarius mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 105213364Smarius &smcphy_funcs, 1); 106179592Sbenno mii_phy_setmedia(sc); 107179592Sbenno 108179592Sbenno return (0); 109179592Sbenno} 110214262Smarius 111179592Sbennostatic int 112179592Sbennosmcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 113179592Sbenno{ 114179592Sbenno struct ifmedia_entry *ife; 115179592Sbenno int reg; 116179592Sbenno 117179592Sbenno ife = mii->mii_media.ifm_cur; 118179592Sbenno 119179592Sbenno switch (cmd) { 120179592Sbenno case MII_POLLSTAT: 121214262Smarius break; 122179592Sbenno 123179592Sbenno case MII_MEDIACHG: 124179592Sbenno /* 125179592Sbenno * If the interface is not up, don't do anything. 126179592Sbenno */ 127179592Sbenno if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 128179592Sbenno break; 129179592Sbenno 130179592Sbenno switch (IFM_SUBTYPE(ife->ifm_media)) { 131179592Sbenno case IFM_AUTO: 132179592Sbenno smcphy_auto(sc, ife->ifm_media); 133179592Sbenno break; 134179592Sbenno 135179592Sbenno default: 136179592Sbenno mii_phy_setmedia(sc); 137179592Sbenno break; 138179592Sbenno } 139179592Sbenno 140179592Sbenno break; 141179592Sbenno 142179592Sbenno case MII_TICK: 143179592Sbenno if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { 144179592Sbenno return (0); 145179592Sbenno } 146179592Sbenno 147179592Sbenno if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 148179592Sbenno break; 149179592Sbenno } 150179592Sbenno 151179592Sbenno /* I have no idea why BMCR_ISO gets set. */ 152179592Sbenno reg = PHY_READ(sc, MII_BMCR); 153179592Sbenno if (reg & BMCR_ISO) { 154179592Sbenno PHY_WRITE(sc, MII_BMCR, reg & ~BMCR_ISO); 155179592Sbenno } 156179592Sbenno 157179592Sbenno reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 158179592Sbenno if (reg & BMSR_LINK) { 159179592Sbenno sc->mii_ticks = 0; 160179592Sbenno break; 161179592Sbenno } 162179592Sbenno 163179592Sbenno if (++sc->mii_ticks <= MII_ANEGTICKS) { 164179592Sbenno break; 165179592Sbenno } 166179592Sbenno 167179592Sbenno sc->mii_ticks = 0; 168179592Sbenno PHY_RESET(sc); 169179592Sbenno smcphy_auto(sc, ife->ifm_media); 170179592Sbenno break; 171179592Sbenno } 172179592Sbenno 173179592Sbenno /* Update the media status. */ 174179592Sbenno PHY_STATUS(sc); 175179592Sbenno 176179592Sbenno /* Callback if something changed. */ 177179592Sbenno mii_phy_update(sc, cmd); 178179592Sbenno return (0); 179179592Sbenno} 180179592Sbenno 181179592Sbennostatic void 182179592Sbennosmcphy_reset(struct mii_softc *sc) 183179592Sbenno{ 184179592Sbenno u_int bmcr; 185179592Sbenno int timeout; 186179592Sbenno 187179592Sbenno PHY_WRITE(sc, MII_BMCR, BMCR_RESET); 188179592Sbenno 189179592Sbenno for (timeout = 2; timeout > 0; timeout--) { 190179592Sbenno DELAY(50000); 191179592Sbenno bmcr = PHY_READ(sc, MII_BMCR); 192179592Sbenno if ((bmcr & BMCR_RESET) == 0) 193179592Sbenno break; 194179592Sbenno } 195179592Sbenno 196179592Sbenno if (bmcr & BMCR_RESET) 197179592Sbenno device_printf(sc->mii_dev, "reset failed\n"); 198179592Sbenno 199179592Sbenno PHY_WRITE(sc, MII_BMCR, 0x3000); 200179592Sbenno 201179592Sbenno /* Mask interrupts, we poll instead. */ 202179592Sbenno PHY_WRITE(sc, 0x1e, 0xffc0); 203179592Sbenno} 204179592Sbenno 205179592Sbennostatic void 206179592Sbennosmcphy_auto(struct mii_softc *sc, int media) 207179592Sbenno{ 208179592Sbenno uint16_t anar; 209179592Sbenno 210179592Sbenno anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | 211179592Sbenno ANAR_CSMA; 212179592Sbenno if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 213179592Sbenno anar |= ANAR_FC; 214179592Sbenno PHY_WRITE(sc, MII_ANAR, anar); 215179592Sbenno /* Apparently this helps. */ 216179592Sbenno anar = PHY_READ(sc, MII_ANAR); 217179592Sbenno PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); 218179592Sbenno} 219179592Sbenno