1*7a9a30c5Sthorpej /* $NetBSD: inphy.c,v 1.60 2020/03/15 23:04:50 thorpej Exp $ */
26bae1a0bSthorpej
36bae1a0bSthorpej /*-
449014bf5Sthorpej * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
56bae1a0bSthorpej * All rights reserved.
66bae1a0bSthorpej *
76bae1a0bSthorpej * This code is derived from software contributed to The NetBSD Foundation
86bae1a0bSthorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
96bae1a0bSthorpej * NASA Ames Research Center.
106bae1a0bSthorpej *
116bae1a0bSthorpej * Redistribution and use in source and binary forms, with or without
126bae1a0bSthorpej * modification, are permitted provided that the following conditions
136bae1a0bSthorpej * are met:
146bae1a0bSthorpej * 1. Redistributions of source code must retain the above copyright
156bae1a0bSthorpej * notice, this list of conditions and the following disclaimer.
166bae1a0bSthorpej * 2. Redistributions in binary form must reproduce the above copyright
176bae1a0bSthorpej * notice, this list of conditions and the following disclaimer in the
186bae1a0bSthorpej * documentation and/or other materials provided with the distribution.
196bae1a0bSthorpej *
206bae1a0bSthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
216bae1a0bSthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
226bae1a0bSthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
236bae1a0bSthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
246bae1a0bSthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
256bae1a0bSthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
266bae1a0bSthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
276bae1a0bSthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
286bae1a0bSthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
296bae1a0bSthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
306bae1a0bSthorpej * POSSIBILITY OF SUCH DAMAGE.
316bae1a0bSthorpej */
326bae1a0bSthorpej
336bae1a0bSthorpej /*
346bae1a0bSthorpej * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
356bae1a0bSthorpej *
366bae1a0bSthorpej * Redistribution and use in source and binary forms, with or without
376bae1a0bSthorpej * modification, are permitted provided that the following conditions
386bae1a0bSthorpej * are met:
396bae1a0bSthorpej * 1. Redistributions of source code must retain the above copyright
406bae1a0bSthorpej * notice, this list of conditions and the following disclaimer.
416bae1a0bSthorpej * 2. Redistributions in binary form must reproduce the above copyright
426bae1a0bSthorpej * notice, this list of conditions and the following disclaimer in the
436bae1a0bSthorpej * documentation and/or other materials provided with the distribution.
446bae1a0bSthorpej *
456bae1a0bSthorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
466bae1a0bSthorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
476bae1a0bSthorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
486bae1a0bSthorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
496bae1a0bSthorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
506bae1a0bSthorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
516bae1a0bSthorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
526bae1a0bSthorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
536bae1a0bSthorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
546bae1a0bSthorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
556bae1a0bSthorpej */
566bae1a0bSthorpej
576bae1a0bSthorpej /*
586bae1a0bSthorpej * driver for Intel's i82555 ethernet 10/100 PHY
596bae1a0bSthorpej * Data Sheet available from www.intel.com
606bae1a0bSthorpej */
616bae1a0bSthorpej
628b7bb912Slukem #include <sys/cdefs.h>
63*7a9a30c5Sthorpej __KERNEL_RCSID(0, "$NetBSD: inphy.c,v 1.60 2020/03/15 23:04:50 thorpej Exp $");
648b7bb912Slukem
656bae1a0bSthorpej #include <sys/param.h>
666bae1a0bSthorpej #include <sys/systm.h>
676bae1a0bSthorpej #include <sys/kernel.h>
686bae1a0bSthorpej #include <sys/device.h>
696bae1a0bSthorpej #include <sys/socket.h>
7083f9ab3cSthorpej #include <sys/errno.h>
716bae1a0bSthorpej
726bae1a0bSthorpej #include <net/if.h>
736bae1a0bSthorpej #include <net/if_media.h>
746bae1a0bSthorpej
756bae1a0bSthorpej #include <dev/mii/mii.h>
766bae1a0bSthorpej #include <dev/mii/miivar.h>
776bae1a0bSthorpej #include <dev/mii/miidevs.h>
786bae1a0bSthorpej
796bae1a0bSthorpej #include <dev/mii/inphyreg.h>
806bae1a0bSthorpej
817db0e577Sxtraeme static int inphymatch(device_t, cfdata_t, void *);
827db0e577Sxtraeme static void inphyattach(device_t, device_t, void *);
836bae1a0bSthorpej
847db0e577Sxtraeme CFATTACH_DECL_NEW(inphy, sizeof(struct mii_softc),
85c9b3657cSthorpej inphymatch, inphyattach, mii_phy_detach, mii_phy_activate);
866bae1a0bSthorpej
871efb3da0Sthorpej static int inphy_service(struct mii_softc *, struct mii_data *, int);
881efb3da0Sthorpej static void inphy_status(struct mii_softc *);
896bae1a0bSthorpej
901efb3da0Sthorpej static const struct mii_phy_funcs inphy_funcs = {
9149014bf5Sthorpej inphy_service, inphy_status, mii_phy_reset,
9249014bf5Sthorpej };
9349014bf5Sthorpej
941efb3da0Sthorpej static const struct mii_phydesc inphys[] = {
957b43da1bSchristos MII_PHY_DESC(yyINTEL, I82555),
967b43da1bSchristos MII_PHY_DESC(yyINTEL, I82562EH),
977b43da1bSchristos MII_PHY_DESC(yyINTEL, I82562EM),
987b43da1bSchristos MII_PHY_DESC(yyINTEL, I82562ET),
997b43da1bSchristos MII_PHY_DESC(yyINTEL, I82562G),
1007b43da1bSchristos MII_PHY_END,
101424f7a1eSthorpej };
102424f7a1eSthorpej
1031efb3da0Sthorpej static int
inphymatch(device_t parent,cfdata_t match,void * aux)1047db0e577Sxtraeme inphymatch(device_t parent, cfdata_t match, void *aux)
1056bae1a0bSthorpej {
1066bae1a0bSthorpej struct mii_attach_args *ma = aux;
1076bae1a0bSthorpej
108424f7a1eSthorpej if (mii_phy_match(ma, inphys) != NULL)
1098e65e831Smsaitoh return 10;
1106bae1a0bSthorpej
1118e65e831Smsaitoh return 0;
1126bae1a0bSthorpej }
1136bae1a0bSthorpej
1141efb3da0Sthorpej static void
inphyattach(device_t parent,device_t self,void * aux)1157db0e577Sxtraeme inphyattach(device_t parent, device_t self, void *aux)
1166bae1a0bSthorpej {
117838ee1e0Sthorpej struct mii_softc *sc = device_private(self);
1186bae1a0bSthorpej struct mii_attach_args *ma = aux;
1196bae1a0bSthorpej struct mii_data *mii = ma->mii_data;
120424f7a1eSthorpej const struct mii_phydesc *mpd;
1216bae1a0bSthorpej
122424f7a1eSthorpej mpd = mii_phy_match(ma, inphys);
123c31f87a5Sthorpej aprint_naive(": Media interface\n");
124c31f87a5Sthorpej aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
1256bae1a0bSthorpej
1267db0e577Sxtraeme sc->mii_dev = self;
1272a17544cSthorpej sc->mii_inst = mii->mii_instance;
1282a17544cSthorpej sc->mii_phy = ma->mii_phyno;
129bb76968eSmsaitoh sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
130bb76968eSmsaitoh sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
131bb76968eSmsaitoh sc->mii_mpd_rev = MII_REV(ma->mii_id2);
13249014bf5Sthorpej sc->mii_funcs = &inphy_funcs;
1332a17544cSthorpej sc->mii_pdata = mii;
134b0178985Sthorpej sc->mii_flags = ma->mii_flags;
13551da8fc3Sthorpej
136*7a9a30c5Sthorpej mii_lock(mii);
137*7a9a30c5Sthorpej
13849014bf5Sthorpej PHY_RESET(sc);
1396bae1a0bSthorpej
140a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
141a5cdd4b4Smsaitoh sc->mii_capabilities &= ma->mii_capmask;
142509697f3Smsaitoh
143*7a9a30c5Sthorpej mii_unlock(mii);
144*7a9a30c5Sthorpej
14584dc99fdSthorpej mii_phy_add_media(sc);
1466bae1a0bSthorpej }
1476bae1a0bSthorpej
1481efb3da0Sthorpej static int
inphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)14989893e42Sthorpej inphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
1506bae1a0bSthorpej {
1511f074c78Sthorpej struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
152a5cdd4b4Smsaitoh uint16_t reg;
1536bae1a0bSthorpej
154*7a9a30c5Sthorpej KASSERT(mii_locked(mii));
155*7a9a30c5Sthorpej
1566bae1a0bSthorpej switch (cmd) {
1576bae1a0bSthorpej case MII_POLLSTAT:
1588e65e831Smsaitoh /* If we're not polling our PHY instance, just return. */
1592a17544cSthorpej if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1608e65e831Smsaitoh return 0;
1616bae1a0bSthorpej break;
1626bae1a0bSthorpej
1636bae1a0bSthorpej case MII_MEDIACHG:
1646bae1a0bSthorpej /*
1656bae1a0bSthorpej * If the media indicates a different PHY instance,
1666bae1a0bSthorpej * isolate ourselves.
1676bae1a0bSthorpej */
1682a17544cSthorpej if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
169a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMCR, ®);
1702a17544cSthorpej PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
1718e65e831Smsaitoh return 0;
1726bae1a0bSthorpej }
1736bae1a0bSthorpej
1748e65e831Smsaitoh /* If the interface is not up, don't do anything. */
1756bae1a0bSthorpej if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
1766bae1a0bSthorpej break;
1776bae1a0bSthorpej
1788fc600c3Sthorpej mii_phy_setmedia(sc);
1796bae1a0bSthorpej break;
1806bae1a0bSthorpej
1816bae1a0bSthorpej case MII_TICK:
1828e65e831Smsaitoh /* If we're not currently selected, just return. */
1832a17544cSthorpej if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1848e65e831Smsaitoh return 0;
1856bae1a0bSthorpej
186ad61d101Sthorpej if (mii_phy_tick(sc) == EJUSTRETURN)
1878e65e831Smsaitoh return 0;
1886bae1a0bSthorpej break;
189bca88a28Sthorpej
190bca88a28Sthorpej case MII_DOWN:
191bca88a28Sthorpej mii_phy_down(sc);
1928e65e831Smsaitoh return 0;
1936bae1a0bSthorpej }
1946bae1a0bSthorpej
1956bae1a0bSthorpej /* Update the media status. */
1968923ca0bSthorpej mii_phy_status(sc);
1976bae1a0bSthorpej
1986bae1a0bSthorpej /* Callback if something changed. */
199ad61d101Sthorpej mii_phy_update(sc, cmd);
2008e65e831Smsaitoh return 0;
2016bae1a0bSthorpej }
2026bae1a0bSthorpej
2031efb3da0Sthorpej static void
inphy_status(struct mii_softc * sc)20489893e42Sthorpej inphy_status(struct mii_softc *sc)
2056bae1a0bSthorpej {
2062a17544cSthorpej struct mii_data *mii = sc->mii_pdata;
2078fc600c3Sthorpej struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
208a5cdd4b4Smsaitoh uint16_t bmsr, bmcr, scr;
2096bae1a0bSthorpej
210*7a9a30c5Sthorpej KASSERT(mii_locked(mii));
211*7a9a30c5Sthorpej
2126bae1a0bSthorpej mii->mii_media_status = IFM_AVALID;
2136bae1a0bSthorpej mii->mii_media_active = IFM_ETHER;
2146bae1a0bSthorpej
215a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMSR, &bmsr);
216a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMSR, &bmsr);
2176bae1a0bSthorpej if (bmsr & BMSR_LINK)
2186bae1a0bSthorpej mii->mii_media_status |= IFM_ACTIVE;
2196bae1a0bSthorpej
220a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMCR, &bmcr);
2216bae1a0bSthorpej if (bmcr & BMCR_ISO) {
2226bae1a0bSthorpej mii->mii_media_active |= IFM_NONE;
2236bae1a0bSthorpej mii->mii_media_status = 0;
2246bae1a0bSthorpej return;
2256bae1a0bSthorpej }
2266bae1a0bSthorpej
2276bae1a0bSthorpej if (bmcr & BMCR_LOOP)
2286bae1a0bSthorpej mii->mii_media_active |= IFM_LOOP;
2296bae1a0bSthorpej
2306bae1a0bSthorpej if (bmcr & BMCR_AUTOEN) {
231981f0cd0Sthorpej if ((bmsr & BMSR_ACOMP) == 0) {
232981f0cd0Sthorpej /* Erg, still trying, I guess... */
233981f0cd0Sthorpej mii->mii_media_active |= IFM_NONE;
234981f0cd0Sthorpej return;
235981f0cd0Sthorpej }
23671e27a6eSmrg
237a5cdd4b4Smsaitoh PHY_READ(sc, MII_INPHY_SCR, &scr);
238add29455Scegger if (scr & SCR_S100)
2396bae1a0bSthorpej mii->mii_media_active |= IFM_100_TX;
240add29455Scegger else if ((bmsr & BMSR_100T4) && (scr & SCR_T4))
241add29455Scegger mii->mii_media_active |= IFM_100_T4;
2426bae1a0bSthorpej else
2436bae1a0bSthorpej mii->mii_media_active |= IFM_10_T;
244b211437bSmsaitoh
2456bae1a0bSthorpej if (scr & SCR_FDX)
2466bae1a0bSthorpej mii->mii_media_active |= IFM_FDX;
247b211437bSmsaitoh else
248b211437bSmsaitoh mii->mii_media_active |= IFM_HDX;
24971e27a6eSmrg
25071e27a6eSmrg if (mii->mii_media_active & IFM_FDX)
25171e27a6eSmrg mii->mii_media_active |= mii_phy_flowstatus(sc);
2522b695df1Sthorpej } else
2538fc600c3Sthorpej mii->mii_media_active = ife->ifm_media;
2546bae1a0bSthorpej }
255