15fb1afd7SWarner Losh /*- 2*718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*718cf2ccSPedro F. Giffuni * 45fb1afd7SWarner Losh * Copyright (c) 2009, M. Warner Losh 55fb1afd7SWarner Losh * All rights reserved. 65fb1afd7SWarner Losh * 75fb1afd7SWarner Losh * Redistribution and use in source and binary forms, with or without 85fb1afd7SWarner Losh * modification, are permitted provided that the following conditions 95fb1afd7SWarner Losh * are met: 105fb1afd7SWarner Losh * 1. Redistributions of source code must retain the above copyright 115fb1afd7SWarner Losh * notice unmodified, this list of conditions, and the following 125fb1afd7SWarner Losh * disclaimer. 135fb1afd7SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 145fb1afd7SWarner Losh * notice, this list of conditions and the following disclaimer in the 155fb1afd7SWarner Losh * documentation and/or other materials provided with the distribution. 165fb1afd7SWarner Losh * 175fb1afd7SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 185fb1afd7SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 195fb1afd7SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 205fb1afd7SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 215fb1afd7SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 225fb1afd7SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 235fb1afd7SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 245fb1afd7SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 255fb1afd7SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 265fb1afd7SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 275fb1afd7SWarner Losh * SUCH DAMAGE. 285fb1afd7SWarner Losh */ 295fb1afd7SWarner Losh #include <sys/cdefs.h> 305fb1afd7SWarner Losh __FBSDID("$FreeBSD$"); 315fb1afd7SWarner Losh 325fb1afd7SWarner Losh /* 335fb1afd7SWarner Losh * driver for internal phy in the AX88x9x chips. 345fb1afd7SWarner Losh */ 355fb1afd7SWarner Losh 365fb1afd7SWarner Losh #include <sys/param.h> 375fb1afd7SWarner Losh #include <sys/systm.h> 385fb1afd7SWarner Losh #include <sys/kernel.h> 395fb1afd7SWarner Losh #include <sys/module.h> 405fb1afd7SWarner Losh #include <sys/socket.h> 415fb1afd7SWarner Losh #include <sys/bus.h> 425fb1afd7SWarner Losh 435fb1afd7SWarner Losh #include <net/if.h> 445fb1afd7SWarner Losh #include <net/if_media.h> 455fb1afd7SWarner Losh 465fb1afd7SWarner Losh #include <dev/mii/mii.h> 475fb1afd7SWarner Losh #include <dev/mii/miivar.h> 485fb1afd7SWarner Losh #include "miidevs.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), 61604f5f1fSMarius Strobl DEVMETHOD_END 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[] = { 783fcb7a53SMarius Strobl MII_PHY_DESC(xxASIX, AX88X9X), 795fb1afd7SWarner Losh MII_PHY_END 805fb1afd7SWarner Losh }; 815fb1afd7SWarner Losh 823fcb7a53SMarius Strobl static const struct mii_phy_funcs axphy_funcs = { 833fcb7a53SMarius Strobl axphy_service, 843fcb7a53SMarius Strobl axphy_status, 853fcb7a53SMarius Strobl mii_phy_reset 863fcb7a53SMarius Strobl }; 873fcb7a53SMarius Strobl 885fb1afd7SWarner Losh static int 895fb1afd7SWarner Losh axphy_probe(device_t dev) 905fb1afd7SWarner Losh { 915fb1afd7SWarner Losh 925fb1afd7SWarner Losh return (mii_phy_dev_probe(dev, axphys, BUS_PROBE_DEFAULT)); 935fb1afd7SWarner Losh } 945fb1afd7SWarner Losh 955fb1afd7SWarner Losh static int 965fb1afd7SWarner Losh axphy_attach(device_t dev) 975fb1afd7SWarner Losh { 985fb1afd7SWarner Losh struct mii_softc *sc; 995fb1afd7SWarner Losh 1005fb1afd7SWarner Losh sc = device_get_softc(dev); 1015fb1afd7SWarner Losh 1023fcb7a53SMarius Strobl mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 1033fcb7a53SMarius Strobl &axphy_funcs, 1); 1045fb1afd7SWarner Losh mii_phy_setmedia(sc); 1055fb1afd7SWarner Losh 1065fb1afd7SWarner Losh return (0); 1075fb1afd7SWarner Losh } 1085fb1afd7SWarner Losh 1095fb1afd7SWarner Losh static int 1105fb1afd7SWarner Losh axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 1115fb1afd7SWarner Losh { 1125fb1afd7SWarner Losh 1135fb1afd7SWarner Losh switch (cmd) { 1145fb1afd7SWarner Losh case MII_POLLSTAT: 1155fb1afd7SWarner Losh break; 1165fb1afd7SWarner Losh 1175fb1afd7SWarner Losh case MII_MEDIACHG: 1185fb1afd7SWarner Losh mii_phy_setmedia(sc); 1195fb1afd7SWarner Losh break; 1205fb1afd7SWarner Losh 1215fb1afd7SWarner Losh case MII_TICK: 1225fb1afd7SWarner Losh if (mii_phy_tick(sc) == EJUSTRETURN) 1235fb1afd7SWarner Losh return (0); 1245fb1afd7SWarner Losh break; 1255fb1afd7SWarner Losh } 1265fb1afd7SWarner Losh 1275fb1afd7SWarner Losh /* Update the media status. */ 1283fcb7a53SMarius Strobl PHY_STATUS(sc); 1295fb1afd7SWarner Losh 1305fb1afd7SWarner Losh /* Callback if something changed. */ 1315fb1afd7SWarner Losh mii_phy_update(sc, cmd); 1325fb1afd7SWarner Losh return (0); 1335fb1afd7SWarner Losh } 1345fb1afd7SWarner Losh 1355fb1afd7SWarner Losh static void 1365fb1afd7SWarner Losh axphy_status(struct mii_softc *sc) 1375fb1afd7SWarner Losh { 1385fb1afd7SWarner Losh struct mii_data *mii = sc->mii_pdata; 1395fb1afd7SWarner Losh struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 1405fb1afd7SWarner Losh int bmsr, bmcr; 1415fb1afd7SWarner Losh 1425fb1afd7SWarner Losh mii->mii_media_status = IFM_AVALID; 1435fb1afd7SWarner Losh mii->mii_media_active = IFM_ETHER; 1445fb1afd7SWarner Losh 1455fb1afd7SWarner Losh bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 1465fb1afd7SWarner Losh if (bmsr & BMSR_LINK) 1475fb1afd7SWarner Losh mii->mii_media_status |= IFM_ACTIVE; 1485fb1afd7SWarner Losh 1495fb1afd7SWarner Losh bmcr = PHY_READ(sc, MII_BMCR); 1505fb1afd7SWarner Losh if (bmcr & BMCR_ISO) { 1515fb1afd7SWarner Losh mii->mii_media_active |= IFM_NONE; 1525fb1afd7SWarner Losh mii->mii_media_status = 0; 1535fb1afd7SWarner Losh return; 1545fb1afd7SWarner Losh } 1555fb1afd7SWarner Losh 1565fb1afd7SWarner Losh if (bmcr & BMCR_LOOP) 1575fb1afd7SWarner Losh mii->mii_media_active |= IFM_LOOP; 1585fb1afd7SWarner Losh 1595fb1afd7SWarner Losh if (bmcr & BMCR_AUTOEN) { 1605fb1afd7SWarner Losh if ((bmsr & BMSR_ACOMP) == 0) { 1615fb1afd7SWarner Losh mii->mii_media_active |= IFM_NONE; 1625fb1afd7SWarner Losh return; 1635fb1afd7SWarner Losh } 1645fb1afd7SWarner Losh 1655fb1afd7SWarner Losh #if 0 1665fb1afd7SWarner Losh scr = PHY_READ(sc, MII_AXPHY_SCR); 1675fb1afd7SWarner Losh if (scr & SCR_S100) 1685fb1afd7SWarner Losh mii->mii_media_active |= IFM_100_TX; 1695fb1afd7SWarner Losh else 1705fb1afd7SWarner Losh mii->mii_media_active |= IFM_10_T; 1715fb1afd7SWarner Losh if (scr & SCR_FDX) 1723fcb7a53SMarius Strobl mii->mii_media_active |= 1733fcb7a53SMarius Strobl IFM_FDX | mii_phy_flowstatus(sc); 174d7a9ad56SMarius Strobl else 175d7a9ad56SMarius Strobl mii->mii_media_active |= IFM_HDX; 1765fb1afd7SWarner Losh #endif 1775fb1afd7SWarner Losh } else 1785fb1afd7SWarner Losh mii->mii_media_active = ife->ifm_media; 1795fb1afd7SWarner Losh } 180