xref: /netbsd-src/sys/dev/mii/dmphy.c (revision 7a9a30c5e763bb556f73924ae04973e33cc385da)
1*7a9a30c5Sthorpej /*	$NetBSD: dmphy.c,v 1.47 2020/03/15 23:04:50 thorpej Exp $	*/
20738a5d4Sthorpej 
30738a5d4Sthorpej /*-
40738a5d4Sthorpej  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
50738a5d4Sthorpej  * All rights reserved.
60738a5d4Sthorpej  *
70738a5d4Sthorpej  * This code is derived from software contributed to The NetBSD Foundation
80738a5d4Sthorpej  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
90738a5d4Sthorpej  * NASA Ames Research Center.
100738a5d4Sthorpej  *
110738a5d4Sthorpej  * Redistribution and use in source and binary forms, with or without
120738a5d4Sthorpej  * modification, are permitted provided that the following conditions
130738a5d4Sthorpej  * are met:
140738a5d4Sthorpej  * 1. Redistributions of source code must retain the above copyright
150738a5d4Sthorpej  *    notice, this list of conditions and the following disclaimer.
160738a5d4Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
170738a5d4Sthorpej  *    notice, this list of conditions and the following disclaimer in the
180738a5d4Sthorpej  *    documentation and/or other materials provided with the distribution.
190738a5d4Sthorpej  *
200738a5d4Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
210738a5d4Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
220738a5d4Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
230738a5d4Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
240738a5d4Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
250738a5d4Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
260738a5d4Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
270738a5d4Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
280738a5d4Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
290738a5d4Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
300738a5d4Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
310738a5d4Sthorpej  */
320738a5d4Sthorpej 
330738a5d4Sthorpej /*
340738a5d4Sthorpej  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
350738a5d4Sthorpej  *
360738a5d4Sthorpej  * Redistribution and use in source and binary forms, with or without
370738a5d4Sthorpej  * modification, are permitted provided that the following conditions
380738a5d4Sthorpej  * are met:
390738a5d4Sthorpej  * 1. Redistributions of source code must retain the above copyright
400738a5d4Sthorpej  *    notice, this list of conditions and the following disclaimer.
410738a5d4Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
420738a5d4Sthorpej  *    notice, this list of conditions and the following disclaimer in the
430738a5d4Sthorpej  *    documentation and/or other materials provided with the distribution.
440738a5d4Sthorpej  *
450738a5d4Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
460738a5d4Sthorpej  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
470738a5d4Sthorpej  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
480738a5d4Sthorpej  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
490738a5d4Sthorpej  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
500738a5d4Sthorpej  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
510738a5d4Sthorpej  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
520738a5d4Sthorpej  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
530738a5d4Sthorpej  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
540738a5d4Sthorpej  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
550738a5d4Sthorpej  */
560738a5d4Sthorpej 
570738a5d4Sthorpej /*
580738a5d4Sthorpej  * driver for Davicom's DM9101 ethernet 10/100 PHY
590738a5d4Sthorpej  * Data Sheet available from www.davicom8.com
600738a5d4Sthorpej  */
610738a5d4Sthorpej 
628b7bb912Slukem #include <sys/cdefs.h>
63*7a9a30c5Sthorpej __KERNEL_RCSID(0, "$NetBSD: dmphy.c,v 1.47 2020/03/15 23:04:50 thorpej Exp $");
648b7bb912Slukem 
650738a5d4Sthorpej #include <sys/param.h>
660738a5d4Sthorpej #include <sys/systm.h>
670738a5d4Sthorpej #include <sys/kernel.h>
680738a5d4Sthorpej #include <sys/device.h>
690738a5d4Sthorpej #include <sys/socket.h>
700738a5d4Sthorpej #include <sys/errno.h>
710738a5d4Sthorpej 
720738a5d4Sthorpej #include <net/if.h>
730738a5d4Sthorpej #include <net/if_media.h>
740738a5d4Sthorpej 
750738a5d4Sthorpej #include <dev/mii/mii.h>
760738a5d4Sthorpej #include <dev/mii/miivar.h>
770738a5d4Sthorpej #include <dev/mii/miidevs.h>
780738a5d4Sthorpej 
790738a5d4Sthorpej #include <dev/mii/dmphyreg.h>
800738a5d4Sthorpej 
817db0e577Sxtraeme static int	dmphymatch(device_t, cfdata_t, void *);
827db0e577Sxtraeme static void	dmphyattach(device_t, device_t, void *);
830738a5d4Sthorpej 
847db0e577Sxtraeme CFATTACH_DECL_NEW(dmphy, sizeof(struct mii_softc),
85c9b3657cSthorpej     dmphymatch, dmphyattach, mii_phy_detach, mii_phy_activate);
860738a5d4Sthorpej 
871efb3da0Sthorpej static int	dmphy_service(struct mii_softc *, struct mii_data *, int);
881efb3da0Sthorpej static void	dmphy_status(struct mii_softc *);
890738a5d4Sthorpej 
901efb3da0Sthorpej static const struct mii_phy_funcs dmphy_funcs = {
9149014bf5Sthorpej 	dmphy_service, dmphy_status, mii_phy_reset,
9249014bf5Sthorpej };
9349014bf5Sthorpej 
941efb3da0Sthorpej static const struct mii_phydesc dmphys[] = {
957b43da1bSchristos 	MII_PHY_DESC(xxDAVICOM, DM9101),
967b43da1bSchristos 	MII_PHY_DESC(xxDAVICOM, DM9102),
9768fa6429Smsaitoh 	MII_PHY_DESC(xxDAVICOM, DM9161),
9868fa6429Smsaitoh 	MII_PHY_DESC(xxDAVICOM, DM9161A),
9968fa6429Smsaitoh 	MII_PHY_DESC(xxDAVICOM, DM9161B),
10068fa6429Smsaitoh 	MII_PHY_DESC(xxDAVICOM, DM9601),
101250005f4Smsaitoh 	MII_PHY_DESC(DAVICOM, DM9101),
1027b43da1bSchristos 	MII_PHY_END,
103424f7a1eSthorpej };
104424f7a1eSthorpej 
1051efb3da0Sthorpej static int
dmphymatch(device_t parent,cfdata_t match,void * aux)1067db0e577Sxtraeme dmphymatch(device_t parent, cfdata_t match, void *aux)
1070738a5d4Sthorpej {
1080738a5d4Sthorpej 	struct mii_attach_args *ma = aux;
1090738a5d4Sthorpej 
110424f7a1eSthorpej 	if (mii_phy_match(ma, dmphys) != NULL)
11102341723Smsaitoh 		return 10;
1120738a5d4Sthorpej 
11302341723Smsaitoh 	return 0;
1140738a5d4Sthorpej }
1150738a5d4Sthorpej 
1161efb3da0Sthorpej static void
dmphyattach(device_t parent,device_t self,void * aux)1177db0e577Sxtraeme dmphyattach(device_t parent, device_t self, void *aux)
1180738a5d4Sthorpej {
119838ee1e0Sthorpej 	struct mii_softc *sc = device_private(self);
1200738a5d4Sthorpej 	struct mii_attach_args *ma = aux;
1210738a5d4Sthorpej 	struct mii_data *mii = ma->mii_data;
122424f7a1eSthorpej 	const struct mii_phydesc *mpd;
1230738a5d4Sthorpej 
124424f7a1eSthorpej 	mpd = mii_phy_match(ma, dmphys);
125c31f87a5Sthorpej 	aprint_naive(": Media interface\n");
126c31f87a5Sthorpej 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
1270738a5d4Sthorpej 
1287db0e577Sxtraeme 	sc->mii_dev = self;
1290738a5d4Sthorpej 	sc->mii_inst = mii->mii_instance;
1300738a5d4Sthorpej 	sc->mii_phy = ma->mii_phyno;
13149014bf5Sthorpej 	sc->mii_funcs = &dmphy_funcs;
1320738a5d4Sthorpej 	sc->mii_pdata = mii;
133b0178985Sthorpej 	sc->mii_flags = ma->mii_flags;
1340738a5d4Sthorpej 
135*7a9a30c5Sthorpej 	mii_lock(mii);
136*7a9a30c5Sthorpej 
13749014bf5Sthorpej 	PHY_RESET(sc);
1380738a5d4Sthorpej 
139a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
140a5cdd4b4Smsaitoh 	sc->mii_capabilities &= ma->mii_capmask;
141509697f3Smsaitoh 
142*7a9a30c5Sthorpej 	mii_unlock(mii);
143*7a9a30c5Sthorpej 
14484dc99fdSthorpej 	mii_phy_add_media(sc);
1450738a5d4Sthorpej }
1460738a5d4Sthorpej 
1471efb3da0Sthorpej static int
dmphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)14889893e42Sthorpej dmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
1490738a5d4Sthorpej {
1500738a5d4Sthorpej 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
151a5cdd4b4Smsaitoh 	uint16_t reg;
1520738a5d4Sthorpej 
153*7a9a30c5Sthorpej 	KASSERT(mii_locked(mii));
154*7a9a30c5Sthorpej 
1550738a5d4Sthorpej 	switch (cmd) {
1560738a5d4Sthorpej 	case MII_POLLSTAT:
15702341723Smsaitoh 		/* If we're not polling our PHY instance, just return. */
1580738a5d4Sthorpej 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
15902341723Smsaitoh 			return 0;
1600738a5d4Sthorpej 		break;
1610738a5d4Sthorpej 
1620738a5d4Sthorpej 	case MII_MEDIACHG:
1630738a5d4Sthorpej 		/*
1640738a5d4Sthorpej 		 * If the media indicates a different PHY instance,
1650738a5d4Sthorpej 		 * isolate ourselves.
1660738a5d4Sthorpej 		 */
1670738a5d4Sthorpej 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
168a5cdd4b4Smsaitoh 			PHY_READ(sc, MII_BMCR, &reg);
1690738a5d4Sthorpej 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
17002341723Smsaitoh 			return 0;
1710738a5d4Sthorpej 		}
1720738a5d4Sthorpej 
17302341723Smsaitoh 		/* If the interface is not up, don't do anything. */
1740738a5d4Sthorpej 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
1750738a5d4Sthorpej 			break;
1760738a5d4Sthorpej 
1770738a5d4Sthorpej 		mii_phy_setmedia(sc);
1780738a5d4Sthorpej 		break;
1790738a5d4Sthorpej 
1800738a5d4Sthorpej 	case MII_TICK:
18102341723Smsaitoh 		/* If we're not currently selected, just return. */
1820738a5d4Sthorpej 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
18302341723Smsaitoh 			return 0;
1840738a5d4Sthorpej 
185ad61d101Sthorpej 		if (mii_phy_tick(sc) == EJUSTRETURN)
18602341723Smsaitoh 			return 0;
1870738a5d4Sthorpej 		break;
1880738a5d4Sthorpej 
1890738a5d4Sthorpej 	case MII_DOWN:
1900738a5d4Sthorpej 		mii_phy_down(sc);
19102341723Smsaitoh 		return 0;
1920738a5d4Sthorpej 	}
1930738a5d4Sthorpej 
1940738a5d4Sthorpej 	/* Update the media status. */
1958923ca0bSthorpej 	mii_phy_status(sc);
1960738a5d4Sthorpej 
1970738a5d4Sthorpej 	/* Callback if something changed. */
198ad61d101Sthorpej 	mii_phy_update(sc, cmd);
19902341723Smsaitoh 	return 0;
2000738a5d4Sthorpej }
2010738a5d4Sthorpej 
2021efb3da0Sthorpej static void
dmphy_status(struct mii_softc * sc)20389893e42Sthorpej dmphy_status(struct mii_softc *sc)
2040738a5d4Sthorpej {
2050738a5d4Sthorpej 	struct mii_data *mii = sc->mii_pdata;
2060738a5d4Sthorpej 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
207a5cdd4b4Smsaitoh 	uint16_t bmsr, bmcr, dscsr;
2080738a5d4Sthorpej 
209*7a9a30c5Sthorpej 	KASSERT(mii_locked(mii));
210*7a9a30c5Sthorpej 
2110738a5d4Sthorpej 	mii->mii_media_status = IFM_AVALID;
2120738a5d4Sthorpej 	mii->mii_media_active = IFM_ETHER;
2130738a5d4Sthorpej 
214a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMSR, &bmsr);
215a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMSR, &bmsr);
2160738a5d4Sthorpej 	if (bmsr & BMSR_LINK)
2170738a5d4Sthorpej 		mii->mii_media_status |= IFM_ACTIVE;
2180738a5d4Sthorpej 
219a5cdd4b4Smsaitoh 	PHY_READ(sc, MII_BMCR, &bmcr);
2200738a5d4Sthorpej 	if (bmcr & BMCR_ISO) {
2210738a5d4Sthorpej 		mii->mii_media_active |= IFM_NONE;
2220738a5d4Sthorpej 		mii->mii_media_status = 0;
2230738a5d4Sthorpej 		return;
2240738a5d4Sthorpej 	}
2250738a5d4Sthorpej 
2260738a5d4Sthorpej 	if (bmcr & BMCR_LOOP)
2270738a5d4Sthorpej 		mii->mii_media_active |= IFM_LOOP;
2280738a5d4Sthorpej 
2290738a5d4Sthorpej 	if (bmcr & BMCR_AUTOEN) {
2300738a5d4Sthorpej 		/*
231afe9412aSmsaitoh 		 * The PAR status bits are only valid if autonegotiation
2320738a5d4Sthorpej 		 * has completed (or it's disabled).
2330738a5d4Sthorpej 		 */
2340738a5d4Sthorpej 		if ((bmsr & BMSR_ACOMP) == 0) {
2350738a5d4Sthorpej 			/* Erg, still trying, I guess... */
2360738a5d4Sthorpej 			mii->mii_media_active |= IFM_NONE;
2370738a5d4Sthorpej 			return;
2380738a5d4Sthorpej 		}
2390738a5d4Sthorpej 
240a5cdd4b4Smsaitoh 		PHY_READ(sc, MII_DMPHY_DSCSR, &dscsr);
2410738a5d4Sthorpej 		if (dscsr & DSCSR_100FDX)
2420738a5d4Sthorpej 			mii->mii_media_active |= IFM_100_TX | IFM_FDX;
2430738a5d4Sthorpej 		else if (dscsr & DSCSR_100HDX)
244b211437bSmsaitoh 			mii->mii_media_active |= IFM_100_TX | IFM_HDX;
2450738a5d4Sthorpej 		else if (dscsr & DSCSR_10FDX)
2460738a5d4Sthorpej 			mii->mii_media_active |= IFM_10_T | IFM_FDX;
2470738a5d4Sthorpej 		else if (dscsr & DSCSR_10HDX)
248b211437bSmsaitoh 			mii->mii_media_active |= IFM_10_T | IFM_HDX;
2490738a5d4Sthorpej 		else
2500738a5d4Sthorpej 			mii->mii_media_active |= IFM_NONE;
251585f0322Snisimura 		if (mii->mii_media_active & IFM_FDX)
25220278436Snisimura 			mii->mii_media_active |= mii_phy_flowstatus(sc);
2530738a5d4Sthorpej 	} else
2540738a5d4Sthorpej 		mii->mii_media_active = ife->ifm_media;
2550738a5d4Sthorpej }
256