1114577Sakiyama/*- 2114577Sakiyama * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>. 3114577Sakiyama * All rights reserved. 4114577Sakiyama * 5114577Sakiyama * Redistribution and use in source and binary forms, with or without 6114577Sakiyama * modification, are permitted provided that the following conditions 7114577Sakiyama * are met: 8114577Sakiyama * 1. Redistributions of source code must retain the above copyright 9114577Sakiyama * notice, this list of conditions and the following disclaimer. 10114577Sakiyama * 2. Redistributions in binary form must reproduce the above copyright 11114577Sakiyama * notice, this list of conditions and the following disclaimer in the 12114577Sakiyama * documentation and/or other materials provided with the distribution. 13114577Sakiyama * 14114577Sakiyama * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15114577Sakiyama * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16114577Sakiyama * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17114577Sakiyama * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18114577Sakiyama * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19114577Sakiyama * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20114577Sakiyama * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21114577Sakiyama * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22114577Sakiyama * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23114577Sakiyama * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24114577Sakiyama * SUCH DAMAGE. 25114577Sakiyama * 26114577Sakiyama */ 27114577Sakiyama 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/dev/usb/net/ruephy.c 257184 2013-10-26 18:40:17Z glebius $"); 30119418Sobrien 31114577Sakiyama/* 32114577Sakiyama * driver for RealTek RTL8150 internal PHY 33114577Sakiyama */ 34114577Sakiyama 35114577Sakiyama#include <sys/param.h> 36114577Sakiyama#include <sys/systm.h> 37114577Sakiyama#include <sys/kernel.h> 38114577Sakiyama#include <sys/malloc.h> 39129876Sphk#include <sys/module.h> 40114577Sakiyama#include <sys/socket.h> 41114577Sakiyama#include <sys/bus.h> 42114577Sakiyama 43114577Sakiyama#include <net/if.h> 44114577Sakiyama#include <net/if_arp.h> 45114577Sakiyama#include <net/if_media.h> 46114577Sakiyama 47114577Sakiyama#include <dev/mii/mii.h> 48114577Sakiyama#include <dev/mii/miivar.h> 49114577Sakiyama#include "miidevs.h" 50114577Sakiyama 51226154Smarius#include <dev/usb/net/ruephyreg.h> 52114577Sakiyama 53114577Sakiyama#include "miibus_if.h" 54114577Sakiyama 55114577Sakiyamastatic int ruephy_probe(device_t); 56114577Sakiyamastatic int ruephy_attach(device_t); 57114577Sakiyama 58114577Sakiyamastatic device_method_t ruephy_methods[] = { 59114577Sakiyama /* device interface */ 60114577Sakiyama DEVMETHOD(device_probe, ruephy_probe), 61114577Sakiyama DEVMETHOD(device_attach, ruephy_attach), 62114577Sakiyama DEVMETHOD(device_detach, mii_phy_detach), 63114577Sakiyama DEVMETHOD(device_shutdown, bus_generic_shutdown), 64227908Smarius DEVMETHOD_END 65114577Sakiyama}; 66114577Sakiyama 67114577Sakiyamastatic devclass_t ruephy_devclass; 68114577Sakiyama 69114577Sakiyamastatic driver_t ruephy_driver = { 70233774Shselasky .name = "ruephy", 71233774Shselasky .methods = ruephy_methods, 72233774Shselasky .size = sizeof(struct mii_softc) 73114577Sakiyama}; 74114577Sakiyama 75114577SakiyamaDRIVER_MODULE(ruephy, miibus, ruephy_driver, ruephy_devclass, 0, 0); 76114577Sakiyama 77114577Sakiyamastatic int ruephy_service(struct mii_softc *, struct mii_data *, int); 78114577Sakiyamastatic void ruephy_reset(struct mii_softc *); 79114577Sakiyamastatic void ruephy_status(struct mii_softc *); 80114577Sakiyama 81165989Smarius/* 82165989Smarius * The RealTek RTL8150 internal PHY doesn't have vendor/device ID 83165989Smarius * registers; rue(4) fakes up a return value of all zeros. 84165989Smarius */ 85165989Smariusstatic const struct mii_phydesc ruephys[] = { 86165989Smarius { 0, 0, "RealTek RTL8150 internal media interface" }, 87165989Smarius MII_PHY_END 88165989Smarius}; 89165989Smarius 90221407Smariusstatic const struct mii_phy_funcs ruephy_funcs = { 91221407Smarius ruephy_service, 92221407Smarius ruephy_status, 93221407Smarius ruephy_reset 94221407Smarius}; 95221407Smarius 96114577Sakiyamastatic int 97114577Sakiyamaruephy_probe(device_t dev) 98114577Sakiyama{ 99114577Sakiyama 100165989Smarius if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), 101165989Smarius "rue") == 0) 102165989Smarius return (mii_phy_dev_probe(dev, ruephys, BUS_PROBE_DEFAULT)); 103165989Smarius return (ENXIO); 104114577Sakiyama} 105114577Sakiyama 106114577Sakiyamastatic int 107114577Sakiyamaruephy_attach(device_t dev) 108114577Sakiyama{ 109114577Sakiyama 110221407Smarius mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 111221407Smarius &ruephy_funcs, 1); 112114577Sakiyama return (0); 113114577Sakiyama} 114114577Sakiyama 115114577Sakiyamastatic int 116114577Sakiyamaruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 117114577Sakiyama{ 118114577Sakiyama struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 119114577Sakiyama int reg; 120114577Sakiyama 121114577Sakiyama switch (cmd) { 122114577Sakiyama case MII_POLLSTAT: 123114577Sakiyama break; 124114577Sakiyama 125114577Sakiyama case MII_MEDIACHG: 126165989Smarius mii_phy_setmedia(sc); 127114577Sakiyama break; 128114577Sakiyama 129114577Sakiyama case MII_TICK: 130114577Sakiyama /* 131114577Sakiyama * Only used for autonegotiation. 132114577Sakiyama */ 133114577Sakiyama if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 134114577Sakiyama break; 135114577Sakiyama 136114577Sakiyama /* 137114577Sakiyama * Check to see if we have link. If we do, we don't 138114577Sakiyama * need to restart the autonegotiation process. Read 139114577Sakiyama * the MSR twice in case it's latched. 140114577Sakiyama */ 141114577Sakiyama reg = PHY_READ(sc, RUEPHY_MII_MSR) | 142165989Smarius PHY_READ(sc, RUEPHY_MII_MSR); 143114577Sakiyama if (reg & RUEPHY_MSR_LINK) 144114577Sakiyama break; 145114577Sakiyama 146213364Smarius /* Only retry autonegotiation every mii_anegticks seconds. */ 147213364Smarius if (sc->mii_ticks <= sc->mii_anegticks) 148128870Sandre break; 149114577Sakiyama 150114577Sakiyama sc->mii_ticks = 0; 151221407Smarius PHY_RESET(sc); 152114577Sakiyama if (mii_phy_auto(sc) == EJUSTRETURN) 153114577Sakiyama return (0); 154114577Sakiyama break; 155114577Sakiyama } 156114577Sakiyama 157114577Sakiyama /* Update the media status. */ 158221407Smarius PHY_STATUS(sc); 159114577Sakiyama 160114577Sakiyama /* Callback if something changed. */ 161114577Sakiyama mii_phy_update(sc, cmd); 162114577Sakiyama 163114577Sakiyama return (0); 164114577Sakiyama} 165114577Sakiyama 166114577Sakiyamastatic void 167114577Sakiyamaruephy_reset(struct mii_softc *sc) 168114577Sakiyama{ 169114577Sakiyama 170114577Sakiyama mii_phy_reset(sc); 171114577Sakiyama 172114577Sakiyama /* 173114577Sakiyama * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after 174114577Sakiyama * XXX reset, which breaks autonegotiation. 175114577Sakiyama */ 176114577Sakiyama PHY_WRITE(sc, MII_BMCR, (BMCR_S100 | BMCR_AUTOEN | BMCR_FDX)); 177114577Sakiyama} 178114577Sakiyama 179114577Sakiyamastatic void 180114577Sakiyamaruephy_status(struct mii_softc *phy) 181114577Sakiyama{ 182114577Sakiyama struct mii_data *mii = phy->mii_pdata; 183165989Smarius struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 184114577Sakiyama int bmsr, bmcr, msr; 185114577Sakiyama 186114577Sakiyama mii->mii_media_status = IFM_AVALID; 187114577Sakiyama mii->mii_media_active = IFM_ETHER; 188114577Sakiyama 189114577Sakiyama msr = PHY_READ(phy, RUEPHY_MII_MSR) | PHY_READ(phy, RUEPHY_MII_MSR); 190114577Sakiyama if (msr & RUEPHY_MSR_LINK) 191114577Sakiyama mii->mii_media_status |= IFM_ACTIVE; 192114577Sakiyama 193114577Sakiyama bmcr = PHY_READ(phy, MII_BMCR); 194114577Sakiyama if (bmcr & BMCR_ISO) { 195114577Sakiyama mii->mii_media_active |= IFM_NONE; 196114577Sakiyama mii->mii_media_status = 0; 197114577Sakiyama return; 198114577Sakiyama } 199114577Sakiyama 200114577Sakiyama bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); 201114577Sakiyama if (bmcr & BMCR_AUTOEN) { 202114577Sakiyama if ((bmsr & BMSR_ACOMP) == 0) { 203114577Sakiyama /* Erg, still trying, I guess... */ 204114577Sakiyama mii->mii_media_active |= IFM_NONE; 205114577Sakiyama return; 206114577Sakiyama } 207114577Sakiyama 208114577Sakiyama if (msr & RUEPHY_MSR_SPEED100) 209114577Sakiyama mii->mii_media_active |= IFM_100_TX; 210114577Sakiyama else 211114577Sakiyama mii->mii_media_active |= IFM_10_T; 212114577Sakiyama 213114577Sakiyama if (msr & RUEPHY_MSR_DUPLEX) 214221407Smarius mii->mii_media_active |= 215221407Smarius IFM_FDX | mii_phy_flowstatus(phy); 216213384Smarius else 217213384Smarius mii->mii_media_active |= IFM_HDX; 218114577Sakiyama } else 219165989Smarius mii->mii_media_active = ife->ifm_media; 220114577Sakiyama} 221