summaryrefslogtreecommitdiffstats
path: root/sys/dev/mii/brgphy.c
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2003-05-03 19:06:50 +0000
committerps <ps@FreeBSD.org>2003-05-03 19:06:50 +0000
commitf6b6404d7f64bbdd5d2288c71cce10b084ac1090 (patch)
tree17617e195afebb5b466aea278f14db480648dab7 /sys/dev/mii/brgphy.c
parent19105c8312c841631a5eff3408f8a43f4958e9ba (diff)
downloadFreeBSD-src-f6b6404d7f64bbdd5d2288c71cce10b084ac1090.zip
FreeBSD-src-f6b6404d7f64bbdd5d2288c71cce10b084ac1090.tar.gz
- Move bge_phy_hack into the phy code and implement the various DSP
patch workarounds for each phy revision. Obtained from: NetBSD & Broadcom Linux driver - Disable AUTOPOLL when accessing the PHY as it may cause PCI errors. Obtained from: NetBSD - Check the UPDATED bit in the status block so the driver knows that the status block as indeed changed since the last access. Broadcom documentation states drivers should unset the UPDATED/CHANGED bits after reading them. - When changing media types, first loop the phy then set the media. Broadcom documentation and Linux drivers do this and I observed much better handling of link after this change. - Broadcom documentation states that for 1000BaseT operation, autonegotiation must be enabled. Fix hard coding of media so that the driver only advertises 1000BaseT as the supported media type and enable autonegotition. - Only set Master/Slave on the 5701. Obtained from Broadcom Linux driver.
Diffstat (limited to 'sys/dev/mii/brgphy.c')
-rw-r--r--sys/dev/mii/brgphy.c181
1 files changed, 161 insertions, 20 deletions
diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c
index 49c4601..7f42688 100644
--- a/sys/dev/mii/brgphy.c
+++ b/sys/dev/mii/brgphy.c
@@ -82,6 +82,12 @@ 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)
@@ -163,7 +169,8 @@ brgphy_attach(dev)
BMCR_LOOP|BMCR_S100);
#endif
- mii_phy_reset(sc);
+ brgphy_mii_model = MII_MODEL(ma->mii_id2);
+ brgphy_reset(sc);
sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
@@ -193,7 +200,7 @@ brgphy_service(sc, mii, cmd)
int cmd;
{
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
- int reg, speed;
+ int reg, speed, gig;
switch (cmd) {
case MII_POLLSTAT:
@@ -221,11 +228,7 @@ brgphy_service(sc, mii, cmd)
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);
+ brgphy_reset(sc); /* XXX hardware bug work-around */
switch (IFM_SUBTYPE(ife->ifm_media)) {
case IFM_AUTO:
@@ -247,15 +250,26 @@ brgphy_service(sc, mii, cmd)
case IFM_10_T:
speed = BRGPHY_S10;
setit:
+ brgphy_loop(sc);
if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
- PHY_WRITE(sc, BRGPHY_MII_BMCR,
- BRGPHY_BMCR_FDX|speed);
+ speed |= BRGPHY_BMCR_FDX;
+ gig = BRGPHY_1000CTL_AFD;
} else {
- PHY_WRITE(sc, BRGPHY_MII_BMCR, speed);
+ 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)
+ 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;
/*
@@ -268,10 +282,10 @@ setit:
*/
if ((mii->mii_ifp->if_flags & IFF_LINK0)) {
PHY_WRITE(sc, BRGPHY_MII_1000CTL,
- BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC);
+ gig|BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC);
} else {
PHY_WRITE(sc, BRGPHY_MII_1000CTL,
- BRGPHY_1000CTL_MSE);
+ gig|BRGPHY_1000CTL_MSE);
}
break;
#ifdef foo
@@ -320,7 +334,6 @@ setit:
return (0);
sc->mii_ticks = 0;
- mii_phy_reset(sc);
brgphy_mii_phy_auto(sc);
return (0);
}
@@ -402,12 +415,12 @@ brgphy_mii_phy_auto(mii)
{
int ktcr = 0;
- mii_phy_reset(mii);
- PHY_WRITE(mii, BRGPHY_MII_BMCR, 0);
- DELAY(1000);
- ktcr = PHY_READ(mii, BRGPHY_MII_1000CTL);
- PHY_WRITE(mii, BRGPHY_MII_1000CTL, ktcr |
- BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD);
+ 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,
@@ -418,3 +431,131 @@ brgphy_mii_phy_auto(mii)
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;
+
+ 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;
+ }
+
+ /* 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));
+}
OpenPOWER on IntegriCloud