diff options
Diffstat (limited to 'sys/dev/mii')
44 files changed, 11141 insertions, 0 deletions
diff --git a/sys/dev/mii/acphy.c b/sys/dev/mii/acphy.c new file mode 100644 index 0000000..47105ff --- /dev/null +++ b/sys/dev/mii/acphy.c @@ -0,0 +1,313 @@ +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Driver for Altima AC101 10/100 PHY + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/acphyreg.h> + +#include "miibus_if.h" + +static int acphy_probe(device_t); +static int acphy_attach(device_t); + +static device_method_t acphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, acphy_probe), + DEVMETHOD(device_attach, acphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t acphy_devclass; + +static driver_t acphy_driver = { + "acphy", + acphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(acphy, miibus, acphy_driver, acphy_devclass, 0, 0); + +static int acphy_service(struct mii_softc *, struct mii_data *, int); +static void acphy_reset(struct mii_softc *); +static void acphy_status(struct mii_softc *); + +static int +acphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxALTIMA && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxALTIMA_AC101) { + device_set_desc(dev, MII_STR_xxALTIMA_AC101); + } else if(MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxALTIMA && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxALTIMA_AC101L) { + device_set_desc(dev, MII_STR_xxALTIMA_AC101L); + } else + return (ENXIO); + + return (0); +} + +static int +acphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = acphy_service; + sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOISOLATE; + + acphy_reset(sc); + + mii->mii_instance++; + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + mii_add_media(sc); + printf("\n"); + + MIIBUS_MEDIAINIT(sc->mii_dev); + return (0); +} + +static int +acphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + /* + * If we're not selected, then do nothing, just isolate and power + * down, if changing media. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + if (cmd == MII_MEDIACHG) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO | BMCR_PDOWN); + } + + return (0); + } + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + /* Wake & deisolate up if necessary */ + reg = PHY_READ(sc, MII_BMCR); + if (reg & (BMCR_ISO | BMCR_PDOWN)) + PHY_WRITE(sc, MII_BMCR, reg & ~(BMCR_ISO | BMCR_PDOWN)); + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) + return (0); + + (void) mii_phy_auto(sc); + break; + + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * This PHY's autonegotiation doesn't need to be kicked. + */ + break; + } + + /* Update the media status. */ + acphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +acphy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmsr, bmcr, diag; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, MII_BMSR) | + PHY_READ(sc, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + diag = PHY_READ(sc, MII_ACPHY_DIAG); + if (diag & AC_DIAG_SPEED) + mii->mii_media_active |= IFM_100_TX; + else + mii->mii_media_active |= IFM_10_T; + + if (diag & AC_DIAG_DUPLEX) + mii->mii_media_active |= IFM_FDX; + } else + mii->mii_media_active = ife->ifm_media; +} + +static void +acphy_reset(sc) + struct mii_softc *sc; +{ + + mii_phy_reset(sc); + PHY_WRITE(sc, MII_ACPHY_INT, 0); +} diff --git a/sys/dev/mii/acphyreg.h b/sys/dev/mii/acphyreg.h new file mode 100644 index 0000000..827aba6 --- /dev/null +++ b/sys/dev/mii/acphyreg.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2001 Semen Ustimenko (semenu@FreeBSD.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_ACPHYREG_H_ +#define _DEV_MII_ACPHYREG_H_ + +/* + * Register definitions for the Altima Communications AC101 + */ + +#define MII_ACPHY_POL 0x10 /* Polarity int level */ + +/* High byte is interrupt mask register */ +#define MII_ACPHY_INT 0x11 /* Interrupt control/status */ +#define AC_INT_ACOMP 0x0001 /* Autoneg complete */ +#define AC_INT_REM_FLT 0x0002 /* Remote fault */ +#define AC_INT_LINK_DOWN 0x0004 /* Link not OK */ +#define AC_INT_LP_ACK 0x0008 /* FLP ack recved */ +#define AC_INT_PD_FLT 0x0010 /* Parallel detect fault */ +#define AC_INT_PAGE_RECV 0x0020 /* New page recved */ +#define AC_INT_RX_ER 0x0040 /* RX_ER transitions high */ +#define AC_INT_JAB 0x0080 /* Jabber detected */ + +#define MII_ACPHY_DIAG 0x12 /* Diagnostic */ +#define AC_DIAG_RX_LOCK 0x0100 +#define AC_DIAG_RX_PASS 0x0200 +#define AC_DIAG_SPEED 0x0400 /* Aneg speed result */ +#define AC_DIAG_DUPLEX 0x0800 /* Aneg duplex result */ + +#define MII_ACPHY_PWRLOOP 0x13 /* Power/Loopback */ +#define MII_ACPHY_CBLMEAS 0x14 /* Cable meas. */ + +#define MII_ACPHY_MCTL 0x15 /* Mode control */ +#define AC_MCTL_FX_SEL 0x0001 /* FX mode */ +#define AC_MCTL_BYP_PCS 0x0001 /* Bypass PCS */ +#define AC_MCTL_SCRMBL 0x0004 /* Data scrambling */ +#define AC_MCTL_REM_LOOP 0x0008 /* Remote loopback */ +#define AC_MCTL_DIS_WDT 0x0010 /* Disable watchdog timer */ +#define AC_MCTL_DIS_REC 0x0020 /* Disable recv error counter */ +#define AC_MCTL_REC_FULL 0x0040 /* Recv error counter full */ +#define AC_MCTL_FRC_FEF 0x0080 /* Force Far End Fault Insert. */ +#define AC_MCTL_DIS_FEF 0x0100 /* Disable FEF Insertion */ +#define AC_MCTL_LED_SEL 0x0200 /* Compat LED config */ +#define AC_MCTL_ALED_SEL 0x0400 /* ActLED RX&TX - RX only */ +#define AC_MCTL_10BT_SEL 0x0800 /* Enable 7-wire interface */ +#define AC_MCTL_DIS_JAB 0x1000 /* Disable jabber */ +#define AC_MCTL_FRC_LINK 0x2000 /* Force TX link up */ +#define AC_MCTL_DIS_NLP 0x4000 /* Disable NLP check */ + +#define MII_ACPHY_REC 0x18 /* Recv error counter */ + +#endif /* _DEV_MII_ACPHYREG_H_ */ diff --git a/sys/dev/mii/amphy.c b/sys/dev/mii/amphy.c new file mode 100644 index 0000000..e63d050 --- /dev/null +++ b/sys/dev/mii/amphy.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * driver for AMD AM79c873 PHYs + * This driver also works for the Davicom DM9101 PHY, which appears to + * be an AM79c873 workalike. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/amphyreg.h> + +#include "miibus_if.h" + +static int amphy_probe(device_t); +static int amphy_attach(device_t); + +static device_method_t amphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, amphy_probe), + DEVMETHOD(device_attach, amphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t amphy_devclass; + +static driver_t amphy_driver = { + "amphy", + amphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(amphy, miibus, amphy_driver, amphy_devclass, 0, 0); + +static int amphy_service(struct mii_softc *, struct mii_data *, int); +static void amphy_status(struct mii_softc *); + +static int +amphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if ((MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_xxAMD || + MII_MODEL(ma->mii_id2) != MII_MODEL_xxAMD_79C873) && + (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_xxDAVICOM || + MII_MODEL(ma->mii_id2) != MII_MODEL_xxDAVICOM_DM9101)) + return(ENXIO); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxAMD) + device_set_desc(dev, MII_STR_xxAMD_79C873); + else if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxDAVICOM) + device_set_desc(dev, MII_STR_xxDAVICOM_DM9101); + + return(0); +} + +static int +amphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = amphy_service; + sc->mii_pdata = mii; + + sc->mii_flags |= MIIF_NOISOLATE; + mii->mii_instance++; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#if 0 + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); +#endif + + mii_phy_reset(sc); + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + mii_add_media(sc); + printf("\n"); +#undef ADD + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +amphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) + return (0); + (void) mii_phy_auto(sc); + break; + case IFM_100_T4: + /* + * XXX Not supported as a manual setting right now. + */ + return (EINVAL); + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + amphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +amphy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + int bmsr, bmcr, par, anlpar; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, MII_BMSR) | + PHY_READ(sc, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * The PAR status bits are only valid of autonegotiation + * has completed (or it's disabled). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + if (PHY_READ(sc, MII_ANER) & ANER_LPAN) { + anlpar = PHY_READ(sc, MII_ANAR) & + PHY_READ(sc, MII_ANLPAR); + if (anlpar & ANLPAR_T4) + mii->mii_media_active |= IFM_100_T4; + else if (anlpar & ANLPAR_TX_FD) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_TX) + mii->mii_media_active |= IFM_100_TX; + else if (anlpar & ANLPAR_10_FD) + mii->mii_media_active |= IFM_10_T|IFM_FDX; + else if (anlpar & ANLPAR_10) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_NONE; + return; + } + + /* + * Link partner is not capable of autonegotiation. + */ + par = PHY_READ(sc, MII_AMPHY_DSCSR); + if (par & DSCSR_100FDX) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (par & DSCSR_100HDX) + mii->mii_media_active |= IFM_100_TX; + else if (par & DSCSR_10FDX) + mii->mii_media_active |= IFM_10_T|IFM_HDX; + else if (par & DSCSR_10HDX) + mii->mii_media_active |= IFM_10_T; + } else + mii->mii_media_active = mii_media_from_bmcr(bmcr); +} diff --git a/sys/dev/mii/amphyreg.h b/sys/dev/mii/amphyreg.h new file mode 100644 index 0000000..ffc362a --- /dev/null +++ b/sys/dev/mii/amphyreg.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_AMTPHYREG_H_ +#define _DEV_MII_AMTPHYREG_H_ + +/* + * AMD Am79C873 registers. + */ + + +#define MII_AMPHY_DSCR 0x10 /* Specified configuration register */a +#define DSCR_BP4B5B 0x8000 /* Bypass 4B5B encoding */ +#define DSCR_BPSCR 0x4000 /* Bypass scrambler */ +#define DSCR_BPALIGN 0x2000 /* Bypass symbol alignment */ +#define DSCR_REPEATER 0x0800 /* Repeater mode */ +#define DSCR_TX 0x0400 /* TX/FX mode control */ +#define DSCR_UTP 0x0200 /* UTP/STP mode control */ +#define DSCR_CLK25MDIS 0x0100 /* CLK25M disable */ +#define DSCR_FGLNKTX 0x0080 /* Force good link at 100baseTX */ +#define DSCR_LINKLEDCTL 0x0020 /* Link LED control */ +#define DSCR_FDXLEDCTL 0x0010 /* FDX LED control */ +#define DSCR_SMRTS 0x0008 /* Reset state machine */ +#define DSCR_MFPSC 0x0004 /* Preamble surpression control */ +#define DSCR_SLEEP 0x0002 /* Sleep mode */ +#define DSCR_RLOUT 0x0001 /* Remote loopout control */ + +#define MII_AMPHY_DSCSR 0x11 /* Specified configuration and status */ +#define DSCSR_100FDX 0x8000 /* 100MBps full duplex */ +#define DSCSR_100HDX 0x4000 /* 100Mbps half duplex */ +#define DSCSR_10FDX 0x2000 /* 10Mbps full duplex */ +#define DSCSR_10HDX 0x1000 /* 10Mbps half duplex */ +#define DSCSR_PADDR 0x01F0 /* PHY address */ +#define DSCSR_ASTAT 0x000F /* Autonegotiation status */ + +#define ASTAT_COMPLETE 0x8 +#define ASTAT_PDLINK_READY_FAIL 0x7 +#define ASTAT_PDLINK_READY 0x6 +#define ASTAT_CONSTMATCH_FAIL 0x5 +#define ASTAT_CONSTMATCH 0x4 +#define ASTAT_ACKMATCH_FAIL 0x3 +#define ASTAT_ACKMATCH 0x2 +#define ASTAT_ABILITYMATCH 0x1 +#define ASTAT_IDLE 0x0 + +#define MII_AMPHY_T10CSRSCR 0x12 /* 10baseT configuration/status */ +#define T10CSRSCR_LPEN 0x4000 /* Link pulse enable */ +#define T10CSRSCR_HBE 0x2000 /* Heartbeat enable */ +#define T10CSRSCR_JABEN 0x0800 /* Jabber enable */ +#define T10CSRSCR_SER 0x0400 /* Serial mode enable */ +#define T10CSRSCR_POLR 0x0001 /* Polarity reversed */ + +#endif /* _DEV_MII_AMTPHYREG_H_ */ diff --git a/sys/dev/mii/bmtphy.c b/sys/dev/mii/bmtphy.c new file mode 100644 index 0000000..df5bdc5 --- /dev/null +++ b/sys/dev/mii/bmtphy.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp + * + */ + +/* + * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also + * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in + * the 3c905C data sheet. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/bmtphyreg.h> + +#include "miibus_if.h" + +static int bmtphy_probe(device_t); +static int bmtphy_attach(device_t); + +static device_method_t bmtphy_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bmtphy_probe), + DEVMETHOD(device_attach, bmtphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + { 0, 0 } +}; + +static devclass_t bmtphy_devclass; + +static driver_t bmtphy_driver = { + "bmtphy", + bmtphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0); + +static int bmtphy_service(struct mii_softc *, struct mii_data *, int); +static void bmtphy_status(struct mii_softc *); + +static int +bmtphy_probe(device_t dev) +{ + struct mii_attach_args *ma; + int rval; + + ma = device_get_ivars(dev); + rval = 0; + + if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM) + return (ENXIO); + + switch (MII_MODEL(ma->mii_id2)) { + case MII_MODEL_BROADCOM_3C905B: + device_set_desc(dev, MII_STR_BROADCOM_3C905B); + rval = -10; /* Let exphy take precedence. */ + break; + case MII_MODEL_BROADCOM_3C905C: + device_set_desc(dev, MII_STR_BROADCOM_3C905C); + rval = -10; /* Let exphy take precedence. */ + break; + case MII_MODEL_BROADCOM_BCM5201: + device_set_desc(dev, MII_STR_BROADCOM_BCM5201); + break; + case MII_MODEL_BROADCOM_BCM5221: + device_set_desc(dev, MII_STR_BROADCOM_BCM5221); + break; + case MII_MODEL_BROADCOM_BCM4401: + device_set_desc(dev, MII_STR_BROADCOM_BCM4401); + break; + default: + return (ENXIO); + } + + return (rval); +} + +static int +bmtphy_attach(device_t dev) +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = bmtphy_service; + sc->mii_pdata = mii; + + mii_phy_reset(sc); + + mii->mii_instance++; + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) + printf("no media present"); + else + mii_phy_add_media(sc); + + printf("\n"); + + MIIBUS_MEDIAINIT(sc->mii_dev); + + return (0); +} + +static int +bmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + struct ifmedia_entry *ife; + int reg; + + ife = mii->mii_media.ifm_cur; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + mii_phy_setmedia(sc); + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + bmtphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + + return (0); +} + +static void +bmtphy_status(struct mii_softc *sc) +{ + struct mii_data *mii; + struct ifmedia_entry *ife; + int bmsr, bmcr, aux_csr; + + mii = sc->mii_pdata; + ife = mii->mii_media.ifm_cur; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); + + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * The media status bits are only valid if autonegotiation + * has completed (or it's disabled). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + if (aux_csr & AUX_CSR_SPEED) + mii->mii_media_active |= IFM_100_TX; + else + mii->mii_media_active |= IFM_10_T; + if (aux_csr & AUX_CSR_FDX) + mii->mii_media_active |= IFM_FDX; + } else + mii->mii_media_active = ife->ifm_media; +} diff --git a/sys/dev/mii/bmtphyreg.h b/sys/dev/mii/bmtphyreg.h new file mode 100644 index 0000000..7f2956a --- /dev/null +++ b/sys/dev/mii/bmtphyreg.h @@ -0,0 +1,182 @@ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from NetBSD: bmtphyreg.h,v 1.1 2001/06/02 21:42:10 thorpej Exp + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_BMTPHYREG_H_ +#define _DEV_MII_BMTPHYREG_H_ + +/* + * BCM5201/BCM5202 registers. + */ + +#define MII_BMTPHY_AUX_CTL 0x10 /* auxiliary control */ +#define AUX_CTL_TXDIS 0x2000 /* transmitter disable */ +#define AUX_CTL_4B5B_BYPASS 0x0400 /* bypass 4b5b encoder */ +#define AUX_CTL_SCR_BYPASS 0x0200 /* bypass scrambler */ +#define AUX_CTL_NRZI_BYPASS 0x0100 /* bypass NRZI encoder */ +#define AUX_CTL_RXALIGN_BYPASS 0x0080 /* bypass rx symbol alignment */ +#define AUX_CTL_BASEWANDER_DIS 0x0040 /* disable baseline wander correction */ +#define AUX_CTL_FEF_EN 0x0020 /* far-end fault enable */ + + +#define MII_BMTPHY_AUX_STS 0x11 /* auxiliary status */ +#define AUX_STS_FX_MODE 0x0400 /* 100base-FX mode (strap pin) */ +#define AUX_STS_LOCKED 0x0200 /* descrambler locked */ +#define AUX_STS_100BASE_LINK 0x0100 /* 1 = 100base link */ +#define AUX_STS_REMFAULT 0x0080 /* remote fault */ +#define AUX_STS_DISCON_STATE 0x0040 /* disconnect state */ +#define AUX_STS_FCARDET 0x0020 /* false carrier detected */ +#define AUX_STS_BAD_ESD 0x0010 /* bad ESD detected */ +#define AUX_STS_RXERROR 0x0008 /* Rx error detected */ +#define AUX_STS_TXERROR 0x0004 /* Tx error detected */ +#define AUX_STS_LOCKERROR 0x0002 /* lock error detected */ +#define AUX_STS_MLT3ERROR 0x0001 /* MLT3 code error detected */ + + +#define MII_BMTPHY_RXERROR_CTR 0x12 /* 100base-X Rx error counter */ +#define RXERROR_CTR_MASK 0x00ff + + +#define MII_BMTPHY_FCS_CTR 0x13 /* 100base-X false carrier counter */ +#define FCS_CTR_MASK 0x00ff + + +#define MII_BMTPHY_DIS_CTR 0x14 /* 100base-X disconnect counter */ +#define DIS_CTR_MASK 0x00ff + + +#define MII_BMTPHY_PTEST 0x17 /* PTEST */ + + +#define MII_BMTPHY_AUX_CSR 0x18 /* auxiliary control/status */ +#define AUX_CSR_JABBER_DIS 0x8000 /* jabber disable */ +#define AUX_CSR_FLINK 0x4000 /* force 10baseT link pass */ +#define AUX_CSR_HSQ 0x0080 /* SQ high */ +#define AUX_CSR_LSQ 0x0040 /* SQ low */ +#define AUX_CSR_ER1 0x0020 /* edge rate 1 */ +#define AUX_CSR_ER0 0x0010 /* edge rate 0 */ +#define AUX_CSR_ANEG 0x0008 /* auto-negotiation activated */ +#define AUX_CSR_F100 0x0004 /* force 100base */ +#define AUX_CSR_SPEED 0x0002 /* 1 = 100, 0 = 10 */ +#define AUX_CSR_FDX 0x0001 /* full-duplex */ + + +#define MII_BMTPHY_AUX_SS 0x19 /* auxiliary status summary */ +#define AUX_SS_ACOMP 0x8000 /* auto-negotiation complete */ +#define AUX_SS_ACOMP_ACK 0x4000 /* auto-negotiation compl. ack */ +#define AUX_SS_AACK_DET 0x2000 /* auto-neg. ack detected */ +#define AUX_SS_ANLPAD 0x1000 /* auto-neg. link part. ability det */ +#define AUX_SS_ANEG_PAUSE 0x0800 /* pause operation bit */ +#define AUX_SS_HCD 0x0700 /* highest common denominator */ +#define AUX_SS_HCD_NONE 0x0000 /* none */ +#define AUX_SS_HCD_10T 0x0100 /* 10baseT */ +#define AUX_SS_HCD_10T_FDX 0x0200 /* 10baseT-FDX */ +#define AUX_SS_HCD_100TX 0x0300 /* 100baseTX-FDX */ +#define AUX_SS_HCD_100T4 0x0400 /* 100baseT4 */ +#define AUX_SS_HCD_100TX_FDX 0x0500 /* 100baseTX-FDX */ +#define AUX_SS_PDF 0x0080 /* parallel detection fault */ +#define AUX_SS_LPRF 0x0040 /* link partner remote fault */ +#define AUX_SS_LPPR 0x0020 /* link partner page received */ +#define AUX_SS_LPANA 0x0010 /* link partner auto-neg able */ +#define AUX_SS_SPEED 0x0008 /* 1 = 100, 0 = 10 */ +#define AUX_SS_LINK 0x0004 /* link pass */ +#define AUX_SS_ANEN 0x0002 /* auto-neg. enabled */ +#define AUX_SS_JABBER 0x0001 /* jabber detected */ + + +#define MII_BMTPHY_INTR 0x1a /* interrupt register */ +#define INTR_FDX_LED 0x8000 /* full-duplex led enable */ +#define INTR_INTR_EN 0x4000 /* interrupt enable */ +#define INTR_FDX_MASK 0x0800 /* full-dupled intr mask */ +#define INTR_SPD_MASK 0x0400 /* speed intr mask */ +#define INTR_LINK_MASK 0x0200 /* link intr mask */ +#define INTR_INTR_MASK 0x0100 /* master interrupt mask */ +#define INTR_FDX_CHANGE 0x0008 /* full-duplex change */ +#define INTR_SPD_CHANGE 0x0004 /* speed change */ +#define INTR_LINK_CHANGE 0x0002 /* link change */ +#define INTR_INTR_STATUS 0x0001 /* interrupt status */ + + +#define MII_BMTPHY_AUX2 0x1b /* auliliary mode 2 */ +#define AUX2_BLOCK_RXDV 0x0200 /* block RXDV mode enabled */ +#define AUX2_ANPDQ 0x0100 /* auto-neg parallel detection Q mode */ +#define AUX2_TRAFFIC_LED 0x0040 /* traffic meter led enable */ +#define AUX2_FXMTRCV_LED 0x0020 /* force Tx and Rx LEDs */ +#define AUX2_HS_TOKEN 0x0010 /* high-speed token ring mode */ +#define AUX2_AUTO_LP 0x0008 /* auto low-power mode */ +#define AUX2_TWOLINK_LED 0x0004 /* two link LEDs */ +#define AUX2_SQE_DIS 0x0002 /* disable SQE pulse */ + + +#define MII_BMTPHY_AUXERR 0x1c /* auxiliary error */ +#define AUXERR_MANCHESTER 0x0400 /* Manchester code error */ +#define AUXERR_EOF 0x0200 /* EOF detection error */ +#define AUXERR_POLARITY 0x0100 /* polarity inversion */ +#define AUXERR_ANEG 0x0008 /* autonegotiation enabled */ +#define AUXERR_F100 0x0004 /* force 100base */ +#define AUXERR_SPEED 0x0002 /* 1 = 100, 0 = 10 */ +#define AUXERR_FDX 0x0001 /* full-duplex */ + + +#define MII_BMTPHY_AUXMODE 0x1d /* auxiliary mode */ +#define AUXMODE_ACT_LED_DIS 0x0010 /* activity LED disable */ +#define AUXMODE_LINK_LED_DIS 0x0008 /* link LED disable */ +#define AUXMODE_BLOCK_TXEN 0x0002 /* enable block TXEN */ + + +#define MII_BMTPHY_AUXMPHY 0x1e /* auxiliary multiple phy register */ +#define AUXMPHY_HCD_TX_FDX 0x8000 /* res. is 100baseTX-FDX */ +#define AUXMPHY_HCD_T4 0x4000 /* res. is 100baseT4 */ +#define AUXMPHY_HCD_TX 0x2000 /* res. is 100baseTX */ +#define AUXMPHY_HCD_10T_FDX 0x1000 /* res. is 10baseT-FDX */ +#define AUXMPHY_HCD_10T 0x0800 /* res. is 10baseT */ +#define AUXMPHY_RES_ANEG 0x0100 /* restart auto-negotiation */ +#define AUXMPHY_ANEG_COMP 0x0080 /* auto-negotiation complete */ +#define AUXMPHY_ACK_COMP 0x0040 /* acknowledge complete */ +#define AUXMPHY_ACK_DET 0x0020 /* acknowledge detected */ +#define AUXMPHY_ABILITY_DET 0x0010 /* waiting for LP ability */ +#define AUXMPHY_SUPER_ISO 0x0008 /* super-isolate mode */ +#define AUXMPHY_10T_SERIAL 0x0002 /* 10baseT serial mode */ + + +#define MII_BMTPHY_TEST 0x1d /* Broadcom test register */ + + +#endif /* _DEV_MII_BMTPHYREG_H_ */ diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c new file mode 100644 index 0000000..6b4d38f --- /dev/null +++ b/sys/dev/mii/brgphy.c @@ -0,0 +1,633 @@ +/* + * Copyright (c) 2000 + * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Driver for the Broadcom BCR5400 1000baseTX PHY. Speed is always + * 1000mbps; all we need to negotiate here is full or half duplex. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <machine/clock.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/brgphyreg.h> +#include <net/if_arp.h> +#include <machine/bus.h> +#include <dev/bge/if_bgereg.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include "miibus_if.h" + +static int brgphy_probe(device_t); +static int brgphy_attach(device_t); + +static device_method_t brgphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, brgphy_probe), + DEVMETHOD(device_attach, brgphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t brgphy_devclass; + +static driver_t brgphy_driver = { + "brgphy", + brgphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0); + +static int brgphy_service(struct mii_softc *, struct mii_data *, int); +static void brgphy_status(struct mii_softc *); +static int brgphy_mii_phy_auto(struct mii_softc *); +static void brgphy_reset(struct mii_softc *); +static void brgphy_loop(struct mii_softc *); +static void bcm5401_load_dspcode(struct mii_softc *); +static void bcm5411_load_dspcode(struct mii_softc *); +static void bcm5703_load_dspcode(struct mii_softc *); +static int brgphy_mii_model; + +static int +brgphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5400) { + device_set_desc(dev, MII_STR_xxBROADCOM_BCM5400); + return(0); + } + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5401) { + device_set_desc(dev, MII_STR_xxBROADCOM_BCM5401); + return(0); + } + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5411) { + device_set_desc(dev, MII_STR_xxBROADCOM_BCM5411); + return(0); + } + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5701) { + device_set_desc(dev, MII_STR_xxBROADCOM_BCM5701); + return(0); + } + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5703) { + device_set_desc(dev, MII_STR_xxBROADCOM_BCM5703); + return(0); + } + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5704) { + device_set_desc(dev, MII_STR_xxBROADCOM_BCM5704); + return(0); + } + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5705) { + device_set_desc(dev, MII_STR_xxBROADCOM_BCM5705); + return(0); + } + + return(ENXIO); +} + +static int +brgphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + const char *sep = ""; + struct bge_softc *bge_sc; + int fast_ether_only = FALSE; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = brgphy_service; + sc->mii_pdata = mii; + + sc->mii_flags |= MIIF_NOISOLATE; + mii->mii_instance++; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) +#define PRINT(s) printf("%s%s", sep, s); sep = ", " + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#if 0 + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); +#endif + + brgphy_mii_model = MII_MODEL(ma->mii_id2); + brgphy_reset(sc); + + + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities &= ~BMSR_ANEG; + device_printf(dev, " "); + mii_add_media(sc); + + /* The 590x chips are 10/100 only. */ + + bge_sc = mii->mii_ifp->if_softc; + + if (strcmp(mii->mii_ifp->if_dname, "bge") == 0 && + pci_get_vendor(bge_sc->bge_dev) == BCOM_VENDORID && + (pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901 || + pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2)) + fast_ether_only = TRUE; + + if (fast_ether_only == FALSE) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, + sc->mii_inst), BRGPHY_BMCR_FDX); + PRINT(", 1000baseTX"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, + IFM_FDX, sc->mii_inst), 0); + PRINT("1000baseTX-FDX"); + } + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); + PRINT("auto"); + + printf("\n"); +#undef ADD +#undef PRINT + + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +brgphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg, speed, gig; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + brgphy_reset(sc); /* XXX hardware bug work-around */ + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: +#ifdef foo + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_AUTOEN) + return (0); +#endif + (void) brgphy_mii_phy_auto(sc); + break; + case IFM_1000_T: + speed = BRGPHY_S1000; + goto setit; + case IFM_100_TX: + speed = BRGPHY_S100; + goto setit; + case IFM_10_T: + speed = BRGPHY_S10; +setit: + brgphy_loop(sc); + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + speed |= BRGPHY_BMCR_FDX; + gig = BRGPHY_1000CTL_AFD; + } else { + gig = BRGPHY_1000CTL_AHD; + } + + PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); + PHY_WRITE(sc, BRGPHY_MII_BMCR, speed); + PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); + + if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) + break; + + PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); + PHY_WRITE(sc, BRGPHY_MII_BMCR, + speed|BRGPHY_BMCR_AUTOEN|BRGPHY_BMCR_STARTNEG); + + if (brgphy_mii_model != MII_MODEL_xxBROADCOM_BCM5701) + break; + + /* + * When settning the link manually, one side must + * be the master and the other the slave. However + * ifmedia doesn't give us a good way to specify + * this, so we fake it by using one of the LINK + * flags. If LINK0 is set, we program the PHY to + * be a master, otherwise it's a slave. + */ + if ((mii->mii_ifp->if_flags & IFF_LINK0)) { + PHY_WRITE(sc, BRGPHY_MII_1000CTL, + gig|BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC); + } else { + PHY_WRITE(sc, BRGPHY_MII_1000CTL, + gig|BRGPHY_1000CTL_MSE); + } + break; +#ifdef foo + case IFM_NONE: + PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN); + break; +#endif + case IFM_100_T4: + default: + return (EINVAL); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * Check to see if we have link. If we do, we don't + * need to restart the autonegotiation process. Read + * the BMSR twice in case it's latched. + */ + reg = PHY_READ(sc, BRGPHY_MII_AUXSTS); + if (reg & BRGPHY_AUXSTS_LINK) + break; + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->mii_ticks != 5) + return (0); + + sc->mii_ticks = 0; + brgphy_mii_phy_auto(sc); + return (0); + } + + /* Update the media status. */ + brgphy_status(sc); + + /* + * Callback if something changed. Note that we need to poke + * the DSP on the Broadcom PHYs if the media changes. + * + */ + if (sc->mii_media_active != mii->mii_media_active || + sc->mii_media_status != mii->mii_media_status || + cmd == MII_MEDIACHG) { + mii_phy_update(sc, cmd); + switch (brgphy_mii_model) { + case MII_MODEL_xxBROADCOM_BCM5401: + bcm5401_load_dspcode(sc); + break; + case MII_MODEL_xxBROADCOM_BCM5411: + bcm5411_load_dspcode(sc); + break; + } + } + return (0); +} + +static void +brgphy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmsr, bmcr; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); + if (PHY_READ(sc, BRGPHY_MII_AUXSTS) & BRGPHY_AUXSTS_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); + + if (bmcr & BRGPHY_BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BRGPHY_BMCR_AUTOEN) { + if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + switch (PHY_READ(sc, BRGPHY_MII_AUXSTS) & + BRGPHY_AUXSTS_AN_RES) { + case BRGPHY_RES_1000FD: + mii->mii_media_active |= IFM_1000_T | IFM_FDX; + break; + case BRGPHY_RES_1000HD: + mii->mii_media_active |= IFM_1000_T | IFM_HDX; + break; + case BRGPHY_RES_100FD: + mii->mii_media_active |= IFM_100_TX | IFM_FDX; + break; + case BRGPHY_RES_100T4: + mii->mii_media_active |= IFM_100_T4; + break; + case BRGPHY_RES_100HD: + mii->mii_media_active |= IFM_100_TX | IFM_HDX; + break; + case BRGPHY_RES_10FD: + mii->mii_media_active |= IFM_10_T | IFM_FDX; + break; + case BRGPHY_RES_10HD: + mii->mii_media_active |= IFM_10_T | IFM_HDX; + break; + default: + mii->mii_media_active |= IFM_NONE; + break; + } + return; + } + + mii->mii_media_active = ife->ifm_media; + + return; +} + + +static int +brgphy_mii_phy_auto(mii) + struct mii_softc *mii; +{ + int ktcr = 0; + + brgphy_loop(mii); + brgphy_reset(mii); + ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD; + if (brgphy_mii_model == MII_MODEL_xxBROADCOM_BCM5701) + ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC; + PHY_WRITE(mii, BRGPHY_MII_1000CTL, ktcr); + ktcr = PHY_READ(mii, BRGPHY_MII_1000CTL); + DELAY(1000); + PHY_WRITE(mii, BRGPHY_MII_ANAR, + BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA); + DELAY(1000); + PHY_WRITE(mii, BRGPHY_MII_BMCR, + BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); + PHY_WRITE(mii, BRGPHY_MII_IMR, 0xFF00); + return (EJUSTRETURN); +} + +static void +brgphy_loop(struct mii_softc *sc) +{ + u_int32_t bmsr; + int i; + + PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); + for (i = 0; i < 15000; i++) { + bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); + if (!(bmsr & BRGPHY_BMSR_LINK)) { +#if 0 + device_printf(sc->mii_dev, "looped %d\n", i); +#endif + break; + } + DELAY(10); + } +} + +/* Turn off tap power management on 5401. */ +static void +bcm5401_load_dspcode(struct mii_softc *sc) +{ + static const struct { + int reg; + uint16_t val; + } dspcode[] = { + { BRGPHY_MII_AUXCTL, 0x0c20 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, + { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, + { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, + { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, + { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, + { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, + { 0, 0 }, + }; + int i; + + for (i = 0; dspcode[i].reg != 0; i++) + PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); + DELAY(40); +} + +static void +bcm5411_load_dspcode(struct mii_softc *sc) +{ + static const struct { + int reg; + uint16_t val; + } dspcode[] = { + { 0x1c, 0x8c23 }, + { 0x1c, 0x8ca3 }, + { 0x1c, 0x8c23 }, + { 0, 0 }, + }; + int i; + + for (i = 0; dspcode[i].reg != 0; i++) + PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); +} + +static void +bcm5703_load_dspcode(struct mii_softc *sc) +{ + static const struct { + int reg; + uint16_t val; + } dspcode[] = { + { BRGPHY_MII_AUXCTL, 0x0c00 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, + { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, + { 0, 0 }, + }; + int i; + + for (i = 0; dspcode[i].reg != 0; i++) + PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); +} + +static void +bcm5704_load_dspcode(struct mii_softc *sc) +{ + static const struct { + int reg; + u_int16_t val; + } dspcode[] = { + { 0x1c, 0x8d68 }, + { 0x1c, 0x8d68 }, + { 0, 0 }, + }; + int i; + + for (i = 0; dspcode[i].reg != 0; i++) + PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); +} + +static void +brgphy_reset(struct mii_softc *sc) +{ + u_int32_t val; + struct ifnet *ifp; + struct bge_softc *bge_sc; + + mii_phy_reset(sc); + + switch (brgphy_mii_model) { + case MII_MODEL_xxBROADCOM_BCM5401: + bcm5401_load_dspcode(sc); + break; + case MII_MODEL_xxBROADCOM_BCM5411: + bcm5411_load_dspcode(sc); + break; + case MII_MODEL_xxBROADCOM_BCM5703: + bcm5703_load_dspcode(sc); + break; + case MII_MODEL_xxBROADCOM_BCM5704: + bcm5704_load_dspcode(sc); + break; + } + + ifp = sc->mii_pdata->mii_ifp; + bge_sc = ifp->if_softc; + + /* + * Don't enable Ethernet@WireSpeed for the 5700 or the + * 5705 A1 and A2 chips. Make sure we only do this test + * on "bge" NICs, since other drivers may use this same + * PHY subdriver. + */ + if (strcmp(ifp->if_dname, "bge") == 0 && + (bge_sc->bge_asicrev == BGE_ASICREV_BCM5700 || + bge_sc->bge_chipid == BGE_CHIPID_BCM5705_A1 || + bge_sc->bge_chipid == BGE_CHIPID_BCM5705_A2)) + return; + + /* Enable Ethernet@WireSpeed. */ + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); + val = PHY_READ(sc, BRGPHY_MII_AUXCTL); + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4)); + + /* Enable Link LED on Dell boxes */ + if (bge_sc->bge_no_3_led) { + PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, + PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) + & ~BRGPHY_PHY_EXTCTL_3_LED); + } +} diff --git a/sys/dev/mii/brgphyreg.h b/sys/dev/mii/brgphyreg.h new file mode 100644 index 0000000..786f49d --- /dev/null +++ b/sys/dev/mii/brgphyreg.h @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2000 + * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_BRGPHYREG_H_ +#define _DEV_MII_BRGPHYREG_H_ + +/* + * Broadcom BCM5400 registers + */ + +#define BRGPHY_MII_BMCR 0x00 +#define BRGPHY_BMCR_RESET 0x8000 +#define BRGPHY_BMCR_LOOP 0x4000 +#define BRGPHY_BMCR_SPD0 0x2000 /* speed select, lower bit */ +#define BRGPHY_BMCR_AUTOEN 0x1000 /* Autoneg enabled */ +#define BRGPHY_BMCR_PDOWN 0x0800 /* Power down */ +#define BRGPHY_BMCR_ISO 0x0400 /* Isolate */ +#define BRGPHY_BMCR_STARTNEG 0x0200 /* Restart autoneg */ +#define BRGPHY_BMCR_FDX 0x0100 /* Duplex mode */ +#define BRGPHY_BMCR_CTEST 0x0080 /* Collision test enable */ +#define BRGPHY_BMCR_SPD1 0x0040 /* Speed select, upper bit */ + +#define BRGPHY_S1000 BRGPHY_BMCR_SPD1 /* 1000mbps */ +#define BRGPHY_S100 BRGPHY_BMCR_SPD0 /* 100mpbs */ +#define BRGPHY_S10 0 /* 10mbps */ + +#define BRGPHY_MII_BMSR 0x01 +#define BRGPHY_BMSR_EXTSTS 0x0100 /* Extended status present */ +#define BRGPHY_BMSR_PRESUB 0x0040 /* Preamble surpression */ +#define BRGPHY_BMSR_ACOMP 0x0020 /* Autoneg complete */ +#define BRGPHY_BMSR_RFAULT 0x0010 /* Remote fault condition occured */ +#define BRGPHY_BMSR_ANEG 0x0008 /* Autoneg capable */ +#define BRGPHY_BMSR_LINK 0x0004 /* Link status */ +#define BRGPHY_BMSR_JABBER 0x0002 /* Jabber detected */ +#define BRGPHY_BMSR_EXT 0x0001 /* Extended capability */ + +#define BRGPHY_MII_ANAR 0x04 +#define BRGPHY_ANAR_NP 0x8000 /* Next page */ +#define BRGPHY_ANAR_RF 0x2000 /* Remote fault */ +#define BRGPHY_ANAR_ASP 0x0800 /* Asymmetric Pause */ +#define BRGPHY_ANAR_PC 0x0400 /* Pause capable */ +#define BRGPHY_ANAR_SEL 0x001F /* selector field, 00001=Ethernet */ + +#define BRGPHY_MII_ANLPAR 0x05 +#define BRGPHY_ANLPAR_NP 0x8000 /* Next page */ +#define BRGPHY_ANLPAR_RF 0x2000 /* Remote fault */ +#define BRGPHY_ANLPAR_ASP 0x0800 /* Asymmetric Pause */ +#define BRGPHY_ANLPAR_PC 0x0400 /* Pause capable */ +#define BRGPHY_ANLPAR_SEL 0x001F /* selector field, 00001=Ethernet */ + +#define BRGPHY_SEL_TYPE 0x0001 /* ethernet */ + +#define BRGPHY_MII_ANER 0x06 +#define BRGPHY_ANER_PDF 0x0010 /* Parallel detection fault */ +#define BRGPHY_ANER_LPNP 0x0008 /* Link partner can next page */ +#define BRGPHY_ANER_NP 0x0004 /* Local PHY can next page */ +#define BRGPHY_ANER_RX 0x0002 /* Next page received */ +#define BRGPHY_ANER_LPAN 0x0001 /* Link partner autoneg capable */ + +#define BRGPHY_MII_NEXTP 0x07 /* Next page */ + +#define BRGPHY_MII_NEXTP_LP 0x08 /* Next page of link partner */ + +#define BRGPHY_MII_1000CTL 0x09 /* 1000baseT control */ +#define BRGPHY_1000CTL_TST 0xE000 /* test modes */ +#define BRGPHY_1000CTL_MSE 0x1000 /* Master/Slave enable */ +#define BRGPHY_1000CTL_MSC 0x0800 /* Master/Slave configuration */ +#define BRGPHY_1000CTL_RD 0x0400 /* Repeater/DTE */ +#define BRGPHY_1000CTL_AFD 0x0200 /* Advertise full duplex */ +#define BRGPHY_1000CTL_AHD 0x0100 /* Advertise half duplex */ + +#define BRGPHY_MII_1000STS 0x0A /* 1000baseT status */ +#define BRGPHY_1000STS_MSF 0x8000 /* Master/slave fault */ +#define BRGPHY_1000STS_MSR 0x4000 /* Master/slave result */ +#define BRGPHY_1000STS_LRS 0x2000 /* Local receiver status */ +#define BRGPHY_1000STS_RRS 0x1000 /* Remote receiver status */ +#define BRGPHY_1000STS_LPFD 0x0800 /* Link partner can FD */ +#define BRGPHY_1000STS_LPHD 0x0400 /* Link partner can HD */ +#define BRGPHY_1000STS_IEC 0x00FF /* Idle error count */ + +#define BRGPHY_MII_EXTSTS 0x0F /* Extended status */ +#define BRGPHY_EXTSTS_X_FD_CAP 0x8000 /* 1000base-X FD capable */ +#define BRGPHY_EXTSTS_X_HD_CAP 0x4000 /* 1000base-X HD capable */ +#define BRGPHY_EXTSTS_T_FD_CAP 0x2000 /* 1000base-T FD capable */ +#define BRGPHY_EXTSTS_T_HD_CAP 0x1000 /* 1000base-T HD capable */ + +#define BRGPHY_MII_PHY_EXTCTL 0x10 /* PHY extended control */ +#define BRGPHY_PHY_EXTCTL_MAC_PHY 0x8000 /* 10BIT/GMI-interface */ +#define BRGPHY_PHY_EXTCTL_DIS_CROSS 0x4000 /* Disable MDI crossover */ +#define BRGPHY_PHY_EXTCTL_TX_DIS 0x2000 /* Tx output disable d*/ +#define BRGPHY_PHY_EXTCTL_INT_DIS 0x1000 /* Interrupts disabled */ +#define BRGPHY_PHY_EXTCTL_F_INT 0x0800 /* Force interrupt */ +#define BRGPHY_PHY_EXTCTL_BY_45 0x0400 /* Bypass 4B5B-Decoder */ +#define BRGPHY_PHY_EXTCTL_BY_SCR 0x0200 /* Bypass scrambler */ +#define BRGPHY_PHY_EXTCTL_BY_MLT3 0x0100 /* Bypass MLT3 encoder */ +#define BRGPHY_PHY_EXTCTL_BY_RXA 0x0080 /* Bypass RX alignment */ +#define BRGPHY_PHY_EXTCTL_RES_SCR 0x0040 /* Reset scrambler */ +#define BRGPHY_PHY_EXTCTL_EN_LTR 0x0020 /* Enable LED traffic mode */ +#define BRGPHY_PHY_EXTCTL_LED_ON 0x0010 /* Force LEDs on */ +#define BRGPHY_PHY_EXTCTL_LED_OFF 0x0008 /* Force LEDs off */ +#define BRGPHY_PHY_EXTCTL_EX_IPG 0x0004 /* Extended TX IPG mode */ +#define BRGPHY_PHY_EXTCTL_3_LED 0x0002 /* Three link LED mode */ +#define BRGPHY_PHY_EXTCTL_HIGH_LA 0x0001 /* GMII Fifo Elasticy (?) */ + +#define BRGPHY_MII_PHY_EXTSTS 0x11 /* PHY extended status */ +#define BRGPHY_PHY_EXTSTS_CROSS_STAT 0x2000 /* MDI crossover status */ +#define BRGPHY_PHY_EXTSTS_INT_STAT 0x1000 /* Interrupt status */ +#define BRGPHY_PHY_EXTSTS_RRS 0x0800 /* Remote receiver status */ +#define BRGPHY_PHY_EXTSTS_LRS 0x0400 /* Local receiver status */ +#define BRGPHY_PHY_EXTSTS_LOCKED 0x0200 /* Locked */ +#define BRGPHY_PHY_EXTSTS_LS 0x0100 /* Link status */ +#define BRGPHY_PHY_EXTSTS_RF 0x0080 /* Remove fault */ +#define BRGPHY_PHY_EXTSTS_CE_ER 0x0040 /* Carrier ext error */ +#define BRGPHY_PHY_EXTSTS_BAD_SSD 0x0020 /* Bad SSD */ +#define BRGPHY_PHY_EXTSTS_BAD_ESD 0x0010 /* Bad ESS */ +#define BRGPHY_PHY_EXTSTS_RX_ER 0x0008 /* RX error */ +#define BRGPHY_PHY_EXTSTS_TX_ER 0x0004 /* TX error */ +#define BRGPHY_PHY_EXTSTS_LOCK_ER 0x0002 /* Lock error */ +#define BRGPHY_PHY_EXTSTS_MLT3_ER 0x0001 /* MLT3 code error */ + +#define BRGPHY_MII_RXERRCNT 0x12 /* RX error counter */ + +#define BRGPHY_MII_FCERRCNT 0x13 /* false carrier sense counter */ +#define BGRPHY_FCERRCNT 0x00FF /* False carrier counter */ + +#define BRGPHY_MII_RXNOCNT 0x14 /* RX not OK counter */ +#define BRGPHY_RXNOCNT_LOCAL 0xFF00 /* Local RX not OK counter */ +#define BRGPHY_RXNOCNT_REMOTE 0x00FF /* Local RX not OK counter */ + +#define BRGPHY_MII_DSP_RW_PORT 0x15 /* DSP coefficient r/w port */ + +#define BRGPHY_MII_DSP_ADDR_REG 0x17 /* DSP coefficient addr register */ + +#define BRGPHY_DSP_TAP_NUMBER_MASK 0x00 +#define BRGPHY_DSP_AGC_A 0x00 +#define BRGPHY_DSP_AGC_B 0x01 +#define BRGPHY_DSP_MSE_PAIR_STATUS 0x02 +#define BRGPHY_DSP_SOFT_DECISION 0x03 +#define BRGPHY_DSP_PHASE_REG 0x04 +#define BRGPHY_DSP_SKEW 0x05 +#define BRGPHY_DSP_POWER_SAVER_UPPER_BOUND 0x06 +#define BRGPHY_DSP_POWER_SAVER_LOWER_BOUND 0x07 +#define BRGPHY_DSP_LAST_ECHO 0x08 +#define BRGPHY_DSP_FREQUENCY 0x09 +#define BRGPHY_DSP_PLL_BANDWIDTH 0x0A +#define BRGPHY_DSP_PLL_PHASE_OFFSET 0x0B + +#define BRGPHYDSP_FILTER_DCOFFSET 0x0C00 +#define BRGPHY_DSP_FILTER_FEXT3 0x0B00 +#define BRGPHY_DSP_FILTER_FEXT2 0x0A00 +#define BRGPHY_DSP_FILTER_FEXT1 0x0900 +#define BRGPHY_DSP_FILTER_FEXT0 0x0800 +#define BRGPHY_DSP_FILTER_NEXT3 0x0700 +#define BRGPHY_DSP_FILTER_NEXT2 0x0600 +#define BRGPHY_DSP_FILTER_NEXT1 0x0500 +#define BRGPHY_DSP_FILTER_NEXT0 0x0400 +#define BRGPHY_DSP_FILTER_ECHO 0x0300 +#define BRGPHY_DSP_FILTER_DFE 0x0200 +#define BRGPHY_DSP_FILTER_FFE 0x0100 + +#define BRGPHY_DSP_CONTROL_ALL_FILTERS 0x1000 + +#define BRGPHY_DSP_SEL_CH_0 0x0000 +#define BRGPHY_DSP_SEL_CH_1 0x2000 +#define BRGPHY_DSP_SEL_CH_2 0x4000 +#define BRGPHY_DSP_SEL_CH_3 0x6000 + +#define BRGPHY_MII_AUXCTL 0x18 /* AUX control */ +#define BRGPHY_AUXCTL_LOW_SQ 0x8000 /* Low squelch */ +#define BRGPHY_AUXCTL_LONG_PKT 0x4000 /* RX long packets */ +#define BRGPHY_AUXCTL_ER_CTL 0x3000 /* Edgerate control */ +#define BRGPHY_AUXCTL_TX_TST 0x0400 /* TX test, always 1 */ +#define BRGPHY_AUXCTL_DIS_PRF 0x0080 /* dis part resp filter */ +#define BRGPHY_AUXCTL_DIAG_MODE 0x0004 /* Diagnostic mode */ + +#define BRGPHY_MII_AUXSTS 0x19 /* AUX status */ +#define BRGPHY_AUXSTS_ACOMP 0x8000 /* autoneg complete */ +#define BRGPHY_AUXSTS_AN_ACK 0x4000 /* autoneg complete ack */ +#define BRGPHY_AUXSTS_AN_ACK_D 0x2000 /* autoneg complete ack detect */ +#define BRGPHY_AUXSTS_AN_NPW 0x1000 /* autoneg next page wait */ +#define BRGPHY_AUXSTS_AN_RES 0x0700 /* AN HDC */ +#define BRGPHY_AUXSTS_PDF 0x0080 /* Parallel detect. fault */ +#define BRGPHY_AUXSTS_RF 0x0040 /* remote fault */ +#define BRGPHY_AUXSTS_ANP_R 0x0020 /* AN page received */ +#define BRGPHY_AUXSTS_LP_ANAB 0x0010 /* LP AN ability */ +#define BRGPHY_AUXSTS_LP_NPAB 0x0008 /* LP Next page ability */ +#define BRGPHY_AUXSTS_LINK 0x0004 /* Link status */ +#define BRGPHY_AUXSTS_PRR 0x0002 /* Pause resolution-RX */ +#define BRGPHY_AUXSTS_PRT 0x0001 /* Pause resolution-TX */ + +#define BRGPHY_RES_1000FD 0x0700 /* 1000baseT full duplex */ +#define BRGPHY_RES_1000HD 0x0600 /* 1000baseT half duplex */ +#define BRGPHY_RES_100FD 0x0500 /* 100baseT full duplex */ +#define BRGPHY_RES_100T4 0x0400 /* 100baseT4 */ +#define BRGPHY_RES_100HD 0x0300 /* 100baseT half duplex */ +#define BRGPHY_RES_10FD 0x0200 /* 10baseT full duplex */ +#define BRGPHY_RES_10HD 0x0100 /* 10baseT half duplex */ + +#define BRGPHY_MII_ISR 0x1A /* interrupt status */ +#define BRGPHY_ISR_PSERR 0x4000 /* Pair swap error */ +#define BRGPHY_ISR_MDXI_SC 0x2000 /* MDIX Status Change */ +#define BRGPHY_ISR_HCT 0x1000 /* counter above 32K */ +#define BRGPHY_ISR_LCT 0x0800 /* all counter below 128 */ +#define BRGPHY_ISR_AN_PR 0x0400 /* Autoneg page received */ +#define BRGPHY_ISR_NO_HDCL 0x0200 /* No HCD Link */ +#define BRGPHY_ISR_NO_HDC 0x0100 /* No HCD */ +#define BRGPHY_ISR_USHDC 0x0080 /* Negotiated Unsupported HCD */ +#define BRGPHY_ISR_SCR_S_ERR 0x0040 /* Scrambler sync error */ +#define BRGPHY_ISR_RRS_CHG 0x0020 /* Remote RX status change */ +#define BRGPHY_ISR_LRS_CHG 0x0010 /* Local RX status change */ +#define BRGPHY_ISR_DUP_CHG 0x0008 /* Duplex mode change */ +#define BRGPHY_ISR_LSP_CHG 0x0004 /* Link speed changed */ +#define BRGPHY_ISR_LNK_CHG 0x0002 /* Link status change */ +#define BRGPHY_ISR_CRCERR 0x0001 /* CEC error */ + +#define BRGPHY_MII_IMR 0x1B /* interrupt mask */ +#define BRGPHY_IMR_PSERR 0x4000 /* Pair swap error */ +#define BRGPHY_IMR_MDXI_SC 0x2000 /* MDIX Status Change */ +#define BRGPHY_IMR_HCT 0x1000 /* counter above 32K */ +#define BRGPHY_IMR_LCT 0x0800 /* all counter below 128 */ +#define BRGPHY_IMR_AN_PR 0x0400 /* Autoneg page received */ +#define BRGPHY_IMR_NO_HDCL 0x0200 /* No HCD Link */ +#define BRGPHY_IMR_NO_HDC 0x0100 /* No HCD */ +#define BRGPHY_IMR_USHDC 0x0080 /* Negotiated Unsupported HCD */ +#define BRGPHY_IMR_SCR_S_ERR 0x0040 /* Scrambler sync error */ +#define BRGPHY_IMR_RRS_CHG 0x0020 /* Remote RX status change */ +#define BRGPHY_IMR_LRS_CHG 0x0010 /* Local RX status change */ +#define BRGPHY_IMR_DUP_CHG 0x0008 /* Duplex mode change */ +#define BRGPHY_IMR_LSP_CHG 0x0004 /* Link speed changed */ +#define BRGPHY_IMR_LNK_CHG 0x0002 /* Link status change */ +#define BRGPHY_IMR_CRCERR 0x0001 /* CEC error */ + +#define BRGPHY_INTRS \ + ~(BRGPHY_IMR_LNK_CHG|BRGPHY_IMR_LSP_CHG|BRGPHY_IMR_DUP_CHG) + +#endif /* _DEV_BRGPHY_MIIREG_H_ */ diff --git a/sys/dev/mii/dcphy.c b/sys/dev/mii/dcphy.c new file mode 100644 index 0000000..4c930e5 --- /dev/null +++ b/sys/dev/mii/dcphy.c @@ -0,0 +1,464 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Pseudo-driver for internal NWAY support on DEC 21143 and workalike + * controllers. Technically we're abusing the miibus code to handle + * media selection and NWAY support here since there is no MII + * interface. However the logical operations are roughly the same, + * and the alternative is to create a fake MII interface in the driver, + * which is harder to do. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <machine/bus_pio.h> +#include <machine/bus_memio.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> + +#include <dev/pci/pcivar.h> + +#include <pci/if_dcreg.h> + +#include "miibus_if.h" + +#define DC_SETBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, \ + CSR_READ_4(sc, reg) | x) + +#define DC_CLRBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, \ + CSR_READ_4(sc, reg) & ~x) + +#define MIIF_AUTOTIMEOUT 0x0004 + +/* + * This is the subsystem ID for the built-in 21143 ethernet + * in several Compaq Presario systems. Apparently these are + * 10Mbps only, so we need to treat them specially. + */ +#define COMPAQ_PRESARIO_ID 0xb0bb0e11 + +static int dcphy_probe(device_t); +static int dcphy_attach(device_t); + +static device_method_t dcphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, dcphy_probe), + DEVMETHOD(device_attach, dcphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t dcphy_devclass; + +static driver_t dcphy_driver = { + "dcphy", + dcphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0); + +static int dcphy_service(struct mii_softc *, struct mii_data *, int); +static void dcphy_status(struct mii_softc *); +static void dcphy_reset(struct mii_softc *); +static int dcphy_auto(struct mii_softc *); + +static int +dcphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + /* + * The dc driver will report the 21143 vendor and device + * ID to let us know that it wants us to attach. + */ + if (ma->mii_id1 != DC_VENDORID_DEC || + ma->mii_id2 != DC_DEVICEID_21143) + return(ENXIO); + + device_set_desc(dev, "Intel 21143 NWAY media interface"); + + return (0); +} + +static int +dcphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + struct dc_softc *dc_sc; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = dcphy_service; + sc->mii_pdata = mii; + + sc->mii_flags |= MIIF_NOISOLATE; + mii->mii_instance++; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); + + /*dcphy_reset(sc);*/ + dc_sc = mii->mii_ifp->if_softc; + CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0); + CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0); + + switch(pci_read_config(device_get_parent(sc->mii_dev), + DC_PCI_CSID, 4)) { + case COMPAQ_PRESARIO_ID: + /* Example of how to only allow 10Mbps modes. */ + sc->mii_capabilities = BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX; + break; + default: + if (dc_sc->dc_pmode == DC_PMODE_SIA) { + sc->mii_capabilities = + BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX; + } else { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, + sc->mii_inst), BMCR_LOOP|BMCR_S100); + + sc->mii_capabilities = + BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX| + BMSR_10TFDX|BMSR_10THDX; + } + break; + } + + sc->mii_capabilities &= ma->mii_capmask; + device_printf(dev, " "); + mii_add_media(sc); + printf("\n"); +#undef ADD + + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +dcphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct dc_softc *dc_sc; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + u_int32_t mode; + + dc_sc = mii->mii_ifp->if_softc; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + return (0); + } + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + sc->mii_flags = 0; + mii->mii_media_active = IFM_NONE; + mode = CSR_READ_4(dc_sc, DC_NETCFG); + mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL| + DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL); + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /*dcphy_reset(sc);*/ + (void) dcphy_auto(sc); + break; + case IFM_100_T4: + /* + * XXX Not supported as a manual setting right now. + */ + return (EINVAL); + case IFM_100_TX: + dcphy_reset(sc); + DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); + mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS| + DC_NETCFG_SCRAMBLER; + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) + mode |= DC_NETCFG_FULLDUPLEX; + else + mode &= ~DC_NETCFG_FULLDUPLEX; + CSR_WRITE_4(dc_sc, DC_NETCFG, mode); + break; + case IFM_10_T: + DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); + DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF); + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) + DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D); + else + DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F); + DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); + DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); + mode &= ~DC_NETCFG_PORTSEL; + mode |= DC_NETCFG_SPEEDSEL; + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) + mode |= DC_NETCFG_FULLDUPLEX; + else + mode &= ~DC_NETCFG_FULLDUPLEX; + CSR_WRITE_4(dc_sc, DC_NETCFG, mode); + break; + default: + return(EINVAL); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + reg = CSR_READ_4(dc_sc, DC_10BTSTAT); + if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) + break; + + /* + * Only retry autonegotiation every 5 seconds. + * + * Otherwise, fall through to calling dcphy_status() + * since real Intel 21143 chips don't show valid link + * status until autonegotiation is switched off, and + * that only happens in dcphy_status(). Without this, + * successful autonegotation is never recognised on + * these chips. + */ + if (++sc->mii_ticks != 50) + break; + + sc->mii_ticks = 0; + dcphy_auto(sc); + + break; + } + + /* Update the media status. */ + dcphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +dcphy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + int reg, anlpar, tstat = 0; + struct dc_softc *dc_sc; + + dc_sc = mii->mii_ifp->if_softc; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return; + + reg = CSR_READ_4(dc_sc, DC_10BTSTAT); + if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) + mii->mii_media_status |= IFM_ACTIVE; + + if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) { + /* Erg, still trying, I guess... */ + tstat = CSR_READ_4(dc_sc, DC_10BTSTAT); + if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) { + if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) && + (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE) + goto skip; + mii->mii_media_active |= IFM_NONE; + return; + } + + if (tstat & DC_TSTAT_LP_CAN_NWAY) { + anlpar = tstat >> 16; + if (anlpar & ANLPAR_T4 && + sc->mii_capabilities & BMSR_100TXHDX) + mii->mii_media_active |= IFM_100_T4; + else if (anlpar & ANLPAR_TX_FD && + sc->mii_capabilities & BMSR_100TXFDX) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_TX && + sc->mii_capabilities & BMSR_100TXHDX) + mii->mii_media_active |= IFM_100_TX; + else if (anlpar & ANLPAR_10_FD) + mii->mii_media_active |= IFM_10_T|IFM_FDX; + else if (anlpar & ANLPAR_10) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_NONE; + if (DC_IS_INTEL(dc_sc)) + DC_CLRBIT(dc_sc, DC_10BTCTRL, + DC_TCTL_AUTONEGENBL); + return; + } + /* + * If the other side doesn't support NWAY, then the + * best we can do is determine if we have a 10Mbps or + * 100Mbps link. There's no way to know if the link + * is full or half duplex, so we default to half duplex + * and hope that the user is clever enough to manually + * change the media settings if we're wrong. + */ + if (!(reg & DC_TSTAT_LS100)) + mii->mii_media_active |= IFM_100_TX; + else if (!(reg & DC_TSTAT_LS10)) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_NONE; + if (DC_IS_INTEL(dc_sc)) + DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); + return; + } + +skip: + + if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_100_TX; + if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX) + mii->mii_media_active |= IFM_FDX; + + return; +} + +static int +dcphy_auto(mii) + struct mii_softc *mii; +{ + struct dc_softc *sc; + + sc = mii->mii_pdata->mii_ifp->if_softc; + + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX); + DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); + if (mii->mii_capabilities & BMSR_100TXHDX) + CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF); + else + CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF); + DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); + DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); + DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE); + + return(EJUSTRETURN); +} + +static void +dcphy_reset(mii) + struct mii_softc *mii; +{ + struct dc_softc *sc; + + sc = mii->mii_pdata->mii_ifp->if_softc; + + DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); + DELAY(1000); + DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); + + return; +} + diff --git a/sys/dev/mii/e1000phy.c b/sys/dev/mii/e1000phy.c new file mode 100644 index 0000000..6f9f458 --- /dev/null +++ b/sys/dev/mii/e1000phy.c @@ -0,0 +1,428 @@ +/* + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + * Principal Author: Parag Patel + * Copyright (c) 2001 + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Additonal Copyright (c) 2001 by Traakan Software under same licence. + * Secondary Author: Matthew Jacob + */ + +/* + * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY. + */ + +/* + * Support added for the Marvell 88E1011 (Alaska) 1000/100/10baseTX and + * 1000baseSX PHY. + * Nathan Binkert <nate@openbsd.org> + * Jung-uk Kim <jkim@niksun.com> + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <machine/clock.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/e1000phyreg.h> + +#include "miibus_if.h" + +static int e1000phy_probe(device_t); +static int e1000phy_attach(device_t); + +static device_method_t e1000phy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, e1000phy_probe), + DEVMETHOD(device_attach, e1000phy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t e1000phy_devclass; +static driver_t e1000phy_driver = { + "e1000phy", e1000phy_methods, sizeof (struct mii_softc) +}; +DRIVER_MODULE(e1000phy, miibus, e1000phy_driver, e1000phy_devclass, 0, 0); + +static int e1000phy_service(struct mii_softc *, struct mii_data *, int); +static void e1000phy_status(struct mii_softc *); +static void e1000phy_reset(struct mii_softc *); +static int e1000phy_mii_phy_auto(struct mii_softc *); + +static int e1000phy_debug = 0; + +static int +e1000phy_probe(device_t dev) +{ + struct mii_attach_args *ma; + u_int32_t id; + + ma = device_get_ivars(dev); + id = ((ma->mii_id1 << 16) | ma->mii_id2) & E1000_ID_MASK; + if (id != E1000_ID_88E1000 + && id != E1000_ID_88E1000S + && id != E1000_ID_88E1011) { + return ENXIO; + } + + device_set_desc(dev, MII_STR_MARVELL_E1000); + return 0; +} + +static int +e1000phy_attach(device_t dev) +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + u_int32_t id; + + getenv_int("e1000phy_debug", &e1000phy_debug); + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = e1000phy_service; + sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOISOLATE; + + id = ((ma->mii_id1 << 16) | ma->mii_id2) & E1000_ID_MASK; + if (id == E1000_ID_88E1011 + && (PHY_READ(sc, E1000_ESSR) & E1000_ESSR_FIBER_LINK)) + sc->mii_flags |= MIIF_HAVEFIBER; + mii->mii_instance++; + e1000phy_reset(sc); + + device_printf(dev, " "); + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { +#if 0 + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + E1000_CR_ISOLATE); +#endif + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), + E1000_CR_SPEED_10); + printf("10baseT, "); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), + E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX); + printf("10baseT-FDX, "); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), + E1000_CR_SPEED_100); + printf("100baseTX, "); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), + E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX); + printf("100baseTX-FDX, "); + /* + * 1000BT-simplex not supported; driver must ignore this entry, + * but it must be present in order to manually set full-duplex. + */ + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), + E1000_CR_SPEED_1000); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), + E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); + printf("1000baseTX-FDX, "); + } else { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), + E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); + printf("1000baseSX-FDX, "); + } + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); + printf("auto\n"); +#undef ADD + + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static void +e1000phy_reset(struct mii_softc *sc) +{ + u_int32_t reg; + int i; + + /* initialize custom E1000 registers to magic values */ + reg = PHY_READ(sc, E1000_SCR); + reg &= ~E1000_SCR_AUTO_X_MODE; + PHY_WRITE(sc, E1000_SCR, reg); + + /* normal PHY reset */ + /*mii_phy_reset(sc);*/ + reg = PHY_READ(sc, E1000_CR); + reg |= E1000_CR_RESET; + PHY_WRITE(sc, E1000_CR, reg); + + for (i = 0; i < 500; i++) { + DELAY(1); + reg = PHY_READ(sc, E1000_CR); + if (!(reg & E1000_CR_RESET)) + break; + } + + /* set more custom E1000 registers to magic values */ + reg = PHY_READ(sc, E1000_SCR); + reg |= E1000_SCR_ASSERT_CRS_ON_TX; + PHY_WRITE(sc, E1000_SCR, reg); + + reg = PHY_READ(sc, E1000_ESCR); + reg |= E1000_ESCR_TX_CLK_25; + PHY_WRITE(sc, E1000_ESCR, reg); + + /* even more magic to reset DSP? */ + PHY_WRITE(sc, 29, 0x1d); + PHY_WRITE(sc, 30, 0xc1); + PHY_WRITE(sc, 30, 0x00); +} + +static int +e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, E1000_CR); + PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { + break; + } + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + e1000phy_reset(sc); + (void)e1000phy_mii_phy_auto(sc); + break; + + case IFM_1000_T: + e1000phy_reset(sc); + + /* TODO - any other way to force 1000BT? */ + (void)e1000phy_mii_phy_auto(sc); + break; + + case IFM_1000_SX: + e1000phy_reset(sc); + + PHY_WRITE(sc, E1000_CR, + E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_1000); + PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD); + break; + + case IFM_100_TX: + e1000phy_reset(sc); + + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + PHY_WRITE(sc, E1000_CR, + E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_100); + PHY_WRITE(sc, E1000_AR, E1000_AR_100TX_FD); + } else { + PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_100); + PHY_WRITE(sc, E1000_AR, E1000_AR_100TX); + } + break; + + case IFM_10_T: + e1000phy_reset(sc); + + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + PHY_WRITE(sc, E1000_CR, + E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_10); + PHY_WRITE(sc, E1000_AR, E1000_AR_10T_FD); + } else { + PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_10); + PHY_WRITE(sc, E1000_AR, E1000_AR_10T); + } + + break; + + default: + return (EINVAL); + } + + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + return (0); + } + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * check for link. + * Read the status register twice; BMSR_LINK is latch-low. + */ + reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + if (reg & BMSR_LINK) + break; + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->mii_ticks != 5) + return (0); + + sc->mii_ticks = 0; + e1000phy_reset(sc); + e1000phy_mii_phy_auto(sc); + return (0); + } + + /* Update the media status. */ + e1000phy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +e1000phy_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + int bmsr, bmcr, esr, ssr, isr, ar, lpar; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); + esr = PHY_READ(sc, E1000_ESR); + bmcr = PHY_READ(sc, E1000_CR); + ssr = PHY_READ(sc, E1000_SSR); + isr = PHY_READ(sc, E1000_ISR); + ar = PHY_READ(sc, E1000_AR); + lpar = PHY_READ(sc, E1000_LPAR); + + if (bmsr & E1000_SR_LINK_STATUS) + mii->mii_media_status |= IFM_ACTIVE; + + if (bmcr & E1000_CR_LOOPBACK) + mii->mii_media_active |= IFM_LOOP; + + if ((!(bmsr & E1000_SR_AUTO_NEG_COMPLETE) || !(ssr & E1000_SSR_LINK) || + !(ssr & E1000_SSR_SPD_DPLX_RESOLVED))) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { + if (ssr & E1000_SSR_1000MBS) + mii->mii_media_active |= IFM_1000_T; + else if (ssr & E1000_SSR_100MBS) + mii->mii_media_active |= IFM_100_TX; + else + mii->mii_media_active |= IFM_10_T; + } else { + if (ssr & E1000_SSR_1000MBS) + mii->mii_media_active |= IFM_1000_SX; + } + + if (ssr & E1000_SSR_DUPLEX) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + + if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { + /* FLAG0==rx-flow-control FLAG1==tx-flow-control */ + if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) { + mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; + } else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && + (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { + mii->mii_media_active |= IFM_FLAG1; + } else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && + !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { + mii->mii_media_active |= IFM_FLAG0; + } + } +} + +static int +e1000phy_mii_phy_auto(struct mii_softc *mii) +{ + + if ((mii->mii_flags & MIIF_HAVEFIBER) == 0) { + PHY_WRITE(mii, E1000_AR, E1000_AR_10T | E1000_AR_10T_FD | + E1000_AR_100TX | E1000_AR_100TX_FD | + E1000_AR_PAUSE | E1000_AR_ASM_DIR); + PHY_WRITE(mii, E1000_1GCR, E1000_1GCR_1000T_FD); + PHY_WRITE(mii, E1000_CR, + E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG); + } + + return (EJUSTRETURN); +} diff --git a/sys/dev/mii/e1000phyreg.h b/sys/dev/mii/e1000phyreg.h new file mode 100644 index 0000000..bdfc665 --- /dev/null +++ b/sys/dev/mii/e1000phyreg.h @@ -0,0 +1,314 @@ +/* $FreeBSD$ */ +/* + * Principal Author: Parag Patel + * Copyright (c) 2001 + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Additonal Copyright (c) 2001 by Traakan Software under same licence. + * Secondary Author: Matthew Jacob + */ + +/* + * Derived by information released by Intel under the following license: + * + * Copyright (c) 1999 - 2001, Intel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * Marvell E1000 PHY registers + */ + +#define E1000_MAX_REG_ADDRESS 0x1F + +#define E1000_CR 0x00 /* control register */ +#define E1000_CR_SPEED_SELECT_MSB 0x0040 +#define E1000_CR_COLL_TEST_ENABLE 0x0080 +#define E1000_CR_FULL_DUPLEX 0x0100 +#define E1000_CR_RESTART_AUTO_NEG 0x0200 +#define E1000_CR_ISOLATE 0x0400 +#define E1000_CR_POWER_DOWN 0x0800 +#define E1000_CR_AUTO_NEG_ENABLE 0x1000 +#define E1000_CR_SPEED_SELECT_LSB 0x2000 +#define E1000_CR_LOOPBACK 0x4000 +#define E1000_CR_RESET 0x8000 + +#define E1000_CR_SPEED_1000 0x0040 +#define E1000_CR_SPEED_100 0x2000 +#define E1000_CR_SPEED_10 0x0000 + +#define E1000_SR 0x01 /* status register */ +#define E1000_SR_EXTENDED 0x0001 +#define E1000_SR_JABBER_DETECT 0x0002 +#define E1000_SR_LINK_STATUS 0x0004 +#define E1000_SR_AUTO_NEG 0x0008 +#define E1000_SR_REMOTE_FAULT 0x0010 +#define E1000_SR_AUTO_NEG_COMPLETE 0x0020 +#define E1000_SR_PREAMBLE_SUPPRESS 0x0040 +#define E1000_SR_EXTENDED_STATUS 0x0100 +#define E1000_SR_100T2 0x0200 +#define E1000_SR_100T2_FD 0x0400 +#define E1000_SR_10T 0x0800 +#define E1000_SR_10T_FD 0x1000 +#define E1000_SR_100TX 0x2000 +#define E1000_SR_100TX_FD 0x4000 +#define E1000_SR_100T4 0x8000 + +#define E1000_ID1 0x02 /* ID register 1 */ +#define E1000_ID2 0x03 /* ID register 2 */ +#define E1000_ID_88E1000 0x01410C50 +#define E1000_ID_88E1000S 0x01410C40 +#define E1000_ID_88E1011 0x01410C20 +#define E1000_ID_MASK 0xFFFFFFF0 + +#define E1000_AR 0x04 /* autonegotiation advertise reg */ +#define E1000_AR_SELECTOR_FIELD 0x0001 +#define E1000_AR_10T 0x0020 +#define E1000_AR_10T_FD 0x0040 +#define E1000_AR_100TX 0x0080 +#define E1000_AR_100TX_FD 0x0100 +#define E1000_AR_100T4 0x0200 +#define E1000_AR_PAUSE 0x0400 +#define E1000_AR_ASM_DIR 0x0800 +#define E1000_AR_REMOTE_FAULT 0x2000 +#define E1000_AR_NEXT_PAGE 0x8000 +#define E1000_AR_SPEED_MASK 0x01E0 + +/* Autonegotiation register bits for fiber cards (Alaska Only!) */ +#define E1000_FA_1000X_FD 0x0020 +#define E1000_FA_1000X 0x0040 +#define E1000_FA_SYM_PAUSE 0x0080 +#define E1000_FA_ASYM_PAUSE 0x0100 +#define E1000_FA_FAULT1 0x1000 +#define E1000_FA_FAULT2 0x2000 +#define E1000_FA_NEXT_PAGE 0x8000 + +#define E1000_LPAR 0x05 /* autoneg link partner abilities reg */ +#define E1000_LPAR_SELECTOR_FIELD 0x0001 +#define E1000_LPAR_10T 0x0020 +#define E1000_LPAR_10T_FD 0x0040 +#define E1000_LPAR_100TX 0x0080 +#define E1000_LPAR_100TX_FD 0x0100 +#define E1000_LPAR_100T4 0x0200 +#define E1000_LPAR_PAUSE 0x0400 +#define E1000_LPAR_ASM_DIR 0x0800 +#define E1000_LPAR_REMOTE_FAULT 0x2000 +#define E1000_LPAR_ACKNOWLEDGE 0x4000 +#define E1000_LPAR_NEXT_PAGE 0x8000 + +/* autoneg link partner ability register bits for fiber cards (Alaska Only!) */ +#define E1000_FPAR_1000X_FD 0x0020 +#define E1000_FPAR_1000X 0x0040 +#define E1000_FPAR_SYM_PAUSE 0x0080 +#define E1000_FPAR_ASYM_PAUSE 0x0100 +#define E1000_FPAR_FAULT1 0x1000 +#define E1000_FPAR_FAULT2 0x2000 +#define E1000_FPAR_ACK 0x4000 +#define E1000_FPAR_NEXT_PAGE 0x8000 + +#define E1000_ER 0x06 /* autoneg expansion reg */ +#define E1000_ER_LP_NWAY 0x0001 +#define E1000_ER_PAGE_RXD 0x0002 +#define E1000_ER_NEXT_PAGE 0x0004 +#define E1000_ER_LP_NEXT_PAGE 0x0008 +#define E1000_ER_PAR_DETECT_FAULT 0x0100 + +#define E1000_NPTX 0x07 /* autoneg next page TX */ +#define E1000_NPTX_MSG_CODE_FIELD 0x0001 +#define E1000_NPTX_TOGGLE 0x0800 +#define E1000_NPTX_ACKNOWLDGE2 0x1000 +#define E1000_NPTX_MSG_PAGE 0x2000 +#define E1000_NPTX_NEXT_PAGE 0x8000 + +#define E1000_RNPR 0x08 /* autoneg link-partner (?) next page */ +#define E1000_RNPR_MSG_CODE_FIELD 0x0001 +#define E1000_RNPR_TOGGLE 0x0800 +#define E1000_RNPR_ACKNOWLDGE2 0x1000 +#define E1000_RNPR_MSG_PAGE 0x2000 +#define E1000_RNPR_ACKNOWLDGE 0x4000 +#define E1000_RNPR_NEXT_PAGE 0x8000 + +#define E1000_1GCR 0x09 /* 1000T (1G) control reg */ +#define E1000_1GCR_ASYM_PAUSE 0x0080 +#define E1000_1GCR_1000T 0x0100 +#define E1000_1GCR_1000T_FD 0x0200 +#define E1000_1GCR_REPEATER_DTE 0x0400 +#define E1000_1GCR_MS_VALUE 0x0800 +#define E1000_1GCR_MS_ENABLE 0x1000 +#define E1000_1GCR_TEST_MODE_NORMAL 0x0000 +#define E1000_1GCR_TEST_MODE_1 0x2000 +#define E1000_1GCR_TEST_MODE_2 0x4000 +#define E1000_1GCR_TEST_MODE_3 0x6000 +#define E1000_1GCR_TEST_MODE_4 0x8000 +#define E1000_1GCR_SPEED_MASK 0x0300 + +#define E1000_1GSR 0x0A /* 1000T (1G) status reg */ +#define E1000_1GSR_IDLE_ERROR_CNT 0x0000 +#define E1000_1GSR_ASYM_PAUSE_DIR 0x0100 +#define E1000_1GSR_LP 0x0400 +#define E1000_1GSR_LP_FD 0x0800 +#define E1000_1GSR_REMOTE_RX_STATUS 0x1000 +#define E1000_1GSR_LOCAL_RX_STATUS 0x2000 +#define E1000_1GSR_MS_CONFIG_RES 0x4000 +#define E1000_1GSR_MS_CONFIG_FAULT 0x8000 + +#define E1000_ESR 0x0F /* IEEE extended status reg */ +#define E1000_ESR_1000T 0x1000 +#define E1000_ESR_1000T_FD 0x2000 +#define E1000_ESR_1000X 0x4000 +#define E1000_ESR_1000X_FD 0x8000 + +#define E1000_TX_POLARITY_MASK 0x0100 +#define E1000_TX_NORMAL_POLARITY 0 + +#define E1000_AUTO_POLARITY_DISABLE 0x0010 + +#define E1000_SCR 0x10 /* special control register */ +#define E1000_SCR_JABBER_DISABLE 0x0001 +#define E1000_SCR_POLARITY_REVERSAL 0x0002 +#define E1000_SCR_SQE_TEST 0x0004 +#define E1000_SCR_INT_FIFO_DISABLE 0x0008 +#define E1000_SCR_CLK125_DISABLE 0x0010 +#define E1000_SCR_MDI_MANUAL_MODE 0x0000 +#define E1000_SCR_MDIX_MANUAL_MODE 0x0020 +#define E1000_SCR_AUTO_X_1000T 0x0040 +#define E1000_SCR_AUTO_X_MODE 0x0060 +#define E1000_SCR_10BT_EXT_ENABLE 0x0080 +#define E1000_SCR_MII_5BIT_ENABLE 0x0100 +#define E1000_SCR_SCRAMBLER_DISABLE 0x0200 +#define E1000_SCR_FORCE_LINK_GOOD 0x0400 +#define E1000_SCR_ASSERT_CRS_ON_TX 0x0800 +#define E1000_SCR_RX_FIFO_DEPTH_6 0x0000 +#define E1000_SCR_RX_FIFO_DEPTH_8 0x1000 +#define E1000_SCR_RX_FIFO_DEPTH_10 0x2000 +#define E1000_SCR_RX_FIFO_DEPTH_12 0x3000 +#define E1000_SCR_TX_FIFO_DEPTH_6 0x0000 +#define E1000_SCR_TX_FIFO_DEPTH_8 0x4000 +#define E1000_SCR_TX_FIFO_DEPTH_10 0x8000 +#define E1000_SCR_TX_FIFO_DEPTH_12 0xC000 + +#define E1000_SSR 0x11 /* special status register */ +#define E1000_SSR_JABBER 0x0001 +#define E1000_SSR_REV_POLARITY 0x0002 +#define E1000_SSR_MDIX 0x0020 +#define E1000_SSR_LINK 0x0400 +#define E1000_SSR_SPD_DPLX_RESOLVED 0x0800 +#define E1000_SSR_PAGE_RCVD 0x1000 +#define E1000_SSR_DUPLEX 0x2000 +#define E1000_SSR_SPEED 0xC000 +#define E1000_SSR_10MBS 0x0000 +#define E1000_SSR_100MBS 0x4000 +#define E1000_SSR_1000MBS 0x8000 + +#define E1000_IER 0x12 /* interrupt enable reg */ +#define E1000_IER_JABBER 0x0001 +#define E1000_IER_POLARITY_CHANGE 0x0002 +#define E1000_IER_MDIX_CHANGE 0x0040 +#define E1000_IER_FIFO_OVER_UNDERUN 0x0080 +#define E1000_IER_FALSE_CARRIER 0x0100 +#define E1000_IER_SYMBOL_ERROR 0x0200 +#define E1000_IER_LINK_STAT_CHANGE 0x0400 +#define E1000_IER_AUTO_NEG_COMPLETE 0x0800 +#define E1000_IER_PAGE_RECEIVED 0x1000 +#define E1000_IER_DUPLEX_CHANGED 0x2000 +#define E1000_IER_SPEED_CHANGED 0x4000 +#define E1000_IER_AUTO_NEG_ERR 0x8000 + +#define E1000_ISR 0x13 /* interrupt status reg */ +#define E1000_ISR_JABBER 0x0001 +#define E1000_ISR_POLARITY_CHANGE 0x0002 +#define E1000_ISR_MDIX_CHANGE 0x0040 +#define E1000_ISR_FIFO_OVER_UNDERUN 0x0080 +#define E1000_ISR_FALSE_CARRIER 0x0100 +#define E1000_ISR_SYMBOL_ERROR 0x0200 +#define E1000_ISR_LINK_STAT_CHANGE 0x0400 +#define E1000_ISR_AUTO_NEG_COMPLETE 0x0800 +#define E1000_ISR_PAGE_RECEIVED 0x1000 +#define E1000_ISR_DUPLEX_CHANGED 0x2000 +#define E1000_ISR_SPEED_CHANGED 0x4000 +#define E1000_ISR_AUTO_NEG_ERR 0x8000 + +#define E1000_ESCR 0x14 /* extended special control reg */ +#define E1000_ESCR_FIBER_LOOPBACK 0x4000 +#define E1000_ESCR_DOWN_NO_IDLE 0x8000 +#define E1000_ESCR_TX_CLK_2_5 0x0060 +#define E1000_ESCR_TX_CLK_25 0x0070 +#define E1000_ESCR_TX_CLK_0 0x0000 + +#define E1000_RECR 0x15 /* RX error counter reg */ + +#define E1000_LCR 0x18 /* LED control reg */ +#define E1000_LCR_LED_TX 0x0001 +#define E1000_LCR_LED_RX 0x0002 +#define E1000_LCR_LED_DUPLEX 0x0004 +#define E1000_LCR_LINK 0x0008 +#define E1000_LCR_BLINK_42MS 0x0000 +#define E1000_LCR_BLINK_84MS 0x0100 +#define E1000_LCR_BLINK_170MS 0x0200 +#define E1000_LCR_BLINK_340MS 0x0300 +#define E1000_LCR_BLINK_670MS 0x0400 +#define E1000_LCR_PULSE_OFF 0x0000 +#define E1000_LCR_PULSE_21_42MS 0x1000 +#define E1000_LCR_PULSE_42_84MS 0x2000 +#define E1000_LCR_PULSE_84_170MS 0x3000 +#define E1000_LCR_PULSE_170_340MS 0x4000 +#define E1000_LCR_PULSE_340_670MS 0x5000 +#define E1000_LCR_PULSE_670_13S 0x6000 +#define E1000_LCR_PULSE_13_26S 0x7000 + +/* The following register is found only on the 88E1011 Alaska PHY */ +#define E1000_ESSR 0x1B /* Extended PHY specific sts */ +#define E1000_ESSR_FIBER_LINK 0x2000 +#define E1000_ESSR_GMII_COPPER 0x000f +#define E1000_ESSR_GMII_FIBER 0x0007 +#define E1000_ESSR_TBI_COPPER 0x000d +#define E1000_ESSR_TBI_FIBER 0x0005 diff --git a/sys/dev/mii/exphy.c b/sys/dev/mii/exphy.c new file mode 100644 index 0000000..97c97cd --- /dev/null +++ b/sys/dev/mii/exphy.c @@ -0,0 +1,274 @@ +/* $NetBSD: exphy.c,v 1.16 1999/04/23 04:24:32 thorpej Exp $ */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center, and by Frank van der Linden. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * driver for 3Com internal PHYs + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include "miibus_if.h" + +static int exphy_probe(device_t); +static int exphy_attach(device_t); + +static device_method_t exphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, exphy_probe), + DEVMETHOD(device_attach, exphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t exphy_devclass; + +static driver_t exphy_driver = { + "xlphy", + exphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(xlphy, miibus, exphy_driver, exphy_devclass, 0, 0); + +static int exphy_service(struct mii_softc *, struct mii_data *, int); +static void exphy_reset(struct mii_softc *); + +static int +exphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + device_t parent; + + ma = device_get_ivars(dev); + parent = device_get_parent(device_get_parent(dev)); + + /* + * Argh, 3Com PHY reports oui == 0 model == 0! + */ + if ((MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || + MII_MODEL(ma->mii_id2) != 0) && + (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM || + MII_MODEL(ma->mii_id2) != MII_MODEL_BROADCOM_3C905C)) + return (ENXIO); + + /* + * Make sure the parent is an `ex'. + */ + if (strcmp(device_get_name(parent), "xl") != 0) + return (ENXIO); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == 0) + device_set_desc(dev, "3Com internal media interface"); + else + device_set_desc(dev, MII_STR_BROADCOM_3C905C); + + return (0); +} + +static int +exphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + + /* + * The 3Com PHY can never be isolated, so never allow non-zero + * instances! + */ + if (mii->mii_instance != 0) { + device_printf(dev, "ignoring this PHY, non-zero instance\n"); + return(ENXIO); + } + + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = exphy_service; + sc->mii_pdata = mii; + mii->mii_instance++; + + sc->mii_flags |= MIIF_NOISOLATE; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + +#if 0 /* See above. */ + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#endif + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); + + exphy_reset(sc); + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + mii_phy_add_media(sc); + printf("\n"); +#undef ADD + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +exphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + + /* + * We can't isolate the 3Com PHY, so it has to be the only one! + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + panic("exphy_service: can't isolate 3Com PHY"); + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + mii_phy_setmedia(sc); + break; + + case MII_TICK: + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * The 3Com PHY's autonegotiation doesn't need to be + * kicked; it continues in the background. + */ + break; + } + + /* Update the media status. */ + ukphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +exphy_reset(struct mii_softc *sc) +{ + + mii_phy_reset(sc); + + /* + * XXX 3Com PHY doesn't set the BMCR properly after + * XXX reset, which breaks autonegotiation. + */ + PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_AUTOEN|BMCR_FDX); +} diff --git a/sys/dev/mii/inphy.c b/sys/dev/mii/inphy.c new file mode 100644 index 0000000..3aa6f16 --- /dev/null +++ b/sys/dev/mii/inphy.c @@ -0,0 +1,236 @@ +/*- + * Copyright (c) 2001 Jonathan Lemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * driver for Intel 82553 and 82555 PHYs + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/inphyreg.h> + +#include "miibus_if.h" + +static int inphy_probe(device_t dev); +static int inphy_attach(device_t dev); + +static device_method_t inphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, inphy_probe), + DEVMETHOD(device_attach, inphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t inphy_devclass; + +static driver_t inphy_driver = { + "inphy", + inphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(inphy, miibus, inphy_driver, inphy_devclass, 0, 0); + +static int inphy_service(struct mii_softc *, struct mii_data *, int); +static void inphy_status(struct mii_softc *); + +static int +inphy_probe(device_t dev) +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + /* Intel 82553 A/B steppings */ + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxINTEL && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxINTEL_I82553AB) { + device_set_desc(dev, MII_STR_xxINTEL_I82553AB); + return (0); + } + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_INTEL) { + switch (MII_MODEL(ma->mii_id2)) { + case MII_MODEL_INTEL_I82555: + device_set_desc(dev, MII_STR_INTEL_I82555); + return (0); + case MII_MODEL_INTEL_I82553C: + device_set_desc(dev, MII_STR_INTEL_I82553C); + return (0); + case MII_MODEL_INTEL_I82562EM: + device_set_desc(dev, MII_STR_INTEL_I82562EM); + return (0); + case MII_MODEL_INTEL_I82562ET: + device_set_desc(dev, MII_STR_INTEL_I82562ET); + return (0); + } + } + + return (ENXIO); +} + +static int +inphy_attach(device_t dev) +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = inphy_service; + sc->mii_pdata = mii; + mii->mii_instance++; + +#if 0 + sc->mii_flags |= MIIF_NOISOLATE; +#endif + + ifmedia_add(&mii->mii_media, + IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100, NULL); + + mii_phy_reset(sc); + + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + mii_phy_add_media(sc); + printf("\n"); + + MIIBUS_MEDIAINIT(sc->mii_dev); + + return (0); +} + +static int +inphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + mii_phy_setmedia(sc); + break; + + case MII_TICK: + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + inphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +inphy_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmsr, bmcr, scr; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + if ((bmsr & BMSR_ACOMP) == 0) { + mii->mii_media_active |= IFM_NONE; + return; + } + + scr = PHY_READ(sc, MII_INPHY_SCR); + if (scr & SCR_S100) + mii->mii_media_active |= IFM_100_TX; + else + mii->mii_media_active |= IFM_10_T; + if (scr & SCR_FDX) + mii->mii_media_active |= IFM_FDX; + } else + mii->mii_media_active = ife->ifm_media; +} diff --git a/sys/dev/mii/inphyreg.h b/sys/dev/mii/inphyreg.h new file mode 100644 index 0000000..4b7d1f1 --- /dev/null +++ b/sys/dev/mii/inphyreg.h @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2001 Jonathan Lemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define MII_INPHY_SCR 0x10 /* status and control register */ +#define SCR_FLOWCTL 0x8000 +#define SCR_S100 0x0002 /* autonegotiated speed */ +#define SCR_FDX 0x0001 /* autonegotiated duplex */ diff --git a/sys/dev/mii/lxtphy.c b/sys/dev/mii/lxtphy.c new file mode 100644 index 0000000..57fbe16 --- /dev/null +++ b/sys/dev/mii/lxtphy.c @@ -0,0 +1,343 @@ +/* OpenBSD: lxtphy.c,v 1.5 2000/08/26 20:04:17 nate Exp */ +/* NetBSD: lxtphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * driver for Level One's LXT-970 ethernet 10/100 PHY + * datasheet from www.level1.com + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/lxtphyreg.h> + +#include "miibus_if.h" + +static int lxtphy_probe(device_t); +static int lxtphy_attach(device_t); + +static device_method_t lxtphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, lxtphy_probe), + DEVMETHOD(device_attach, lxtphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t lxtphy_devclass; + +static driver_t lxtphy_driver = { + "lxtphy", + lxtphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(lxtphy, miibus, lxtphy_driver, lxtphy_devclass, 0, 0); + +static int lxtphy_service(struct mii_softc *, struct mii_data *, int); +static void lxtphy_status(struct mii_softc *); +static void lxtphy_set_tp(struct mii_softc *); +static void lxtphy_set_fx(struct mii_softc *); + +static int +lxtphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxLEVEL1 && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxLEVEL1_LXT970) { + device_set_desc(dev, MII_STR_xxLEVEL1_LXT970); + } else + return (ENXIO); + + return (0); +} + +static int +lxtphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = lxtphy_service; + sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOISOLATE; + + mii_phy_reset(sc); + + mii->mii_instance++; + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst), + BMCR_S100); + printf("100baseFX, "); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst), + BMCR_S100|BMCR_FDX); + printf("100baseFX-FDX, "); +#undef ADD + + mii_add_media(sc); + printf("\n"); + + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +lxtphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) + return (0); + + lxtphy_set_tp(sc); + + (void) mii_phy_auto(sc); + break; + case IFM_100_T4: + /* + * XXX Not supported as a manual setting right now. + */ + return (EINVAL); + + case IFM_100_FX: + lxtphy_set_fx(sc); + /* XXX: fall though intentional ?? */ + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + lxtphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +lxtphy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmcr, bmsr, csr; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + /* + * Get link status from the CSR; we need to read the CSR + * for media type anyhow, and the link status in the CSR + * doens't latch, so fewer register reads are required. + */ + csr = PHY_READ(sc, MII_LXTPHY_CSR); + if (csr & CSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + if (csr & CSR_SPEED) + mii->mii_media_active |= IFM_100_TX; + else + mii->mii_media_active |= IFM_10_T; + if (csr & CSR_DUPLEX) + mii->mii_media_active |= IFM_FDX; + } else + mii->mii_media_active = ife->ifm_media; +} + +static void +lxtphy_set_tp(sc) + struct mii_softc *sc; +{ + int cfg; + + cfg = PHY_READ(sc, MII_LXTPHY_CONFIG); + cfg &= ~CONFIG_100BASEFX; + PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg); +} + +static void +lxtphy_set_fx(sc) + struct mii_softc *sc; +{ + int cfg; + + cfg = PHY_READ(sc, MII_LXTPHY_CONFIG); + cfg |= CONFIG_100BASEFX; + PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg); +} + diff --git a/sys/dev/mii/lxtphyreg.h b/sys/dev/mii/lxtphyreg.h new file mode 100644 index 0000000..662bd34 --- /dev/null +++ b/sys/dev/mii/lxtphyreg.h @@ -0,0 +1,90 @@ +/* OpenBSD: lxtphyreg.h,v 1.1 1998/11/11 19:34:47 jason Exp */ +/* NetBSD: lxtphyreg.h,v 1.1 1998/10/24 00:33:17 thorpej Exp */ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_MII_LXTPHYREG_H_ +#define _DEV_MII_LXTPHYREG_H_ + +/* + * LXT970 registers. + */ + +#define MII_LXTPHY_MIRROR 0x10 /* Mirror register */ + /* All bits user-defined */ + +#define MII_LXTPHY_IER 0x11 /* Interrupt Enable Register */ +#define IER_MIIDRVLVL 0x0008 /* Rediced MII driver levels */ +#define IER_LNK_CRITERIA 0x0004 /* Enhanced Link Loss Criteria */ +#define IER_INTEN 0x0002 /* Interrupt Enable */ +#define IER_TINT 0x0001 /* Force Interrupt */ + +#define MII_LXTPHY_ISR 0x12 /* Interrupt Status Register */ +#define ISR_MINT 0x8000 /* MII Interrupt Pending */ +#define ISR_XTALOK 0x4000 /* Clocks OK */ + +#define MII_LXTPHY_CONFIG 0x13 /* Configuration Register */ +#define CONFIG_TXMIT_TEST 0x4000 /* 100base-T Transmit Test */ +#define CONFIG_REPEATER 0x2000 /* Repeater Mode */ +#define CONFIG_MDIO_INT 0x1000 /* Enable intr signalling on MDIO */ +#define CONFIG_TPLOOP 0x0800 /* Disable 10base-T Loopback */ +#define CONFIG_SQE 0x0400 /* Enable SQE */ +#define CONFIG_DISJABBER 0x0200 /* Disable Jabber */ +#define CONFIG_DISLINKTEST 0x0100 /* Disable Link Test */ +#define CONFIG_LEDC1 0x0080 /* LEDC configuration */ +#define CONFIG_LEDC0 0x0040 /* ... */ + /* 0 0 LEDC indicates collision */ + /* 0 1 LEDC is off */ + /* 1 0 LEDC indicates activity */ + /* 1 1 LEDC is on */ +#define CONFIG_ADVTXCLK 0x0020 /* Advance TX clock */ +#define CONFIG_5BSYMBOL 0x0010 /* 5-bit Symbol mode */ +#define CONFIG_SCRAMBLER 0x0008 /* Bypass scrambler */ +#define CONFIG_100BASEFX 0x0004 /* 100base-FX */ +#define CONFIG_TXDISCON 0x0001 /* Disconnect TP transmitter */ + +#define MII_LXTPHY_CSR 0x14 /* Chip Status Register */ +#define CSR_LINK 0x2000 /* Link is up */ +#define CSR_DUPLEX 0x1000 /* Full-duplex */ +#define CSR_SPEED 0x0800 /* 100Mbps */ +#define CSR_ACOMP 0x0400 /* Autonegotiation complete */ +#define CSR_PAGERCVD 0x0200 /* Link page received */ +#define CSR_LOWVCC 0x0004 /* Low Voltage Fault */ + +#endif /* _DEV_MII_LXTPHYREG_H_ */ diff --git a/sys/dev/mii/mii.c b/sys/dev/mii/mii.c new file mode 100644 index 0000000..4771cc5 --- /dev/null +++ b/sys/dev/mii/mii.c @@ -0,0 +1,386 @@ +/* $NetBSD: mii.c,v 1.12 1999/08/03 19:41:49 drochner Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * MII bus layer, glues MII-capable network interface drivers to sharable + * PHY drivers. This exports an interface compatible with BSD/OS 3.0's, + * plus some NetBSD extensions. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +MODULE_VERSION(miibus, 1); + +#include "miibus_if.h" + +static int miibus_readreg(device_t, int, int); +static int miibus_writereg(device_t, int, int, int); +static void miibus_statchg(device_t); +static void miibus_linkchg(device_t); +static void miibus_mediainit(device_t); + +static device_method_t miibus_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, miibus_probe), + DEVMETHOD(device_attach, miibus_attach), + DEVMETHOD(device_detach, miibus_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + /* bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + + /* MII interface */ + DEVMETHOD(miibus_readreg, miibus_readreg), + DEVMETHOD(miibus_writereg, miibus_writereg), + DEVMETHOD(miibus_statchg, miibus_statchg), + DEVMETHOD(miibus_linkchg, miibus_linkchg), + DEVMETHOD(miibus_mediainit, miibus_mediainit), + + { 0, 0 } +}; + +devclass_t miibus_devclass; + +driver_t miibus_driver = { + "miibus", + miibus_methods, + sizeof(struct mii_data) +}; + +/* + * Helper function used by network interface drivers, attaches PHYs + * to the network interface driver parent. + */ + +int +miibus_probe(dev) + device_t dev; +{ + struct mii_attach_args ma, *args; + struct mii_data *mii; + device_t child = NULL, parent; + int bmsr, capmask = 0xFFFFFFFF; + + mii = device_get_softc(dev); + parent = device_get_parent(dev); + LIST_INIT(&mii->mii_phys); + + for (ma.mii_phyno = 0; ma.mii_phyno < MII_NPHY; ma.mii_phyno++) { + /* + * Check to see if there is a PHY at this address. Note, + * many braindead PHYs report 0/0 in their ID registers, + * so we test for media in the BMSR. + */ + bmsr = MIIBUS_READREG(parent, ma.mii_phyno, MII_BMSR); + if (bmsr == 0 || bmsr == 0xffff || + (bmsr & BMSR_MEDIAMASK) == 0) { + /* Assume no PHY at this address. */ + continue; + } + + /* + * Extract the IDs. Braindead PHYs will be handled by + * the `ukphy' driver, as we have no ID information to + * match on. + */ + ma.mii_id1 = MIIBUS_READREG(parent, ma.mii_phyno, + MII_PHYIDR1); + ma.mii_id2 = MIIBUS_READREG(parent, ma.mii_phyno, + MII_PHYIDR2); + + ma.mii_data = mii; + ma.mii_capmask = capmask; + + args = malloc(sizeof(struct mii_attach_args), + M_DEVBUF, M_NOWAIT); + bcopy((char *)&ma, (char *)args, sizeof(ma)); + child = device_add_child(dev, NULL, -1); + device_set_ivars(child, args); + } + + if (child == NULL) + return(ENXIO); + + device_set_desc(dev, "MII bus"); + + return(0); +} + +int +miibus_attach(dev) + device_t dev; +{ + void **v; + ifm_change_cb_t ifmedia_upd; + ifm_stat_cb_t ifmedia_sts; + struct mii_data *mii; + + mii = device_get_softc(dev); + /* + * Note that each NIC's softc must start with an ifnet structure. + */ + mii->mii_ifp = device_get_softc(device_get_parent(dev)); + v = device_get_ivars(dev); + ifmedia_upd = v[0]; + ifmedia_sts = v[1]; + ifmedia_init(&mii->mii_media, IFM_IMASK, ifmedia_upd, ifmedia_sts); + bus_generic_attach(dev); + + return(0); +} + +int +miibus_detach(dev) + device_t dev; +{ + struct mii_data *mii; + + bus_generic_detach(dev); + mii = device_get_softc(dev); + ifmedia_removeall(&mii->mii_media); + mii->mii_ifp = NULL; + + return(0); +} + +static int +miibus_readreg(dev, phy, reg) + device_t dev; + int phy, reg; +{ + device_t parent; + + parent = device_get_parent(dev); + return(MIIBUS_READREG(parent, phy, reg)); +} + +static int +miibus_writereg(dev, phy, reg, data) + device_t dev; + int phy, reg, data; +{ + device_t parent; + + parent = device_get_parent(dev); + return(MIIBUS_WRITEREG(parent, phy, reg, data)); +} + +static void +miibus_statchg(dev) + device_t dev; +{ + device_t parent; + + parent = device_get_parent(dev); + MIIBUS_STATCHG(parent); + return; +} + +static void +miibus_linkchg(dev) + device_t dev; +{ + struct mii_data *mii; + struct ifnet *ifp; + device_t parent; + int link; + + parent = device_get_parent(dev); + MIIBUS_LINKCHG(parent); + + mii = device_get_softc(dev); + /* + * Note that each NIC's softc must start with an ifnet structure. + */ + ifp = device_get_softc(parent); + + if (mii->mii_media_status & IFM_AVALID) { + if (mii->mii_media_status & IFM_ACTIVE) + link = NOTE_LINKUP; + else + link = NOTE_LINKDOWN; + } else { + link = NOTE_LINKINV; + } + + KNOTE(&ifp->if_klist, link); +} + +static void +miibus_mediainit(dev) + device_t dev; +{ + struct mii_data *mii; + struct ifmedia_entry *m; + int media = 0; + + /* Poke the parent in case it has any media of its own to add. */ + MIIBUS_MEDIAINIT(device_get_parent(dev)); + + mii = device_get_softc(dev); + LIST_FOREACH(m, &mii->mii_media.ifm_list, ifm_list) { + media = m->ifm_media; + if (media == (IFM_ETHER|IFM_AUTO)) + break; + } + + ifmedia_set(&mii->mii_media, media); + + return; +} + +int +mii_phy_probe(dev, child, ifmedia_upd, ifmedia_sts) + device_t dev; + device_t *child; + ifm_change_cb_t ifmedia_upd; + ifm_stat_cb_t ifmedia_sts; +{ + void **v; + int bmsr, i; + + v = malloc(sizeof(vm_offset_t) * 2, M_DEVBUF, M_NOWAIT); + if (v == 0) { + return (ENOMEM); + } + v[0] = ifmedia_upd; + v[1] = ifmedia_sts; + *child = device_add_child(dev, "miibus", -1); + device_set_ivars(*child, v); + + for (i = 0; i < MII_NPHY; i++) { + bmsr = MIIBUS_READREG(dev, i, MII_BMSR); + if (bmsr == 0 || bmsr == 0xffff || + (bmsr & BMSR_MEDIAMASK) == 0) { + /* Assume no PHY at this address. */ + continue; + } else + break; + } + + if (i == MII_NPHY) { + device_delete_child(dev, *child); + *child = NULL; + return(ENXIO); + } + + bus_generic_attach(dev); + + return(0); +} + +/* + * Media changed; notify all PHYs. + */ +int +mii_mediachg(mii) + struct mii_data *mii; +{ + struct mii_softc *child; + int rv; + + mii->mii_media_status = 0; + mii->mii_media_active = IFM_NONE; + + LIST_FOREACH(child, &mii->mii_phys, mii_list) { + rv = (*child->mii_service)(child, mii, MII_MEDIACHG); + if (rv) + return (rv); + } + return (0); +} + +/* + * Call the PHY tick routines, used during autonegotiation. + */ +void +mii_tick(mii) + struct mii_data *mii; +{ + struct mii_softc *child; + + LIST_FOREACH(child, &mii->mii_phys, mii_list) + (void) (*child->mii_service)(child, mii, MII_TICK); +} + +/* + * Get media status from PHYs. + */ +void +mii_pollstat(mii) + struct mii_data *mii; +{ + struct mii_softc *child; + + mii->mii_media_status = 0; + mii->mii_media_active = IFM_NONE; + + LIST_FOREACH(child, &mii->mii_phys, mii_list) + (void) (*child->mii_service)(child, mii, MII_POLLSTAT); +} + +/* + * Inform the PHYs that the interface is down. + */ +void +mii_down(struct mii_data *mii) +{ + struct mii_softc *child; + + LIST_FOREACH(child, &mii->mii_phys, mii_list) + mii_phy_down(child); +} diff --git a/sys/dev/mii/mii.h b/sys/dev/mii/mii.h new file mode 100644 index 0000000..963c226 --- /dev/null +++ b/sys/dev/mii/mii.h @@ -0,0 +1,206 @@ +/* $NetBSD: mii.h,v 1.9 2001/05/31 03:07:14 thorpej Exp $ */ + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Modification to match BSD/OS 3.0 MII interface by Jason R. Thorpe, + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_MII_H_ +#define _DEV_MII_MII_H_ + +/* + * Registers common to all PHYs. + */ + +#define MII_NPHY 32 /* max # of PHYs per MII */ + +/* + * MII commands, used if a device must drive the MII lines + * manually. + */ +#define MII_COMMAND_START 0x01 +#define MII_COMMAND_READ 0x02 +#define MII_COMMAND_WRITE 0x01 +#define MII_COMMAND_ACK 0x02 + +#define MII_BMCR 0x00 /* Basic mode control register (rw) */ +#define BMCR_RESET 0x8000 /* reset */ +#define BMCR_LOOP 0x4000 /* loopback */ +#define BMCR_SPEED0 0x2000 /* speed selection (LSB) */ +#define BMCR_AUTOEN 0x1000 /* autonegotiation enable */ +#define BMCR_PDOWN 0x0800 /* power down */ +#define BMCR_ISO 0x0400 /* isolate */ +#define BMCR_STARTNEG 0x0200 /* restart autonegotiation */ +#define BMCR_FDX 0x0100 /* Set duplex mode */ +#define BMCR_CTEST 0x0080 /* collision test */ +#define BMCR_SPEED1 0x0040 /* speed selection (MSB) */ + +#define BMCR_S10 0x0000 /* 10 Mb/s */ +#define BMCR_S100 BMCR_SPEED0 /* 100 Mb/s */ +#define BMCR_S1000 BMCR_SPEED1 /* 1000 Mb/s */ + +#define BMCR_SPEED(x) ((x) & (BMCR_SPEED0|BMCR_SPEED1)) + +#define MII_BMSR 0x01 /* Basic mode status register (ro) */ +#define BMSR_100T4 0x8000 /* 100 base T4 capable */ +#define BMSR_100TXFDX 0x4000 /* 100 base Tx full duplex capable */ +#define BMSR_100TXHDX 0x2000 /* 100 base Tx half duplex capable */ +#define BMSR_10TFDX 0x1000 /* 10 base T full duplex capable */ +#define BMSR_10THDX 0x0800 /* 10 base T half duplex capable */ +#define BMSR_100T2FDX 0x0400 /* 100 base T2 full duplex capable */ +#define BMSR_100T2HDX 0x0200 /* 100 base T2 half duplex capable */ +#define BMSR_EXTSTAT 0x0100 /* Extended status in register 15 */ +#define BMSR_MFPS 0x0040 /* MII Frame Preamble Suppression */ +#define BMSR_ACOMP 0x0020 /* Autonegotiation complete */ +#define BMSR_RFAULT 0x0010 /* Link partner fault */ +#define BMSR_ANEG 0x0008 /* Autonegotiation capable */ +#define BMSR_LINK 0x0004 /* Link status */ +#define BMSR_JABBER 0x0002 /* Jabber detected */ +#define BMSR_EXTCAP 0x0001 /* Extended capability */ + +/* + * Note that the EXTSTAT bit indicates that there is extended status + * info available in register 15, but 802.3 section 22.2.4.3 also + * states that that all 1000 Mb/s capable PHYs will set this bit to 1. + */ +#if 0 +#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX| \ + BMSR_10THDX|BMSR_ANEG) + +#else +/* NetBSD uses: */ +#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX| \ + BMSR_10TFDX|BMSR_10THDX|BMSR_100T2FDX|BMSR_100T2HDX) +#endif + +/* + * Convert BMSR media capabilities to ANAR bits for autonegotiation. + * Note the shift chopps off the BMSR_ANEG bit. + */ +#define BMSR_MEDIA_TO_ANAR(x) (((x) & BMSR_MEDIAMASK) >> 6) + +#define MII_PHYIDR1 0x02 /* ID register 1 (ro) */ + +#define MII_PHYIDR2 0x03 /* ID register 2 (ro) */ +#define IDR2_OUILSB 0xfc00 /* OUI LSB */ +#define IDR2_MODEL 0x03f0 /* vendor model */ +#define IDR2_REV 0x000f /* vendor revision */ + +#define MII_OUI(id1, id2) (((id1) << 6) | ((id2) >> 10)) +#define MII_MODEL(id2) (((id2) & IDR2_MODEL) >> 4) +#define MII_REV(id2) ((id2) & IDR2_REV) + +#define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */ + /* section 28.2.4.1 and 37.2.6.1 */ +#define ANAR_NP 0x8000 /* Next page (ro) */ +#define ANAR_ACK 0x4000 /* link partner abilities acknowledged (ro) */ +#define ANAR_RF 0x2000 /* remote fault (ro) */ +#define ANAR_FC 0x0400 /* local device supports PAUSE */ +#define ANAR_T4 0x0200 /* local device supports 100bT4 */ +#define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */ +#define ANAR_TX 0x0080 /* local device supports 100bTx */ +#define ANAR_10_FD 0x0040 /* local device supports 10bT FD */ +#define ANAR_10 0x0020 /* local device supports 10bT */ +#define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */ + +#define ANAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ +#define ANAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ +#define ANAR_X_PAUSE_NONE (0 << 7) +#define ANAR_X_PAUSE_SYM (1 << 7) +#define ANAR_X_PAUSE_ASYM (2 << 7) +#define ANAR_X_PAUSE_TOWARDS (3 << 7) + +#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ + /* section 28.2.4.1 and 37.2.6.1 */ +#define ANLPAR_NP 0x8000 /* Next page (ro) */ +#define ANLPAR_ACK 0x4000 /* link partner accepted ACK (ro) */ +#define ANLPAR_RF 0x2000 /* remote fault (ro) */ +#define ANLPAR_FC 0x0400 /* link partner supports PAUSE */ +#define ANLPAR_T4 0x0200 /* link partner supports 100bT4 */ +#define ANLPAR_TX_FD 0x0100 /* link partner supports 100bTx FD */ +#define ANLPAR_TX 0x0080 /* link partner supports 100bTx */ +#define ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */ +#define ANLPAR_10 0x0020 /* link partner supports 10bT */ +#define ANLPAR_CSMA 0x0001 /* protocol selector CSMA/CD */ + +#define ANLPAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ +#define ANLPAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ +#define ANLPAR_X_PAUSE_MASK (3 << 7) +#define ANLPAR_X_PAUSE_NONE (0 << 7) +#define ANLPAR_X_PAUSE_SYM (1 << 7) +#define ANLPAR_X_PAUSE_ASYM (2 << 7) +#define ANLPAR_X_PAUSE_TOWARDS (3 << 7) + +#define MII_ANER 0x06 /* Autonegotiation expansion (ro) */ + /* section 28.2.4.1 and 37.2.6.1 */ +#define ANER_MLF 0x0010 /* multiple link detection fault */ +#define ANER_LPNP 0x0008 /* link parter next page-able */ +#define ANER_NP 0x0004 /* next page-able */ +#define ANER_PAGE_RX 0x0002 /* Page received */ +#define ANER_LPAN 0x0001 /* link parter autoneg-able */ + +#define MII_ANNP 0x07 /* Autonegotiation next page */ + /* section 28.2.4.1 and 37.2.6.1 */ + +#define MII_ANLPRNP 0x08 /* Autonegotiation link partner rx next page */ + /* section 32.5.1 and 37.2.6.1 */ + + /* This is also the 1000baseT control register */ +#define MII_100T2CR 0x09 /* 100base-T2 control register */ +#define GTCR_TEST_MASK 0xe000 /* see 802.3ab ss. 40.6.1.1.2 */ +#define GTCR_MAN_MS 0x1000 /* enable manual master/slave control */ +#define GTCR_ADV_MS 0x0800 /* 1 = adv. master, 0 = adv. slave */ +#define GTCR_PORT_TYPE 0x0400 /* 1 = DCE, 0 = DTE (NIC) */ +#define GTCR_ADV_1000TFDX 0x0200 /* adv. 1000baseT FDX */ +#define GTCR_ADV_1000THDX 0x0100 /* adv. 1000baseT HDX */ + + /* This is also the 1000baseT status register */ +#define MII_100T2SR 0x0a /* 100base-T2 status register */ +#define GTSR_MAN_MS_FLT 0x8000 /* master/slave config fault */ +#define GTSR_MS_RES 0x4000 /* result: 1 = master, 0 = slave */ +#define GTSR_LRS 0x2000 /* local rx status, 1 = ok */ +#define GTSR_RRS 0x1000 /* remove rx status, 1 = ok */ +#define GTSR_LP_1000TFDX 0x0800 /* link partner 1000baseT FDX capable */ +#define GTSR_LP_1000THDX 0x0400 /* link partner 1000baseT HDX capable */ +#define GTSR_LP_ASM_DIR 0x0200 /* link partner asym. pause dir. capable */ +#define GTSR_IDLE_ERR 0x00ff /* IDLE error count */ + +#define MII_EXTSR 0x0f /* Extended status register */ +#define EXTSR_1000XFDX 0x8000 /* 1000X full-duplex capable */ +#define EXTSR_1000XHDX 0x4000 /* 1000X half-duplex capable */ +#define EXTSR_1000TFDX 0x2000 /* 1000T full-duplex capable */ +#define EXTSR_1000THDX 0x1000 /* 1000T half-duplex capable */ + +#define EXTSR_MEDIAMASK (EXTSR_1000XFDX|EXTSR_1000XHDX| \ + EXTSR_1000TFDX|EXTSR_1000THDX) + +#endif /* _DEV_MII_MII_H_ */ diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c new file mode 100644 index 0000000..96e481c --- /dev/null +++ b/sys/dev/mii/mii_physubr.c @@ -0,0 +1,545 @@ +/* $NetBSD: mii_physubr.c,v 1.5 1999/08/03 19:41:49 drochner Exp $ */ + +/*- + * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Subroutines common to all PHYs. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> + + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include "miibus_if.h" + +/* + * Media to register setting conversion table. Order matters. + */ +const struct mii_media mii_media_table[MII_NMEDIA] = { + /* None */ + { BMCR_ISO, ANAR_CSMA, + 0, }, + + /* 10baseT */ + { BMCR_S10, ANAR_CSMA|ANAR_10, + 0, }, + + /* 10baseT-FDX */ + { BMCR_S10|BMCR_FDX, ANAR_CSMA|ANAR_10_FD, + 0, }, + + /* 100baseT4 */ + { BMCR_S100, ANAR_CSMA|ANAR_T4, + 0, }, + + /* 100baseTX */ + { BMCR_S100, ANAR_CSMA|ANAR_TX, + 0, }, + + /* 100baseTX-FDX */ + { BMCR_S100|BMCR_FDX, ANAR_CSMA|ANAR_TX_FD, + 0, }, + + /* 1000baseX */ + { BMCR_S1000, ANAR_CSMA, + 0, }, + + /* 1000baseX-FDX */ + { BMCR_S1000|BMCR_FDX, ANAR_CSMA, + 0, }, + + /* 1000baseT */ + { BMCR_S1000, ANAR_CSMA, + GTCR_ADV_1000THDX }, + + /* 1000baseT-FDX */ + { BMCR_S1000, ANAR_CSMA, + GTCR_ADV_1000TFDX }, +}; + +void +mii_phy_setmedia(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmcr, anar, gtcr; + + if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { + if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0) + (void) mii_phy_auto(sc); + return; + } + + /* + * Table index is stored in the media entry. + */ + + KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA, + ("invalid ife->ifm_data (0x%x) in mii_phy_setmedia", + ife->ifm_data)); + + anar = mii_media_table[ife->ifm_data].mm_anar; + bmcr = mii_media_table[ife->ifm_data].mm_bmcr; + gtcr = mii_media_table[ife->ifm_data].mm_gtcr; + + if (mii->mii_media.ifm_media & IFM_ETH_MASTER) { + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_1000_T: + gtcr |= GTCR_MAN_MS|GTCR_ADV_MS; + break; + + default: + panic("mii_phy_setmedia: MASTER on wrong media"); + } + } + + if (ife->ifm_media & IFM_LOOP) + bmcr |= BMCR_LOOP; + + PHY_WRITE(sc, MII_ANAR, anar); + PHY_WRITE(sc, MII_BMCR, bmcr); + if (sc->mii_flags & MIIF_HAVE_GTCR) + PHY_WRITE(sc, MII_100T2CR, gtcr); +} + +int +mii_phy_auto(struct mii_softc *sc) +{ + + /* + * Check for 1000BASE-X. Autonegotiation is a bit + * different on such devices. + */ + if (sc->mii_flags & MIIF_IS_1000X) { + uint16_t anar = 0; + + if (sc->mii_extcapabilities & EXTSR_1000XFDX) + anar |= ANAR_X_FD; + if (sc->mii_extcapabilities & EXTSR_1000XHDX) + anar |= ANAR_X_HD; + + if (sc->mii_flags & MIIF_DOPAUSE) { + /* XXX Asymmetric vs. symmetric? */ + anar |= ANLPAR_X_PAUSE_TOWARDS; + } + + PHY_WRITE(sc, MII_ANAR, anar); + } else { + uint16_t anar; + + anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | + ANAR_CSMA; + if (sc->mii_flags & MIIF_DOPAUSE) + anar |= ANAR_FC; + PHY_WRITE(sc, MII_ANAR, anar); + if (sc->mii_flags & MIIF_HAVE_GTCR) { + uint16_t gtcr = 0; + + if (sc->mii_extcapabilities & EXTSR_1000TFDX) + gtcr |= GTCR_ADV_1000TFDX; + if (sc->mii_extcapabilities & EXTSR_1000THDX) + gtcr |= GTCR_ADV_1000THDX; + + PHY_WRITE(sc, MII_100T2CR, gtcr); + } + } + PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); + return (EJUSTRETURN); +} + +int +mii_phy_tick(struct mii_softc *sc) +{ + struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; + struct ifnet *ifp = sc->mii_pdata->mii_ifp; + int reg; + + /* Just bail now if the interface is down. */ + if ((ifp->if_flags & IFF_UP) == 0) + return (EJUSTRETURN); + + /* + * If we're not doing autonegotiation, we don't need to do + * any extra work here. However, we need to check the link + * status so we can generate an announcement if the status + * changes. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + return (0); + + /* Read the status register twice; BMSR_LINK is latch-low. */ + reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + if (reg & BMSR_LINK) { + /* + * See above. + */ + return (0); + } + + /* + * Only retry autonegotiation every N seconds. + */ + if (sc->mii_anegticks == 0) + sc->mii_anegticks = 17; + if (++sc->mii_ticks != sc->mii_anegticks) + return (EJUSTRETURN); + + sc->mii_ticks = 0; + mii_phy_reset(sc); + mii_phy_auto(sc); + return (0); +} + +void +mii_phy_reset(struct mii_softc *sc) +{ + int reg, i; + + if (sc->mii_flags & MIIF_NOISOLATE) + reg = BMCR_RESET; + else + reg = BMCR_RESET | BMCR_ISO; + PHY_WRITE(sc, MII_BMCR, reg); + + /* Wait 100ms for it to complete. */ + for (i = 0; i < 100; i++) { + reg = PHY_READ(sc, MII_BMCR); + if ((reg & BMCR_RESET) == 0) + break; + DELAY(1000); + } + + if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0)) + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); +} + +void +mii_phy_down(struct mii_softc *sc) +{ + +} + +void +mii_phy_update(struct mii_softc *sc, int cmd) +{ + struct mii_data *mii = sc->mii_pdata; + + if (sc->mii_media_active != mii->mii_media_active || + cmd == MII_MEDIACHG) { + MIIBUS_STATCHG(sc->mii_dev); + sc->mii_media_active = mii->mii_media_active; + } + if (sc->mii_media_status != mii->mii_media_status) { + MIIBUS_LINKCHG(sc->mii_dev); + sc->mii_media_status = mii->mii_media_status; + } +} + +/* + * Given an ifmedia word, return the corresponding ANAR value. + */ +int +mii_anar(media) + int media; +{ + int rv; + + switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) { + case IFM_ETHER|IFM_10_T: + rv = ANAR_10|ANAR_CSMA; + break; + case IFM_ETHER|IFM_10_T|IFM_FDX: + rv = ANAR_10_FD|ANAR_CSMA; + break; + case IFM_ETHER|IFM_100_TX: + rv = ANAR_TX|ANAR_CSMA; + break; + case IFM_ETHER|IFM_100_TX|IFM_FDX: + rv = ANAR_TX_FD|ANAR_CSMA; + break; + case IFM_ETHER|IFM_100_T4: + rv = ANAR_T4|ANAR_CSMA; + break; + default: + rv = 0; + break; + } + + return (rv); +} + +/* + * Given a BMCR value, return the corresponding ifmedia word. + */ +int +mii_media_from_bmcr(bmcr) + int bmcr; +{ + int rv = IFM_ETHER; + + if (bmcr & BMCR_S100) + rv |= IFM_100_TX; + else + rv |= IFM_10_T; + if (bmcr & BMCR_FDX) + rv |= IFM_FDX; + + return (rv); +} + +/* + * Initialize generic PHY media based on BMSR, called when a PHY is + * attached. We expect to be set up to print a comma-separated list + * of media names. Does not print a newline. + */ +void +mii_add_media(struct mii_softc *sc) +{ + const char *sep = ""; + struct mii_data *mii; + + mii = device_get_softc(sc->mii_dev); + if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) { + printf("no media present"); + return; + } + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) +#define PRINT(s) printf("%s%s", sep, s); sep = ", " + + if (sc->mii_capabilities & BMSR_10THDX) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 0); + PRINT("10baseT"); + } + if (sc->mii_capabilities & BMSR_10TFDX) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), + BMCR_FDX); + PRINT("10baseT-FDX"); + } + if (sc->mii_capabilities & BMSR_100TXHDX) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), + BMCR_S100); + PRINT("100baseTX"); + } + if (sc->mii_capabilities & BMSR_100TXFDX) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), + BMCR_S100|BMCR_FDX); + PRINT("100baseTX-FDX"); + } + if (sc->mii_capabilities & BMSR_100T4) { + /* + * XXX How do you enable 100baseT4? I assume we set + * XXX BMCR_S100 and then assume the PHYs will take + * XXX watever action is necessary to switch themselves + * XXX into T4 mode. + */ + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst), + BMCR_S100); + PRINT("100baseT4"); + } + if (sc->mii_capabilities & BMSR_ANEG) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), + BMCR_AUTOEN); + PRINT("auto"); + } + + + +#undef ADD +#undef PRINT +} + +/* + * Initialize generic PHY media based on BMSR, called when a PHY is + * attached. We expect to be set up to print a comma-separated list + * of media names. Does not print a newline. + */ +void +mii_phy_add_media(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + const char *sep = ""; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) +#define PRINT(s) printf("%s%s", sep, s); sep = ", " + + if ((sc->mii_flags & MIIF_NOISOLATE) == 0) + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + MII_MEDIA_NONE); + + /* + * There are different interpretations for the bits in + * HomePNA PHYs. And there is really only one media type + * that is supported. + */ + if (sc->mii_flags & MIIF_IS_HPNA) { + if (sc->mii_capabilities & BMSR_10THDX) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, + sc->mii_inst), + MII_MEDIA_10_T); + PRINT("HomePNA1"); + } + return; + } + + if (sc->mii_capabilities & BMSR_10THDX) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), + MII_MEDIA_10_T); + PRINT("10baseT"); + } + if (sc->mii_capabilities & BMSR_10TFDX) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), + MII_MEDIA_10_T_FDX); + PRINT("10baseT-FDX"); + } + if (sc->mii_capabilities & BMSR_100TXHDX) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), + MII_MEDIA_100_TX); + PRINT("100baseTX"); + } + if (sc->mii_capabilities & BMSR_100TXFDX) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), + MII_MEDIA_100_TX_FDX); + PRINT("100baseTX-FDX"); + } + if (sc->mii_capabilities & BMSR_100T4) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst), + MII_MEDIA_100_T4); + PRINT("100baseT4"); + } + + if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) { + /* + * XXX Right now only handle 1000SX and 1000TX. Need + * XXX to handle 1000LX and 1000CX some how. + * + * Note since it can take 5 seconds to auto-negotiate + * a gigabit link, we make anegticks 10 seconds for + * all the gigabit media types. + */ + if (sc->mii_extcapabilities & EXTSR_1000XHDX) { + sc->mii_anegticks = 17; + sc->mii_flags |= MIIF_IS_1000X; + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, + sc->mii_inst), MII_MEDIA_1000_X); + PRINT("1000baseSX"); + } + if (sc->mii_extcapabilities & EXTSR_1000XFDX) { + sc->mii_anegticks = 17; + sc->mii_flags |= MIIF_IS_1000X; + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, + sc->mii_inst), MII_MEDIA_1000_X_FDX); + PRINT("1000baseSX-FDX"); + } + + /* + * 1000baseT media needs to be able to manipulate + * master/slave mode. We set IFM_ETH_MASTER in + * the "don't care mask" and filter it out when + * the media is set. + * + * All 1000baseT PHYs have a 1000baseT control register. + */ + if (sc->mii_extcapabilities & EXTSR_1000THDX) { + sc->mii_anegticks = 17; + sc->mii_flags |= MIIF_HAVE_GTCR; + mii->mii_media.ifm_mask |= IFM_ETH_MASTER; + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, + sc->mii_inst), MII_MEDIA_1000_T); + PRINT("1000baseT"); + } + if (sc->mii_extcapabilities & EXTSR_1000TFDX) { + sc->mii_anegticks = 17; + sc->mii_flags |= MIIF_HAVE_GTCR; + mii->mii_media.ifm_mask |= IFM_ETH_MASTER; + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, + sc->mii_inst), MII_MEDIA_1000_T_FDX); + PRINT("1000baseT-FDX"); + } + } + + if (sc->mii_capabilities & BMSR_ANEG) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), + MII_NMEDIA); /* intentionally invalid index */ + PRINT("auto"); + } +#undef ADD +#undef PRINT +} + +int +mii_phy_detach(device_t dev) +{ + struct mii_softc *sc; + + sc = device_get_softc(dev); + mii_phy_down(sc); + sc->mii_dev = NULL; + LIST_REMOVE(sc, mii_list); + + return(0); +} + +const struct mii_phydesc * +mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd) +{ + + for (; mpd->mpd_name != NULL; mpd++) { + if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui && + MII_MODEL(ma->mii_id2) == mpd->mpd_model) + return (mpd); + } + return (NULL); +} diff --git a/sys/dev/mii/miibus_if.m b/sys/dev/mii/miibus_if.m new file mode 100644 index 0000000..017812f --- /dev/null +++ b/sys/dev/mii/miibus_if.m @@ -0,0 +1,45 @@ +# $FreeBSD$ + +#include <sys/bus.h> + +INTERFACE miibus; + +# +# Read register from device on MII bus +# +METHOD int readreg { + device_t dev; + int phy; + int reg; +}; + +# +# Write register to device on MII bus +# +METHOD int writereg { + device_t dev; + int phy; + int reg; + int val; +}; + +# +# Notify bus about PHY status change. +# +METHOD void statchg { + device_t dev; +}; + +# +# Notify bus about PHY link change. +# +METHOD void linkchg { + device_t dev; +}; + +# +# Notify bus that media has been set. +# +METHOD void mediainit { + device_t dev; +}; diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs new file mode 100644 index 0000000..1f58417 --- /dev/null +++ b/sys/dev/mii/miidevs @@ -0,0 +1,176 @@ +$FreeBSD$ +/*$NetBSD: miidevs,v 1.6 1999/05/14 11:37:30 drochner Exp $*/ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * List of known MII OUIs. + * For a complete list see http://standards.ieee.org/regauth/oui/ + * + * XXX Vendors do obviously not agree how OUIs (18 bit) are mapped + * to the 16 bits available in the id registers. The MII_OUI() macro + * in "mii.h" reflects the most obvious way. If a vendor uses a + * different mapping, an "xx" prefixed OUI is defined here which is + * mangled accordingly to compensate. + */ + +oui ALTIMA 0x0010a9 Altima Communications +oui AMD 0x00001a Advanced Micro Devices +oui BROADCOM 0x001018 Broadcom Corporation +oui DAVICOM 0x00606e Davicom Semiconductor +oui ICS 0x00a0be Integrated Circuit Systems +oui INTEL 0x00aa00 Intel +oui JATO 0x00e083 Jato Technologies +oui LEVEL1 0x00207b Level 1 +oui NATSEMI 0x080017 National Semiconductor +oui QUALSEMI 0x006051 Quality Semiconductor +oui REALTEK 0x000020 RealTek Semicondctor +oui SEEQ 0x00a07d Seeq +oui SIS 0x00e006 Silicon Integrated Systems +oui TDK 0x00c039 TDK +oui TI 0x080028 Texas Instruments +oui XAQTI 0x00e0ae XaQti Corp. +oui MARVELL 0x005043 Marvell Semiconductor +oui xxMARVELL 0x000ac2 Marvell Semiconductor + +/* in the 79c873, AMD uses another OUI (which matches Davicom!) */ +oui xxAMD 0x00606e Advanced Micro Devices + +/* Intel 82553 A/B steppings */ +oui xxINTEL 0x00f800 Intel + +/* some vendors have the bits swapped within bytes + (ie, ordered as on the wire) */ +oui xxALTIMA 0x000895 Altima Communications +oui xxBROADCOM 0x000818 Broadcom Corporation +oui xxICS 0x00057d Integrated Circuit Systems +oui xxSEEQ 0x0005be Seeq +oui xxSIS 0x000760 Silicon Integrated Systems +oui xxTI 0x100014 Texas Instruments +oui xxXAQTI 0x350700 XaQti Corp. + +/* Level 1 is completely different - from right to left. + (Two bits get lost in the third OUI byte.) */ +oui xxLEVEL1 0x1e0400 Level 1 + +/* Don't know what's going on here. */ +oui xxDAVICOM 0x006040 Davicom Semiconductor + +/* This is the OUI of the gigE PHY in the RealTek 8169S/8110S chips */ +oui xxREALTEK 0x000732 + +/* + * List of known models. Grouped by oui. + */ + +/* Altima Communications PHYs */ +model xxALTIMA AC101 0x0021 AC101 10/100 media interface +model xxALTIMA AC101L 0x0012 AC101L 10/100 media interface + +/* Advanced Micro Devices PHYs */ +model xxAMD 79C873 0x0000 Am79C873 10/100 media interface +model AMD 79c973phy 0x0036 Am79c973 internal PHY +model AMD 79c978 0x0039 Am79c978 HomePNA PHY + +/* Broadcom Corp. PHYs. */ +model BROADCOM 3C905B 0x0012 3c905B 10/100 internal PHY +model BROADCOM 3C905C 0x0017 3c905C 10/100 internal PHY +model BROADCOM BCM5201 0x0021 BCM5201 10/100baseTX PHY +model BROADCOM BCM5221 0x001e BCM5221 10/100baseTX PHY +model BROADCOM BCM4401 0x0036 BCM4401 10/100baseTX PHY +model xxBROADCOM BCM5400 0x0004 Broadcom 1000baseTX PHY +model xxBROADCOM BCM5401 0x0005 BCM5401 10/100/1000baseTX PHY +model xxBROADCOM BCM5411 0x0007 BCM5411 10/100/1000baseTX PHY +model xxBROADCOM BCM5701 0x0011 BCM5701 10/100/1000baseTX PHY +model xxBROADCOM BCM5703 0x0016 BCM5703 10/100/1000baseTX PHY +model xxBROADCOM BCM5704 0x0019 BCM5704 10/100/1000baseTX PHY +model xxBROADCOM BCM5705 0x001a BCM5705 10/100/1000baseTX PHY + +/* Davicom Semiconductor PHYs */ +model xxDAVICOM DM9101 0x0000 DM9101 10/100 media interface + +/* Integrated Circuit Systems PHYs */ +model xxICS 1890 0x0002 ICS1890 10/100 media interface + +/* Intel PHYs */ +model xxINTEL I82553AB 0x0000 i83553 10/100 media interface +model INTEL I82555 0x0015 i82555 10/100 media interface +model INTEL I82562EM 0x0032 i82562EM 10/100 media interface +model INTEL I82562ET 0x0033 i82562ET 10/100 media interface +model INTEL I82553C 0x0035 i82553 10/100 media interface + +/* Jato Technologies PHYs */ +model JATO BASEX 0x0000 Jato 1000baseX media interface + +/* Level 1 PHYs */ +model xxLEVEL1 LXT970 0x0000 LXT970 10/100 media interface + +/* National Semiconductor PHYs */ +model NATSEMI DP83840 0x0000 DP83840 10/100 media interface +model NATSEMI DP83843 0x0001 DP83843 10/100 media interface +model NATSEMI DP83891 0x0005 DP83891 10/100/1000 media interface +model NATSEMI DP83861 0x0006 DP83861 10/100/1000 media interface + +/* Quality Semiconductor PHYs */ +model QUALSEMI QS6612 0x0000 QS6612 10/100 media interface + +/* RealTek Semiconductor PHYs */ +model REALTEK RTL8201L 0x0020 RTL8201L 10/100 media interface +model xxREALTEK RTL8169S 0x0011 RTL8169S/8110S media interface + +/* Seeq PHYs */ +model xxSEEQ 80220 0x0003 Seeq 80220 10/100 media interface +model xxSEEQ 84220 0x0004 Seeq 84220 10/100 media interface + +/* Silicon Integrated Systems PHYs */ +model xxSIS 900 0x0000 SiS 900 10/100 media interface + +/* TDK */ +model TDK 78Q2120 0x0014 TDK 78Q2120 media interface + +/* Texas Instruments PHYs */ +model xxTI TLAN10T 0x0001 ThunderLAN 10baseT media interface +model xxTI 100VGPMI 0x0002 ThunderLAN 100VG-AnyLan media interface + +/* XaQti Corp. PHYs. */ +model XAQTI XMACII 0x0000 XaQti Corp. XMAC II gigabit interface + +/* Marvell Semiconductor PHYs */ +model MARVELL E1000 0x0000 Marvell 88E1000 Gigabit PHY +model MARVELL E1011 0x0002 Marvell 88E1011 Gigabit PHY +model xxMARVELL E1000 0x0005 Marvell 88E1000 Gigabit PHY diff --git a/sys/dev/mii/miivar.h b/sys/dev/mii/miivar.h new file mode 100644 index 0000000..f6c759c --- /dev/null +++ b/sys/dev/mii/miivar.h @@ -0,0 +1,225 @@ +/* $NetBSD: miivar.h,v 1.8 1999/04/23 04:24:32 thorpej Exp $ */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_MIIVAR_H_ +#define _DEV_MII_MIIVAR_H_ + +#include <sys/queue.h> + +/* + * Media Independent Interface configuration defintions. + */ + +struct mii_softc; + +/* + * Callbacks from MII layer into network interface device driver. + */ +typedef int (*mii_readreg_t)(struct device *, int, int); +typedef void (*mii_writereg_t)(struct device *, int, int, int); +typedef void (*mii_statchg_t)(struct device *); + +/* + * A network interface driver has one of these structures in its softc. + * It is the interface from the network interface driver to the MII + * layer. + */ +struct mii_data { + struct ifmedia mii_media; /* media information */ + struct ifnet *mii_ifp; /* pointer back to network interface */ + + /* + * For network interfaces with multiple PHYs, a list of all + * PHYs is required so they can all be notified when a media + * request is made. + */ + LIST_HEAD(mii_listhead, mii_softc) mii_phys; + int mii_instance; + + /* + * PHY driver fills this in with active media status. + */ + int mii_media_status; + int mii_media_active; + + /* + * Calls from MII layer into network interface driver. + */ + mii_readreg_t mii_readreg; + mii_writereg_t mii_writereg; + mii_statchg_t mii_statchg; +}; +typedef struct mii_data mii_data_t; + +/* + * This call is used by the MII layer to call into the PHY driver + * to perform a `service request'. + */ +typedef int (*mii_downcall_t)(struct mii_softc *, struct mii_data *, int); + +/* + * Requests that can be made to the downcall. + */ +#define MII_TICK 1 /* once-per-second tick */ +#define MII_MEDIACHG 2 /* user changed media; perform the switch */ +#define MII_POLLSTAT 3 /* user requested media status; fill it in */ + +/* + * Each PHY driver's softc has one of these as the first member. + * XXX This would be better named "phy_softc", but this is the name + * XXX BSDI used, and we would like to have the same interface. + */ +struct mii_softc { + device_t mii_dev; /* generic device glue */ + + LIST_ENTRY(mii_softc) mii_list; /* entry on parent's PHY list */ + + int mii_phy; /* our MII address */ + int mii_inst; /* instance for ifmedia */ + + mii_downcall_t mii_service; /* our downcall */ + struct mii_data *mii_pdata; /* pointer to parent's mii_data */ + + int mii_flags; /* misc. flags; see below */ + int mii_capabilities; /* capabilities from BMSR */ + int mii_extcapabilities; /* extended capabilities */ + int mii_ticks; /* MII_TICK counter */ + int mii_anegticks; /* ticks before retrying aneg */ + int mii_media_active; /* last active media */ + int mii_media_status; /* last active status */ +}; +typedef struct mii_softc mii_softc_t; + +/* mii_flags */ +#define MIIF_INITDONE 0x0001 /* has been initialized (mii_data) */ +#define MIIF_NOISOLATE 0x0002 /* do not isolate the PHY */ +#define MIIF_NOLOOP 0x0004 /* no loopback capability */ +#define MIIF_AUTOTSLEEP 0x0010 /* use tsleep(), not callout() */ +#define MIIF_HAVEFIBER 0x0020 /* from parent: has fiber interface */ +#define MIIF_HAVE_GTCR 0x0040 /* has 100base-T2/1000base-T CR */ +#define MIIF_IS_1000X 0x0080 /* is a 1000BASE-X device */ +#define MIIF_DOPAUSE 0x0100 /* advertise PAUSE capability */ +#define MIIF_IS_HPNA 0x0200 /* is a HomePNA device */ + +#define MIIF_INHERIT_MASK (MIIF_NOISOLATE|MIIF_NOLOOP|MIIF_AUTOTSLEEP) + +/* + * Used to attach a PHY to a parent. + */ +struct mii_attach_args { + struct mii_data *mii_data; /* pointer to parent data */ + int mii_phyno; /* MII address */ + int mii_id1; /* PHY ID register 1 */ + int mii_id2; /* PHY ID register 2 */ + int mii_capmask; /* capability mask from BMSR */ +}; +typedef struct mii_attach_args mii_attach_args_t; + +/* + * Used to match a PHY. + */ +struct mii_phydesc { + u_int32_t mpd_oui; /* the PHY's OUI */ + u_int32_t mpd_model; /* the PHY's model */ + const char *mpd_name; /* the PHY's name */ +}; + +/* + * An array of these structures map MII media types to BMCR/ANAR settings. + */ +struct mii_media { + int mm_bmcr; /* BMCR settings for this media */ + int mm_anar; /* ANAR settings for this media */ + int mm_gtcr; /* 100base-T2 or 1000base-T CR */ +}; + +#define MII_MEDIA_NONE 0 +#define MII_MEDIA_10_T 1 +#define MII_MEDIA_10_T_FDX 2 +#define MII_MEDIA_100_T4 3 +#define MII_MEDIA_100_TX 4 +#define MII_MEDIA_100_TX_FDX 5 +#define MII_MEDIA_1000_X 6 +#define MII_MEDIA_1000_X_FDX 7 +#define MII_MEDIA_1000_T 8 +#define MII_MEDIA_1000_T_FDX 9 +#define MII_NMEDIA 10 + +#ifdef _KERNEL + +#define PHY_READ(p, r) \ + MIIBUS_READREG((p)->mii_dev, (p)->mii_phy, (r)) + +#define PHY_WRITE(p, r, v) \ + MIIBUS_WRITEREG((p)->mii_dev, (p)->mii_phy, (r), (v)) + +extern devclass_t miibus_devclass; +extern driver_t miibus_driver; + +int miibus_probe(device_t); +int miibus_attach(device_t); +int miibus_detach(device_t); + +int mii_anar(int); +void mii_down(struct mii_data *); +int mii_mediachg(struct mii_data *); +void mii_tick(struct mii_data *); +void mii_pollstat(struct mii_data *); +int mii_phy_probe(device_t, device_t *, ifm_change_cb_t, ifm_stat_cb_t); +void mii_add_media(struct mii_softc *); +void mii_phy_add_media(struct mii_softc *); + +int mii_media_from_bmcr(int); + +int mii_phy_auto(struct mii_softc *); +int mii_phy_detach(device_t dev); +void mii_phy_down(struct mii_softc *); +void mii_phy_reset(struct mii_softc *); +void mii_phy_setmedia(struct mii_softc *sc); +void mii_phy_update(struct mii_softc *, int); +int mii_phy_tick(struct mii_softc *); + +const struct mii_phydesc * mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd); + +void ukphy_status(struct mii_softc *); +#endif /* _KERNEL */ + +#endif /* _DEV_MII_MIIVAR_H_ */ diff --git a/sys/dev/mii/mlphy.c b/sys/dev/mii/mlphy.c new file mode 100644 index 0000000..744d3c3 --- /dev/null +++ b/sys/dev/mii/mlphy.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * driver for Micro Linear 6692 PHYs + * + * The Micro Linear 6692 is a strange beast, and dealing with it using + * this code framework is tricky. The 6692 is actually a 100Mbps-only + * device, which means that a second PHY is required to support 10Mbps + * modes. However, even though the 6692 does not support 10Mbps modes, + * it can still advertise them when performing autonegotiation. If a + * 10Mbps mode is negotiated, we must program the registers of the + * companion PHY accordingly in addition to programming the registers + * of the 6692. + * + * This device also does not have vendor/device ID registers. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/malloc.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include "miibus_if.h" + +#define ML_STATE_AUTO_SELF 1 +#define ML_STATE_AUTO_OTHER 2 + +struct mlphy_softc { + struct mii_softc ml_mii; + int ml_state; + int ml_linked; +}; + +static int mlphy_probe(device_t); +static int mlphy_attach(device_t); + +static device_method_t mlphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, mlphy_probe), + DEVMETHOD(device_attach, mlphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t mlphy_devclass; + +static driver_t mlphy_driver = { + "mlphy", + mlphy_methods, + sizeof(struct mlphy_softc) +}; + +DRIVER_MODULE(mlphy, miibus, mlphy_driver, mlphy_devclass, 0, 0); + +static int mlphy_service(struct mii_softc *, struct mii_data *, int); +static void mlphy_reset(struct mii_softc *); +static void mlphy_status(struct mii_softc *); + +static int +mlphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + device_t parent; + + ma = device_get_ivars(dev); + parent = device_get_parent(device_get_parent(dev)); + + /* + * Micro Linear PHY reports oui == 0 model == 0 + */ + if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || + MII_MODEL(ma->mii_id2) != 0) + return (ENXIO); + + /* + * Make sure the parent is a `tl'. So far, I have only + * encountered the 6692 on an Olicom card with a ThunderLAN + * controller chip. + */ + if (strcmp(device_get_name(parent), "tl") != 0) + return (ENXIO); + + device_set_desc(dev, "Micro Linear 6692 media interface"); + + return (0); +} + +static int +mlphy_attach(dev) + device_t dev; +{ + struct mlphy_softc *msc; + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + msc = device_get_softc(dev); + sc = &msc->ml_mii; + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = mlphy_service; + sc->mii_pdata = mii; + + mii->mii_instance++; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + +#if 0 /* See above. */ + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#endif + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); + + sc->mii_flags &= ~MIIF_NOISOLATE; + mii_phy_reset(sc); + sc->mii_flags |= MIIF_NOISOLATE; + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + ma->mii_capmask = ~sc->mii_capabilities; + device_printf(dev, " "); + mii_add_media(sc); + printf("\n"); +#undef ADD + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +mlphy_service(xsc, mii, cmd) + struct mii_softc *xsc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + struct mii_softc *other = NULL; + struct mlphy_softc *msc = (struct mlphy_softc *)xsc; + struct mii_softc *sc = (struct mii_softc *)&msc->ml_mii; + device_t *devlist; + int devs, i; + + /* + * See if there's another PHY on this bus with us. + * If so, we may need it for 10Mbps modes. + */ + device_get_children(msc->ml_mii.mii_dev, &devlist, &devs); + for (i = 0; i < devs; i++) { + if (strcmp(device_get_name(devlist[i]), "mlphy")) { + other = device_get_softc(devlist[i]); + break; + } + } + free(devlist, M_TEMP); + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * For autonegotiation, reset and isolate the + * companion PHY (if any) and then do NWAY + * autonegotiation ourselves. + */ + msc->ml_state = ML_STATE_AUTO_SELF; + if (other != NULL) { + mii_phy_reset(other); + PHY_WRITE(other, MII_BMCR, BMCR_ISO); + } + (void) mii_phy_auto(sc); + msc->ml_linked = 0; + return(0); + case IFM_10_T: + /* + * For 10baseT modes, reset and program the + * companion PHY (of any), then program ourselves + * to match. This will put us in pass-through + * mode and let the companion PHY do all the + * work. + * + * BMCR data is stored in the ifmedia entry. + */ + if (other != NULL) { + mii_phy_reset(other); + PHY_WRITE(other, MII_BMCR, ife->ifm_data); + } + PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + msc->ml_state = 0; + break; + case IFM_100_TX: + /* + * For 100baseTX modes, reset and isolate the + * companion PHY (if any), then program ourselves + * accordingly. + * + * BMCR data is stored in the ifmedia entry. + */ + if (other != NULL) { + mii_phy_reset(other); + PHY_WRITE(other, MII_BMCR, BMCR_ISO); + } + PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + msc->ml_state = 0; + break; + case IFM_100_T4: + /* + * XXX Not supported as a manual setting right now. + */ + return (EINVAL); + default: + break; + + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * Check to see if we have link. If we do, we don't + * need to restart the autonegotiation process. Read + * the BMSR twice in case it's latched. + * If we're in a 10Mbps mode, check the link of the + * 10Mbps PHY. Sometimes the Micro Linear PHY's + * linkstat bit will clear while the linkstat bit of + * the companion PHY will remain set. + */ + if (msc->ml_state == ML_STATE_AUTO_OTHER) { + reg = PHY_READ(other, MII_BMSR) | + PHY_READ(other, MII_BMSR); + } else { + reg = PHY_READ(sc, MII_BMSR) | + PHY_READ(sc, MII_BMSR); + } + + if (reg & BMSR_LINK) { + if (!msc->ml_linked) { + msc->ml_linked = 1; + mlphy_status(sc); + } + break; + } + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->mii_ticks != 5) + return (0); + + sc->mii_ticks = 0; + msc->ml_linked = 0; + mii->mii_media_active = IFM_NONE; + mii_phy_reset(sc); + msc->ml_state = ML_STATE_AUTO_SELF; + if (other != NULL) { + mii_phy_reset(other); + PHY_WRITE(other, MII_BMCR, BMCR_ISO); + } + mii_phy_auto(sc); + return(0); + } + + /* Update the media status. */ + + if (msc->ml_state == ML_STATE_AUTO_OTHER) { + int other_inst; + other_inst = other->mii_inst; + other->mii_inst = sc->mii_inst; + (void) (*other->mii_service)(other, mii, MII_POLLSTAT); + other->mii_inst = other_inst; + sc->mii_media_active = other->mii_media_active; + sc->mii_media_status = other->mii_media_status; + } else + ukphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +/* + * The Micro Linear PHY comes out of reset with the 'autoneg + * enable' bit set, which we don't want. + */ +static void +mlphy_reset(sc) + struct mii_softc *sc; +{ + int reg; + + mii_phy_reset(sc); + reg = PHY_READ(sc, MII_BMCR); + reg &= ~BMCR_AUTOEN; + PHY_WRITE(sc, MII_BMCR, reg); + + return; +} + +/* + * If we negotiate a 10Mbps mode, we need to check for an alternate + * PHY and make sure it's enabled and set correctly. + */ +static void +mlphy_status(sc) + struct mii_softc *sc; +{ + struct mlphy_softc *msc = (struct mlphy_softc *)sc; + struct mii_data *mii = msc->ml_mii.mii_pdata; + struct mii_softc *other = NULL; + device_t *devlist; + int devs, i; + + /* See if there's another PHY on the bus with us. */ + device_get_children(msc->ml_mii.mii_dev, &devlist, &devs); + for (i = 0; i < devs; i++) { + if (strcmp(device_get_name(devlist[i]), "mlphy")) { + other = device_get_softc(devlist[i]); + break; + } + } + free(devlist, M_TEMP); + + if (other == NULL) + return; + + ukphy_status(sc); + + if (IFM_SUBTYPE(mii->mii_media_active) != IFM_10_T) { + msc->ml_state = ML_STATE_AUTO_SELF; + mii_phy_reset(other); + PHY_WRITE(other, MII_BMCR, BMCR_ISO); + } + + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) { + msc->ml_state = ML_STATE_AUTO_OTHER; + mlphy_reset(&msc->ml_mii); + PHY_WRITE(&msc->ml_mii, MII_BMCR, BMCR_ISO); + mii_phy_reset(other); + mii_phy_auto(other); + } + + return; +} diff --git a/sys/dev/mii/nsgphy.c b/sys/dev/mii/nsgphy.c new file mode 100644 index 0000000..0cd6133 --- /dev/null +++ b/sys/dev/mii/nsgphy.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2001 Wind River Systems + * Copyright (c) 2001 + * Bill Paul <wpaul@bsdi.com>. All rights reserved. + * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Driver for the National Semiconductor DP83891 and DP83861 + * 10/100/1000 PHYs. + * Datasheet available at: http://www.national.com/ds/DP/DP83861.pdf + * + * The DP83891 is the older NatSemi gigE PHY which isn't being sold + * anymore. The DP83861 is its replacement, which is an 'enhanced' + * firmware driven component. The major difference between the + * two is that the 83891 can't generate interrupts, while the + * 83861 can. (I think it wasn't originally designed to do this, but + * it can now thanks to firmware updates.) The 83861 also allows + * access to its internal RAM via indirect register access. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <machine/clock.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/nsgphyreg.h> + +#include "miibus_if.h" + +static int nsgphy_probe(device_t); +static int nsgphy_attach(device_t); + +static device_method_t nsgphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, nsgphy_probe), + DEVMETHOD(device_attach, nsgphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t nsgphy_devclass; + +static driver_t nsgphy_driver = { + "nsgphy", + nsgphy_methods, + sizeof(struct mii_softc) +}; + + +DRIVER_MODULE(nsgphy, miibus, nsgphy_driver, nsgphy_devclass, 0, 0); + +static int nsgphy_service(struct mii_softc *, struct mii_data *,int); +static void nsgphy_status(struct mii_softc *); + +const struct mii_phydesc gphyters[] = { + { MII_OUI_NATSEMI, MII_MODEL_NATSEMI_DP83861, + MII_STR_NATSEMI_DP83861 }, + + { MII_OUI_NATSEMI, MII_MODEL_NATSEMI_DP83891, + MII_STR_NATSEMI_DP83891 }, + + { 0, 0, + NULL }, +}; + +static int +nsgphy_probe(device_t dev) +{ + struct mii_attach_args *ma; + const struct mii_phydesc *mpd; + + ma = device_get_ivars(dev); + mpd = mii_phy_match(ma, gphyters); + if (mpd != NULL) { + device_set_desc(dev, mpd->mpd_name); + return(0); + } + + return(ENXIO); +} + +static int +nsgphy_attach(device_t dev) +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + if (bootverbose) + device_printf(dev, "<rev. %d>\n", MII_REV(ma->mii_id2)); + device_printf(dev, " "); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = nsgphy_service; + sc->mii_pdata = mii; + sc->mii_anegticks = 5; + + mii->mii_instance++; + + sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | + (BMSR_10TFDX|BMSR_10THDX)) & ma->mii_capmask; + if (sc->mii_capabilities & BMSR_EXTSTAT) + sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); + + mii_phy_add_media(sc); + printf("\n"); + + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + mii_phy_setmedia(sc); + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + nsgphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +nsgphy_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmsr, bmcr, physup, gtsr; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + + physup = PHY_READ(sc, NSGPHY_MII_PHYSUP); + + if (physup & PHY_SUP_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * The media status bits are only valid if autonegotiation + * has completed (or it's disabled). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + switch (physup & (PHY_SUP_SPEED1|PHY_SUP_SPEED0)) { + case PHY_SUP_SPEED1: + mii->mii_media_active |= IFM_1000_T; + gtsr = PHY_READ(sc, MII_100T2SR); + if (gtsr & GTSR_MS_RES) + mii->mii_media_active |= IFM_ETH_MASTER; + break; + + case PHY_SUP_SPEED0: + mii->mii_media_active |= IFM_100_TX; + break; + + case 0: + mii->mii_media_active |= IFM_10_T; + break; + + default: + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + } + if (physup & PHY_SUP_DUPLEX) + mii->mii_media_active |= IFM_FDX; + } else + mii->mii_media_active = ife->ifm_media; +} diff --git a/sys/dev/mii/nsgphyreg.h b/sys/dev/mii/nsgphyreg.h new file mode 100644 index 0000000..c7680f1 --- /dev/null +++ b/sys/dev/mii/nsgphyreg.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2001 Wind River Systems + * Copyright (c) 2001 + * Bill Paul <wpaul@bsdi.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_NSGPHYREG_H_ +#define _DEV_MII_NSGPHYREG_H_ + +/* + * NatSemi DP83891 registers + */ + +#define NSGPHY_MII_STRAPOPT 0x10 /* Strap options */ +#define NSGPHY_STRAPOPT_PHYADDR 0xF800 /* PHY address */ +#define NSGPHY_STRAPOPT_COMPAT 0x0400 /* Broadcom compat mode */ +#define NSGPHY_STRAPOPT_MMSE 0x0200 /* Manual master/slave enable */ +#define NSGPHY_STRAPOPT_ANEG 0x0100 /* Autoneg enable */ +#define NSGPHY_STRAPOPT_MMSV 0x0080 /* Manual master/slave setting */ +#define NSGPHY_STRAPOPT_1000HDX 0x0010 /* Advertise 1000 half-duplex */ +#define NSGPHY_STRAPOPT_1000FDX 0x0008 /* Advertise 1000 full-duplex */ +#define NSGPHY_STRAPOPT_100_ADV 0x0004 /* Advertise 100 full/half-duplex */ +#define NSGPHY_STRAPOPT_SPEED1 0x0002 /* speed selection */ +#define NSGPHY_STRAPOPT_SPEED0 0x0001 /* speed selection */ +#define NSGPHY_STRAPOPT_SPDSEL (NSGPHY_STRAPOPT_SPEED1|NSGPHY_STRAPOPT_SPEED0) + +#define NSGPHY_MII_PHYSUP 0x11 /* PHY support/current status */ +#define PHY_SUP_SPEED1 0x0010 /* speed bit 1 */ +#define PHY_SUP_SPEED0 0x0008 /* speed bit 1 */ +#define NSGPHY_PHYSUP_SPEED1 0x0010 /* speed status */ +#define NSGPHY_PHYSUP_SPEED0 0x0008 /* speed status */ +#define NSGPHY_PHYSUP_SPDSTS (NSGPHY_PHYSUP_SPEED1|NSGPHY_PHYSUP_SPEED0) +#define NSGPHY_PHYSUP_LNKSTS 0x0004 /* link status */ +#define PHY_SUP_LINK 0x0004 /* link status */ +#define PHY_SUP_DUPLEX 0x0002 /* 1 == full-duplex */ +#define NSGPHY_PHYSUP_DUPSTS 0x0002 /* duplex status 1 == full */ +#define NSGPHY_PHYSUP_10BT 0x0001 /* 10baseT resolved */ + +#define NSGPHY_SPDSTS_1000 0x0010 +#define NSGPHY_SPDSTS_100 0x0008 +#define NSGPHY_SPDSTS_10 0x0000 + +#endif /* _DEV_NSGPHY_MIIREG_H_ */ diff --git a/sys/dev/mii/nsphy.c b/sys/dev/mii/nsphy.c new file mode 100644 index 0000000..85a1d8f --- /dev/null +++ b/sys/dev/mii/nsphy.c @@ -0,0 +1,384 @@ +/* $NetBSD: nsphy.c,v 1.18 1999/07/14 23:57:36 thorpej Exp $ */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * driver for National Semiconductor's DP83840A ethernet 10/100 PHY + * Data Sheet available from www.national.com + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/nsphyreg.h> + +#include "miibus_if.h" + +static int nsphy_probe(device_t); +static int nsphy_attach(device_t); + +static device_method_t nsphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, nsphy_probe), + DEVMETHOD(device_attach, nsphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t nsphy_devclass; + +static driver_t nsphy_driver = { + "nsphy", + nsphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(nsphy, miibus, nsphy_driver, nsphy_devclass, 0, 0); + +static int nsphy_service(struct mii_softc *, struct mii_data *, int); +static void nsphy_status(struct mii_softc *); + +static int +nsphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_NATSEMI && + MII_MODEL(ma->mii_id2) == MII_MODEL_NATSEMI_DP83840) { + device_set_desc(dev, MII_STR_NATSEMI_DP83840); + } else + return (ENXIO); + + return (0); +} + +static int +nsphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = nsphy_service; + sc->mii_pdata = mii; + +#ifdef foo + /* + * i82557 wedges if all of its PHYs are isolated! + */ + if (strcmp(device_get_name(device_get_parent(sc->mii_dev)), + "fxp") == 0 && mii->mii_instance == 0) +#endif + + sc->mii_flags |= MIIF_NOISOLATE; + mii->mii_instance++; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + +#if 0 + /* Can't do this on the i82557! */ + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#endif + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); + + mii_phy_reset(sc); + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + mii_add_media(sc); + printf("\n"); +#undef ADD + + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +nsphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + reg = PHY_READ(sc, MII_NSPHY_PCR); + + /* + * Set up the PCR to use LED4 to indicate full-duplex + * in both 10baseT and 100baseTX modes. + */ + reg |= PCR_LED4MODE; + + /* + * Make sure Carrier Intgrity Monitor function is + * disabled (normal for Node operation, but sometimes + * it's not set?!) + */ + reg |= PCR_CIMDIS; + + /* + * Make sure "force link good" is set to normal mode. + * It's only intended for debugging. + */ + reg |= PCR_FLINK100; + + /* + * Mystery bits which are supposedly `reserved', + * but we seem to need to set them when the PHY + * is connected to some interfaces: + * + * 0x0400 is needed for fxp + * (Intel EtherExpress Pro 10+/100B, 82557 chip) + * (nsphy with a DP83840 chip) + * 0x0100 may be needed for some other card + */ + reg |= 0x0100 | 0x0400; + + if (strcmp(device_get_name(device_get_parent(sc->mii_dev)), + "fxp") == 0) + PHY_WRITE(sc, MII_NSPHY_PCR, reg); + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) + return (0); + (void) mii_phy_auto(sc); + break; + case IFM_100_T4: + /* + * XXX Not supported as a manual setting right now. + */ + return (EINVAL); + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + nsphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +nsphy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + int bmsr, bmcr, par, anlpar; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, MII_BMSR) | + PHY_READ(sc, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * The PAR status bits are only valid of autonegotiation + * has completed (or it's disabled). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + /* + * Argh. The PAR doesn't seem to indicate duplex mode + * properly! Determine media based on link partner's + * advertised capabilities. + */ + if (PHY_READ(sc, MII_ANER) & ANER_LPAN) { + anlpar = PHY_READ(sc, MII_ANAR) & + PHY_READ(sc, MII_ANLPAR); + if (anlpar & ANLPAR_T4) + mii->mii_media_active |= IFM_100_T4; + else if (anlpar & ANLPAR_TX_FD) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_TX) + mii->mii_media_active |= IFM_100_TX; + else if (anlpar & ANLPAR_10_FD) + mii->mii_media_active |= IFM_10_T|IFM_FDX; + else if (anlpar & ANLPAR_10) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_NONE; + return; + } + + /* + * Link partner is not capable of autonegotiation. + * We will never be in full-duplex mode if this is + * the case, so reading the PAR is OK. + */ + par = PHY_READ(sc, MII_NSPHY_PAR); + if (par & PAR_10) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_100_TX; +#if 0 + if (par & PAR_FDX) + mii->mii_media_active |= IFM_FDX; +#endif + } else + mii->mii_media_active |= mii_media_from_bmcr(bmcr); +} diff --git a/sys/dev/mii/nsphyreg.h b/sys/dev/mii/nsphyreg.h new file mode 100644 index 0000000..5ff0490 --- /dev/null +++ b/sys/dev/mii/nsphyreg.h @@ -0,0 +1,115 @@ +/* $NetBSD: nsphyreg.h,v 1.1 1998/08/10 23:58:39 thorpej Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_NSPHYREG_H_ +#define _DEV_MII_NSPHYREG_H_ + +/* + * DP83840 registers. + */ + +#define MII_NSPHY_DCR 0x12 /* Disconnect counter */ + +#define MII_NSPHY_FCSCR 0x13 /* False carrier sense counter */ + +#define MII_NSPHY_RECR 0x15 /* Receive error counter */ + +#define MII_NSPHY_SRR 0x16 /* Silicon revision */ + +#define MII_NSPHY_PCR 0x17 /* PCS sub-layer configuration */ +#define PCR_NRZI 0x8000 /* NRZI encoding enabled for 100TX */ +#define PCR_DESCRTOSEL 0x4000 /* descrambler t/o select (2ms) */ +#define PCR_DESCRTODIS 0x2000 /* descrambler t/o disable */ +#define PCR_REPEATER 0x1000 /* repeater mode */ +#define PCR_ENCSEL 0x0800 /* encoder mode select */ +#define PCR_CLK25MDIS 0x0080 /* CLK25M disable */ +#define PCR_FLINK100 0x0040 /* force good link in 100mbps */ +#define PCR_CIMDIS 0x0020 /* carrier integrity monitor disable */ +#define PCR_TXOFF 0x0010 /* force transmit off */ +#define PCR_LED1MODE 0x0004 /* LED1 mode: see below */ +#define PCR_LED4MODE 0x0002 /* LED4 mode: see below */ + +/* + * LED1 Mode: + * + * 1 LED1 output configured to PAR's CON_STATUS, useful for + * network management in 100baseTX mode. + * + * 0 Normal LED1 operation - 10baseTX and 100baseTX transmission + * activity. + * + * LED4 Mode: + * + * 1 LED4 output configured to indicate full-duplex in both + * 10baseT and 100baseTX modes. + * + * 0 LED4 output configured to indicate polarity in 10baseT + * mode and full-duplex in 100baseTX mode. + */ + +#define MII_NSPHY_LBREMR 0x18 /* Loopback, bypass, error mask */ +#define LBREMR_BADSSDEN 0x8000 /* enable bad SSD detection */ +#define LBREMR_BP4B5B 0x4000 /* bypass 4b/5b encoding */ +#define LBREMR_BPSCR 0x2000 /* bypass scrambler */ +#define LBREMR_BPALIGN 0x1000 /* bypass alignment function */ +#define LBREMR_10LOOP 0x0800 /* 10baseT loopback */ +#define LBREMR_LB1 0x0200 /* loopback ctl 1 */ +#define LBREMR_LB0 0x0100 /* loopback ctl 0 */ +#define LBREMR_ALTCRS 0x0040 /* alt crs operation */ +#define LBREMR_LOOPXMTDIS 0x0020 /* disable transmit in 100TX loopbk */ +#define LBREMR_CODEERR 0x0010 /* code errors */ +#define LBREMR_PEERR 0x0008 /* premature end errors */ +#define LBREMR_LINKERR 0x0004 /* link errors */ +#define LBREMR_PKTERR 0x0002 /* packet errors */ + +#define MII_NSPHY_PAR 0x19 /* Physical address and status */ +#define PAR_DISCRSJAB 0x0800 /* disable car sense during jab */ +#define PAR_ANENSTAT 0x0400 /* autoneg mode status */ +#define PAR_FEFIEN 0x0100 /* far end fault enable */ +#define PAR_FDX 0x0080 /* full duplex status */ +#define PAR_10 0x0040 /* 10mbps mode */ +#define PAR_CON 0x0020 /* connect status */ +#define PAR_AMASK 0x001f /* PHY address bits */ + +#define MII_NSPHY_10BTSR 0x1b /* 10baseT status */ +#define MII_NSPHY_10BTCR 0x1c /* 10baseT configuration */ + +#endif /* _DEV_MII_NSPHYREG_H_ */ diff --git a/sys/dev/mii/pnaphy.c b/sys/dev/mii/pnaphy.c new file mode 100644 index 0000000..f952574 --- /dev/null +++ b/sys/dev/mii/pnaphy.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2000 Berkeley Software Design, Inc. + * Copyright (c) 1997, 1998, 1999, 2000 + * Bill Paul <wpaul@osd.bsdi.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * driver for homePNA PHYs + * This is really just a stub that allows us to identify homePNA-based + * transceicers and display the link status. MII-based homePNA PHYs + * only support one media type and no autonegotiation. If we were + * really clever, we could tweak some of the vendor-specific registers + * to optimize the link. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include "miibus_if.h" + +static int pnaphy_probe(device_t); +static int pnaphy_attach(device_t); + +static device_method_t pnaphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, pnaphy_probe), + DEVMETHOD(device_attach, pnaphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t pnaphy_devclass; + +static driver_t pnaphy_driver = { + "pnaphy", + pnaphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(pnaphy, miibus, pnaphy_driver, pnaphy_devclass, 0, 0); + +static int pnaphy_service(struct mii_softc *, struct mii_data *,int); + +static int +pnaphy_probe(dev) + device_t dev; +{ + + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_AMD && + MII_MODEL(ma->mii_id2) == MII_MODEL_AMD_79c978) { + device_set_desc(dev, MII_STR_AMD_79c978); + return(0); + } + + return(ENXIO); +} + +static int +pnaphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + const char *sep = ""; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = pnaphy_service; + sc->mii_pdata = mii; + + mii->mii_instance++; + + sc->mii_flags |= MIIF_NOISOLATE; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) +#define PRINT(s) printf("%s%s", sep, s); sep = ", " + + mii_phy_reset(sc); + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) + printf("no media present"); + else { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, sc->mii_inst), 0); + PRINT("HomePNA"); + } + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); + + printf("\n"); + +#undef ADD +#undef PRINT + + MIIBUS_MEDIAINIT(sc->mii_dev); + + return(0); +} + +static int +pnaphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + case IFM_10_T: + case IFM_100_TX: + case IFM_100_T4: + return (EINVAL); + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + ukphy_status(sc); + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) + mii->mii_media_active = IFM_ETHER|IFM_HPNA_1; + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} diff --git a/sys/dev/mii/pnphy.c b/sys/dev/mii/pnphy.c new file mode 100644 index 0000000..4cfed03 --- /dev/null +++ b/sys/dev/mii/pnphy.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Pseudo-driver for media selection on the Lite-On PNIC 82c168 + * chip. The NWAY support on this chip is horribly broken, so we + * only support manual mode selection. This is lame, but getting + * NWAY to work right is amazingly difficult. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <machine/bus_pio.h> +#include <machine/bus_memio.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> + +#include <pci/if_dcreg.h> + +#include "miibus_if.h" + +#define DC_SETBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, \ + CSR_READ_4(sc, reg) | x) + +#define DC_CLRBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, \ + CSR_READ_4(sc, reg) & ~x) + +static int pnphy_probe(device_t); +static int pnphy_attach(device_t); + +static device_method_t pnphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, pnphy_probe), + DEVMETHOD(device_attach, pnphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t pnphy_devclass; + +static driver_t pnphy_driver = { + "pnphy", + pnphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(pnphy, miibus, pnphy_driver, pnphy_devclass, 0, 0); + +static int pnphy_service(struct mii_softc *, struct mii_data *, int); +static void pnphy_status(struct mii_softc *); + +static int +pnphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + /* + * The dc driver will report the 82c168 vendor and device + * ID to let us know that it wants us to attach. + */ + if (ma->mii_id1 != DC_VENDORID_LO || + ma->mii_id2 != DC_DEVICEID_82C168) + return(ENXIO); + + device_set_desc(dev, "PNIC 82c168 media interface"); + + return (0); +} + +static int +pnphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = pnphy_service; + sc->mii_pdata = mii; + + sc->mii_flags |= MIIF_NOISOLATE; + mii->mii_instance++; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + + sc->mii_capabilities = + BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX|BMSR_10THDX; + sc->mii_capabilities &= ma->mii_capmask; + device_printf(dev, " "); + mii_add_media(sc); + printf("\n"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); + +#undef ADD + + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +pnphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + return (0); + } + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + sc->mii_flags = 0; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* NWAY is busted on this chip */ + case IFM_100_T4: + /* + * XXX Not supported as a manual setting right now. + */ + return (EINVAL); + case IFM_100_TX: + mii->mii_media_active = IFM_ETHER|IFM_100_TX; + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) + mii->mii_media_active |= IFM_FDX; + MIIBUS_STATCHG(sc->mii_dev); + return(0); + case IFM_10_T: + mii->mii_media_active = IFM_ETHER|IFM_10_T; + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) + mii->mii_media_active |= IFM_FDX; + MIIBUS_STATCHG(sc->mii_dev); + return(0); + default: + return(EINVAL); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + break; + } + + /* Update the media status. */ + pnphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +pnphy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + int reg; + struct dc_softc *dc_sc; + + dc_sc = mii->mii_ifp->if_softc; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + reg = CSR_READ_4(dc_sc, DC_ISR); + + if (!(reg & DC_ISR_LINKFAIL)) + mii->mii_media_status |= IFM_ACTIVE; + + if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_100_TX; + if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX) + mii->mii_media_active |= IFM_FDX; + + return; +} diff --git a/sys/dev/mii/qsphy.c b/sys/dev/mii/qsphy.c new file mode 100644 index 0000000..2c2bd6a --- /dev/null +++ b/sys/dev/mii/qsphy.c @@ -0,0 +1,317 @@ +/* OpenBSD: qsphy.c,v 1.6 2000/08/26 20:04:18 nate Exp */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +/* NetBSD: qsphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * driver for Quality Semiconductor's QS6612 ethernet 10/100 PHY + * datasheet from www.qualitysemi.com + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/qsphyreg.h> + +#include "miibus_if.h" + +static int qsphy_probe(device_t); +static int qsphy_attach(device_t); + +static device_method_t qsphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, qsphy_probe), + DEVMETHOD(device_attach, qsphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t qsphy_devclass; + +static driver_t qsphy_driver = { + "qsphy", + qsphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(qsphy, miibus, qsphy_driver, qsphy_devclass, 0, 0); + +static int qsphy_service(struct mii_softc *, struct mii_data *, int); +static void qsphy_reset(struct mii_softc *); +static void qsphy_status(struct mii_softc *); + +static int +qsphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_QUALSEMI && + MII_MODEL(ma->mii_id2) == MII_MODEL_QUALSEMI_QS6612) { + device_set_desc(dev, MII_STR_QUALSEMI_QS6612); + } else + return (ENXIO); + + return (0); +} + +static int +qsphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = qsphy_service; + sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOISOLATE; + + qsphy_reset(sc); + + mii->mii_instance++; + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + mii_add_media(sc); + printf("\n"); + + MIIBUS_MEDIAINIT(sc->mii_dev); + return (0); +} + +static int +qsphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + /* + * If we're not selected, then do nothing, just isolate, if + * changing media. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + if (cmd == MII_MEDIACHG) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + } + + return (0); + } + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) + return (0); + + (void) mii_phy_auto(sc); + break; + + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * This PHY's autonegotiation doesn't need to be kicked. + */ + break; + } + + /* Update the media status. */ + qsphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +qsphy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + int bmsr, bmcr, pctl; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, MII_BMSR) | + PHY_READ(sc, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + pctl = PHY_READ(sc, MII_QSPHY_PCTL); + switch (pctl & PCTL_OPMASK) { + case PCTL_10_T: + mii->mii_media_active |= IFM_10_T; + break; + case PCTL_10_T_FDX: + mii->mii_media_active |= IFM_10_T|IFM_FDX; + break; + case PCTL_100_TX: + mii->mii_media_active |= IFM_100_TX; + break; + case PCTL_100_TX_FDX: + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + break; + case PCTL_100_T4: + mii->mii_media_active |= IFM_100_T4; + break; + case PCTL_AN: + mii->mii_media_active |= IFM_NONE; + break; + default: + /* Erg... this shouldn't happen. */ + mii->mii_media_active |= IFM_NONE; + break; + } +} + +static void +qsphy_reset(sc) + struct mii_softc *sc; +{ + + mii_phy_reset(sc); + PHY_WRITE(sc, MII_QSPHY_IMASK, 0); +} diff --git a/sys/dev/mii/qsphyreg.h b/sys/dev/mii/qsphyreg.h new file mode 100644 index 0000000..a697865 --- /dev/null +++ b/sys/dev/mii/qsphyreg.h @@ -0,0 +1,88 @@ +/* OpenBSD: qsphyreg.h,v 1.2 1999/03/09 00:02:45 jason Exp */ +/* NetBSD: qsphyreg.h,v 1.1 1998/08/11 00:01:03 thorpej Exp */ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_MII_QSPHYREG_H_ +#define _DEV_MII_QSPHYREG_H_ + +/* + * Register definitions for the Quality Semiconductor QS6612 + * Further documentation can be found at: + * http://www.qualitysemi.com/products/network.html + */ + +#define MII_QSPHY_MCTL 0x11 /* Mode control */ +#define MCTL_T4PRE 0x1000 /* 100baseT4 interface present */ +#define MCTL_BTEXT 0x0800 /* reduce 10baseT squelch level */ +#define MCTL_FACTTEST 0x0100 /* factory test mode */ +#define MCTL_PHYADDRMASK 0x00f8 /* PHY address */ +#define MCTL_FACTTEST2 0x0004 /* another factory test mode */ +#define MCTL_NLPDIS 0x0002 /* disable link pulse tx */ +#define MCTL_SQEDIS 0x0001 /* disable SQE */ + +#define MII_QSPHY_ISRC 0x1d /* Interrupt source */ +#define MII_QSPHY_IMASK 0x1e /* Interrupt mask */ +#define IMASK_TLINTR 0x8000 /* ThunderLAN interrupt mode */ +#define IMASK_ANCPL 0x0040 /* autonegotiation complete */ +#define IMASK_RFD 0x0020 /* remote fault detected */ +#define IMASK_LD 0x0010 /* link down */ +#define IMASK_ANLPA 0x0008 /* autonegotiation LP ACK */ +#define IMASK_PDT 0x0004 /* parallel detection fault */ +#define IMASK_ANPR 0x0002 /* autonegotiation page received */ +#define IMASK_REF 0x0001 /* receive error counter full */ + +#define MII_QSPHY_PCTL 0x1f /* PHY control */ +#define PCTL_RXERDIS 0x2000 /* receive error counter disable */ +#define PCTL_ANC 0x1000 /* autonegotiation complete */ +#define PCTL_RLBEN 0x0200 /* remote coopback enable */ +#define PCTL_DCREN 0x0100 /* DC restoration enable */ +#define PCTL_4B5BEN 0x0040 /* 4b/5b encoding */ +#define PCTL_PHYISO 0x0020 /* isolate PHY */ +#define PCTL_OPMASK 0x001c /* operation mode mask */ +#define PCTL_AN 0x0000 /* autonegotiation in-progress */ +#define PCTL_10_T 0x0004 /* 10baseT */ +#define PCTL_100_TX 0x0008 /* 100baseTX */ +#define PCTL_100_T4 0x0010 /* 100baseT4 */ +#define PCTL_10_T_FDX 0x0014 /* 10baseT-FDX */ +#define PCTL_100_TX_FDX 0x0018 /* 100baseTX-FDX */ +#define PCTL_MLT3DIS 0x0002 /* disable MLT3 */ +#define PCTL_SRCDIS 0x0001 /* disable scrambling */ + +#endif /* _DEV_MII_QSPHYREG_H_ */ diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c new file mode 100644 index 0000000..5c0f13d --- /dev/null +++ b/sys/dev/mii/rgephy.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Driver for the RealTek 8169S/8110S internal 10/100/1000 PHY. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <machine/clock.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/rgephyreg.h> + +#include "miibus_if.h" + +#include <machine/bus.h> +#include <pci/if_rlreg.h> + +static int rgephy_probe(device_t); +static int rgephy_attach(device_t); + +static device_method_t rgephy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, rgephy_probe), + DEVMETHOD(device_attach, rgephy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t rgephy_devclass; + +static driver_t rgephy_driver = { + "rgephy", + rgephy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0); + +static int rgephy_service(struct mii_softc *, struct mii_data *, int); +static void rgephy_status(struct mii_softc *); +static int rgephy_mii_phy_auto(struct mii_softc *); +static void rgephy_reset(struct mii_softc *); +static void rgephy_loop(struct mii_softc *); +static void rgephy_load_dspcode(struct mii_softc *); +static int rgephy_mii_model; + +static int +rgephy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxREALTEK && + MII_MODEL(ma->mii_id2) == MII_MODEL_xxREALTEK_RTL8169S) { + device_set_desc(dev, MII_STR_xxREALTEK_RTL8169S); + return(0); + } + + return(ENXIO); +} + +static int +rgephy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + const char *sep = ""; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = rgephy_service; + sc->mii_pdata = mii; + + sc->mii_flags |= MIIF_NOISOLATE; + mii->mii_instance++; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) +#define PRINT(s) printf("%s%s", sep, s); sep = ", " + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#if 0 + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); +#endif + + rgephy_mii_model = MII_MODEL(ma->mii_id2); + rgephy_reset(sc); + + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities &= ~BMSR_ANEG; + + device_printf(dev, " "); + mii_add_media(sc); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), + RGEPHY_BMCR_FDX); + PRINT(", 1000baseTX"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), 0); + PRINT("1000baseTX-FDX"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); + PRINT("auto"); + + printf("\n"); +#undef ADD +#undef PRINT + + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +rgephy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg, speed, gig; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + rgephy_reset(sc); /* XXX hardware bug work-around */ + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: +#ifdef foo + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN) + return (0); +#endif + (void) rgephy_mii_phy_auto(sc); + break; + case IFM_1000_T: + speed = RGEPHY_S1000; + goto setit; + case IFM_100_TX: + speed = RGEPHY_S100; + goto setit; + case IFM_10_T: + speed = RGEPHY_S10; +setit: + rgephy_loop(sc); + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + speed |= RGEPHY_BMCR_FDX; + gig = RGEPHY_1000CTL_AFD; + } else { + gig = RGEPHY_1000CTL_AHD; + } + + PHY_WRITE(sc, RGEPHY_MII_1000CTL, 0); + PHY_WRITE(sc, RGEPHY_MII_BMCR, speed); + PHY_WRITE(sc, RGEPHY_MII_ANAR, RGEPHY_SEL_TYPE); + + if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) + break; + + PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig); + PHY_WRITE(sc, RGEPHY_MII_BMCR, + speed|RGEPHY_BMCR_AUTOEN|RGEPHY_BMCR_STARTNEG); + + /* + * When settning the link manually, one side must + * be the master and the other the slave. However + * ifmedia doesn't give us a good way to specify + * this, so we fake it by using one of the LINK + * flags. If LINK0 is set, we program the PHY to + * be a master, otherwise it's a slave. + */ + if ((mii->mii_ifp->if_flags & IFF_LINK0)) { + PHY_WRITE(sc, RGEPHY_MII_1000CTL, + gig|RGEPHY_1000CTL_MSE|RGEPHY_1000CTL_MSC); + } else { + PHY_WRITE(sc, RGEPHY_MII_1000CTL, + gig|RGEPHY_1000CTL_MSE); + } + break; +#ifdef foo + case IFM_NONE: + PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN); + break; +#endif + case IFM_100_T4: + default: + return (EINVAL); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * Check to see if we have link. If we do, we don't + * need to restart the autonegotiation process. Read + * the BMSR twice in case it's latched. + */ + reg = PHY_READ(sc, RL_GMEDIASTAT); + if (reg & RL_GMEDIASTAT_LINK) + break; + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->mii_ticks != 5/*10*/) + return (0); + + sc->mii_ticks = 0; + rgephy_mii_phy_auto(sc); + return (0); + } + + /* Update the media status. */ + rgephy_status(sc); + + /* + * Callback if something changed. Note that we need to poke + * the DSP on the RealTek PHYs if the media changes. + * + */ + if (sc->mii_media_active != mii->mii_media_active || + sc->mii_media_status != mii->mii_media_status || + cmd == MII_MEDIACHG) { + mii_phy_update(sc, cmd); + rgephy_load_dspcode(sc); + } + return (0); +} + +static void +rgephy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + int bmsr, bmcr; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, RL_GMEDIASTAT); + + if (bmsr & RL_GMEDIASTAT_LINK) + mii->mii_media_status |= IFM_ACTIVE; + bmsr = PHY_READ(sc, RGEPHY_MII_BMSR); + + bmcr = PHY_READ(sc, RGEPHY_MII_BMCR); + + if (bmcr & RGEPHY_BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & RGEPHY_BMCR_AUTOEN) { + if ((bmsr & RGEPHY_BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + } + + bmsr = PHY_READ(sc, RL_GMEDIASTAT); + if (bmsr & RL_GMEDIASTAT_10MBPS) + mii->mii_media_active |= IFM_10_T; + if (bmsr & RL_GMEDIASTAT_100MBPS) + mii->mii_media_active |= IFM_100_TX; + if (bmsr & RL_GMEDIASTAT_1000MBPS) + mii->mii_media_active |= IFM_1000_T; + if (bmsr & RL_GMEDIASTAT_FDX) + mii->mii_media_active |= IFM_FDX; + + return; +} + + +static int +rgephy_mii_phy_auto(mii) + struct mii_softc *mii; +{ + rgephy_loop(mii); + rgephy_reset(mii); + + PHY_WRITE(mii, RGEPHY_MII_ANAR, + BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA); + DELAY(1000); + PHY_WRITE(mii, RGEPHY_MII_1000CTL, RGEPHY_1000CTL_AFD); + DELAY(1000); + PHY_WRITE(mii, RGEPHY_MII_BMCR, + RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); + DELAY(100); + + return (EJUSTRETURN); +} + +static void +rgephy_loop(struct mii_softc *sc) +{ + u_int32_t bmsr; + int i; + + PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN); + DELAY(1000); + + for (i = 0; i < 15000; i++) { + bmsr = PHY_READ(sc, RGEPHY_MII_BMSR); + if (!(bmsr & RGEPHY_BMSR_LINK)) { +#if 0 + device_printf(sc->mii_dev, "looped %d\n", i); +#endif + break; + } + DELAY(10); + } +} + +#define PHY_SETBIT(x, y, z) \ + PHY_WRITE(x, y, (PHY_READ(x, y) | (z))) +#define PHY_CLRBIT(x, y, z) \ + PHY_WRITE(x, y, (PHY_READ(x, y) & ~(z))) + +/* + * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of + * existing revisions of the 8169S/8110S chips need to be tuned in + * order to reliably negotiate a 1000Mbps link. Later revs of the + * chips may not require this software tuning. + */ +static void +rgephy_load_dspcode(struct mii_softc *sc) +{ + int val; + + PHY_WRITE(sc, 31, 0x0001); + PHY_WRITE(sc, 21, 0x1000); + PHY_WRITE(sc, 24, 0x65C7); + PHY_CLRBIT(sc, 4, 0x0800); + val = PHY_READ(sc, 4) & 0xFFF; + PHY_WRITE(sc, 4, val); + PHY_WRITE(sc, 3, 0x00A1); + PHY_WRITE(sc, 2, 0x0008); + PHY_WRITE(sc, 1, 0x1020); + PHY_WRITE(sc, 0, 0x1000); + PHY_SETBIT(sc, 4, 0x0800); + PHY_CLRBIT(sc, 4, 0x0800); + val = (PHY_READ(sc, 4) & 0xFFF) | 0x7000; + PHY_WRITE(sc, 4, val); + PHY_WRITE(sc, 3, 0xFF41); + PHY_WRITE(sc, 2, 0xDE60); + PHY_WRITE(sc, 1, 0x0140); + PHY_WRITE(sc, 0, 0x0077); + val = (PHY_READ(sc, 4) & 0xFFF) | 0xA000; + PHY_WRITE(sc, 4, val); + PHY_WRITE(sc, 3, 0xDF01); + PHY_WRITE(sc, 2, 0xDF20); + PHY_WRITE(sc, 1, 0xFF95); + PHY_WRITE(sc, 0, 0xFA00); + val = (PHY_READ(sc, 4) & 0xFFF) | 0xB000; + PHY_WRITE(sc, 4, val); + PHY_WRITE(sc, 3, 0xFF41); + PHY_WRITE(sc, 2, 0xDE20); + PHY_WRITE(sc, 1, 0x0140); + PHY_WRITE(sc, 0, 0x00BB); + val = (PHY_READ(sc, 4) & 0xFFF) | 0xF000; + PHY_WRITE(sc, 4, val); + PHY_WRITE(sc, 3, 0xDF01); + PHY_WRITE(sc, 2, 0xDF20); + PHY_WRITE(sc, 1, 0xFF95); + PHY_WRITE(sc, 0, 0xBF00); + PHY_SETBIT(sc, 4, 0x0800); + PHY_CLRBIT(sc, 4, 0x0800); + PHY_WRITE(sc, 31, 0x0000); + + DELAY(40); +} + +static void +rgephy_reset(struct mii_softc *sc) +{ + mii_phy_reset(sc); + DELAY(1000); + rgephy_load_dspcode(sc); + + return; +} diff --git a/sys/dev/mii/rgephyreg.h b/sys/dev/mii/rgephyreg.h new file mode 100644 index 0000000..1adecf4 --- /dev/null +++ b/sys/dev/mii/rgephyreg.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_RGEPHYREG_H_ +#define _DEV_MII_RGEPHYREG_H_ + +/* + * RealTek 8169S/8110S gigE PHY registers + */ + +#define RGEPHY_MII_BMCR 0x00 +#define RGEPHY_BMCR_RESET 0x8000 +#define RGEPHY_BMCR_LOOP 0x4000 +#define RGEPHY_BMCR_SPD0 0x2000 /* speed select, lower bit */ +#define RGEPHY_BMCR_AUTOEN 0x1000 /* Autoneg enabled */ +#define RGEPHY_BMCR_PDOWN 0x0800 /* Power down */ +#define RGEPHY_BMCR_ISO 0x0400 /* Isolate */ +#define RGEPHY_BMCR_STARTNEG 0x0200 /* Restart autoneg */ +#define RGEPHY_BMCR_FDX 0x0100 /* Duplex mode */ +#define RGEPHY_BMCR_CTEST 0x0080 /* Collision test enable */ +#define RGEPHY_BMCR_SPD1 0x0040 /* Speed select, upper bit */ + +#define RGEPHY_S1000 RGEPHY_BMCR_SPD1 /* 1000mbps */ +#define RGEPHY_S100 RGEPHY_BMCR_SPD0 /* 100mpbs */ +#define RGEPHY_S10 0 /* 10mbps */ + +#define RGEPHY_MII_BMSR 0x01 +#define RGEPHY_BMSR_100T4 0x8000 /* 100 base T4 capable */ +#define RGEPHY_BMSR_100TXFDX 0x4000 /* 100 base Tx full duplex capable */ +#define RGEPHY_BMSR_100TXHDX 0x2000 /* 100 base Tx half duplex capable */ +#define RGEPHY_BMSR_10TFDX 0x1000 /* 10 base T full duplex capable */ +#define RGEPHY_BMSR_10THDX 0x0800 /* 10 base T half duplex capable */ +#define RGEPHY_BMSR_100T2FDX 0x0400 /* 100 base T2 full duplex capable */ +#define RGEPHY_BMSR_100T2HDX 0x0200 /* 100 base T2 half duplex capable */ +#define RGEPHY_BMSR_EXTSTS 0x0100 /* Extended status present */ +#define RGEPHY_BMSR_PRESUB 0x0040 /* Preamble surpression */ +#define RGEPHY_BMSR_ACOMP 0x0020 /* Autoneg complete */ +#define RGEPHY_BMSR_RFAULT 0x0010 /* Remote fault condition occured */ +#define RGEPHY_BMSR_ANEG 0x0008 /* Autoneg capable */ +#define RGEPHY_BMSR_LINK 0x0004 /* Link status */ +#define RGEPHY_BMSR_JABBER 0x0002 /* Jabber detected */ +#define RGEPHY_BMSR_EXT 0x0001 /* Extended capability */ + +#define RGEPHY_MII_ANAR 0x04 +#define RGEPHY_ANAR_NP 0x8000 /* Next page */ +#define RGEPHY_ANAR_RF 0x2000 /* Remote fault */ +#define RGEPHY_ANAR_ASP 0x0800 /* Asymmetric Pause */ +#define RGEPHY_ANAR_PC 0x0400 /* Pause capable */ +#define RGEPHY_ANAR_T4 0x0200 /* local device supports 100bT4 */ +#define RGEPHY_ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */ +#define RGEPHY_ANAR_TX 0x0080 /* local device supports 100bTx */ +#define RGEPHY_ANAR_10_FD 0x0040 /* local device supports 10bT FD */ +#define RGEPHY_ANAR_10 0x0020 /* local device supports 10bT */ +#define RGEPHY_ANAR_SEL 0x001F /* selector field, 00001=Ethernet */ + +#define RGEPHY_MII_ANLPAR 0x05 +#define RGEPHY_ANLPAR_NP 0x8000 /* Next page */ +#define RGEPHY_ANLPAR_RF 0x2000 /* Remote fault */ +#define RGEPHY_ANLPAR_ASP 0x0800 /* Asymmetric Pause */ +#define RGEPHY_ANLPAR_PC 0x0400 /* Pause capable */ +#define RGEPHY_ANLPAR_T4 0x0200 /* link partner supports 100bT4 */ +#define RGEPHY_ANLPAR_TX_FD 0x0100 /* link partner supports 100bTx FD */ +#define RGEPHY_ANLPAR_TX 0x0080 /* link partner supports 100bTx */ +#define RGEPHY_ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */ +#define RGEPHY_ANLPAR_10 0x0020 /* link partner supports 10bT */ +#define RGEPHY_ANLPAR_SEL 0x001F /* selector field, 00001=Ethernet */ + +#define RGEPHY_SEL_TYPE 0x0001 /* ethernet */ + +#define RGEPHY_MII_ANER 0x06 +#define RGEPHY_ANER_PDF 0x0010 /* Parallel detection fault */ +#define RGEPHY_ANER_LPNP 0x0008 /* Link partner can next page */ +#define RGEPHY_ANER_NP 0x0004 /* Local PHY can next page */ +#define RGEPHY_ANER_RX 0x0002 /* Next page received */ +#define RGEPHY_ANER_LPAN 0x0001 /* Link partner autoneg capable */ + +#define RGEPHY_MII_NEXTP 0x07 /* Next page */ + +#define RGEPHY_MII_NEXTP_LP 0x08 /* Next page of link partner */ + +#define RGEPHY_MII_1000CTL 0x09 /* 1000baseT control */ +#define RGEPHY_1000CTL_TST 0xE000 /* test modes */ +#define RGEPHY_1000CTL_MSE 0x1000 /* Master/Slave manual enable */ +#define RGEPHY_1000CTL_MSC 0x0800 /* Master/Slave select */ +#define RGEPHY_1000CTL_RD 0x0400 /* Repeater/DTE */ +#define RGEPHY_1000CTL_AFD 0x0200 /* Advertise full duplex */ +#define RGEPHY_1000CTL_AHD 0x0100 /* Advertise half duplex */ + +#define RGEPHY_TEST_TX_JITTER 0x2000 +#define RGEPHY_TEST_TX_JITTER_MASTER_MODE 0x4000 +#define RGEPHY_TEST_TX_JITTER_SLAVE_MODE 0x6000 +#define RGEPHY_TEST_TX_DISTORTION 0x8000 + +#define RGEPHY_MII_1000STS 0x0A /* 1000baseT status */ +#define RGEPHY_1000STS_MSF 0x8000 /* Master/slave fault */ +#define RGEPHY_1000STS_MSR 0x4000 /* Master/slave result */ +#define RGEPHY_1000STS_LRS 0x2000 /* Local receiver status */ +#define RGEPHY_1000STS_RRS 0x1000 /* Remote receiver status */ +#define RGEPHY_1000STS_LPFD 0x0800 /* Link partner can FD */ +#define RGEPHY_1000STS_LPHD 0x0400 /* Link partner can HD */ +#define RGEPHY_1000STS_IEC 0x00FF /* Idle error count */ + +#define RGEPHY_MII_EXTSTS 0x0F /* Extended status */ +#define RGEPHY_EXTSTS_X_FD_CAP 0x8000 /* 1000base-X FD capable */ +#define RGEPHY_EXTSTS_X_HD_CAP 0x4000 /* 1000base-X HD capable */ +#define RGEPHY_EXTSTS_T_FD_CAP 0x2000 /* 1000base-T FD capable */ +#define RGEPHY_EXTSTS_T_HD_CAP 0x1000 /* 1000base-T HD capable */ + + + +#endif /* _DEV_RGEPHY_MIIREG_H_ */ diff --git a/sys/dev/mii/rlphy.c b/sys/dev/mii/rlphy.c new file mode 100644 index 0000000..1847586 --- /dev/null +++ b/sys/dev/mii/rlphy.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * driver for RealTek 8139 internal PHYs + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <machine/bus.h> +#include <pci/if_rlreg.h> + +#include "miibus_if.h" + +static int rlphy_probe(device_t); +static int rlphy_attach(device_t); + +static device_method_t rlphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, rlphy_probe), + DEVMETHOD(device_attach, rlphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t rlphy_devclass; + +static driver_t rlphy_driver = { + "rlphy", + rlphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(rlphy, miibus, rlphy_driver, rlphy_devclass, 0, 0); + +static int rlphy_service(struct mii_softc *, struct mii_data *, int); +static void rlphy_status(struct mii_softc *); + +static int +rlphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + device_t parent; + + ma = device_get_ivars(dev); + parent = device_get_parent(device_get_parent(dev)); + + /* Test for RealTek 8201L PHY */ + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_REALTEK && + MII_MODEL(ma->mii_id2) == MII_MODEL_REALTEK_RTL8201L) { + device_set_desc(dev, MII_STR_REALTEK_RTL8201L); + return(0); + } + + /* + * RealTek PHY doesn't have vendor/device ID registers: + * the rl driver fakes up a return value of all zeros. + */ + if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || + MII_MODEL(ma->mii_id2) != 0) + return (ENXIO); + + /* + * Make sure the parent is an `rl' or an `re'. + */ + if (strcmp(device_get_name(parent), "rl") != 0 && + strcmp(device_get_name(parent), "re") != 0) + return (ENXIO); + + device_set_desc(dev, "RealTek internal media interface"); + + return (0); +} + +static int +rlphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + + /* + * The RealTek PHY can never be isolated, so never allow non-zero + * instances! + */ + if (mii->mii_instance != 0) { + device_printf(dev, "ignoring this PHY, non-zero instance\n"); + return(ENXIO); + } + + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = rlphy_service; + sc->mii_pdata = mii; + mii->mii_instance++; + + sc->mii_flags |= MIIF_NOISOLATE; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + +#if 0 /* See above. */ + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#endif + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); + + mii_phy_reset(sc); + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + mii_add_media(sc); + printf("\n"); +#undef ADD + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +rlphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + + /* + * We can't isolate the RealTek PHY, so it has to be the only one! + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + panic("rlphy_service: can't isolate RealTek PHY"); + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) + return (0); + (void) mii_phy_auto(sc); + break; + case IFM_100_T4: + /* + * XXX Not supported as a manual setting right now. + */ + return (EINVAL); + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * The RealTek PHY's autonegotiation doesn't need to be + * kicked; it continues in the background. + */ + break; + } + + /* Update the media status. */ + rlphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +rlphy_status(phy) + struct mii_softc *phy; +{ + struct mii_data *mii = phy->mii_pdata; + int bmsr, bmcr, anlpar; + device_t parent; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(phy, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * NWay autonegotiation takes the highest-order common + * bit of the ANAR and ANLPAR (i.e. best media advertised + * both by us and our link partner). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + if ((anlpar = PHY_READ(phy, MII_ANAR) & + PHY_READ(phy, MII_ANLPAR))) { + if (anlpar & ANLPAR_T4) + mii->mii_media_active |= IFM_100_T4; + else if (anlpar & ANLPAR_TX_FD) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_TX) + mii->mii_media_active |= IFM_100_TX; + else if (anlpar & ANLPAR_10_FD) + mii->mii_media_active |= IFM_10_T|IFM_FDX; + else if (anlpar & ANLPAR_10) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_NONE; + return; + } + /* + * If the other side doesn't support NWAY, then the + * best we can do is determine if we have a 10Mbps or + * 100Mbps link. There's no way to know if the link + * is full or half duplex, so we default to half duplex + * and hope that the user is clever enough to manually + * change the media settings if we're wrong. + */ + + + /* + * The RealTek PHY supports non-NWAY link speed + * detection, however it does not report the link + * detection results via the ANLPAR or BMSR registers. + * (What? RealTek doesn't do things the way everyone + * else does? I'm just shocked, shocked I tell you.) + * To determine the link speed, we have to do one + * of two things: + * + * - If this is a standalone RealTek RTL8201(L) PHY, + * we can determine the link speed by testing bit 0 + * in the magic, vendor-specific register at offset + * 0x19. + * + * - If this is a RealTek MAC with integrated PHY, we + * can test the 'SPEED10' bit of the MAC's media status + * register. + */ + parent = device_get_parent(phy->mii_dev); + if (strcmp(device_get_name(parent), "rl") != 0) { + if (PHY_READ(phy, 0x0019) & 0x01) + mii->mii_media_active |= IFM_100_TX; + else + mii->mii_media_active |= IFM_10_T; + } else { + if (PHY_READ(phy, RL_MEDIASTAT) & + RL_MEDIASTAT_SPEED10) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_100_TX; + } + + } else + mii->mii_media_active = mii_media_from_bmcr(bmcr); +} diff --git a/sys/dev/mii/ruephy.c b/sys/dev/mii/ruephy.c new file mode 100644 index 0000000..f2dbc16 --- /dev/null +++ b/sys/dev/mii/ruephy.c @@ -0,0 +1,299 @@ +/*- + * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * driver for RealTek RTL8150 internal PHY + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <machine/bus.h> +#include <dev/mii/ruephyreg.h> + +#include "miibus_if.h" + +static int ruephy_probe(device_t); +static int ruephy_attach(device_t); + +static device_method_t ruephy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ruephy_probe), + DEVMETHOD(device_attach, ruephy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t ruephy_devclass; + +static driver_t ruephy_driver = { + "ruephy", + ruephy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(ruephy, miibus, ruephy_driver, ruephy_devclass, 0, 0); + +static int ruephy_service(struct mii_softc *, struct mii_data *, int); +static void ruephy_reset(struct mii_softc *); +static void ruephy_status(struct mii_softc *); + +static int +ruephy_probe(device_t dev) +{ + struct mii_attach_args *ma; + device_t parent; + + ma = device_get_ivars(dev); + parent = device_get_parent(device_get_parent(dev)); + + /* + * RealTek RTL8150 PHY doesn't have vendor/device ID registers: + * the rue driver fakes up a return value of all zeros. + */ + if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || + MII_MODEL(ma->mii_id2) != 0) + return (ENXIO); + + /* + * Make sure the parent is an 'rue'. + */ + if (strcmp(device_get_name(parent), "rue") != 0) + return (ENXIO); + + device_set_desc(dev, "RealTek RTL8150 internal media interface"); + + return (0); +} + +static int +ruephy_attach(device_t dev) +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + + /* + * The RealTek PHY can never be isolated, so never allow non-zero + * instances! + */ + if (mii->mii_instance != 0) { + device_printf(dev, "ignoring this PHY, non-zero instance\n"); + return (ENXIO); + } + + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = ruephy_service; + sc->mii_pdata = mii; + mii->mii_instance++; + + sc->mii_flags |= MIIF_NOISOLATE; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + + ruephy_reset(sc); + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + mii_phy_add_media(sc); + printf("\n"); +#undef ADD + + MIIBUS_MEDIAINIT(sc->mii_dev); + return (0); +} + +static int +ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + /* + * We can't isolate the RealTek RTL8150 PHY, + * so it has to be the only one! + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + panic("ruephy_service: can't isolate RealTek RTL8150 PHY"); + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) + return (0); + (void) mii_phy_auto(sc); + break; + case IFM_100_T4: + /* + * XXX Not supported as a manual setting right now. + */ + return (EINVAL); + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * Check to see if we have link. If we do, we don't + * need to restart the autonegotiation process. Read + * the MSR twice in case it's latched. + */ + reg = PHY_READ(sc, RUEPHY_MII_MSR) | + PHY_READ(sc, RUEPHY_MII_MSR); + if (reg & RUEPHY_MSR_LINK) + break; + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->mii_ticks != 5) + return (0); + + sc->mii_ticks = 0; + ruephy_reset(sc); + if (mii_phy_auto(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + ruephy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + + return (0); +} + +static void +ruephy_reset(struct mii_softc *sc) +{ + + mii_phy_reset(sc); + + /* + * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after + * XXX reset, which breaks autonegotiation. + */ + PHY_WRITE(sc, MII_BMCR, (BMCR_S100 | BMCR_AUTOEN | BMCR_FDX)); +} + +static void +ruephy_status(struct mii_softc *phy) +{ + struct mii_data *mii = phy->mii_pdata; + int bmsr, bmcr, msr; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + msr = PHY_READ(phy, RUEPHY_MII_MSR) | PHY_READ(phy, RUEPHY_MII_MSR); + if (msr & RUEPHY_MSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(phy, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); + + if (bmcr & BMCR_AUTOEN) { + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + if (msr & RUEPHY_MSR_SPEED100) + mii->mii_media_active |= IFM_100_TX; + else + mii->mii_media_active |= IFM_10_T; + + if (msr & RUEPHY_MSR_DUPLEX) + mii->mii_media_active |= IFM_FDX; + } else + mii->mii_media_active = mii_media_from_bmcr(bmcr); +} diff --git a/sys/dev/mii/ruephyreg.h b/sys/dev/mii/ruephyreg.h new file mode 100644 index 0000000..5f3911b --- /dev/null +++ b/sys/dev/mii/ruephyreg.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _RUEPHYREG_H_ +#define _RUEPHYREG_H_ + +#define RUEPHY_MII_MSR 0x0137 /* B, R/W */ +#define RUEPHY_MSR_RXFCE 0x40 +#define RUEPHY_MSR_DUPLEX 0x10 +#define RUEPHY_MSR_SPEED100 0x08 +#define RUEPHY_MSR_LINK 0x04 + +#endif /* _RUEPHYREG_H_ */ diff --git a/sys/dev/mii/tdkphy.c b/sys/dev/mii/tdkphy.c new file mode 100644 index 0000000..b21311f --- /dev/null +++ b/sys/dev/mii/tdkphy.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2000,2001 Jonathan Chen. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Driver for the TDK 78Q2120 MII + * + * References: + * Datasheet for the 78Q2120 - http://www.tsc.tdk.com/lan/78q2120.pdf + * Most of this code stolen from ukphy.c + */ + +/* + * The TDK 78Q2120 is found on some Xircom X3201 based cardbus cards. It's just + * like any other normal phy, except it does auto negotiation in a different + * way. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <machine/clock.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/tdkphyreg.h> + +#include "miibus_if.h" + +#if 0 +#if !defined(lint) +static const char rcsid[] = + "$Id: tdkphy.c,v 1.3 2000/10/14 06:20:56 jon Exp $"; +#endif +#endif + +static int tdkphy_probe(device_t); +static int tdkphy_attach(device_t); + +static device_method_t tdkphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, tdkphy_probe), + DEVMETHOD(device_attach, tdkphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t tdkphy_devclass; + +static driver_t tdkphy_driver = { + "tdkphy", + tdkphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(tdkphy, miibus, tdkphy_driver, tdkphy_devclass, 0, 0); + +static int tdkphy_service(struct mii_softc *, struct mii_data *, int); +static void tdkphy_status(struct mii_softc *); + +static int +tdkphy_probe(device_t dev) +{ + struct mii_attach_args *ma; + ma = device_get_ivars(dev); + if ((MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_TDK || + MII_MODEL(ma->mii_id2) != MII_MODEL_TDK_78Q2120)) + return (ENXIO); + + device_set_desc(dev, MII_STR_TDK_78Q2120); + return (0); +} + +static int +tdkphy_attach(device_t dev) +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + if (bootverbose) + device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n", + MII_OUI(ma->mii_id1, ma->mii_id2), + MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = tdkphy_service; + sc->mii_pdata = mii; + + mii->mii_instance++; + + sc->mii_flags |= MIIF_NOISOLATE; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#if 0 + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); +#endif + + mii_phy_reset(sc); + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + mii_add_media(sc); + printf("\n"); +#undef ADD + + MIIBUS_MEDIAINIT(sc->mii_dev); + + return(0); +} + +static int +tdkphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) + return (0); + (void) mii_phy_auto(sc); + break; + case IFM_100_T4: + /* + * Not supported on MII + */ + return (EINVAL); + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + tdkphy_status(sc); + if (sc->mii_pdata->mii_media_active & IFM_FDX) + PHY_WRITE(sc, MII_BMCR, PHY_READ(sc, MII_BMCR) | BMCR_FDX); + else + PHY_WRITE(sc, MII_BMCR, PHY_READ(sc, MII_BMCR) & ~BMCR_FDX); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +tdkphy_status(struct mii_softc *phy) +{ + struct mii_data *mii = phy->mii_pdata; + int bmsr, bmcr, anlpar, diag; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(phy, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * NWay autonegotiation takes the highest-order common + * bit of the ANAR and ANLPAR (i.e. best media advertised + * both by us and our link partner). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR); + /* + * ANLPAR doesn't get set on my card, but we check it anyway, + * since it is mentioned in the 78Q2120 specs. + */ + if (anlpar & ANLPAR_T4) + mii->mii_media_active |= IFM_100_T4; + else if (anlpar & ANLPAR_TX_FD) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_TX) + mii->mii_media_active |= IFM_100_TX; + else if (anlpar & ANLPAR_10_FD) + mii->mii_media_active |= IFM_10_T|IFM_FDX; + else if (anlpar & ANLPAR_10) + mii->mii_media_active |= IFM_10_T; + else { + /* + * ANLPAR isn't set, which leaves two possibilities: + * 1) Auto negotiation failed + * 2) Auto negotiation completed, but the card forgot + * to set ANLPAR. + * So we check the MII_DIAG(18) register... + */ + diag = PHY_READ(phy, MII_DIAG); + if (diag & DIAG_NEGFAIL) /* assume 10baseT if no neg */ + mii->mii_media_active |= IFM_10_T; + else { + if (diag & DIAG_DUPLEX) + mii->mii_media_active |= IFM_FDX; + if (diag & DIAG_RATE_100) + mii->mii_media_active |= IFM_100_TX; + else + mii->mii_media_active |= IFM_10_T; + } + } + } else { + mii->mii_media_active = mii_media_from_bmcr(bmcr); + } +} diff --git a/sys/dev/mii/tdkphyreg.h b/sys/dev/mii/tdkphyreg.h new file mode 100644 index 0000000..1f10625 --- /dev/null +++ b/sys/dev/mii/tdkphyreg.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2000,2001 Jonathan Chen. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Register definitions for TDK 78Q2120 + */ + +#ifndef _DEV_MII_TDKPHYREG_H_ +#define _DEV_MII_TDKPHYREG_H_ + +#define MII_VENDOR 16 +#define VENDOR_RXCC 0x0001 +#define VENDOR_PCSBP 0x0002 +#define VENDOR_RVSPOL 0x0010 +#define VENDOR_NOAPOL 0x0020 +#define VENDOR_GPIO0DIR 0x0040 +#define VENDOR_GPIO0DAT 0x0080 +#define VENDOR_GPIO1DIR 0x0100 +#define VENDOR_GPIO1DAT 0x0200 +#define VENDOR_10BTLOOP 0x0400 +#define VENDOR_NOSQE 0x0800 +#define VENDOR_TXHIM 0x1000 +#define VENDOR_INTLVL 0x4000 +#define VENDOR_RPTR 0x8000 + +#define MII_INT 17 +#define INT_STAT_MASK 0x00ff +#define INT_STAT_ACOMP 0x0001 +#define INT_STAT_RFAULT 0x0002 +#define INT_STAT_LSCHG 0x0004 +#define INT_STAT_LPACK 0x0008 +#define INT_STAT_PDF 0x0010 +#define INT_STAT_PRX 0x0020 +#define INT_STAT_RXERR 0x0040 +#define INT_STAT_JABBER 0x0080 +#define INT_CTRL_MASK 0xff00 +#define INT_CTRL_ACOMP 0x0100 +#define INT_CTRL_RFAULT 0x0200 +#define INT_CTRL_LSCHG 0x0400 +#define INT_CTRL_LPACK 0x0800 +#define INT_CTRL_PDF 0x1000 +#define INT_CTRL_PRX 0x2000 +#define INT_CTRL_RXERR 0x4000 +#define INT_CTRL_JABBER 0x8000 + + +#define MII_DIAG 18 +#define DIAG_RLOCK 0x0100 +#define DIAG_RPASS 0x0200 +#define DIAG_RATE_100 0x0400 +#define DIAG_DUPLEX 0x0800 +#define DIAG_NEGFAIL 0x1000 + + +#endif diff --git a/sys/dev/mii/tlphy.c b/sys/dev/mii/tlphy.c new file mode 100644 index 0000000..ca9f854 --- /dev/null +++ b/sys/dev/mii/tlphy.c @@ -0,0 +1,439 @@ +/* $NetBSD: tlphy.c,v 1.18 1999/05/14 11:40:28 drochner Exp $ */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Driver for Texas Instruments's ThunderLAN PHYs + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/malloc.h> + +#include <machine/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/tlphyreg.h> + +#include "miibus_if.h" + +struct tlphy_softc { + struct mii_softc sc_mii; /* generic PHY */ + int sc_need_acomp; +}; + +static int tlphy_probe(device_t); +static int tlphy_attach(device_t); + +static device_method_t tlphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, tlphy_probe), + DEVMETHOD(device_attach, tlphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t tlphy_devclass; + +static driver_t tlphy_driver = { + "tlphy", + tlphy_methods, + sizeof(struct tlphy_softc) +}; + +DRIVER_MODULE(tlphy, miibus, tlphy_driver, tlphy_devclass, 0, 0); + +static int tlphy_service(struct mii_softc *, struct mii_data *, int); +static int tlphy_auto(struct tlphy_softc *); +static void tlphy_acomp(struct tlphy_softc *); +static void tlphy_status(struct tlphy_softc *); + +static int +tlphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_xxTI || + MII_MODEL(ma->mii_id2) != MII_MODEL_xxTI_TLAN10T) + return (ENXIO); + + device_set_desc(dev, MII_STR_xxTI_TLAN10T); + + return (0); +} + +static int +tlphy_attach(dev) + device_t dev; +{ + struct tlphy_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + const char *sep = ""; + int capmask = 0xFFFFFFFF; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->sc_mii.mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->sc_mii.mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, &sc->sc_mii, mii_list); + + sc->sc_mii.mii_inst = mii->mii_instance; + sc->sc_mii.mii_phy = ma->mii_phyno; + sc->sc_mii.mii_service = tlphy_service; + sc->sc_mii.mii_pdata = mii; + + if (mii->mii_instance) { + struct mii_softc *other; + device_t *devlist; + int devs, i; + + device_get_children(sc->sc_mii.mii_dev, &devlist, &devs); + for (i = 0; i < devs; i++) { + if (strcmp(device_get_name(devlist[i]), "tlphy")) { + other = device_get_softc(devlist[i]); + capmask &= ~other->mii_capabilities; + break; + } + } + free(devlist, M_TEMP); + } + + mii->mii_instance++; + + sc->sc_mii.mii_flags &= ~MIIF_NOISOLATE; + mii_phy_reset(&sc->sc_mii); + sc->sc_mii.mii_flags |= MIIF_NOISOLATE; + + /* + * Note that if we're on a device that also supports 100baseTX, + * we are not going to want to use the built-in 10baseT port, + * since there will be another PHY on the MII wired up to the + * UTP connector. The parent indicates this to us by specifying + * the TLPHY_MEDIA_NO_10_T bit. + */ + sc->sc_mii.mii_capabilities = + PHY_READ(&sc->sc_mii, MII_BMSR) & capmask /*ma->mii_capmask*/; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->sc_mii.mii_inst), + BMCR_ISO); + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_LOOP, + sc->sc_mii.mii_inst), BMCR_LOOP); + +#define PRINT(s) printf("%s%s", sep, s); sep = ", " + + device_printf(dev, " "); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc->sc_mii.mii_inst), 0); + PRINT("10base2/BNC"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc->sc_mii.mii_inst), 0); + PRINT("10base5/AUI"); + + if (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) { + printf("%s", sep); + mii_add_media(&sc->sc_mii); + } + + printf("\n"); +#undef ADD +#undef PRINT + MIIBUS_MEDIAINIT(sc->sc_mii.mii_dev); + return(0); +} + +static int +tlphy_service(self, mii, cmd) + struct mii_softc *self; + struct mii_data *mii; + int cmd; +{ + struct tlphy_softc *sc = (struct tlphy_softc *)self; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + if (sc->sc_need_acomp) + tlphy_acomp(sc); + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) { + reg = PHY_READ(&sc->sc_mii, MII_BMCR); + PHY_WRITE(&sc->sc_mii, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * The ThunderLAN PHY doesn't self-configure after + * an autonegotiation cycle, so there's no such + * thing as "already in auto mode". + */ + (void) tlphy_auto(sc); + break; + case IFM_10_2: + case IFM_10_5: + PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); + PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL); + DELAY(100000); + break; + default: + PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0); + DELAY(100000); + PHY_WRITE(&sc->sc_mii, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(&sc->sc_mii, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * Check to see if we have link. If we do, we don't + * need to restart the autonegotiation process. Read + * the BMSR twice in case it's latched. + * + * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?! + */ + reg = PHY_READ(&sc->sc_mii, MII_BMSR) | + PHY_READ(&sc->sc_mii, MII_BMSR); + if (reg & BMSR_LINK) + break; + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->sc_mii.mii_ticks != 5) + return (0); + + sc->sc_mii.mii_ticks = 0; + mii_phy_reset(&sc->sc_mii); + tlphy_auto(sc); + return (0); + } + + /* Update the media status. */ + tlphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(&sc->sc_mii, cmd); + return (0); +} + +static void +tlphy_status(sc) + struct tlphy_softc *sc; +{ + struct mii_data *mii = sc->sc_mii.mii_pdata; + int bmsr, bmcr, tlctrl; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmcr = PHY_READ(&sc->sc_mii, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL); + if (tlctrl & CTRL_AUISEL) { + mii->mii_media_status = 0; + mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media; + return; + } + + bmsr = PHY_READ(&sc->sc_mii, MII_BMSR) | + PHY_READ(&sc->sc_mii, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + /* + * Grr, braindead ThunderLAN PHY doesn't have any way to + * tell which media is actually active. (Note it also + * doesn't self-configure after autonegotiation.) We + * just have to report what's in the BMCR. + */ + if (bmcr & BMCR_FDX) + mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= IFM_10_T; +} + +static int +tlphy_auto(sc) + struct tlphy_softc *sc; +{ + int error; + + switch ((error = mii_phy_auto(&sc->sc_mii))) { + case EIO: + /* + * Just assume we're not in full-duplex mode. + * XXX Check link and try AUI/BNC? + */ + PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); + break; + + case EJUSTRETURN: + /* Flag that we need to program when it completes. */ + sc->sc_need_acomp = 1; + break; + + default: + tlphy_acomp(sc); + } + + return (error); +} + +static void +tlphy_acomp(sc) + struct tlphy_softc *sc; +{ + int aner, anlpar; + + sc->sc_need_acomp = 0; + + /* + * Grr, braindead ThunderLAN PHY doesn't self-configure + * after autonegotiation. We have to do it ourselves + * based on the link partner status. + */ + + aner = PHY_READ(&sc->sc_mii, MII_ANER); + if (aner & ANER_LPAN) { + anlpar = PHY_READ(&sc->sc_mii, MII_ANLPAR) & + PHY_READ(&sc->sc_mii, MII_ANAR); + if (anlpar & ANAR_10_FD) { + PHY_WRITE(&sc->sc_mii, MII_BMCR, BMCR_FDX); + return; + } + } + PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); +} diff --git a/sys/dev/mii/tlphyreg.h b/sys/dev/mii/tlphyreg.h new file mode 100644 index 0000000..77e4a45 --- /dev/null +++ b/sys/dev/mii/tlphyreg.h @@ -0,0 +1,59 @@ +/* $NetBSD: tlphyreg.h,v 1.1 1998/08/10 23:59:58 thorpej Exp $ */ + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_TLPHYREG_H_ +#define _DEV_MII_TLPHYREG_H_ + +/* + * Registers for the TI ThunderLAN internal PHY. + */ + +#define MII_TLPHY_ID 0x10 /* ThunderLAN PHY ID */ +#define ID_10BASETAUI 0x0001 /* 10baseT/AUI PHY */ + +#define MII_TLPHY_CTRL 0x11 /* Control regiseter */ +#define CTRL_ILINK 0x8000 /* Ignore link */ +#define CTRL_SWPOL 0x4000 /* swap polarity */ +#define CTRL_AUISEL 0x2000 /* Select AUI */ +#define CTRL_SQEEN 0x1000 /* Enable SQE */ +#define CTRL_NFEW 0x0004 /* Not far end wrap */ +#define CTRL_INTEN 0x0002 /* Interrupts enable */ +#define CTRL_TINT 0x0001 /* Test Interrupts */ + +#define MII_TLPHY_ST 0x12 /* Status register */ +#define ST_MII_INT 0x8000 /* MII interrupt */ +#define ST_PHOK 0x4000 /* Power high OK */ +#define ST_POLOK 0x2000 /* Polarity OK */ +#define ST_TPE 0x1000 /* Twisted pair energy */ + +#endif /* _DEV_MII_TLPHYREG_H_ */ diff --git a/sys/dev/mii/ukphy.c b/sys/dev/mii/ukphy.c new file mode 100644 index 0000000..68403ee --- /dev/null +++ b/sys/dev/mii/ukphy.c @@ -0,0 +1,229 @@ +/* $NetBSD: ukphy.c,v 1.2 1999/04/23 04:24:32 thorpej Exp $ */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center, and by Frank van der Linden. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * driver for generic unknown PHYs + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include "miibus_if.h" + +static int ukphy_probe(device_t); +static int ukphy_attach(device_t); + +static device_method_t ukphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ukphy_probe), + DEVMETHOD(device_attach, ukphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t ukphy_devclass; + +static driver_t ukphy_driver = { + "ukphy", + ukphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(ukphy, miibus, ukphy_driver, ukphy_devclass, 0, 0); + +static int ukphy_service(struct mii_softc *, struct mii_data *, int); + +static int +ukphy_probe(dev) + device_t dev; +{ + + /* + * We know something is here, so always match at a low priority. + */ + device_set_desc(dev, "Generic IEEE 802.3u media interface"); + return (-100); +} + +static int +ukphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + if (bootverbose) + device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n", + MII_OUI(ma->mii_id1, ma->mii_id2), + MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = ukphy_service; + sc->mii_pdata = mii; + + mii->mii_instance++; + + sc->mii_flags |= MIIF_NOISOLATE; + + mii_phy_reset(sc); + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + if (sc->mii_capabilities & BMSR_EXTSTAT) + sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); + device_printf(dev, " "); + mii_phy_add_media(sc); + printf("\n"); + + MIIBUS_MEDIAINIT(sc->mii_dev); + + return(0); +} + +static int +ukphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + mii_phy_setmedia(sc); + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + ukphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} diff --git a/sys/dev/mii/ukphy_subr.c b/sys/dev/mii/ukphy_subr.c new file mode 100644 index 0000000..ca26b95 --- /dev/null +++ b/sys/dev/mii/ukphy_subr.c @@ -0,0 +1,119 @@ +/* $NetBSD: ukphy_subr.c,v 1.2 1998/11/05 04:08:02 thorpej Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center, and by Frank van der Linden. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Subroutines shared by the ukphy driver and other PHY drivers. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include "miibus_if.h" + +/* + * Media status subroutine. If a PHY driver does media detection simply + * by decoding the NWay autonegotiation, use this routine. + */ +void +ukphy_status(struct mii_softc *phy) +{ + struct mii_data *mii = phy->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmsr, bmcr, anlpar; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(phy, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * NWay autonegotiation takes the highest-order common + * bit of the ANAR and ANLPAR (i.e. best media advertised + * both by us and our link partner). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR); + if (anlpar & ANLPAR_T4) + mii->mii_media_active |= IFM_100_T4; + else if (anlpar & ANLPAR_TX_FD) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_TX) + mii->mii_media_active |= IFM_100_TX; + else if (anlpar & ANLPAR_10_FD) + mii->mii_media_active |= IFM_10_T|IFM_FDX; + else if (anlpar & ANLPAR_10) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_NONE; + } else + mii->mii_media_active = ife->ifm_media; +} diff --git a/sys/dev/mii/xmphy.c b/sys/dev/mii/xmphy.c new file mode 100644 index 0000000..2a1ee80 --- /dev/null +++ b/sys/dev/mii/xmphy.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2000 + * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * driver for the XaQti XMAC II's internal PHY. This is sort of + * like a 10/100 PHY, except the only thing we're really autoselecting + * here is full/half duplex. Speed is always 1000mbps. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <dev/mii/xmphyreg.h> + +#include "miibus_if.h" + +static int xmphy_probe(device_t); +static int xmphy_attach(device_t); + +static device_method_t xmphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, xmphy_probe), + DEVMETHOD(device_attach, xmphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t xmphy_devclass; + +static driver_t xmphy_driver = { + "xmphy", + xmphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(xmphy, miibus, xmphy_driver, xmphy_devclass, 0, 0); + +static int xmphy_service(struct mii_softc *, struct mii_data *, int); +static void xmphy_status(struct mii_softc *); +static int xmphy_mii_phy_auto(struct mii_softc *); + +static int +xmphy_probe(dev) + device_t dev; +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxXAQTI && + MII_MODEL(ma->mii_id2) == MII_MODEL_XAQTI_XMACII) { + device_set_desc(dev, MII_STR_XAQTI_XMACII); + return(0); + } + + if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_JATO && + MII_MODEL(ma->mii_id2) == MII_MODEL_JATO_BASEX) { + device_set_desc(dev, MII_STR_JATO_BASEX); + return(0); + } + + return(ENXIO); +} + +static int +xmphy_attach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + const char *sep = ""; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = xmphy_service; + sc->mii_pdata = mii; + + sc->mii_flags |= MIIF_NOISOLATE; + mii->mii_instance++; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) +#define PRINT(s) printf("%s%s", sep, s); sep = ", " + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#if 0 + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); +#endif + + mii_phy_reset(sc); + + device_printf(dev, " "); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst), + XMPHY_BMCR_FDX); + PRINT("1000baseSX"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 0); + PRINT("1000baseSX-FDX"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); + PRINT("auto"); + + printf("\n"); +#undef ADD +#undef PRINT + + MIIBUS_MEDIAINIT(sc->mii_dev); + return(0); +} + +static int +xmphy_service(sc, mii, cmd) + struct mii_softc *sc; + struct mii_data *mii; + int cmd; +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: +#ifdef foo + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, XMPHY_MII_BMCR) & XMPHY_BMCR_AUTOEN) + return (0); +#endif + (void) xmphy_mii_phy_auto(sc); + break; + case IFM_1000_SX: + mii_phy_reset(sc); + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_FDX); + PHY_WRITE(sc, XMPHY_MII_BMCR, XMPHY_BMCR_FDX); + } else { + PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_HDX); + PHY_WRITE(sc, XMPHY_MII_BMCR, 0); + } + break; + case IFM_100_T4: + case IFM_100_TX: + case IFM_10_T: + default: + return (EINVAL); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + /* + * Check to see if we have link. If we do, we don't + * need to restart the autonegotiation process. Read + * the BMSR twice in case it's latched. + */ + reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + if (reg & BMSR_LINK) + break; + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->mii_ticks != 5) + return (0); + + sc->mii_ticks = 0; + + mii_phy_reset(sc); + xmphy_mii_phy_auto(sc); + return(0); + } + + /* Update the media status. */ + xmphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +xmphy_status(sc) + struct mii_softc *sc; +{ + struct mii_data *mii = sc->mii_pdata; + int bmsr, bmcr, anlpar; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, XMPHY_MII_BMSR) | + PHY_READ(sc, XMPHY_MII_BMSR); + if (bmsr & XMPHY_BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + /* Do dummy read of extended status register. */ + bmcr = PHY_READ(sc, XMPHY_MII_EXTSTS); + + bmcr = PHY_READ(sc, XMPHY_MII_BMCR); + + if (bmcr & XMPHY_BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + + if (bmcr & XMPHY_BMCR_AUTOEN) { + if ((bmsr & XMPHY_BMSR_ACOMP) == 0) { + if (bmsr & XMPHY_BMSR_LINK) { + mii->mii_media_active |= IFM_1000_SX|IFM_HDX; + return; + } + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + mii->mii_media_active |= IFM_1000_SX; + anlpar = PHY_READ(sc, XMPHY_MII_ANAR) & + PHY_READ(sc, XMPHY_MII_ANLPAR); + if (anlpar & XMPHY_ANLPAR_FDX) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + return; + } + + mii->mii_media_active |= IFM_1000_SX; + if (bmcr & XMPHY_BMCR_FDX) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + + return; +} + + +static int +xmphy_mii_phy_auto(mii) + struct mii_softc *mii; +{ + int anar = 0; + + anar = PHY_READ(mii, XMPHY_MII_ANAR); + anar |= XMPHY_ANAR_FDX|XMPHY_ANAR_HDX; + PHY_WRITE(mii, XMPHY_MII_ANAR, anar); + DELAY(1000); + PHY_WRITE(mii, XMPHY_MII_BMCR, + XMPHY_BMCR_AUTOEN | XMPHY_BMCR_STARTNEG); + + return (EJUSTRETURN); +} diff --git a/sys/dev/mii/xmphyreg.h b/sys/dev/mii/xmphyreg.h new file mode 100644 index 0000000..e06b197 --- /dev/null +++ b/sys/dev/mii/xmphyreg.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2000 + * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_XMPHYREG_H_ +#define _DEV_MII_XMPHYREG_H_ + +/* + * XaQti XMAC II PHY registers + */ + +#define XMPHY_MII_BMCR 0x00 +#define XMPHY_BMCR_RESET 0x8000 +#define XMPHY_BMCR_LOOP 0x4000 +#define XMPHY_BMCR_AUTOEN 0x1000 /* Autoneg enabled */ +#define XMPHY_BMCR_PDOWN 0x0800 /* Power down */ +#define XMPHY_BMCR_ISO 0x0400 /* Isolate */ +#define XMPHY_BMCR_STARTNEG 0x0200 /* Restart autoneg */ +#define XMPHY_BMCR_FDX 0x0100 /* Duplex mode */ + +#define XMPHY_MII_BMSR 0x01 +#define XMPHY_BMSR_EXTSTS 0x0100 /* Extended status present */ +#define XMPHY_BMSR_ACOMP 0x0020 /* Autoneg complete */ +#define XMPHY_BMSR_RFAULT 0x0010 /* Remote fault condition occured */ +#define XMPHY_BMSR_ANEG 0x0008 /* Autoneg capable */ +#define XMPHY_BMSR_LINK 0x0004 /* Link status */ +#define XMPHY_BMSR_EXT 0x0001 /* Extended capability */ + +#define XMPHY_MII_ANAR 0x04 +#define XMPHY_ANAR_NP 0x8000 /* Next page */ +#define XMPHY_ANAR_ACK 0x4000 /* Next page or base received */ +#define XMPHY_ANAR_RFBITS 0x3000 /* Remote fault bits */ +#define XMPHY_ANAR_PAUSEBITS 0x0180 /* Pause bits */ +#define XMPHY_ANAR_HDX 0x0040 /* Select half duplex */ +#define XMPHY_ANAR_FDX 0x0020 /* Select full duplex */ + +#define XMPHY_MII_ANLPAR 0x05 +#define XMPHY_ANLPAR_NP 0x8000 /* Next page */ +#define XMPHY_ANLPAR_ACK 0x4000 /* Next page or base received */ +#define XMPHY_ANLPAR_RFBITS 0x3000 /* Remote fault bits */ +#define XMPHY_ANLPAR_PAUSEBITS 0x0180 /* Pause bits */ +#define XMPHY_ANLPAR_HDX 0x0040 /* Select half duplex */ +#define XMPHY_ANLPAR_FDX 0x0020 /* Select full duplex */ + +#define XMPHY_RF_OK 0x0000 /* No error -- link is good */ +#define XMPHY_RF_LINKFAIL 0x1000 /* Link failure */ +#define XMPHY_RF_OFFLINE 0x2000 /* Offline */ +#define XMPHY_RF_ANEGFAIL 0x3000 /* Autonegotiation error */ + +#define XMPHY_PAUSE_NOPAUSE 0x0000 /* No pause possible */ +#define XMPHY_PAUSE_ASYMETRIC 0x0080 /* Asymetric pause toward LP */ +#define XMPHY_PAUSE_SYMETRIC 0x0100 /* Symetric pause */ +#define XMPHY_PAUSE_BOTH 0x0180 /* Both sym and asym pause */ + +#define XMPHY_MII_ANER 0x06 +#define XMPHY_ANER_LPNP 0x0008 /* Link partner can next page */ +#define XMPHY_ANER_NP 0x0004 /* Local PHY can next page */ +#define XMPHY_ANER_RX 0x0002 /* Next page received */ + +#define XMPHY_MII_NEXTP 0x07 /* Next page */ +#define XMPHY_NEXTP_MORE 0x8000 /* More next pages to follow */ +#define XMPHY_NEXTP_ACK1 0x4000 /* Ack bit received OK */ +#define XMPHY_NEXTP_MP 0x2000 /* Page is message page */ +#define XMPHY_NEXTP_ACK2 0x1000 /* can comply with message (r/o) */ +#define XMPHY_NEXTP_TOGGLE 0x0800 /* sync with LP */ +#define XMPHY_NEXTP_MESSAGE 0x07FF /* message */ + +#define XMPHY_MII_NEXTPLP 0x08 /* Next page of link partner */ +#define XMPHY_NEXTPLP_MORE 0x8000 /* More next pages to follow */ +#define XMPHY_NEXTPLP_ACK1 0x4000 /* Ack bit received OK */ +#define XMPHY_NEXTPLP_MP 0x2000 /* Page is message page */ +#define XMPHY_NEXTPLP_ACK2 0x1000 /* can comply with message (r/o) */ +#define XMPHY_NEXTPLP_TOGGLE 0x0800 /* sync with LP */ +#define XMPHY_NEXTPLP_MESSAGE 0x07FF /* message */ + +#define XMPHY_MII_EXTSTS 0x0F /* Extended status */ +#define XMPHY_EXTSTS_FDX 0x8000 /* 1000base-X FD capable */ +#define XMPHY_EXTSTS_HDX 0x4000 /* 1000base-X HD capable */ + +#define XMPHY_MII_RESAB 0x10 /* Resolved ability */ +#define XMPHY_RESAB_PAUSEBITS 0x0180 /* Pause bits */ +#define XMPHY_RESAB_HDX 0x0040 /* Half duplex selected */ +#define XMPHY_RESAB_FDX 0x0020 /* Full duplex selected */ +#define XMPHY_RESAB_ABLMIS 0x0010 /* Ability mismatch */ +#define XMPHY_RESAB_PAUSEMIS 0x0008 /* Pause mismatch */ + +#endif /* _DEV_MII_XMPHYREG_H_ */ |