Add PHY drivers for the XMAC II's internal PHY and the Broadcom BCM5400
1000baseTX PHY. These will be used by the SysKonnect gigabit ethernet driver shortly.
This commit is contained in:
parent
22e1916c12
commit
421e265bf0
406
sys/dev/mii/brgphy.c
Normal file
406
sys/dev/mii/brgphy.c
Normal file
@ -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);
|
||||
}
|
224
sys/dev/mii/brgphyreg.h
Normal file
224
sys/dev/mii/brgphyreg.h
Normal file
@ -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_ */
|
392
sys/dev/mii/xmphy.c
Normal file
392
sys/dev/mii/xmphy.c
Normal file
@ -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);
|
||||
}
|
116
sys/dev/mii/xmphyreg.h
Normal file
116
sys/dev/mii/xmphyreg.h
Normal file
@ -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_ */
|
Loading…
Reference in New Issue
Block a user