xref: /dragonfly/sys/dev/netif/mii_layer/ruephy.c (revision bff82488)
13c374c15SSepherosa Ziehau /*-
23c374c15SSepherosa Ziehau  * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>.
33c374c15SSepherosa Ziehau  * All rights reserved.
43c374c15SSepherosa Ziehau  *
53c374c15SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
63c374c15SSepherosa Ziehau  * modification, are permitted provided that the following conditions
73c374c15SSepherosa Ziehau  * are met:
83c374c15SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
93c374c15SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
103c374c15SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
113c374c15SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
123c374c15SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
133c374c15SSepherosa Ziehau  *
143c374c15SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153c374c15SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163c374c15SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173c374c15SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183c374c15SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193c374c15SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203c374c15SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213c374c15SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223c374c15SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233c374c15SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243c374c15SSepherosa Ziehau  * SUCH DAMAGE.
253c374c15SSepherosa Ziehau  *
263c374c15SSepherosa Ziehau  * $FreeBSD: src/sys/dev/mii/ruephy.c,v 1.1.4.1 2003/07/30 13:57:35 akiyama Exp $
273c374c15SSepherosa Ziehau  */
283c374c15SSepherosa Ziehau 
293c374c15SSepherosa Ziehau /*
303c374c15SSepherosa Ziehau  * driver for RealTek RTL8150 internal PHY
313c374c15SSepherosa Ziehau  */
323c374c15SSepherosa Ziehau 
333c374c15SSepherosa Ziehau #include <sys/param.h>
343c374c15SSepherosa Ziehau #include <sys/systm.h>
353c374c15SSepherosa Ziehau #include <sys/kernel.h>
363c374c15SSepherosa Ziehau #include <sys/malloc.h>
373c374c15SSepherosa Ziehau #include <sys/socket.h>
383c374c15SSepherosa Ziehau #include <sys/bus.h>
393c374c15SSepherosa Ziehau 
403c374c15SSepherosa Ziehau #include <net/if.h>
41*bff82488SAaron LI #include <net/if_var.h>
423c374c15SSepherosa Ziehau #include <net/if_media.h>
433c374c15SSepherosa Ziehau 
443c374c15SSepherosa Ziehau #include <dev/netif/mii_layer/mii.h>
453c374c15SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h>
463c374c15SSepherosa Ziehau #include <dev/netif/mii_layer/ruephyreg.h>
473c374c15SSepherosa Ziehau 
483c374c15SSepherosa Ziehau #include "miibus_if.h"
493c374c15SSepherosa Ziehau 
503c374c15SSepherosa Ziehau static int ruephy_probe(device_t);
513c374c15SSepherosa Ziehau static int ruephy_attach(device_t);
523c374c15SSepherosa Ziehau 
533c374c15SSepherosa Ziehau static device_method_t ruephy_methods[] = {
543c374c15SSepherosa Ziehau 	/* device interface */
553c374c15SSepherosa Ziehau 	DEVMETHOD(device_probe,		ruephy_probe),
563c374c15SSepherosa Ziehau 	DEVMETHOD(device_attach,	ruephy_attach),
5746ad174eSSepherosa Ziehau 	DEVMETHOD(device_detach,	ukphy_detach),
583c374c15SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
59d3c9c58eSSascha Wildner 	DEVMETHOD_END
603c374c15SSepherosa Ziehau };
613c374c15SSepherosa Ziehau 
623c374c15SSepherosa Ziehau static devclass_t ruephy_devclass;
633c374c15SSepherosa Ziehau 
643c374c15SSepherosa Ziehau static driver_t ruephy_driver = {
653c374c15SSepherosa Ziehau 	"ruephy",
663c374c15SSepherosa Ziehau 	ruephy_methods,
673c374c15SSepherosa Ziehau 	sizeof(struct mii_softc)
683c374c15SSepherosa Ziehau };
693c374c15SSepherosa Ziehau 
70aa2b9d05SSascha Wildner DRIVER_MODULE(ruephy, miibus, ruephy_driver, ruephy_devclass, NULL, NULL);
713c374c15SSepherosa Ziehau 
723c374c15SSepherosa Ziehau static int ruephy_service(struct mii_softc *, struct mii_data *, int);
733c374c15SSepherosa Ziehau static void ruephy_reset(struct mii_softc *);
743c374c15SSepherosa Ziehau static void ruephy_status(struct mii_softc *);
753c374c15SSepherosa Ziehau 
763c374c15SSepherosa Ziehau static int
ruephy_probe(device_t dev)773c374c15SSepherosa Ziehau ruephy_probe(device_t dev)
783c374c15SSepherosa Ziehau {
793c374c15SSepherosa Ziehau 	struct mii_attach_args *ma;
803c374c15SSepherosa Ziehau 	device_t		parent;
813c374c15SSepherosa Ziehau 
823c374c15SSepherosa Ziehau 	ma = device_get_ivars(dev);
833c374c15SSepherosa Ziehau 	parent = device_get_parent(device_get_parent(dev));
843c374c15SSepherosa Ziehau 
853c374c15SSepherosa Ziehau 	/*
863c374c15SSepherosa Ziehau 	 * RealTek RTL8150 PHY doesn't have vendor/device ID registers:
873c374c15SSepherosa Ziehau 	 * the rue driver fakes up a return value of all zeros.
883c374c15SSepherosa Ziehau 	 */
893c374c15SSepherosa Ziehau 	if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
903c374c15SSepherosa Ziehau 	    MII_MODEL(ma->mii_id2) != 0)
913c374c15SSepherosa Ziehau 		return (ENXIO);
923c374c15SSepherosa Ziehau 
933c374c15SSepherosa Ziehau 	/*
943c374c15SSepherosa Ziehau 	 * Make sure the parent is an 'rue'.
953c374c15SSepherosa Ziehau 	 */
963c374c15SSepherosa Ziehau 	if (strcmp(device_get_name(parent), "rue") != 0)
973c374c15SSepherosa Ziehau 		return (ENXIO);
983c374c15SSepherosa Ziehau 
993c374c15SSepherosa Ziehau 	device_set_desc(dev, "RealTek RTL8150 internal media interface");
1003c374c15SSepherosa Ziehau 
1013c374c15SSepherosa Ziehau 	return (0);
1023c374c15SSepherosa Ziehau }
1033c374c15SSepherosa Ziehau 
1043c374c15SSepherosa Ziehau static int
ruephy_attach(device_t dev)1053c374c15SSepherosa Ziehau ruephy_attach(device_t dev)
1063c374c15SSepherosa Ziehau {
1073c374c15SSepherosa Ziehau 	struct mii_softc	*sc;
1083c374c15SSepherosa Ziehau 	struct mii_attach_args	*ma;
1093c374c15SSepherosa Ziehau 	struct mii_data		*mii;
1103c374c15SSepherosa Ziehau 
1113c374c15SSepherosa Ziehau 	sc = device_get_softc(dev);
1123c374c15SSepherosa Ziehau 	ma = device_get_ivars(dev);
113b9bc8a8cSMatthew Dillon 	mii_softc_init(sc, ma);
1143c374c15SSepherosa Ziehau 	sc->mii_dev = device_get_parent(dev);
1153c374c15SSepherosa Ziehau 	mii = device_get_softc(sc->mii_dev);
1163c374c15SSepherosa Ziehau 
1173c374c15SSepherosa Ziehau 	/*
1183c374c15SSepherosa Ziehau 	 * The RealTek PHY can never be isolated, so never allow non-zero
1193c374c15SSepherosa Ziehau 	 * instances!
1203c374c15SSepherosa Ziehau 	 */
1213c374c15SSepherosa Ziehau 	if (mii->mii_instance != 0) {
1223c374c15SSepherosa Ziehau 		device_printf(dev, "ignoring this PHY, non-zero instance\n");
1233c374c15SSepherosa Ziehau 		return (ENXIO);
1243c374c15SSepherosa Ziehau 	}
1253c374c15SSepherosa Ziehau 
1263c374c15SSepherosa Ziehau 	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
1273c374c15SSepherosa Ziehau 
1283c374c15SSepherosa Ziehau 	sc->mii_inst = mii->mii_instance;
1293c374c15SSepherosa Ziehau 	sc->mii_service = ruephy_service;
13046ad174eSSepherosa Ziehau 	sc->mii_reset = ruephy_reset;
1313c374c15SSepherosa Ziehau 	sc->mii_pdata = mii;
1323c374c15SSepherosa Ziehau 	mii->mii_instance++;
1333c374c15SSepherosa Ziehau 
1343c374c15SSepherosa Ziehau 	sc->mii_flags |= MIIF_NOISOLATE;
1353c374c15SSepherosa Ziehau 
1363c374c15SSepherosa Ziehau 	ruephy_reset(sc);
1373c374c15SSepherosa Ziehau 
13846ad174eSSepherosa Ziehau 	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
13946ad174eSSepherosa Ziehau 
1403c374c15SSepherosa Ziehau 	device_printf(dev, " ");
1413c374c15SSepherosa Ziehau 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
142e3869ec7SSascha Wildner 		kprintf("no media present");
1433c374c15SSepherosa Ziehau 	else
14446ad174eSSepherosa Ziehau 		mii_phy_add_media(sc);
145e3869ec7SSascha Wildner 	kprintf("\n");
1463c374c15SSepherosa Ziehau 
1473c374c15SSepherosa Ziehau 	MIIBUS_MEDIAINIT(sc->mii_dev);
1483c374c15SSepherosa Ziehau 	return (0);
1493c374c15SSepherosa Ziehau }
1503c374c15SSepherosa Ziehau 
1513c374c15SSepherosa Ziehau static int
ruephy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)1523c374c15SSepherosa Ziehau ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
1533c374c15SSepherosa Ziehau {
1543c374c15SSepherosa Ziehau 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
1553c374c15SSepherosa Ziehau 	int reg;
1563c374c15SSepherosa Ziehau 
1573c374c15SSepherosa Ziehau 	/*
1583c374c15SSepherosa Ziehau 	 * We can't isolate the RealTek RTL8150 PHY,
1593c374c15SSepherosa Ziehau 	 * so it has to be the only one!
1603c374c15SSepherosa Ziehau 	 */
16146ad174eSSepherosa Ziehau 	KASSERT(IFM_INST(ife->ifm_media) == sc->mii_inst,
16246ad174eSSepherosa Ziehau 		("ruephy_service: can't isolate RealTek RTL8150 PHY"));
1633c374c15SSepherosa Ziehau 
1643c374c15SSepherosa Ziehau 	switch (cmd) {
1653c374c15SSepherosa Ziehau 	case MII_POLLSTAT:
1663c374c15SSepherosa Ziehau 		break;
1673c374c15SSepherosa Ziehau 
1683c374c15SSepherosa Ziehau 	case MII_MEDIACHG:
1693c374c15SSepherosa Ziehau 		/*
1703c374c15SSepherosa Ziehau 		 * If the interface is not up, don't do anything.
1713c374c15SSepherosa Ziehau 		 */
1723c374c15SSepherosa Ziehau 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
1733c374c15SSepherosa Ziehau 			break;
1743c374c15SSepherosa Ziehau 
17546ad174eSSepherosa Ziehau 		if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_T4) {
1763c374c15SSepherosa Ziehau 			/*
1773c374c15SSepherosa Ziehau 			 * XXX Not supported as a manual setting right now.
1783c374c15SSepherosa Ziehau 			 */
1793c374c15SSepherosa Ziehau 			return (EINVAL);
1803c374c15SSepherosa Ziehau 		}
18146ad174eSSepherosa Ziehau 
18246ad174eSSepherosa Ziehau 		mii_phy_set_media(sc);
1833c374c15SSepherosa Ziehau 		break;
1843c374c15SSepherosa Ziehau 
1853c374c15SSepherosa Ziehau 	case MII_TICK:
1863c374c15SSepherosa Ziehau 		/*
1873c374c15SSepherosa Ziehau 		 * Is the interface even up?
1883c374c15SSepherosa Ziehau 		 */
1893c374c15SSepherosa Ziehau 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
1903c374c15SSepherosa Ziehau 			return (0);
1913c374c15SSepherosa Ziehau 
1923c374c15SSepherosa Ziehau 		/*
1933c374c15SSepherosa Ziehau 		 * Only used for autonegotiation.
1943c374c15SSepherosa Ziehau 		 */
1953c374c15SSepherosa Ziehau 		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
1963c374c15SSepherosa Ziehau 			break;
1973c374c15SSepherosa Ziehau 
1983c374c15SSepherosa Ziehau 		/*
1993c374c15SSepherosa Ziehau 		 * Check to see if we have link.  If we do, we don't
2003c374c15SSepherosa Ziehau 		 * need to restart the autonegotiation process.  Read
2013c374c15SSepherosa Ziehau 		 * the MSR twice in case it's latched.
2023c374c15SSepherosa Ziehau 		 */
2033c374c15SSepherosa Ziehau 		reg = PHY_READ(sc, RUEPHY_MII_MSR) |
2043c374c15SSepherosa Ziehau 		      PHY_READ(sc, RUEPHY_MII_MSR);
20512b5e22dSSepherosa Ziehau 		if (reg & RUEPHY_MSR_LINK) {
20612b5e22dSSepherosa Ziehau 			sc->mii_ticks = 0;
2073c374c15SSepherosa Ziehau 			break;
20812b5e22dSSepherosa Ziehau 		}
2093c374c15SSepherosa Ziehau 
2103c374c15SSepherosa Ziehau 		/*
2113c374c15SSepherosa Ziehau 		 * Only retry autonegotiation every 5 seconds.
2123c374c15SSepherosa Ziehau 		 */
2133c374c15SSepherosa Ziehau 		if (++sc->mii_ticks != 5)
2143c374c15SSepherosa Ziehau 			return (0);
2153c374c15SSepherosa Ziehau 
2163c374c15SSepherosa Ziehau 		sc->mii_ticks = 0;
2173c374c15SSepherosa Ziehau 		ruephy_reset(sc);
21846ad174eSSepherosa Ziehau 
2193c374c15SSepherosa Ziehau 		if (mii_phy_auto(sc, 0) == EJUSTRETURN)
2203c374c15SSepherosa Ziehau 			return (0);
2213c374c15SSepherosa Ziehau 		break;
2223c374c15SSepherosa Ziehau 	}
2233c374c15SSepherosa Ziehau 
2243c374c15SSepherosa Ziehau 	/* Update the media status. */
2253c374c15SSepherosa Ziehau 	ruephy_status(sc);
2263c374c15SSepherosa Ziehau 
2273c374c15SSepherosa Ziehau 	/* Callback if something changed. */
22846ad174eSSepherosa Ziehau 	mii_phy_update(sc, cmd);
2293c374c15SSepherosa Ziehau 	return (0);
2303c374c15SSepherosa Ziehau }
2313c374c15SSepherosa Ziehau 
2323c374c15SSepherosa Ziehau static void
ruephy_reset(struct mii_softc * sc)2333c374c15SSepherosa Ziehau ruephy_reset(struct mii_softc *sc)
2343c374c15SSepherosa Ziehau {
2353c374c15SSepherosa Ziehau 
2363c374c15SSepherosa Ziehau 	mii_phy_reset(sc);
2373c374c15SSepherosa Ziehau 
2383c374c15SSepherosa Ziehau 	/*
2393c374c15SSepherosa Ziehau 	 * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after
2403c374c15SSepherosa Ziehau 	 * XXX reset, which breaks autonegotiation.
2413c374c15SSepherosa Ziehau 	 */
242e9fa3ce7SSepherosa Ziehau 	PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN);
2433c374c15SSepherosa Ziehau }
2443c374c15SSepherosa Ziehau 
2453c374c15SSepherosa Ziehau static void
ruephy_status(struct mii_softc * sc)24646ad174eSSepherosa Ziehau ruephy_status(struct mii_softc *sc)
2473c374c15SSepherosa Ziehau {
24846ad174eSSepherosa Ziehau 	struct mii_data *mii = sc->mii_pdata;
2493c374c15SSepherosa Ziehau 	int bmsr, bmcr, msr;
2503c374c15SSepherosa Ziehau 
2513c374c15SSepherosa Ziehau 	mii->mii_media_status = IFM_AVALID;
2523c374c15SSepherosa Ziehau 	mii->mii_media_active = IFM_ETHER;
2533c374c15SSepherosa Ziehau 
25446ad174eSSepherosa Ziehau 	msr = PHY_READ(sc, RUEPHY_MII_MSR) | PHY_READ(sc, RUEPHY_MII_MSR);
2553c374c15SSepherosa Ziehau 	if (msr & RUEPHY_MSR_LINK)
2563c374c15SSepherosa Ziehau 		mii->mii_media_status |= IFM_ACTIVE;
2573c374c15SSepherosa Ziehau 
25846ad174eSSepherosa Ziehau 	bmcr = PHY_READ(sc, MII_BMCR);
2593c374c15SSepherosa Ziehau 	if (bmcr & BMCR_ISO) {
2603c374c15SSepherosa Ziehau 		mii->mii_media_active |= IFM_NONE;
2613c374c15SSepherosa Ziehau 		mii->mii_media_status = 0;
2623c374c15SSepherosa Ziehau 		return;
2633c374c15SSepherosa Ziehau 	}
2643c374c15SSepherosa Ziehau 
26546ad174eSSepherosa Ziehau 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
2663c374c15SSepherosa Ziehau 
2673c374c15SSepherosa Ziehau 	if (bmcr & BMCR_AUTOEN) {
2683c374c15SSepherosa Ziehau 		if ((bmsr & BMSR_ACOMP) == 0) {
2693c374c15SSepherosa Ziehau 			/* Erg, still trying, I guess... */
2703c374c15SSepherosa Ziehau 			mii->mii_media_active |= IFM_NONE;
2713c374c15SSepherosa Ziehau 			return;
2723c374c15SSepherosa Ziehau 		}
2733c374c15SSepherosa Ziehau 
2743c374c15SSepherosa Ziehau 		if (msr & RUEPHY_MSR_SPEED100)
2753c374c15SSepherosa Ziehau 			mii->mii_media_active |= IFM_100_TX;
2763c374c15SSepherosa Ziehau 		else
2773c374c15SSepherosa Ziehau 			mii->mii_media_active |= IFM_10_T;
2783c374c15SSepherosa Ziehau 
2793c374c15SSepherosa Ziehau 		if (msr & RUEPHY_MSR_DUPLEX)
2803c374c15SSepherosa Ziehau 			mii->mii_media_active |= IFM_FDX;
28146ad174eSSepherosa Ziehau 	} else {
28246ad174eSSepherosa Ziehau 		mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media;
28346ad174eSSepherosa Ziehau 	}
2843c374c15SSepherosa Ziehau }
285