浏览代码

Merge branch 'master' of git://www.denx.de/git/u-boot-net

Wolfgang Denk 17 年之前
父节点
当前提交
2468592d79
共有 10 个文件被更改,包括 273 次插入122 次删除
  1. 4 0
      README
  2. 17 0
      board/bf537-stamp/bf537-stamp.c
  3. 0 39
      board/bf537-stamp/ether_bf537.h
  4. 1 1
      common/cmd_net.c
  5. 12 11
      drivers/net/rtl8139.c
  6. 97 20
      drivers/net/tsec.c
  7. 8 0
      drivers/net/tsec.h
  8. 85 27
      drivers/qe/uec.c
  9. 37 24
      drivers/qe/uec_phy.c
  10. 12 0
      net/eth.c

+ 4 - 0
README

@@ -2699,6 +2699,10 @@ Some configuration options can be set using Environment Variables:
 		  => setenv ethact SCC ETHERNET
 		  => setenv ethact SCC ETHERNET
 		  => ping 10.0.0.1 # traffic sent on SCC ETHERNET
 		  => ping 10.0.0.1 # traffic sent on SCC ETHERNET
 
 
+  ethrotate	- When set to "no" U-Boot does not go through all
+		  available network interfaces.
+		  It just stays at the currently selected interface.
+
    netretry	- When set to "no" each network operation will
    netretry	- When set to "no" each network operation will
 		  either succeed or fail without retrying.
 		  either succeed or fail without retrying.
 		  When set to "once" the network operation will
 		  When set to "once" the network operation will

+ 17 - 0
board/bf537-stamp/bf537-stamp.c

@@ -30,8 +30,25 @@
 #include <command.h>
 #include <command.h>
 #include <asm/blackfin.h>
 #include <asm/blackfin.h>
 #include <asm/io.h>
 #include <asm/io.h>
+#include <net.h>
 #include "ether_bf537.h"
 #include "ether_bf537.h"
 
 
+/**
+ * is_valid_ether_addr - Determine if the given Ethernet address is valid
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
+ * a multicast address, and is not FF:FF:FF:FF:FF:FF.
+ *
+ * Return true if the address is valid.
+ */
+static inline int is_valid_ether_addr(const u8 * addr)
+{
+	/* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
+	 * explicitly check for it here. */
+	return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
+}
+
 DECLARE_GLOBAL_DATA_PTR;
 DECLARE_GLOBAL_DATA_PTR;
 
 
 #define POST_WORD_ADDR 0xFF903FFC
 #define POST_WORD_ADDR 0xFF903FFC

+ 0 - 39
board/bf537-stamp/ether_bf537.h

@@ -69,42 +69,3 @@ void SoftResetPHY(void);
 void DumpPHYRegs(void);
 void DumpPHYRegs(void);
 
 
 int SetupSystemRegs(int *opmode);
 int SetupSystemRegs(int *opmode);
-
-/**
- * is_zero_ether_addr - Determine if give Ethernet address is all zeros.
- * @addr: Pointer to a six-byte array containing the Ethernet address
- *
- * Return true if the address is all zeroes.
- */
-static inline int is_zero_ether_addr(const u8 * addr)
-{
-	return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
-}
-
-/**
- * is_multicast_ether_addr - Determine if the Ethernet address is a multicast.
- * @addr: Pointer to a six-byte array containing the Ethernet address
- *
- * Return true if the address is a multicast address.
- * By definition the broadcast address is also a multicast address.
- */
-static inline int is_multicast_ether_addr(const u8 * addr)
-{
-	return (0x01 & addr[0]);
-}
-
-/**
- * is_valid_ether_addr - Determine if the given Ethernet address is valid
- * @addr: Pointer to a six-byte array containing the Ethernet address
- *
- * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
- * a multicast address, and is not FF:FF:FF:FF:FF:FF.
- *
- * Return true if the address is valid.
- */
-static inline int is_valid_ether_addr(const u8 * addr)
-{
-	/* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
-	 * explicitly check for it here. */
-	return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
-}

+ 1 - 1
common/cmd_net.c

