net: Multiple updates/enhancements to designware.c

This patch adds the following changes to designware ethernet driver
found on the ST SPEAr SoC:

- Don't init MAC & PHY upon startup. This causes a delay, waiting for
  the auto negotiation to complete. And we don't want this delay to
  always happen. Especially not on platforms where ethernet is not
  used at all (e.g. booting via flash).
  Instead postpone the MAC / PHY configuration to the stage, where
  ethernet is first used.
- Add possibility for board specific PHY init code. This is needed
  for example on the X600 board, where the Vitesse PHY needs to be
  configured for GMII mode.
  This board specific PHY init is done via the function
  designware_board_phy_init(). And this driver now adds a weak default
  which can be overridden by board code.
- Use common functions miiphy_speed() & miiphy_duplex() to read
  link status from PHY.
- Print status and progress of auto negotiation.
- Print link status (speed, dupex) upon first usage.

Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Amit Virdi <amit.virdi@st.com>
Cc: Vipin Kumar <vipin.kumar@st.com>
Cc: Joe Hershberger <joe.hershberger@gmail.com>
Acked-by: Joe Hershberger <joe.hershberger@gmail.com>
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 8f22e00..326d550 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -28,6 +28,7 @@
 #include <common.h>
 #include <miiphy.h>
 #include <malloc.h>
+#include <linux/compiler.h>
 #include <linux/err.h>
 #include <asm/io.h>
 #include "designware.h"
@@ -153,6 +154,13 @@
 	if (priv->phy_configured != 1)
 		configure_phy(dev);
 
+	/* Print link status only once */
+	if (!priv->link_printed) {
+		printf("ENET Speed is %d Mbps - %s duplex connection\n",
+		       priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
+		priv->link_printed = 1;
+	}
+
 	/* Reset ethernet hardware */
 	if (mac_reset(dev) < 0)
 		return -1;
@@ -168,17 +176,17 @@
 
 	conf = FRAMEBURSTENABLE | DISABLERXOWN;
 
-	if (priv->speed != SPEED_1000M)
+	if (priv->speed != 1000)
 		conf |= MII_PORTSELECT;
 
 	if ((priv->interface != PHY_INTERFACE_MODE_MII) &&
 		(priv->interface != PHY_INTERFACE_MODE_GMII)) {
 
-		if (priv->speed == SPEED_100M)
+		if (priv->speed == 100)
 			conf |= FES_100;
 	}
 
-	if (priv->duplex == FULL_DUPLEX)
+	if (priv->duplex == FULL)
 		conf |= FULLDPLXMODE;
 
 	writel(conf, &mac_p->conf);
@@ -396,6 +404,16 @@
 	return 0;
 }
 
+/*
+ * Add weak default function for board specific PHY configuration
+ */
+int __weak designware_board_phy_init(struct eth_device *dev, int phy_addr,
+		int (*mii_write)(struct eth_device *, u8, u8, u16),
+		int dw_reset_phy(struct eth_device *))
+{
+	return 0;
+}
+
 static int configure_phy(struct eth_device *dev)
 {
 	struct dw_eth_dev *priv = dev->priv;
@@ -405,9 +423,6 @@
 	u16 bmsr;
 	u32 timeout;
 	ulong start;
-	u16 anlpar, btsr;
-#else
-	u16 ctrl;
 #endif
 
 #if defined(CONFIG_DW_SEARCH_PHY)
@@ -419,6 +434,16 @@
 #else
 	phy_addr = priv->address;
 #endif
+
+	/*
+	 * Some boards need board specific PHY initialization. This is
+	 * after the main driver init code but before the auto negotiation
+	 * is run.
+	 */
+	if (designware_board_phy_init(dev, phy_addr,
+				      eth_mdio_write, dw_reset_phy) < 0)
+		return -1;
+
 	if (dw_reset_phy(dev) < 0)
 		return -1;
 
@@ -444,72 +469,32 @@
 #if defined(CONFIG_DW_AUTONEG)
 	timeout = CONFIG_AUTONEG_TIMEOUT;
 	start = get_timer(0);
-
+	puts("Waiting for PHY auto negotiation to complete");
 	while (get_timer(start) < timeout) {
 		eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr);
-		if (bmsr & BMSR_ANEGCOMPLETE)
+		if (bmsr & BMSR_ANEGCOMPLETE) {
+			priv->phy_configured = 1;
 			break;
+		}
 
-		/* Try again after 10usec */
-		udelay(10);
+		/* Print dot all 1s to show progress */
+		if ((get_timer(start) % 1000) == 0)
+			putc('.');
+
+		/* Try again after 1msec */
+		udelay(1000);
 	};
 
