xref: /netbsd-src/sys/dev/mii/micphy.c (revision 1214ec155bd02ecc8b9550143dfce80889710870)
1*1214ec15Sjmcneill /*	$NetBSD: micphy.c,v 1.15 2022/10/31 22:45:13 jmcneill Exp $	*/
2bc17336aSozaki-r 
3bc17336aSozaki-r /*-
4bc17336aSozaki-r  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
5bc17336aSozaki-r  * All rights reserved.
6bc17336aSozaki-r  *
7bc17336aSozaki-r  * This code is derived from software contributed to The NetBSD Foundation
8bc17336aSozaki-r  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9bc17336aSozaki-r  * NASA Ames Research Center, and by Frank van der Linden.
10bc17336aSozaki-r  *
11bc17336aSozaki-r  * Redistribution and use in source and binary forms, with or without
12bc17336aSozaki-r  * modification, are permitted provided that the following conditions
13bc17336aSozaki-r  * are met:
14bc17336aSozaki-r  * 1. Redistributions of source code must retain the above copyright
15bc17336aSozaki-r  *    notice, this list of conditions and the following disclaimer.
16bc17336aSozaki-r  * 2. Redistributions in binary form must reproduce the above copyright
17bc17336aSozaki-r  *    notice, this list of conditions and the following disclaimer in the
18bc17336aSozaki-r  *    documentation and/or other materials provided with the distribution.
19bc17336aSozaki-r  *
20bc17336aSozaki-r  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21bc17336aSozaki-r  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22bc17336aSozaki-r  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23bc17336aSozaki-r  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24bc17336aSozaki-r  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25bc17336aSozaki-r  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26bc17336aSozaki-r  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27bc17336aSozaki-r  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28bc17336aSozaki-r  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29bc17336aSozaki-r  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30bc17336aSozaki-r  * POSSIBILITY OF SUCH DAMAGE.
31bc17336aSozaki-r  */
32bc17336aSozaki-r 
33bc17336aSozaki-r /*
34bc17336aSozaki-r  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
35bc17336aSozaki-r  *
36bc17336aSozaki-r  * Redistribution and use in source and binary forms, with or without
37bc17336aSozaki-r  * modification, are permitted provided that the following conditions
38bc17336aSozaki-r  * are met:
39bc17336aSozaki-r  * 1. Redistributions of source code must retain the above copyright
40bc17336aSozaki-r  *    notice, this list of conditions and the following disclaimer.
41bc17336aSozaki-r  * 2. Redistributions in binary form must reproduce the above copyright
42bc17336aSozaki-r  *    notice, this list of conditions and the following disclaimer in the
43bc17336aSozaki-r  *    documentation and/or other materials provided with the distribution.
44bc17336aSozaki-r  *
45bc17336aSozaki-r  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46bc17336aSozaki-r  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47bc17336aSozaki-r  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48bc17336aSozaki-r  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49bc17336aSozaki-r  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50bc17336aSozaki-r  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51bc17336aSozaki-r  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52bc17336aSozaki-r  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53bc17336aSozaki-r  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54bc17336aSozaki-r  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55bc17336aSozaki-r  */
56bc17336aSozaki-r 
57bc17336aSozaki-r /*
589068f29fSmsaitoh  * Driver for Micrel KSZ8xxx 10/100 and KSZ9xxx 10/100/1000 PHY.
59bc17336aSozaki-r  */
60bc17336aSozaki-r 
61bc17336aSozaki-r #include <sys/cdefs.h>
62*1214ec15Sjmcneill __KERNEL_RCSID(0, "$NetBSD: micphy.c,v 1.15 2022/10/31 22:45:13 jmcneill Exp $");
63bc17336aSozaki-r 
64bc17336aSozaki-r #include "opt_mii.h"
65bc17336aSozaki-r 
66bc17336aSozaki-r #include <sys/param.h>
67bc17336aSozaki-r #include <sys/systm.h>
68bc17336aSozaki-r #include <sys/kernel.h>
69bc17336aSozaki-r #include <sys/device.h>
70bc17336aSozaki-r #include <sys/socket.h>
71bc17336aSozaki-r #include <sys/errno.h>
72bc17336aSozaki-r 
73bc17336aSozaki-r #include <net/if.h>
74bc17336aSozaki-r #include <net/if_media.h>
75bc17336aSozaki-r 
76bc17336aSozaki-r #include <dev/mii/mii.h>
77bc17336aSozaki-r #include <dev/mii/miivar.h>
78bc17336aSozaki-r #include <dev/mii/miidevs.h>
79bc17336aSozaki-r 
80bc17336aSozaki-r static int	micphymatch(device_t, cfdata_t, void *);
81bc17336aSozaki-r static void	micphyattach(device_t, device_t, void *);
82f16620c1Smsaitoh static void	micphy_reset(struct mii_softc *);
83f16620c1Smsaitoh static int	micphy_service(struct mii_softc *, struct mii_data *, int);
84bc17336aSozaki-r 
8568e9e41eSthorpej CFATTACH_DECL_NEW(micphy, sizeof(struct mii_softc),
8668e9e41eSthorpej     micphymatch, micphyattach, mii_phy_detach, mii_phy_activate);
87bc17336aSozaki-r 
88bc17336aSozaki-r static int	micphy_service(struct mii_softc *, struct mii_data *, int);
899068f29fSmsaitoh static void	micphy_status(struct mii_softc *);
90bc17336aSozaki-r static void	micphy_fixup(struct mii_softc *, int, int, device_t);
91bc17336aSozaki-r 
92bc17336aSozaki-r static const struct mii_phy_funcs micphy_funcs = {
939068f29fSmsaitoh 	micphy_service, micphy_status, micphy_reset,
949068f29fSmsaitoh };
959068f29fSmsaitoh 
969068f29fSmsaitoh struct micphy_softc {
979068f29fSmsaitoh 	struct mii_softc sc_mii;
989068f29fSmsaitoh 	uint32_t sc_lstype;	/* Type of link status register */
99bc17336aSozaki-r };
100bc17336aSozaki-r 
101bc17336aSozaki-r static const struct mii_phydesc micphys[] = {
1029068f29fSmsaitoh 	MII_PHY_DESC(MICREL, KSZ8041),
1039068f29fSmsaitoh 	MII_PHY_DESC(MICREL, KSZ8051), /* +8021,8031 */
1049068f29fSmsaitoh 	MII_PHY_DESC(MICREL, KSZ8061),
1059068f29fSmsaitoh 	MII_PHY_DESC(MICREL, KSZ8081), /* +8051,8091 */
1069068f29fSmsaitoh 	MII_PHY_DESC(MICREL, KS8737),
1079068f29fSmsaitoh 	MII_PHY_DESC(MICREL, KSZ9021_8001_8721),
1089068f29fSmsaitoh 	MII_PHY_DESC(MICREL, KSZ9031),
1099068f29fSmsaitoh 	MII_PHY_DESC(MICREL, KSZ9131),
1109068f29fSmsaitoh 	MII_PHY_DESC(MICREL, KSZ9477), /* +LAN7430internal */
1117b43da1bSchristos 	MII_PHY_END,
112bc17336aSozaki-r };
113bc17336aSozaki-r 
1149068f29fSmsaitoh /*
1159068f29fSmsaitoh  * Model Rev. Media  LSTYPE Devices
1169068f29fSmsaitoh  *
1179068f29fSmsaitoh  * 0x11	      100    1F_42  KSZ8041
1189068f29fSmsaitoh  * 0x13	      100    1F_42? KSZ8041RNLI
1199068f29fSmsaitoh  * 0x15	   ?  100    1E_20  KSZ8051
1209068f29fSmsaitoh  * 	 0x5  100    1E_20  KSZ8021
1219068f29fSmsaitoh  * 	 0x6  100    1E_20  KSZ8031
1229068f29fSmsaitoh  * 0x16	   ?  100    1E_20  KSZ8081
1239068f29fSmsaitoh  * 	   ?  100    1E_20  KSZ8091
1249068f29fSmsaitoh  * 0x17	      100    1E_20  KSZ8061
1259068f29fSmsaitoh  * 0x21	 0x0  giga   GIGA   KSZ9021
1269068f29fSmsaitoh  * 	 0x1  giga   GIGA   KSZ9021RLRN
1279068f29fSmsaitoh  * 	 0x9  100    1F_42  KSZ8721BL/SL
1289068f29fSmsaitoh  * 	 0x9  100    none?  KSZ8721CL
1299068f29fSmsaitoh  * 	 0xa  100    1F_42  KSZ8001
1309068f29fSmsaitoh  * 0x22	      giga   GIGA   KSZ9031
1319068f29fSmsaitoh  * 0x23	   1? gigasw GIGA   KSZ9477 (No master/slave bit)
1329068f29fSmsaitoh  * 	   5? giga   GIGA   LAN7430internal
1339068f29fSmsaitoh  * 0x24	      giga   GIGA   KSZ9131
1349068f29fSmsaitoh  * 0x32	      100    1F_42  KS8737
1359068f29fSmsaitoh  */
1369068f29fSmsaitoh 
1379068f29fSmsaitoh /* Type of link status register */
1389068f29fSmsaitoh #define MICPHYF_LSTYPE_DEFAULT	0
1399068f29fSmsaitoh #define MICPHYF_LSTYPE_1F_42	1
1409068f29fSmsaitoh #define MICPHYF_LSTYPE_1E_20	2
1419068f29fSmsaitoh #define MICPHYF_LSTYPE_GIGA	3
1429068f29fSmsaitoh 
1439068f29fSmsaitoh /* Return if the device is Gigabit (KSZ9021) */
1449068f29fSmsaitoh #define KSZ_MODEL21H_GIGA(rev)			\
1459068f29fSmsaitoh 	((((rev) & 0x0e) == 0) ? true : false)
1469068f29fSmsaitoh 
1479068f29fSmsaitoh #define KSZ_XREG_CONTROL	0x0b
1489068f29fSmsaitoh #define KSZ_XREG_WRITE		0x0c
1499068f29fSmsaitoh #define KSZ_XREG_READ		0x0d
1509068f29fSmsaitoh #define KSZ_XREG_CTL_SEL_READ	0x0000
1519068f29fSmsaitoh #define KSZ_XREG_CTL_SEL_WRITE	0x8000
1529068f29fSmsaitoh 
1539068f29fSmsaitoh #define REG_RGMII_CLOCK_AND_CONTROL	0x104
1549068f29fSmsaitoh #define REG_RGMII_RX_DATA		0x105
1559068f29fSmsaitoh 
1569068f29fSmsaitoh /* PHY control 1 register for 10/100 PHYs (KSZ80[235689]1) */
1579068f29fSmsaitoh #define KSZ8051_PHYCTL1		0x1e
1589068f29fSmsaitoh #define KSZ8051_PHY_LINK	0x0100
1599068f29fSmsaitoh #define KSZ8051_PHY_MDIX	0x0020
1609068f29fSmsaitoh #define KSZ8051_PHY_FDX		0x0004
1619068f29fSmsaitoh #define KSZ8051_PHY_SPD_MASK	0x0003
1629068f29fSmsaitoh #define KSZ8051_PHY_SPD_10T	0x0001
1639068f29fSmsaitoh #define KSZ8051_PHY_SPD_100TX	0x0002
1649068f29fSmsaitoh 
1659068f29fSmsaitoh /* PHY control 2 register for 10/100 PHYs (KSZ8041, KSZ8721 and KSZ8001) */
1669068f29fSmsaitoh #define	KSZ8041_PHYCTL2		0x1f
1679068f29fSmsaitoh #define KSZ8041_PHY_ACOMP	0x0080
1689068f29fSmsaitoh #define KSZ8041_PHY_SPD_MASK	0x001c
1699068f29fSmsaitoh #define KSZ8041_PHY_SPD_10T	0x0004
1709068f29fSmsaitoh #define KSZ8041_PHY_SPD_100TX	0x0008
1719068f29fSmsaitoh #define KSZ8041_PHY_FDX		0x0010
1729068f29fSmsaitoh #define KSZ8051_PHYCTL2		0x1f
1739068f29fSmsaitoh 
1749068f29fSmsaitoh /* PHY control register for Gigabit PHYs */
1759068f29fSmsaitoh #define KSZ_GPHYCTL		0x1f
1769068f29fSmsaitoh #define KSZ_GPHY_SPD_1000T	0x0040
1779068f29fSmsaitoh #define KSZ_GPHY_SPD_100TX	0x0020
1789068f29fSmsaitoh #define KSZ_GPHY_SPD_10T	0x0010
1799068f29fSmsaitoh #define KSZ_GPHY_FDX		0x0008
1809068f29fSmsaitoh #define KSZ_GPHY_1000T_MS	0x0004
181f16620c1Smsaitoh 
182bc17336aSozaki-r static int
micphymatch(device_t parent,cfdata_t match,void * aux)183bc17336aSozaki-r micphymatch(device_t parent, cfdata_t match, void *aux)
184bc17336aSozaki-r {
185bc17336aSozaki-r 	struct mii_attach_args *ma = aux;
186bc17336aSozaki-r 
187bc17336aSozaki-r 	if (mii_phy_match(ma, micphys) != NULL)
188bc17336aSozaki-r 		return 10;
189bc17336aSozaki-r 
190bc17336aSozaki-r 	return 1;
191bc17336aSozaki-r }
192bc17336aSozaki-r 
193bc17336aSozaki-r static void
micphyattach(device_t parent,device_t self,void * aux)194bc17336aSozaki-r micphyattach(device_t parent, device_t self, void *aux)
195bc17336aSozaki-r {
1969068f29fSmsaitoh 	struct micphy_softc *msc = device_private(self);
1979068f29fSmsaitoh 	struct mii_softc *sc = &msc->sc_mii;
198bc17336aSozaki-r 	struct mii_attach_args *ma = aux;
199bc17336aSozaki-r 	struct mii_data *mii = ma->mii_data;
200bc17336aSozaki-r 	int model = MII_MODEL(ma->mii_id2);
201bc17336aSozaki-r 	int rev = MII_REV(ma->mii_id2);
202bc17336aSozaki-r 	const struct mii_phydesc *mpd;
203bc17336aSozaki-r 
204bc17336aSozaki-r 	mpd = mii_phy_match(ma, micphys);
205bc17336aSozaki-r 	aprint_naive(": Media interface\n");
206bc17336aSozaki-r 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, rev);
207bc17336aSozaki-r 
208bc17336aSozaki-r 	sc->mii_dev = self;
209bc17336aSozaki-r 	sc->mii_inst = mii->mii_instance;
210bc17336aSozaki-r 	sc->mii_phy = ma->mii_phyno;
211bc17336aSozaki-r 	sc->mii_funcs = &micphy_funcs;
212bc17336aSozaki-r 	sc->mii_pdata = mii;
213bc17336aSozaki-r 	sc->mii_flags = ma->mii_flags;
214bc17336aSozaki-r 
2159068f29fSmsaitoh 	if ((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8041)
2169068f29fSmsaitoh 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8041RNLI)
2179068f29fSmsaitoh 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KS8737)
2189068f29fSmsaitoh 	    || ((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9021_8001_8721)
2199068f29fSmsaitoh 		&& !KSZ_MODEL21H_GIGA(sc->mii_mpd_rev))) {
2209068f29fSmsaitoh 		msc->sc_lstype = MICPHYF_LSTYPE_1F_42;
2219068f29fSmsaitoh 	} else if ((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8051)
2229068f29fSmsaitoh 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081)
2239068f29fSmsaitoh 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8061)) {
2249068f29fSmsaitoh 		msc->sc_lstype = MICPHYF_LSTYPE_1E_20;
2259068f29fSmsaitoh 	} else if (((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9021_8001_8721)
2269068f29fSmsaitoh 		&& KSZ_MODEL21H_GIGA(sc->mii_mpd_rev))
2279068f29fSmsaitoh 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9031)
2289068f29fSmsaitoh 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9477)
2299068f29fSmsaitoh 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9131)) {
2309068f29fSmsaitoh 		msc->sc_lstype = MICPHYF_LSTYPE_GIGA;
2319068f29fSmsaitoh 	} else
2329068f29fSmsaitoh 		msc->sc_lstype = MICPHYF_LSTYPE_DEFAULT;
2339068f29fSmsaitoh 
2347a9a30c5Sthorpej 	mii_lock(mii);
2357a9a30c5Sthorpej 
236bc17336aSozaki-r 	PHY_RESET(sc);
237bc17336aSozaki-r 
238bc17336aSozaki-r 	micphy_fixup(sc, model, rev, parent);
239bc17336aSozaki-r 
24018a9b5c8Sskrll 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
24118a9b5c8Sskrll 	sc->mii_capabilities &= ma->mii_capmask;
242bc17336aSozaki-r 	if (sc->mii_capabilities & BMSR_EXTSTAT)
24318a9b5c8Sskrll 		PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
244509697f3Smsaitoh 
2457a9a30c5Sthorpej 	mii_unlock(mii);
2467a9a30c5Sthorpej 
247bc17336aSozaki-r 	mii_phy_add_media(sc);
248bc17336aSozaki-r }
249bc17336aSozaki-r 
250f16620c1Smsaitoh static void
micphy_reset(struct mii_softc * sc)251f16620c1Smsaitoh micphy_reset(struct mii_softc *sc)
252f16620c1Smsaitoh {
253f16620c1Smsaitoh 	uint16_t reg;
254f16620c1Smsaitoh 
2557a9a30c5Sthorpej 	KASSERT(mii_locked(sc->mii_pdata));
2567a9a30c5Sthorpej 
257f16620c1Smsaitoh 	/*
25802341723Smsaitoh 	 * The 8081 has no "sticky bits" that survive a soft reset; several
25902341723Smsaitoh 	 * bits in the Phy Control Register 2 must be preserved across the
26002341723Smsaitoh 	 * reset. These bits are set up by the bootloader; they control how the
26102341723Smsaitoh 	 * phy interfaces to the board (such as clock frequency and LED
26202341723Smsaitoh 	 * behavior).
263f16620c1Smsaitoh 	 */
264f16620c1Smsaitoh 	if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081)
2659068f29fSmsaitoh 		PHY_READ(sc, KSZ8051_PHYCTL2, &reg);
266f16620c1Smsaitoh 	mii_phy_reset(sc);
267f16620c1Smsaitoh 	if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081)
2689068f29fSmsaitoh 		PHY_WRITE(sc, KSZ8051_PHYCTL2, reg);
269f16620c1Smsaitoh }
270f16620c1Smsaitoh 
271bc17336aSozaki-r static int
micphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)272bc17336aSozaki-r micphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
273bc17336aSozaki-r {
274bc17336aSozaki-r 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
27518a9b5c8Sskrll 	uint16_t reg;
276bc17336aSozaki-r 
2777a9a30c5Sthorpej 	KASSERT(mii_locked(mii));
2787a9a30c5Sthorpej 
279bc17336aSozaki-r 	switch (cmd) {
280bc17336aSozaki-r 	case MII_POLLSTAT:
28102341723Smsaitoh 		/* If we're not polling our PHY instance, just return. */
282bc17336aSozaki-r 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
283bc17336aSozaki-r 			return 0;
284bc17336aSozaki-r 		break;
285bc17336aSozaki-r 
286bc17336aSozaki-r 	case MII_MEDIACHG:
287bc17336aSozaki-r 		/*
288bc17336aSozaki-r 		 * If the media indicates a different PHY instance,
289bc17336aSozaki-r 		 * isolate ourselves.
290bc17336aSozaki-r 		 */
291bc17336aSozaki-r 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
29218a9b5c8Sskrll 			PHY_READ(sc, MII_BMCR, &reg);
293bc17336aSozaki-r 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
294bc17336aSozaki-r 			return 0;
295bc17336aSozaki-r 		}
296bc17336aSozaki-r 
29702341723Smsaitoh 		/* If the interface is not up, don't do anything. */
298bc17336aSozaki-r 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
299bc17336aSozaki-r 			break;
300bc17336aSozaki-r 
301bc17336aSozaki-r 		mii_phy_setmedia(sc);
302bc17336aSozaki-r 		break;
303bc17336aSozaki-r 
304bc17336aSozaki-r 	case MII_TICK:
30502341723Smsaitoh 		/* If we're not currently selected, just return. */
306bc17336aSozaki-r 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
307bc17336aSozaki-r 			return 0;
308bc17336aSozaki-r 
309bc17336aSozaki-r 		if (mii_phy_tick(sc) == EJUSTRETURN)
310bc17336aSozaki-r 			return 0;
311bc17336aSozaki-r 		break;
312bc17336aSozaki-r 
313bc17336aSozaki-r 	case MII_DOWN:
314bc17336aSozaki-r 		mii_phy_down(sc);
315bc17336aSozaki-r 		return 0;
316bc17336aSozaki-r 	}
317bc17336aSozaki-r 
318bc17336aSozaki-r 	/* Update the media status. */
319bc17336aSozaki-r 	mii_phy_status(sc);
320bc17336aSozaki-r 
321bc17336aSozaki-r 	/* Callback if something changed. */
322bc17336aSozaki-r 	mii_phy_update(sc, cmd);
323bc17336aSozaki-r 	return 0;
324bc17336aSozaki-r }
325bc17336aSozaki-r 
32602341723Smsaitoh static void
micphy_writexreg(struct mii_softc * sc,uint32_t reg,uint32_t wval)32702341723Smsaitoh micphy_writexreg(struct mii_softc *sc, uint32_t reg, uint32_t wval)
328bc17336aSozaki-r {
32918a9b5c8Sskrll 	uint16_t rval __debugused;
330bc17336aSozaki-r 
3319068f29fSmsaitoh 	PHY_WRITE(sc, KSZ_XREG_CONTROL, KSZ_XREG_CTL_SEL_WRITE | reg);
3329068f29fSmsaitoh 	PHY_WRITE(sc, KSZ_XREG_WRITE, wval);
3339068f29fSmsaitoh 	PHY_WRITE(sc, KSZ_XREG_CONTROL, KSZ_XREG_CTL_SEL_READ | reg);
3349068f29fSmsaitoh 	PHY_READ(sc, KSZ_XREG_READ, &rval);
335bc17336aSozaki-r 	KDASSERT(wval == rval);
336bc17336aSozaki-r }
337bc17336aSozaki-r 
338bc17336aSozaki-r static void
micphy_fixup(struct mii_softc * sc,int model,int rev,device_t parent)339bc17336aSozaki-r micphy_fixup(struct mii_softc *sc, int model, int rev, device_t parent)
340bc17336aSozaki-r {
3417a9a30c5Sthorpej 
3427a9a30c5Sthorpej 	KASSERT(mii_locked(sc->mii_pdata));
3437a9a30c5Sthorpej 
344bc17336aSozaki-r 	switch (model) {
3459068f29fSmsaitoh 	case MII_MODEL_MICREL_KSZ9021_8001_8721:
346bc17336aSozaki-r 		if (!device_is_a(parent, "cpsw"))
347bc17336aSozaki-r 			break;
348bc17336aSozaki-r 
34902341723Smsaitoh 		aprint_normal_dev(sc->mii_dev,
35002341723Smsaitoh 		    "adjusting RGMII signal timing for cpsw\n");
351bc17336aSozaki-r 
352bc17336aSozaki-r 		// RGMII RX Data Pad Skew
353bc17336aSozaki-r 		micphy_writexreg(sc, REG_RGMII_RX_DATA, 0x0000);
354bc17336aSozaki-r 
355bc17336aSozaki-r 		// RGMII Clock and Control Pad Skew
356bc17336aSozaki-r 		micphy_writexreg(sc, REG_RGMII_CLOCK_AND_CONTROL, 0x9090);
357bc17336aSozaki-r 
358bc17336aSozaki-r 		break;
35902341723Smsaitoh 	default:
36002341723Smsaitoh 		break;
361bc17336aSozaki-r 	}
362bc17336aSozaki-r 
363bc17336aSozaki-r 	return;
364bc17336aSozaki-r }
3659068f29fSmsaitoh 
3669068f29fSmsaitoh static void
micphy_status(struct mii_softc * sc)3679068f29fSmsaitoh micphy_status(struct mii_softc *sc)
3689068f29fSmsaitoh {
3699068f29fSmsaitoh 	struct micphy_softc *msc = device_private(sc->mii_dev);
3709068f29fSmsaitoh 	struct mii_data *mii = sc->mii_pdata;
3719068f29fSmsaitoh 	uint16_t bmsr, bmcr, sr;
3729068f29fSmsaitoh 
3737a9a30c5Sthorpej 	KASSERT(mii_locked(mii));
3747a9a30c5Sthorpej 
3759068f29fSmsaitoh 	/* For unknown devices */
3769068f29fSmsaitoh 	if (msc->sc_lstype == MICPHYF_LSTYPE_DEFAULT) {
3779068f29fSmsaitoh 		ukphy_status(sc);
3789068f29fSmsaitoh 		return;
3799068f29fSmsaitoh 	}
3809068f29fSmsaitoh 
3819068f29fSmsaitoh 	mii->mii_media_status = IFM_AVALID;
3829068f29fSmsaitoh 	mii->mii_media_active = IFM_ETHER;
3839068f29fSmsaitoh 
3849068f29fSmsaitoh 	PHY_READ(sc, MII_BMCR, &bmcr);
3859068f29fSmsaitoh 
3869068f29fSmsaitoh 	PHY_READ(sc, MII_BMSR, &bmsr);
3879068f29fSmsaitoh 	PHY_READ(sc, MII_BMSR, &bmsr);
3889068f29fSmsaitoh 	if (bmsr & BMSR_LINK)
3899068f29fSmsaitoh 		mii->mii_media_status |= IFM_ACTIVE;
3909068f29fSmsaitoh 
3919068f29fSmsaitoh 	if (bmcr & BMCR_AUTOEN) {
3929068f29fSmsaitoh 		if ((bmsr & BMSR_ACOMP) == 0) {
3939068f29fSmsaitoh 			mii->mii_media_active |= IFM_NONE;
3949068f29fSmsaitoh 			return;
3959068f29fSmsaitoh 		}
3969068f29fSmsaitoh 	}
3979068f29fSmsaitoh 
3989068f29fSmsaitoh 	if (msc->sc_lstype == MICPHYF_LSTYPE_1F_42) {
3999068f29fSmsaitoh 		PHY_READ(sc, KSZ8041_PHYCTL2, &sr);
4009068f29fSmsaitoh 		if ((sr & KSZ8041_PHY_SPD_MASK) == 0)
4019068f29fSmsaitoh 			mii->mii_media_active |= IFM_NONE;
4029068f29fSmsaitoh 		else if (sr & KSZ8041_PHY_SPD_100TX)
4039068f29fSmsaitoh 			mii->mii_media_active |= IFM_100_TX;
4049068f29fSmsaitoh 		else if (sr & KSZ8041_PHY_SPD_10T)
4059068f29fSmsaitoh 			mii->mii_media_active |= IFM_10_T;
4069068f29fSmsaitoh 		if (sr & KSZ8041_PHY_FDX)
4079068f29fSmsaitoh 			mii->mii_media_active |= IFM_FDX
4089068f29fSmsaitoh 			    | mii_phy_flowstatus(sc);
4099068f29fSmsaitoh 	} else if (msc->sc_lstype == MICPHYF_LSTYPE_1E_20) {
4109068f29fSmsaitoh 		PHY_READ(sc, KSZ8051_PHYCTL1, &sr);
4119068f29fSmsaitoh 		if ((sr & KSZ8051_PHY_SPD_MASK) == 0)
4129068f29fSmsaitoh 			mii->mii_media_active |= IFM_NONE;
4139068f29fSmsaitoh 		else if (sr & KSZ8051_PHY_SPD_100TX)
4149068f29fSmsaitoh 			mii->mii_media_active |= IFM_100_TX;
4159068f29fSmsaitoh 		else if (sr & KSZ8051_PHY_SPD_10T)
4169068f29fSmsaitoh 			mii->mii_media_active |= IFM_10_T;
4179068f29fSmsaitoh 		if (sr & KSZ8051_PHY_FDX)
4189068f29fSmsaitoh 			mii->mii_media_active |= IFM_FDX
4199068f29fSmsaitoh 			    | mii_phy_flowstatus(sc);
4209068f29fSmsaitoh 	} else if (msc->sc_lstype == MICPHYF_LSTYPE_GIGA) {
4219068f29fSmsaitoh 		/* 9021/9031/7430/9131 gphy */
4229068f29fSmsaitoh 		PHY_READ(sc, KSZ_GPHYCTL, &sr);
4239068f29fSmsaitoh 		if (sr & KSZ_GPHY_SPD_1000T)
4249068f29fSmsaitoh 			mii->mii_media_active |= IFM_1000_T;
4259068f29fSmsaitoh 		else if (sr & KSZ_GPHY_SPD_100TX)
4269068f29fSmsaitoh 			mii->mii_media_active |= IFM_100_TX;
4279068f29fSmsaitoh 		else if (sr & KSZ_GPHY_SPD_10T)
4289068f29fSmsaitoh 			mii->mii_media_active |= IFM_10_T;
4299068f29fSmsaitoh 		else
4309068f29fSmsaitoh 			mii->mii_media_active |= IFM_NONE;
4319068f29fSmsaitoh 		if ((mii->mii_media_active & IFM_1000_T)
4329068f29fSmsaitoh 		    && (sr & KSZ_GPHY_1000T_MS))
4339068f29fSmsaitoh 			mii->mii_media_active |= IFM_ETH_MASTER;
4349068f29fSmsaitoh 		if (sr & KSZ_GPHY_FDX)
4359068f29fSmsaitoh 			mii->mii_media_active |= IFM_FDX
4369068f29fSmsaitoh 			    | mii_phy_flowstatus(sc);
4379068f29fSmsaitoh 		else
4389068f29fSmsaitoh 			mii->mii_media_active |= IFM_HDX;
4399068f29fSmsaitoh 	}
4409068f29fSmsaitoh }
441