@@ -87,7 +87,7 @@ int do_nfs (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 U_BOOT_CMD(
 U_BOOT_CMD(
 	nfs,	3,	1,	do_nfs,
 	nfs,	3,	1,	do_nfs,
 	"nfs\t- boot image via network using NFS protocol\n",
 	"nfs\t- boot image via network using NFS protocol\n",
-	"[loadAddress] [host ip addr:bootfilename]\n"
+	"[loadAddress] [[hostIPaddr:]bootfilename]\n"
 );
 );
 #endif
 #endif
 
 

+ 12 - 11
drivers/net/rtl8139.c

@@ -80,10 +80,7 @@
 #if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
 #if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
 	defined(CONFIG_RTL8139)
 	defined(CONFIG_RTL8139)
 
 
-#define TICKS_PER_SEC	CFG_HZ
-#define TICKS_PER_MS	(TICKS_PER_SEC/1000)
-
-#define RTL_TIMEOUT	(1*TICKS_PER_SEC)
+#define RTL_TIMEOUT	100000
 
 
 #define ETH_FRAME_LEN		1514
 #define ETH_FRAME_LEN		1514
 #define ETH_ALEN		6
 #define ETH_ALEN		6
@@ -392,6 +389,7 @@ static void rtl_reset(struct eth_device *dev)
 #ifdef	DEBUG_RX
 #ifdef	DEBUG_RX
 	printf("rx ring address is %X\n",(unsigned long)rx_ring);
 	printf("rx ring address is %X\n",(unsigned long)rx_ring);
 #endif
 #endif
+	flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
 	outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf);
 	outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf);
 
 
 	/* If we add multicast support, the MAR0 register would have to be
 	/* If we add multicast support, the MAR0 register would have to be
@@ -414,9 +412,10 @@ static void rtl_reset(struct eth_device *dev)
 
 
 static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length)
 static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length)
 {
 {
-	unsigned int status, to;
+	unsigned int status;
 	unsigned long txstatus;
 	unsigned long txstatus;
 	unsigned int len = length;
 	unsigned int len = length;
+	int i = 0;
 
 
 	ioaddr = dev->iobase;
 	ioaddr = dev->iobase;
 
 
@@ -432,12 +431,11 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt
 		tx_buffer[len++] = '\0';
 		tx_buffer[len++] = '\0';
 	}
 	}
 
 
+	flush_cache((unsigned long)tx_buffer, length);
 	outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4);
 	outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4);
 	outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,
 	outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,
 		ioaddr + TxStatus0 + cur_tx*4);
 		ioaddr + TxStatus0 + cur_tx*4);
 
 
-	to = currticks() + RTL_TIMEOUT;
-
 	do {
 	do {
 		status = inw(ioaddr + IntrStatus);
 		status = inw(ioaddr + IntrStatus);
 		/* Only acknlowledge interrupt sources we can properly handle
 		/* Only acknlowledge interrupt sources we can properly handle
@@ -445,7 +443,8 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt
 		 * rtl_poll() function.	 */
 		 * rtl_poll() function.	 */
 		outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus);
 		outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus);
 		if ((status & (TxOK | TxErr | PCIErr)) != 0) break;
 		if ((status & (TxOK | TxErr | PCIErr)) != 0) break;
-	} while (currticks() < to);
+		udelay(10);
+	} while (i++ < RTL_TIMEOUT);
 
 
 	txstatus = inl(ioaddr + TxStatus0 + cur_tx*4);
 	txstatus = inl(ioaddr + TxStatus0 + cur_tx*4);
 
 
@@ -458,8 +457,8 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt
 		return length;
 		return length;
 	} else {
 	} else {
 #ifdef	DEBUG_TX
 #ifdef	DEBUG_TX
-		printf("tx timeout/error (%d ticks), status %hX txstatus %X\n",
-			currticks()-to, status, txstatus);
+		printf("tx timeout/error (%d usecs), status %hX txstatus %X\n",
+		       10*i, status, txstatus);
 #endif
 #endif
 		rtl_reset(dev);
 		rtl_reset(dev);
 
 
@@ -489,7 +488,8 @@ static int rtl_poll(struct eth_device *dev)
 #endif
 #endif
 
 
 	ring_offs = cur_rx % RX_BUF_LEN;
 	ring_offs = cur_rx % RX_BUF_LEN;
-	rx_status = *(unsigned int*)KSEG1ADDR((rx_ring + ring_offs));
+	/* ring_offs is guaranteed being 4-byte aligned */
+	rx_status = le32_to_cpu(*(unsigned int *)(rx_ring + ring_offs));
 	rx_size = rx_status >> 16;
 	rx_size = rx_status >> 16;
 	rx_status &= 0xffff;
 	rx_status &= 0xffff;
 
 
@@ -519,6 +519,7 @@ static int rtl_poll(struct eth_device *dev)
 		printf("rx packet %d bytes", rx_size-4);
 		printf("rx packet %d bytes", rx_size-4);
 #endif
 #endif
 	}
 	}