-	eth_mdio_read(dev, phy_addr, MII_LPA, &anlpar);
-	eth_mdio_read(dev, phy_addr, MII_STAT1000, &btsr);
-
-	if (bmsr & BMSR_ANEGCOMPLETE) {
-		if (btsr & PHY_1000BTSR_1000FD) {
-			priv->speed = SPEED_1000M;
-			bmcr |= BMCR_SPEED1000;
-			priv->duplex = FULL_DUPLEX;
-			bmcr |= BMCR_FULLDPLX;
-		} else if (btsr & PHY_1000BTSR_1000HD) {
-			priv->speed = SPEED_1000M;
-			bmcr |= BMCR_SPEED1000;
-			priv->duplex = HALF_DUPLEX;
-			bmcr &= ~BMCR_FULLDPLX;
-		} else if (anlpar & LPA_100FULL) {
-			priv->speed = SPEED_100M;
-			bmcr |= BMCR_SPEED100;
-			priv->duplex = FULL_DUPLEX;
-			bmcr |= BMCR_FULLDPLX;
-		} else if (anlpar & LPA_100HALF) {
-			priv->speed = SPEED_100M;
-			bmcr |= BMCR_SPEED100;
-			priv->duplex = HALF_DUPLEX;
-			bmcr &= ~BMCR_FULLDPLX;
-		} else if (anlpar & LPA_10FULL) {
-			priv->speed = SPEED_10M;
-			bmcr &= ~BMCR_SPEED100;
-			priv->duplex = FULL_DUPLEX;
-			bmcr |= BMCR_FULLDPLX;
-		} else {
-				priv->speed = SPEED_10M;
-				bmcr &= ~BMCR_SPEED100;
-				priv->duplex = HALF_DUPLEX;
-				bmcr &= ~BMCR_FULLDPLX;
-		}
-		if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0)
-			return -1;
-	} else
-		return -1;
+	if (!(bmsr & BMSR_ANEGCOMPLETE))
+		puts(" TIMEOUT!\n");
+	else
+		puts(" done\n");
 #else
-	if (eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl) < 0)
-		return -1;
-
-	if (ctrl & BMCR_FULLDPLX)
-		priv->duplex = FULL_DUPLEX;
-	else
-		priv->duplex = HALF_DUPLEX;
-
-	if (ctrl & BMCR_SPEED1000)
-		priv->speed = SPEED_1000M;
-	else if (ctrl & BMCR_SPEED100)
-		priv->speed = SPEED_100M;
-	else
-		priv->speed = SPEED_10M;
-#endif
 	priv->phy_configured = 1;
+#endif
+
+	priv->speed = miiphy_speed(dev->name, phy_addr);
+	priv->duplex = miiphy_duplex(dev->name, phy_addr);
 
 	return 0;
 }
@@ -574,11 +559,6 @@
 	priv->phy_configured = 0;
 	priv->interface = interface;
 
-	if (mac_reset(dev) < 0)
-		return -1;
-
-	configure_phy(dev);
-
 	dev->init = dw_eth_init;
 	dev->send = dw_eth_send;
 	dev->recv = dw_eth_recv;
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index 40020bf..d668f8f 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -240,6 +240,7 @@
 	u32 tx_currdescnum;
 	u32 rx_currdescnum;
 	u32 phy_configured;
+	int link_printed;
 	u32 padding;
 
 	struct dmamacdescr tx_mac_descrtable[CONFIG_TX_DESCR_NUM];
diff --git a/include/configs/spear-common.h b/include/configs/spear-common.h
index 36c2a8b..a6d1cfb 100644
--- a/include/configs/spear-common.h
+++ b/include/configs/spear-common.h
@@ -38,6 +38,7 @@
 #define CONFIG_NET_MULTI
 #define CONFIG_PHY_RESET_DELAY			10000		/* in usec */
 #define CONFIG_DW_AUTONEG
+#define CONFIG_PHY_GIGE			/* Include GbE speed/duplex detection */
 
 /* USBD driver configuration */
 #if defined(CONFIG_SPEAR_USBTTY)