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