+	flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
 
 
 	cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
 	cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
 	outw(cur_rx - 16, ioaddr + RxBufPtr);
 	outw(cur_rx - 16, ioaddr + RxBufPtr);

+ 97 - 20
drivers/net/tsec.c

@@ -241,10 +241,9 @@ int tsec_init(struct eth_device *dev, bd_t * bd)
  * It will wait for the write to be done (or for a timeout to
  * It will wait for the write to be done (or for a timeout to
  * expire) before exiting
  * expire) before exiting
  */
  */
-void write_phy_reg(struct tsec_private *priv, uint regnum, uint value)
+void write_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum, uint value)
 {
 {
 	volatile tsec_t *regbase = priv->phyregs;
 	volatile tsec_t *regbase = priv->phyregs;
-	uint phyid = priv->phyaddr;
 	int timeout = 1000000;
 	int timeout = 1000000;
 
 
 	regbase->miimadd = (phyid << 8) | regnum;
 	regbase->miimadd = (phyid << 8) | regnum;
@@ -255,17 +254,19 @@ void write_phy_reg(struct tsec_private *priv, uint regnum, uint value)
 	while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
 	while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
 }
 }
 
 
+/* #define to provide old write_phy_reg functionality without duplicating code */
+#define write_phy_reg(priv, regnum, value) write_any_phy_reg(priv,priv->phyaddr,regnum,value)
+
 /* Reads register regnum on the device's PHY through the
 /* Reads register regnum on the device's PHY through the
  * registers specified in priv.	 It lowers and raises the read
  * registers specified in priv.	 It lowers and raises the read
  * command, and waits for the data to become valid (miimind
  * command, and waits for the data to become valid (miimind
  * notvalid bit cleared), and the bus to cease activity (miimind
  * notvalid bit cleared), and the bus to cease activity (miimind
  * busy bit cleared), and then returns the value
  * busy bit cleared), and then returns the value
  */
  */
-uint read_phy_reg(struct tsec_private *priv, uint regnum)
+uint read_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum)
 {
 {
 	uint value;
 	uint value;
 	volatile tsec_t *regbase = priv->phyregs;
 	volatile tsec_t *regbase = priv->phyregs;
-	uint phyid = priv->phyaddr;
 
 
 	/* Put the address of the phy, and the register
 	/* Put the address of the phy, and the register
 	 * number into MIIMADD */
 	 * number into MIIMADD */
@@ -288,6 +289,9 @@ uint read_phy_reg(struct tsec_private *priv, uint regnum)
 	return value;
 	return value;
 }
 }
 
 
+/* #define to provide old read_phy_reg functionality without duplicating code */
+#define read_phy_reg(priv,regnum) read_any_phy_reg(priv,priv->phyaddr,regnum)
+
 /* Discover which PHY is attached to the device, and configure it
 /* Discover which PHY is attached to the device, and configure it
  * properly.  If the PHY is not recognized, then return 0
  * properly.  If the PHY is not recognized, then return 0
  * (failure).  Otherwise, return 1
  * (failure).  Otherwise, return 1
@@ -571,6 +575,63 @@ uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv)
 	return 0;
 	return 0;
 }
 }
 
 
+/* Parse the RTL8211B's status register for speed and duplex
+ * information
+ */
+uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv)
+{
+	uint speed;
+
+	mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
+	if ((mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) &&
+		!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
+		int i = 0;
+
+		puts("Waiting for PHY realtime link");
+		while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
+			/* 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_RTL8211B_PHY_STATUS);
+		}
+		puts(" done\n");
+		udelay(500000);	/* another 500 ms (results in faster booting) */
+	} else {
+		if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK)
+			priv->link = 1;
+		else
+			priv->link = 0;
+	}
+
+	if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX)
+		priv->duplexity = 1;
+	else
+		priv->duplexity = 0;
+
+	speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED);
+
+	switch (speed) {
+	case MIIM_RTL8211B_PHYSTAT_GBIT:
+		priv->speed = 1000;
+		break;
+	case MIIM_RTL8211B_PHYSTAT_100:
+		priv->speed = 100;
+		break;
+	default:
+		priv->speed = 10;
+	}
+
+	return 0;
+}
+
 /* Parse the cis8201's status register for speed and duplex
 /* Parse the cis8201's status register for speed and duplex
  * information
  * information
  */
  */
