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$"); 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 switch (IFM_SUBTYPE(ife->ifm_media)) { 138179592Sbenno case IFM_AUTO: 139215297Smarius smcphy_auto(sc, ife->ifm_media); 140179592Sbenno break; 141179592Sbenno 142179592Sbenno default: 143179592Sbenno mii_phy_setmedia(sc); 144179592Sbenno break; 145179592Sbenno } 146179592Sbenno 147179592Sbenno break; 148179592Sbenno 149179592Sbenno case MII_TICK: 150179592Sbenno if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 151179592Sbenno break; 152179592Sbenno } 153179592Sbenno 154179592Sbenno /* I have no idea why BMCR_ISO gets set. */ 155179592Sbenno reg = PHY_READ(sc, MII_BMCR); 156179592Sbenno if (reg & BMCR_ISO) { 157179592Sbenno PHY_WRITE(sc, MII_BMCR, reg & ~BMCR_ISO); 158179592Sbenno } 159179592Sbenno 160179592Sbenno reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 161179592Sbenno if (reg & BMSR_LINK) { 162179592Sbenno sc->mii_ticks = 0; 163179592Sbenno break; 164179592Sbenno } 165179592Sbenno 166179592Sbenno if (++sc->mii_ticks <= MII_ANEGTICKS) { 167179592Sbenno break; 168179592Sbenno } 169179592Sbenno 170179592Sbenno sc->mii_ticks = 0; 171221407Smarius PHY_RESET(sc); 172215297Smarius smcphy_auto(sc, ife->ifm_media); 173179592Sbenno break; 174179592Sbenno } 175179592Sbenno 176179592Sbenno /* Update the media status. */ 177221407Smarius PHY_STATUS(sc); 178179592Sbenno 179179592Sbenno /* Callback if something changed. */ 180179592Sbenno mii_phy_update(sc, cmd); 181179592Sbenno return (0); 182179592Sbenno} 183179592Sbenno 184221407Smariusstatic void 185179592Sbennosmcphy_reset(struct mii_softc *sc) 186179592Sbenno{ 187179592Sbenno u_int bmcr; 188179592Sbenno int timeout; 189179592Sbenno 190179592Sbenno PHY_WRITE(sc, MII_BMCR, BMCR_RESET); 191179592Sbenno 192179592Sbenno for (timeout = 2; timeout > 0; timeout--) { 193179592Sbenno DELAY(50000); 194179592Sbenno bmcr = PHY_READ(sc, MII_BMCR); 195179592Sbenno if ((bmcr & BMCR_RESET) == 0) 196179592Sbenno break; 197179592Sbenno } 198179592Sbenno 199221407Smarius if (bmcr & BMCR_RESET) 200221407Smarius device_printf(sc->mii_dev, "reset failed\n"); 201179592Sbenno 202179592Sbenno PHY_WRITE(sc, MII_BMCR, 0x3000); 203221407Smarius 204221407Smarius /* Mask interrupts, we poll instead. */ 205221407Smarius PHY_WRITE(sc, 0x1e, 0xffc0); 206179592Sbenno} 207179592Sbenno 208179592Sbennostatic void 209215297Smariussmcphy_auto(struct mii_softc *sc, int media) 210179592Sbenno{ 211179592Sbenno uint16_t anar; 212179592Sbenno 213227908Smarius anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; 214215297Smarius if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 215179592Sbenno anar |= ANAR_FC; 216179592Sbenno PHY_WRITE(sc, MII_ANAR, anar); 217179592Sbenno /* Apparently this helps. */ 218179592Sbenno anar = PHY_READ(sc, MII_ANAR); 219179592Sbenno PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); 220179592Sbenno} 221232015Syongari 222232015Syongaristatic void 223232015Syongarismcphy_status(struct mii_softc *sc) 224232015Syongari{ 225232015Syongari struct mii_data *mii; 226232015Syongari uint32_t bmcr, bmsr, status; 227232015Syongari 228232015Syongari mii = sc->mii_pdata; 229232015Syongari mii->mii_media_status = IFM_AVALID; 230232015Syongari mii->mii_media_active = IFM_ETHER; 231232015Syongari 232232015Syongari bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 233232015Syongari if ((bmsr & BMSR_LINK) != 0) 234232015Syongari mii->mii_media_status |= IFM_ACTIVE; 235232015Syongari 236232015Syongari bmcr = PHY_READ(sc, MII_BMCR); 237232015Syongari if ((bmcr & BMCR_ISO) != 0) { 238232015Syongari mii->mii_media_active |= IFM_NONE; 239232015Syongari mii->mii_media_status = 0; 240232015Syongari return; 241232015Syongari } 242232015Syongari 243232015Syongari if ((bmcr & BMCR_LOOP) != 0) 244232015Syongari mii->mii_media_active |= IFM_LOOP; 245232015Syongari 246232015Syongari if ((bmcr & BMCR_AUTOEN) != 0) { 247232015Syongari if ((bmsr & BMSR_ACOMP) == 0) { 248232015Syongari /* Erg, still trying, I guess... */ 249232015Syongari mii->mii_media_active |= IFM_NONE; 250232015Syongari return; 251232015Syongari } 252232015Syongari } 253232015Syongari 254232015Syongari status = PHY_READ(sc, 0x12); 255232015Syongari if (status & 0x0080) 256232015Syongari mii->mii_media_active |= IFM_100_TX; 257232015Syongari else 258232015Syongari mii->mii_media_active |= IFM_10_T; 259232015Syongari if (status & 0x0040) 260232015Syongari mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); 261232015Syongari else 262232015Syongari mii->mii_media_active |= IFM_HDX; 263232015Syongari} 264