15fb1afd7SWarner Losh /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4f86e6000SWarner Losh * Copyright (c) 2009 M. Warner Losh <imp@FreeBSD.org>
55fb1afd7SWarner Losh *
65fb1afd7SWarner Losh * Redistribution and use in source and binary forms, with or without
75fb1afd7SWarner Losh * modification, are permitted provided that the following conditions
85fb1afd7SWarner Losh * are met:
95fb1afd7SWarner Losh * 1. Redistributions of source code must retain the above copyright
105fb1afd7SWarner Losh * notice unmodified, this list of conditions, and the following
115fb1afd7SWarner Losh * disclaimer.
125fb1afd7SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright
135fb1afd7SWarner Losh * notice, this list of conditions and the following disclaimer in the
145fb1afd7SWarner Losh * documentation and/or other materials provided with the distribution.
155fb1afd7SWarner Losh *
165fb1afd7SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
175fb1afd7SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
185fb1afd7SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
195fb1afd7SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
205fb1afd7SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
215fb1afd7SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
225fb1afd7SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
235fb1afd7SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
245fb1afd7SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
255fb1afd7SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
265fb1afd7SWarner Losh * SUCH DAMAGE.
275fb1afd7SWarner Losh */
285fb1afd7SWarner Losh #include <sys/cdefs.h>
295fb1afd7SWarner Losh /*
305fb1afd7SWarner Losh * driver for internal phy in the AX88x9x chips.
315fb1afd7SWarner Losh */
325fb1afd7SWarner Losh
335fb1afd7SWarner Losh #include <sys/param.h>
345fb1afd7SWarner Losh #include <sys/systm.h>
355fb1afd7SWarner Losh #include <sys/kernel.h>
365fb1afd7SWarner Losh #include <sys/module.h>
375fb1afd7SWarner Losh #include <sys/socket.h>
385fb1afd7SWarner Losh #include <sys/bus.h>
395fb1afd7SWarner Losh
405fb1afd7SWarner Losh #include <net/if.h>
415fb1afd7SWarner Losh #include <net/if_media.h>
425fb1afd7SWarner Losh
435fb1afd7SWarner Losh #include <dev/mii/mii.h>
445fb1afd7SWarner Losh #include <dev/mii/miivar.h>
455fb1afd7SWarner Losh #include "miidevs.h"
465fb1afd7SWarner Losh
475fb1afd7SWarner Losh #include "miibus_if.h"
485fb1afd7SWarner Losh
495fb1afd7SWarner Losh static int axphy_probe(device_t dev);
505fb1afd7SWarner Losh static int axphy_attach(device_t dev);
515fb1afd7SWarner Losh
525fb1afd7SWarner Losh static device_method_t axphy_methods[] = {
535fb1afd7SWarner Losh /* device interface */
545fb1afd7SWarner Losh DEVMETHOD(device_probe, axphy_probe),
555fb1afd7SWarner Losh DEVMETHOD(device_attach, axphy_attach),
565fb1afd7SWarner Losh DEVMETHOD(device_detach, mii_phy_detach),
575fb1afd7SWarner Losh DEVMETHOD(device_shutdown, bus_generic_shutdown),
58604f5f1fSMarius Strobl DEVMETHOD_END
595fb1afd7SWarner Losh };
605fb1afd7SWarner Losh
615fb1afd7SWarner Losh static driver_t axphy_driver = {
625fb1afd7SWarner Losh "axphy",
635fb1afd7SWarner Losh axphy_methods,
645fb1afd7SWarner Losh sizeof(struct mii_softc)
655fb1afd7SWarner Losh };
665fb1afd7SWarner Losh
67f438c2ffSJohn Baldwin DRIVER_MODULE(axphy, miibus, axphy_driver, 0, 0);
685fb1afd7SWarner Losh
695fb1afd7SWarner Losh static int axphy_service(struct mii_softc *, struct mii_data *, int);
705fb1afd7SWarner Losh static void axphy_status(struct mii_softc *);
715fb1afd7SWarner Losh
725fb1afd7SWarner Losh static const struct mii_phydesc axphys[] = {
733fcb7a53SMarius Strobl MII_PHY_DESC(xxASIX, AX88X9X),
745fb1afd7SWarner Losh MII_PHY_END
755fb1afd7SWarner Losh };
765fb1afd7SWarner Losh
773fcb7a53SMarius Strobl static const struct mii_phy_funcs axphy_funcs = {
783fcb7a53SMarius Strobl axphy_service,
793fcb7a53SMarius Strobl axphy_status,
803fcb7a53SMarius Strobl mii_phy_reset
813fcb7a53SMarius Strobl };
823fcb7a53SMarius Strobl
835fb1afd7SWarner Losh static int
axphy_probe(device_t dev)845fb1afd7SWarner Losh axphy_probe(device_t dev)
855fb1afd7SWarner Losh {
865fb1afd7SWarner Losh
875fb1afd7SWarner Losh return (mii_phy_dev_probe(dev, axphys, BUS_PROBE_DEFAULT));
885fb1afd7SWarner Losh }
895fb1afd7SWarner Losh
905fb1afd7SWarner Losh static int
axphy_attach(device_t dev)915fb1afd7SWarner Losh axphy_attach(device_t dev)
925fb1afd7SWarner Losh {
935fb1afd7SWarner Losh struct mii_softc *sc;
945fb1afd7SWarner Losh
955fb1afd7SWarner Losh sc = device_get_softc(dev);
965fb1afd7SWarner Losh
973fcb7a53SMarius Strobl mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE,
983fcb7a53SMarius Strobl &axphy_funcs, 1);
995fb1afd7SWarner Losh mii_phy_setmedia(sc);
1005fb1afd7SWarner Losh
1015fb1afd7SWarner Losh return (0);
1025fb1afd7SWarner Losh }
1035fb1afd7SWarner Losh
1045fb1afd7SWarner Losh static int
axphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)1055fb1afd7SWarner Losh axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
1065fb1afd7SWarner Losh {
1075fb1afd7SWarner Losh
1085fb1afd7SWarner Losh switch (cmd) {
1095fb1afd7SWarner Losh case MII_POLLSTAT:
1105fb1afd7SWarner Losh break;
1115fb1afd7SWarner Losh
1125fb1afd7SWarner Losh case MII_MEDIACHG:
1135fb1afd7SWarner Losh mii_phy_setmedia(sc);
1145fb1afd7SWarner Losh break;
1155fb1afd7SWarner Losh
1165fb1afd7SWarner Losh case MII_TICK:
1175fb1afd7SWarner Losh if (mii_phy_tick(sc) == EJUSTRETURN)
1185fb1afd7SWarner Losh return (0);
1195fb1afd7SWarner Losh break;
1205fb1afd7SWarner Losh }
1215fb1afd7SWarner Losh
1225fb1afd7SWarner Losh /* Update the media status. */
1233fcb7a53SMarius Strobl PHY_STATUS(sc);
1245fb1afd7SWarner Losh
1255fb1afd7SWarner Losh /* Callback if something changed. */
1265fb1afd7SWarner Losh mii_phy_update(sc, cmd);
1275fb1afd7SWarner Losh return (0);
1285fb1afd7SWarner Losh }
1295fb1afd7SWarner Losh
1305fb1afd7SWarner Losh static void
axphy_status(struct mii_softc * sc)1315fb1afd7SWarner Losh axphy_status(struct mii_softc *sc)
1325fb1afd7SWarner Losh {
1335fb1afd7SWarner Losh struct mii_data *mii = sc->mii_pdata;
1345fb1afd7SWarner Losh struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
1355fb1afd7SWarner Losh int bmsr, bmcr;
1365fb1afd7SWarner Losh
1375fb1afd7SWarner Losh mii->mii_media_status = IFM_AVALID;
1385fb1afd7SWarner Losh mii->mii_media_active = IFM_ETHER;
1395fb1afd7SWarner Losh
1405fb1afd7SWarner Losh bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
1415fb1afd7SWarner Losh if (bmsr & BMSR_LINK)
1425fb1afd7SWarner Losh mii->mii_media_status |= IFM_ACTIVE;
1435fb1afd7SWarner Losh
1445fb1afd7SWarner Losh bmcr = PHY_READ(sc, MII_BMCR);
1455fb1afd7SWarner Losh if (bmcr & BMCR_ISO) {
1465fb1afd7SWarner Losh mii->mii_media_active |= IFM_NONE;
1475fb1afd7SWarner Losh mii->mii_media_status = 0;
1485fb1afd7SWarner Losh return;
1495fb1afd7SWarner Losh }
1505fb1afd7SWarner Losh
1515fb1afd7SWarner Losh if (bmcr & BMCR_LOOP)
1525fb1afd7SWarner Losh mii->mii_media_active |= IFM_LOOP;
1535fb1afd7SWarner Losh
1545fb1afd7SWarner Losh if (bmcr & BMCR_AUTOEN) {
1555fb1afd7SWarner Losh if ((bmsr & BMSR_ACOMP) == 0) {
1565fb1afd7SWarner Losh mii->mii_media_active |= IFM_NONE;
1575fb1afd7SWarner Losh return;
1585fb1afd7SWarner Losh }
1595fb1afd7SWarner Losh
1605fb1afd7SWarner Losh #if 0
1615fb1afd7SWarner Losh scr = PHY_READ(sc, MII_AXPHY_SCR);
1625fb1afd7SWarner Losh if (scr & SCR_S100)
1635fb1afd7SWarner Losh mii->mii_media_active |= IFM_100_TX;
1645fb1afd7SWarner Losh else
1655fb1afd7SWarner Losh mii->mii_media_active |= IFM_10_T;
1665fb1afd7SWarner Losh if (scr & SCR_FDX)
1673fcb7a53SMarius Strobl mii->mii_media_active |=
1683fcb7a53SMarius Strobl IFM_FDX | mii_phy_flowstatus(sc);
169d7a9ad56SMarius Strobl else
170d7a9ad56SMarius Strobl mii->mii_media_active |= IFM_HDX;
1715fb1afd7SWarner Losh #endif
1725fb1afd7SWarner Losh } else
1735fb1afd7SWarner Losh mii->mii_media_active = ife->ifm_media;
1745fb1afd7SWarner Losh }
175