@@ -1361,6 +1422,33 @@ struct phy_info phy_info_dp83865 = {
 			   },
 			   },
 };
 };
 
 
+struct phy_info phy_info_rtl8211b = {
+	0x001cc91,
+	"RealTek RTL8211B",
+	4,
+	(struct phy_cmd[]){	/* config */
+		/* Reset and configure the PHY */
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+		{miim_end,}
+	},
+	(struct phy_cmd[]){	/* startup */
+		/* Status is read once to clear old link state */
+		{MIIM_STATUS, miim_read, NULL},
+		/* Auto-negotiate */
+		{MIIM_STATUS, miim_read, &mii_parse_sr},
+		/* Read the status */
+		{MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr},
+		{miim_end,}
+	},
+	(struct phy_cmd[]){	/* shutdown */
+		{miim_end,}
+	},
+};
+
 struct phy_info *phy_info[] = {
 struct phy_info *phy_info[] = {
 	&phy_info_cis8204,
 	&phy_info_cis8204,
 	&phy_info_cis8201,
 	&phy_info_cis8201,
@@ -1374,6 +1462,7 @@ struct phy_info *phy_info[] = {
 	&phy_info_lxt971,
 	&phy_info_lxt971,
 	&phy_info_VSC8244,
 	&phy_info_VSC8244,
 	&phy_info_dp83865,
 	&phy_info_dp83865,
+	&phy_info_rtl8211b,
 	&phy_info_generic,
 	&phy_info_generic,
 	NULL
 	NULL
 };
 };
@@ -1497,18 +1586,6 @@ static void relocate_cmds(void)
 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
 	&& !defined(BITBANGMII)
 	&& !defined(BITBANGMII)
 
 
-struct tsec_private *get_priv_for_phy(unsigned char phyaddr)
-{
-	int i;
-
-	for (i = 0; i < MAXCONTROLLERS; i++) {
-		if (privlist[i]->phyaddr == phyaddr)
-			return privlist[i];
-	}
-
-	return NULL;
-}
-
 /*
 /*
  * Read a MII PHY register.
  * Read a MII PHY register.
  *
  *
@@ -1519,14 +1596,14 @@ static int tsec_miiphy_read(char *devname, unsigned char addr,
 			    unsigned char reg, unsigned short *value)
 			    unsigned char reg, unsigned short *value)
 {
 {
 	unsigned short ret;
 	unsigned short ret;
-	struct tsec_private *priv = get_priv_for_phy(addr);
+	struct tsec_private *priv = privlist[0];
 
 
 	if (NULL == priv) {
 	if (NULL == priv) {
 		printf("Can't read PHY at address %d\n", addr);
 		printf("Can't read PHY at address %d\n", addr);
 		return -1;
 		return -1;
 	}
 	}
 
 
-	ret = (unsigned short)read_phy_reg(priv, reg);
+	ret = (unsigned short)read_any_phy_reg(priv, addr, reg);
 	*value = ret;
 	*value = ret;
 
 
 	return 0;
 	return 0;
@@ -1541,14 +1618,14 @@ static int tsec_miiphy_read(char *devname, unsigned char addr,
 static int tsec_miiphy_write(char *devname, unsigned char addr,
 static int tsec_miiphy_write(char *devname, unsigned char addr,
 			     unsigned char reg, unsigned short value)
 			     unsigned char reg, unsigned short value)
 {
 {
-	struct tsec_private *priv = get_priv_for_phy(addr);
+	struct tsec_private *priv = privlist[0];
 
 
 	if (NULL == priv) {
 	if (NULL == priv) {
 		printf("Can't write PHY at address %d\n", addr);
 		printf("Can't write PHY at address %d\n", addr);
 		return -1;
 		return -1;
 	}
 	}
 
 
-	write_phy_reg(priv, reg, value);
+	write_any_phy_reg(priv, addr, reg, value);
 
 
 	return 0;
 	return 0;
 }
 }

+ 8 - 0
drivers/net/tsec.h

@@ -184,6 +184,14 @@
 #define MIIM_88E1145_PHY_PAGE   29
 #define MIIM_88E1145_PHY_PAGE   29
 #define MIIM_88E1145_PHY_CAL_OV 30
 #define MIIM_88E1145_PHY_CAL_OV 30
 
 
+/* RTL8211B PHY Status Register */
+#define MIIM_RTL8211B_PHY_STATUS	0x11
+#define MIIM_RTL8211B_PHYSTAT_SPEED	0xc000
+#define MIIM_RTL8211B_PHYSTAT_GBIT	0x8000
+#define MIIM_RTL8211B_PHYSTAT_100	0x4000
+#define MIIM_RTL8211B_PHYSTAT_DUPLEX	0x2000
+#define MIIM_RTL8211B_PHYSTAT_SPDDONE	0x0800
+#define MIIM_RTL8211B_PHYSTAT_LINK	0x0400
 
 
 /* DM9161 Control register values */
 /* DM9161 Control register values */
 #define MIIM_DM9161_CR_STOP	0x0400
 #define MIIM_DM9161_CR_STOP	0x0400

+ 85 - 27
drivers/qe/uec.c

@@ -40,8 +40,13 @@ static uec_info_t eth1_uec_info = {
 		.tx_clock	= CFG_UEC1_TX_CLK,
 		.tx_clock	= CFG_UEC1_TX_CLK,
 		.eth_type	= CFG_UEC1_ETH_TYPE,
 		.eth_type	= CFG_UEC1_ETH_TYPE,
 	},
 	},
