xref: /netbsd-src/sys/dev/mii/iophy.c (revision 7a9a30c5e763bb556f73924ae04973e33cc385da)
1*7a9a30c5Sthorpej /*	$NetBSD: iophy.c,v 1.43 2020/03/15 23:04:50 thorpej Exp $	*/
2b8e941e9Ssoren 
3b8e941e9Ssoren /*
449014bf5Sthorpej  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
5b8e941e9Ssoren  * All rights reserved.
6b8e941e9Ssoren  *
7b8e941e9Ssoren  * This code is derived from software contributed to The NetBSD Foundation
8b8e941e9Ssoren  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9b8e941e9Ssoren  * NASA Ames Research Center.
10b8e941e9Ssoren  *
11b8e941e9Ssoren  * Redistribution and use in source and binary forms, with or without
12b8e941e9Ssoren  * modification, are permitted provided that the following conditions
13b8e941e9Ssoren  * are met:
14b8e941e9Ssoren  * 1. Redistributions of source code must retain the above copyright
15b8e941e9Ssoren  *    notice, this list of conditions and the following disclaimer.
16b8e941e9Ssoren  * 2. Redistributions in binary form must reproduce the above copyright
17b8e941e9Ssoren  *    notice, this list of conditions and the following disclaimer in the
18b8e941e9Ssoren  *    documentation and/or other materials provided with the distribution.
19b8e941e9Ssoren  *
20b8e941e9Ssoren  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21b8e941e9Ssoren  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22b8e941e9Ssoren  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23b8e941e9Ssoren  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24b8e941e9Ssoren  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25b8e941e9Ssoren  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26b8e941e9Ssoren  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27b8e941e9Ssoren  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28b8e941e9Ssoren  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29b8e941e9Ssoren  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30b8e941e9Ssoren  * POSSIBILITY OF SUCH DAMAGE.
31b8e941e9Ssoren  */
32b8e941e9Ssoren 
33b8e941e9Ssoren /*
34b8e941e9Ssoren  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
35b8e941e9Ssoren  *
36b8e941e9Ssoren  * Redistribution and use in source and binary forms, with or without
37b8e941e9Ssoren  * modification, are permitted provided that the following conditions
38b8e941e9Ssoren  * are met:
39b8e941e9Ssoren  * 1. Redistributions of source code must retain the above copyright
40b8e941e9Ssoren  *    notice, this list of conditions and the following disclaimer.
41b8e941e9Ssoren  * 2. Redistributions in binary form must reproduce the above copyright
42b8e941e9Ssoren  *    notice, this list of conditions and the following disclaimer in the
43b8e941e9Ssoren  *    documentation and/or other materials provided with the distribution.
44b8e941e9Ssoren  *
45b8e941e9Ssoren  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46b8e941e9Ssoren  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47b8e941e9Ssoren  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48b8e941e9Ssoren  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49b8e941e9Ssoren  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50b8e941e9Ssoren  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51b8e941e9Ssoren  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52b8e941e9Ssoren  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53b8e941e9Ssoren  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54b8e941e9Ssoren  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55b8e941e9Ssoren  */
56b8e941e9Ssoren 
57b8e941e9Ssoren /*
58b8e941e9Ssoren  * Intel 82553 PHY driver
59b8e941e9Ssoren  */
60b8e941e9Ssoren 
618b7bb912Slukem #include <sys/cdefs.h>
62*7a9a30c5Sthorpej __KERNEL_RCSID(0, "$NetBSD: iophy.c,v 1.43 2020/03/15 23:04:50 thorpej Exp $");
638b7bb912Slukem 
64b8e941e9Ssoren #include <sys/param.h>
65b8e941e9Ssoren #include <sys/systm.h>
66b8e941e9Ssoren #include <sys/kernel.h>
67b8e941e9Ssoren #include <sys/device.h>
68b8e941e9Ssoren #include <sys/socket.h>
69b8e941e9Ssoren 
70b8e941e9Ssoren #include <net/if.h>
71b8e941e9Ssoren #include <net/if_media.h>
72b8e941e9Ssoren 
73b8e941e9Ssoren #include <dev/mii/mii.h>
74b8e941e9Ssoren #include <dev/mii/miivar.h>
75b8e941e9Ssoren #include <dev/mii/miidevs.h>
76b8e941e9Ssoren 
77b8e941e9Ssoren #include <dev/mii/iophyreg.h>
78b8e941e9Ssoren 
797db0e577Sxtraeme static int	iophymatch(device_t, cfdata_t, void *);
807db0e577Sxtraeme static void	iophyattach(device_t, device_t, void *);
81b8e941e9Ssoren 
827db0e577Sxtraeme CFATTACH_DECL_NEW(iophy, sizeof(struct mii_softc),
83c9b3657cSthorpej     iophymatch, iophyattach, mii_phy_detach, mii_phy_activate);
84b8e941e9Ssoren 
851efb3da0Sthorpej static int	iophy_service(struct mii_softc *, struct mii_data *, int);
861efb3da0Sthorpej static void	iophy_status(struct mii_softc *);
87b8e941e9Ssoren 
881efb3da0Sthorpej static const struct mii_phy_funcs iophy_funcs = {
8949014bf5Sthorpej 	iophy_service, iophy_status, mii_phy_reset,
9049014bf5Sthorpej };
9149014bf5Sthorpej 
921efb3da0Sthorpej static const struct mii_phydesc iophys[] = {
937b43da1bSchristos 	MII_PHY_DESC(xxINTEL, I82553),
947b43da1bSchristos 	MII_PHY_DESC(yyINTEL, I82553),
957b43da1bSchristos 	MII_PHY_END,
96424f7a1eSthorpej };
97424f7a1eSthorpej 
981efb3da0Sthorpej static int
iophymatch(device_t parent,cfdata_t match,void * aux)997db0e577Sxtraeme iophymatch(device_t parent, cfdata_t match, void *aux)
100b8e941e9Ssoren {
101b8e941e9Ssoren 	struct mii_attach_args *ma = aux;
102b8e941e9Ssoren 
103424f7a1eSthorpej 	if (mii_phy_match(ma, iophys) != NULL)
1048e65e831Smsaitoh 		return 10;
105b8e941e9Ssoren 
1068e65e831Smsaitoh 	return 0;
107b8e941e9Ssoren }
108b8e941e9Ssoren 
1091efb3da0Sthorpej static void
iophyattach(device_t parent,device_t self,void * aux)1107db0e577Sxtraeme iophyattach(device_t parent, device_t self, void *aux)
111b8e941e9Ssoren {
112838ee1e0Sthorpej 	struct mii_softc *sc = device_private(self);
113b8e941e9Ssoren 	struct mii_attach_args *ma = aux;
114b8e941e9Ssoren 	struct mii_data *mii = ma->mii_data;
115424f7a1eSthorpej 	const struct mii_phydesc *mpd;
116b8e941e9Ssoren 
117424f7a1eSthorpej 	mpd = mii_phy_match(ma, iophys);
118c31f87a5Sthorpej 	aprint_naive(": Media interface\n");
119c31f87a5Sthorpej 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
120b8e941e9Ssoren 
1217db0e577Sxtraeme 	sc->mii_dev = self;
122b8e941e9Ssoren 	sc->mii_inst = mii->mii_instance;
123b8e941e9Ssoren 	sc->mii_phy = ma->mii_phyno;
12449014bf5Sthorpej 	sc->mii_funcs = &iophy_funcs;
125b8e941e9Ssoren 	sc->mii_pdata = mii;
126b0178985Sthorpej 	sc->mii_flags = ma->mii_flags;
127b8e941e9Ssoren 
128*7a9a30c5Sthorpej 	mii_lock(mii);
129*7a9a30c5Sthorpej 
13049014bf5Sthorpej 	PHY_RESET(sc);
131b8e941e9Ssoren 
132a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
133a5cdd4b4Smsaitoh 	sc->mii_capabilities &= ma->mii_capmask;
134509697f3Smsaitoh 
135*7a9a30c5Sthorpej 	mii_unlock(mii);
136*7a9a30c5Sthorpej 
13784dc99fdSthorpej 	mii_phy_add_media(sc);
138b8e941e9Ssoren }
139b8e941e9Ssoren 
1401efb3da0Sthorpej static int
iophy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)14189893e42Sthorpej iophy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
142b8e941e9Ssoren {
143b8e941e9Ssoren 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
144a5cdd4b4Smsaitoh 	uint16_t reg;
145b8e941e9Ssoren 
146*7a9a30c5Sthorpej 	KASSERT(mii_locked(mii));
147*7a9a30c5Sthorpej 
148b8e941e9Ssoren 	switch (cmd) {
149b8e941e9Ssoren 	case MII_POLLSTAT:
1508e65e831Smsaitoh 		/* If we're not polling our PHY instance, just return. */
151b8e941e9Ssoren 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1528e65e831Smsaitoh 			return 0;
153b8e941e9Ssoren 		break;
154b8e941e9Ssoren 
155b8e941e9Ssoren 	case MII_MEDIACHG:
156b8e941e9Ssoren 		/*
157b8e941e9Ssoren 		 * If the media indicates a different PHY instance,
158b8e941e9Ssoren 		 * isolate ourselves.
159b8e941e9Ssoren 		 */
160b8e941e9Ssoren 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
161a5cdd4b4Smsaitoh 			PHY_READ(sc, MII_BMCR, &reg);
162b8e941e9Ssoren 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
1638e65e831Smsaitoh 			return 0;
164b8e941e9Ssoren 		}
165b8e941e9Ssoren 
1668e65e831Smsaitoh 		/* If the interface is not up, don't do anything. */
167b8e941e9Ssoren 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
168b8e941e9Ssoren 			break;
169b8e941e9Ssoren 
1708fc600c3Sthorpej 		mii_phy_setmedia(sc);
171b8e941e9Ssoren 		break;
172b8e941e9Ssoren 
173b8e941e9Ssoren 	case MII_TICK:
1748e65e831Smsaitoh 		/* If we're not currently selected, just return. */
175b8e941e9Ssoren 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1768e65e831Smsaitoh 			return 0;
177b8e941e9Ssoren 
178ad61d101Sthorpej 		if (mii_phy_tick(sc) == EJUSTRETURN)
1798e65e831Smsaitoh 			return 0;
180b8e941e9Ssoren 		break;
181bca88a28Sthorpej 
182bca88a28Sthorpej 	case MII_DOWN:
183bca88a28Sthorpej 		mii_phy_down(sc);
1848e65e831Smsaitoh 		return 0;
185b8e941e9Ssoren 	}
186b8e941e9Ssoren 
187b8e941e9Ssoren 	/* Update the media status. */
1888923ca0bSthorpej 	mii_phy_status(sc);
189b8e941e9Ssoren 
190b8e941e9Ssoren 	/* Callback if something changed. */
191ad61d101Sthorpej 	mii_phy_update(sc, cmd);
1928e65e831Smsaitoh 	return 0;
193b8e941e9Ssoren }
194b8e941e9Ssoren 
1951efb3da0Sthorpej static void
iophy_status(struct mii_softc * sc)19689893e42Sthorpej iophy_status(struct mii_softc *sc)
197b8e941e9Ssoren {
198b8e941e9Ssoren 	struct mii_data *mii = sc->mii_pdata;
1998fc600c3Sthorpej 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
200a5cdd4b4Smsaitoh 	uint16_t bmsr, bmcr, ext0;
201b8e941e9Ssoren 
202*7a9a30c5Sthorpej 	KASSERT(mii_locked(mii));
203*7a9a30c5Sthorpej 
204b8e941e9Ssoren 	mii->mii_media_status = IFM_AVALID;
205b8e941e9Ssoren 	mii->mii_media_active = IFM_ETHER;
206b8e941e9Ssoren 
207a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMSR, &bmsr);
208b8e941e9Ssoren 	if (bmsr & BMSR_LINK)
209b8e941e9Ssoren 		mii->mii_media_status |= IFM_ACTIVE;
210b8e941e9Ssoren 
211a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMCR, &bmcr);
212b8e941e9Ssoren 	if (bmcr & BMCR_ISO) {
213b8e941e9Ssoren 		mii->mii_media_active |= IFM_NONE;
214b8e941e9Ssoren 		mii->mii_media_status = 0;
215b8e941e9Ssoren 		return;
216b8e941e9Ssoren 	}
217b8e941e9Ssoren 
218b8e941e9Ssoren 	if (bmcr & BMCR_LOOP)
219b8e941e9Ssoren 		mii->mii_media_active |= IFM_LOOP;
220b8e941e9Ssoren 
221b8e941e9Ssoren 	if (bmcr & BMCR_AUTOEN) {
222b8e941e9Ssoren 		if ((bmsr & BMSR_ACOMP) == 0) {
223b8e941e9Ssoren 			/* Erg, still trying, I guess... */
224b8e941e9Ssoren 			mii->mii_media_active |= IFM_NONE;
225b8e941e9Ssoren 			return;
226b8e941e9Ssoren 		}
227a5cdd4b4Smsaitoh 		PHY_READ(sc, MII_IOPHY_EXT0, &ext0);
228b8e941e9Ssoren 
229add29455Scegger 		if (ext0 & EXT0_SPEED) {
2308e65e831Smsaitoh 			if ((bmsr & BMSR_100TXFDX) || (bmsr & BMSR_100TXHDX))
231b8e941e9Ssoren 				mii->mii_media_active |= IFM_100_TX;
2328e65e831Smsaitoh 			else if (bmsr & BMSR_100T4)
233add29455Scegger 				mii->mii_media_active |= IFM_100_T4;
234add29455Scegger 		} else
235b8e941e9Ssoren 			mii->mii_media_active |= IFM_10_T;
236b8e941e9Ssoren 
237b8e941e9Ssoren 		if (ext0 & EXT0_DUPLEX)
238b8e941e9Ssoren 			mii->mii_media_active |= IFM_FDX;
239b211437bSmsaitoh 		else
240b211437bSmsaitoh 			mii->mii_media_active |= IFM_HDX;
241b8e941e9Ssoren 	} else
2428fc600c3Sthorpej 		mii->mii_media_active = ife->ifm_media;
243b8e941e9Ssoren }
244