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: releng/10.2/sys/dev/mii/smcphy.c 239275 2012-08-15 04:03:55Z gonzo $"); 27179592Sbenno 28179592Sbenno/* 29239275Sgonzo * Driver for the SEEQ 80220 and 84220. 30239275Sgonzo * (Originally developed for the internal PHY on the SMSC LAN91C111.) 31179592Sbenno */ 32179592Sbenno 33179592Sbenno#include <sys/param.h> 34179592Sbenno#include <sys/systm.h> 35179592Sbenno#include <sys/kernel.h> 36179592Sbenno#include <sys/socket.h> 37179592Sbenno#include <sys/errno.h> 38179592Sbenno#include <sys/module.h> 39179592Sbenno#include <sys/bus.h> 40179592Sbenno#include <sys/malloc.h> 41179592Sbenno 42179592Sbenno#include <machine/bus.h> 43179592Sbenno 44179592Sbenno#include <net/if.h> 45179592Sbenno#include <net/if_media.h> 46179592Sbenno 47179592Sbenno#include <dev/mii/mii.h> 48179592Sbenno#include <dev/mii/miivar.h> 49179592Sbenno#include "miidevs.h" 50179592Sbenno 51179592Sbenno#include "miibus_if.h" 52179592Sbenno 53179592Sbennostatic int smcphy_probe(device_t); 54179592Sbennostatic int smcphy_attach(device_t); 55179592Sbenno 56179592Sbennostatic int smcphy_service(struct mii_softc *, struct mii_data *, int); 57221407Smariusstatic void smcphy_reset(struct mii_softc *); 58215297Smariusstatic void smcphy_auto(struct mii_softc *, int); 59232015Syongaristatic void smcphy_status(struct mii_softc *); 60179592Sbenno 61179592Sbennostatic device_method_t smcphy_methods[] = { 62179592Sbenno /* device interface */ 63179592Sbenno DEVMETHOD(device_probe, smcphy_probe), 64179592Sbenno DEVMETHOD(device_attach, smcphy_attach), 65179592Sbenno DEVMETHOD(device_detach, mii_phy_detach), 66179592Sbenno DEVMETHOD(device_shutdown, bus_generic_shutdown), 67227908Smarius DEVMETHOD_END 68179592Sbenno}; 69179592Sbenno 70179592Sbennostatic devclass_t smcphy_devclass; 71179592Sbenno 72179592Sbennostatic driver_t smcphy_driver = { 73179592Sbenno "smcphy", 74179592Sbenno smcphy_methods, 75179592Sbenno sizeof(struct mii_softc) 76179592Sbenno}; 77179592Sbenno 78179592SbennoDRIVER_MODULE(smcphy, miibus, smcphy_driver, smcphy_devclass, 0, 0); 79179592Sbenno 80214262Smariusstatic const struct mii_phydesc smcphys[] = { 81232015Syongari MII_PHY_DESC(SEEQ, 80220), 82221407Smarius MII_PHY_DESC(SEEQ, 84220), 83214262Smarius MII_PHY_END 84214262Smarius}; 85214262Smarius 86232015Syongaristatic const struct mii_phy_funcs smcphy80220_funcs = { 87232015Syongari smcphy_service, 88232015Syongari smcphy_status, 89232015Syongari mii_phy_reset 90232015Syongari}; 91232015Syongari 92221407Smariusstatic const struct mii_phy_funcs smcphy_funcs = { 93221407Smarius smcphy_service, 94232015Syongari smcphy_status, 95221407Smarius smcphy_reset 96221407Smarius}; 97221407Smarius 98179592Sbennostatic int 99179592Sbennosmcphy_probe(device_t dev) 100179592Sbenno{ 101179592Sbenno 102214262Smarius return (mii_phy_dev_probe(dev, smcphys, BUS_PROBE_DEFAULT)); 103179592Sbenno} 104179592Sbenno 105179592Sbennostatic int 106179592Sbennosmcphy_attach(device_t dev) 107179592Sbenno{ 108221407Smarius struct mii_softc *sc; 109232015Syongari struct mii_attach_args *ma; 110232015Syongari const struct mii_phy_funcs *mpf; 111179592Sbenno 112179592Sbenno sc = device_get_softc(dev); 113232015Syongari ma = device_get_ivars(dev); 114232015Syongari if (MII_MODEL(ma->mii_id2) == MII_MODEL_SEEQ_80220) 115232015Syongari mpf = &smcphy80220_funcs; 116232015Syongari else 117232015Syongari mpf = &smcphy_funcs; 118232015Syongari mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, mpf, 1); 119179592Sbenno mii_phy_setmedia(sc); 120179592Sbenno 121179592Sbenno return (0); 122179592Sbenno} 123179592Sbenno 124179592Sbennostatic int 125179592Sbennosmcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 126179592Sbenno{ 127179592Sbenno struct ifmedia_entry *ife; 128179592Sbenno int reg; 129179592Sbenno 130179592Sbenno ife = mii->mii_media.ifm_cur; 131179592Sbenno 132179592Sbenno switch (cmd) { 133179592Sbenno case MII_POLLSTAT: 134179592Sbenno break; 135179592Sbenno 136179592Sbenno case MII_MEDIACHG: 137179592Sbenno /* 138179592Sbenno * If the interface is not up, don't do anything. 139179592Sbenno */ 140179592Sbenno if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 141179592Sbenno break; 142179592Sbenno 143179592Sbenno switch (IFM_SUBTYPE(ife->ifm_media)) { 144179592Sbenno case IFM_AUTO: 145215297Smarius smcphy_auto(sc, ife->ifm_media); 146179592Sbenno break; 147179592Sbenno 148179592Sbenno default: 149179592Sbenno mii_phy_setmedia(sc); 150179592Sbenno break; 151179592Sbenno } 152179592Sbenno 153179592Sbenno break; 154179592Sbenno 155179592Sbenno case MII_TICK: 156179592Sbenno if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { 157179592Sbenno return (0); 158179592Sbenno } 159179592Sbenno 160179592Sbenno if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 161179592Sbenno break; 162179592Sbenno } 163179592Sbenno 164179592Sbenno /* I have no idea why BMCR_ISO gets set. */ 165179592Sbenno reg = PHY_READ(sc, MII_BMCR); 166179592Sbenno if (reg & BMCR_ISO) { 167179592Sbenno PHY_WRITE(sc, MII_BMCR, reg & ~BMCR_ISO); 168179592Sbenno } 169179592Sbenno 170179592Sbenno reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 171179592Sbenno if (reg & BMSR_LINK) { 172179592Sbenno sc->mii_ticks = 0; 173179592Sbenno break; 174179592Sbenno } 175179592Sbenno 176179592Sbenno if (++sc->mii_ticks <= MII_ANEGTICKS) { 177179592Sbenno break; 178179592Sbenno } 179179592Sbenno 180179592Sbenno sc->mii_ticks = 0; 181221407Smarius PHY_RESET(sc); 182215297Smarius smcphy_auto(sc, ife->ifm_media); 183179592Sbenno break; 184179592Sbenno } 185179592Sbenno 186179592Sbenno /* Update the media status. */ 187221407Smarius PHY_STATUS(sc); 188179592Sbenno 189179592Sbenno /* Callback if something changed. */ 190179592Sbenno mii_phy_update(sc, cmd); 191179592Sbenno return (0); 192179592Sbenno} 193179592Sbenno 194221407Smariusstatic void 195179592Sbennosmcphy_reset(struct mii_softc *sc) 196179592Sbenno{ 197179592Sbenno u_int bmcr; 198179592Sbenno int timeout; 199179592Sbenno 200179592Sbenno PHY_WRITE(sc, MII_BMCR, BMCR_RESET); 201179592Sbenno 202179592Sbenno for (timeout = 2; timeout > 0; timeout--) { 203179592Sbenno DELAY(50000); 204179592Sbenno bmcr = PHY_READ(sc, MII_BMCR); 205179592Sbenno if ((bmcr & BMCR_RESET) == 0) 206179592Sbenno break; 207179592Sbenno } 208179592Sbenno 209221407Smarius if (bmcr & BMCR_RESET) 210221407Smarius device_printf(sc->mii_dev, "reset failed\n"); 211179592Sbenno 212179592Sbenno PHY_WRITE(sc, MII_BMCR, 0x3000); 213221407Smarius 214221407Smarius /* Mask interrupts, we poll instead. */ 215221407Smarius PHY_WRITE(sc, 0x1e, 0xffc0); 216179592Sbenno} 217179592Sbenno 218179592Sbennostatic void 219215297Smariussmcphy_auto(struct mii_softc *sc, int media) 220179592Sbenno{ 221179592Sbenno uint16_t anar; 222179592Sbenno 223227908Smarius anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 224215297Smarius if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 225179592Sbenno anar |= ANAR_FC; 226179592Sbenno PHY_WRITE(sc, MII_ANAR, anar); 227179592Sbenno /* Apparently this helps. */ 228179592Sbenno anar = PHY_READ(sc, MII_ANAR); 229179592Sbenno PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); 230179592Sbenno} 231232015Syongari 232232015Syongaristatic void 233232015Syongarismcphy_status(struct mii_softc *sc) 234232015Syongari{ 235232015Syongari struct mii_data *mii; 236232015Syongari uint32_t bmcr, bmsr, status; 237232015Syongari 238232015Syongari mii = sc->mii_pdata; 239232015Syongari mii->mii_media_status = IFM_AVALID; 240232015Syongari mii->mii_media_active = IFM_ETHER; 241232015Syongari 242232015Syongari bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 243232015Syongari if ((bmsr & BMSR_LINK) != 0) 244232015Syongari mii->mii_media_status |= IFM_ACTIVE; 245232015Syongari 246232015Syongari bmcr = PHY_READ(sc, MII_BMCR); 247232015Syongari if ((bmcr & BMCR_ISO) != 0) { 248232015Syongari mii->mii_media_active |= IFM_NONE; 249232015Syongari mii->mii_media_status = 0; 250232015Syongari return; 251232015Syongari } 252232015Syongari 253232015Syongari if ((bmcr & BMCR_LOOP) != 0) 254232015Syongari mii->mii_media_active |= IFM_LOOP; 255232015Syongari 256232015Syongari if ((bmcr & BMCR_AUTOEN) != 0) { 257232015Syongari if ((bmsr & BMSR_ACOMP) == 0) { 258232015Syongari /* Erg, still trying, I guess... */ 259232015Syongari mii->mii_media_active |= IFM_NONE; 260232015Syongari return; 261232015Syongari } 262232015Syongari } 263232015Syongari 264232015Syongari status = PHY_READ(sc, 0x12); 265232015Syongari if (status & 0x0080) 266232015Syongari mii->mii_media_active |= IFM_100_TX; 267232015Syongari else 268232015Syongari mii->mii_media_active |= IFM_10_T; 269232015Syongari if (status & 0x0040) 270232015Syongari mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); 271232015Syongari else 272232015Syongari mii->mii_media_active |= IFM_HDX; 273232015Syongari} 274