15fb1afd7SWarner Losh /*- 25fb1afd7SWarner Losh * Copyright (c) 2009, M. Warner Losh 35fb1afd7SWarner Losh * All rights reserved. 45fb1afd7SWarner Losh * 55fb1afd7SWarner Losh * Redistribution and use in source and binary forms, with or without 65fb1afd7SWarner Losh * modification, are permitted provided that the following conditions 75fb1afd7SWarner Losh * are met: 85fb1afd7SWarner Losh * 1. Redistributions of source code must retain the above copyright 95fb1afd7SWarner Losh * notice unmodified, this list of conditions, and the following 105fb1afd7SWarner Losh * disclaimer. 115fb1afd7SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 125fb1afd7SWarner Losh * notice, this list of conditions and the following disclaimer in the 135fb1afd7SWarner Losh * documentation and/or other materials provided with the distribution. 145fb1afd7SWarner Losh * 155fb1afd7SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 165fb1afd7SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 175fb1afd7SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 185fb1afd7SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 195fb1afd7SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 205fb1afd7SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 215fb1afd7SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 225fb1afd7SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 235fb1afd7SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 245fb1afd7SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 255fb1afd7SWarner Losh * SUCH DAMAGE. 265fb1afd7SWarner Losh */ 275fb1afd7SWarner Losh #include <sys/cdefs.h> 285fb1afd7SWarner Losh __FBSDID("$FreeBSD$"); 295fb1afd7SWarner Losh 305fb1afd7SWarner Losh /* 315fb1afd7SWarner Losh * driver for internal phy in the AX88x9x chips. 325fb1afd7SWarner Losh */ 335fb1afd7SWarner Losh 345fb1afd7SWarner Losh #include <sys/param.h> 355fb1afd7SWarner Losh #include <sys/systm.h> 365fb1afd7SWarner Losh #include <sys/kernel.h> 375fb1afd7SWarner Losh #include <sys/module.h> 385fb1afd7SWarner Losh #include <sys/socket.h> 395fb1afd7SWarner Losh #include <sys/bus.h> 405fb1afd7SWarner Losh 415fb1afd7SWarner Losh #include <net/if.h> 425fb1afd7SWarner Losh #include <net/if_media.h> 435fb1afd7SWarner Losh 445fb1afd7SWarner Losh #include <dev/mii/mii.h> 455fb1afd7SWarner Losh #include <dev/mii/miivar.h> 465fb1afd7SWarner Losh #include "miidevs.h" 475fb1afd7SWarner Losh 485fb1afd7SWarner Losh #include <dev/mii/axphyreg.h> 495fb1afd7SWarner Losh 505fb1afd7SWarner Losh #include "miibus_if.h" 515fb1afd7SWarner Losh 525fb1afd7SWarner Losh static int axphy_probe(device_t dev); 535fb1afd7SWarner Losh static int axphy_attach(device_t dev); 545fb1afd7SWarner Losh 555fb1afd7SWarner Losh static device_method_t axphy_methods[] = { 565fb1afd7SWarner Losh /* device interface */ 575fb1afd7SWarner Losh DEVMETHOD(device_probe, axphy_probe), 585fb1afd7SWarner Losh DEVMETHOD(device_attach, axphy_attach), 595fb1afd7SWarner Losh DEVMETHOD(device_detach, mii_phy_detach), 605fb1afd7SWarner Losh DEVMETHOD(device_shutdown, bus_generic_shutdown), 615fb1afd7SWarner Losh { 0, 0 } 625fb1afd7SWarner Losh }; 635fb1afd7SWarner Losh 645fb1afd7SWarner Losh static devclass_t axphy_devclass; 655fb1afd7SWarner Losh 665fb1afd7SWarner Losh static driver_t axphy_driver = { 675fb1afd7SWarner Losh "axphy", 685fb1afd7SWarner Losh axphy_methods, 695fb1afd7SWarner Losh sizeof(struct mii_softc) 705fb1afd7SWarner Losh }; 715fb1afd7SWarner Losh 725fb1afd7SWarner Losh DRIVER_MODULE(axphy, miibus, axphy_driver, axphy_devclass, 0, 0); 735fb1afd7SWarner Losh 745fb1afd7SWarner Losh static int axphy_service(struct mii_softc *, struct mii_data *, int); 755fb1afd7SWarner Losh static void axphy_status(struct mii_softc *); 765fb1afd7SWarner Losh 775fb1afd7SWarner Losh static const struct mii_phydesc axphys[] = { 785fb1afd7SWarner Losh MII_PHY_DESC(ASIX, AX88X9X), 795fb1afd7SWarner Losh MII_PHY_END 805fb1afd7SWarner Losh }; 815fb1afd7SWarner Losh 825fb1afd7SWarner Losh static int 835fb1afd7SWarner Losh axphy_probe(device_t dev) 845fb1afd7SWarner Losh { 855fb1afd7SWarner Losh 865fb1afd7SWarner Losh return (mii_phy_dev_probe(dev, axphys, BUS_PROBE_DEFAULT)); 875fb1afd7SWarner Losh } 885fb1afd7SWarner Losh 895fb1afd7SWarner Losh static int 905fb1afd7SWarner Losh axphy_attach(device_t dev) 915fb1afd7SWarner Losh { 925fb1afd7SWarner Losh struct mii_softc *sc; 935fb1afd7SWarner Losh struct mii_attach_args *ma; 945fb1afd7SWarner Losh struct mii_data *mii; 955fb1afd7SWarner Losh 965fb1afd7SWarner Losh sc = device_get_softc(dev); 975fb1afd7SWarner Losh ma = device_get_ivars(dev); 985fb1afd7SWarner Losh sc->mii_dev = device_get_parent(dev); 995fb1afd7SWarner Losh mii = device_get_softc(sc->mii_dev); 1005fb1afd7SWarner Losh LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 1015fb1afd7SWarner Losh 1025fb1afd7SWarner Losh sc->mii_inst = mii->mii_instance; 1035fb1afd7SWarner Losh sc->mii_phy = ma->mii_phyno; 1045fb1afd7SWarner Losh sc->mii_service = axphy_service; 1055fb1afd7SWarner Losh sc->mii_pdata = mii; 1065fb1afd7SWarner Losh sc->mii_flags |= MIIF_NOISOLATE; 1075fb1afd7SWarner Losh mii->mii_instance++; 1085fb1afd7SWarner Losh 1095fb1afd7SWarner Losh mii_phy_reset(sc); 1105fb1afd7SWarner Losh 1115fb1afd7SWarner Losh sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 1125fb1afd7SWarner Losh device_printf(dev, " "); 1135fb1afd7SWarner Losh mii_phy_add_media(sc); 1145fb1afd7SWarner Losh printf("\n"); 1155fb1afd7SWarner Losh 1165fb1afd7SWarner Losh MIIBUS_MEDIAINIT(sc->mii_dev); 1175fb1afd7SWarner Losh mii_phy_setmedia(sc); 1185fb1afd7SWarner Losh 1195fb1afd7SWarner Losh return (0); 1205fb1afd7SWarner Losh } 1215fb1afd7SWarner Losh 1225fb1afd7SWarner Losh static int 1235fb1afd7SWarner Losh axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 1245fb1afd7SWarner Losh { 1255fb1afd7SWarner Losh struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 1265fb1afd7SWarner Losh int reg; 1275fb1afd7SWarner Losh 1285fb1afd7SWarner Losh switch (cmd) { 1295fb1afd7SWarner Losh case MII_POLLSTAT: 1305fb1afd7SWarner Losh if (IFM_INST(ife->ifm_media) != sc->mii_inst) 1315fb1afd7SWarner Losh return (0); 1325fb1afd7SWarner Losh break; 1335fb1afd7SWarner Losh 1345fb1afd7SWarner Losh case MII_MEDIACHG: 1355fb1afd7SWarner Losh if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 1365fb1afd7SWarner Losh reg = PHY_READ(sc, MII_BMCR); 1375fb1afd7SWarner Losh PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 1385fb1afd7SWarner Losh return (0); 1395fb1afd7SWarner Losh } 1405fb1afd7SWarner Losh 1415fb1afd7SWarner Losh /* 1425fb1afd7SWarner Losh * If the interface is not up, don't do anything. 1435fb1afd7SWarner Losh */ 1445fb1afd7SWarner Losh if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 1455fb1afd7SWarner Losh break; 1465fb1afd7SWarner Losh 1475fb1afd7SWarner Losh mii_phy_setmedia(sc); 1485fb1afd7SWarner Losh break; 1495fb1afd7SWarner Losh 1505fb1afd7SWarner Losh case MII_TICK: 1515fb1afd7SWarner Losh if (IFM_INST(ife->ifm_media) != sc->mii_inst) 1525fb1afd7SWarner Losh return (0); 1535fb1afd7SWarner Losh if (mii_phy_tick(sc) == EJUSTRETURN) 1545fb1afd7SWarner Losh return (0); 1555fb1afd7SWarner Losh break; 1565fb1afd7SWarner Losh } 1575fb1afd7SWarner Losh 1585fb1afd7SWarner Losh /* Update the media status. */ 1595fb1afd7SWarner Losh axphy_status(sc); 1605fb1afd7SWarner Losh 1615fb1afd7SWarner Losh /* Callback if something changed. */ 1625fb1afd7SWarner Losh mii_phy_update(sc, cmd); 1635fb1afd7SWarner Losh return (0); 1645fb1afd7SWarner Losh } 1655fb1afd7SWarner Losh 1665fb1afd7SWarner Losh static void 1675fb1afd7SWarner Losh axphy_status(struct mii_softc *sc) 1685fb1afd7SWarner Losh { 1695fb1afd7SWarner Losh struct mii_data *mii = sc->mii_pdata; 1705fb1afd7SWarner Losh struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 1715fb1afd7SWarner Losh int bmsr, bmcr; 1725fb1afd7SWarner Losh 1735fb1afd7SWarner Losh mii->mii_media_status = IFM_AVALID; 1745fb1afd7SWarner Losh mii->mii_media_active = IFM_ETHER; 1755fb1afd7SWarner Losh 1765fb1afd7SWarner Losh bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 1775fb1afd7SWarner Losh if (bmsr & BMSR_LINK) 1785fb1afd7SWarner Losh mii->mii_media_status |= IFM_ACTIVE; 1795fb1afd7SWarner Losh 1805fb1afd7SWarner Losh bmcr = PHY_READ(sc, MII_BMCR); 1815fb1afd7SWarner Losh if (bmcr & BMCR_ISO) { 1825fb1afd7SWarner Losh mii->mii_media_active |= IFM_NONE; 1835fb1afd7SWarner Losh mii->mii_media_status = 0; 1845fb1afd7SWarner Losh return; 1855fb1afd7SWarner Losh } 1865fb1afd7SWarner Losh 1875fb1afd7SWarner Losh if (bmcr & BMCR_LOOP) 1885fb1afd7SWarner Losh mii->mii_media_active |= IFM_LOOP; 1895fb1afd7SWarner Losh 1905fb1afd7SWarner Losh if (bmcr & BMCR_AUTOEN) { 1915fb1afd7SWarner Losh if ((bmsr & BMSR_ACOMP) == 0) { 1925fb1afd7SWarner Losh mii->mii_media_active |= IFM_NONE; 1935fb1afd7SWarner Losh return; 1945fb1afd7SWarner Losh } 1955fb1afd7SWarner Losh 1965fb1afd7SWarner Losh #if 0 1975fb1afd7SWarner Losh scr = PHY_READ(sc, MII_AXPHY_SCR); 1985fb1afd7SWarner Losh if (scr & SCR_S100) 1995fb1afd7SWarner Losh mii->mii_media_active |= IFM_100_TX; 2005fb1afd7SWarner Losh else 2015fb1afd7SWarner Losh mii->mii_media_active |= IFM_10_T; 2025fb1afd7SWarner Losh if (scr & SCR_FDX) 2035fb1afd7SWarner Losh mii->mii_media_active |= IFM_FDX; 2045fb1afd7SWarner Losh #endif 2055fb1afd7SWarner Losh } else 2065fb1afd7SWarner Losh mii->mii_media_active = ife->ifm_media; 2075fb1afd7SWarner Losh } 208