xref: /netbsd-src/sys/dev/mii/tqphy.c (revision 7a9a30c5e763bb556f73924ae04973e33cc385da)
1*7a9a30c5Sthorpej /*	$NetBSD: tqphy.c,v 1.45 2020/03/15 23:04:50 thorpej Exp $	*/
257f7d332Ssoren 
357f7d332Ssoren /*
449014bf5Sthorpej  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
557f7d332Ssoren  * All rights reserved.
657f7d332Ssoren  *
757f7d332Ssoren  * This code is derived from software contributed to The NetBSD Foundation
857f7d332Ssoren  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
957f7d332Ssoren  * NASA Ames Research Center.
1057f7d332Ssoren  *
1157f7d332Ssoren  * Redistribution and use in source and binary forms, with or without
1257f7d332Ssoren  * modification, are permitted provided that the following conditions
1357f7d332Ssoren  * are met:
1457f7d332Ssoren  * 1. Redistributions of source code must retain the above copyright
1557f7d332Ssoren  *    notice, this list of conditions and the following disclaimer.
1657f7d332Ssoren  * 2. Redistributions in binary form must reproduce the above copyright
1757f7d332Ssoren  *    notice, this list of conditions and the following disclaimer in the
1857f7d332Ssoren  *    documentation and/or other materials provided with the distribution.
1957f7d332Ssoren  *
2057f7d332Ssoren  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2157f7d332Ssoren  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2257f7d332Ssoren  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2357f7d332Ssoren  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2457f7d332Ssoren  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2557f7d332Ssoren  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2657f7d332Ssoren  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2757f7d332Ssoren  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2857f7d332Ssoren  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2957f7d332Ssoren  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3057f7d332Ssoren  * POSSIBILITY OF SUCH DAMAGE.
3157f7d332Ssoren  */
3257f7d332Ssoren 
3357f7d332Ssoren /*
3457f7d332Ssoren  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
3557f7d332Ssoren  *
3657f7d332Ssoren  * Redistribution and use in source and binary forms, with or without
3757f7d332Ssoren  * modification, are permitted provided that the following conditions
3857f7d332Ssoren  * are met:
3957f7d332Ssoren  * 1. Redistributions of source code must retain the above copyright
4057f7d332Ssoren  *    notice, this list of conditions and the following disclaimer.
4157f7d332Ssoren  * 2. Redistributions in binary form must reproduce the above copyright
4257f7d332Ssoren  *    notice, this list of conditions and the following disclaimer in the
4357f7d332Ssoren  *    documentation and/or other materials provided with the distribution.
4457f7d332Ssoren  *
4557f7d332Ssoren  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4657f7d332Ssoren  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4757f7d332Ssoren  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4857f7d332Ssoren  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
4957f7d332Ssoren  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
5057f7d332Ssoren  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5157f7d332Ssoren  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5257f7d332Ssoren  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5357f7d332Ssoren  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
5457f7d332Ssoren  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5557f7d332Ssoren  */
5657f7d332Ssoren 
5757f7d332Ssoren /*
5857f7d332Ssoren  * TDK TSC78Q2120 PHY driver
5957f7d332Ssoren  *
6057f7d332Ssoren  * Documentation available at http://www.tsc.tdk.com/lan/78Q2120.pdf .
6157f7d332Ssoren  */
6257f7d332Ssoren 
638b7bb912Slukem #include <sys/cdefs.h>
64*7a9a30c5Sthorpej __KERNEL_RCSID(0, "$NetBSD: tqphy.c,v 1.45 2020/03/15 23:04:50 thorpej Exp $");
658b7bb912Slukem 
6657f7d332Ssoren #include <sys/param.h>
6757f7d332Ssoren #include <sys/systm.h>
6857f7d332Ssoren #include <sys/kernel.h>
6957f7d332Ssoren #include <sys/device.h>
7057f7d332Ssoren #include <sys/socket.h>
7157f7d332Ssoren 
7257f7d332Ssoren #include <net/if.h>
7357f7d332Ssoren #include <net/if_media.h>
7457f7d332Ssoren 
7557f7d332Ssoren #include <dev/mii/mii.h>
7657f7d332Ssoren #include <dev/mii/miivar.h>
7757f7d332Ssoren #include <dev/mii/miidevs.h>
7857f7d332Ssoren 
7957f7d332Ssoren #include <dev/mii/tqphyreg.h>
8057f7d332Ssoren 
817db0e577Sxtraeme static int	tqphymatch(device_t, cfdata_t, void *);
827db0e577Sxtraeme static void	tqphyattach(device_t, device_t, void *);
8357f7d332Ssoren 
847db0e577Sxtraeme CFATTACH_DECL_NEW(tqphy, sizeof(struct mii_softc),
85c9b3657cSthorpej     tqphymatch, tqphyattach, mii_phy_detach, mii_phy_activate);
8657f7d332Ssoren 
871efb3da0Sthorpej static int	tqphy_service(struct mii_softc *, struct mii_data *, int);
881efb3da0Sthorpej static void	tqphy_status(struct mii_softc *);
8957f7d332Ssoren 
901efb3da0Sthorpej static const struct mii_phy_funcs tqphy_funcs = {
9149014bf5Sthorpej 	tqphy_service, tqphy_status, mii_phy_reset,
9249014bf5Sthorpej };
9349014bf5Sthorpej 
941efb3da0Sthorpej static const struct mii_phydesc tqphys[] = {
957b43da1bSchristos 	MII_PHY_DESC(xxTSC, 78Q2120),
96424f7a1eSthorpej #if 0
977b43da1bSchristos 	MII_PHY_DESC(xxTSC, 78Q2121),
98424f7a1eSthorpej #endif
997b43da1bSchristos 	MII_PHY_END,
100424f7a1eSthorpej };
101424f7a1eSthorpej 
1021efb3da0Sthorpej static int
tqphymatch(device_t parent,cfdata_t match,void * aux)1037db0e577Sxtraeme tqphymatch(device_t parent, cfdata_t match, void *aux)
10457f7d332Ssoren {
10557f7d332Ssoren 	struct mii_attach_args *ma = aux;
10657f7d332Ssoren 
107aa878fabSmycroft 	if (mii_phy_match(ma, tqphys) != NULL) {
108aa878fabSmycroft 		/* The DIAG register is unreliable on early revisions. */
109aa878fabSmycroft 		if (MII_MODEL(ma->mii_id2) == MII_MODEL_xxTSC_78Q2120 &&
110aa878fabSmycroft 		    MII_REV(ma->mii_id2) <= 3)
1118e65e831Smsaitoh 			return 0;
1128e65e831Smsaitoh 		return 10;
113aa878fabSmycroft 	}
11457f7d332Ssoren 
1158e65e831Smsaitoh 	return 0;
11657f7d332Ssoren }
11757f7d332Ssoren 
1181efb3da0Sthorpej static void
tqphyattach(device_t parent,device_t self,void * aux)1197db0e577Sxtraeme tqphyattach(device_t parent, device_t self, void *aux)
12057f7d332Ssoren {
121838ee1e0Sthorpej 	struct mii_softc *sc = device_private(self);
12257f7d332Ssoren 	struct mii_attach_args *ma = aux;
12357f7d332Ssoren 	struct mii_data *mii = ma->mii_data;
124424f7a1eSthorpej 	const struct mii_phydesc *mpd;
12557f7d332Ssoren 
126424f7a1eSthorpej 	mpd = mii_phy_match(ma, tqphys);
127c31f87a5Sthorpej 	aprint_naive(": Media interface\n");
128c31f87a5Sthorpej 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
12957f7d332Ssoren 
1307db0e577Sxtraeme 	sc->mii_dev = self;
13157f7d332Ssoren 	sc->mii_inst = mii->mii_instance;
13257f7d332Ssoren 	sc->mii_phy = ma->mii_phyno;
13349014bf5Sthorpej 	sc->mii_funcs = &tqphy_funcs;
13457f7d332Ssoren 	sc->mii_pdata = mii;
135b0178985Sthorpej 	sc->mii_flags = ma->mii_flags;
13657f7d332Ssoren 
1378e65e831Smsaitoh 	/* Apparently, we can't do loopback on this PHY. */
1388fc600c3Sthorpej 	sc->mii_flags |= MIIF_NOLOOP;
13957f7d332Ssoren 
140*7a9a30c5Sthorpej 	mii_lock(mii);
141*7a9a30c5Sthorpej 
14249014bf5Sthorpej 	PHY_RESET(sc);
14357f7d332Ssoren 
144a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
145a5cdd4b4Smsaitoh 	sc->mii_capabilities &= ma->mii_capmask;
146509697f3Smsaitoh 
147*7a9a30c5Sthorpej 	mii_unlock(mii);
148*7a9a30c5Sthorpej 
14984dc99fdSthorpej 	mii_phy_add_media(sc);
15057f7d332Ssoren }
15157f7d332Ssoren 
1521efb3da0Sthorpej static int
tqphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)15389893e42Sthorpej tqphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
15457f7d332Ssoren {
15557f7d332Ssoren 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
156a5cdd4b4Smsaitoh 	uint16_t reg;
15757f7d332Ssoren 
158*7a9a30c5Sthorpej 	KASSERT(mii_locked(mii));
159*7a9a30c5Sthorpej 
16057f7d332Ssoren 	switch (cmd) {
16157f7d332Ssoren 	case MII_POLLSTAT:
1628e65e831Smsaitoh 		/* If we're not polling our PHY instance, just return. */
16357f7d332Ssoren 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1648e65e831Smsaitoh 			return 0;
16557f7d332Ssoren 		break;
16657f7d332Ssoren 
16757f7d332Ssoren 	case MII_MEDIACHG:
16857f7d332Ssoren 		/*
16957f7d332Ssoren 		 * If the media indicates a different PHY instance,
17057f7d332Ssoren 		 * isolate ourselves.
17157f7d332Ssoren 		 */
17257f7d332Ssoren 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
173a5cdd4b4Smsaitoh 			PHY_READ(sc, MII_BMCR, &reg);
17457f7d332Ssoren 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
1758e65e831Smsaitoh 			return 0;
17657f7d332Ssoren 		}
17757f7d332Ssoren 
1788e65e831Smsaitoh 		/* If the interface is not up, don't do anything. */
17957f7d332Ssoren 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
18057f7d332Ssoren 			break;
18157f7d332Ssoren 
1828fc600c3Sthorpej 		mii_phy_setmedia(sc);
18357f7d332Ssoren 		break;
18457f7d332Ssoren 
18557f7d332Ssoren 	case MII_TICK:
1868e65e831Smsaitoh 		/* If we're not currently selected, just return. */
18757f7d332Ssoren 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1888e65e831Smsaitoh 			return 0;
18957f7d332Ssoren 
190ad61d101Sthorpej 		if (mii_phy_tick(sc) == EJUSTRETURN)
1918e65e831Smsaitoh 			return 0;
19257f7d332Ssoren 		break;
193bca88a28Sthorpej 
194bca88a28Sthorpej 	case MII_DOWN:
195bca88a28Sthorpej 		mii_phy_down(sc);
1968e65e831Smsaitoh 		return 0;
19757f7d332Ssoren 	}
19857f7d332Ssoren 
19957f7d332Ssoren 	/* Update the media status. */
2008923ca0bSthorpej 	mii_phy_status(sc);
20157f7d332Ssoren 
20257f7d332Ssoren 	/* Callback if something changed. */
203ad61d101Sthorpej 	mii_phy_update(sc, cmd);
2048e65e831Smsaitoh 	return 0;
20557f7d332Ssoren }
20657f7d332Ssoren 
2071efb3da0Sthorpej static void
tqphy_status(struct mii_softc * sc)20889893e42Sthorpej tqphy_status(struct mii_softc *sc)
20957f7d332Ssoren {
21057f7d332Ssoren 	struct mii_data *mii = sc->mii_pdata;
2118fc600c3Sthorpej 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
212a5cdd4b4Smsaitoh 	uint16_t bmsr, bmcr, diag;
21357f7d332Ssoren 
214*7a9a30c5Sthorpej 	KASSERT(mii_locked(mii));
215*7a9a30c5Sthorpej 
21657f7d332Ssoren 	mii->mii_media_status = IFM_AVALID;
21757f7d332Ssoren 	mii->mii_media_active = IFM_ETHER;
21857f7d332Ssoren 
219a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMSR, &bmsr);
220a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMSR, &bmsr);
22157f7d332Ssoren 	if (bmsr & BMSR_LINK)
22257f7d332Ssoren 		mii->mii_media_status |= IFM_ACTIVE;
22357f7d332Ssoren 
224a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMCR, &bmcr);
22557f7d332Ssoren 	if (bmcr & BMCR_ISO) {
22657f7d332Ssoren 		mii->mii_media_active |= IFM_NONE;
22757f7d332Ssoren 		mii->mii_media_status = 0;
22857f7d332Ssoren 		return;
22957f7d332Ssoren 	}
23057f7d332Ssoren 
23157f7d332Ssoren 	if (bmcr & BMCR_LOOP)
23257f7d332Ssoren 		mii->mii_media_active |= IFM_LOOP;
23357f7d332Ssoren 
23457f7d332Ssoren 	if (bmcr & BMCR_AUTOEN) {
23557f7d332Ssoren 		if ((bmsr & BMSR_ACOMP) == 0) {
23657f7d332Ssoren 			/* Erg, still trying, I guess... */
23757f7d332Ssoren 			mii->mii_media_active |= IFM_NONE;
23857f7d332Ssoren 			return;
23957f7d332Ssoren 		}
240a5cdd4b4Smsaitoh 		PHY_READ(sc, MII_TQPHY_DIAG, &diag);
24157f7d332Ssoren 		if (diag & DIAG_RATE)
24257f7d332Ssoren 			mii->mii_media_active |= IFM_100_TX;
24357f7d332Ssoren 		else
24457f7d332Ssoren 			mii->mii_media_active |= IFM_10_T;
245b211437bSmsaitoh 
24657f7d332Ssoren 		if (diag & DIAG_DPLX)
24757f7d332Ssoren 			mii->mii_media_active |= IFM_FDX;
248b211437bSmsaitoh 		else
249b211437bSmsaitoh 			mii->mii_media_active |= IFM_HDX;
25057f7d332Ssoren 	} else
2518fc600c3Sthorpej 		mii->mii_media_active = ife->ifm_media;
25257f7d332Ssoren }
253