diff --git a/README b/README
index 4c74cb79347ada1cb1c0906d5894cbfd0f5a465b..90714727cde2d714643b2ac11d246bf41ec74627 100644
--- a/README
+++ b/README
@@ -1184,6 +1184,11 @@ The following options need to be configured:
 		Defines a default value for the IP address of a TFTP
 		server to contact when using the "tftboot" command.
 
+		CONFIG_KEEP_SERVERADDR
+
+		Keeps the server's MAC address, in the env 'serveraddr'
+		for passing to bootargs (like Linux's netconsole option)
+
 - Multicast TFTP Mode:
 		CONFIG_MCAST_TFTP
 
diff --git a/board/bf548-ezkit/bf548-ezkit.c b/board/bf548-ezkit/bf548-ezkit.c
index 74f93ba27da73bc53444dd1e2b849a4910593ea1..88a0cd4d619b9d15ddc9ebaf1615fd76199bc4da 100644
--- a/board/bf548-ezkit/bf548-ezkit.c
+++ b/board/bf548-ezkit/bf548-ezkit.c
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <netdev.h>
 #include <config.h>
 #include <command.h>
 #include <asm/blackfin.h>
@@ -77,3 +78,10 @@ int board_early_init_f(void)
 
 	return 0;
 }
+
+#ifdef CONFIG_SMC911X
+int board_eth_init(bd_t *bis)
+{
+	return smc911x_initialize(0, CONFIG_SMC911X_BASE);
+}
+#endif
diff --git a/board/cm-bf548/cm-bf548.c b/board/cm-bf548/cm-bf548.c
index 1c2660046fb82a12e79ad316a8488954470b1528..796263d62b39b66a5f700be7563baefc0c64a351 100644
--- a/board/cm-bf548/cm-bf548.c
+++ b/board/cm-bf548/cm-bf548.c
@@ -9,6 +9,7 @@
 #include <common.h>
 #include <config.h>
 #include <command.h>
+#include <netdev.h>
 #include <asm/blackfin.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -77,3 +78,12 @@ int board_early_init_f(void)
 
 	return 0;
 }
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_SMC911X
+	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+	return rc;
+}
diff --git a/board/freescale/mx31pdk/mx31pdk.c b/board/freescale/mx31pdk/mx31pdk.c
index 6b60c17dca8c07b58b5c125da031210b8df62ff4..9f471692dd9f695dec5ac6b7d9abb7a100e8cf3d 100644
--- a/board/freescale/mx31pdk/mx31pdk.c
+++ b/board/freescale/mx31pdk/mx31pdk.c
@@ -25,6 +25,7 @@
 
 
 #include <common.h>
+#include <netdev.h>
 #include <asm/arch/mx31.h>
 #include <asm/arch/mx31-regs.h>
 
@@ -61,3 +62,12 @@ int checkboard(void)
 	printf("Board: i.MX31 MAX PDK (3DS)\n");
 	return 0;
 }
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_SMC911X
+	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+	return rc;
+}
diff --git a/board/imx31_litekit/imx31_litekit.c b/board/imx31_litekit/imx31_litekit.c
index cb3e174841838351ba8c66c8cfc63e5531961ccd..2ac622dbbe33954bc3cf3748a31ebf14b5355631 100644
--- a/board/imx31_litekit/imx31_litekit.c
+++ b/board/imx31_litekit/imx31_litekit.c
@@ -23,6 +23,7 @@
 
 
 #include <common.h>
+#include <netdev.h>
 #include <asm/arch/mx31.h>
 #include <asm/arch/mx31-regs.h>
 
@@ -75,3 +76,12 @@ int checkboard (void)
 	printf("Board: i.MX31 Litekit\n");
 	return 0;
 }
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_SMC911X
+	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+	return rc;
+}
diff --git a/board/imx31_phycore/imx31_phycore.c b/board/imx31_phycore/imx31_phycore.c
index 92aba96b98343a76f9ce53e9f8f5e82a462586ac..3d7b7f70ce6e323f982b09d0cec4942babd0bfca 100644
--- a/board/imx31_phycore/imx31_phycore.c
+++ b/board/imx31_phycore/imx31_phycore.c
@@ -24,6 +24,7 @@
 
 #include <common.h>
 #include <s6e63d6.h>
+#include <netdev.h>
 #include <asm/arch/mx31.h>
 #include <asm/arch/mx31-regs.h>
 
@@ -128,3 +129,12 @@ int checkboard (void)
 	printf("Board: Phytec phyCore i.MX31\n");
 	return 0;
 }
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_SMC911X
+	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+	return rc;
+}
diff --git a/board/micronas/vct/ebi_smc911x.c b/board/micronas/vct/ebi_smc911x.c
index e1b67a075b7eb0ba6e61df7cc78f22dbe0b7f696..c9ef33d9510d92e40fbaa0c94832949955224b28 100644
--- a/board/micronas/vct/ebi_smc911x.c
+++ b/board/micronas/vct/ebi_smc911x.c
@@ -18,6 +18,7 @@
  */
 
 #include <common.h>
+#include <netdev.h>
 #include <asm/io.h>
 #include "vct.h"
 
@@ -45,10 +46,11 @@ int ebi_init_smc911x(void)
  * Accessor functions replacing the "weak" functions in
  * drivers/net/smc911x.c
  */
-u32 smc911x_reg_read(u32 addr)
+u32 smc911x_reg_read(struct eth_device *dev, u32 addr)
 {
 	volatile u32 data;
 
+	addr += dev->iobase;
 	reg_write(EBI_DEV1_CONFIG2(EBI_BASE), 0x0000004F);
 	ebi_wait();
 	reg_write(EBI_CPU_IO_ACCS(EBI_BASE), (EXT_DEVICE_CHANNEL_1 | addr));
@@ -58,8 +60,9 @@ u32 smc911x_reg_read(u32 addr)
 	return (data);
 }
 
-void smc911x_reg_write(u32 addr, u32 data)
+void smc911x_reg_write(struct eth_device *dev, u32 addr, u32 data)
 {
+	addr += dev->iobase;
 	reg_write(EBI_DEV1_CONFIG2(EBI_BASE), 0x0000004F);
 	ebi_wait();
 	reg_write(EBI_IO_ACCS_DATA(EBI_BASE), data);
@@ -68,8 +71,9 @@ void smc911x_reg_write(u32 addr, u32 data)
 	ebi_wait();
 }
 
-void pkt_data_push(u32 addr, u32 data)
+void pkt_data_push(struct eth_device *dev, u32 addr, u32 data)
 {
+	addr += dev->iobase;
 	reg_write(EBI_DEV1_CONFIG2(EBI_BASE), 0x0000004A);
 	ebi_wait();
 	reg_write(EBI_IO_ACCS_DATA(EBI_BASE), data);
@@ -80,10 +84,11 @@ void pkt_data_push(u32 addr, u32 data)
 	return;
 }
 
-u32 pkt_data_pull(u32 addr)
+u32 pkt_data_pull(struct eth_device *dev, u32 addr)
 {
 	volatile u32 data;
 
+	addr += dev->iobase;
 	reg_write(EBI_DEV1_CONFIG2(EBI_BASE), 0x0000004A);
 	ebi_wait();
 	reg_write(EBI_CPU_IO_ACCS(EBI_BASE), (EXT_DEVICE_CHANNEL_1 | addr));
@@ -92,3 +97,12 @@ u32 pkt_data_pull(u32 addr)
 
 	return data;
 }
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_SMC911X
+	rc = smc911x_initialize(0, CONFIG_DRIVER_SMC911X_BASE);
+#endif
+	return rc;
+}
diff --git a/board/micronas/vct/vct.c b/board/micronas/vct/vct.c
index d320e0b5f0d898b1d11094d2eea2270e7b6a8629..7fc3507b0e10ccfc27d29adbf8cbae67391f9f35 100644
--- a/board/micronas/vct/vct.c
+++ b/board/micronas/vct/vct.c
@@ -21,6 +21,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <netdev.h>
 #include <asm/mipsregs.h>
 #include "vct.h"
 
@@ -115,3 +116,12 @@ int checkboard(void)
 
 	return 0;
 }
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_SMC911X
+	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+	return rc;
+}
diff --git a/board/omap3/evm/evm.c b/board/omap3/evm/evm.c
index 5fd5efad9c2e6db29d19fd629dbd899306bb1107..bfd2688d7343d3cc5217ca03740cc0e024d34daf 100644
--- a/board/omap3/evm/evm.c
+++ b/board/omap3/evm/evm.c
@@ -28,6 +28,7 @@
  * MA 02111-1307 USA
  */
 #include <common.h>
+#include <netdev.h>
 #include <asm/io.h>
 #include <asm/arch/mem.h>
 #include <asm/arch/mux.h>
@@ -122,3 +123,12 @@ static void setup_net_chip(void)
 	udelay(1);
 	writel(GPIO0, &gpio3_base->setdataout);
 }
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_SMC911X
+	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+	return rc;
+}
diff --git a/board/renesas/ap325rxa/ap325rxa.c b/board/renesas/ap325rxa/ap325rxa.c
index 9f1112a4360941222415c2a6bc8293d7eab99808..be919f5454a10cb1667f18962c3392ba71cfe564 100644
--- a/board/renesas/ap325rxa/ap325rxa.c
+++ b/board/renesas/ap325rxa/ap325rxa.c
@@ -19,6 +19,7 @@
  */
 
 #include <common.h>
+#include <netdev.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 
@@ -160,3 +161,12 @@ void ide_set_reset(int idereset)
 	udelay(FPGA_NAND_RST_WAIT);
 	outw(FPGA_NAND_INIT, FPGA_NAND_CTL);
 }
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_SMC911X
+	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+	return rc;
+}
diff --git a/board/renesas/rsk7203/rsk7203.c b/board/renesas/rsk7203/rsk7203.c
index 2cbd45e043fb9ce81fd137ecd9d2843d0180a589..2b857998697f4ad1c22b1520ce039f8ed082be0c 100644
--- a/board/renesas/rsk7203/rsk7203.c
+++ b/board/renesas/rsk7203/rsk7203.c
@@ -21,6 +21,7 @@
  */
 
 #include <common.h>
+#include <netdev.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 
@@ -57,15 +58,25 @@ void led_set_state(unsigned short value)
  * And this has problem by FIFO access only. pkt_data_pull/pkt_data_push
  * functions necessary to solve this problem.
  */
-u32 pkt_data_pull(u32 addr)
+u32 pkt_data_pull(struct eth_device *dev, u32 addr)
 {
-	volatile u16 *addr_16 = (u16 *)addr;
+	volatile u16 *addr_16 = (u16 *)(dev->iobase + addr);
 	return (u32)((swab16(*addr_16) << 16) & 0xFFFF0000)\
 				| swab16(*(addr_16 + 1));
 }
 
-void pkt_data_push(u32 addr, u32 val)
+void pkt_data_push(struct eth_device *dev, u32 addr, u32 val)
 {
+	addr += dev->iobase;
 	*(volatile u16 *)(addr + 2) = swab16((u16)val);
 	*(volatile u16 *)(addr) = swab16((u16)(val >> 16));
 }
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_SMC911X
+	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+	return rc;
+}
diff --git a/common/cmd_net.c b/common/cmd_net.c
index 68183c49af9233666705f2025fad4ec0ccebb84b..ac706ae8d5e73eb7f6f58d173b3c1e83eba6935f 100644
--- a/common/cmd_net.c
+++ b/common/cmd_net.c
@@ -353,3 +353,52 @@ U_BOOT_CMD(
 	"[NTP server IP]\n"
 );
 #endif
+
+#if defined(CONFIG_CMD_DNS)
+int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	if (argc == 1) {
+		cmd_usage(cmdtp);
+		return -1;
+	}
+
+	/*
+	 * We should check for a valid hostname:
+	 * - Each label must be between 1 and 63 characters long
+	 * - the entire hostname has a maximum of 255 characters
+	 * - only the ASCII letters 'a' through 'z' (case-insensitive),
+	 *   the digits '0' through '9', and the hyphen
+	 * - cannot begin or end with a hyphen
+	 * - no other symbols, punctuation characters, or blank spaces are
+	 *   permitted
+	 * but hey - this is a minimalist implmentation, so only check length
+	 * and let the name server deal with things.
+	 */
+	if (strlen(argv[1]) >= 255) {
+		printf("dns error: hostname too long\n");
+		return 1;
+	}
+
+	NetDNSResolve = argv[1];
+
+	if (argc == 3)
+		NetDNSenvvar = argv[2];
+	else
+		NetDNSenvvar = NULL;
+
+	if (NetLoop(DNS) < 0) {
+		printf("dns lookup of %s failed, check setup\n", argv[1]);
+		return 1;
+	}
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	dns,	3,	1,	do_dns,
+	"lookup the IP of a hostname",
+	"hostname [envvar]"
+);
+
+#endif	/* CONFIG_CMD_DNS */
+
diff --git a/cpu/arm920t/at91rm9200/ether.c b/cpu/arm920t/at91rm9200/ether.c
index d9d33a23208e7e744662eabd3012c1753936d3cf..91eab95eed1e1844384ed34a9438747546d8868a 100644
--- a/cpu/arm920t/at91rm9200/ether.c
+++ b/cpu/arm920t/at91rm9200/ether.c
@@ -24,6 +24,7 @@
 #include <at91rm9200_net.h>
 #include <net.h>
 #include <miiphy.h>
+#include <asm/mach-types.h>
 
 /* ----- Ethernet Buffer definitions ----- */
 
@@ -184,7 +185,7 @@ int eth_init (bd_t * bd)
 
 	p_mac->EMAC_CFG |= AT91C_EMAC_CSR;	/* Clear statistics */
 
