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$"); 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: 126114577Sakiyama /* 127114577Sakiyama * If the interface is not up, don't do anything. 128114577Sakiyama */ 129114577Sakiyama if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 130114577Sakiyama break; 131114577Sakiyama 132165989Smarius mii_phy_setmedia(sc); 133114577Sakiyama break; 134114577Sakiyama 135114577Sakiyama case MII_TICK: 136114577Sakiyama /* 137114577Sakiyama * Is the interface even up? 138114577Sakiyama */ 139114577Sakiyama if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 140114577Sakiyama return (0); 141114577Sakiyama 142114577Sakiyama /* 143114577Sakiyama * Only used for autonegotiation. 144114577Sakiyama */ 145114577Sakiyama if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 146114577Sakiyama break; 147114577Sakiyama 148114577Sakiyama /* 149114577Sakiyama * Check to see if we have link. If we do, we don't 150114577Sakiyama * need to restart the autonegotiation process. Read 151114577Sakiyama * the MSR twice in case it's latched. 152114577Sakiyama */ 153114577Sakiyama reg = PHY_READ(sc, RUEPHY_MII_MSR) | 154165989Smarius PHY_READ(sc, RUEPHY_MII_MSR); 155114577Sakiyama if (reg & RUEPHY_MSR_LINK) 156114577Sakiyama break; 157114577Sakiyama 158213364Smarius /* Only retry autonegotiation every mii_anegticks seconds. */ 159213364Smarius if (sc->mii_ticks <= sc->mii_anegticks) 160128870Sandre break; 161114577Sakiyama 162114577Sakiyama sc->mii_ticks = 0; 163221407Smarius PHY_RESET(sc); 164114577Sakiyama if (mii_phy_auto(sc) == EJUSTRETURN) 165114577Sakiyama return (0); 166114577Sakiyama break; 167114577Sakiyama } 168114577Sakiyama 169114577Sakiyama /* Update the media status. */ 170221407Smarius PHY_STATUS(sc); 171114577Sakiyama 172114577Sakiyama /* Callback if something changed. */ 173114577Sakiyama mii_phy_update(sc, cmd); 174114577Sakiyama 175114577Sakiyama return (0); 176114577Sakiyama} 177114577Sakiyama 178114577Sakiyamastatic void 179114577Sakiyamaruephy_reset(struct mii_softc *sc) 180114577Sakiyama{ 181114577Sakiyama 182114577Sakiyama mii_phy_reset(sc); 183114577Sakiyama 184114577Sakiyama /* 185114577Sakiyama * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after 186114577Sakiyama * XXX reset, which breaks autonegotiation. 187114577Sakiyama */ 188114577Sakiyama PHY_WRITE(sc, MII_BMCR, (BMCR_S100 | BMCR_AUTOEN | BMCR_FDX)); 189114577Sakiyama} 190114577Sakiyama 191114577Sakiyamastatic void 192114577Sakiyamaruephy_status(struct mii_softc *phy) 193114577Sakiyama{ 194114577Sakiyama struct mii_data *mii = phy->mii_pdata; 195165989Smarius struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 196114577Sakiyama int bmsr, bmcr, msr; 197114577Sakiyama 198114577Sakiyama mii->mii_media_status = IFM_AVALID; 199114577Sakiyama mii->mii_media_active = IFM_ETHER; 200114577Sakiyama 201114577Sakiyama msr = PHY_READ(phy, RUEPHY_MII_MSR) | PHY_READ(phy, RUEPHY_MII_MSR); 202114577Sakiyama if (msr & RUEPHY_MSR_LINK) 203114577Sakiyama mii->mii_media_status |= IFM_ACTIVE; 204114577Sakiyama 205114577Sakiyama bmcr = PHY_READ(phy, MII_BMCR); 206114577Sakiyama if (bmcr & BMCR_ISO) { 207114577Sakiyama mii->mii_media_active |= IFM_NONE; 208114577Sakiyama mii->mii_media_status = 0; 209114577Sakiyama return; 210114577Sakiyama } 211114577Sakiyama 212114577Sakiyama bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); 213114577Sakiyama if (bmcr & BMCR_AUTOEN) { 214114577Sakiyama if ((bmsr & BMSR_ACOMP) == 0) { 215114577Sakiyama /* Erg, still trying, I guess... */ 216114577Sakiyama mii->mii_media_active |= IFM_NONE; 217114577Sakiyama return; 218114577Sakiyama } 219114577Sakiyama 220114577Sakiyama if (msr & RUEPHY_MSR_SPEED100) 221114577Sakiyama mii->mii_media_active |= IFM_100_TX; 222114577Sakiyama else 223114577Sakiyama mii->mii_media_active |= IFM_10_T; 224114577Sakiyama 225114577Sakiyama if (msr & RUEPHY_MSR_DUPLEX) 226221407Smarius mii->mii_media_active |= 227221407Smarius IFM_FDX | mii_phy_flowstatus(phy); 228213384Smarius else 229213384Smarius mii->mii_media_active |= IFM_HDX; 230114577Sakiyama } else 231165989Smarius mii->mii_media_active = ife->ifm_media; 232114577Sakiyama} 233