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 "miibus_if.h" 495fb1afd7SWarner Losh 505fb1afd7SWarner Losh static int axphy_probe(device_t dev); 515fb1afd7SWarner Losh static int axphy_attach(device_t dev); 525fb1afd7SWarner Losh 535fb1afd7SWarner Losh static device_method_t axphy_methods[] = { 545fb1afd7SWarner Losh /* device interface */ 555fb1afd7SWarner Losh DEVMETHOD(device_probe, axphy_probe), 565fb1afd7SWarner Losh DEVMETHOD(device_attach, axphy_attach), 575fb1afd7SWarner Losh DEVMETHOD(device_detach, mii_phy_detach), 585fb1afd7SWarner Losh DEVMETHOD(device_shutdown, bus_generic_shutdown), 59*604f5f1fSMarius Strobl DEVMETHOD_END 605fb1afd7SWarner Losh }; 615fb1afd7SWarner Losh 625fb1afd7SWarner Losh static devclass_t axphy_devclass; 635fb1afd7SWarner Losh 645fb1afd7SWarner Losh static driver_t axphy_driver = { 655fb1afd7SWarner Losh "axphy", 665fb1afd7SWarner Losh axphy_methods, 675fb1afd7SWarner Losh sizeof(struct mii_softc) 685fb1afd7SWarner Losh }; 695fb1afd7SWarner Losh 705fb1afd7SWarner Losh DRIVER_MODULE(axphy, miibus, axphy_driver, axphy_devclass, 0, 0); 715fb1afd7SWarner Losh 725fb1afd7SWarner Losh static int axphy_service(struct mii_softc *, struct mii_data *, int); 735fb1afd7SWarner Losh static void axphy_status(struct mii_softc *); 745fb1afd7SWarner Losh 755fb1afd7SWarner Losh static const struct mii_phydesc axphys[] = { 763fcb7a53SMarius Strobl MII_PHY_DESC(xxASIX, AX88X9X), 775fb1afd7SWarner Losh MII_PHY_END 785fb1afd7SWarner Losh }; 795fb1afd7SWarner Losh 803fcb7a53SMarius Strobl static const struct mii_phy_funcs axphy_funcs = { 813fcb7a53SMarius Strobl axphy_service, 823fcb7a53SMarius Strobl axphy_status, 833fcb7a53SMarius Strobl mii_phy_reset 843fcb7a53SMarius Strobl }; 853fcb7a53SMarius Strobl 865fb1afd7SWarner Losh static int 875fb1afd7SWarner Losh axphy_probe(device_t dev) 885fb1afd7SWarner Losh { 895fb1afd7SWarner Losh 905fb1afd7SWarner Losh return (mii_phy_dev_probe(dev, axphys, BUS_PROBE_DEFAULT)); 915fb1afd7SWarner Losh } 925fb1afd7SWarner Losh 935fb1afd7SWarner Losh static int 945fb1afd7SWarner Losh axphy_attach(device_t dev) 955fb1afd7SWarner Losh { 965fb1afd7SWarner Losh struct mii_softc *sc; 975fb1afd7SWarner Losh 985fb1afd7SWarner Losh sc = device_get_softc(dev); 995fb1afd7SWarner Losh 1003fcb7a53SMarius Strobl mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 1013fcb7a53SMarius Strobl &axphy_funcs, 1); 1025fb1afd7SWarner Losh mii_phy_setmedia(sc); 1035fb1afd7SWarner Losh 1045fb1afd7SWarner Losh return (0); 1055fb1afd7SWarner Losh } 1065fb1afd7SWarner Losh 1075fb1afd7SWarner Losh static int 1085fb1afd7SWarner Losh axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 1095fb1afd7SWarner Losh { 1105fb1afd7SWarner Losh 1115fb1afd7SWarner Losh switch (cmd) { 1125fb1afd7SWarner Losh case MII_POLLSTAT: 1135fb1afd7SWarner Losh break; 1145fb1afd7SWarner Losh 1155fb1afd7SWarner Losh case MII_MEDIACHG: 1165fb1afd7SWarner Losh /* 1175fb1afd7SWarner Losh * If the interface is not up, don't do anything. 1185fb1afd7SWarner Losh */ 1195fb1afd7SWarner Losh if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 1205fb1afd7SWarner Losh break; 1215fb1afd7SWarner Losh 1225fb1afd7SWarner Losh mii_phy_setmedia(sc); 1235fb1afd7SWarner Losh break; 1245fb1afd7SWarner Losh 1255fb1afd7SWarner Losh case MII_TICK: 1265fb1afd7SWarner Losh if (mii_phy_tick(sc) == EJUSTRETURN) 1275fb1afd7SWarner Losh return (0); 1285fb1afd7SWarner Losh break; 1295fb1afd7SWarner Losh } 1305fb1afd7SWarner Losh 1315fb1afd7SWarner Losh /* Update the media status. */ 1323fcb7a53SMarius Strobl PHY_STATUS(sc); 1335fb1afd7SWarner Losh 1345fb1afd7SWarner Losh /* Callback if something changed. */ 1355fb1afd7SWarner Losh mii_phy_update(sc, cmd); 1365fb1afd7SWarner Losh return (0); 1375fb1afd7SWarner Losh } 1385fb1afd7SWarner Losh 1395fb1afd7SWarner Losh static void 1405fb1afd7SWarner Losh axphy_status(struct mii_softc *sc) 1415fb1afd7SWarner Losh { 1425fb1afd7SWarner Losh struct mii_data *mii = sc->mii_pdata; 1435fb1afd7SWarner Losh struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 1445fb1afd7SWarner Losh int bmsr, bmcr; 1455fb1afd7SWarner Losh 1465fb1afd7SWarner Losh mii->mii_media_status = IFM_AVALID; 1475fb1afd7SWarner Losh mii->mii_media_active = IFM_ETHER; 1485fb1afd7SWarner Losh 1495fb1afd7SWarner Losh bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 1505fb1afd7SWarner Losh if (bmsr & BMSR_LINK) 1515fb1afd7SWarner Losh mii->mii_media_status |= IFM_ACTIVE; 1525fb1afd7SWarner Losh 1535fb1afd7SWarner Losh bmcr = PHY_READ(sc, MII_BMCR); 1545fb1afd7SWarner Losh if (bmcr & BMCR_ISO) { 1555fb1afd7SWarner Losh mii->mii_media_active |= IFM_NONE; 1565fb1afd7SWarner Losh mii->mii_media_status = 0; 1575fb1afd7SWarner Losh return; 1585fb1afd7SWarner Losh } 1595fb1afd7SWarner Losh 1605fb1afd7SWarner Losh if (bmcr & BMCR_LOOP) 1615fb1afd7SWarner Losh mii->mii_media_active |= IFM_LOOP; 1625fb1afd7SWarner Losh 1635fb1afd7SWarner Losh if (bmcr & BMCR_AUTOEN) { 1645fb1afd7SWarner Losh if ((bmsr & BMSR_ACOMP) == 0) { 1655fb1afd7SWarner Losh mii->mii_media_active |= IFM_NONE; 1665fb1afd7SWarner Losh return; 1675fb1afd7SWarner Losh } 1685fb1afd7SWarner Losh 1695fb1afd7SWarner Losh #if 0 1705fb1afd7SWarner Losh scr = PHY_READ(sc, MII_AXPHY_SCR); 1715fb1afd7SWarner Losh if (scr & SCR_S100) 1725fb1afd7SWarner Losh mii->mii_media_active |= IFM_100_TX; 1735fb1afd7SWarner Losh else 1745fb1afd7SWarner Losh mii->mii_media_active |= IFM_10_T; 1755fb1afd7SWarner Losh if (scr & SCR_FDX) 1763fcb7a53SMarius Strobl mii->mii_media_active |= 1773fcb7a53SMarius Strobl IFM_FDX | mii_phy_flowstatus(sc); 178d7a9ad56SMarius Strobl else 179d7a9ad56SMarius Strobl mii->mii_media_active |= IFM_HDX; 1805fb1afd7SWarner Losh #endif 1815fb1afd7SWarner Losh } else 1825fb1afd7SWarner Losh mii->mii_media_active = ife->ifm_media; 1835fb1afd7SWarner Losh } 184