13c374c15SSepherosa Ziehau /*- 23c374c15SSepherosa Ziehau * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>. 33c374c15SSepherosa Ziehau * All rights reserved. 43c374c15SSepherosa Ziehau * 53c374c15SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 63c374c15SSepherosa Ziehau * modification, are permitted provided that the following conditions 73c374c15SSepherosa Ziehau * are met: 83c374c15SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 93c374c15SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 103c374c15SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 113c374c15SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 123c374c15SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 133c374c15SSepherosa Ziehau * 143c374c15SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 153c374c15SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 163c374c15SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 173c374c15SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 183c374c15SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 193c374c15SSepherosa Ziehau * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 203c374c15SSepherosa Ziehau * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 213c374c15SSepherosa Ziehau * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 223c374c15SSepherosa Ziehau * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 233c374c15SSepherosa Ziehau * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 243c374c15SSepherosa Ziehau * SUCH DAMAGE. 253c374c15SSepherosa Ziehau * 263c374c15SSepherosa Ziehau * $FreeBSD: src/sys/dev/mii/ruephy.c,v 1.1.4.1 2003/07/30 13:57:35 akiyama Exp $ 27*e3869ec7SSascha Wildner * $DragonFly: src/sys/dev/netif/mii_layer/ruephy.c,v 1.6 2006/12/22 23:26:20 swildner Exp $ 283c374c15SSepherosa Ziehau */ 293c374c15SSepherosa Ziehau 303c374c15SSepherosa Ziehau /* 313c374c15SSepherosa Ziehau * driver for RealTek RTL8150 internal PHY 323c374c15SSepherosa Ziehau */ 333c374c15SSepherosa Ziehau 343c374c15SSepherosa Ziehau #include <sys/param.h> 353c374c15SSepherosa Ziehau #include <sys/systm.h> 363c374c15SSepherosa Ziehau #include <sys/kernel.h> 373c374c15SSepherosa Ziehau #include <sys/malloc.h> 383c374c15SSepherosa Ziehau #include <sys/socket.h> 393c374c15SSepherosa Ziehau #include <sys/bus.h> 403c374c15SSepherosa Ziehau 413c374c15SSepherosa Ziehau #include <net/if.h> 423c374c15SSepherosa Ziehau #include <net/if_media.h> 433c374c15SSepherosa Ziehau 443c374c15SSepherosa Ziehau #include <dev/netif/mii_layer/mii.h> 453c374c15SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h> 463c374c15SSepherosa Ziehau #include <dev/netif/mii_layer/ruephyreg.h> 473c374c15SSepherosa Ziehau 483c374c15SSepherosa Ziehau #include "miibus_if.h" 493c374c15SSepherosa Ziehau 503c374c15SSepherosa Ziehau static int ruephy_probe(device_t); 513c374c15SSepherosa Ziehau static int ruephy_attach(device_t); 523c374c15SSepherosa Ziehau 533c374c15SSepherosa Ziehau static device_method_t ruephy_methods[] = { 543c374c15SSepherosa Ziehau /* device interface */ 553c374c15SSepherosa Ziehau DEVMETHOD(device_probe, ruephy_probe), 563c374c15SSepherosa Ziehau DEVMETHOD(device_attach, ruephy_attach), 5746ad174eSSepherosa Ziehau DEVMETHOD(device_detach, ukphy_detach), 583c374c15SSepherosa Ziehau DEVMETHOD(device_shutdown, bus_generic_shutdown), 593c374c15SSepherosa Ziehau { 0, 0 } 603c374c15SSepherosa Ziehau }; 613c374c15SSepherosa Ziehau 623c374c15SSepherosa Ziehau static devclass_t ruephy_devclass; 633c374c15SSepherosa Ziehau 643c374c15SSepherosa Ziehau static driver_t ruephy_driver = { 653c374c15SSepherosa Ziehau "ruephy", 663c374c15SSepherosa Ziehau ruephy_methods, 673c374c15SSepherosa Ziehau sizeof(struct mii_softc) 683c374c15SSepherosa Ziehau }; 693c374c15SSepherosa Ziehau 703c374c15SSepherosa Ziehau DRIVER_MODULE(ruephy, miibus, ruephy_driver, ruephy_devclass, 0, 0); 713c374c15SSepherosa Ziehau 723c374c15SSepherosa Ziehau static int ruephy_service(struct mii_softc *, struct mii_data *, int); 733c374c15SSepherosa Ziehau static void ruephy_reset(struct mii_softc *); 743c374c15SSepherosa Ziehau static void ruephy_status(struct mii_softc *); 753c374c15SSepherosa Ziehau 763c374c15SSepherosa Ziehau static int 773c374c15SSepherosa Ziehau ruephy_probe(device_t dev) 783c374c15SSepherosa Ziehau { 793c374c15SSepherosa Ziehau struct mii_attach_args *ma; 803c374c15SSepherosa Ziehau device_t parent; 813c374c15SSepherosa Ziehau 823c374c15SSepherosa Ziehau ma = device_get_ivars(dev); 833c374c15SSepherosa Ziehau parent = device_get_parent(device_get_parent(dev)); 843c374c15SSepherosa Ziehau 853c374c15SSepherosa Ziehau /* 863c374c15SSepherosa Ziehau * RealTek RTL8150 PHY doesn't have vendor/device ID registers: 873c374c15SSepherosa Ziehau * the rue driver fakes up a return value of all zeros. 883c374c15SSepherosa Ziehau */ 893c374c15SSepherosa Ziehau if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || 903c374c15SSepherosa Ziehau MII_MODEL(ma->mii_id2) != 0) 913c374c15SSepherosa Ziehau return (ENXIO); 923c374c15SSepherosa Ziehau 933c374c15SSepherosa Ziehau /* 943c374c15SSepherosa Ziehau * Make sure the parent is an 'rue'. 953c374c15SSepherosa Ziehau */ 963c374c15SSepherosa Ziehau if (strcmp(device_get_name(parent), "rue") != 0) 973c374c15SSepherosa Ziehau return (ENXIO); 983c374c15SSepherosa Ziehau 993c374c15SSepherosa Ziehau device_set_desc(dev, "RealTek RTL8150 internal media interface"); 1003c374c15SSepherosa Ziehau 1013c374c15SSepherosa Ziehau return (0); 1023c374c15SSepherosa Ziehau } 1033c374c15SSepherosa Ziehau 1043c374c15SSepherosa Ziehau static int 1053c374c15SSepherosa Ziehau ruephy_attach(device_t dev) 1063c374c15SSepherosa Ziehau { 1073c374c15SSepherosa Ziehau struct mii_softc *sc; 1083c374c15SSepherosa Ziehau struct mii_attach_args *ma; 1093c374c15SSepherosa Ziehau struct mii_data *mii; 1103c374c15SSepherosa Ziehau 1113c374c15SSepherosa Ziehau sc = device_get_softc(dev); 1123c374c15SSepherosa Ziehau ma = device_get_ivars(dev); 113b9bc8a8cSMatthew Dillon mii_softc_init(sc, ma); 1143c374c15SSepherosa Ziehau sc->mii_dev = device_get_parent(dev); 1153c374c15SSepherosa Ziehau mii = device_get_softc(sc->mii_dev); 1163c374c15SSepherosa Ziehau 1173c374c15SSepherosa Ziehau /* 1183c374c15SSepherosa Ziehau * The RealTek PHY can never be isolated, so never allow non-zero 1193c374c15SSepherosa Ziehau * instances! 1203c374c15SSepherosa Ziehau */ 1213c374c15SSepherosa Ziehau if (mii->mii_instance != 0) { 1223c374c15SSepherosa Ziehau device_printf(dev, "ignoring this PHY, non-zero instance\n"); 1233c374c15SSepherosa Ziehau return (ENXIO); 1243c374c15SSepherosa Ziehau } 1253c374c15SSepherosa Ziehau 1263c374c15SSepherosa Ziehau LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 1273c374c15SSepherosa Ziehau 1283c374c15SSepherosa Ziehau sc->mii_inst = mii->mii_instance; 1293c374c15SSepherosa Ziehau sc->mii_service = ruephy_service; 13046ad174eSSepherosa Ziehau sc->mii_reset = ruephy_reset; 1313c374c15SSepherosa Ziehau sc->mii_pdata = mii; 1323c374c15SSepherosa Ziehau mii->mii_instance++; 1333c374c15SSepherosa Ziehau 1343c374c15SSepherosa Ziehau sc->mii_flags |= MIIF_NOISOLATE; 1353c374c15SSepherosa Ziehau 1363c374c15SSepherosa Ziehau ruephy_reset(sc); 1373c374c15SSepherosa Ziehau 13846ad174eSSepherosa Ziehau sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 13946ad174eSSepherosa Ziehau 1403c374c15SSepherosa Ziehau device_printf(dev, " "); 1413c374c15SSepherosa Ziehau if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 142*e3869ec7SSascha Wildner kprintf("no media present"); 1433c374c15SSepherosa Ziehau else 14446ad174eSSepherosa Ziehau mii_phy_add_media(sc); 145*e3869ec7SSascha Wildner kprintf("\n"); 1463c374c15SSepherosa Ziehau 1473c374c15SSepherosa Ziehau MIIBUS_MEDIAINIT(sc->mii_dev); 1483c374c15SSepherosa Ziehau return (0); 1493c374c15SSepherosa Ziehau } 1503c374c15SSepherosa Ziehau 1513c374c15SSepherosa Ziehau static int 1523c374c15SSepherosa Ziehau ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 1533c374c15SSepherosa Ziehau { 1543c374c15SSepherosa Ziehau struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 1553c374c15SSepherosa Ziehau int reg; 1563c374c15SSepherosa Ziehau 1573c374c15SSepherosa Ziehau /* 1583c374c15SSepherosa Ziehau * We can't isolate the RealTek RTL8150 PHY, 1593c374c15SSepherosa Ziehau * so it has to be the only one! 1603c374c15SSepherosa Ziehau */ 16146ad174eSSepherosa Ziehau KASSERT(IFM_INST(ife->ifm_media) == sc->mii_inst, 16246ad174eSSepherosa Ziehau ("ruephy_service: can't isolate RealTek RTL8150 PHY")); 1633c374c15SSepherosa Ziehau 1643c374c15SSepherosa Ziehau switch (cmd) { 1653c374c15SSepherosa Ziehau case MII_POLLSTAT: 1663c374c15SSepherosa Ziehau break; 1673c374c15SSepherosa Ziehau 1683c374c15SSepherosa Ziehau case MII_MEDIACHG: 1693c374c15SSepherosa Ziehau /* 1703c374c15SSepherosa Ziehau * If the interface is not up, don't do anything. 1713c374c15SSepherosa Ziehau */ 1723c374c15SSepherosa Ziehau if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 1733c374c15SSepherosa Ziehau break; 1743c374c15SSepherosa Ziehau 17546ad174eSSepherosa Ziehau if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_T4) { 1763c374c15SSepherosa Ziehau /* 1773c374c15SSepherosa Ziehau * XXX Not supported as a manual setting right now. 1783c374c15SSepherosa Ziehau */ 1793c374c15SSepherosa Ziehau return (EINVAL); 1803c374c15SSepherosa Ziehau } 18146ad174eSSepherosa Ziehau 18246ad174eSSepherosa Ziehau mii_phy_set_media(sc); 1833c374c15SSepherosa Ziehau break; 1843c374c15SSepherosa Ziehau 1853c374c15SSepherosa Ziehau case MII_TICK: 1863c374c15SSepherosa Ziehau /* 1873c374c15SSepherosa Ziehau * Is the interface even up? 1883c374c15SSepherosa Ziehau */ 1893c374c15SSepherosa Ziehau if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 1903c374c15SSepherosa Ziehau return (0); 1913c374c15SSepherosa Ziehau 1923c374c15SSepherosa Ziehau /* 1933c374c15SSepherosa Ziehau * Only used for autonegotiation. 1943c374c15SSepherosa Ziehau */ 1953c374c15SSepherosa Ziehau if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 1963c374c15SSepherosa Ziehau break; 1973c374c15SSepherosa Ziehau 1983c374c15SSepherosa Ziehau /* 1993c374c15SSepherosa Ziehau * Check to see if we have link. If we do, we don't 2003c374c15SSepherosa Ziehau * need to restart the autonegotiation process. Read 2013c374c15SSepherosa Ziehau * the MSR twice in case it's latched. 2023c374c15SSepherosa Ziehau */ 2033c374c15SSepherosa Ziehau reg = PHY_READ(sc, RUEPHY_MII_MSR) | 2043c374c15SSepherosa Ziehau PHY_READ(sc, RUEPHY_MII_MSR); 2053c374c15SSepherosa Ziehau if (reg & RUEPHY_MSR_LINK) 2063c374c15SSepherosa Ziehau break; 2073c374c15SSepherosa Ziehau 2083c374c15SSepherosa Ziehau /* 2093c374c15SSepherosa Ziehau * Only retry autonegotiation every 5 seconds. 2103c374c15SSepherosa Ziehau */ 2113c374c15SSepherosa Ziehau if (++sc->mii_ticks != 5) 2123c374c15SSepherosa Ziehau return (0); 2133c374c15SSepherosa Ziehau 2143c374c15SSepherosa Ziehau sc->mii_ticks = 0; 2153c374c15SSepherosa Ziehau ruephy_reset(sc); 21646ad174eSSepherosa Ziehau 2173c374c15SSepherosa Ziehau if (mii_phy_auto(sc, 0) == EJUSTRETURN) 2183c374c15SSepherosa Ziehau return (0); 2193c374c15SSepherosa Ziehau break; 2203c374c15SSepherosa Ziehau } 2213c374c15SSepherosa Ziehau 2223c374c15SSepherosa Ziehau /* Update the media status. */ 2233c374c15SSepherosa Ziehau ruephy_status(sc); 2243c374c15SSepherosa Ziehau 2253c374c15SSepherosa Ziehau /* Callback if something changed. */ 22646ad174eSSepherosa Ziehau mii_phy_update(sc, cmd); 2273c374c15SSepherosa Ziehau return (0); 2283c374c15SSepherosa Ziehau } 2293c374c15SSepherosa Ziehau 2303c374c15SSepherosa Ziehau static void 2313c374c15SSepherosa Ziehau ruephy_reset(struct mii_softc *sc) 2323c374c15SSepherosa Ziehau { 2333c374c15SSepherosa Ziehau 2343c374c15SSepherosa Ziehau mii_phy_reset(sc); 2353c374c15SSepherosa Ziehau 2363c374c15SSepherosa Ziehau /* 2373c374c15SSepherosa Ziehau * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after 2383c374c15SSepherosa Ziehau * XXX reset, which breaks autonegotiation. 2393c374c15SSepherosa Ziehau */ 240e9fa3ce7SSepherosa Ziehau PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN); 2413c374c15SSepherosa Ziehau } 2423c374c15SSepherosa Ziehau 2433c374c15SSepherosa Ziehau static void 24446ad174eSSepherosa Ziehau ruephy_status(struct mii_softc *sc) 2453c374c15SSepherosa Ziehau { 24646ad174eSSepherosa Ziehau struct mii_data *mii = sc->mii_pdata; 2473c374c15SSepherosa Ziehau int bmsr, bmcr, msr; 2483c374c15SSepherosa Ziehau 2493c374c15SSepherosa Ziehau mii->mii_media_status = IFM_AVALID; 2503c374c15SSepherosa Ziehau mii->mii_media_active = IFM_ETHER; 2513c374c15SSepherosa Ziehau 25246ad174eSSepherosa Ziehau msr = PHY_READ(sc, RUEPHY_MII_MSR) | PHY_READ(sc, RUEPHY_MII_MSR); 2533c374c15SSepherosa Ziehau if (msr & RUEPHY_MSR_LINK) 2543c374c15SSepherosa Ziehau mii->mii_media_status |= IFM_ACTIVE; 2553c374c15SSepherosa Ziehau 25646ad174eSSepherosa Ziehau bmcr = PHY_READ(sc, MII_BMCR); 2573c374c15SSepherosa Ziehau if (bmcr & BMCR_ISO) { 2583c374c15SSepherosa Ziehau mii->mii_media_active |= IFM_NONE; 2593c374c15SSepherosa Ziehau mii->mii_media_status = 0; 2603c374c15SSepherosa Ziehau return; 2613c374c15SSepherosa Ziehau } 2623c374c15SSepherosa Ziehau 26346ad174eSSepherosa Ziehau bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 2643c374c15SSepherosa Ziehau 2653c374c15SSepherosa Ziehau if (bmcr & BMCR_AUTOEN) { 2663c374c15SSepherosa Ziehau if ((bmsr & BMSR_ACOMP) == 0) { 2673c374c15SSepherosa Ziehau /* Erg, still trying, I guess... */ 2683c374c15SSepherosa Ziehau mii->mii_media_active |= IFM_NONE; 2693c374c15SSepherosa Ziehau return; 2703c374c15SSepherosa Ziehau } 2713c374c15SSepherosa Ziehau 2723c374c15SSepherosa Ziehau if (msr & RUEPHY_MSR_SPEED100) 2733c374c15SSepherosa Ziehau mii->mii_media_active |= IFM_100_TX; 2743c374c15SSepherosa Ziehau else 2753c374c15SSepherosa Ziehau mii->mii_media_active |= IFM_10_T; 2763c374c15SSepherosa Ziehau 2773c374c15SSepherosa Ziehau if (msr & RUEPHY_MSR_DUPLEX) 2783c374c15SSepherosa Ziehau mii->mii_media_active |= IFM_FDX; 27946ad174eSSepherosa Ziehau } else { 28046ad174eSSepherosa Ziehau mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media; 28146ad174eSSepherosa Ziehau } 2823c374c15SSepherosa Ziehau } 283