diff options
-rw-r--r-- | sys/dev/mii/brgphy.c | 406 | ||||
-rw-r--r-- | sys/dev/mii/brgphyreg.h | 224 | ||||
-rw-r--r-- | sys/dev/mii/xmphy.c | 392 | ||||
-rw-r--r-- | sys/dev/mii/xmphyreg.h | 116 |
4 files changed, 1138 insertions, 0 deletions
diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c new file mode 100644 index 0000000..06a61d5 --- /dev/null +++ b/sys/dev/mii/brgphy.c @@ -0,0 +1,406 @@ +/* + * 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$ + */ + +/* + * Driver for the Broadcom BCR5400 1000baseTX PHY. Speed is always + * 1000mbps; all we need to negotiate here is full or half duplex. + */ + +#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 <machine/clock.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include <dev/mii/miidevs.h> + +#include <dev/mii/brgphyreg.h> + +#include "miibus_if.h" + +#if !defined(lint) +static const char rcsid[] = + "$FreeBSD$"; +#endif + +static int brgphy_probe __P((device_t)); +static int brgphy_attach __P((device_t)); +static int brgphy_detach __P((device_t)); + +static device_method_t brgphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, brgphy_probe), + DEVMETHOD(device_attach, brgphy_attach), + DEVMETHOD(device_detach, brgphy_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); + +int brgphy_service __P((struct mii_softc *, struct mii_data *, int)); +void brgphy_status __P((struct mii_softc *)); + +static int brgphy_mii_phy_auto __P((struct mii_softc *, int)); +extern void mii_phy_auto_timeout __P((void *)); + +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) + return(ENXIO); + + device_set_desc(dev, MII_STR_xxBROADCOM_BCM5400); + + return(0); +} + +static int brgphy_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 = 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 + + mii_phy_reset(sc); + + device_printf(dev, " "); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_TX, 0, sc->mii_inst), + BRGPHY_BMCR_FDX); + PRINT("1000baseTX"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_TX, 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_detach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_data *mii; + + sc = device_get_softc(dev); + mii = device_get_softc(device_get_parent(dev)); + sc->mii_dev = NULL; + LIST_REMOVE(sc, mii_list); + + return(0); +} +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; + + 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; + + PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, + BRGPHY_PHY_EXTCTL_HIGH_LA|BRGPHY_PHY_EXTCTL_EN_LTR); + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, + BRGPHY_AUXCTL_LONG_PKT|BRGPHY_AUXCTL_TX_TST); + PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); + + 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, 1); + break; + case IFM_1000_TX: + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + PHY_WRITE(sc, BRGPHY_MII_BMCR, + BRGPHY_BMCR_FDX|BRGPHY_BMCR_SPD1); + } else { + PHY_WRITE(sc, BRGPHY_MII_BMCR, + BRGPHY_BMCR_SPD1); + } + PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); + + /* + * 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, + BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC); + } else { + PHY_WRITE(sc, BRGPHY_MII_1000CTL, + BRGPHY_1000CTL_MSE); + } + 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); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->mii_ticks != 5) + return (0); + + sc->mii_ticks = 0; + + /* + * 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; + + mii_phy_reset(sc); + if (brgphy_mii_phy_auto(sc, 0) == EJUSTRETURN) + return(0); + break; + } + + /* Update the media status. */ + brgphy_status(sc); + + /* Callback if something changed. */ + if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) { + MIIBUS_STATCHG(sc->mii_dev); + sc->mii_active = mii->mii_media_active; + } + return (0); +} + +void +brgphy_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, 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; + } + + mii->mii_media_active |= IFM_1000_TX; + anlpar = PHY_READ(sc, BRGPHY_MII_AUXSTS); + if ((anlpar & BRGPHY_AUXSTS_AN_RES) == BRGPHY_RES_1000FD) + mii->mii_media_active |= IFM_FDX; + if ((anlpar & BRGPHY_AUXSTS_AN_RES) == BRGPHY_RES_1000HD) + mii->mii_media_active |= IFM_HDX; + return; + } + + mii->mii_media_active |= IFM_1000_TX; + if (bmcr & BRGPHY_BMCR_FDX) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + + return; +} + + +static int +brgphy_mii_phy_auto(mii, waitfor) + struct mii_softc *mii; + int waitfor; +{ + int bmsr, i; + + if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) { + PHY_WRITE(mii, BRGPHY_MII_1000CTL, + BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD); + PHY_WRITE(mii, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); + PHY_WRITE(mii, BRGPHY_MII_BMCR, + BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); + PHY_WRITE(mii, BRGPHY_MII_IMR, 0xFF00); + } + + if (waitfor) { + /* Wait 500ms for it to complete. */ + for (i = 0; i < 500; i++) { + if ((bmsr = PHY_READ(mii, BRGPHY_MII_BMSR)) & + BRGPHY_BMSR_ACOMP) + return (0); + DELAY(1000); +#if 0 + if ((bmsr & BMSR_ACOMP) == 0) + printf("%s: autonegotiation failed to complete\n", + mii->mii_dev.dv_xname); +#endif + } + + /* + * Don't need to worry about clearing MIIF_DOINGAUTO. + * If that's set, a timeout is pending, and it will + * clear the flag. + */ + return (EIO); + } + + /* + * Just let it finish asynchronously. This is for the benefit of + * the tick handler driving autonegotiation. Don't want 500ms + * delays all the time while the system is running! + */ + if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) { + mii->mii_flags |= MIIF_DOINGAUTO; + timeout(mii_phy_auto_timeout, mii, hz >> 1); + } + return (EJUSTRETURN); +} diff --git a/sys/dev/mii/brgphyreg.h b/sys/dev/mii/brgphyreg.h new file mode 100644 index 0000000..ce289cd --- /dev/null +++ b/sys/dev/mii/brgphyreg.h @@ -0,0 +1,224 @@ +/* + * 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 /* Asymetric 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 /* Asymetric 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_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_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/xmphy.c b/sys/dev/mii/xmphy.c new file mode 100644 index 0000000..bf6aa3e --- /dev/null +++ b/sys/dev/mii/xmphy.c @@ -0,0 +1,392 @@ +/* + * 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$ + */ + +/* + * 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/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.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 <dev/mii/miidevs.h> + +#include <dev/mii/xmphyreg.h> + +#include "miibus_if.h" + +#if !defined(lint) +static const char rcsid[] = + "$FreeBSD$"; +#endif + +static int xmphy_probe __P((device_t)); +static int xmphy_attach __P((device_t)); +static int xmphy_detach __P((device_t)); + +static device_method_t xmphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, xmphy_probe), + DEVMETHOD(device_attach, xmphy_attach), + DEVMETHOD(device_detach, xmphy_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); + +int xmphy_service __P((struct mii_softc *, struct mii_data *, int)); +void xmphy_status __P((struct mii_softc *)); + +static int xmphy_mii_phy_auto __P((struct mii_softc *, int)); +extern void mii_phy_auto_timeout __P((void *)); + +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) + return(ENXIO); + + device_set_desc(dev, MII_STR_XAQTI_XMACII); + + return(0); +} + +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_detach(dev) + device_t dev; +{ + struct mii_softc *sc; + struct mii_data *mii; + + sc = device_get_softc(dev); + mii = device_get_softc(device_get_parent(dev)); + sc->mii_dev = NULL; + LIST_REMOVE(sc, mii_list); + + return(0); +} +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: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, XMPHY_MII_BMCR) & XMPHY_BMCR_AUTOEN) + return (0); + (void) xmphy_mii_phy_auto(sc, 1); + 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); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->mii_ticks != 5) + return (0); + + sc->mii_ticks = 0; + + /* + * 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, XMPHY_MII_BMSR) | + PHY_READ(sc, XMPHY_MII_BMSR); + if (reg & XMPHY_BMSR_LINK) + break; + + mii_phy_reset(sc); + if (xmphy_mii_phy_auto(sc, 0) == EJUSTRETURN) + return(0); + break; + } + + /* Update the media status. */ + xmphy_status(sc); + + /* Callback if something changed. */ + if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) { + MIIBUS_STATCHG(sc->mii_dev); + sc->mii_active = mii->mii_media_active; + } + return (0); +} + +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, waitfor) + struct mii_softc *mii; + int waitfor; +{ + int bmsr, i; + + if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) { + PHY_WRITE(mii, XMPHY_MII_ANAR, + XMPHY_ANAR_FDX|XMPHY_ANAR_HDX); + PHY_WRITE(mii, XMPHY_MII_BMCR, + XMPHY_BMCR_AUTOEN | XMPHY_BMCR_STARTNEG); + } + + if (waitfor) { + /* Wait 500ms for it to complete. */ + for (i = 0; i < 500; i++) { + if ((bmsr = PHY_READ(mii, XMPHY_MII_BMSR)) & + XMPHY_BMSR_ACOMP) + return (0); + DELAY(1000); +#if 0 + if ((bmsr & BMSR_ACOMP) == 0) + printf("%s: autonegotiation failed to complete\n", + mii->mii_dev.dv_xname); +#endif + } + + /* + * Don't need to worry about clearing MIIF_DOINGAUTO. + * If that's set, a timeout is pending, and it will + * clear the flag. + */ + return (EIO); + } + + /* + * Just let it finish asynchronously. This is for the benefit of + * the tick handler driving autonegotiation. Don't want 500ms + * delays all the time while the system is running! + */ + if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) { + mii->mii_flags |= MIIF_DOINGAUTO; + timeout(mii_phy_auto_timeout, mii, hz >> 1); + } + return (EJUSTRETURN); +} diff --git a/sys/dev/mii/xmphyreg.h b/sys/dev/mii/xmphyreg.h new file mode 100644 index 0000000..1dff3a5 --- /dev/null +++ b/sys/dev/mii/xmphyreg.h @@ -0,0 +1,116 @@ +/* + * 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_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_FDX 0x0040 /* Select full duplex */ +#define XMPHY_ANAR_HDX 0x0020 /* Select half 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_FDX 0x0040 /* Select full duplex */ +#define XMPHY_ANLPAR_HDX 0x0020 /* Select half 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_ */ |