xref: /netbsd-src/sys/dev/mii/inphy.c (revision 7a9a30c5e763bb556f73924ae04973e33cc385da)
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, &reg);
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