+#if (CFG_UEC1_ETH_TYPE == FAST_ETH)
+	.num_threads_tx		= UEC_NUM_OF_THREADS_1,
+	.num_threads_rx		= UEC_NUM_OF_THREADS_1,
+#else
 	.num_threads_tx		= UEC_NUM_OF_THREADS_4,
 	.num_threads_tx		= UEC_NUM_OF_THREADS_4,
 	.num_threads_rx		= UEC_NUM_OF_THREADS_4,
 	.num_threads_rx		= UEC_NUM_OF_THREADS_4,
+#endif
 	.riscTx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.riscTx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.riscRx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.riscRx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.tx_bd_ring_len		= 16,
 	.tx_bd_ring_len		= 16,
@@ -58,8 +63,13 @@ static uec_info_t eth2_uec_info = {
 		.tx_clock	= CFG_UEC2_TX_CLK,
 		.tx_clock	= CFG_UEC2_TX_CLK,
 		.eth_type	= CFG_UEC2_ETH_TYPE,
 		.eth_type	= CFG_UEC2_ETH_TYPE,
 	},
 	},
+#if (CFG_UEC2_ETH_TYPE == FAST_ETH)
+	.num_threads_tx		= UEC_NUM_OF_THREADS_1,
+	.num_threads_rx		= UEC_NUM_OF_THREADS_1,
+#else
 	.num_threads_tx		= UEC_NUM_OF_THREADS_4,
 	.num_threads_tx		= UEC_NUM_OF_THREADS_4,
 	.num_threads_rx		= UEC_NUM_OF_THREADS_4,
 	.num_threads_rx		= UEC_NUM_OF_THREADS_4,
+#endif
 	.riscTx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.riscTx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.riscRx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.riscRx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.tx_bd_ring_len		= 16,
 	.tx_bd_ring_len		= 16,
@@ -68,7 +78,6 @@ static uec_info_t eth2_uec_info = {
 	.enet_interface		= CFG_UEC2_INTERFACE_MODE,
 	.enet_interface		= CFG_UEC2_INTERFACE_MODE,
 };
 };
 #endif
 #endif
