Fix autonegotiation in tsec ethernet driver
Patch by Stefan Roese, 21 Sep 2005
diff --git a/drivers/tsec.c b/drivers/tsec.c
index 0c8b0de..ddca901 100644
--- a/drivers/tsec.c
+++ b/drivers/tsec.c
@@ -338,16 +338,35 @@
  * auto-negotiation */
 uint mii_parse_sr(uint mii_reg, struct tsec_private *priv)
 {
-	uint timeout = TSEC_TIMEOUT;
+	/*
+	 * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
+	 */
+	mii_reg = read_phy_reg(priv, MIIM_STATUS);
+	if ((mii_reg & PHY_BMSR_AUTN_ABLE) && !(mii_reg & PHY_BMSR_AUTN_COMP)) {
+		int i = 0;
 
-	if(mii_reg & MIIM_STATUS_LINK)
-		priv->link = 1;
-	else
-		priv->link = 0;
+		puts ("Waiting for PHY auto negotiation to complete");
+		while (!((mii_reg & PHY_BMSR_AUTN_COMP) && (mii_reg & MIIM_STATUS_LINK))) {
+			/*
+			 * Timeout reached ?
+			 */
+			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+				puts (" TIMEOUT !\n");
+				priv->link = 0;
+				break;
+			}
 
-	if(priv->link) {
-		while((!(mii_reg & MIIM_STATUS_AN_DONE)) && timeout--)
+			if ((i++ % 1000) == 0) {
+				putc ('.');
+			}
+			udelay (1000);	/* 1 ms */
 			mii_reg = read_phy_reg(priv, MIIM_STATUS);
+		}
+		puts (" done\n");
+		priv->link = 1;
+		udelay (500000);	/* another 500 ms (results in faster booting) */
+	} else {
+		priv->link = 1;
 	}
 
 	return 0;
@@ -360,6 +379,34 @@
 {
 	uint speed;
 
+	mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
+
+	if (!((mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE) &&
+	      (mii_reg & MIIM_88E1011_PHYSTAT_LINK))) {
+		int i = 0;
+
+		puts ("Waiting for PHY realtime link");
+		while (!((mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE) &&
+			 (mii_reg & MIIM_88E1011_PHYSTAT_LINK))) {
+			/*
+			 * Timeout reached ?
+			 */
+			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+				puts (" TIMEOUT !\n");
+				priv->link = 0;
+				break;
+			}
+
+			if ((i++ % 1000) == 0) {
+				putc ('.');
+			}
+			udelay (1000);	/* 1 ms */
+			mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
+		}
+		puts (" done\n");
+		udelay (500000);	/* another 500 ms (results in faster booting) */
+	}
+
 	if(mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
 		priv->duplexity = 1;
 	else
@@ -926,8 +973,7 @@
 		printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
 		return NULL;
 	} else {
-		printf("%s: PHY is %s (%x)\n", dev->name, theInfo->name,
-				phy_ID);
+		debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
 	}
 
 	return theInfo;
diff --git a/drivers/tsec.h b/drivers/tsec.h
index 15961d7..c26fcc0 100644
--- a/drivers/tsec.h
+++ b/drivers/tsec.h
@@ -40,6 +40,8 @@
 #define TSEC_TIMEOUT 1000
 #define TOUT_LOOP 	1000000
 
+#define PHY_AUTONEGOTIATE_TIMEOUT	5000 /* in ms */
+
 /* MAC register bits */
 #define MACCFG1_SOFT_RESET	0x80000000
 #define MACCFG1_RESET_RX_MC	0x00080000
@@ -77,6 +79,7 @@
 #define MIIM_CONTROL            0x00
 #define MIIM_CONTROL_RESET	0x00009140
 #define MIIM_CONTROL_INIT       0x00001140
+#define MIIM_CONTROL_RESTART    0x00001340
 #define MIIM_ANEN               0x00001000
 
 #define MIIM_CR                 0x00
@@ -86,6 +89,8 @@
 #define MIIM_STATUS		0x1
 #define MIIM_STATUS_AN_DONE 	0x00000020
 #define MIIM_STATUS_LINK	0x0004
+#define PHY_BMSR_AUTN_ABLE	0x0008
+#define PHY_BMSR_AUTN_COMP	0x0020
 
 #define MIIM_PHYIR1		0x2
 #define MIIM_PHYIR2		0x3