Subject: brgphy patch
To: None <current-users@netbsd.org>
From: SAITOH Masanobu <masanobu@iij.ad.jp>
List: current-users
Date: 02/23/2007 18:13:37
 If you have any problem on brgphy, please test the following patch.
At least, it fixes the problem "ifconfig bge0 media auto" negotiates to
100Mbps on 1000BaseT HUB.


Index: brgphy.c
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/brgphy.c,v
retrieving revision 1.31
diff -u -r1.31 brgphy.c
--- brgphy.c	26 Nov 2006 16:31:48 -0000	1.31
+++ brgphy.c	23 Feb 2007 09:10:08 -0000
@@ -100,6 +100,8 @@
 
 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_loop(struct mii_softc *);
 
 static void	brgphy_5401_reset(struct mii_softc *);
 static void	brgphy_5411_reset(struct mii_softc *);
@@ -210,6 +212,7 @@
 
 	sc->mii_inst = mii->mii_instance;
 	sc->mii_phy = ma->mii_phyno;
+	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
 	sc->mii_pdata = mii;
 	sc->mii_flags = ma->mii_flags;
 	sc->mii_anegticks = MII_ANEGTICKS;
@@ -286,7 +289,7 @@
 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
 {
 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
-	int reg;
+	int reg, speed, gig;
 
 	switch (cmd) {
 	case MII_POLLSTAT:
@@ -314,9 +317,50 @@
 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
 			break;
 
-		if (sc->mii_funcs != &brgphy_5705_funcs)
-			mii_phy_reset(sc);    /* XXX hardware bug work-around */
-		mii_phy_setmedia(sc);
+		PHY_RESET(sc); /* XXX hardware bug work-around */
+
+		switch (IFM_SUBTYPE(ife->ifm_media)) {
+		case IFM_AUTO:
+			(void) brgphy_mii_phy_auto(sc);
+			break;
+		case IFM_1000_T:
+			speed = BMCR_S1000;
+			goto setit;
+		case IFM_100_TX:
+			speed = BMCR_S100;
+			goto setit;
+		case IFM_10_T:
+			speed = BMCR_S10;
+setit:
+			brgphy_loop(sc);
+			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
+				speed |= BMCR_FDX;
+				gig = GTCR_ADV_1000TFDX;
+			} else {
+				gig = GTCR_ADV_1000THDX;
+			}
+
+			PHY_WRITE(sc, MII_100T2CR, 0);
+			PHY_WRITE(sc, MII_BMCR, speed);
+			PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
+
+			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
+				break;
+
+			PHY_WRITE(sc, MII_100T2CR, gig);
+			PHY_WRITE(sc, MII_BMCR,
+			    speed|BMCR_AUTOEN|BMCR_STARTNEG);
+
+			if (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701)
+ 				break;
+
+			if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
+				gig |= GTCR_MAN_MS | GTCR_ADV_MS;
+			PHY_WRITE(sc, MII_100T2CR, gig);
+			break;
+		default:
+			return (EINVAL);
+		}
 		break;
 
 	case MII_TICK:
@@ -339,8 +383,8 @@
 	mii_phy_status(sc);
 
 	/*
-	 * Callback if something changed.  Note that we need to poke
-	 * the DSP on the Broadcom PHYs if the media changes.
+	 * 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 ||
@@ -435,6 +479,47 @@
 		mii->mii_media_active = ife->ifm_media;
 }
 
+int
+brgphy_mii_phy_auto(struct mii_softc *sc)
+{
+	int anar, ktcr = 0;
+
+	brgphy_loop(sc);
+	PHY_RESET(sc);
+	ktcr = GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX;
+	if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701)
+		ktcr |= GTCR_MAN_MS|GTCR_ADV_MS;
+	PHY_WRITE(sc, MII_100T2CR, ktcr);
+	ktcr = PHY_READ(sc, MII_100T2CR);
+	DELAY(1000);
+	anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
+	if (sc->mii_flags & MIIF_DOPAUSE)
+		anar |= ANAR_FC| ANAR_X_PAUSE_ASYM;
+
+	PHY_WRITE(sc, MII_ANAR, anar);
+	DELAY(1000);
+	PHY_WRITE(sc, MII_BMCR,
+	    BMCR_AUTOEN | BMCR_STARTNEG);
+	PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
+
+	return (EJUSTRETURN);
+}
+
+void
+brgphy_loop(struct mii_softc *sc)
+{
+	u_int32_t bmsr;
+	int i;
+
+	PHY_WRITE(sc, MII_BMCR, BMCR_LOOP);
+ 	for (i = 0; i < 15000; i++) {
+		bmsr = PHY_READ(sc, MII_BMSR);
+		if (!(bmsr & BMSR_LINK))
+			break;
+		DELAY(10);
+	}
+}
+
 static void
 brgphy_5401_reset(struct mii_softc *sc)
 {

----------------------------------------------------------
		SAITOH Masanobu (masanobu@iij.ad.jp
				  msaitoh@netbsd.org)