-
 #ifdef CONFIG_UEC_ETH3
 #ifdef CONFIG_UEC_ETH3
 static uec_info_t eth3_uec_info = {
 static uec_info_t eth3_uec_info = {
 	.uf_info		= {
 	.uf_info		= {
@@ -77,8 +86,13 @@ static uec_info_t eth3_uec_info = {
 		.tx_clock	= CFG_UEC3_TX_CLK,
 		.tx_clock	= CFG_UEC3_TX_CLK,
 		.eth_type	= CFG_UEC3_ETH_TYPE,
 		.eth_type	= CFG_UEC3_ETH_TYPE,
 	},
 	},
+#if (CFG_UEC3_ETH_TYPE == FAST_ETH)
+	.num_threads_tx		= UEC_NUM_OF_THREADS_1,
+	.num_threads_rx		= UEC_NUM_OF_THREADS_1,
+#else
 	.num_threads_tx		= UEC_NUM_OF_THREADS_4,
 	.num_threads_tx		= UEC_NUM_OF_THREADS_4,
 	.num_threads_rx		= UEC_NUM_OF_THREADS_4,
 	.num_threads_rx		= UEC_NUM_OF_THREADS_4,
+#endif
 	.riscTx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.riscTx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.riscRx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.riscRx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
 	.tx_bd_ring_len		= 16,
 	.tx_bd_ring_len		= 16,
@@ -87,6 +101,29 @@ static uec_info_t eth3_uec_info = {
 	.enet_interface		= CFG_UEC3_INTERFACE_MODE,
 	.enet_interface		= CFG_UEC3_INTERFACE_MODE,
 };
 };
 #endif
 #endif
+#ifdef CONFIG_UEC_ETH4
+static uec_info_t eth4_uec_info = {
+	.uf_info		= {
+		.ucc_num	= CFG_UEC4_UCC_NUM,
+		.rx_clock	= CFG_UEC4_RX_CLK,
+		.tx_clock	= CFG_UEC4_TX_CLK,
+		.eth_type	= CFG_UEC4_ETH_TYPE,
+	},
+#if (CFG_UEC4_ETH_TYPE == FAST_ETH)
+	.num_threads_tx		= UEC_NUM_OF_THREADS_1,
+	.num_threads_rx		= UEC_NUM_OF_THREADS_1,
+#else
+	.num_threads_tx		= UEC_NUM_OF_THREADS_4,
+	.num_threads_rx		= UEC_NUM_OF_THREADS_4,
+#endif
+	.riscTx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+	.riscRx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+	.tx_bd_ring_len		= 16,
+	.rx_bd_ring_len		= 16,
+	.phy_address		= CFG_UEC4_PHY_ADDR,
+	.enet_interface		= CFG_UEC4_INTERFACE_MODE,
+};
+#endif
 
 
 static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode)
 static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode)
 {
 {
@@ -475,6 +512,8 @@ static int init_phy(struct eth_device *dev)
 
 
 	uec->mii_info = mii_info;
 	uec->mii_info = mii_info;
 
 
+	qe_set_mii_clk_src(uec->uec_info->uf_info.ucc_num);
+
 	if (init_mii_management_configuration(umii_regs)) {
 	if (init_mii_management_configuration(umii_regs)) {
 		printf("%s: The MII Bus is stuck!", dev->name);
 		printf("%s: The MII Bus is stuck!", dev->name);
 		err = -1;
 		err = -1;
@@ -581,21 +620,12 @@ static void adjust_link(struct eth_device *dev)
 static void phy_change(struct eth_device *dev)
 static void phy_change(struct eth_device *dev)
 {
 {
 	uec_private_t	*uec = (uec_private_t *)dev->priv;
 	uec_private_t	*uec = (uec_private_t *)dev->priv;
-	uec_t		*uec_regs;
-	int		result = 0;
-
-	uec_regs = uec->uec_regs;
-
-	/* Delay 5s to give the PHY a chance to change the register state */
-	udelay(5000000);
 
 
 	/* Update the link, speed, duplex */
 	/* Update the link, speed, duplex */
-	result = uec->mii_info->phyinfo->read_status(uec->mii_info);
+	uec->mii_info->phyinfo->read_status(uec->mii_info);
 
 
 	/* Adjust the interface according to speed */
 	/* Adjust the interface according to speed */
-	if ((0 == result) || (uec->mii_info->link == 0)) {
-		adjust_link(dev);
-	}
+	adjust_link(dev);
 }
 }
 
 
 static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr)
 static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr)
@@ -1120,27 +1150,59 @@ static int uec_startup(uec_private_t *uec)
 static int uec_init(struct eth_device* dev, bd_t *bd)
 static int uec_init(struct eth_device* dev, bd_t *bd)
 {
 {
 	uec_private_t		*uec;
 	uec_private_t		*uec;
-	int			err;
+	int			err, i;
+	struct phy_info         *curphy;
 
 
 	uec = (uec_private_t *)dev->priv;
 	uec = (uec_private_t *)dev->priv;
 
 
 	if (uec->the_first_run == 0) {
 	if (uec->the_first_run == 0) {
-		/* Set up the MAC address */
-		if (dev->enetaddr[0] & 0x01) {
-			printf("%s: MacAddress is multcast address\n",
-				 __FUNCTION__);
-			return -1;
+		err = init_phy(dev);
+		if (err) {
+			printf("%s: Cannot initialize PHY, aborting.\n",
+			       dev->name);
+			return err;
+		}
+
+		curphy = uec->mii_info->phyinfo;
+
+		if (curphy->config_aneg) {
+			err = curphy->config_aneg(uec->mii_info);
+			if (err) {
+				printf("%s: Can't negotiate PHY\n", dev->name);
+				return err;
+			}
 		}
 		}
-		uec_set_mac_address(uec, dev->enetaddr);
+
+		/* Give PHYs up to 5 sec to report a link */
+		i = 50;
+		do {
+			err = curphy->read_status(uec->mii_info);
+			udelay(100000);
+		} while (((i-- > 0) && !uec->mii_info->link) || err);
+
+		if (err || i <= 0)
+			printf("warning: %s: timeout on PHY link\n", dev->name);
+
 		uec->the_first_run = 1;
 		uec->the_first_run = 1;
 	}
 	}
 
 
+	/* Set up the MAC address */
+	if (dev->enetaddr[0] & 0x01) {
+		printf("%s: MacAddress is multcast address\n",
+			 __FUNCTION__);
+		return -1;
+	}
+	uec_set_mac_address(uec, dev->enetaddr);
+
+
 	err = uec_open(uec, COMM_DIR_RX_AND_TX);
 	err = uec_open(uec, COMM_DIR_RX_AND_TX);
 	if (err) {
 	if (err) {
 		printf("%s: cannot enable UEC device\n", dev->name);
 		printf("%s: cannot enable UEC device\n", dev->name);
 		return -1;
 		return -1;
 	}
 	}
 
 
+	phy_change(dev);
+
 	return (uec->mii_info->link ? 0 : -1);
 	return (uec->mii_info->link ? 0 : -1);
 }
 }
 
 
@@ -1261,6 +1323,10 @@ int uec_initialize(int index)
 	} else if (index == 2) {
 	} else if (index == 2) {
 #ifdef CONFIG_UEC_ETH3
 #ifdef CONFIG_UEC_ETH3
 		uec_info = &eth3_uec_info;
 		uec_info = &eth3_uec_info;
+#endif
+	} else if (index == 3) {
+#ifdef CONFIG_UEC_ETH4
+		uec_info = &eth4_uec_info;
 #endif
 #endif
 	} else {
 	} else {
 		printf("%s: index is illegal.\n", __FUNCTION__);
 		printf("%s: index is illegal.\n", __FUNCTION__);
@@ -1289,14 +1355,6 @@ int uec_initialize(int index)
 		return err;
 		return err;
 	}
 	}
 
 
