Move the BCM5401 DSP patch out of the bge driver and into

the brgphy driver; all users of the BCM5400 and BCM5401 need
the DSP patch and the sledgehammer-reset-at-media-set-time.

Also add a DSP patch for the BCM5411 gleaned from Apple's
GMAC driver for Darwin.

Tested with a 3Com 3c996-T (BCM5700 + BCM5401).
This commit is contained in:
thorpej 2002-07-13 01:23:27 +00:00
parent f216ec52a0
commit 7d85789f0a
2 changed files with 116 additions and 56 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: brgphy.c,v 1.9 2002/07/12 04:00:10 thorpej Exp $ */
/* $NetBSD: brgphy.c,v 1.10 2002/07/13 01:23:27 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@ -74,7 +74,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: brgphy.c,v 1.9 2002/07/12 04:00:10 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: brgphy.c,v 1.10 2002/07/13 01:23:27 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -103,10 +103,21 @@ struct cfattach brgphy_ca = {
int brgphy_service(struct mii_softc *, struct mii_data *, int);
void brgphy_status(struct mii_softc *);
void brgphy_5401_reset(struct mii_softc *);
void brgphy_5411_reset(struct mii_softc *);
const struct mii_phy_funcs brgphy_funcs = {
brgphy_service, brgphy_status, mii_phy_reset,
};
const struct mii_phy_funcs brgphy_5401_funcs = {
brgphy_service, brgphy_status, brgphy_5401_reset,
};
const struct mii_phy_funcs brgphy_5411_funcs = {
brgphy_service, brgphy_status, brgphy_5411_reset,
};
const struct mii_phydesc brgphys[] = {
{ MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5400,
MII_STR_BROADCOM_BCM5400 },
@ -127,6 +138,9 @@ const struct mii_phydesc brgphys[] = {
NULL },
};
static void bcm5401_load_dspcode(struct mii_softc *);
static void bcm5411_load_dspcode(struct mii_softc *);
int
brgphymatch(struct device *parent, struct cfdata *match, void *aux)
{
@ -151,11 +165,35 @@ brgphyattach(struct device *parent, struct device *self, void *aux)
sc->mii_inst = mii->mii_instance;
sc->mii_phy = ma->mii_phyno;
sc->mii_funcs = &brgphy_funcs;
sc->mii_pdata = mii;
sc->mii_flags = ma->mii_flags;
sc->mii_anegticks = 5;
switch (MII_MODEL(ma->mii_id2)) {
case MII_MODEL_BROADCOM_BCM5400:
sc->mii_funcs = &brgphy_5401_funcs;
printf("%s: using BCM5401 DSP patch\n", sc->mii_dev.dv_xname);
break;
case MII_MODEL_BROADCOM_BCM5401:
if (MII_REV(ma->mii_id2) == 1 || MII_REV(ma->mii_id2) == 3) {
sc->mii_funcs = &brgphy_5401_funcs;
printf("%s: using BCM5401 DSP patch\n",
sc->mii_dev.dv_xname);
} else
sc->mii_funcs = &brgphy_funcs;
break;
case MII_MODEL_BROADCOM_BCM5411:
sc->mii_funcs = &brgphy_5411_funcs;
printf("%s: using BCM5411 DSP patch\n", sc->mii_dev.dv_xname);
break;
default:
sc->mii_funcs = &brgphy_funcs;
break;
}
PHY_RESET(sc);
sc->mii_capabilities =
@ -204,6 +242,7 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
break;
mii_phy_reset(sc); /* XXX hardware bug work-around */
mii_phy_setmedia(sc);
break;
@ -226,8 +265,19 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
/* Update the media status. */
mii_phy_status(sc);
/* Callback if something changed. */
mii_phy_update(sc, cmd);
/*
* 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);
if (sc->mii_funcs == &brgphy_5401_funcs)
bcm5401_load_dspcode(sc);
else if (sc->mii_funcs == &brgphy_5411_funcs)
bcm5411_load_dspcode(sc);
}
return (0);
}
@ -309,3 +359,63 @@ brgphy_status(struct mii_softc *sc)
} else
mii->mii_media_active = ife->ifm_media;
}
void
brgphy_5401_reset(struct mii_softc *sc)
{
mii_phy_reset(sc);
bcm5401_load_dspcode(sc);
}
void
brgphy_5411_reset(struct mii_softc *sc)
{
mii_phy_reset(sc);
bcm5411_load_dspcode(sc);
}
static void
bcm5401_load_dspcode(struct mii_softc *sc)
{
static const struct {
int reg;
uint16_t val;
} dspcode[] = {
{ BRGPHY_MII_AUXCTL, 0x4c20 },
{ 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);
}
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);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_bge.c,v 1.14 2002/07/12 22:29:14 enami Exp $ */
/* $NetBSD: if_bge.c,v 1.15 2002/07/13 01:23:27 thorpej Exp $ */
/*
* Copyright (c) 2001 Wind River Systems
@ -181,7 +181,6 @@ void bge_miibus_writereg(struct device *, int, int, int);
void bge_miibus_statchg(struct device *);
void bge_reset(struct bge_softc *);
void bge_phy_hack(struct bge_softc *);
void bge_dump_status(struct bge_softc *);
void bge_dump_rxbd(struct bge_rx_bd *);
@ -489,8 +488,6 @@ bge_miibus_statchg(dev)
} else {
BGE_SETBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX);
}
bge_phy_hack(sc);
}
/*
@ -2498,46 +2495,6 @@ bge_start(ifp)
ifp->if_timer = 5;
}
/*
* If we have a BCM5400 or BCM5401 PHY, we need to properly
* program its internal DSP. Failing to do this can result in
* massive packet loss at 1Gb speeds.
*/
void
bge_phy_hack(sc)
struct bge_softc *sc;
{
struct bge_bcom_hack bhack[] = {
{ BRGPHY_MII_AUXCTL, 0x4C20 },
{ 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 } };
u_int16_t vid, did;
int i;
vid = bge_miibus_readreg(&sc->bge_dev, 1, MII_PHYIDR1);
did = bge_miibus_readreg(&sc->bge_dev, 1, MII_PHYIDR2);
if (MII_OUI(vid, did) == MII_OUI_BROADCOM &&
(MII_MODEL(did) == MII_MODEL_BROADCOM_BCM5400 ||
MII_MODEL(did) == MII_MODEL_BROADCOM_BCM5401)) {
i = 0;
while (bhack[i].reg) {
bge_miibus_writereg(&sc->bge_dev, 1, bhack[i].reg,
bhack[i].val);
i++;
}
}
}
int
bge_init(ifp)
struct ifnet *ifp;
@ -2661,13 +2618,6 @@ bge_ifmedia_upd(ifp)
}
sc->bge_link = 0;
if (mii->mii_instance) {
struct mii_softc *miisc;
for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
miisc = LIST_NEXT(miisc, mii_list))
mii_phy_reset(miisc);
}
bge_phy_hack(sc);
mii_mediachg(mii);
return(0);