-	/* Init Ehternet buffers */
+	/* Init Ethernet buffers */
 	for (i = 0; i < RBF_FRAMEMAX; i++) {
 		rbfdt[i].addr = (unsigned long)rbf_framebuf[i];
 		rbfdt[i].size = 0;
@@ -193,9 +194,22 @@ int eth_init (bd_t * bd)
 	rbfp = &rbfdt[0];
 
 	eth_getenv_enetaddr("ethaddr", enetaddr);
-	p_mac->EMAC_SA2L = (enetaddr[3] << 24) | (enetaddr[2] << 16)
-			 | (enetaddr[1] <<  8) | (enetaddr[0]);
-	p_mac->EMAC_SA2H = (enetaddr[5] <<  8) | (enetaddr[4]);
+
+	/* The CSB337 originally used a version of the MicroMonitor bootloader
+	 * which saved Ethernet addresses in the "wrong" order.  Operating
+	 * systems (like Linux) know this, and apply a workaround.  Replicate
+	 * that MicroMonitor behavior so we avoid needing to make such OS code
+	 * care about which bootloader was used.
+	 */
+	if (machine_is_csb337()) {
+		p_mac->EMAC_SA2H = (enetaddr[0] <<  8) | (enetaddr[1]);
+		p_mac->EMAC_SA2L = (enetaddr[2] << 24) | (enetaddr[3] << 16)
+				 | (enetaddr[4] <<  8) | (enetaddr[5]);
+	} else {
+		p_mac->EMAC_SA2L = (enetaddr[3] << 24) | (enetaddr[2] << 16)
+				 | (enetaddr[1] <<  8) | (enetaddr[0]);
+		p_mac->EMAC_SA2H = (enetaddr[5] <<  8) | (enetaddr[4]);
+	}
 
 	p_mac->EMAC_RBQP = (long) (&rbfdt[0]);
 	p_mac->EMAC_RSR &= ~(AT91C_EMAC_RSR_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);
diff --git a/cpu/arm926ejs/mx27/generic.c b/cpu/arm926ejs/mx27/generic.c
index bcf7899baa59a2132595bf458fb6529fcfc48043..47fa4b48edd938ffdf3c74b4f605951ebf3203fb 100644
--- a/cpu/arm926ejs/mx27/generic.c
+++ b/cpu/arm926ejs/mx27/generic.c
@@ -20,6 +20,7 @@
 
 #include <common.h>
 #include <div64.h>
+#include <netdev.h>
 #include <asm/io.h>
 #include <asm/arch/imx-regs.h>
 
@@ -159,6 +160,15 @@ int print_cpuinfo (void)
 }
 #endif
 
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_FEC_MXC)
+	return fecmxc_initialize(bis);
+#else
+	return 0;
+#endif
+}
+
 void imx_gpio_mode(int gpio_mode)
 {
 	struct gpio_regs *regs = (struct gpio_regs *)IMX_GPIO_BASE;
diff --git a/doc/README.dns b/doc/README.dns
new file mode 100644
index 0000000000000000000000000000000000000000..deeccd77200dad39b1c092ecef1e557501e44916
--- /dev/null
+++ b/doc/README.dns
@@ -0,0 +1,64 @@
+Domain Name System
+-------------------------------------------
+
+The Domain Name System (DNS) is a hierarchical naming system for computers,
+services, or any resource participating in the Internet. It associates various
+information with domain names assigned to each of the participants. Most
+importantly, it translates domain names meaningful to humans into the numerical
+(binary) identifiers associated with networking equipment for the purpose of
+locating and addressing these devices world-wide. An often used analogy to
+explain the Domain Name System is that it serves as the "phone book" for the
+Internet by translating human-friendly computer hostnames into IP addresses.
+For example, www.example.com translates to 208.77.188.166.
+
+For more information on DNS - http://en.wikipedia.org/wiki/Domain_Name_System
+
+
+
+U-Boot and DNS
+------------------------------------------
+
+CONFIG_CMD_DNS - controls if the 'dns' command is compiled in. If it is, it
+                 will send name lookups to the dns server (env var 'dnsip')
+                 Turning this option on will about abou 1k to U-Boot's size.
+
+                 Example:
+
+bfin> print dnsip
+dnsip=192.168.0.1
+
+bfin> dns www.google.com
+66.102.1.104
+
+                 By default, dns does nothing except print the IP number on
+                 the default console - which by itself, would be pretty
+                 useless. Adding a third argument to the dns command will
+                 use that as the environment variable to be set.
+
+                 Example:
+
+bfin> print googleip
+## Error: "googleip" not defined
+bfin> dns www.google.com googleip
+64.233.161.104
+bfin> print googleip
+googleip=64.233.161.104
+bfin> ping ${googleip}
+Using Blackfin EMAC device
+host 64.233.161.104 is alive
+
+                 In this way, you can lookup, and set many more meaningful
+                 things.
+
+bfin> sntp
+ntpserverip not set
+bfin> dns pool.ntp.org ntpserverip
+72.18.205.156
+bfin> sntp
+Date: 2009-07-18 Time:  4:06:57
+
+                 For some helpful things that can be related to DNS in U-Boot,
+                 look at the top level README for these config options:
+                    CONFIG_CMD_DHCP
+                    CONFIG_BOOTP_DNS
+                    CONFIG_BOOTP_DNS2
diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c
index 587605dfd1f8b0da64c8538e5834e87ebc9e5651..c0200481c62cdd2fac1bf197663a1a68fd8aa848 100644
--- a/drivers/net/4xx_enet.c
+++ b/drivers/net/4xx_enet.c
@@ -870,7 +870,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
     defined(CONFIG_405EX)
 	u32 opbfreq;
 	sys_info_t sysinfo;
-#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
+#if defined(CONFIG_440GX) || \
     defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
     defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
     defined(CONFIG_405EX)
@@ -1119,7 +1119,6 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
 
 #if defined(CONFIG_440GX) || \
     defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
-    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
     defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
     defined(CONFIG_405EX)
 
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index c6097c3c5f587fcd5a40a549ab9afbe4f379dfa9..34b56d82530e54427890450105105acebc9f9a69 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -37,6 +37,7 @@ COBJS-$(CONFIG_DNET) += dnet.o
 COBJS-$(CONFIG_E1000) += e1000.o
 COBJS-$(CONFIG_EEPRO100) += eepro100.o
 COBJS-$(CONFIG_ENC28J60) += enc28j60.o
+COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
@@ -63,7 +64,7 @@ COBJS-$(CONFIG_RTL8169) += rtl8169.o
 COBJS-$(CONFIG_DRIVER_S3C4510_ETH) += s3c4510b_eth.o
 COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
 COBJS-$(CONFIG_DRIVER_SMC91111) += smc91111.o
-COBJS-$(CONFIG_DRIVER_SMC911X) += smc911x.o
+COBJS-$(CONFIG_SMC911X) += smc911x.o
 COBJS-$(CONFIG_TIGON3) += tigon3.o bcm570x_autoneg.o 5701rls.o
 COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
 COBJS-$(CONFIG_TSEC_ENET) += tsec.o
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
new file mode 100644
index 0000000000000000000000000000000000000000..faf008cea16ec958ecc3bb32c8947f9a26d628c8
--- /dev/null
+++ b/drivers/net/fec_mxc.c
@@ -0,0 +1,742 @@
+/*
+ * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
+ * (C) Copyright 2008,2009 Eric Jarrige <eric.jarrige@armadeus.org>
+ * (C) Copyright 2008 Armadeus Systems nc
+ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include "fec_mxc.h"
+
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_MII
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#undef DEBUG
+
+struct nbuf {
+	uint8_t data[1500];	/**< actual data */
+	int length;		/**< actual length */
+	int used;		/**< buffer in use or not */
+	uint8_t head[16];	/**< MAC header(6 + 6 + 2) + 2(aligned) */
+};
+
+struct fec_priv gfec = {
+	.eth       = (struct ethernet_regs *)IMX_FEC_BASE,
+	.xcv_type  = MII100,
+	.rbd_base  = NULL,
+	.rbd_index = 0,
+	.tbd_base  = NULL,
+	.tbd_index = 0,
+	.bd        = NULL,
+};
+
+/*
+ * MII-interface related functions
+ */
+static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr,
+		uint16_t *retVal)
+{
+	struct eth_device *edev = eth_get_dev_by_name(dev);
+	struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+	uint32_t reg;		/* convenient holder for the PHY register */
+	uint32_t phy;		/* convenient holder for the PHY */
+	uint32_t start;
+
+	/*
+	 * reading from any PHY's register is done by properly
+	 * programming the FEC's MII data register.
+	 */
+	writel(FEC_IEVENT_MII, &fec->eth->ievent);
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA |
+			phy | reg, &fec->eth->mii_data);
+
+	/*
+	 * wait for the related interrupt
+	 */
+	start = get_timer_masked();
+	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
+		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+			printf("Read MDIO failed...\n");
+			return -1;
+		}
+	}
+
+	/*
+	 * clear mii interrupt bit
+	 */
+	writel(FEC_IEVENT_MII, &fec->eth->ievent);
+
+	/*
+	 * it's now safe to read the PHY's register
+	 */
+	*retVal = readl(&fec->eth->mii_data);
+	debug("fec_miiphy_read: phy: %02x reg:%02x val:%#x\n", phyAddr,
+			regAddr, *retVal);
+	return 0;
+}
+
+static int fec_miiphy_write(char *dev, uint8_t phyAddr, uint8_t regAddr,
+		uint16_t data)
+{
+	struct eth_device *edev = eth_get_dev_by_name(dev);
+	struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+	uint32_t reg;		/* convenient holder for the PHY register */
+	uint32_t phy;		/* convenient holder for the PHY */
+	uint32_t start;
+
+	reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+	phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+	writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
+		FEC_MII_DATA_TA | phy | reg | data, &fec->eth->mii_data);
+
+	/*
+	 * wait for the MII interrupt
+	 */
+	start = get_timer_masked();
+	while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
+		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+			printf("Write MDIO failed...\n");
+			return -1;
+		}
+	}
+
+	/*
+	 * clear MII interrupt bit
+	 */
+	writel(FEC_IEVENT_MII, &fec->eth->ievent);
+	debug("fec_miiphy_write: phy: %02x reg:%02x val:%#x\n", phyAddr,
+			regAddr, data);
+
+	return 0;
+}
+
+static int miiphy_restart_aneg(struct eth_device *dev)
+{
+	/*
+	 * Wake up from sleep if necessary
+	 * Reset PHY, then delay 300ns
+	 */
+	miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_MIPGSR, 0x00FF);
+	miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_BMCR,
+			PHY_BMCR_RESET);
+	udelay(1000);
+
+	/*
+	 * Set the auto-negotiation advertisement register bits
+	 */
+	miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_ANAR, 0x1e0);
+	miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_BMCR,
+			PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
+
+	return 0;
+}
+
+static int miiphy_wait_aneg(struct eth_device *dev)
+{
+	uint32_t start;
+	uint16_t status;
+
+	/*
+	 * Wait for AN completion
+	 */
+	start = get_timer_masked();
+	do {
+		if (get_timer(start) > (CONFIG_SYS_HZ * 5)) {
+			printf("%s: Autonegotiation timeout\n", dev->name);
+			return -1;
+		}
+
+		if (miiphy_read(dev->name, CONFIG_FEC_MXC_PHYADDR,
+					PHY_BMSR, &status)) {
+			printf("%s: Autonegotiation failed. status: 0x%04x\n",
+					dev->name, status);
+			return -1;
+		}
+	} while (!(status & PHY_BMSR_LS));
+
+	return 0;
+}
+static int fec_rx_task_enable(struct fec_priv *fec)
+{
+	writel(1 << 24, &fec->eth->r_des_active);
+	return 0;
+}
+
+static int fec_rx_task_disable(struct fec_priv *fec)
+{
+	return 0;
+}
+
+static int fec_tx_task_enable(struct fec_priv *fec)
+{
+	writel(1 << 24, &fec->eth->x_des_active);
+	return 0;
+}
+
+static int fec_tx_task_disable(struct fec_priv *fec)
+{
+	return 0;
+}
+
+/**
+ * Initialize receive task's buffer descriptors
+ * @param[in] fec all we know about the device yet
+ * @param[in] count receive buffer count to be allocated
+ * @param[in] size size of each receive buffer
+ * @return 0 on success
+ *
+ * For this task we need additional memory for the data buffers. And each
+ * data buffer requires some alignment. Thy must be aligned to a specific
+ * boundary each (DB_DATA_ALIGNMENT).
+ */
+static int fec_rbd_init(struct fec_priv *fec, int count, int size)
+{
+	int ix;
+	uint32_t p = 0;
+
+	/* reserve data memory and consider alignment */
+	fec->rdb_ptr = malloc(size * count + DB_DATA_ALIGNMENT);
+	p = (uint32_t)fec->rdb_ptr;
+	if (!p) {
+		puts("fec_imx27: not enough malloc memory!\n");
+		return -ENOMEM;
+	}
+	memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT);
+	p += DB_DATA_ALIGNMENT-1;
+	p &= ~(DB_DATA_ALIGNMENT-1);
+
+	for (ix = 0; ix < count; ix++) {
+		writel(p, &fec->rbd_base[ix].data_pointer);
+		p += size;
+		writew(FEC_RBD_EMPTY, &fec->rbd_base[ix].status);
+		writew(0, &fec->rbd_base[ix].data_length);
+	}
+	/*
+	 * mark the last RBD to close the ring
+	 */
+	writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[ix - 1].status);
+	fec->rbd_index = 0;
+
+	return 0;
+}
+
+/**
+ * Initialize transmit task's buffer descriptors
+ * @param[in] fec all we know about the device yet
+ *
+ * Transmit buffers are created externally. We only have to init the BDs here.\n
+ * Note: There is a race condition in the hardware. When only one BD is in
+ * use it must be marked with the WRAP bit to use it for every transmitt.
+ * This bit in combination with the READY bit results into double transmit
+ * of each data buffer. It seems the state machine checks READY earlier then
+ * resetting it after the first transfer.
+ * Using two BDs solves this issue.
+ */
+static void fec_tbd_init(struct fec_priv *fec)
+{
+	writew(0x0000, &fec->tbd_base[0].status);
+	writew(FEC_TBD_WRAP, &fec->tbd_base[1].status);
+	fec->tbd_index = 0;
+}
+
+/**
+ * Mark the given read buffer descriptor as free
+ * @param[in] last 1 if this is the last buffer descriptor in the chain, else 0
+ * @param[in] pRbd buffer descriptor to mark free again
+ */
+static void fec_rbd_clean(int last, struct fec_bd *pRbd)
+{
+	/*
+	 * Reset buffer descriptor as empty
+	 */
+	if (last)
+		writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &pRbd->status);
+	else
+		writew(FEC_RBD_EMPTY, &pRbd->status);
+	/*
+	 * no data in it
+	 */
+	writew(0, &pRbd->data_length);
+}
+
+static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac)
+{
+	struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
+	int i;
+
+	for (i = 0; i < 6; i++)
+		mac[6-1-i] = readl(&iim->iim_bank_area0[IIM0_MAC + i]);
+
+	return is_valid_ether_addr(mac);
+}
+
+static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac)
+{
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+	writel(0, &fec->eth->iaddr1);
+	writel(0, &fec->eth->iaddr2);
+	writel(0, &fec->eth->gaddr1);
+	writel(0, &fec->eth->gaddr2);
+
+	/*
+	 * Set physical address
+	 */
+	writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
+			&fec->eth->paddr1);
+	writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, &fec->eth->paddr2);
+
+	return 0;
+}
+
+/**
+ * Start the FEC engine
+ * @param[in] dev Our device to handle
+ */
+static int fec_open(struct eth_device *edev)
+{
+	struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+	debug("fec_open: fec_open(dev)\n");
+	/* full-duplex, heartbeat disabled */
+	writel(1 << 2, &fec->eth->x_cntrl);
+	fec->rbd_index = 0;
+
+	/*
+	 * Enable FEC-Lite controller
+	 */
+	writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl);
+
+	miiphy_wait_aneg(edev);
+	miiphy_speed(edev->name, 0);
+	miiphy_duplex(edev->name, 0);
+
+	/*
+	 * Enable SmartDMA receive task
+	 */
+	fec_rx_task_enable(fec);
+
+	udelay(100000);
+	return 0;
+}
+
+static int fec_init(struct eth_device *dev, bd_t* bd)
+{
+	uint32_t base;
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+	/*
+	 * reserve memory for both buffer descriptor chains at once
+	 * Datasheet forces the startaddress of each chain is 16 byte
+	 * aligned
+	 */
+	fec->base_ptr = malloc((2 + FEC_RBD_NUM) *
+			sizeof(struct fec_bd) + DB_ALIGNMENT);
+	base = (uint32_t)fec->base_ptr;
+	if (!base) {
+		puts("fec_imx27: not enough malloc memory!\n");
+		return -ENOMEM;
+	}
+	memset((void *)base, 0, (2 + FEC_RBD_NUM) *
+			sizeof(struct fec_bd) + DB_ALIGNMENT);
+	base += (DB_ALIGNMENT-1);
+	base &= ~(DB_ALIGNMENT-1);
+
+	fec->rbd_base = (struct fec_bd *)base;
+
+	base += FEC_RBD_NUM * sizeof(struct fec_bd);
+
+	fec->tbd_base = (struct fec_bd *)base;
+
+	/*
+	 * Set interrupt mask register
+	 */
+	writel(0x00000000, &fec->eth->imask);
+
+	/*
+	 * Clear FEC-Lite interrupt event register(IEVENT)
+	 */
+	writel(0xffffffff, &fec->eth->ievent);
+
+
+	/*
+	 * Set FEC-Lite receive control register(R_CNTRL):
+	 */
+	if (fec->xcv_type == SEVENWIRE) {
+		/*
+		 * Frame length=1518; 7-wire mode
+		 */
+		writel(0x05ee0020, &fec->eth->r_cntrl);	/* FIXME 0x05ee0000 */
+	} else {
+		/*
+		 * Frame length=1518; MII mode;
+		 */
+		writel(0x05ee0024, &fec->eth->r_cntrl);	/* FIXME 0x05ee0004 */
+		/*
+		 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+		 * and do not drop the Preamble.
+		 */
+		writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1,
+				&fec->eth->mii_speed);
+		debug("fec_init: mii_speed %#lx\n",
+				(((imx_get_ahbclk() / 1000000) + 2) / 5) << 1);
+	}
+	/*
+	 * Set Opcode/Pause Duration Register
+	 */
+	writel(0x00010020, &fec->eth->op_pause);	/* FIXME 0xffff0020; */
+	writel(0x2, &fec->eth->x_wmrk);
+	/*
+	 * Set multicast address filter
+	 */
+	writel(0x00000000, &fec->eth->gaddr1);
+	writel(0x00000000, &fec->eth->gaddr2);
+
+
+	/* clear MIB RAM */
+	long *mib_ptr = (long *)(IMX_FEC_BASE + 0x200);
+	while (mib_ptr <= (long *)(IMX_FEC_BASE + 0x2FC))
+		*mib_ptr++ = 0;
+
+	/* FIFO receive start register */
+	writel(0x520, &fec->eth->r_fstart);
+
+	/* size and address of each buffer */
+	writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr);
+	writel((uint32_t)fec->tbd_base, &fec->eth->etdsr);
+	writel((uint32_t)fec->rbd_base, &fec->eth->erdsr);
+
+	/*
+	 * Initialize RxBD/TxBD rings
+	 */
+	if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) {
+		free(fec->base_ptr);
+		return -ENOMEM;
+	}
+	fec_tbd_init(fec);
+
+
+	if (fec->xcv_type != SEVENWIRE)
+		miiphy_restart_aneg(dev);
+
+	fec_open(dev);
+	return 0;
+}
+
+/**
+ * Halt the FEC engine
+ * @param[in] dev Our device to handle
+ */
+static void fec_halt(struct eth_device *dev)
+{
+	struct fec_priv *fec = &gfec;
+	int counter = 0xffff;
+
+	/*
+	 * issue graceful stop command to the FEC transmitter if necessary
+	 */
+	writel(FEC_ECNTRL_RESET | readl(&fec->eth->x_cntrl),
+			&fec->eth->x_cntrl);
+
+	debug("eth_halt: wait for stop regs\n");
+	/*
+	 * wait for graceful stop to register
+	 */
+	while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA)))
+		;	/* FIXME ensure time */
+
+	/*
+	 * Disable SmartDMA tasks
+	 */
+	fec_tx_task_disable(fec);
+	fec_rx_task_disable(fec);
+
+	/*
+	 * Disable the Ethernet Controller
+	 * Note: this will also reset the BD index counter!
+	 */
+	writel(0, &fec->eth->ecntrl);
+	fec->rbd_index = 0;
+	fec->tbd_index = 0;
+	free(fec->rdb_ptr);
+	free(fec->base_ptr);
+	debug("eth_halt: done\n");
+}
+
+/**
+ * Transmit one frame
+ * @param[in] dev Our ethernet device to handle
+ * @param[in] packet Pointer to the data to be transmitted
+ * @param[in] length Data count in bytes
+ * @return 0 on success
+ */
+static int fec_send(struct eth_device *dev, volatile void* packet, int length)
+{
+	unsigned int status;
+
+	/*
+	 * This routine transmits one frame.  This routine only accepts
+	 * 6-byte Ethernet addresses.
+	 */
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+
+	/*
+	 * Check for valid length of data.
+	 */
+	if ((length > 1500) || (length <= 0)) {
+		printf("Payload (%d) to large!\n", length);
+		return -1;
+	}
+
+	/*
+	 * Setup the transmit buffer
+	 * Note: We are always using the first buffer for transmission,
+	 * the second will be empty and only used to stop the DMA engine
+	 */
+	writew(length, &fec->tbd_base[fec->tbd_index].data_length);
+	writel((uint32_t)packet, &fec->tbd_base[fec->tbd_index].data_pointer);
+	/*
+	 * update BD's status now
+	 * This block:
+	 * - is always the last in a chain (means no chain)
+	 * - should transmitt the CRC
+	 * - might be the last BD in the list, so the address counter should
+	 *   wrap (-> keep the WRAP flag)
+	 */
+	status = readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_WRAP;
+	status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
+	writew(status, &fec->tbd_base[fec->tbd_index].status);
+
+	/*
+	 * Enable SmartDMA transmit task
+	 */
+	fec_tx_task_enable(fec);
+
+	/*
+	 * wait until frame is sent .
+	 */
+	while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) {
+		/* FIXME: Timeout */
+	}
+	debug("fec_send: status 0x%x index %d\n",
+			readw(&fec->tbd_base[fec->tbd_index].status),
+			fec->tbd_index);
+	/* for next transmission use the other buffer */
+	if (fec->tbd_index)
+		fec->tbd_index = 0;
+	else
+		fec->tbd_index = 1;
+
+	return 0;
+}
+
+/**
+ * Pull one frame from the card
+ * @param[in] dev Our ethernet device to handle
+ * @return Length of packet read
+ */
+static int fec_recv(struct eth_device *dev)
+{
+	struct fec_priv *fec = (struct fec_priv *)dev->priv;
+	struct fec_bd *rbd = &fec->rbd_base[fec->rbd_index];
+	unsigned long ievent;
+	int frame_length, len = 0;
+	struct nbuf *frame;
+	uint16_t bd_status;
+	uchar buff[FEC_MAX_PKT_SIZE];
+
+	/*
+	 * Check if any critical events have happened
+	 */
+	ievent = readl(&fec->eth->ievent);
+	writel(ievent, &fec->eth->ievent);
+	debug("fec_recv: ievent 0x%x\n", ievent);
+	if (ievent & FEC_IEVENT_BABR) {
+		fec_halt(dev);
+		fec_init(dev, fec->bd);
+		printf("some error: 0x%08lx\n", ievent);
+		return 0;
+	}
+	if (ievent & FEC_IEVENT_HBERR) {
+		/* Heartbeat error */
+		writel(0x00000001 | readl(&fec->eth->x_cntrl),
+				&fec->eth->x_cntrl);
+	}
+	if (ievent & FEC_IEVENT_GRA) {
+		/* Graceful stop complete */
+		if (readl(&fec->eth->x_cntrl) & 0x00000001) {
+			fec_halt(dev);
+			writel(~0x00000001 & readl(&fec->eth->x_cntrl),
+					&fec->eth->x_cntrl);
+			fec_init(dev, fec->bd);
+		}
+	}
+
+	/*
+	 * ensure reading the right buffer status
+	 */
+	bd_status = readw(&rbd->status);
+	debug("fec_recv: status 0x%x\n", bd_status);
+
+	if (!(bd_status & FEC_RBD_EMPTY)) {
+		if ((bd_status & FEC_RBD_LAST) && !(bd_status & FEC_RBD_ERR) &&
+			((readw(&rbd->data_length) - 4) > 14)) {
+			/*
+			 * Get buffer address and size
+			 */
+			frame = (struct nbuf *)readl(&rbd->data_pointer);
+			frame_length = readw(&rbd->data_length) - 4;
+			/*
+			 *  Fill the buffer and pass it to upper layers
+			 */
+			memcpy(buff, frame->data, frame_length);
+			NetReceive(buff, frame_length);
+			len = frame_length;
+		} else {
+			if (bd_status & FEC_RBD_ERR)
+				printf("error frame: 0x%08lx 0x%08x\n",
+						(ulong)rbd->data_pointer,
+						bd_status);
+		}
+		/*
+		 * free the current buffer, restart the engine
+		 * and move forward to the next buffer
+		 */
+		fec_rbd_clean(fec->rbd_index == (FEC_RBD_NUM - 1) ? 1 : 0, rbd);
+		fec_rx_task_enable(fec);
+		fec->rbd_index = (fec->rbd_index + 1) % FEC_RBD_NUM;
+	}
+	debug("fec_recv: stop\n");
+
+	return len;
+}
+
+static int fec_probe(bd_t *bd)
+{
+	struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
+	struct eth_device *edev;
+	struct fec_priv *fec = &gfec;
+	unsigned char ethaddr_str[20];
+	unsigned char ethaddr[6];
+	char *tmp = getenv("ethaddr");
+	char *end;
+
+	/* enable FEC clock */
+	writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1);
+	writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0);
+
+	/* create and fill edev struct */
+	edev = (struct eth_device *)malloc(sizeof(struct eth_device));
+	if (!edev) {
+		puts("fec_imx27: not enough malloc memory!\n");
+		return -ENOMEM;
+	}
+	edev->priv = fec;
+	edev->init = fec_init;
+	edev->send = fec_send;
+	edev->recv = fec_recv;
+	edev->halt = fec_halt;
+
+	fec->eth = (struct ethernet_regs *)IMX_FEC_BASE;
+	fec->bd = bd;
+
+	fec->xcv_type = MII100;
+
+	/* Reset chip. */
+	writel(FEC_ECNTRL_RESET, &fec->eth->ecntrl);
+	while (readl(&fec->eth->ecntrl) & 1)
+		udelay(10);
+
+	/*
+	 * Set interrupt mask register
+	 */
+	writel(0x00000000, &fec->eth->imask);
+
+	/*
+	 * Clear FEC-Lite interrupt event register(IEVENT)
+	 */
+	writel(0xffffffff, &fec->eth->ievent);
+
+	/*
+	 * Set FEC-Lite receive control register(R_CNTRL):
+	 */
+	/*
+	 * Frame length=1518; MII mode;
+	 */
+	writel(0x05ee0024, &fec->eth->r_cntrl);	/* FIXME 0x05ee0004 */
+	/*
+	 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+	 * and do not drop the Preamble.
+	 */
+	writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1,
+			&fec->eth->mii_speed);
+	debug("fec_init: mii_speed %#lx\n",
+			(((imx_get_ahbclk() / 1000000) + 2) / 5) << 1);
+
+	sprintf(edev->name, "FEC_MXC");
+
+	miiphy_register(edev->name, fec_miiphy_read, fec_miiphy_write);
+
+	eth_register(edev);
+
+	if ((NULL != tmp) && (12 <= strlen(tmp))) {
+		int i;
+		/* convert MAC from string to int */
+		for (i = 0; i < 6; i++) {
+			ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+			if (tmp)
+				tmp = (*end) ? end + 1 : end;
+		}
+	} else if (fec_get_hwaddr(edev, ethaddr) == 0) {
+		printf("got MAC address from EEPROM: %pM\n", ethaddr);
+		setenv("ethaddr", (char *)ethaddr_str);
+	}
+	memcpy(edev->enetaddr, ethaddr, 6);
+	fec_set_hwaddr(edev, ethaddr);
+
+	return 0;
+}
+
+int fecmxc_initialize(bd_t *bd)
+{
+	int lout = 1;
+
+	debug("eth_init: fec_probe(bd)\n");
+	lout = fec_probe(bd);
+
+	return lout;
+}
+
diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h
new file mode 100644
index 0000000000000000000000000000000000000000..6cb1bfc055e620a355b9cd590c9cbb6aba0ca4f5
--- /dev/null
+++ b/drivers/net/fec_mxc.h
@@ -0,0 +1,304 @@
+/*
+ * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
+ * (C) Copyright 2008 Armadeus Systems, nc
+ * (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org>
+ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
+ *
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.h
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+
+#ifndef __FEC_MXC_H
+#define __FEC_MXC_H
+
+/**
+ * Layout description of the FEC
+ */
+struct ethernet_regs {
+
+/* [10:2]addr = 00 */
+
+/*  Control and status Registers (offset 000-1FF) */
+
+	uint32_t res0[1];		/* MBAR_ETH + 0x000 */
+	uint32_t ievent;		/* MBAR_ETH + 0x004 */
+	uint32_t imask;			/* MBAR_ETH + 0x008 */
+
+	uint32_t res1[1];		/* MBAR_ETH + 0x00C */
+	uint32_t r_des_active;		/* MBAR_ETH + 0x010 */
+	uint32_t x_des_active;		/* MBAR_ETH + 0x014 */
+	uint32_t res2[3];		/* MBAR_ETH + 0x018-20 */
+	uint32_t ecntrl;		/* MBAR_ETH + 0x024 */
+
+	uint32_t res3[6];		/* MBAR_ETH + 0x028-03C */
+	uint32_t mii_data;		/* MBAR_ETH + 0x040 */
+	uint32_t mii_speed;		/* MBAR_ETH + 0x044 */
+	uint32_t res4[7];		/* MBAR_ETH + 0x048-60 */
+	uint32_t mib_control;		/* MBAR_ETH + 0x064 */
+
+	uint32_t res5[7];		/* MBAR_ETH + 0x068-80 */
+	uint32_t r_cntrl;		/* MBAR_ETH + 0x084 */
+	uint32_t res6[15];		/* MBAR_ETH + 0x088-C0 */
+	uint32_t x_cntrl;		/* MBAR_ETH + 0x0C4 */
+	uint32_t res7[7];		/* MBAR_ETH + 0x0C8-E0 */
+	uint32_t paddr1;		/* MBAR_ETH + 0x0E4 */
+	uint32_t paddr2;		/* MBAR_ETH + 0x0E8 */
+	uint32_t op_pause;		/* MBAR_ETH + 0x0EC */
+
+	uint32_t res8[10];		/* MBAR_ETH + 0x0F0-114 */
+	uint32_t iaddr1;		/* MBAR_ETH + 0x118 */
+	uint32_t iaddr2;		/* MBAR_ETH + 0x11C */
+	uint32_t gaddr1;		/* MBAR_ETH + 0x120 */
+	uint32_t gaddr2;		/* MBAR_ETH + 0x124 */
+	uint32_t res9[7];		/* MBAR_ETH + 0x128-140 */
+
+	uint32_t x_wmrk;		/* MBAR_ETH + 0x144 */
+	uint32_t res10[1];		/* MBAR_ETH + 0x148 */
+	uint32_t r_bound;		/* MBAR_ETH + 0x14C */
+	uint32_t r_fstart;		/* MBAR_ETH + 0x150 */
+	uint32_t res11[11];		/* MBAR_ETH + 0x154-17C */
+	uint32_t erdsr;			/* MBAR_ETH + 0x180 */
+	uint32_t etdsr;			/* MBAR_ETH + 0x184 */
+	uint32_t emrbr;			/* MBAR_ETH + 0x188 */
+	uint32_t res12[29];		/* MBAR_ETH + 0x18C-1FC */
+
+/*  MIB COUNTERS (Offset 200-2FF) */
+
+	uint32_t rmon_t_drop;		/* MBAR_ETH + 0x200 */
+	uint32_t rmon_t_packets;	/* MBAR_ETH + 0x204 */
+	uint32_t rmon_t_bc_pkt;		/* MBAR_ETH + 0x208 */
+	uint32_t rmon_t_mc_pkt;		/* MBAR_ETH + 0x20C */
+	uint32_t rmon_t_crc_align;	/* MBAR_ETH + 0x210 */
+	uint32_t rmon_t_undersize;	/* MBAR_ETH + 0x214 */
+	uint32_t rmon_t_oversize;	/* MBAR_ETH + 0x218 */
+	uint32_t rmon_t_frag;		/* MBAR_ETH + 0x21C */
+	uint32_t rmon_t_jab;		/* MBAR_ETH + 0x220 */
+	uint32_t rmon_t_col;		/* MBAR_ETH + 0x224 */
+	uint32_t rmon_t_p64;		/* MBAR_ETH + 0x228 */
+	uint32_t rmon_t_p65to127;	/* MBAR_ETH + 0x22C */
+	uint32_t rmon_t_p128to255;	/* MBAR_ETH + 0x230 */
+	uint32_t rmon_t_p256to511;	/* MBAR_ETH + 0x234 */
+	uint32_t rmon_t_p512to1023;	/* MBAR_ETH + 0x238 */
+	uint32_t rmon_t_p1024to2047;	/* MBAR_ETH + 0x23C */
+	uint32_t rmon_t_p_gte2048;	/* MBAR_ETH + 0x240 */
+	uint32_t rmon_t_octets;		/* MBAR_ETH + 0x244 */
+	uint32_t ieee_t_drop;		/* MBAR_ETH + 0x248 */
+	uint32_t ieee_t_frame_ok;	/* MBAR_ETH + 0x24C */
+	uint32_t ieee_t_1col;		/* MBAR_ETH + 0x250 */
+	uint32_t ieee_t_mcol;		/* MBAR_ETH + 0x254 */
+	uint32_t ieee_t_def;		/* MBAR_ETH + 0x258 */
+	uint32_t ieee_t_lcol;		/* MBAR_ETH + 0x25C */
+	uint32_t ieee_t_excol;		/* MBAR_ETH + 0x260 */
+	uint32_t ieee_t_macerr;		/* MBAR_ETH + 0x264 */
+	uint32_t ieee_t_cserr;		/* MBAR_ETH + 0x268 */
+	uint32_t ieee_t_sqe;		/* MBAR_ETH + 0x26C */
+	uint32_t t_fdxfc;		/* MBAR_ETH + 0x270 */
+	uint32_t ieee_t_octets_ok;	/* MBAR_ETH + 0x274 */
+
+	uint32_t res13[2];		/* MBAR_ETH + 0x278-27C */
+	uint32_t rmon_r_drop;		/* MBAR_ETH + 0x280 */
+	uint32_t rmon_r_packets;	/* MBAR_ETH + 0x284 */
+	uint32_t rmon_r_bc_pkt;		/* MBAR_ETH + 0x288 */
+	uint32_t rmon_r_mc_pkt;		/* MBAR_ETH + 0x28C */
+	uint32_t rmon_r_crc_align;	/* MBAR_ETH + 0x290 */
+	uint32_t rmon_r_undersize;	/* MBAR_ETH + 0x294 */
+	uint32_t rmon_r_oversize;	/* MBAR_ETH + 0x298 */
+	uint32_t rmon_r_frag;		/* MBAR_ETH + 0x29C */
+	uint32_t rmon_r_jab;		/* MBAR_ETH + 0x2A0 */
+
+	uint32_t rmon_r_resvd_0;	/* MBAR_ETH + 0x2A4 */
+
+	uint32_t rmon_r_p64;		/* MBAR_ETH + 0x2A8 */
+	uint32_t rmon_r_p65to127;	/* MBAR_ETH + 0x2AC */
+	uint32_t rmon_r_p128to255;	/* MBAR_ETH + 0x2B0 */
+	uint32_t rmon_r_p256to511;	/* MBAR_ETH + 0x2B4 */
+	uint32_t rmon_r_p512to1023;	/* MBAR_ETH + 0x2B8 */
+	uint32_t rmon_r_p1024to2047;	/* MBAR_ETH + 0x2BC */
+	uint32_t rmon_r_p_gte2048;	/* MBAR_ETH + 0x2C0 */
+	uint32_t rmon_r_octets;		/* MBAR_ETH + 0x2C4 */
+	uint32_t ieee_r_drop;		/* MBAR_ETH + 0x2C8 */
+	uint32_t ieee_r_frame_ok;	/* MBAR_ETH + 0x2CC */
+	uint32_t ieee_r_crc;		/* MBAR_ETH + 0x2D0 */
+	uint32_t ieee_r_align;		/* MBAR_ETH + 0x2D4 */
+	uint32_t r_macerr;		/* MBAR_ETH + 0x2D8 */
+	uint32_t r_fdxfc;		/* MBAR_ETH + 0x2DC */
+	uint32_t ieee_r_octets_ok;	/* MBAR_ETH + 0x2E0 */
+
+	uint32_t res14[6];		/* MBAR_ETH + 0x2E4-2FC */
+
+	uint32_t res15[64];		/* MBAR_ETH + 0x300-3FF */
+};
+
+#define FEC_IEVENT_HBERR		0x80000000
+#define FEC_IEVENT_BABR			0x40000000
+#define FEC_IEVENT_BABT			0x20000000
+#define FEC_IEVENT_GRA			0x10000000
+#define FEC_IEVENT_TXF			0x08000000
+#define FEC_IEVENT_TXB			0x04000000
+#define FEC_IEVENT_RXF			0x02000000
+#define FEC_IEVENT_RXB			0x01000000
+#define FEC_IEVENT_MII			0x00800000
+#define FEC_IEVENT_EBERR		0x00400000
+#define FEC_IEVENT_LC			0x00200000
+#define FEC_IEVENT_RL			0x00100000
+#define FEC_IEVENT_UN			0x00080000
+
+#define FEC_IMASK_HBERR			0x80000000
+#define FEC_IMASK_BABR			0x40000000
+#define FEC_IMASKT_BABT			0x20000000
+#define FEC_IMASK_GRA			0x10000000
+#define FEC_IMASKT_TXF			0x08000000
+#define FEC_IMASK_TXB			0x04000000
+#define FEC_IMASKT_RXF			0x02000000
+#define FEC_IMASK_RXB			0x01000000
+#define FEC_IMASK_MII			0x00800000
+#define FEC_IMASK_EBERR			0x00400000
+#define FEC_IMASK_LC			0x00200000
+#define FEC_IMASKT_RL			0x00100000
+#define FEC_IMASK_UN			0x00080000
+
+
+#define FEC_RCNTRL_MAX_FL_SHIFT		16
+#define FEC_RCNTRL_LOOP			0x00000001
+#define FEC_RCNTRL_DRT			0x00000002
+#define FEC_RCNTRL_MII_MODE		0x00000004
+#define FEC_RCNTRL_PROM			0x00000008
+#define FEC_RCNTRL_BC_REJ		0x00000010
+#define FEC_RCNTRL_FCE			0x00000020
+
+#define FEC_TCNTRL_GTS			0x00000001
+#define FEC_TCNTRL_HBC			0x00000002
+#define FEC_TCNTRL_FDEN			0x00000004
+#define FEC_TCNTRL_TFC_PAUSE		0x00000008
+#define FEC_TCNTRL_RFC_PAUSE		0x00000010
+
+#define FEC_ECNTRL_RESET		0x00000001	/* reset the FEC */
+#define FEC_ECNTRL_ETHER_EN		0x00000002	/* enable the FEC */
+
+/**
+ * @brief Descriptor buffer alignment
+ *
+ * i.MX27 requires a 16 byte alignment (but for the first element only)
+ */
+#define DB_ALIGNMENT		16
+
+/**
+ * @brief Data buffer alignment
+ *
+ * i.MX27 requires a four byte alignment for transmit and 16 bits
+ * alignment for receive so take 16
+ * Note: Valid for member data_pointer in struct buffer_descriptor
+ */
+#define DB_DATA_ALIGNMENT	16
+
+/**
+ * @brief Receive & Transmit Buffer Descriptor definitions
+ *
+ * Note: The first BD must be aligned (see DB_ALIGNMENT)
+ */
+struct fec_bd {
+	uint16_t data_length;		/* payload's length in bytes */
+	uint16_t status;		/* BD's staus (see datasheet) */
+	uint32_t data_pointer;		/* payload's buffer address */
+};
+
+/**
+ * Supported phy types on this platform
+ */
+enum xceiver_type {
+	SEVENWIRE,	/* 7-wire       */
+	MII10,		/* MII 10Mbps   */
+	MII100		/* MII 100Mbps  */
+};
+
+/**
+ * @brief i.MX27-FEC private structure
+ */
+struct fec_priv {
+	struct ethernet_regs *eth;	/* pointer to register'S base */
+	enum xceiver_type xcv_type;	/* transceiver type */
+	struct fec_bd *rbd_base;	/* RBD ring */
+	int rbd_index;			/* next receive BD to read */
+	struct fec_bd *tbd_base;	/* TBD ring */
+	int tbd_index;			/* next transmit BD to write */
+	bd_t *bd;
+	void *rdb_ptr;
+	void *base_ptr;
+};
+
+/**
+ * @brief Numbers of buffer descriptors for receiving
+ *
+ * The number defines the stocked memory buffers for the receiving task.
+ * Larger values makes no sense in this limited environment.
+ */
+#define FEC_RBD_NUM		64
+
+/**
+ * @brief Define the ethernet packet size limit in memory
+ *
+ * Note: Do not shrink this number. This will force the FEC to spread larger
+ * frames in more than one BD. This is nothing to worry about, but the current
+ * driver can't handle it.
+ */
+#define FEC_MAX_PKT_SIZE	1536
+
+/* Receive BD status bits */
+#define FEC_RBD_EMPTY	0x8000	/* Receive BD status: Buffer is empty */
+#define FEC_RBD_WRAP	0x2000	/* Receive BD status: Last BD in ring */
+/* Receive BD status: Buffer is last in frame (useless here!) */
+#define FEC_RBD_LAST	0x0800
+#define FEC_RBD_MISS	0x0100	/* Receive BD status: Miss bit for prom mode */
+/* Receive BD status: The received frame is broadcast frame */
+#define FEC_RBD_BC	0x0080
+/* Receive BD status: The received frame is multicast frame */
+#define FEC_RBD_MC	0x0040
+#define FEC_RBD_LG	0x0020	/* Receive BD status: Frame length violation */
+#define FEC_RBD_NO	0x0010	/* Receive BD status: Nonoctet align frame */
+#define FEC_RBD_CR	0x0004	/* Receive BD status: CRC error */
+#define FEC_RBD_OV	0x0002	/* Receive BD status: Receive FIFO overrun */
+#define FEC_RBD_TR	0x0001	/* Receive BD status: Frame is truncated */
+#define FEC_RBD_ERR	(FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
+			FEC_RBD_OV | FEC_RBD_TR)
+
+/* Transmit BD status bits */
+#define FEC_TBD_READY	0x8000	/* Tansmit BD status: Buffer is ready */
+#define FEC_TBD_WRAP	0x2000	/* Tansmit BD status: Mark as last BD in ring */
+#define FEC_TBD_LAST	0x0800	/* Tansmit BD status: Buffer is last in frame */
+#define FEC_TBD_TC	0x0400	/* Tansmit BD status: Transmit the CRC */
+#define FEC_TBD_ABC	0x0200	/* Tansmit BD status: Append bad CRC */
+
+/* MII-related definitios */
+#define FEC_MII_DATA_ST		0x40000000	/* Start of frame delimiter */
+#define FEC_MII_DATA_OP_RD	0x20000000	/* Perform a read operation */
+#define FEC_MII_DATA_OP_WR	0x10000000	/* Perform a write operation */
+#define FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address field mask */
+#define FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register field mask */
+#define FEC_MII_DATA_TA		0x00020000	/* Turnaround */
+#define FEC_MII_DATA_DATAMSK	0x0000ffff	/* PHY data field */
+
+#define FEC_MII_DATA_RA_SHIFT	18	/* MII Register address bits */
+#define FEC_MII_DATA_PA_SHIFT	23	/* MII PHY address bits */
+
+#endif	/* __FEC_MXC_H */
diff --git a/drivers/net/kirkwood_egiga.c b/drivers/net/kirkwood_egiga.c
index 3c5db19cb084fce8ad98505cbf9e5ce685c29ab3..701812bf1c5258175a223fb1896791a588bcbde1 100644
--- a/drivers/net/kirkwood_egiga.c
+++ b/drivers/net/kirkwood_egiga.c
@@ -49,7 +49,7 @@ static int smi_reg_read(char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
 	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
 	struct kwgbe_registers *regs = dkwgbe->regs;
 	u32 smi_reg;
-	volatile u32 timeout;
+	u32 timeout;
 
 	/* Phyadr read request */
 	if (phy_adr == 0xEE && reg_ofs == 0xEE) {
@@ -124,7 +124,7 @@ static int smi_reg_write(char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
 	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
 	struct kwgbe_registers *regs = dkwgbe->regs;
 	u32 smi_reg;
-	volatile u32 timeout;
+	u32 timeout;
 
 	/* Phyadr write request*/
 	if (phy_adr == 0xEE && reg_ofs == 0xEE) {
@@ -370,7 +370,7 @@ static void port_uc_addr_set(struct kwgbe_registers *regs, u8 * p_addr)
  */
 static void kwgbe_init_rx_desc_ring(struct kwgbe_device *dkwgbe)
 {
-	volatile struct kwgbe_rxdesc *p_rx_desc;
+	struct kwgbe_rxdesc *p_rx_desc;
 	int i;
 
 	/* initialize the Rx descriptors ring */
@@ -487,6 +487,7 @@ static int kwgbe_send(struct eth_device *dev, volatile void *dataptr,
 	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
 	struct kwgbe_registers *regs = dkwgbe->regs;
 	struct kwgbe_txdesc *p_txdesc = dkwgbe->p_txdesc;
+	u32 cmd_sts;
 
 	if ((u32) dataptr & 0x07) {
 		printf("Err..(%s) xmit dataptr not 64bit aligned\n",
@@ -507,21 +508,26 @@ static int kwgbe_send(struct eth_device *dev, volatile void *dataptr,
 	/*
 	 * wait for packet xmit completion
 	 */
-	while (p_txdesc->cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA) {
+	cmd_sts = readl(&p_txdesc->cmd_sts);
+	while (cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA) {
 		/* return fail if error is detected */
-		if (p_txdesc->cmd_sts & (KWGBE_UR_ERROR | KWGBE_RL_ERROR)) {
+		if ((cmd_sts & (KWGBE_ERROR_SUMMARY | KWGBE_TX_LAST_FRAME)) ==
+				(KWGBE_ERROR_SUMMARY | KWGBE_TX_LAST_FRAME) &&
+				cmd_sts & (KWGBE_UR_ERROR | KWGBE_RL_ERROR)) {
 			printf("Err..(%s) in xmit packet\n", __FUNCTION__);
 			return -1;
 		}
+		cmd_sts = readl(&p_txdesc->cmd_sts);
 	};
 	return 0;
 }
 
 static int kwgbe_recv(struct eth_device *dev)
 {
-	volatile struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
-	volatile struct kwgbe_rxdesc *p_rxdesc_curr = dkwgbe->p_rxdesc_curr;
-	volatile u32 timeout = 0;
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct kwgbe_rxdesc *p_rxdesc_curr = dkwgbe->p_rxdesc_curr;
+	u32 cmd_sts;
+	u32 timeout = 0;
 
 	/* wait untill rx packet available or timeout */
 	do {
@@ -531,7 +537,7 @@ static int kwgbe_recv(struct eth_device *dev)
 			debug("%s time out...\n", __FUNCTION__);
 			return -1;
 		}
-	} while (p_rxdesc_curr->cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA);
+	} while (readl(&p_rxdesc_curr->cmd_sts) & KWGBE_BUFFER_OWNED_BY_DMA);
 
 	if (p_rxdesc_curr->byte_cnt != 0) {
 		debug("%s: Received %d byte Packet @ 0x%x (cmd_sts= %08x)\n",
@@ -545,14 +551,16 @@ static int kwgbe_recv(struct eth_device *dev)
 	 * OR the error summary bit is on,
 	 * the packets needs to be dropeed.
 	 */
-	if ((p_rxdesc_curr->cmd_sts &
+	cmd_sts = readl(&p_rxdesc_curr->cmd_sts);
+
+	if ((cmd_sts &
 		(KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC))
 		!= (KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC)) {
 
 		printf("Err..(%s) Dropping packet spread on"
 			" multiple descriptors\n", __FUNCTION__);
 
-	} else if (p_rxdesc_curr->cmd_sts & KWGBE_ERROR_SUMMARY) {
+	} else if (cmd_sts & KWGBE_ERROR_SUMMARY) {
 
 		printf("Err..(%s) Dropping packet with errors\n",
 			__FUNCTION__);
@@ -574,7 +582,8 @@ static int kwgbe_recv(struct eth_device *dev)
 	p_rxdesc_curr->buf_size = PKTSIZE_ALIGN;
 	p_rxdesc_curr->byte_cnt = 0;
 
-	dkwgbe->p_rxdesc_curr = p_rxdesc_curr->nxtdesc_p;
+	writel((unsigned)p_rxdesc_curr->nxtdesc_p, &dkwgbe->p_rxdesc_curr);
+
 	return 0;
 }
 
diff --git a/drivers/net/kirkwood_egiga.h b/drivers/net/kirkwood_egiga.h
index 8b67c9c79078ba417afc03b62dd1a890d68b730c..9c893d131831164ae68ce7f92c0bbd69d389cab5 100644
--- a/drivers/net/kirkwood_egiga.h
+++ b/drivers/net/kirkwood_egiga.h
@@ -256,6 +256,7 @@
 #define KWGBE_UR_ERROR			(1 << 1)
 #define KWGBE_RL_ERROR			(1 << 2)
 #define KWGBE_LLC_SNAP_FORMAT		(1 << 9)
+#define KWGBE_TX_LAST_FRAME		(1 << 20)
 
 /* Rx descriptors status */
 #define KWGBE_CRC_ERROR			0
diff --git a/drivers/net/phy/miiphybb.c b/drivers/net/phy/miiphybb.c
index e3c163a349f7eed46ec379c4e2fb3bd00ad2cd3c..b77c917462ad654f53da93d9cf9eac3d0039ecb9 100644
--- a/drivers/net/phy/miiphybb.c
+++ b/drivers/net/phy/miiphybb.c
@@ -127,6 +127,11 @@ int bb_miiphy_read (char *devname, unsigned char addr,
 	volatile ioport_t *iop = ioport_addr ((immap_t *) CONFIG_SYS_IMMR, MDIO_PORT);
 #endif
 
+	if (value == NULL) {
+		puts("NULL value pointer\n");
+		return (-1);
+	}
+
 	miiphy_pre (1, addr, reg);
 
 	/* tri-state our MDIO I/O pin so we can read */
@@ -145,6 +150,8 @@ int bb_miiphy_read (char *devname, unsigned char addr,
 			MDC (1);
 			MIIDELAY;
 		}
+		/* There is no PHY, set value to 0xFFFF and return */
+		*value = 0xFFFF;
 		return (-1);
 	}
 
diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c
index ec47286ddde0e1a49c23bb309d5d536d9204073f..29630f5bf566aad36d80abe6750bf2454c37e8d4 100644
--- a/drivers/net/phy/mv88e61xx.c
+++ b/drivers/net/phy/mv88e61xx.c
@@ -36,7 +36,7 @@
  * By default single chip mode is configured
  * multichip mode operation can be configured in board header
  */
-static int mv88e61xx_busychk_multic(u32 devaddr)
+static int mv88e61xx_busychk_multic(char *name, u32 devaddr)
 {
 	u32 reg = 0;
 	u32 timeout = MV88E61XX_PHY_TIMEOUT;
@@ -58,11 +58,11 @@ static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data)
 	u32 mii_dev_addr;
 
 	/* command to read PHY dev address */
-	if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
+	if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
 		printf("Error..could not read PHY dev address\n");
 		return;
 	}
-	mv88e61xx_busychk_multic(mii_dev_addr);
+	mv88e61xx_busychk_multic(name, mii_dev_addr);
 	/* Write data to Switch indirect data register */
 	miiphy_write(name, mii_dev_addr, 0x1, data);
 	/* Write command to Switch indirect command register (write) */
@@ -77,18 +77,18 @@ static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data)
 	u32 mii_dev_addr;
 
 	/* command to read PHY dev address */
-	if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
+	if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
 		printf("Error..could not read PHY dev address\n");
 		return;
 	}
-	mv88e61xx_busychk_multic(mii_dev_addr);
+	mv88e61xx_busychk_multic(name, mii_dev_addr);
 	/* Write command to Switch indirect command register (read) */
 	miiphy_write(name, mii_dev_addr, 0x0,
-		     reg_ofs | (phy_adr << 5) | (1 << 10) | (1 << 12) | (1 <<
+		     reg_ofs | (phy_adr << 5) | (1 << 11) | (1 << 12) | (1 <<
 									 15));
-	mv88e61xx_busychk_multic(mii_dev_addr);
+	mv88e61xx_busychk_multic(name, mii_dev_addr);
 	/* Read data from Switch indirect data register */
-	miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data);
+	miiphy_read(name, mii_dev_addr, 0x1, data);
 }
 #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
 
@@ -212,7 +212,7 @@ static int mv88e61xx_busychk(char *name)
 			printf("SMI busy timeout\n");
 			return -1;
 		}
-	} while (reg & 1 << 28);	/* busy mask */
+	} while (reg & 1 << 15);	/* busy mask */
 	return 0;
 }
 
diff --git a/drivers/net/phy/mv88e61xx.h b/drivers/net/phy/mv88e61xx.h
index 42794644eca1eec1ab9f928734d9cd0ee7cf25d0..57762b686175f1810184ee2dd2c8caf0591d4026 100644
--- a/drivers/net/phy/mv88e61xx.h
+++ b/drivers/net/phy/mv88e61xx.h
@@ -49,7 +49,7 @@
 #define MV88E61XX_ADDR_OFST		5
 
 #ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE
-static int mv88e61xx_busychk_multic(u32 devaddr);
+static int mv88e61xx_busychk_multic(char *name, u32 devaddr);
 static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data);
 static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data);
 #define WR_PHY mv88e61xx_wr_phy
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index f24ded2730107528c8c4053e46264202ca2bbd73..86cc324e96e716301e242d0a086a9ebd4469e82a 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -546,7 +546,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
 	/* Configure phy */
 	ret = sh_eth_phy_config(eth);
 	if (ret) {
-		printf(SHETHER_NAME ":i phy config timeout\n");
+		printf(SHETHER_NAME ": phy config timeout\n");
 		goto err_phy_cfg;
 	}
 	/* Read phy status to finish configuring the e-mac */
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 8c9a2a8a0572f0bd67d6a0163f912e5a30bf25ad..18a729cfbcab8af2352c1700460f8af201a763a6 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -24,110 +24,90 @@
 
 #include <common.h>
 #include <command.h>
+#include <malloc.h>
 #include <net.h>
 #include <miiphy.h>
 
 #include "smc911x.h"
 
-u32 pkt_data_pull(u32 addr) \
+u32 pkt_data_pull(struct eth_device *dev, u32 addr) \
 	__attribute__ ((weak, alias ("smc911x_reg_read")));
-void pkt_data_push(u32 addr, u32 val) \
+void pkt_data_push(struct eth_device *dev, u32 addr, u32 val) \
 	__attribute__ ((weak, alias ("smc911x_reg_write")));
 
 #define mdelay(n)       udelay((n)*1000)
 
-static int smx911x_handle_mac_address(bd_t *bd)
+static void smx911x_handle_mac_address(struct eth_device *dev)
 {
 	unsigned long addrh, addrl;
-	uchar m[6];
-
-	if (eth_getenv_enetaddr("ethaddr", m)) {
-		/* if the environment has a valid mac address then use it */
-		addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
-		addrh = m[4] | (m[5] << 8);
-		smc911x_set_mac_csr(ADDRL, addrl);
-		smc911x_set_mac_csr(ADDRH, addrh);
-	} else {
-		/* if not, try to get one from the eeprom */
-		addrh = smc911x_get_mac_csr(ADDRH);
-		addrl = smc911x_get_mac_csr(ADDRL);
-
-		m[0] = (addrl       ) & 0xff;
-		m[1] = (addrl >>  8 ) & 0xff;
-		m[2] = (addrl >> 16 ) & 0xff;
-		m[3] = (addrl >> 24 ) & 0xff;
-		m[4] = (addrh       ) & 0xff;
-		m[5] = (addrh >>  8 ) & 0xff;
-
-		/* we get 0xff when there is no eeprom connected */
-		if ((m[0] & m[1] & m[2] & m[3] & m[4] & m[5]) == 0xff) {
-			printf(DRIVERNAME ": no valid mac address in environment "
-				"and no eeprom found\n");
-			return -1;
-		}
-
-		eth_setenv_enetaddr("ethaddr", m);
-	}
+	uchar *m = dev->enetaddr;
 
-	printf(DRIVERNAME ": MAC %pM\n", m);
+	addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
+	addrh = m[4] | (m[5] << 8);
+	smc911x_set_mac_csr(dev, ADDRL, addrl);
+	smc911x_set_mac_csr(dev, ADDRH, addrh);
 
-	return 0;
+	printf(DRIVERNAME ": MAC %pM\n", m);
 }
 
-static int smc911x_miiphy_read(u8 phy, u8 reg, u16 *val)
+static int smc911x_miiphy_read(struct eth_device *dev,
+				u8 phy, u8 reg, u16 *val)
 {
-	while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
+	while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
 		;
 
-	smc911x_set_mac_csr(MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY);
+	smc911x_set_mac_csr(dev, MII_ACC, phy << 11 | reg << 6 |
+				MII_ACC_MII_BUSY);
 
-	while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
+	while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
 		;
 
-	*val = smc911x_get_mac_csr(MII_DATA);
+	*val = smc911x_get_mac_csr(dev, MII_DATA);
 
 	return 0;
 }
 
-static int smc911x_miiphy_write(u8 phy, u8 reg, u16  val)
+static int smc911x_miiphy_write(struct eth_device *dev,
+				u8 phy, u8 reg, u16  val)
 {
-	while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
+	while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
 		;
 
-	smc911x_set_mac_csr(MII_DATA, val);
-	smc911x_set_mac_csr(MII_ACC,
+	smc911x_set_mac_csr(dev, MII_DATA, val);
+	smc911x_set_mac_csr(dev, MII_ACC,
 		phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE);
 
-	while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
+	while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
 		;
 	return 0;
 }
 
-static int smc911x_phy_reset(void)
+static int smc911x_phy_reset(struct eth_device *dev)
 {
 	u32 reg;
 
-	reg = smc911x_reg_read(PMT_CTRL);
+	reg = smc911x_reg_read(dev, PMT_CTRL);
 	reg &= ~0xfffff030;
 	reg |= PMT_CTRL_PHY_RST;
-	smc911x_reg_write(PMT_CTRL, reg);
+	smc911x_reg_write(dev, PMT_CTRL, reg);
 
 	mdelay(100);
 
 	return 0;
 }
 
-static void smc911x_phy_configure(void)
+static void smc911x_phy_configure(struct eth_device *dev)
 {
 	int timeout;
 	u16 status;
 
-	smc911x_phy_reset();
+	smc911x_phy_reset(dev);
 
-	smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_RESET);
+	smc911x_miiphy_write(dev, 1, PHY_BMCR, PHY_BMCR_RESET);
 	mdelay(1);
-	smc911x_miiphy_write(1, PHY_ANAR, 0x01e1);
-	smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
+	smc911x_miiphy_write(dev, 1, PHY_ANAR, 0x01e1);
+	smc911x_miiphy_write(dev, 1, PHY_BMCR, PHY_BMCR_AUTON |
+				PHY_BMCR_RST_NEG);
 
 	timeout = 5000;
 	do {
@@ -135,7 +115,7 @@ static void smc911x_phy_configure(void)
 		if ((timeout--) == 0)
 			goto err_out;
 
-		if (smc911x_miiphy_read(1, PHY_BMSR, &status) != 0)
+		if (smc911x_miiphy_read(dev, 1, PHY_BMSR, &status) != 0)
 			goto err_out;
 	} while (!(status & PHY_BMSR_LS));
 
@@ -147,39 +127,39 @@ err_out:
 	printf(DRIVERNAME ": autonegotiation timed out\n");
 }
 
-static void smc911x_enable(void)
+static void smc911x_enable(struct eth_device *dev)
 {
 	/* Enable TX */
-	smc911x_reg_write(HW_CFG, 8 << 16 | HW_CFG_SF);
+	smc911x_reg_write(dev, HW_CFG, 8 << 16 | HW_CFG_SF);
 
-	smc911x_reg_write(GPT_CFG, GPT_CFG_TIMER_EN | 10000);
+	smc911x_reg_write(dev, GPT_CFG, GPT_CFG_TIMER_EN | 10000);
 
-	smc911x_reg_write(TX_CFG, TX_CFG_TX_ON);
+	smc911x_reg_write(dev, TX_CFG, TX_CFG_TX_ON);
 
 	/* no padding to start of packets */
-	smc911x_reg_write(RX_CFG, 0);
+	smc911x_reg_write(dev, RX_CFG, 0);
 
-	smc911x_set_mac_csr(MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS);
+	smc911x_set_mac_csr(dev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
+				MAC_CR_HBDIS);
 
 }
 
-int eth_init(bd_t *bd)
+static int smc911x_init(struct eth_device *dev, bd_t * bd)
 {
 	printf(DRIVERNAME ": initializing\n");
 
-	if (smc911x_detect_chip())
+	if (smc911x_detect_chip(dev))
 		goto err_out;
 
-	smc911x_reset();
+	smc911x_reset(dev);
 
 	/* Configure the PHY, initialize the link state */
-	smc911x_phy_configure();
+	smc911x_phy_configure(dev);
 
-	if (smx911x_handle_mac_address(bd))
-		goto err_out;
+	smx911x_handle_mac_address(dev);
 
 	/* Turn on Tx + Rx */
-	smc911x_enable();
+	smc911x_enable(dev);
 
 	return 0;
 
@@ -187,28 +167,32 @@ err_out:
 	return -1;
 }
 
-int eth_send(volatile void *packet, int length)
+static int smc911x_send(struct eth_device *dev,
+			volatile void *packet, int length)
 {
 	u32 *data = (u32*)packet;
 	u32 tmplen;
 	u32 status;
 
-	smc911x_reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length);
-	smc911x_reg_write(TX_DATA_FIFO, length);
+	smc911x_reg_write(dev, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG |
+				TX_CMD_A_INT_LAST_SEG | length);
+	smc911x_reg_write(dev, TX_DATA_FIFO, length);
 
 	tmplen = (length + 3) / 4;
 
 	while (tmplen--)
-		pkt_data_push(TX_DATA_FIFO, *data++);
+		pkt_data_push(dev, TX_DATA_FIFO, *data++);
 
 	/* wait for transmission */
-	while (!((smc911x_reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16));
+	while (!((smc911x_reg_read(dev, TX_FIFO_INF) &
+					TX_FIFO_INF_TSUSED) >> 16));
 
 	/* get status. Ignore 'no carrier' error, it has no meaning for
 	 * full duplex operation
 	 */
-	status = smc911x_reg_read(TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL |
-		TX_STS_MANY_COLL | TX_STS_MANY_DEFER | TX_STS_UNDERRUN);
+	status = smc911x_reg_read(dev, TX_STATUS_FIFO) &
+			(TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL |
+			TX_STS_MANY_DEFER | TX_STS_UNDERRUN);
 
 	if (!status)
 		return 0;
@@ -223,26 +207,26 @@ int eth_send(volatile void *packet, int length)
 	return -1;
 }
 
-void eth_halt(void)
+static void smc911x_halt(struct eth_device *dev)
 {
-	smc911x_reset();
+	smc911x_reset(dev);
 }
 
-int eth_rx(void)
+static int smc911x_rx(struct eth_device *dev)
 {
 	u32 *data = (u32 *)NetRxPackets[0];
 	u32 pktlen, tmplen;
 	u32 status;
 
-	if ((smc911x_reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) {
-		status = smc911x_reg_read(RX_STATUS_FIFO);
+	if ((smc911x_reg_read(dev, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) {
+		status = smc911x_reg_read(dev, RX_STATUS_FIFO);
 		pktlen = (status & RX_STS_PKT_LEN) >> 16;
 
-		smc911x_reg_write(RX_CFG, 0);
+		smc911x_reg_write(dev, RX_CFG, 0);
 
 		tmplen = (pktlen + 2+ 3) / 4;
 		while (tmplen--)
-			*data++ = pkt_data_pull(RX_DATA_FIFO);
+			*data++ = pkt_data_pull(dev, RX_DATA_FIFO);
 
 		if (status & RX_STS_ES)
 			printf(DRIVERNAME
@@ -254,3 +238,36 @@ int eth_rx(void)
 
 	return 0;
 }
+
+int smc911x_initialize(u8 dev_num, int base_addr)
+{
+	unsigned long addrl, addrh;
+	struct eth_device *dev;
+
+	dev = malloc(sizeof(*dev));
+	if (!dev) {
+		free(dev);
+		return 0;
+	}
+	memset(dev, 0, sizeof(*dev));
+
+	dev->iobase = base_addr;
+
+	addrh = smc911x_get_mac_csr(dev, ADDRH);
+	addrl = smc911x_get_mac_csr(dev, ADDRL);
+	dev->enetaddr[0] = addrl;
+	dev->enetaddr[1] = addrl >>  8;
+	dev->enetaddr[2] = addrl >> 16;
+	dev->enetaddr[3] = addrl >> 24;
+	dev->enetaddr[4] = addrh;
+	dev->enetaddr[5] = addrh >> 8;
+
+	dev->init = smc911x_init;
+	dev->halt = smc911x_halt;
+	dev->send = smc911x_send;
+	dev->recv = smc911x_rx;
+	sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num);
+
+	eth_register(dev);
+	return 0;
+}
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 80d2ce0aa8451d9db4ab52e6ad1945534ed00028..053e33016bc9929093102f4d641fbcf144aadd86 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -27,45 +27,51 @@
 
 #include <linux/types.h>
 
-#if defined (CONFIG_DRIVER_SMC911X_32_BIT) && \
-	defined (CONFIG_DRIVER_SMC911X_16_BIT)
-#error "SMC911X: Only one of CONFIG_DRIVER_SMC911X_32_BIT and \
-	CONFIG_DRIVER_SMC911X_16_BIT shall be set"
+#define DRIVERNAME "smc911x"
+
+#if defined (CONFIG_SMC911X_32_BIT) && \
+	defined (CONFIG_SMC911X_16_BIT)
+#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \
+	CONFIG_SMC911X_16_BIT shall be set"
 #endif
 
-#if defined (CONFIG_DRIVER_SMC911X_32_BIT)
-static inline u32 __smc911x_reg_read(u32 addr)
+#if defined (CONFIG_SMC911X_32_BIT)
+static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset)
 {
-	return *(volatile u32*)addr;
+	return *(volatile u32*)(dev->iobase + offset);
 }
-u32 smc911x_reg_read(u32 addr) __attribute__((weak, alias("__smc911x_reg_read")));
+u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
+	__attribute__((weak, alias("__smc911x_reg_read")));
 
-static inline void __smc911x_reg_write(u32 addr, u32 val)
+static inline void __smc911x_reg_write(struct eth_device *dev,
+					u32 offset, u32 val)
 {
-	*(volatile u32*)addr = val;
+	*(volatile u32*)(dev->iobase + offset) = val;
 }
-void smc911x_reg_write(u32 addr, u32 val) __attribute__((weak, alias("__smc911x_reg_write")));
-#elif defined (CONFIG_DRIVER_SMC911X_16_BIT)
-static inline u32 smc911x_reg_read(u32 addr)
+void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val)
+	__attribute__((weak, alias("__smc911x_reg_write")));
+#elif defined (CONFIG_SMC911X_16_BIT)
+static inline u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
 {
-	volatile u16 *addr_16 = (u16 *)addr;
+	volatile u16 *addr_16 = (u16 *)(dev->iobase + offset);
 	return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16));
 }
-static inline void smc911x_reg_write(u32 addr, u32 val)
+static inline void smc911x_reg_write(struct eth_device *dev,
+					u32 offset, u32 val)
 {
-	*(volatile u16*)addr = (u16)val;
-	*(volatile u16*)(addr + 2) = (u16)(val >> 16);
+	*(volatile u16 *)(dev->iobase + offset) = (u16)val;
+	*(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16);
 }
 #else
 #error "SMC911X: undefined bus width"
-#endif /* CONFIG_DRIVER_SMC911X_16_BIT */
+#endif /* CONFIG_SMC911X_16_BIT */
 
 /* Below are the register offsets and bit definitions
  * of the Lan911x memory space
  */
-#define RX_DATA_FIFO		 (CONFIG_DRIVER_SMC911X_BASE + 0x00)
+#define RX_DATA_FIFO		 		0x00
 
-#define TX_DATA_FIFO		 (CONFIG_DRIVER_SMC911X_BASE + 0x20)
+#define TX_DATA_FIFO		 		0x20
 #define	TX_CMD_A_INT_ON_COMP			0x80000000
 #define	TX_CMD_A_INT_BUF_END_ALGN		0x03000000
 #define	TX_CMD_A_INT_4_BYTE_ALGN		0x00000000
@@ -80,7 +86,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define	TX_CMD_B_DISABLE_PADDING		0x00001000
 #define	TX_CMD_B_PKT_BYTE_LENGTH		0x000007FF
 
-#define RX_STATUS_FIFO		(CONFIG_DRIVER_SMC911X_BASE + 0x40)
+#define RX_STATUS_FIFO				0x40
 #define	RX_STS_PKT_LEN				0x3FFF0000
 #define	RX_STS_ES				0x00008000
 #define	RX_STS_BCST				0x00002000
@@ -94,8 +100,8 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define	RX_STS_MII_ERR				0x00000008
 #define	RX_STS_DRIBBLING			0x00000004
 #define	RX_STS_CRC_ERR				0x00000002
-#define RX_STATUS_FIFO_PEEK	(CONFIG_DRIVER_SMC911X_BASE + 0x44)
-#define TX_STATUS_FIFO		(CONFIG_DRIVER_SMC911X_BASE + 0x48)
+#define RX_STATUS_FIFO_PEEK			0x44
+#define TX_STATUS_FIFO				0x48
 #define	TX_STS_TAG				0xFFFF0000
 #define	TX_STS_ES				0x00008000
 #define	TX_STS_LOC				0x00000800
@@ -106,21 +112,23 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define	TX_STS_MANY_DEFER			0x00000004
 #define	TX_STS_UNDERRUN				0x00000002
 #define	TX_STS_DEFERRED				0x00000001
-#define TX_STATUS_FIFO_PEEK	(CONFIG_DRIVER_SMC911X_BASE + 0x4C)
-#define ID_REV			(CONFIG_DRIVER_SMC911X_BASE + 0x50)
+#define TX_STATUS_FIFO_PEEK			0x4C
+#define ID_REV					0x50
 #define	ID_REV_CHIP_ID				0xFFFF0000  /* RO */
 #define	ID_REV_REV_ID				0x0000FFFF  /* RO */
 
-#define INT_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x54)
+#define INT_CFG					0x54
 #define	INT_CFG_INT_DEAS			0xFF000000  /* R/W */
 #define	INT_CFG_INT_DEAS_CLR			0x00004000
 #define	INT_CFG_INT_DEAS_STS			0x00002000
 #define	INT_CFG_IRQ_INT				0x00001000  /* RO */
 #define	INT_CFG_IRQ_EN				0x00000100  /* R/W */
-#define	INT_CFG_IRQ_POL				0x00000010  /* R/W Not Affected by SW Reset */
-#define	INT_CFG_IRQ_TYPE			0x00000001  /* R/W Not Affected by SW Reset */
+					/* R/W Not Affected by SW Reset */
+#define	INT_CFG_IRQ_POL				0x00000010
+					/* R/W Not Affected by SW Reset */
+#define	INT_CFG_IRQ_TYPE			0x00000001
 
-#define INT_STS			(CONFIG_DRIVER_SMC911X_BASE + 0x58)
+#define INT_STS					0x58
 #define	INT_STS_SW_INT				0x80000000  /* R/WC */
 #define	INT_STS_TXSTOP_INT			0x02000000  /* R/WC */
 #define	INT_STS_RXSTOP_INT			0x01000000  /* R/WC */
@@ -149,7 +157,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define	INT_STS_GPIO2_INT			0x00000004  /* R/WC */
 #define	INT_STS_GPIO1_INT			0x00000002  /* R/WC */
 #define	INT_STS_GPIO0_INT			0x00000001  /* R/WC */
-#define INT_EN			(CONFIG_DRIVER_SMC911X_BASE + 0x5C)
+#define INT_EN					0x5C
 #define	INT_EN_SW_INT_EN			0x80000000  /* R/W */
 #define	INT_EN_TXSTOP_INT_EN			0x02000000  /* R/W */
 #define	INT_EN_RXSTOP_INT_EN			0x01000000  /* R/W */
@@ -179,14 +187,14 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define	INT_EN_GPIO1_INT			0x00000002  /* R/W */
 #define	INT_EN_GPIO0_INT			0x00000001  /* R/W */
 
-#define BYTE_TEST		(CONFIG_DRIVER_SMC911X_BASE + 0x64)
-#define FIFO_INT		(CONFIG_DRIVER_SMC911X_BASE + 0x68)
+#define BYTE_TEST				0x64
+#define FIFO_INT				0x68
 #define	FIFO_INT_TX_AVAIL_LEVEL			0xFF000000  /* R/W */
 #define	FIFO_INT_TX_STS_LEVEL			0x00FF0000  /* R/W */
 #define	FIFO_INT_RX_AVAIL_LEVEL			0x0000FF00  /* R/W */
 #define	FIFO_INT_RX_STS_LEVEL			0x000000FF  /* R/W */
 
-#define RX_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x6C)
+#define RX_CFG					0x6C
 #define	RX_CFG_RX_END_ALGN			0xC0000000  /* R/W */
 #define		RX_CFG_RX_END_ALGN4		0x00000000  /* R/W */
 #define		RX_CFG_RX_END_ALGN16		0x40000000  /* R/W */
@@ -196,16 +204,17 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define	RX_CFG_RXDOFF				0x00001F00  /* R/W */
 /*#define	RX_CFG_RXBAD			0x00000001*/  /* R/W */
 
-#define TX_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x70)
+#define TX_CFG					0x70
 /*#define	TX_CFG_TX_DMA_LVL		0xE0000000*/	 /* R/W */
-/*#define	TX_CFG_TX_DMA_CNT		0x0FFF0000*/	 /* R/W Self Clearing */
+						 /* R/W Self Clearing */
+/*#define	TX_CFG_TX_DMA_CNT		0x0FFF0000*/
 #define	TX_CFG_TXS_DUMP				0x00008000  /* Self Clearing */
 #define	TX_CFG_TXD_DUMP				0x00004000  /* Self Clearing */
 #define	TX_CFG_TXSAO				0x00000004  /* R/W */
 #define	TX_CFG_TX_ON				0x00000002  /* R/W */
 #define	TX_CFG_STOP_TX				0x00000001  /* Self Clearing */
 
-#define HW_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x74)
+#define HW_CFG					0x74
 #define	HW_CFG_TTM				0x00200000  /* R/W */
 #define	HW_CFG_SF				0x00100000  /* R/W */
 #define	HW_CFG_TX_FIF_SZ			0x000F0000  /* R/W */
@@ -221,24 +230,25 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define	HW_CFG_SRST_TO				0x00000002  /* RO */
 #define	HW_CFG_SRST				0x00000001  /* Self Clearing */
 
-#define RX_DP_CTRL		(CONFIG_DRIVER_SMC911X_BASE + 0x78)
+#define RX_DP_CTRL				0x78
 #define	RX_DP_CTRL_RX_FFWD			0x80000000  /* R/W */
 #define	RX_DP_CTRL_FFWD_BUSY			0x80000000  /* RO */
 
-#define RX_FIFO_INF		(CONFIG_DRIVER_SMC911X_BASE + 0x7C)
+#define RX_FIFO_INF				0x7C
 #define	 RX_FIFO_INF_RXSUSED			0x00FF0000  /* RO */
 #define	 RX_FIFO_INF_RXDUSED			0x0000FFFF  /* RO */
 
-#define TX_FIFO_INF		(CONFIG_DRIVER_SMC911X_BASE + 0x80)
+#define TX_FIFO_INF				0x80
 #define	TX_FIFO_INF_TSUSED			0x00FF0000  /* RO */
 #define	TX_FIFO_INF_TDFREE			0x0000FFFF  /* RO */
 
-#define PMT_CTRL		(CONFIG_DRIVER_SMC911X_BASE + 0x84)
+#define PMT_CTRL				0x84
 #define	PMT_CTRL_PM_MODE			0x00003000  /* Self Clearing */
 #define	PMT_CTRL_PHY_RST			0x00000400  /* Self Clearing */
 #define	PMT_CTRL_WOL_EN				0x00000200  /* R/W */
 #define	PMT_CTRL_ED_EN				0x00000100  /* R/W */
-#define	PMT_CTRL_PME_TYPE			0x00000040  /* R/W Not Affected by SW Reset */
+					/* R/W Not Affected by SW Reset */
+#define	PMT_CTRL_PME_TYPE			0x00000040
 #define	PMT_CTRL_WUPS				0x00000030  /* R/WC */
 #define	PMT_CTRL_WUPS_NOWAKE			0x00000000  /* R/WC */
 #define	PMT_CTRL_WUPS_ED			0x00000010  /* R/WC */
@@ -246,10 +256,11 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define	PMT_CTRL_WUPS_MULTI			0x00000030  /* R/WC */
 #define	PMT_CTRL_PME_IND			0x00000008  /* R/W */
 #define	PMT_CTRL_PME_POL			0x00000004  /* R/W */
-#define	PMT_CTRL_PME_EN				0x00000002  /* R/W Not Affected by SW Reset */
+					/* R/W Not Affected by SW Reset */
+#define	PMT_CTRL_PME_EN				0x00000002
 #define	PMT_CTRL_READY				0x00000001  /* RO */
 
-#define GPIO_CFG		(CONFIG_DRIVER_SMC911X_BASE + 0x88)
+#define GPIO_CFG				0x88
 #define	GPIO_CFG_LED3_EN			0x40000000  /* R/W */
 #define	GPIO_CFG_LED2_EN			0x20000000  /* R/W */
 #define	GPIO_CFG_LED1_EN			0x10000000  /* R/W */
@@ -269,23 +280,23 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define	GPIO_CFG_GPIOD1				0x00000002  /* R/W */
 #define	GPIO_CFG_GPIOD0				0x00000001  /* R/W */
 
-#define GPT_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x8C)
+#define GPT_CFG					0x8C
 #define	GPT_CFG_TIMER_EN			0x20000000  /* R/W */
 #define	GPT_CFG_GPT_LOAD			0x0000FFFF  /* R/W */
 
-#define GPT_CNT			(CONFIG_DRIVER_SMC911X_BASE + 0x90)
+#define GPT_CNT					0x90
 #define	GPT_CNT_GPT_CNT				0x0000FFFF  /* RO */
 
-#define ENDIAN			(CONFIG_DRIVER_SMC911X_BASE + 0x98)
-#define FREE_RUN		(CONFIG_DRIVER_SMC911X_BASE + 0x9C)
-#define RX_DROP			(CONFIG_DRIVER_SMC911X_BASE + 0xA0)
-#define MAC_CSR_CMD		(CONFIG_DRIVER_SMC911X_BASE + 0xA4)
+#define ENDIAN					0x98
+#define FREE_RUN				0x9C
+#define RX_DROP					0xA0
+#define MAC_CSR_CMD				0xA4
 #define	 MAC_CSR_CMD_CSR_BUSY			0x80000000  /* Self Clearing */
 #define	 MAC_CSR_CMD_R_NOT_W			0x40000000  /* R/W */
 #define	 MAC_CSR_CMD_CSR_ADDR			0x000000FF  /* R/W */
 
-#define MAC_CSR_DATA		(CONFIG_DRIVER_SMC911X_BASE + 0xA8)
-#define AFC_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0xAC)
+#define MAC_CSR_DATA				0xA8
+#define AFC_CFG					0xAC
 #define		AFC_CFG_AFC_HI			0x00FF0000  /* R/W */
 #define		AFC_CFG_AFC_LO			0x0000FF00  /* R/W */
 #define		AFC_CFG_BACK_DUR		0x000000F0  /* R/W */
@@ -294,7 +305,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define		AFC_CFG_FCADD			0x00000002  /* R/W */
 #define		AFC_CFG_FCANY			0x00000001  /* R/W */
 
-#define E2P_CMD			(CONFIG_DRIVER_SMC911X_BASE + 0xB0)
+#define E2P_CMD					0xB0
 #define		E2P_CMD_EPC_BUSY		0x80000000  /* Self Clearing */
 #define		E2P_CMD_EPC_CMD			0x70000000  /* R/W */
 #define		E2P_CMD_EPC_CMD_READ		0x00000000  /* R/W */
@@ -309,7 +320,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define		E2P_CMD_MAC_ADDR_LOADED		0x00000100  /* RO */
 #define		E2P_CMD_EPC_ADDR		0x000000FF  /* R/W */
 
-#define E2P_DATA		(CONFIG_DRIVER_SMC911X_BASE + 0xB4)
+#define E2P_DATA				0xB4
 #define	E2P_DATA_EEPROM_DATA			0x000000FF  /* R/W */
 /* end of LAN register offsets and bit definitions */
 
@@ -382,6 +393,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
 #define CHIP_9216	0x116a
 #define CHIP_9217	0x117a
 #define CHIP_9218	0x118a
+#define CHIP_9221	0x9221
 
 struct chip_id {
 	u16 id;
@@ -398,44 +410,43 @@ static const struct chip_id chip_ids[] =  {
 	{ CHIP_9216, "LAN9216" },
 	{ CHIP_9217, "LAN9217" },
 	{ CHIP_9218, "LAN9218" },
+	{ CHIP_9221, "LAN9221" },
 	{ 0, NULL },
 };
 
-
-#define DRIVERNAME "smc911x"
-
-static u32 smc911x_get_mac_csr(u8 reg)
+static u32 smc911x_get_mac_csr(struct eth_device *dev, u8 reg)
 {
-	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+	while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
 		;
-	smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
-	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+	smc911x_reg_write(dev, MAC_CSR_CMD,
+			MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
+	while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
 		;
 
-	return smc911x_reg_read(MAC_CSR_DATA);
+	return smc911x_reg_read(dev, MAC_CSR_DATA);
 }
 
-static void smc911x_set_mac_csr(u8 reg, u32 data)
+static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data)
 {
-	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+	while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
 		;
-	smc911x_reg_write(MAC_CSR_DATA, data);
-	smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
-	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+	smc911x_reg_write(dev, MAC_CSR_DATA, data);
+	smc911x_reg_write(dev, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
+	while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
 		;
 }
 
-static int smc911x_detect_chip(void)
+static int smc911x_detect_chip(struct eth_device *dev)
 {
 	unsigned long val, i;
 
-	val = smc911x_reg_read(BYTE_TEST);
+	val = smc911x_reg_read(dev, BYTE_TEST);
 	if (val != 0x87654321) {
 		printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
 		return -1;
 	}
 
-	val = smc911x_reg_read(ID_REV) >> 16;
+	val = smc911x_reg_read(dev, ID_REV) >> 16;
 	for (i = 0; chip_ids[i].id != 0; i++) {
 		if (chip_ids[i].id == val) break;
 	}
@@ -449,18 +460,19 @@ static int smc911x_detect_chip(void)
 	return 0;
 }
 
-static void smc911x_reset(void)
+static void smc911x_reset(struct eth_device *dev)
 {
 	int timeout;
 
 	/* Take out of PM setting first */
-	if (smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY) {
+	if (smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY) {
 		/* Write to the bytetest will take out of powerdown */
-		smc911x_reg_write(BYTE_TEST, 0x0);
+		smc911x_reg_write(dev, BYTE_TEST, 0x0);
 
 		timeout = 10;
 
-		while (timeout-- && !(smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY))
+		while (timeout-- &&
+			!(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY))
 			udelay(10);
 		if (!timeout) {
 			printf(DRIVERNAME
@@ -470,12 +482,12 @@ static void smc911x_reset(void)
 	}
 
 	/* Disable interrupts */
-	smc911x_reg_write(INT_EN, 0);
+	smc911x_reg_write(dev, INT_EN, 0);
 
-	smc911x_reg_write(HW_CFG, HW_CFG_SRST);
+	smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST);
 
 	timeout = 1000;
-	while (timeout-- && smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
+	while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
 		udelay(10);
 
 	if (!timeout) {
@@ -484,11 +496,11 @@ static void smc911x_reset(void)
 	}
 
 	/* Reset the FIFO level and flow control settings */
-	smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN);
-	smc911x_reg_write(AFC_CFG, 0x0050287F);
+	smc911x_set_mac_csr(dev, FLOW, FLOW_FCPT | FLOW_FCEN);
+	smc911x_reg_write(dev, AFC_CFG, 0x0050287F);
 
 	/* Set to LED outputs */
-	smc911x_reg_write(GPIO_CFG, 0x70070000);
+	smc911x_reg_write(dev, GPIO_CFG, 0x70070000);
 }
 
 #endif
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 63fc02e44d1be1980145e0382772ee9ad4022855..29902d315e24f38ebecf862845850e99aaef3476 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -5,7 +5,7 @@
  * terms of the GNU Public License, Version 2, incorporated
  * herein by reference.
  *
- * Copyright 2004, 2007 Freescale Semiconductor, Inc.
+ * Copyright (C) 2004-2009 Freescale Semiconductor, Inc. All rights reserved.
  * (C) Copyright 2003, Motorola, Inc.
  * author Andy Fleming
  *
@@ -197,7 +197,10 @@ int tsec_init(struct eth_device *dev, bd_t * bd)
 	for (i = 0; i < MAC_ADDR_LEN; i++) {
 		tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
 	}
-	regs->macstnaddr1 = *((uint *) (tmpbuf));
+	tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
+		  tmpbuf[3];
+
+	regs->macstnaddr1 = tempval;
 
 	tempval = *((uint *) (tmpbuf + 4));
 
@@ -1426,6 +1429,54 @@ struct phy_info phy_info_VSC8244 = {
 			   },
 };
 
+struct phy_info phy_info_VSC8641 = {
+	0x7043,
+	"Vitesse VSC8641",
+	4,
+	(struct phy_cmd[]){	/* config */
+			   /* Configure some basic stuff */
+			   {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Read the Status (2x to make sure link is right) */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the status */
+			   {MIIM_VSC8244_AUX_CONSTAT, miim_read,
+			    &mii_parse_vsc8244},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+
+struct phy_info phy_info_VSC8221 = {
+	0xfc55,
+	"Vitesse VSC8221",
+	4,
+	(struct phy_cmd[]){	/* config */
+			   /* Configure some basic stuff */
+			   {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* startup */
+			   /* Read the Status (2x to make sure link is right) */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the status */
+			   {MIIM_VSC8244_AUX_CONSTAT, miim_read,
+			    &mii_parse_vsc8244},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]){	/* shutdown */
+			   {miim_end,}
+			   },
+};
+
 struct phy_info phy_info_VSC8601 = {
 		0x00007042,
 		"Vitesse VSC8601",
@@ -1663,6 +1714,8 @@ struct phy_info *phy_info[] = {
 	&phy_info_VSC8211,
 	&phy_info_VSC8244,
 	&phy_info_VSC8601,
+	&phy_info_VSC8641,
+	&phy_info_VSC8221,
 	&phy_info_dp83865,
 	&phy_info_rtl8211b,
 	&phy_info_generic,	/* must be last; has ID 0 and 32 bit mask */
diff --git a/include/configs/ap325rxa.h b/include/configs/ap325rxa.h
index 6f58a05692ff60eff7e2334334cea504fa834ed0..70dd47ecb56b0886fd03b385fa9ff437fa54de13 100644
--- a/include/configs/ap325rxa.h
+++ b/include/configs/ap325rxa.h
@@ -53,9 +53,10 @@
 #undef  CONFIG_SHOW_BOOT_PROGRESS
 
 /* SMC9118 */
-#define CONFIG_DRIVER_SMC911X 1
-#define CONFIG_DRIVER_SMC911X_32_BIT 1
-#define CONFIG_DRIVER_SMC911X_BASE 0xB6080000
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X 1
+#define CONFIG_SMC911X_32_BIT 1
+#define CONFIG_SMC911X_BASE 0xB6080000
 
 /* MEMORY */
 #define AP325RXA_SDRAM_BASE		(0x88000000)
diff --git a/include/configs/bf548-ezkit.h b/include/configs/bf548-ezkit.h
index dbcd2afb0d26584e699753ae23efca130b371e29..5b9de169581204c13cbd4c14ca2a11a7b3e4d000 100644
--- a/include/configs/bf548-ezkit.h
+++ b/include/configs/bf548-ezkit.h
@@ -69,9 +69,10 @@
  * Network Settings
  */
 #define ADI_CMDS_NETWORK	1
-#define CONFIG_DRIVER_SMC911X	1
-#define CONFIG_DRIVER_SMC911X_BASE	0x24000000
-#define CONFIG_DRIVER_SMC911X_16_BIT
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X	1
+#define CONFIG_SMC911X_BASE	0x24000000
+#define CONFIG_SMC911X_16_BIT
 #define CONFIG_HOSTNAME		bf548-ezkit
 /* Uncomment next line to use fixed MAC address */
 /* #define CONFIG_ETHADDR	02:80:ad:20:31:e8 */
diff --git a/include/configs/cm-bf548.h b/include/configs/cm-bf548.h
index 93c2239ea868a8118ac96badb777ac200cc00a94..b5cfc2199e2cfcd0650d305412d9bddc4fd1a536 100644
--- a/include/configs/cm-bf548.h
+++ b/include/configs/cm-bf548.h
@@ -69,9 +69,10 @@
  * Network Settings
  */
 #define ADI_CMDS_NETWORK	1
-#define CONFIG_DRIVER_SMC911X	1
-#define CONFIG_DRIVER_SMC911X_BASE	0x24000000
-#define CONFIG_DRIVER_SMC911X_16_BIT
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X	1
+#define CONFIG_SMC911X_BASE	0x24000000
+#define CONFIG_SMC911X_16_BIT
 #define CONFIG_HOSTNAME		cm-bf548
 /* Uncomment next line to use fixed MAC address */
 /* #define CONFIG_ETHADDR	02:80:ad:24:31:91 */
diff --git a/include/configs/imx31_litekit.h b/include/configs/imx31_litekit.h
index 74f54c0c785a5217b61df56a1fde820fdd978621..61310089b7b0bf2af2eb4e5117435939f329d7a1 100644
--- a/include/configs/imx31_litekit.h
+++ b/include/configs/imx31_litekit.h
@@ -104,9 +104,10 @@
 	"prg_uboot=tftpboot 0x80000000 u-boot-imx31_litekit.bin; protect off all; erase 0xa00d0000 0xa01effff; cp.b 0x80000000 0xa00d0000 $(filesize)\0"
 
 
-#define CONFIG_DRIVER_SMC911X		1
-#define CONFIG_DRIVER_SMC911X_BASE	(CS4_BASE + 0x00020000)
-#define CONFIG_DRIVER_SMC911X_32_BIT	1
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X		1
+#define CONFIG_SMC911X_BASE	(CS4_BASE + 0x00020000)
+#define CONFIG_SMC911X_32_BIT	1
 
 /*
  * Miscellaneous configurable options
diff --git a/include/configs/imx31_phycore.h b/include/configs/imx31_phycore.h
index cb42a7cc96bbadbeea7055e8b8c19be3dbb30d7f..1dbafa0521ce59c21148fe173169c9dc13a254f3 100644
--- a/include/configs/imx31_phycore.h
+++ b/include/configs/imx31_phycore.h
@@ -106,9 +106,10 @@
 	"prg_jffs2=tftpboot 0x80000000 $(jffs2); erase 0xa01c0000 0xa1ffffff; cp.b 0x80000000 0xa01c0000 $(filesize)\0"
 
 
-#define CONFIG_DRIVER_SMC911X		1
-#define CONFIG_DRIVER_SMC911X_BASE	0xa8000000
-#define CONFIG_DRIVER_SMC911X_32_BIT	1
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X		1
+#define CONFIG_SMC911X_BASE	0xa8000000
+#define CONFIG_SMC911X_32_BIT	1
 
 /*
  * Miscellaneous configurable options
diff --git a/include/configs/mx31pdk.h b/include/configs/mx31pdk.h
index a4862c6fc5a204b325a0da6c7ef2e32dd634d63c..fb61432e7ff79056bed66a4669fdae6414f2efc7 100644
--- a/include/configs/mx31pdk.h
+++ b/include/configs/mx31pdk.h
@@ -106,9 +106,10 @@
 	"bootcmd_net=run bootargs_base bootargs_mtd bootargs_nfs; "	\
 		"tftpboot 0x81000000 uImage-mx31; bootm\0"
 
-#define CONFIG_DRIVER_SMC911X		1
-#define CONFIG_DRIVER_SMC911X_BASE	0xB6000000
-#define CONFIG_DRIVER_SMC911X_32_BIT	1
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X		1
+#define CONFIG_SMC911X_BASE	0xB6000000
+#define CONFIG_SMC911X_32_BIT	1
 
 /*
  * Miscellaneous configurable options
diff --git a/include/configs/omap3_evm.h b/include/configs/omap3_evm.h
index 198c3d1fd2c4c3a541babd0d664ac30e9941848d..3d9d72caf3bc4a3b40b0503f714b79fccd707069 100644
--- a/include/configs/omap3_evm.h
+++ b/include/configs/omap3_evm.h
@@ -302,9 +302,10 @@ extern unsigned int boot_flash_type;
  */
 #if defined(CONFIG_CMD_NET)
 
-#define CONFIG_DRIVER_SMC911X
-#define CONFIG_DRIVER_SMC911X_32_BIT
-#define CONFIG_DRIVER_SMC911X_BASE	0x2C000000
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X
+#define CONFIG_SMC911X_32_BIT
+#define CONFIG_SMC911X_BASE	0x2C000000
 
 #endif /* (CONFIG_CMD_NET) */
 
diff --git a/include/configs/rsk7203.h b/include/configs/rsk7203.h
index 36e4c017bbe716aee75c9ed0f9941dcf83b3b1dd..9aa71b4496a6e84e539c0a85ffd0e1aab940593a 100644
--- a/include/configs/rsk7203.h
+++ b/include/configs/rsk7203.h
@@ -105,8 +105,9 @@
 #define CONFIG_SYS_HZ			(CONFIG_SYS_CLK_FREQ / CMT_CLK_DIVIDER)
 
 /* Network interface */
-#define CONFIG_DRIVER_SMC911X
-#define CONFIG_DRIVER_SMC911X_16_BIT
-#define CONFIG_DRIVER_SMC911X_BASE (0x24000000)
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X
+#define CONFIG_SMC911X_16_BIT
+#define CONFIG_SMC911X_BASE (0x24000000)
 
 #endif	/* __RSK7203_H */
diff --git a/include/configs/vct.h b/include/configs/vct.h
index e72b504549460a603723a92e1c2d5a643a534bc6..20bf48148a8b782a6a6082ae6ee7190ba7625c7f 100644
--- a/include/configs/vct.h
+++ b/include/configs/vct.h
@@ -89,10 +89,11 @@
 /*
  * SMSC91C11x Network Card
  */
-#define CONFIG_DRIVER_SMC911X
-#define CONFIG_DRIVER_SMC911X_BASE	0x00000000
-#define CONFIG_DRIVER_SMC911X_32_BIT
+#define CONFIG_SMC911X
+#define CONFIG_SMC911X_BASE	0x00000000
+#define CONFIG_SMC911X_32_BIT
 #define CONFIG_NET_RETRY_COUNT		20
+#define CONFIG_NET_MULTI
 #endif
 
 /*
@@ -342,7 +343,7 @@ int vct_gpio_get(int pin);
 #undef CONFIG_CMD_TERMINAL
 #undef CONFIG_CMD_USB
 
-#undef CONFIG_DRIVER_SMC911X
+#undef CONFIG_SMC911X
 #undef CONFIG_SOFT_I2C
 #undef CONFIG_SOURCE
 #undef CONFIG_SYS_LONGHELP
diff --git a/include/net.h b/include/net.h
index 5a1d36ee3113c57bb3a3fd51f77edeb7fdebe42d..4a03717ae9bcd99efe80e75956e1905e1c0b0c74 100644
--- a/include/net.h
+++ b/include/net.h
@@ -331,8 +331,8 @@ extern IPaddr_t		NetOurIP;		/* Our    IP addr (0 = unknown)	*/
 extern IPaddr_t		NetServerIP;		/* Server IP addr (0 = unknown)	*/
 extern volatile uchar * NetTxPacket;		/* THE transmit packet		*/
 extern volatile uchar * NetRxPackets[PKTBUFSRX];/* Receive packets		*/
-extern volatile uchar * NetRxPkt;		/* Current receive packet	*/
-extern int		NetRxPktLen;		/* Current rx packet length	*/
+extern volatile uchar * NetRxPacket;		/* Current receive packet	*/
+extern int		NetRxPacketLen;		/* Current rx packet length	*/
 extern unsigned		NetIPID;		/* IP ID (counting)		*/
 extern uchar		NetBcastAddr[6];	/* Ethernet boardcast address	*/
 extern uchar		NetEtherNullAddr[6];
@@ -361,6 +361,11 @@ typedef enum { BOOTP, RARP, ARP, TFTP, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP
 /* from net/net.c */
 extern char	BootFile[128];			/* Boot File name		*/
 
+#if defined(CONFIG_CMD_DNS)
+extern char *NetDNSResolve;		/* The host to resolve  */
+extern char *NetDNSenvvar;		/* the env var to put the ip into */
+#endif
+
 #if defined(CONFIG_CMD_PING)
 extern IPaddr_t	NetPingIP;			/* the ip address to ping		*/
 #endif
diff --git a/include/netdev.h b/include/netdev.h
index 17fdafba835e97c91e42fd945a5125dc4cf9dcf5..3e66586b4fd51799ceb75e119ef216f606398df7 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -50,6 +50,7 @@ int e1000_initialize(bd_t *bis);
 int eepro100_initialize(bd_t *bis);
 int eth_3com_initialize (bd_t * bis);
 int fec_initialize (bd_t *bis);
+int fecmxc_initialize (bd_t *bis);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
@@ -71,6 +72,7 @@ int rtl8139_initialize(bd_t *bis);
 int rtl8169_initialize(bd_t *bis);
 int scc_initialize(bd_t *bis);
 int skge_initialize(bd_t *bis);
+int smc911x_initialize(u8 dev_num, int base_addr);
 int tsi108_eth_initialize(bd_t *bis);
 int uec_initialize(int index);
 int uec_standard_init(bd_t *bis);
diff --git a/net/Makefile b/net/Makefile
index d3418742502e463c6ee96e8d342a3d127328b00b..835a04af4552f5813efddca4aa24c6455c856458 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -27,13 +27,14 @@ include $(TOPDIR)/config.mk
 
 LIB	= $(obj)libnet.a
 
-COBJS-y += net.o
-COBJS-y += tftp.o
 COBJS-y += bootp.o
-COBJS-y += rarp.o
+COBJS-$(CONFIG_CMD_DNS)  += dns.o
 COBJS-y += eth.o
+COBJS-y += net.o
 COBJS-y += nfs.o
+COBJS-y += rarp.o
 COBJS-$(CONFIG_CMD_SNTP) += sntp.o
+COBJS-y += tftp.o
 
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
diff --git a/net/bootp.c b/net/bootp.c
index 77057c6c0a7b2c51e29dc4ed0482a6f8d1cd5992..d5f9c4be6d32dffb3508f9a70a9c0988bc98917c 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -124,7 +124,7 @@ static void BootpCopyNetParams(Bootp_t *bp)
 	NetCopyIP(&tmp_ip, &bp->bp_siaddr);
 	if (tmp_ip != 0)
 		NetCopyIP(&NetServerIP, &bp->bp_siaddr);
-	memcpy (NetServerEther, ((Ethernet_t *)NetRxPkt)->et_src, 6);
+	memcpy (NetServerEther, ((Ethernet_t *)NetRxPacket)->et_src, 6);
 #endif
 	if (strlen(bp->bp_file) > 0)
 		copy_filename (BootFile, bp->bp_file, sizeof(BootFile));
diff --git a/net/dns.c b/net/dns.c
new file mode 100644
index 0000000000000000000000000000000000000000..f25c3f8c247c937fe128d75224f822da347e3bcf
--- /dev/null
+++ b/net/dns.c
@@ -0,0 +1,211 @@
+/*
+ * DNS support driver
+ *
+ * Copyright (c) 2008 Pieter Voorthuijsen <pieter.voorthuijsen@prodrive.nl>
+ * Copyright (c) 2009 Robin Getz <rgetz@blackfin.uclinux.org>
+ *
+ * This is a simple DNS implementation for U-Boot. It will use the first IP
+ * in the DNS response as NetServerIP. This can then be used for any other
+ * network related activities.
+ *
+ * The packet handling is partly based on TADNS, original copyrights
+ * follow below.
+ *
+ */
+
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+
+#include "dns.h"
+
+char *NetDNSResolve;	/* The host to resolve  */
+char *NetDNSenvvar;	/* The envvar to store the answer in */
+
+static int DnsOurPort;
+
+static void
+DnsSend(void)
+{
+	struct header *header;
+	int n, name_len;
+	uchar *p, *pkt;
+	const char *s;
+	const char *name;
+	enum dns_query_type qtype = DNS_A_RECORD;
+
+	name = NetDNSResolve;
+	pkt = p = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE);
+
+	/* Prepare DNS packet header */
+	header           = (struct header *) pkt;
+	header->tid      = 1;
+	header->flags    = htons(0x100);	/* standard query */
+	header->nqueries = htons(1);		/* Just one query */
+	header->nanswers = 0;
+	header->nauth    = 0;
+	header->nother   = 0;
+
+	/* Encode DNS name */
+	name_len = strlen(name);
+	p = (uchar *) &header->data;	/* For encoding host name into packet */
+
+	do {
+		s = strchr(name, '.');
+		if (!s)
+			s = name + name_len;
+
+		n = s - name;			/* Chunk length */
+		*p++ = n;			/* Copy length  */
+		memcpy(p, name, n);		/* Copy chunk   */
+		p += n;
+
+		if (*s == '.')
+			n++;
+
+		name += n;
+		name_len -= n;
+	} while (*s != '\0');
+
+	*p++ = 0;			/* Mark end of host name */
+	*p++ = 0;			/* Some servers require double null */
+	*p++ = (unsigned char) qtype;	/* Query Type */
+
+	*p++ = 0;
+	*p++ = 1;				/* Class: inet, 0x0001 */
+
+	n = p - pkt;				/* Total packet length */
+	debug("Packet size %d\n", n);
+
+	DnsOurPort = random_port();
+
+	NetSendUDPPacket(NetServerEther, NetOurDNSIP, DNS_SERVICE_PORT,
+		DnsOurPort, n);
+	debug("DNS packet sent\n");
+}
+
+static void
+DnsTimeout(void)
+{
+	puts("Timeout\n");
+	NetState = NETLOOP_FAIL;
+}
+
+static void
+DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len)
+{
+	struct header *header;
+	const unsigned char *p, *e, *s;
+	u16 type, i;
+	int found, stop, dlen;
+	char IPStr[22];
+	IPaddr_t IPAddress;
+	short tmp;
+
+
+	debug("%s\n", __func__);
+	if (dest != DnsOurPort)
+		return;
+
+	for (i = 0; i < len; i += 4)
+		debug("0x%p - 0x%.2x  0x%.2x  0x%.2x  0x%.2x\n",
+			pkt+i, pkt[i], pkt[i+1], pkt[i+2], pkt[i+3]);
+
+	/* We sent 1 query. We want to see more that 1 answer. */
+	header = (struct header *) pkt;
+	if (ntohs(header->nqueries) != 1)
+		return;
+
+	/* Received 0 answers */
+	if (header->nanswers == 0) {
+		puts("DNS server returned no answers\n");
+		NetState = NETLOOP_SUCCESS;
+		return;
+	}
+
+	/* Skip host name */
+	s = &header->data[0];
+	e = pkt + len;
+	for (p = s; p < e && *p != '\0'; p++)
+		continue;
+
+	/* We sent query class 1, query type 1 */
+	tmp = p[1] | (p[2] << 8);
+	if (&p[5] > e || ntohs(tmp) != DNS_A_RECORD) {
+		puts("DNS response was not A record\n");
+		NetState = NETLOOP_SUCCESS;
+		return;
+	}
+
+	/* Go to the first answer section */
+	p += 5;
+
+	/* Loop through the answers, we want A type answer */
+	for (found = stop = 0; !stop && &p[12] < e; ) {
+
+		/* Skip possible name in CNAME answer */
+		if (*p != 0xc0) {
+			while (*p && &p[12] < e)
+				p++;
+			p--;
+		}
+		debug("Name (Offset in header): %d\n", p[1]);
+
+		tmp = p[2] | (p[3] << 8);
+		type = ntohs(tmp);
+		debug("type = %d\n", type);
+		if (type == DNS_CNAME_RECORD) {
+			/* CNAME answer. shift to the next section */
+			debug("Found canonical name\n");
+			tmp = p[10] | (p[11] << 8);
+			dlen = ntohs(tmp);
+			debug("dlen = %d\n", dlen);
+			p += 12 + dlen;
+		} else if (type == DNS_A_RECORD) {
+			debug("Found A-record\n");
+			found = stop = 1;
+		} else {
+			debug("Unknown type\n");
+			stop = 1;
+		}
+	}
+
+	if (found && &p[12] < e) {
+
+		tmp = p[10] | (p[11] << 8);
+		dlen = ntohs(tmp);
+		p += 12;
+		memcpy(&IPAddress, p, 4);
+
+		if (p + dlen <= e) {
+			ip_to_string(IPAddress, IPStr);
+			printf("%s\n", IPStr);
+			if (NetDNSenvvar)
+				setenv(NetDNSenvvar, IPStr);
+		} else
+			puts("server responded with invalid IP number\n");
+	}
+
+	NetState = NETLOOP_SUCCESS;
+}
+
+void
+DnsStart(void)
+{
+	debug("%s\n", __func__);
+
+	NetSetTimeout(DNS_TIMEOUT, DnsTimeout);
+	NetSetHandler(DnsHandler);
+
+	DnsSend();
+}
+
diff --git a/net/dns.h b/net/dns.h
new file mode 100644
index 0000000000000000000000000000000000000000..277c093ed333d305db5a5138e54ba829b0fbde20
--- /dev/null
+++ b/net/dns.h
@@ -0,0 +1,39 @@
+/*
+ * (C) Masami Komiya <mkomiya@sonare.it> 2005
+ *  Copyright 2009, Robin Getz <rgetz@blackfin.uclinux.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+#ifndef __DNS_H__
+#define __DNS_H__
+
+#define DNS_SERVICE_PORT 53
+#define DNS_TIMEOUT      10000UL
+
+/* http://en.wikipedia.org/wiki/List_of_DNS_record_types */
+enum dns_query_type {
+	DNS_A_RECORD = 0x01,
+	DNS_CNAME_RECORD = 0x05,
+	DNS_MX_RECORD = 0x0f,
+};
+
+/*
+ * DNS network packet
+ */
+struct header {
+	uint16_t	tid;		/* Transaction ID */
+	uint16_t	flags;		/* Flags */
+	uint16_t	nqueries;	/* Questions */
+	uint16_t	nanswers;	/* Answers */
+	uint16_t	nauth;		/* Authority PRs */
+	uint16_t	nother;		/* Other PRs */
+	unsigned char	data[1];	/* Data, variable length */
+};
+
+extern void DnsStart(void);		/* Begin DNS */
+
+#endif
diff --git a/net/eth.c b/net/eth.c
index 3d93966918e0f6527f95a08b6c8e2032cbf51877..8e1d6921ca4673eacd49de024a421959900875d9 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -500,6 +500,8 @@ char *eth_get_name (void)
 }
 #elif defined(CONFIG_CMD_NET) && !defined(CONFIG_NET_MULTI)
 
+#warning Ethernet driver is deprecated.  Please update to use CONFIG_NET_MULTI
+
 extern int at91rm9200_miiphy_initialize(bd_t *bis);
 extern int mcf52x2_miiphy_initialize(bd_t *bis);
 extern int ns7520_miiphy_initialize(bd_t *bis);
diff --git a/net/net.c b/net/net.c
index 5637cf54f6d64efe21a8a168b050262d51a83756..641c37cb8f3b898bf756d48b006914f2c1f1b774 100644
--- a/net/net.c
+++ b/net/net.c
@@ -92,6 +92,9 @@
 #if defined(CONFIG_CDP_VERSION)
 #include <timestamp.h>
 #endif
+#if defined(CONFIG_CMD_DNS)
+#include "dns.h"
+#endif
 
 #if defined(CONFIG_CMD_NET)
 
@@ -139,8 +142,8 @@ uchar		NetServerEther[6] =	/* Boot server enet address		*/
 			{ 0, 0, 0, 0, 0, 0 };
 IPaddr_t	NetOurIP;		/* Our IP addr (0 = unknown)		*/
 IPaddr_t	NetServerIP;		/* Server IP addr (0 = unknown)		*/
-volatile uchar *NetRxPkt;		/* Current receive packet		*/
-int		NetRxPktLen;		/* Current rx packet length		*/
+volatile uchar *NetRxPacket;		/* Current receive packet		*/
+int		NetRxPacketLen;		/* Current rx packet length		*/
 unsigned	NetIPID;		/* IP packet ID				*/
 uchar		NetBcastAddr[6] =	/* Ethernet bcast address		*/
 			{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -291,6 +294,9 @@ NetInitLoop(proto_t protocol)
 		NetServerIP = getenv_IPaddr ("serverip");
 		NetOurNativeVLAN = getenv_VLAN("nvlan");
 		NetOurVLAN = getenv_VLAN("vlan");
+#if defined(CONFIG_CMD_DNS)
+		NetOurDNSIP = getenv_IPaddr("dnsip");
+#endif
 		env_changed_id = env_id;
 	}
 
@@ -388,17 +394,20 @@ restart:
 #if defined(CONFIG_CMD_DHCP)
 		case DHCP:
 			BootpTry = 0;
+			NetOurIP = 0;
 			DhcpRequest();		/* Basically same as BOOTP */
 			break;
 #endif
 
 		case BOOTP:
 			BootpTry = 0;
+			NetOurIP = 0;
 			BootpRequest ();
 			break;
 
 		case RARP:
 			RarpTry = 0;
+			NetOurIP = 0;
 			RarpRequest ();
 			break;
 #if defined(CONFIG_CMD_PING)
@@ -425,6 +434,11 @@ restart:
 		case SNTP:
 			SntpStart();
 			break;
+#endif
+#if defined(CONFIG_CMD_DNS)
+		case DNS:
+			DnsStart();
+			break;
 #endif
 		default:
 			break;
@@ -1122,8 +1136,8 @@ NetReceive(volatile uchar * inpkt, int len)
 	printf("packet received\n");
 #endif
 
-	NetRxPkt = inpkt;
-	NetRxPktLen = len;
+	NetRxPacket = inpkt;
+	NetRxPacketLen = len;
 	et = (Ethernet_t *)inpkt;
 
 	/* too small packet? */
@@ -1273,6 +1287,15 @@ NetReceive(volatile uchar * inpkt, int len)
 			/* are we waiting for a reply */
 			if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
 				break;
+
+#ifdef CONFIG_KEEP_SERVERADDR
+			if (NetServerIP == NetArpWaitPacketIP) {
+				char buf[20];
+				sprintf(buf, "%pM", arp->ar_data);
+				setenv("serveraddr", buf);
+			}
+#endif
+
 #ifdef ET_DEBUG
 			printf("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
 				arp->ar_data);
@@ -1518,6 +1541,14 @@ static int net_check_prereq (proto_t protocol)
 		}
 		goto common;
 #endif
+#if defined(CONFIG_CMD_DNS)
+	case DNS:
+		if (NetOurDNSIP == 0) {
+			puts("*** ERROR: DNS server address not given\n");
+			return 1;
+		}
+		goto common;
+#endif
 #if defined(CONFIG_CMD_NFS)
 	case NFS:
 #endif
@@ -1681,6 +1712,16 @@ void copy_filename (char *dst, char *src, int size)
 
 #endif
 
+#if defined(CONFIG_CMD_NFS) || defined(CONFIG_CMD_SNTP) || defined(CONFIG_CMD_DNS)
+/*
+ * make port a little random, but use something trivial to compute
+ */
+unsigned int random_port(void)
+{
+	return 1024 + (get_timer(0) % 0x8000);;
+}
+#endif
+
 void ip_to_string (IPaddr_t x, char *s)
 {
 	x = ntohl (x);