-	err = init_phy(dev);
-	if (err) {
-		printf("%s: Cannot initialize PHY, aborting.\n", dev->name);
-		return err;
-	}
-
-	phy_change(dev);
-
 	return 1;
 	return 1;
 }
 }
 #endif /* CONFIG_QE */
 #endif /* CONFIG_QE */

+ 37 - 24
drivers/qe/uec_phy.c

@@ -28,7 +28,6 @@
 
 
 #if defined(CONFIG_QE)
 #if defined(CONFIG_QE)
 
 
-#define UEC_VERBOSE_DEBUG
 #define ugphy_printk(format, arg...)  \
 #define ugphy_printk(format, arg...)  \
 	printf(format "\n", ## arg)
 	printf(format "\n", ## arg)
 
 
@@ -77,11 +76,10 @@ void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int valu
 
 
 	/* Setting up the MII Mangement Control Register with the value */
 	/* Setting up the MII Mangement Control Register with the value */
 	out_be32 (&ug_regs->miimcon, (u32) value);
 	out_be32 (&ug_regs->miimcon, (u32) value);
+	sync();
 
 
 	/* Wait till MII management write is complete */
 	/* Wait till MII management write is complete */
 	while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY);
 	while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY);
-
-	udelay (100000);
 }
 }
 
 
 /* Reads from register regnum in the PHY for device dev, */
 /* Reads from register regnum in the PHY for device dev, */
@@ -101,20 +99,21 @@ int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum)
 	tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
 	tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
 	out_be32 (&ug_regs->miimadd, tmp_reg);
 	out_be32 (&ug_regs->miimadd, tmp_reg);
 
 
-	/* Perform an MII management read cycle */
+	/* clear MII management command cycle */
 	out_be32 (&ug_regs->miimcom, 0);
 	out_be32 (&ug_regs->miimcom, 0);
+	sync();
+
+	/* Perform an MII management read cycle */
 	out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE);
 	out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE);
 
 
 	/* Wait till MII management write is complete */
 	/* Wait till MII management write is complete */
 	while ((in_be32 (&ug_regs->miimind)) &
 	while ((in_be32 (&ug_regs->miimind)) &
 	       (MIIMIND_NOT_VALID | MIIMIND_BUSY));
 	       (MIIMIND_NOT_VALID | MIIMIND_BUSY));
 
 
-	udelay (100000);
-
 	/* Read MII management status  */
 	/* Read MII management status  */
 	value = (u16) in_be32 (&ug_regs->miimstat);
 	value = (u16) in_be32 (&ug_regs->miimstat);
 	if (value == 0xffff)
 	if (value == 0xffff)
-		ugphy_warn
+		ugphy_vdbg
 			("read wrong value : mii_id %d,mii_reg %d, base %08x",
 			("read wrong value : mii_id %d,mii_reg %d, base %08x",
 			 mii_id, mii_reg, (u32) & (ug_regs->miimcfg));
 			 mii_id, mii_reg, (u32) & (ug_regs->miimcfg));
 
 
@@ -270,20 +269,38 @@ static int genmii_update_link (struct uec_mii_info *mii_info)
 {
 {
 	u16 status;
 	u16 status;
 
 
-	/* Do a fake read */
+	/* Status is read once to clear old link state */
 	phy_read (mii_info, PHY_BMSR);
 	phy_read (mii_info, PHY_BMSR);
 
 
-	/* Read link and autonegotiation status */
-	status = phy_read (mii_info, PHY_BMSR);
-	if ((status & PHY_BMSR_LS) == 0)
-		mii_info->link = 0;
-	else
+	/*
+	 * Wait if the link is up, and autonegotiation is in progress
+	 * (ie - we're capable and it's not done)
+	 */
+	status = phy_read(mii_info, PHY_BMSR);
+	if ((status & PHY_BMSR_LS) && (status & PHY_BMSR_AUTN_ABLE)
+	    && !(status & PHY_BMSR_AUTN_COMP)) {
+		int i = 0;
+
+		while (!(status & PHY_BMSR_AUTN_COMP)) {
+			/*
+			 * Timeout reached ?
+			 */
+			if (i > UGETH_AN_TIMEOUT) {
+				mii_info->link = 0;
+				return 0;
+			}
+
+			udelay(1000);	/* 1 ms */
+			status = phy_read(mii_info, PHY_BMSR);
+		}
 		mii_info->link = 1;
 		mii_info->link = 1;
-
-	/* If we are autonegotiating, and not done,
-	 * return an error */
-	if (mii_info->autoneg && !(status & PHY_BMSR_AUTN_COMP))
-		return -EAGAIN;
+		udelay(500000);	/* another 500 ms (results in faster booting) */
+	} else {
+		if (status & PHY_BMSR_LS)
+			mii_info->link = 1;
+		else
+			mii_info->link = 0;
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -389,16 +406,12 @@ static int dm9161_init (struct uec_mii_info *mii_info)
 	/* PHY and MAC connect */
 	/* PHY and MAC connect */
 	phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) &
 	phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) &
 		   ~PHY_BMCR_ISO);
 		   ~PHY_BMCR_ISO);
-#ifdef CONFIG_RMII_MODE
-	phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_RMII_INIT);
-#else
+
 	phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
 	phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
-#endif
+
 	config_genmii_advert (mii_info);
 	config_genmii_advert (mii_info);
 	/* Start/restart aneg */
 	/* Start/restart aneg */
 	genmii_config_aneg (mii_info);
 	genmii_config_aneg (mii_info);
-	/* Delay to wait the aneg compeleted */
-	udelay (3000000);
 
 
 	return 0;
 	return 0;
 }
 }

+ 12 - 0
net/eth.c

@@ -217,6 +217,9 @@ int eth_initialize(bd_t *bis)
 #if defined(CONFIG_UEC_ETH3)
 #if defined(CONFIG_UEC_ETH3)
 	uec_initialize(2);
 	uec_initialize(2);
 #endif
 #endif
+#if defined(CONFIG_UEC_ETH4)
+	uec_initialize(3);
+#endif
 
 
 #if defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FCC)
 #if defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FCC)
 	fec_initialize(bis);
 	fec_initialize(bis);
@@ -522,6 +525,15 @@ int eth_receive(volatile void *packet, int length)
 void eth_try_another(int first_restart)
 void eth_try_another(int first_restart)
 {
 {
 	static struct eth_device *first_failed = NULL;
 	static struct eth_device *first_failed = NULL;
+	char *ethrotate;
+
+	/*
+	 * Do not rotate between network interfaces when
+	 * 'ethrotate' variable is set to 'no'.
+	 */
+	if (((ethrotate = getenv ("ethrotate")) != NULL) &&
+	    (strcmp(ethrotate, "no") == 0))
+		return;
 
 
 	if (!eth_current)
 	if (!eth_current)
 		return;
 		return;