Merge branch 'master' of git://git.denx.de/u-boot-net
diff --git a/.checkpatch.conf b/.checkpatch.conf
index d88af57..35167e1 100644
--- a/.checkpatch.conf
+++ b/.checkpatch.conf
@@ -18,3 +18,6 @@
 
 # Not Linux, so we don't recommend usleep_range() over udelay()
 --ignore USLEEP_RANGE
+
+# Ignore networking block comment style
+--ignore NETWORKING_BLOCK_COMMENT_STYLE
diff --git a/board/atmel/at91sam9n12ek/at91sam9n12ek.c b/board/atmel/at91sam9n12ek/at91sam9n12ek.c
index 8752794..3013a42 100644
--- a/board/atmel/at91sam9n12ek/at91sam9n12ek.c
+++ b/board/atmel/at91sam9n12ek/at91sam9n12ek.c
@@ -33,6 +33,7 @@
 #include <lcd.h>
 #include <atmel_hlcdc.h>
 #include <atmel_mci.h>
+#include <netdev.h>
 
 #ifdef CONFIG_LCD_INFO
 #include <nand.h>
@@ -190,6 +191,30 @@
 }
 #endif
 
+#ifdef CONFIG_KS8851_MLL
+void at91sam9n12ek_ks8851_hw_init(void)
+{
+	struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC;
+
+	writel(AT91_SMC_SETUP_NWE(2) | AT91_SMC_SETUP_NCS_WR(0) |
+	       AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(0),
+	       &smc->cs[2].setup);
+	writel(AT91_SMC_PULSE_NWE(7) | AT91_SMC_PULSE_NCS_WR(7) |
+	       AT91_SMC_PULSE_NRD(7) | AT91_SMC_PULSE_NCS_RD(7),
+	       &smc->cs[2].pulse);
+	writel(AT91_SMC_CYCLE_NWE(9) | AT91_SMC_CYCLE_NRD(9),
+	       &smc->cs[2].cycle);
+	writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE |
+	       AT91_SMC_MODE_EXNW_DISABLE |
+	       AT91_SMC_MODE_BAT | AT91_SMC_MODE_DBW_16 |
+	       AT91_SMC_MODE_TDF_CYCLE(1),
+	       &smc->cs[2].mode);
+
+	/* Configure NCS2 PIN */
+	at91_set_b_periph(AT91_PIO_PORTD, 19, 0);
+}
+#endif
+
 int board_early_init_f(void)
 {
 	/* Enable clocks for all PIOs */
@@ -217,9 +242,20 @@
 	at91_lcd_hw_init();
 #endif
 
+#ifdef CONFIG_KS8851_MLL
+	at91sam9n12ek_ks8851_hw_init();
+#endif
+
 	return 0;
 }
 
+#ifdef CONFIG_KS8851_MLL
+int board_eth_init(bd_t *bis)
+{
+	return ks8851_mll_initialize(0, CONFIG_KS8851_MLL_BASEADDR);
+}
+#endif
+
 int dram_init(void)
 {
 	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 05130b6..e452fca 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -1707,7 +1707,7 @@
 	return 0;
 }
 
-static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	bootm_headers_t	images;
 
diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c
index 2dbd49c..1fb75d8 100644
--- a/common/cmd_pxe.c
+++ b/common/cmd_pxe.c
@@ -26,12 +26,21 @@
 
 #define MAX_TFTP_PATH_LEN 127
 
+const char *pxe_default_paths[] = {
+#ifdef CONFIG_SYS_SOC
+	"default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC,
+#endif
+	"default-" CONFIG_SYS_ARCH,
+	"default",
+	NULL
+};
+
 /*
  * Like getenv, but prints an error if envvar isn't defined in the
  * environment.  It always returns what getenv does, so it can be used in
  * place of getenv without changing error handling otherwise.
  */
-static char *from_env(char *envvar)
+static char *from_env(const char *envvar)
 {
 	char *ret;
 
@@ -55,37 +64,21 @@
  */
 static int format_mac_pxe(char *outbuf, size_t outbuf_len)
 {
-	size_t ethaddr_len;
-	char *p, *ethaddr;
-
-	ethaddr = from_env("ethaddr");
+	uchar ethaddr[6];
 
-	if (!ethaddr)
-		return -ENOENT;
-
-	ethaddr_len = strlen(ethaddr);
-
-	/*
-	 * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at
-	 * the end.
-	 */
-	if (outbuf_len < ethaddr_len + 4) {
-		printf("outbuf is too small (%d < %d)\n",
-				outbuf_len, ethaddr_len + 4);
+	if (outbuf_len < 21) {
+		printf("outbuf is too small (%d < 21)\n", outbuf_len);
 
 		return -EINVAL;
 	}
 
-	strcpy(outbuf, "01-");
-
-	for (p = outbuf + 3; *ethaddr; ethaddr++, p++) {
-		if (*ethaddr == ':')
-			*p = '-';
-		else
-			*p = tolower(*ethaddr);
-	}
+	if (!eth_getenv_enetaddr_by_index("eth", eth_get_dev_index(),
+					  ethaddr))
+		return -ENOENT;
 
-	*p = '\0';
+	sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x",
+		ethaddr[0], ethaddr[1], ethaddr[2],
+		ethaddr[3], ethaddr[4], ethaddr[5]);
 
 	return 1;
 }
@@ -131,14 +124,14 @@
 	return 1;
 }
 
-static int (*do_getfile)(char *file_path, char *file_addr);
+static int (*do_getfile)(const char *file_path, char *file_addr);
 
-static int do_get_tftp(char *file_path, char *file_addr)
+static int do_get_tftp(const char *file_path, char *file_addr)
 {
 	char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
 
 	tftp_argv[1] = file_addr;
-	tftp_argv[2] = file_path;
+	tftp_argv[2] = (void *)file_path;
 
 	if (do_tftpb(NULL, 0, 3, tftp_argv))
 		return -ENOENT;
@@ -148,12 +141,12 @@
 
 static char *fs_argv[5];
 
-static int do_get_ext2(char *file_path, char *file_addr)
+static int do_get_ext2(const char *file_path, char *file_addr)
 {
 #ifdef CONFIG_CMD_EXT2
 	fs_argv[0] = "ext2load";
 	fs_argv[3] = file_addr;
-	fs_argv[4] = file_path;
+	fs_argv[4] = (void *)file_path;
 
 	if (!do_ext2load(NULL, 0, 5, fs_argv))
 		return 1;
@@ -161,12 +154,12 @@
 	return -ENOENT;
 }
 
-static int do_get_fat(char *file_path, char *file_addr)
+static int do_get_fat(const char *file_path, char *file_addr)
 {
 #ifdef CONFIG_CMD_FAT
 	fs_argv[0] = "fatload";
 	fs_argv[3] = file_addr;
-	fs_argv[4] = file_path;
+	fs_argv[4] = (void *)file_path;
 
 	if (!do_fat_fsload(NULL, 0, 5, fs_argv))
 		return 1;
@@ -182,7 +175,7 @@
  *
  * Returns 1 for success, or < 0 on error.
  */
-static int get_relfile(char *file_path, void *file_addr)
+static int get_relfile(const char *file_path, void *file_addr)
 {
 	size_t path_len;
 	char relfile[MAX_TFTP_PATH_LEN+1];
@@ -221,7 +214,7 @@
  *
  * Returns 1 on success, or < 0 for error.
  */
-static int get_pxe_file(char *file_path, void *file_addr)
+static int get_pxe_file(const char *file_path, void *file_addr)
 {
 	unsigned long config_file_size;
 	char *tftp_filesize;
@@ -258,7 +251,7 @@
  *
  * Returns 1 on success or < 0 on error.
  */
-static int get_pxelinux_path(char *file, void *pxefile_addr_r)
+static int get_pxelinux_path(const char *file, void *pxefile_addr_r)
 {
 	size_t base_len = strlen(PXELINUX_DIR);
 	char path[MAX_TFTP_PATH_LEN+1];
@@ -355,7 +348,7 @@
 {
 	char *pxefile_addr_str;
 	unsigned long pxefile_addr_r;
-	int err;
+	int err, i = 0;
 
 	do_getfile = do_get_tftp;
 
@@ -376,16 +369,23 @@
 	 * Keep trying paths until we successfully get a file we're looking
 	 * for.
 	 */
-	if (pxe_uuid_path((void *)pxefile_addr_r) > 0
-		|| pxe_mac_path((void *)pxefile_addr_r) > 0
-		|| pxe_ipaddr_paths((void *)pxefile_addr_r) > 0
-		|| get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) {
-
+	if (pxe_uuid_path((void *)pxefile_addr_r) > 0 ||
+	    pxe_mac_path((void *)pxefile_addr_r) > 0 ||
+	    pxe_ipaddr_paths((void *)pxefile_addr_r) > 0) {
 		printf("Config file found\n");
 
 		return 0;
 	}
 
+	while (pxe_default_paths[i]) {
+		if (get_pxelinux_path(pxe_default_paths[i],
+				      (void *)pxefile_addr_r) > 0) {
+			printf("Config file found\n");
+			return 0;
+		}
+		i++;
+	}
+
 	printf("Config file not found\n");
 
 	return 1;
@@ -398,7 +398,7 @@
  *
  * Returns 1 on success or < 0 on error.
  */
-static int get_relfile_envaddr(char *file_path, char *envaddr_name)
+static int get_relfile_envaddr(const char *file_path, const char *envaddr_name)
 {
 	unsigned long file_addr;
 	char *envaddr;
@@ -445,14 +445,17 @@
  * list - lets these form a list, which a pxe_menu struct will hold.
  */
 struct pxe_label {
+	char num[4];
 	char *name;
 	char *menu;
 	char *kernel;
 	char *append;
 	char *initrd;
 	char *fdt;
+	int ipappend;
 	int attempted;
 	int localboot;
+	int localboot_val;
 	struct list_head list;
 };
 
@@ -533,21 +536,9 @@
 static void label_print(void *data)
 {
 	struct pxe_label *label = data;
-	const char *c = label->menu ? label->menu : label->kernel;
-
-	printf("%s:\t%s\n", label->name, c);
-
-	if (label->kernel)
-		printf("\t\tkernel: %s\n", label->kernel);
-
-	if (label->append)
-		printf("\t\tappend: %s\n", label->append);
+	const char *c = label->menu ? label->menu : label->name;
 
-	if (label->initrd)
-		printf("\t\tinitrd: %s\n", label->initrd);
-
-	if (label->fdt)
-		printf("\tfdt: %s\n", label->fdt);
+	printf("%s:\t%s\n", label->num, c);
 }
 
 /*
@@ -591,34 +582,43 @@
  * If the label specifies an 'append' line, its contents will overwrite that
  * of the 'bootargs' environment variable.
  */
-static void label_boot(struct pxe_label *label)
+static int label_boot(struct pxe_label *label)
 {
 	char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
+	char initrd_str[22];
+	char mac_str[29] = "";
+	char ip_str[68] = "";
+	char *bootargs;
 	int bootm_argc = 3;
+	int len = 0;
 
 	label_print(label);
 
 	label->attempted = 1;
 
 	if (label->localboot) {
-		label_localboot(label);
-		return;
+		if (label->localboot_val >= 0)
+			label_localboot(label);
+		return 0;
 	}
 
 	if (label->kernel == NULL) {
 		printf("No kernel given, skipping %s\n",
 				label->name);
-		return;
+		return 1;
 	}
 
 	if (label->initrd) {
 		if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) {
 			printf("Skipping %s for failure retrieving initrd\n",
 					label->name);
-			return;
+			return 1;
 		}
 
-		bootm_argv[2] = getenv("ramdisk_addr_r");
+		bootm_argv[2] = initrd_str;
+		strcpy(bootm_argv[2], getenv("ramdisk_addr_r"));
+		strcat(bootm_argv[2], ":");
+		strcat(bootm_argv[2], getenv("filesize"));
 	} else {
 		bootm_argv[2] = "-";
 	}
@@ -626,11 +626,43 @@
 	if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) {
 		printf("Skipping %s for failure retrieving kernel\n",
 				label->name);
-		return;
+		return 1;
+	}
+
+	if (label->ipappend & 0x1) {
+		sprintf(ip_str, " ip=%s:%s:%s:%s",
+			getenv("ipaddr"), getenv("serverip"),
+			getenv("gatewayip"), getenv("netmask"));
+		len += strlen(ip_str);
+	}
+
+	if (label->ipappend & 0x2) {
+		int err;
+		strcpy(mac_str, " BOOTIF=");
+		err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
+		if (err < 0)
+			mac_str[0] = '\0';
+		len += strlen(mac_str);
 	}
 
 	if (label->append)
-		setenv("bootargs", label->append);
+		len += strlen(label->append);
+
+	if (len) {
+		bootargs = malloc(len + 1);
+		if (!bootargs)
+			return 1;
+		bootargs[0] = '\0';
+		if (label->append)
+			strcpy(bootargs, label->append);
+		strcat(bootargs, ip_str);
+		strcat(bootargs, mac_str);
+
+		setenv("bootargs", bootargs);
+		printf("append: %s\n", bootargs);
+
+		free(bootargs);
+	}
 
 	bootm_argv[1] = getenv("kernel_addr_r");
 
@@ -654,7 +686,7 @@
 		if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) {
 			printf("Skipping %s for failure retrieving fdt\n",
 					label->name);
-			return;
+			return 1;
 		}
 	} else
 		bootm_argv[3] = getenv("fdt_addr");
@@ -663,6 +695,12 @@
 		bootm_argc = 4;
 
 	do_bootm(NULL, 0, bootm_argc, bootm_argv);
+
+#ifdef CONFIG_CMD_BOOTZ
+	/* Try booting a zImage if do_bootm returns */
+	do_bootz(NULL, 0, bootm_argc, bootm_argv);
+#endif
+	return 1;
 }
 
 /*
@@ -685,6 +723,8 @@
 	T_PROMPT,
 	T_INCLUDE,
 	T_FDT,
+	T_ONTIMEOUT,
+	T_IPAPPEND,
 	T_INVALID
 };
 
@@ -713,6 +753,8 @@
 	{"initrd", T_INITRD},
 	{"include", T_INCLUDE},
 	{"fdt", T_FDT},
+	{"ontimeout", T_ONTIMEOUT,},
+	{"ipappend", T_IPAPPEND,},
 	{NULL, T_INVALID}
 };
 
@@ -903,7 +945,6 @@
 {
 	struct token t;
 	char *s = *c;
-	unsigned long temp;
 
 	get_token(c, &t, L_SLITERAL);
 
@@ -912,12 +953,7 @@
 		return -EINVAL;
 	}
 
-	if (strict_strtoul(t.val, 10, &temp) < 0) {
-		printf("Expected unsigned integer: %s\n", t.val);
-		return -EINVAL;
-	}
-
-	*dst = (int)temp;
+	*dst = simple_strtol(t.val, NULL, 10);
 
 	free(t.val);
 
@@ -1016,10 +1052,8 @@
 
 	switch (t.type) {
 	case T_DEFAULT:
-		if (cfg->default_label)
-			free(cfg->default_label);
-
-		cfg->default_label = strdup(label->name);
+		if (!cfg->default_label)
+			cfg->default_label = strdup(label->name);
 
 		if (!cfg->default_label)
 			return -ENOMEM;
@@ -1108,7 +1142,12 @@
 			break;
 
 		case T_LOCALBOOT:
-			err = parse_integer(c, &label->localboot);
+			label->localboot = 1;
+			err = parse_integer(c, &label->localboot_val);
+			break;
+
+		case T_IPAPPEND:
+			err = parse_integer(c, &label->ipappend);
 			break;
 
 		case T_EOL:
@@ -1164,6 +1203,7 @@
 		err = 0;
 		switch (t.type) {
 		case T_MENU:
+			cfg->prompt = 1;
 			err = parse_menu(&p, cfg, b, nest_level);
 			break;
 
@@ -1176,6 +1216,7 @@
 			break;
 
 		case T_DEFAULT:
+		case T_ONTIMEOUT:
 			err = parse_sliteral(&p, &label_name);
 
 			if (label_name) {
@@ -1193,7 +1234,7 @@
 			break;
 
 		case T_PROMPT:
-			err = parse_integer(&p, &cfg->prompt);
+			eol_or_eof(&p);
 			break;
 
 		case T_EOL:
@@ -1276,6 +1317,8 @@
 	struct list_head *pos;
 	struct menu *m;
 	int err;
+	int i = 1;
+	char *default_num = NULL;
 
 	/*
 	 * Create a menu and add items for all the labels.
@@ -1289,18 +1332,23 @@
 	list_for_each(pos, &cfg->labels) {
 		label = list_entry(pos, struct pxe_label, list);
 
-		if (menu_item_add(m, label->name, label) != 1) {
+		sprintf(label->num, "%d", i++);
+		if (menu_item_add(m, label->num, label) != 1) {
 			menu_destroy(m);
 			return NULL;
 		}
+		if (cfg->default_label &&
+		    (strcmp(label->name, cfg->default_label) == 0))
+			default_num = label->num;
+
 	}
 
 	/*
 	 * After we've created items for each label in the menu, set the
 	 * menu's default label if one was specified.
 	 */
-	if (cfg->default_label) {
-		err = menu_default_set(m, cfg->default_label);
+	if (default_num) {
+		err = menu_default_set(m, default_num);
 		if (err != 1) {
 			if (err != -ENOENT) {
 				menu_destroy(m);
@@ -1367,10 +1415,13 @@
 	 * we give up.
 	 */
 
-	if (err == 1)
-		label_boot(choice);
-	else if (err != -ENOENT)
+	if (err == 1) {
+		err = label_boot(choice);
+		if (!err)
+			return;
+	} else if (err != -ENOENT) {
 		return;
+	}
 
 	boot_unattempted_labels(cfg);
 }
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 786a656..9cf2983 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -46,10 +46,12 @@
 COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o
+COBJS-$(CONFIG_FTMAC110) += ftmac110.o
 COBJS-$(CONFIG_FTMAC100) += ftmac100.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
 COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
+COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
 COBJS-$(CONFIG_LAN91C96) += lan91c96.o
 COBJS-$(CONFIG_MACB) += macb.o
 COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
@@ -68,6 +70,7 @@
 COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
 COBJS-$(CONFIG_SMC91111) += smc91111.o
 COBJS-$(CONFIG_SMC911X) += smc911x.o
+COBJS-$(CONFIG_SUNXI_WEMAC) += sunxi_wemac.o
 COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
 COBJS-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o
 COBJS-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index bf21a08..46f6601 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -113,7 +113,9 @@
 	int timeout = CONFIG_MACRESET_TIMEOUT;
 
 	writel(DMAMAC_SRST, &dma_p->busmode);
-	writel(MII_PORTSELECT, &mac_p->conf);
+
+	if (priv->interface != PHY_INTERFACE_MODE_RGMII)
+		writel(MII_PORTSELECT, &mac_p->conf);
 
 	start = get_timer(0);
 	while (get_timer(start) < timeout) {
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 69ba57d..2dbb328 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -27,11 +27,13 @@
 #include <malloc.h>
 #include <net.h>
 #include <asm/io.h>
+#include <asm/dma-mapping.h>
 #include <linux/mii.h>
 
 #include "ftgmac100.h"
 
 #define ETH_ZLEN	60
+#define CFG_XBUF_SIZE	1536
 
 /* RBSR - hw default init value is also 0x640 */
 #define RBSR_DEFAULT_VALUE	0x640
@@ -40,8 +42,10 @@
 #define PKTBUFSTX	4	/* must be power of 2 */
 
 struct ftgmac100_data {
-	struct ftgmac100_txdes txdes[PKTBUFSTX];
-	struct ftgmac100_rxdes rxdes[PKTBUFSRX];
+	ulong txdes_dma;
+	struct ftgmac100_txdes *txdes;
+	ulong rxdes_dma;
+	struct ftgmac100_rxdes *rxdes;
 	int tx_index;
 	int rx_index;
 	int phy_addr;
@@ -375,13 +379,34 @@
 {
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
-	struct ftgmac100_txdes *txdes = priv->txdes;
-	struct ftgmac100_rxdes *rxdes = priv->rxdes;
+	struct ftgmac100_txdes *txdes;
+	struct ftgmac100_rxdes *rxdes;
 	unsigned int maccr;
+	void *buf;
 	int i;
 
 	debug("%s()\n", __func__);
 
+	if (!priv->txdes) {
+		txdes = dma_alloc_coherent(
+			sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
+		if (!txdes)
+			panic("ftgmac100: out of memory\n");
+		memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
+		priv->txdes = txdes;
+	}
+	txdes = priv->txdes;
+
+	if (!priv->rxdes) {
+		rxdes = dma_alloc_coherent(
+			sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
+		if (!rxdes)
+			panic("ftgmac100: out of memory\n");
+		memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
+		priv->rxdes = rxdes;
+	}
+	rxdes = priv->rxdes;
+
 	/* set the ethernet address */
 	ftgmac100_set_mac_from_env(dev);
 
@@ -397,21 +422,31 @@
 
 	for (i = 0; i < PKTBUFSTX; i++) {
 		/* TXBUF_BADR */
-		txdes[i].txdes3 = 0;
+		if (!txdes[i].txdes2) {
+			buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+			if (!buf)
+				panic("ftgmac100: out of memory\n");
+			txdes[i].txdes3 = virt_to_phys(buf);
+			txdes[i].txdes2 = (uint)buf;
+		}
 		txdes[i].txdes1 = 0;
 	}
 
 	for (i = 0; i < PKTBUFSRX; i++) {
 		/* RXBUF_BADR */
-		rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i];
+		if (!rxdes[i].rxdes2) {
+			buf = NetRxPackets[i];
+			rxdes[i].rxdes3 = virt_to_phys(buf);
+			rxdes[i].rxdes2 = (uint)buf;
+		}
 		rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
 	}
 
 	/* transmit ring */
-	writel((unsigned int)txdes, &ftgmac100->txr_badr);
+	writel(priv->txdes_dma, &ftgmac100->txr_badr);
 
 	/* receive ring */
-	writel((unsigned int)rxdes, &ftgmac100->rxr_badr);
+	writel(priv->rxdes_dma, &ftgmac100->rxr_badr);
 
 	/* poll receive descriptor automatically */
 	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
@@ -466,8 +501,11 @@
 	debug("%s(): RX buffer %d, %x received\n",
 	       __func__, priv->rx_index, rxlen);
 
+	/* invalidate d-cache */
+	dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
+
 	/* pass the packet up to the protocol layers. */
-	NetReceive((void *)curr_des->rxdes3, rxlen);
+	NetReceive((void *)curr_des->rxdes2, rxlen);
 
 	/* release buffer to DMA */
 	curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
@@ -485,7 +523,6 @@
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
 	struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
-	int start;
 
 	if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
 		debug("%s(): no TX descriptor available\n", __func__);
@@ -496,8 +533,8 @@
 
 	length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
 
-	/* initiate a transmit sequence */
-	curr_des->txdes3 = (unsigned int)packet;	/* TXBUF_BADR */
+	memcpy((void *)curr_des->txdes2, (void *)packet, length);
+	dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);
 
 	/* only one descriptor on TXBUF */
 	curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
@@ -509,15 +546,6 @@
 	/* start transmit */
 	writel(1, &ftgmac100->txpd);
 
-	/* wait for transfer to succeed */
-	start = get_timer(0);
-	while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
-		if (get_timer(0) >= 5) {
-			debug("%s(): timed out\n", __func__);
-			return -1;
-		}
-	}
-
 	debug("%s(): packet sent\n", __func__);
 
 	priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c
new file mode 100644
index 0000000..579dcc7
--- /dev/null
+++ b/drivers/net/ftmac110.c
@@ -0,0 +1,473 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#include "ftmac110.h"
+
+#define CFG_RXDES_NUM   8
+#define CFG_TXDES_NUM   2
+#define CFG_XBUF_SIZE   1536
+
+#define CFG_MDIORD_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_MDIOWR_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_LINKUP_TIMEOUT  (CONFIG_SYS_HZ << 2) /* 4 sec */
+
+/*
+ * FTMAC110 DMA design issue
+ *
+ * Its DMA engine has a weird restriction that its Rx DMA engine
+ * accepts only 16-bits aligned address, 32-bits aligned is not
+ * acceptable. However this restriction does not apply to Tx DMA.
+ *
+ * Conclusion:
+ * (1) Tx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)
+ * (2) Rx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: Invalid
+ */
+
+struct ftmac110_chip {
+	void __iomem *regs;
+	uint32_t imr;
+	uint32_t maccr;
+	uint32_t lnkup;
+	uint32_t phy_addr;
+
+	struct ftmac110_rxd *rxd;
+	ulong                rxd_dma;
+	uint32_t             rxd_idx;
+
+	struct ftmac110_txd *txd;
+	ulong                txd_dma;
+	uint32_t             txd_idx;
+};
+
+static int ftmac110_reset(struct eth_device *dev);
+
+static uint16_t mdio_read(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint16_t ret = 0xffff;
+
+	tmp = PHYCR_READ
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT);
+
+	writel(tmp, &regs->phycr);
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) {
+		tmp = readl(&regs->phycr);
+		if (tmp & PHYCR_READ)
+			continue;
+		break;
+	}
+
+	if (tmp & PHYCR_READ)
+		printf("ftmac110: mdio read timeout\n");
+	else
+		ret = (uint16_t)(tmp & 0xffff);
+
+	return ret;
+}
+
+static void mdio_write(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+	uint32_t tmp, ts;
+
+	tmp = PHYCR_WRITE
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT);
+
+	writel(phydata, &regs->phydr);
+	writel(tmp, &regs->phycr);
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) {
+		if (readl(&regs->phycr) & PHYCR_WRITE)
+			continue;
+		break;
+	}
+
+	if (readl(&regs->phycr) & PHYCR_WRITE)
+		printf("ftmac110: mdio write timeout\n");
+}
+
+static uint32_t ftmac110_phyqry(struct eth_device *dev)
+{
+	ulong ts;
+	uint32_t maccr;
+	uint16_t pa, tmp, bmsr, bmcr;
+	struct ftmac110_chip *chip = dev->priv;
+
+	/* Default = 100Mbps Full */
+	maccr = MACCR_100M | MACCR_FD;
+
+	/* 1. find the phy device  */
+	for (pa = 0; pa < 32; ++pa) {
+		tmp = mdio_read(dev, pa, MII_PHYSID1);
+		if (tmp == 0xFFFF || tmp == 0x0000)
+			continue;
+		chip->phy_addr = pa;
+		break;
+	}
+	if (pa >= 32) {
+		puts("ftmac110: phy device not found!\n");
+		goto exit;
+	}
+
+	/* 2. wait until link-up & auto-negotiation complete */
+	chip->lnkup = 0;
+	bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR);
+	ts = get_timer(0);
+	do {
+		bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR);
+		chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0;
+		if (!chip->lnkup)
+			continue;
+		if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE))
+			break;
+	} while (get_timer(ts) < CFG_LINKUP_TIMEOUT);
+	if (!chip->lnkup) {
+		puts("ftmac110: link down\n");
+		goto exit;
+	}
+	if (!(bmcr & BMCR_ANENABLE))
+		puts("ftmac110: auto negotiation disabled\n");
+	else if (!(bmsr & BMSR_ANEGCOMPLETE))
+		puts("ftmac110: auto negotiation timeout\n");
+
+	/* 3. derive MACCR */
+	if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) {
+		tmp  = mdio_read(dev, chip->phy_addr, MII_ADVERTISE);
+		tmp &= mdio_read(dev, chip->phy_addr, MII_LPA);
+		if (tmp & LPA_100FULL)      /* 100Mbps full-duplex */
+			maccr = MACCR_100M | MACCR_FD;
+		else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */
+			maccr = MACCR_100M;
+		else if (tmp & LPA_10FULL)  /* 10Mbps full-duplex */
+			maccr = MACCR_FD;
+		else if (tmp & LPA_10HALF)  /* 10Mbps half-duplex */
+			maccr = 0;
+	} else {
+		if (bmcr & BMCR_SPEED100)
+			maccr = MACCR_100M;
+		else
+			maccr = 0;
+		if (bmcr & BMCR_FULLDPLX)
+			maccr |= MACCR_FD;
+	}
+
+exit:
+	printf("ftmac110: %d Mbps, %s\n",
+	       (maccr & MACCR_100M) ? 100 : 10,
+	       (maccr & MACCR_FD) ? "Full" : "half");
+	return maccr;
+}
+
+static int ftmac110_reset(struct eth_device *dev)
+{
+	uint8_t *a;
+	uint32_t i, maccr;
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+
+	/* 1. MAC reset */
+	writel(MACCR_RESET, &regs->maccr);
+	for (i = get_timer(0); get_timer(i) < 1000; ) {
+		if (readl(&regs->maccr) & MACCR_RESET)
+			continue;
+		break;
+	}
+	if (readl(&regs->maccr) & MACCR_RESET) {
+		printf("ftmac110: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* 1-1. Init tx ring */
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		/* owned by SW */
+		chip->txd[i].ct[0] = 0;
+	}
+	chip->txd_idx = 0;
+
+	/* 1-2. Init rx ring */
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		/* owned by HW */
+		chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+	}
+	chip->rxd_idx = 0;
+
+	/* 2. PHY status query */
+	maccr = ftmac110_phyqry(dev);
+
+	/* 3. Fix up the MACCR value */
+	chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
+		| MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
+
+	/* 4. MAC address setup */
+	a = dev->enetaddr;
+	writel(a[1] | (a[0] << 8), &regs->mac[0]);
+	writel(a[5] | (a[4] << 8) | (a[3] << 16)
+		| (a[2] << 24), &regs->mac[1]);
+
+	/* 5. MAC registers setup */
+	writel(chip->rxd_dma, &regs->rxba);
+	writel(chip->txd_dma, &regs->txba);
+	/* interrupt at each tx/rx */
+	writel(ITC_DEFAULT, &regs->itc);
+	/* no tx pool, rx poll = 1 normal cycle */
+	writel(APTC_DEFAULT, &regs->aptc);
+	/* rx threshold = [6/8 fifo, 2/8 fifo] */
+	writel(DBLAC_DEFAULT, &regs->dblac);
+	/* disable & clear all interrupt status */
+	chip->imr = 0;
+	writel(ISR_ALL, &regs->isr);
+	writel(chip->imr, &regs->imr);
+	/* enable mac */
+	writel(chip->maccr, &regs->maccr);
+
+	return 0;
+}
+
+static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
+{
+	debug("ftmac110: probe\n");
+
+	if (ftmac110_reset(dev))
+		return -1;
+
+	return 0;
+}
+
+static void ftmac110_halt(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+
+	writel(0, &regs->imr);
+	writel(0, &regs->maccr);
+
+	debug("ftmac110: halt\n");
+}
+
+static int ftmac110_send(struct eth_device *dev, void *pkt, int len)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+	struct ftmac110_txd *des;
+
+	if (!chip->lnkup)
+		return 0;
+
+	if (len <= 0 || len > CFG_XBUF_SIZE) {
+		printf("ftmac110: bad tx pkt len(%d)\n", len);
+		return 0;
+	}
+
+	len = max(60, len);
+
+	des = &chip->txd[chip->txd_idx];
+	if (le32_to_cpu(des->ct[0]) & FTMAC110_TXCT0_OWNER) {
+		/* kick-off Tx DMA */
+		writel(0xffffffff, &regs->txpd);
+		printf("ftmac110: out of txd\n");
+		return 0;
+	}
+
+	memcpy(des->vbuf, (void *)pkt, len);
+	dma_map_single(des->vbuf, len, DMA_TO_DEVICE);
+
+	/* update len, fts and lts */
+	des->ct[1] &= cpu_to_le32(FTMAC110_TXCT1_END);
+	des->ct[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len)
+		| FTMAC110_TXCT1_FTS | FTMAC110_TXCT1_LTS);
+
+	/* set owner bit and clear others */
+	des->ct[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER);
+
+	/* kick-off Tx DMA */
+	writel(0xffffffff, &regs->txpd);
+
+	chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM;
+
+	return len;
+}
+
+static int ftmac110_recv(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_rxd *des;
+	uint32_t ct0, len, rlen = 0;
+	uint8_t *buf;
+
+	if (!chip->lnkup)
+		return 0;
+
+	do {
+		des = &chip->rxd[chip->rxd_idx];
+		ct0 = le32_to_cpu(des->ct[0]);
+		if (ct0 & FTMAC110_RXCT0_OWNER)
+			break;
+
+		len = FTMAC110_RXCT0_LEN(ct0);
+		buf = des->vbuf;
+
+		if (ct0 & FTMAC110_RXCT0_ERRMASK) {
+			printf("ftmac110: rx error\n");
+		} else {
+			dma_map_single(buf, len, DMA_FROM_DEVICE);
+			NetReceive(buf, len);
+			rlen += len;
+		}
+
+		/* owned by hardware */
+		des->ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+
+		chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM;
+	} while (0);
+
+	return rlen;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+static int ftmac110_mdio_read(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		*value = mdio_read(dev, addr, reg);
+	}
+
+	return ret;
+}
+
+static int ftmac110_mdio_write(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		mdio_write(dev, addr, reg, value);
+	}
+
+	return ret;
+}
+
+#endif    /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+int ftmac110_initialize(bd_t *bis)
+{
+	int i, card_nr = 0;
+	struct eth_device *dev;
+	struct ftmac110_chip *chip;
+
+	dev = malloc(sizeof(*dev) + sizeof(*chip));
+	if (dev == NULL) {
+		panic("ftmac110: out of memory 1\n");
+		return -1;
+	}
+	chip = (struct ftmac110_chip *)(dev + 1);
+	memset(dev, 0, sizeof(*dev) + sizeof(*chip));
+
+	sprintf(dev->name, "FTMAC110#%d", card_nr);
+
+	dev->iobase = CONFIG_FTMAC110_BASE;
+	chip->regs = (void __iomem *)dev->iobase;
+	dev->priv = chip;
+	dev->init = ftmac110_probe;
+	dev->halt = ftmac110_halt;
+	dev->send = ftmac110_send;
+	dev->recv = ftmac110_recv;
+
+	if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr))
+		eth_random_enetaddr(dev->enetaddr);
+
+	/* allocate tx descriptors (it must be 16 bytes aligned) */
+	chip->txd = dma_alloc_coherent(
+		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma);
+	if (!chip->txd)
+		panic("ftmac110: out of memory 3\n");
+	memset(chip->txd, 0,
+	       sizeof(struct ftmac110_txd) * CFG_TXDES_NUM);
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+		if (!va)
+			panic("ftmac110: out of memory 4\n");
+		chip->txd[i].vbuf  = va;
+		chip->txd[i].buf   = cpu_to_le32(virt_to_phys(va));
+		chip->txd[i].ct[1] = 0;
+		chip->txd[i].ct[0] = 0; /* owned by SW */
+	}
+	chip->txd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_TXCT1_END);
+	chip->txd_idx = 0;
+
+	/* allocate rx descriptors (it must be 16 bytes aligned) */
+	chip->rxd = dma_alloc_coherent(
+		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma);
+	if (!chip->rxd)
+		panic("ftmac110: out of memory 4\n");
+	memset((void *)chip->rxd, 0,
+	       sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM);
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
+		if (!va)
+			panic("ftmac110: out of memory 5\n");
+		/* it needs to be exactly 2 bytes aligned */
+		va = ((uint8_t *)va + 2);
+		chip->rxd[i].vbuf  = va;
+		chip->rxd[i].buf   = cpu_to_le32(virt_to_phys(va));
+		chip->rxd[i].ct[1] = cpu_to_le32(CFG_XBUF_SIZE);
+		chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+	}
+	chip->rxd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_RXCT1_END);
+	chip->rxd_idx = 0;
+
+	eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
+#endif
+
+	card_nr++;
+
+	return card_nr;
+}
diff --git a/drivers/net/ftmac110.h b/drivers/net/ftmac110.h
new file mode 100644
index 0000000..5b2d23b
--- /dev/null
+++ b/drivers/net/ftmac110.h
@@ -0,0 +1,177 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTMAC110_H
+#define _FTMAC110_H
+
+struct ftmac110_regs {
+	uint32_t isr;    /* 0x00: Interrups Status Register */
+	uint32_t imr;    /* 0x04: Interrupt Mask Register */
+	uint32_t mac[2]; /* 0x08: MAC Address */
+	uint32_t mht[2]; /* 0x10: Multicast Hash Table Register */
+	uint32_t txpd;   /* 0x18: Tx Poll Demand Register */
+	uint32_t rxpd;   /* 0x1c: Rx Poll Demand Register */
+	uint32_t txba;   /* 0x20: Tx Ring Base Address Register */
+	uint32_t rxba;   /* 0x24: Rx Ring Base Address Register */
+	uint32_t itc;    /* 0x28: Interrupt Timer Control Register */
+	uint32_t aptc;   /* 0x2C: Automatic Polling Timer Control Register */
+	uint32_t dblac;  /* 0x30: DMA Burst Length&Arbitration Control */
+	uint32_t revr;   /* 0x34: Revision Register */
+	uint32_t fear;   /* 0x38: Feature Register */
+	uint32_t rsvd[19];
+	uint32_t maccr;  /* 0x88: MAC Control Register */
+	uint32_t macsr;  /* 0x8C: MAC Status Register */
+	uint32_t phycr;  /* 0x90: PHY Control Register */
+	uint32_t phydr;  /* 0x94: PHY Data Register */
+	uint32_t fcr;    /* 0x98: Flow Control Register */
+	uint32_t bpr;    /* 0x9C: Back Pressure Register */
+};
+
+/*
+ * Interrupt status/mask register(ISR/IMR) bits
+ */
+#define ISR_ALL          0x3ff
+#define ISR_PHYSTCHG     (1 << 9) /* phy status change */
+#define ISR_AHBERR       (1 << 8) /* bus error */
+#define ISR_RXLOST       (1 << 7) /* rx lost */
+#define ISR_RXFIFO       (1 << 6) /* rx to fifo */
+#define ISR_TXLOST       (1 << 5) /* tx lost */
+#define ISR_TXOK         (1 << 4) /* tx to ethernet */
+#define ISR_NOTXBUF      (1 << 3) /* out of tx buffer */
+#define ISR_TXFIFO       (1 << 2) /* tx to fifo */
+#define ISR_NORXBUF      (1 << 1) /* out of rx buffer */
+#define ISR_RXOK         (1 << 0) /* rx to buffer */
+
+/*
+ * MACCR control bits
+ */
+#define MACCR_100M       (1 << 18) /* 100Mbps mode */
+#define MACCR_RXBCST     (1 << 17) /* rx broadcast packet */
+#define MACCR_RXMCST     (1 << 16) /* rx multicast packet */
+#define MACCR_FD         (1 << 15) /* full duplex */
+#define MACCR_CRCAPD     (1 << 14) /* tx crc append */
+#define MACCR_RXALL      (1 << 12) /* rx all packets */
+#define MACCR_RXFTL      (1 << 11) /* rx packet even it's > 1518 byte */
+#define MACCR_RXRUNT     (1 << 10) /* rx packet even it's < 64 byte */
+#define MACCR_RXMCSTHT   (1 << 9)  /* rx multicast hash table */
+#define MACCR_RXEN       (1 << 8)  /* rx enable */
+#define MACCR_RXINHDTX   (1 << 6)  /* rx in half duplex tx */
+#define MACCR_TXEN       (1 << 5)  /* tx enable */
+#define MACCR_CRCDIS     (1 << 4)  /* tx packet even it's crc error */
+#define MACCR_LOOPBACK   (1 << 3)  /* loop-back */
+#define MACCR_RESET      (1 << 2)  /* reset */
+#define MACCR_RXDMAEN    (1 << 1)  /* rx dma enable */
+#define MACCR_TXDMAEN    (1 << 0)  /* tx dma enable */
+
+/*
+ * PHYCR control bits
+ */
+#define PHYCR_READ       (1 << 26)
+#define PHYCR_WRITE      (1 << 27)
+#define PHYCR_REG_SHIFT  21
+#define PHYCR_ADDR_SHIFT 16
+
+/*
+ * ITC control bits
+ */
+
+/* Tx Cycle Length */
+#define ITC_TX_CYCLONG   (1 << 15) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_TX_CYCNORM   (0 << 15) /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Tx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_TX_THR(n)    (((n) & 0x7) << 12)
+/* Tx Interrupt Timeout = n * Tx Cycle */
+#define ITC_TX_ITMO(n)   (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define ITC_RX_CYCLONG   (1 << 7)  /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_RX_CYCNORM   (0 << 7)  /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Rx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_RX_THR(n)    (((n) & 0x7) << 4)
+/* Rx Interrupt Timeout = n * Rx Cycle */
+#define ITC_RX_ITMO(n)   (((n) & 0xf) << 0)
+
+#define ITC_DEFAULT \
+	(ITC_TX_THR(1) | ITC_TX_ITMO(0) | ITC_RX_THR(1) | ITC_RX_ITMO(0))
+
+/*
+ * APTC contrl bits
+ */
+
+/* Tx Cycle Length */
+#define APTC_TX_CYCLONG  (1 << 12) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_TX_CYCNORM  (0 << 12) /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Tx Poll Timeout = n * Tx Cycle, 0=No auto polling */
+#define APTC_TX_PTMO(n)  (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define APTC_RX_CYCLONG  (1 << 4)  /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_RX_CYCNORM  (0 << 4)  /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Rx Poll Timeout = n * Rx Cycle, 0=No auto polling */
+#define APTC_RX_PTMO(n)  (((n) & 0xf) << 0)
+
+#define APTC_DEFAULT     (APTC_TX_PTMO(0) | APTC_RX_PTMO(1))
+
+/*
+ * DBLAC contrl bits
+ */
+#define DBLAC_BURST_MAX_ANY  (0 << 14) /* un-limited */
+#define DBLAC_BURST_MAX_32X4 (2 << 14) /* max = 32 x 4 bytes */
+#define DBLAC_BURST_MAX_64X4 (3 << 14) /* max = 64 x 4 bytes */
+#define DBLAC_RXTHR_EN       (1 << 9)  /* enable rx threshold arbitration */
+#define DBLAC_RXTHR_HIGH(n)  (((n) & 0x7) << 6) /* upper bound = n/8 fifo */
+#define DBLAC_RXTHR_LOW(n)   (((n) & 0x7) << 3) /* lower bound = n/8 fifo */
+#define DBLAC_BURST_CAP16    (1 << 2)  /* support burst 16 */
+#define DBLAC_BURST_CAP8     (1 << 1)  /* support burst 8 */
+#define DBLAC_BURST_CAP4     (1 << 0)  /* support burst 4 */
+
+#define DBLAC_DEFAULT \
+	(DBLAC_RXTHR_EN | DBLAC_RXTHR_HIGH(6) | DBLAC_RXTHR_LOW(2))
+
+/*
+ * descriptor structure
+ */
+struct ftmac110_rxd {
+	uint32_t ct[2];
+	uint32_t buf;
+	void    *vbuf; /* reserved */
+};
+
+#define FTMAC110_RXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_RXCT0_FRS         BIT_MASK(29) /* first pkt desc */
+#define FTMAC110_RXCT0_LRS         BIT_MASK(28) /* last pkt desc */
+#define FTMAC110_RXCT0_ODDNB       BIT_MASK(22) /* odd nibble */
+#define FTMAC110_RXCT0_RUNT        BIT_MASK(21) /* runt pkt */
+#define FTMAC110_RXCT0_FTL         BIT_MASK(20) /* frame too long */
+#define FTMAC110_RXCT0_CRC         BIT_MASK(19) /* pkt crc error */
+#define FTMAC110_RXCT0_ERR         BIT_MASK(18) /* bus error */
+#define FTMAC110_RXCT0_ERRMASK     (0x1f << 18) /* all errors */
+#define FTMAC110_RXCT0_BCST        BIT_MASK(17) /* Bcst pkt */
+#define FTMAC110_RXCT0_MCST        BIT_MASK(16) /* Mcst pkt */
+#define FTMAC110_RXCT0_LEN(x)      ((x) & 0x7ff)
+
+#define FTMAC110_RXCT1_END         BIT_MASK(31)
+#define FTMAC110_RXCT1_BUFSZ(x)    ((x) & 0x7ff)
+
+struct ftmac110_txd {
+	uint32_t ct[2];
+	uint32_t buf;
+	void    *vbuf; /* reserved */
+};
+
+#define FTMAC110_TXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_TXCT0_COL         0x00000003   /* collision */
+
+#define FTMAC110_TXCT1_END         BIT_MASK(31) /* end of ring */
+#define FTMAC110_TXCT1_TXIC        BIT_MASK(30) /* tx done interrupt */
+#define FTMAC110_TXCT1_TX2FIC      BIT_MASK(29) /* tx fifo interrupt */
+#define FTMAC110_TXCT1_FTS         BIT_MASK(28) /* first pkt desc */
+#define FTMAC110_TXCT1_LTS         BIT_MASK(27) /* last pkt desc */
+#define FTMAC110_TXCT1_LEN(x)      ((x) & 0x7ff)
+
+#endif  /* FTMAC110_H */
diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c
new file mode 100644
index 0000000..b02d59a
--- /dev/null
+++ b/drivers/net/ks8851_mll.c
@@ -0,0 +1,645 @@
+/*
+ * Micrel KS8851_MLL 16bit Network driver
+ * Copyright (c) 2011 Roberto Cerati <roberto.cerati@bticino.it>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+
+#include "ks8851_mll.h"
+
+#define DRIVERNAME			"ks8851_mll"
+
+#define MAX_RECV_FRAMES			32
+#define MAX_BUF_SIZE			2048
+#define TX_BUF_SIZE			2000
+#define RX_BUF_SIZE			2000
+
+static const struct chip_id chip_ids[] =  {
+	{CIDER_ID, "KSZ8851"},
+	{0, NULL},
+};
+
+/*
+ * union ks_tx_hdr - tx header data
+ * @txb: The header as bytes
+ * @txw: The header as 16bit, little-endian words
+ *
+ * A dual representation of the tx header data to allow
+ * access to individual bytes, and to allow 16bit accesses
+ * with 16bit alignment.
+ */
+union ks_tx_hdr {
+	u8      txb[4];
+	__le16  txw[2];
+};
+
+/*
+ * struct ks_net - KS8851 driver private data
+ * @net_device	: The network device we're bound to
+ * @txh		: temporaly buffer to save status/length.
+ * @frame_head_info	: frame header information for multi-pkt rx.
+ * @statelock	: Lock on this structure for tx list.
+ * @msg_enable	: The message flags controlling driver output (see ethtool).
+ * @frame_cnt	: number of frames received.
+ * @bus_width	: i/o bus width.
+ * @irq		: irq number assigned to this device.
+ * @rc_rxqcr	: Cached copy of KS_RXQCR.
+ * @rc_txcr	: Cached copy of KS_TXCR.
+ * @rc_ier	: Cached copy of KS_IER.
+ * @sharedbus	: Multipex(addr and data bus) mode indicator.
+ * @cmd_reg_cache	: command register cached.
+ * @cmd_reg_cache_int	: command register cached. Used in the irq handler.
+ * @promiscuous	: promiscuous mode indicator.
+ * @all_mcast	: mutlicast indicator.
+ * @mcast_lst_size	: size of multicast list.
+ * @mcast_lst		: multicast list.
+ * @mcast_bits		: multicast enabed.
+ * @mac_addr		: MAC address assigned to this device.
+ * @fid			: frame id.
+ * @extra_byte		: number of extra byte prepended rx pkt.
+ * @enabled		: indicator this device works.
+ */
+
+/* Receive multiplex framer header info */
+struct type_frame_head {
+	u16	sts;         /* Frame status */
+	u16	len;         /* Byte count */
+} fr_h_i[MAX_RECV_FRAMES];
+
+struct ks_net {
+	struct net_device	*netdev;
+	union ks_tx_hdr		txh;
+	struct type_frame_head	*frame_head_info;
+	u32			msg_enable;
+	u32			frame_cnt;
+	int			bus_width;
+	int			irq;
+	u16			rc_rxqcr;
+	u16			rc_txcr;
+	u16			rc_ier;
+	u16			sharedbus;
+	u16			cmd_reg_cache;
+	u16			cmd_reg_cache_int;
+	u16			promiscuous;
+	u16			all_mcast;
+	u16			mcast_lst_size;
+	u8			mcast_lst[MAX_MCAST_LST][MAC_ADDR_LEN];
+	u8			mcast_bits[HW_MCAST_SIZE];
+	u8			mac_addr[6];
+	u8                      fid;
+	u8			extra_byte;
+	u8			enabled;
+} ks_str, *ks;
+
+#define BE3             0x8000      /* Byte Enable 3 */
+#define BE2             0x4000      /* Byte Enable 2 */
+#define BE1             0x2000      /* Byte Enable 1 */
+#define BE0             0x1000      /* Byte Enable 0 */
+
+static u8 ks_rdreg8(struct eth_device *dev, u16 offset)
+{
+	u8 shift_bit = offset & 0x03;
+	u8 shift_data = (offset & 1) << 3;
+
+	writew(offset | (BE0 << shift_bit), dev->iobase + 2);
+
+	return (u8)(readw(dev->iobase) >> shift_data);
+}
+
+static u16 ks_rdreg16(struct eth_device *dev, u16 offset)
+{
+	writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2);
+
+	return readw(dev->iobase);
+}
+
+static void ks_wrreg8(struct eth_device *dev, u16 offset, u8 val)
+{
+	u8 shift_bit = (offset & 0x03);
+	u16 value_write = (u16)(val << ((offset & 1) << 3));
+
+	writew(offset | (BE0 << shift_bit), dev->iobase + 2);
+	writew(value_write, dev->iobase);
+}
+
+static void ks_wrreg16(struct eth_device *dev, u16 offset, u16 val)
+{
+	writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2);
+	writew(val, dev->iobase);
+}
+
+/*
+ * ks_inblk - read a block of data from QMU. This is called after sudo DMA mode
+ * enabled.
+ * @ks: The chip state
+ * @wptr: buffer address to save data
+ * @len: length in byte to read
+ */
+static inline void ks_inblk(struct eth_device *dev, u16 *wptr, u32 len)
+{
+	len >>= 1;
+
+	while (len--)
+		*wptr++ = readw(dev->iobase);
+}
+
+/*
+ * ks_outblk - write data to QMU. This is called after sudo DMA mode enabled.
+ * @ks: The chip information
+ * @wptr: buffer address
+ * @len: length in byte to write
+ */
+static inline void ks_outblk(struct eth_device *dev, u16 *wptr, u32 len)
+{
+	len >>= 1;
+
+	while (len--)
+		writew(*wptr++, dev->iobase);
+}
+
+static void ks_enable_int(struct eth_device *dev)
+{
+	ks_wrreg16(dev, KS_IER, ks->rc_ier);
+}
+
+static void ks_set_powermode(struct eth_device *dev, unsigned pwrmode)
+{
+	unsigned pmecr;
+
+	ks_rdreg16(dev, KS_GRR);
+	pmecr = ks_rdreg16(dev, KS_PMECR);
+	pmecr &= ~PMECR_PM_MASK;
+	pmecr |= pwrmode;
+
+	ks_wrreg16(dev, KS_PMECR, pmecr);
+}
+
+/*
+ * ks_read_config - read chip configuration of bus width.
+ * @ks: The chip information
+ */
+static void ks_read_config(struct eth_device *dev)
+{
+	u16 reg_data = 0;
+
+	/* Regardless of bus width, 8 bit read should always work. */
+	reg_data = ks_rdreg8(dev, KS_CCR) & 0x00FF;
+	reg_data |= ks_rdreg8(dev, KS_CCR + 1) << 8;
+
+	/* addr/data bus are multiplexed */
+	ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED;
+
+	/*
+	 * There are garbage data when reading data from QMU,
+	 * depending on bus-width.
+	 */
+	if (reg_data & CCR_8BIT) {
+		ks->bus_width = ENUM_BUS_8BIT;
+		ks->extra_byte = 1;
+	} else if (reg_data & CCR_16BIT) {
+		ks->bus_width = ENUM_BUS_16BIT;
+		ks->extra_byte = 2;
+	} else {
+		ks->bus_width = ENUM_BUS_32BIT;
+		ks->extra_byte = 4;
+	}
+}
+
+/*
+ * ks_soft_reset - issue one of the soft reset to the device
+ * @ks: The device state.
+ * @op: The bit(s) to set in the GRR
+ *
+ * Issue the relevant soft-reset command to the device's GRR register
+ * specified by @op.
+ *
+ * Note, the delays are in there as a caution to ensure that the reset
+ * has time to take effect and then complete. Since the datasheet does
+ * not currently specify the exact sequence, we have chosen something
+ * that seems to work with our device.
+ */
+static void ks_soft_reset(struct eth_device *dev, unsigned op)
+{
+	/* Disable interrupt first */
+	ks_wrreg16(dev, KS_IER, 0x0000);
+	ks_wrreg16(dev, KS_GRR, op);
+	mdelay(10);	/* wait a short time to effect reset */
+	ks_wrreg16(dev, KS_GRR, 0);
+	mdelay(1);	/* wait for condition to clear */
+}
+
+void ks_enable_qmu(struct eth_device *dev)
+{
+	u16 w;
+
+	w = ks_rdreg16(dev, KS_TXCR);
+
+	/* Enables QMU Transmit (TXCR). */
+	ks_wrreg16(dev, KS_TXCR, w | TXCR_TXE);
+
+	/* Enable RX Frame Count Threshold and Auto-Dequeue RXQ Frame */
+	w = ks_rdreg16(dev, KS_RXQCR);
+	ks_wrreg16(dev, KS_RXQCR, w | RXQCR_RXFCTE);
+
+	/* Enables QMU Receive (RXCR1). */
+	w = ks_rdreg16(dev, KS_RXCR1);
+	ks_wrreg16(dev, KS_RXCR1, w | RXCR1_RXE);
+}
+
+static void ks_disable_qmu(struct eth_device *dev)
+{
+	u16 w;
+
+	w = ks_rdreg16(dev, KS_TXCR);
+
+	/* Disables QMU Transmit (TXCR). */
+	w &= ~TXCR_TXE;
+	ks_wrreg16(dev, KS_TXCR, w);
+
+	/* Disables QMU Receive (RXCR1). */
+	w = ks_rdreg16(dev, KS_RXCR1);
+	w &= ~RXCR1_RXE;
+	ks_wrreg16(dev, KS_RXCR1, w);
+}
+
+static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len)
+{
+	u32 r = ks->extra_byte & 0x1;
+	u32 w = ks->extra_byte - r;
+
+	/* 1. set sudo DMA mode */
+	ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI);
+	ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
+
+	/*
+	 * 2. read prepend data
+	 *
+	 * read 4 + extra bytes and discard them.
+	 * extra bytes for dummy, 2 for status, 2 for len
+	 */
+
+	if (r)
+		ks_rdreg8(dev, 0);
+
+	ks_inblk(dev, buf, w + 2 + 2);
+
+	/* 3. read pkt data */
+	ks_inblk(dev, buf, ALIGN(len, 4));
+
+	/* 4. reset sudo DMA Mode */
+	ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff);
+}
+
+static void ks_rcv(struct eth_device *dev, uchar **pv_data)
+{
+	struct type_frame_head *frame_hdr = ks->frame_head_info;
+	int i;
+
+	ks->frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8;
+
+	/* read all header information */
+	for (i = 0; i < ks->frame_cnt; i++) {
+		/* Checking Received packet status */
+		frame_hdr->sts = ks_rdreg16(dev, KS_RXFHSR);
+		/* Get packet len from hardware */
+		frame_hdr->len = ks_rdreg16(dev, KS_RXFHBCR);
+		frame_hdr++;
+	}
+
+	frame_hdr = ks->frame_head_info;
+	while (ks->frame_cnt--) {
+		if ((frame_hdr->sts & RXFSHR_RXFV) &&
+		    (frame_hdr->len < RX_BUF_SIZE) &&
+		    frame_hdr->len) {
+			/* read data block including CRC 4 bytes */
+			ks_read_qmu(dev, (u16 *)(*pv_data), frame_hdr->len);
+
+			/* NetRxPackets buffer size is ok (*pv_data pointer) */
+			NetReceive(*pv_data, frame_hdr->len);
+			pv_data++;
+		} else {
+			ks_wrreg16(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF));
+			printf(DRIVERNAME ": bad packet\n");
+		}
+		frame_hdr++;
+	}
+}
+
+/*
+ * ks_read_selftest - read the selftest memory info.
+ * @ks: The device state
+ *
+ * Read and check the TX/RX memory selftest information.
+ */
+static int ks_read_selftest(struct eth_device *dev)
+{
+	u16 both_done = MBIR_TXMBF | MBIR_RXMBF;
+	u16 mbir;
+	int ret = 0;
+
+	mbir = ks_rdreg16(dev, KS_MBIR);
+
+	if ((mbir & both_done) != both_done) {
+		printf(DRIVERNAME ": Memory selftest not finished\n");
+		return 0;
+	}
+
+	if (mbir & MBIR_TXMBFA) {
+		printf(DRIVERNAME ": TX memory selftest fails\n");
+		ret |= 1;
+	}
+
+	if (mbir & MBIR_RXMBFA) {
+		printf(DRIVERNAME ": RX memory selftest fails\n");
+		ret |= 2;
+	}
+
+	debug(DRIVERNAME ": the selftest passes\n");
+
+	return ret;
+}
+
+static void ks_setup(struct eth_device *dev)
+{
+	u16 w;
+
+	/* Setup Transmit Frame Data Pointer Auto-Increment (TXFDPR) */
+	ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI);
+
+	/* Setup Receive Frame Data Pointer Auto-Increment */
+	ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI);
+
+	/* Setup Receive Frame Threshold - 1 frame (RXFCTFC) */
+	ks_wrreg16(dev, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK);
+
+	/* Setup RxQ Command Control (RXQCR) */
+	ks->rc_rxqcr = RXQCR_CMD_CNTL;
+	ks_wrreg16(dev, KS_RXQCR, ks->rc_rxqcr);
+
+	/*
+	 * set the force mode to half duplex, default is full duplex
+	 * because if the auto-negotiation fails, most switch uses
+	 * half-duplex.
+	 */
+	w = ks_rdreg16(dev, KS_P1MBCR);
+	w &= ~P1MBCR_FORCE_FDX;
+	ks_wrreg16(dev, KS_P1MBCR, w);
+
+	w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP;
+	ks_wrreg16(dev, KS_TXCR, w);
+
+	w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXIPFCC;
+
+	/* Normal mode */
+	w |= RXCR1_RXPAFMA;
+
+	ks_wrreg16(dev, KS_RXCR1, w);
+}
+
+static void ks_setup_int(struct eth_device *dev)
+{
+	ks->rc_ier = 0x00;
+
+	/* Clear the interrupts status of the hardware. */
+	ks_wrreg16(dev, KS_ISR, 0xffff);
+
+	/* Enables the interrupts of the hardware. */
+	ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI);
+}
+
+static int ks8851_mll_detect_chip(struct eth_device *dev)
+{
+	unsigned short val, i;
+
+	ks_read_config(dev);
+
+	val = ks_rdreg16(dev, KS_CIDER);
+
+	if (val == 0xffff) {
+		/* Special case -- no chip present */
+		printf(DRIVERNAME ":  is chip mounted ?\n");
+		return -1;
+	} else if ((val & 0xfff0) != CIDER_ID) {
+		printf(DRIVERNAME ": Invalid chip id 0x%04x\n", val);
+		return -1;
+	}
+
+	debug("Read back KS8851 id 0x%x\n", val);
+
+	/* only one entry in the table */
+	val &= 0xfff0;
+	for (i = 0; chip_ids[i].id != 0; i++) {
+		if (chip_ids[i].id == val)
+			break;
+	}
+	if (!chip_ids[i].id) {
+		printf(DRIVERNAME ": Unknown chip ID %04x\n", val);
+		return -1;
+	}
+
+	dev->priv = (void *)&chip_ids[i];
+
+	return 0;
+}
+
+static void ks8851_mll_reset(struct eth_device *dev)
+{
+	/* wake up powermode to normal mode */
+	ks_set_powermode(dev, PMECR_PM_NORMAL);
+	mdelay(1);	/* wait for normal mode to take effect */
+
+	/* Disable interrupt and reset */
+	ks_soft_reset(dev, GRR_GSR);
+
+	/* turn off the IRQs and ack any outstanding */
+	ks_wrreg16(dev, KS_IER, 0x0000);
+	ks_wrreg16(dev, KS_ISR, 0xffff);
+
+	/* shutdown RX/TX QMU */
+	ks_disable_qmu(dev);
+}
+
+static void ks8851_mll_phy_configure(struct eth_device *dev)
+{
+	u16 data;
+
+	ks_setup(dev);
+	ks_setup_int(dev);
+
+	/* Probing the phy */
+	data = ks_rdreg16(dev, KS_OBCR);
+	ks_wrreg16(dev, KS_OBCR, data | OBCR_ODS_16MA);
+
+	debug(DRIVERNAME ": phy initialized\n");
+}
+
+static void ks8851_mll_enable(struct eth_device *dev)
+{
+	ks_wrreg16(dev, KS_ISR, 0xffff);
+	ks_enable_int(dev);
+	ks_enable_qmu(dev);
+}
+
+static int ks8851_mll_init(struct eth_device *dev, bd_t *bd)
+{
+	struct chip_id *id = dev->priv;
+
+	debug(DRIVERNAME ": detected %s controller\n", id->name);
+
+	if (ks_read_selftest(dev)) {
+		printf(DRIVERNAME ": Selftest failed\n");
+		return -1;
+	}
+
+	ks8851_mll_reset(dev);
+
+	/* Configure the PHY, initialize the link state */
+	ks8851_mll_phy_configure(dev);
+
+	/* static allocation of private informations */
+	ks->frame_head_info = fr_h_i;
+
+	/* Turn on Tx + Rx */
+	ks8851_mll_enable(dev);
+
+	return 0;
+}
+
+static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len)
+{
+	/* start header at txb[0] to align txw entries */
+	ks->txh.txw[0] = 0;
+	ks->txh.txw[1] = cpu_to_le16(len);
+
+	/* 1. set sudo-DMA mode */
+	ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI);
+	ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
+	/* 2. write status/lenth info */
+	ks_outblk(dev, ks->txh.txw, 4);
+	/* 3. write pkt data */
+	ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4));
+	/* 4. reset sudo-DMA mode */
+	ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff);
+	/* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */
+	ks_wrreg16(dev, KS_TXQCR, TXQCR_METFE);
+	/* 6. wait until TXQCR_METFE is auto-cleared */
+	do { } while (ks_rdreg16(dev, KS_TXQCR) & TXQCR_METFE);
+}
+
+static int ks8851_mll_send(struct eth_device *dev, void *packet, int length)
+{
+	u8 *data = (u8 *)packet;
+	u16 tmplen = (u16)length;
+	u16 retv;
+
+	/*
+	 * Extra space are required:
+	 * 4 byte for alignment, 4 for status/length, 4 for CRC
+	 */
+	retv = ks_rdreg16(dev, KS_TXMIR) & 0x1fff;
+	if (retv >= tmplen + 12) {
+		ks_write_qmu(dev, data, tmplen);
+		return 0;
+	} else {
+		printf(DRIVERNAME ": failed to send packet: No buffer\n");
+		return -1;
+	}
+}
+
+static void ks8851_mll_halt(struct eth_device *dev)
+{
+	ks8851_mll_reset(dev);
+}
+
+/*
+ * Maximum receive ring size; that is, the number of packets
+ * we can buffer before overflow happens. Basically, this just
+ * needs to be enough to prevent a packet being discarded while
+ * we are processing the previous one.
+ */
+static int ks8851_mll_recv(struct eth_device *dev)
+{
+	u16 status;
+
+	status = ks_rdreg16(dev, KS_ISR);
+
+	ks_wrreg16(dev, KS_ISR, status);
+
+	if ((status & IRQ_RXI))
+		ks_rcv(dev, (uchar **)NetRxPackets);
+
+	if ((status & IRQ_LDI)) {
+		u16 pmecr = ks_rdreg16(dev, KS_PMECR);
+		pmecr &= ~PMECR_WKEVT_MASK;
+		ks_wrreg16(dev, KS_PMECR, pmecr | PMECR_WKEVT_LINK);
+	}
+
+	return 0;
+}
+
+static int ks8851_mll_write_hwaddr(struct eth_device *dev)
+{
+	u16 addrl, addrm, addrh;
+
+	addrh = (dev->enetaddr[0] << 8) | dev->enetaddr[1];
+	addrm = (dev->enetaddr[2] << 8) | dev->enetaddr[3];
+	addrl = (dev->enetaddr[4] << 8) | dev->enetaddr[5];
+
+	ks_wrreg16(dev, KS_MARH, addrh);
+	ks_wrreg16(dev, KS_MARM, addrm);
+	ks_wrreg16(dev, KS_MARL, addrl);
+
+	return 0;
+}
+
+int ks8851_mll_initialize(u8 dev_num, int base_addr)
+{
+	struct eth_device *dev;
+
+	dev = malloc(sizeof(*dev));
+	if (!dev) {
+		printf("Error: Failed to allocate memory\n");
+		return -1;
+	}
+	memset(dev, 0, sizeof(*dev));
+
+	dev->iobase = base_addr;
+
+	ks = &ks_str;
+
+	/* Try to detect chip. Will fail if not present. */
+	if (ks8851_mll_detect_chip(dev)) {
+		free(dev);
+		return -1;
+	}
+
+	dev->init = ks8851_mll_init;
+	dev->halt = ks8851_mll_halt;
+	dev->send = ks8851_mll_send;
+	dev->recv = ks8851_mll_recv;
+	dev->write_hwaddr = ks8851_mll_write_hwaddr;
+	sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num);
+
+	eth_register(dev);
+
+	return 0;
+}
diff --git a/drivers/net/ks8851_mll.h b/drivers/net/ks8851_mll.h
new file mode 100644
index 0000000..7f90ae4
--- /dev/null
+++ b/drivers/net/ks8851_mll.h
@@ -0,0 +1,357 @@
+/*
+ * drivers/net/ks8851_mll.c
+ *
+ * Supports:
+ * KS8851 16bit MLL chip from Micrel Inc.
+ *
+ * Copyright (c) 2009 Micrel Inc.
+ *
+ * modified by
+ * (c) 2011 Bticino s.p.a, Roberto Cerati <roberto.cerati@bticino.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _KS8851_MLL_H_
+#define _KS8851_MLL_H_
+
+#include <linux/types.h>
+
+#define KS_CCR				0x08
+#define CCR_EEPROM			(1 << 9)
+#define CCR_SPI				(1 << 8)
+#define CCR_8BIT			(1 << 7)
+#define CCR_16BIT			(1 << 6)
+#define CCR_32BIT			(1 << 5)
+#define CCR_SHARED			(1 << 4)
+#define CCR_32PIN			(1 << 0)
+
+/* MAC address registers */
+#define KS_MARL				0x10
+#define KS_MARM				0x12
+#define KS_MARH				0x14
+
+#define KS_OBCR				0x20
+#define OBCR_ODS_16MA			(1 << 6)
+
+#define KS_EEPCR			0x22
+#define EEPCR_EESA			(1 << 4)
+#define EEPCR_EESB			(1 << 3)
+#define EEPCR_EEDO			(1 << 2)
+#define EEPCR_EESCK			(1 << 1)
+#define EEPCR_EECS			(1 << 0)
+
+#define KS_MBIR				0x24
+#define MBIR_TXMBF			(1 << 12)
+#define MBIR_TXMBFA			(1 << 11)
+#define MBIR_RXMBF			(1 << 4)
+#define MBIR_RXMBFA			(1 << 3)
+
+#define KS_GRR				0x26
+#define GRR_QMU				(1 << 1)
+#define GRR_GSR				(1 << 0)
+
+#define KS_WFCR				0x2A
+#define WFCR_MPRXE			(1 << 7)
+#define WFCR_WF3E			(1 << 3)
+#define WFCR_WF2E			(1 << 2)
+#define WFCR_WF1E			(1 << 1)
+#define WFCR_WF0E			(1 << 0)
+
+#define KS_WF0CRC0			0x30
+#define KS_WF0CRC1			0x32
+#define KS_WF0BM0			0x34
+#define KS_WF0BM1			0x36
+#define KS_WF0BM2			0x38
+#define KS_WF0BM3			0x3A
+
+#define KS_WF1CRC0			0x40
+#define KS_WF1CRC1			0x42
+#define KS_WF1BM0			0x44
+#define KS_WF1BM1			0x46
+#define KS_WF1BM2			0x48
+#define KS_WF1BM3			0x4A
+
+#define KS_WF2CRC0			0x50
+#define KS_WF2CRC1			0x52
+#define KS_WF2BM0			0x54
+#define KS_WF2BM1			0x56
+#define KS_WF2BM2			0x58
+#define KS_WF2BM3			0x5A
+
+#define KS_WF3CRC0			0x60
+#define KS_WF3CRC1			0x62
+#define KS_WF3BM0			0x64
+#define KS_WF3BM1			0x66
+#define KS_WF3BM2			0x68
+#define KS_WF3BM3			0x6A
+
+#define KS_TXCR				0x70
+#define TXCR_TCGICMP			(1 << 8)
+#define TXCR_TCGUDP			(1 << 7)
+#define TXCR_TCGTCP			(1 << 6)
+#define TXCR_TCGIP			(1 << 5)
+#define TXCR_FTXQ			(1 << 4)
+#define TXCR_TXFCE			(1 << 3)
+#define TXCR_TXPE			(1 << 2)
+#define TXCR_TXCRC			(1 << 1)
+#define TXCR_TXE			(1 << 0)
+
+#define KS_TXSR				0x72
+#define TXSR_TXLC			(1 << 13)
+#define TXSR_TXMC			(1 << 12)
+#define TXSR_TXFID_MASK			(0x3f << 0)
+#define TXSR_TXFID_SHIFT		(0)
+#define TXSR_TXFID_GET(_v)		(((_v) >> 0) & 0x3f)
+
+
+#define KS_RXCR1			0x74
+#define RXCR1_FRXQ			(1 << 15)
+#define RXCR1_RXUDPFCC			(1 << 14)
+#define RXCR1_RXTCPFCC			(1 << 13)
+#define RXCR1_RXIPFCC			(1 << 12)
+#define RXCR1_RXPAFMA			(1 << 11)
+#define RXCR1_RXFCE			(1 << 10)
+#define RXCR1_RXEFE			(1 << 9)
+#define RXCR1_RXMAFMA			(1 << 8)
+#define RXCR1_RXBE			(1 << 7)
+#define RXCR1_RXME			(1 << 6)
+#define RXCR1_RXUE			(1 << 5)
+#define RXCR1_RXAE			(1 << 4)
+#define RXCR1_RXINVF			(1 << 1)
+#define RXCR1_RXE			(1 << 0)
+#define RXCR1_FILTER_MASK		(RXCR1_RXINVF | RXCR1_RXAE | \
+					 RXCR1_RXMAFMA | RXCR1_RXPAFMA)
+
+#define KS_RXCR2			0x76
+#define RXCR2_SRDBL_MASK		(0x7 << 5)
+#define RXCR2_SRDBL_SHIFT		(5)
+#define RXCR2_SRDBL_4B			(0x0 << 5)
+#define RXCR2_SRDBL_8B			(0x1 << 5)
+#define RXCR2_SRDBL_16B			(0x2 << 5)
+#define RXCR2_SRDBL_32B			(0x3 << 5)
+/* #define RXCR2_SRDBL_FRAME		(0x4 << 5) */
+#define RXCR2_IUFFP			(1 << 4)
+#define RXCR2_RXIUFCEZ			(1 << 3)
+#define RXCR2_UDPLFE			(1 << 2)
+#define RXCR2_RXICMPFCC			(1 << 1)
+#define RXCR2_RXSAF			(1 << 0)
+
+#define KS_TXMIR			0x78
+
+#define KS_RXFHSR			0x7C
+#define RXFSHR_RXFV			(1 << 15)
+#define RXFSHR_RXICMPFCS		(1 << 13)
+#define RXFSHR_RXIPFCS			(1 << 12)
+#define RXFSHR_RXTCPFCS			(1 << 11)
+#define RXFSHR_RXUDPFCS			(1 << 10)
+#define RXFSHR_RXBF			(1 << 7)
+#define RXFSHR_RXMF			(1 << 6)
+#define RXFSHR_RXUF			(1 << 5)
+#define RXFSHR_RXMR			(1 << 4)
+#define RXFSHR_RXFT			(1 << 3)
+#define RXFSHR_RXFTL			(1 << 2)
+#define RXFSHR_RXRF			(1 << 1)
+#define RXFSHR_RXCE			(1 << 0)
+#define RXFSHR_ERR			(RXFSHR_RXCE | RXFSHR_RXRF |\
+					RXFSHR_RXFTL | RXFSHR_RXMR |\
+					RXFSHR_RXICMPFCS | RXFSHR_RXIPFCS |\
+					RXFSHR_RXTCPFCS)
+#define KS_RXFHBCR			0x7E
+#define RXFHBCR_CNT_MASK		0x0FFF
+
+#define KS_TXQCR			0x80
+#define TXQCR_AETFE			(1 << 2)
+#define TXQCR_TXQMAM			(1 << 1)
+#define TXQCR_METFE			(1 << 0)
+
+#define KS_RXQCR			0x82
+#define RXQCR_RXDTTS			(1 << 12)
+#define RXQCR_RXDBCTS			(1 << 11)
+#define RXQCR_RXFCTS			(1 << 10)
+#define RXQCR_RXIPHTOE			(1 << 9)
+#define RXQCR_RXDTTE			(1 << 7)
+#define RXQCR_RXDBCTE			(1 << 6)
+#define RXQCR_RXFCTE			(1 << 5)
+#define RXQCR_ADRFE			(1 << 4)
+#define RXQCR_SDA			(1 << 3)
+#define RXQCR_RRXEF			(1 << 0)
+#define RXQCR_CMD_CNTL			(RXQCR_RXFCTE|RXQCR_ADRFE)
+
+#define KS_TXFDPR			0x84
+#define TXFDPR_TXFPAI			(1 << 14)
+#define TXFDPR_TXFP_MASK		(0x7ff << 0)
+#define TXFDPR_TXFP_SHIFT		(0)
+
+#define KS_RXFDPR			0x86
+#define RXFDPR_RXFPAI			(1 << 14)
+
+#define KS_RXDTTR			0x8C
+#define KS_RXDBCTR			0x8E
+
+#define KS_IER				0x90
+#define KS_ISR				0x92
+#define IRQ_LCI				(1 << 15)
+#define IRQ_TXI				(1 << 14)
+#define IRQ_RXI				(1 << 13)
+#define IRQ_RXOI			(1 << 11)
+#define IRQ_TXPSI			(1 << 9)
+#define IRQ_RXPSI			(1 << 8)
+#define IRQ_TXSAI			(1 << 6)
+#define IRQ_RXWFDI			(1 << 5)
+#define IRQ_RXMPDI			(1 << 4)
+#define IRQ_LDI				(1 << 3)
+#define IRQ_EDI				(1 << 2)
+#define IRQ_SPIBEI			(1 << 1)
+#define IRQ_DEDI			(1 << 0)
+
+#define KS_RXFCTR			0x9C
+#define RXFCTR_THRESHOLD_MASK		0x00FF
+
+#define KS_RXFC				0x9D
+#define RXFCTR_RXFC_MASK		(0xff << 8)
+#define RXFCTR_RXFC_SHIFT		(8)
+#define RXFCTR_RXFC_GET(_v)		(((_v) >> 8) & 0xff)
+#define RXFCTR_RXFCT_MASK		(0xff << 0)
+#define RXFCTR_RXFCT_SHIFT		(0)
+
+#define KS_TXNTFSR			0x9E
+
+#define KS_MAHTR0			0xA0
+#define KS_MAHTR1			0xA2
+#define KS_MAHTR2			0xA4
+#define KS_MAHTR3			0xA6
+
+#define KS_FCLWR			0xB0
+#define KS_FCHWR			0xB2
+#define KS_FCOWR			0xB4
+
+#define KS_CIDER			0xC0
+#define CIDER_ID			0x8870
+#define CIDER_REV_MASK			(0x7 << 1)
+#define CIDER_REV_SHIFT			(1)
+#define CIDER_REV_GET(_v)		(((_v) >> 1) & 0x7)
+
+#define KS_CGCR				0xC6
+#define KS_IACR				0xC8
+#define IACR_RDEN			(1 << 12)
+#define IACR_TSEL_MASK			(0x3 << 10)
+#define IACR_TSEL_SHIFT			(10)
+#define IACR_TSEL_MIB			(0x3 << 10)
+#define IACR_ADDR_MASK			(0x1f << 0)
+#define IACR_ADDR_SHIFT			(0)
+
+#define KS_IADLR			0xD0
+#define KS_IAHDR			0xD2
+
+#define KS_PMECR			0xD4
+#define PMECR_PME_DELAY			(1 << 14)
+#define PMECR_PME_POL			(1 << 12)
+#define PMECR_WOL_WAKEUP		(1 << 11)
+#define PMECR_WOL_MAGICPKT		(1 << 10)
+#define PMECR_WOL_LINKUP		(1 << 9)
+#define PMECR_WOL_ENERGY		(1 << 8)
+#define PMECR_AUTO_WAKE_EN		(1 << 7)
+#define PMECR_WAKEUP_NORMAL		(1 << 6)
+#define PMECR_WKEVT_MASK		(0xf << 2)
+#define PMECR_WKEVT_SHIFT		(2)
+#define PMECR_WKEVT_GET(_v)		(((_v) >> 2) & 0xf)
+#define PMECR_WKEVT_ENERGY		(0x1 << 2)
+#define PMECR_WKEVT_LINK		(0x2 << 2)
+#define PMECR_WKEVT_MAGICPKT		(0x4 << 2)
+#define PMECR_WKEVT_FRAME		(0x8 << 2)
+#define PMECR_PM_MASK			(0x3 << 0)
+#define PMECR_PM_SHIFT			(0)
+#define PMECR_PM_NORMAL			(0x0 << 0)
+#define PMECR_PM_ENERGY			(0x1 << 0)
+#define PMECR_PM_SOFTDOWN		(0x2 << 0)
+#define PMECR_PM_POWERSAVE		(0x3 << 0)
+
+/* Standard MII PHY data */
+#define KS_P1MBCR			0xE4
+#define P1MBCR_FORCE_FDX		(1 << 8)
+
+#define KS_P1MBSR			0xE6
+#define P1MBSR_AN_COMPLETE		(1 << 5)
+#define P1MBSR_AN_CAPABLE		(1 << 3)
+#define P1MBSR_LINK_UP			(1 << 2)
+
+#define KS_PHY1ILR			0xE8
+#define KS_PHY1IHR			0xEA
+#define KS_P1ANAR			0xEC
+#define KS_P1ANLPR			0xEE
+
+#define KS_P1SCLMD			0xF4
+#define P1SCLMD_LEDOFF			(1 << 15)
+#define P1SCLMD_TXIDS			(1 << 14)
+#define P1SCLMD_RESTARTAN		(1 << 13)
+#define P1SCLMD_DISAUTOMDIX		(1 << 10)
+#define P1SCLMD_FORCEMDIX		(1 << 9)
+#define P1SCLMD_AUTONEGEN		(1 << 7)
+#define P1SCLMD_FORCE100		(1 << 6)
+#define P1SCLMD_FORCEFDX		(1 << 5)
+#define P1SCLMD_ADV_FLOW		(1 << 4)
+#define P1SCLMD_ADV_100BT_FDX		(1 << 3)
+#define P1SCLMD_ADV_100BT_HDX		(1 << 2)
+#define P1SCLMD_ADV_10BT_FDX		(1 << 1)
+#define P1SCLMD_ADV_10BT_HDX		(1 << 0)
+
+#define KS_P1CR				0xF6
+#define P1CR_HP_MDIX			(1 << 15)
+#define P1CR_REV_POL			(1 << 13)
+#define P1CR_OP_100M			(1 << 10)
+#define P1CR_OP_FDX			(1 << 9)
+#define P1CR_OP_MDI			(1 << 7)
+#define P1CR_AN_DONE			(1 << 6)
+#define P1CR_LINK_GOOD			(1 << 5)
+#define P1CR_PNTR_FLOW			(1 << 4)
+#define P1CR_PNTR_100BT_FDX		(1 << 3)
+#define P1CR_PNTR_100BT_HDX		(1 << 2)
+#define P1CR_PNTR_10BT_FDX		(1 << 1)
+#define P1CR_PNTR_10BT_HDX		(1 << 0)
+
+/* TX Frame control */
+#define TXFR_TXIC			(1 << 15)
+#define TXFR_TXFID_MASK			(0x3f << 0)
+#define TXFR_TXFID_SHIFT		(0)
+
+#define KS_P1SR				0xF8
+#define P1SR_HP_MDIX			(1 << 15)
+#define P1SR_REV_POL			(1 << 13)
+#define P1SR_OP_100M			(1 << 10)
+#define P1SR_OP_FDX			(1 << 9)
+#define P1SR_OP_MDI			(1 << 7)
+#define P1SR_AN_DONE			(1 << 6)
+#define P1SR_LINK_GOOD			(1 << 5)
+#define P1SR_PNTR_FLOW			(1 << 4)
+#define P1SR_PNTR_100BT_FDX		(1 << 3)
+#define P1SR_PNTR_100BT_HDX		(1 << 2)
+#define P1SR_PNTR_10BT_FDX		(1 << 1)
+#define P1SR_PNTR_10BT_HDX		(1 << 0)
+
+#define ENUM_BUS_NONE			0
+#define ENUM_BUS_8BIT			1
+#define ENUM_BUS_16BIT			2
+#define ENUM_BUS_32BIT			3
+
+#define MAX_MCAST_LST			32
+#define HW_MCAST_SIZE			8
+#define MAC_ADDR_LEN			6
+
+/* Chip ID values */
+struct chip_id {
+	u16 id;
+	char *name;
+};
+
+#endif
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 8bacbda..b7802a2 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -103,9 +103,15 @@
 	const struct device	*dev;
 	struct eth_device	netdev;
 	unsigned short		phy_addr;
+	struct mii_dev		*bus;
 };
 #define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
 
+static int macb_is_gem(struct macb_device *macb)
+{
+	return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2;
+}
+
 static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
 {
 	unsigned long netctl;
@@ -163,7 +169,12 @@
 	return MACB_BFEXT(DATA, frame);
 }
 
-#if defined(CONFIG_CMD_MII)
+void __weak arch_get_mdio_control(const char *name)
+{
+	return;
+}
+
+#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
 
 int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
 {
@@ -173,6 +184,7 @@
 	if ( macb->phy_addr != phy_adr )
 		return -1;
 
+	arch_get_mdio_control(devname);
 	*value = macb_mdio_read(macb, reg);
 
 	return 0;
@@ -186,6 +198,7 @@
 	if ( macb->phy_addr != phy_adr )
 		return -1;
 
+	arch_get_mdio_control(devname);
 	macb_mdio_write(macb, reg, value);
 
 	return 0;
@@ -372,11 +385,15 @@
 static int macb_phy_init(struct macb_device *macb)
 {
 	struct eth_device *netdev = &macb->netdev;
+#ifdef CONFIG_PHYLIB
+	struct phy_device *phydev;
+#endif
 	u32 ncfgr;
 	u16 phy_id, status, adv, lpa;
 	int media, speed, duplex;
 	int i;
 
+	arch_get_mdio_control(netdev->name);
 #ifdef CONFIG_MACB_SEARCH_PHY
 	/* Auto-detect phy_addr */
 	if (!macb_phy_find(macb)) {
@@ -391,6 +408,13 @@
 		return 0;
 	}
 
+#ifdef CONFIG_PHYLIB
+	phydev->bus = macb->bus;
+	phydev->dev = netdev;
+	phydev->addr = macb->phy_addr;
+	phy_config(phydev);
+#endif
+
 	status = macb_mdio_read(macb, MII_BMSR);
 	if (!(status & BMSR_LSTATUS)) {
 		/* Try to re-negotiate if we don't have link already. */
@@ -408,28 +432,64 @@
 		printf("%s: link down (status: 0x%04x)\n",
 		       netdev->name, status);
 		return 0;
-	} else {
-		adv = macb_mdio_read(macb, MII_ADVERTISE);
-		lpa = macb_mdio_read(macb, MII_LPA);
-		media = mii_nway_result(lpa & adv);
-		speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
-			 ? 1 : 0);
-		duplex = (media & ADVERTISE_FULL) ? 1 : 0;
-		printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
-		       netdev->name,
-		       speed ? "100" : "10",
-		       duplex ? "full" : "half",
-		       lpa);
+	}
 
-		ncfgr = macb_readl(macb, NCFGR);
-		ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
-		if (speed)
-			ncfgr |= MACB_BIT(SPD);
-		if (duplex)
-			ncfgr |= MACB_BIT(FD);
-		macb_writel(macb, NCFGR, ncfgr);
-		return 1;
+	/* First check for GMAC */
+	if (macb_is_gem(macb)) {
+		lpa = macb_mdio_read(macb, MII_STAT1000);
+		if (lpa & (1 << 11)) {
+			speed = 1000;
+			duplex = 1;
+		} else {
+		       if (lpa & (1 << 10)) {
+				speed = 1000;
+				duplex = 1;
+			} else {
+				speed = 0;
+			}
+		}
+
+		if (speed == 1000) {
+			printf("%s: link up, %dMbps %s-duplex (lpa: 0x%04x)\n",
+			       netdev->name,
+			       speed,
+			       duplex ? "full" : "half",
+			       lpa);
+
+			ncfgr = macb_readl(macb, NCFGR);
+			ncfgr &= ~(GEM_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD));
+			if (speed)
+				ncfgr |= GEM_BIT(GBE);
+			if (duplex)
+				ncfgr |= MACB_BIT(FD);
+			macb_writel(macb, NCFGR, ncfgr);
+
+			return 1;
+		}
 	}
+
+	/* fall back for EMAC checking */
+	adv = macb_mdio_read(macb, MII_ADVERTISE);
+	lpa = macb_mdio_read(macb, MII_LPA);
+	media = mii_nway_result(lpa & adv);
+	speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+		 ? 1 : 0);
+	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+	printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
+	       netdev->name,
+	       speed ? "100" : "10",
+	       duplex ? "full" : "half",
+	       lpa);
+
+	ncfgr = macb_readl(macb, NCFGR);
+	ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
+	if (speed)
+		ncfgr |= MACB_BIT(SPD);
+	if (duplex)
+		ncfgr |= MACB_BIT(FD);
+	macb_writel(macb, NCFGR, ncfgr);
+
+	return 1;
 }
 
 static int macb_init(struct eth_device *netdev, bd_t *bd)
@@ -464,26 +524,28 @@
 	macb_writel(macb, RBQP, macb->rx_ring_dma);
 	macb_writel(macb, TBQP, macb->tx_ring_dma);
 
+	if (macb_is_gem(macb)) {
+#ifdef CONFIG_RGMII
+		gem_writel(macb, UR, GEM_BIT(RGMII));
+#else
+		gem_writel(macb, UR, 0);
+#endif
+	} else {
 	/* choose RMII or MII mode. This depends on the board */
 #ifdef CONFIG_RMII
-#if	defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
-	defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \
-	defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \
-	defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5)
+#ifdef CONFIG_AT91FAMILY
 	macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN));
 #else
 	macb_writel(macb, USRIO, 0);
 #endif
 #else
-#if	defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
-	defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \
-	defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \
-	defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5)
+#ifdef CONFIG_AT91FAMILY
 	macb_writel(macb, USRIO, MACB_BIT(CLKEN));
 #else
 	macb_writel(macb, USRIO, MACB_BIT(MII));
 #endif
 #endif /* CONFIG_RMII */
+	}
 
 	if (!macb_phy_init(macb))
 		return -1;
@@ -527,11 +589,48 @@
 	return 0;
 }
 
+static u32 macb_mdc_clk_div(int id, struct macb_device *macb)
+{
+	u32 config;
+	unsigned long macb_hz = get_macb_pclk_rate(id);
+
+	if (macb_hz < 20000000)
+		config = MACB_BF(CLK, MACB_CLK_DIV8);
+	else if (macb_hz < 40000000)
+		config = MACB_BF(CLK, MACB_CLK_DIV16);
+	else if (macb_hz < 80000000)
+		config = MACB_BF(CLK, MACB_CLK_DIV32);
+	else
+		config = MACB_BF(CLK, MACB_CLK_DIV64);
+
+	return config;
+}
+
+static u32 gem_mdc_clk_div(int id, struct macb_device *macb)
+{
+	u32 config;
+	unsigned long macb_hz = get_macb_pclk_rate(id);
+
+	if (macb_hz < 20000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV8);
+	else if (macb_hz < 40000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV16);
+	else if (macb_hz < 80000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV32);
+	else if (macb_hz < 120000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV48);
+	else if (macb_hz < 160000000)
+		config = GEM_BF(CLK, GEM_CLK_DIV64);
+	else
+		config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+	return config;
+}
+
 int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
 {
 	struct macb_device *macb;
 	struct eth_device *netdev;
-	unsigned long macb_hz;
 	u32 ncfgr;
 
 	macb = malloc(sizeof(struct macb_device));
@@ -555,7 +654,11 @@
 	macb->regs = regs;
 	macb->phy_addr = phy_addr;
 
+	if (macb_is_gem(macb))
+		sprintf(netdev->name, "gmac%d", id);
+	else
+		sprintf(netdev->name, "macb%d", id);
+
-	sprintf(netdev->name, "macb%d", id);
 	netdev->init = macb_init;
 	netdev->halt = macb_halt;
 	netdev->send = macb_send;
@@ -566,22 +669,20 @@
 	 * Do some basic initialization so that we at least can talk
 	 * to the PHY
 	 */
-	macb_hz = get_macb_pclk_rate(id);
-	if (macb_hz < 20000000)
-		ncfgr = MACB_BF(CLK, MACB_CLK_DIV8);
-	else if (macb_hz < 40000000)
-		ncfgr = MACB_BF(CLK, MACB_CLK_DIV16);
-	else if (macb_hz < 80000000)
-		ncfgr = MACB_BF(CLK, MACB_CLK_DIV32);
-	else
-		ncfgr = MACB_BF(CLK, MACB_CLK_DIV64);
+	if (macb_is_gem(macb)) {
+		ncfgr = gem_mdc_clk_div(id, macb);
+		ncfgr |= GEM_BF(DBW, 1);
+	} else {
+		ncfgr = macb_mdc_clk_div(id, macb);
+	}
 
 	macb_writel(macb, NCFGR, ncfgr);
 
 	eth_register(netdev);
 
-#if defined(CONFIG_CMD_MII)
+#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
 	miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write);
+	macb->bus = miiphy_get_dev_by_name(netdev->name);
 #endif
 	return 0;
 }
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index f92a20c..68eef00 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -26,6 +26,7 @@
 #define MACB_NCR				0x0000
 #define MACB_NCFGR				0x0004
 #define MACB_NSR				0x0008
+#define GEM_UR					0x000c
 #define MACB_TSR				0x0014
 #define MACB_RBQP				0x0018
 #define MACB_TBQP				0x001c
@@ -71,6 +72,7 @@
 #define MACB_TPQ				0x00bc
 #define MACB_USRIO				0x00c0
 #define MACB_WOL				0x00c4
+#define MACB_MID				0x00fc
 
 /* Bitfields in NCR */
 #define MACB_LB_OFFSET				0
@@ -138,6 +140,13 @@
 #define MACB_IRXFCS_OFFSET			19
 #define MACB_IRXFCS_SIZE			1
 
+#define GEM_GBE_OFFSET				10
+#define GEM_GBE_SIZE				1
+#define GEM_CLK_OFFSET				18
+#define GEM_CLK_SIZE				3
+#define GEM_DBW_OFFSET				21
+#define GEM_DBW_SIZE				2
+
 /* Bitfields in NSR */
 #define MACB_NSR_LINK_OFFSET			0
 #define MACB_NSR_LINK_SIZE			1
@@ -146,6 +155,10 @@
 #define MACB_IDLE_OFFSET			2
 #define MACB_IDLE_SIZE				1
 
+/* Bitfields in UR */
+#define GEM_RGMII_OFFSET			0
+#define GEM_RGMII_SIZE				1
+
 /* Bitfields in TSR */
 #define MACB_UBR_OFFSET				0
 #define MACB_UBR_SIZE				1
@@ -240,12 +253,25 @@
 #define MACB_WOL_MTI_OFFSET			19
 #define MACB_WOL_MTI_SIZE			1
 
+/* Bitfields in MID */
+#define MACB_IDNUM_OFFSET			16
+#define MACB_IDNUM_SIZE				16
+
+/* Bitfields in DCFG1 */
 /* Constants for CLK */
 #define MACB_CLK_DIV8				0
 #define MACB_CLK_DIV16				1
 #define MACB_CLK_DIV32				2
 #define MACB_CLK_DIV64				3
 
+/* GEM specific constants for CLK */
+#define GEM_CLK_DIV8				0
+#define GEM_CLK_DIV16				1
+#define GEM_CLK_DIV32				2
+#define GEM_CLK_DIV48				3
+#define GEM_CLK_DIV64				4
+#define GEM_CLK_DIV96				5
+
 /* Constants for MAN register */
 #define MACB_MAN_SOF				1
 #define MACB_MAN_WRITE				1
@@ -255,21 +281,38 @@
 /* Bit manipulation macros */
 #define MACB_BIT(name)					\
 	(1 << MACB_##name##_OFFSET)
-#define MACB_BF(name,value)				\
+#define MACB_BF(name, value)				\
 	(((value) & ((1 << MACB_##name##_SIZE) - 1))	\
 	 << MACB_##name##_OFFSET)
-#define MACB_BFEXT(name,value)\
+#define MACB_BFEXT(name, value)\
 	(((value) >> MACB_##name##_OFFSET)		\
 	 & ((1 << MACB_##name##_SIZE) - 1))
-#define MACB_BFINS(name,value,old)			\
+#define MACB_BFINS(name, value, old)			\
 	(((old) & ~(((1 << MACB_##name##_SIZE) - 1)	\
 		    << MACB_##name##_OFFSET))		\
-	 | MACB_BF(name,value))
+	 | MACB_BF(name, value))
+
+#define GEM_BIT(name)					\
+	(1 << GEM_##name##_OFFSET)
+#define GEM_BF(name, value)				\
+	(((value) & ((1 << GEM_##name##_SIZE) - 1))	\
+	 << GEM_##name##_OFFSET)
+#define GEM_BFEXT(name, value)\
+	(((value) >> GEM_##name##_OFFSET)		\
+	 & ((1 << GEM_##name##_SIZE) - 1))
+#define GEM_BFINS(name, value, old)			\
+	(((old) & ~(((1 << GEM_##name##_SIZE) - 1)	\
+		    << GEM_##name##_OFFSET))		\
+	 | GEM_BF(name, value))
 
 /* Register access macros */
-#define macb_readl(port,reg)				\
+#define macb_readl(port, reg)				\
 	readl((port)->regs + MACB_##reg)
-#define macb_writel(port,reg,value)			\
+#define macb_writel(port, reg, value)			\
 	writel((value), (port)->regs + MACB_##reg)
+#define gem_readl(port, reg)				\
+	readl((port)->regs + GEM_##reg)
+#define gem_writel(port, reg, value)			\
+	writel((value), (port)->regs + GEM_##reg)
 
 #endif /* __DRIVERS_MACB_H__ */
diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c
index 47bf27c..319fe8a 100644
--- a/drivers/net/mvgbe.c
+++ b/drivers/net/mvgbe.c
@@ -43,6 +43,8 @@
 #include <asm/arch/kirkwood.h>
 #elif defined(CONFIG_ORION5X)
 #include <asm/arch/orion5x.h>
+#elif defined(CONFIG_DOVE)
+#include <asm/arch/dove.h>
 #endif
 
 #include "mvgbe.h"
@@ -52,7 +54,7 @@
 #define MV_PHY_ADR_REQUEST 0xee
 #define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi)
 
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
 /*
  * smi_reg_read - miiphy_read callback function.
  *
@@ -184,6 +186,25 @@
 }
 #endif
 
+#if defined(CONFIG_PHYLIB)
+int mvgbe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
+		   int reg_addr)
+{
+	u16 data;
+	int ret;
+	ret = smi_reg_read(bus->name, phy_addr, reg_addr, &data);
+	if (ret)
+		return ret;
+	return data;
+}
+
+int mvgbe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
+		    int reg_addr, u16 data)
+{
+	return smi_reg_write(bus->name, phy_addr, reg_addr, data);
+}
+#endif
+
 /* Stop and checks all queues */
 static void stop_queue(u32 * qreg)
 {
@@ -467,8 +488,9 @@
 	/* Enable port Rx. */
 	MVGBE_REG_WR(regs->rqc, (1 << RXUQ));
 
-#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \
-	 && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
+	!defined(CONFIG_PHYLIB) && \
+	defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
 	/* Wait up to 5s for the link status */
 	for (i = 0; i < 5; i++) {
 		u16 phyadr;
@@ -647,6 +669,45 @@
 	return 0;
 }
 
+#if defined(CONFIG_PHYLIB)
+int mvgbe_phylib_init(struct eth_device *dev, int phyid)
+{
+	struct mii_dev *bus;
+	struct phy_device *phydev;
+	int ret;
+
+	bus = mdio_alloc();
+	if (!bus) {
+		printf("mdio_alloc failed\n");
+		return -ENOMEM;
+	}
+	bus->read = mvgbe_phy_read;
+	bus->write = mvgbe_phy_write;
+	sprintf(bus->name, dev->name);
+
+	ret = mdio_register(bus);
+	if (ret) {
+		printf("mdio_register failed\n");
+		free(bus);
+		return -ENOMEM;
+	}
+
+	/* Set phy address of the port */
+	mvgbe_phy_write(bus, MV_PHY_ADR_REQUEST, 0, MV_PHY_ADR_REQUEST, phyid);
+
+	phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_RGMII);
+	if (!phydev) {
+		printf("phy_connect failed\n");
+		return -ENODEV;
+	}
+
+	phy_config(phydev);
+	phy_startup(phydev);
+
+	return 0;
+}
+#endif
+
 int mvgbe_initialize(bd_t *bis)
 {
 	struct mvgbe_device *dmvgbe;
@@ -729,7 +790,9 @@
 
 		eth_register(dev);
 
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#if defined(CONFIG_PHYLIB)
+		mvgbe_phylib_init(dev, PHY_BASE_ADR + devnum);
+#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
 		miiphy_register(dev->name, smi_reg_read, smi_reg_write);
 		/* Set phy address of the port */
 		miiphy_write(dev->name, MV_PHY_ADR_REQUEST,
diff --git a/drivers/net/mvgbe.h b/drivers/net/mvgbe.h
index d8a5429..7f5d98f 100644
--- a/drivers/net/mvgbe.h
+++ b/drivers/net/mvgbe.h
@@ -308,10 +308,17 @@
 #define EBAR_TARGET_GUNIT			0x00000007
 
 /* Window attrib */
+#if defined(CONFIG_DOVE)
+#define EBAR_DRAM_CS0				0x00000000
+#define EBAR_DRAM_CS1				0x00000000
+#define EBAR_DRAM_CS2				0x00000000
+#define EBAR_DRAM_CS3				0x00000000
+#else
 #define EBAR_DRAM_CS0				0x00000E00
 #define EBAR_DRAM_CS1				0x00000D00
 #define EBAR_DRAM_CS2				0x00000B00
 #define EBAR_DRAM_CS3				0x00000700
+#endif
 
 /* DRAM Target interface */
 #define EBAR_DRAM_NO_CACHE_COHERENCY		0x00000000
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index af5f4b8..695873e 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -35,6 +35,7 @@
 COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o
 COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o
 COBJS-$(CONFIG_PHY_ET1011C) += et1011c.o
+COBJS-$(CONFIG_PHY_ICPLUS) += icplus.o
 COBJS-$(CONFIG_PHY_LXT) += lxt.o
 COBJS-$(CONFIG_PHY_MARVELL) += marvell.o
 COBJS-$(CONFIG_PHY_MICREL) += micrel.o
diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c
index 9b3808b..09d4879 100644
--- a/drivers/net/phy/atheros.c
+++ b/drivers/net/phy/atheros.c
@@ -16,7 +16,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
  *
- * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011, 2013 Freescale Semiconductor, Inc.
  * author Andy Fleming
  *
  */
@@ -30,6 +30,27 @@
 	return 0;
 }
 
+static int ar8035_config(struct phy_device *phydev)
+{
+	int regval;
+
+	phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007);
+	phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016);
+	phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007);
+	regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe);
+	phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018));
+
+	phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
+	regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e);
+	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100));
+
+	genphy_config_aneg(phydev);
+
+	phy_reset(phydev);
+
+	return 0;
+}
+
 static struct phy_driver AR8021_driver =  {
 	.name = "AR8021",
 	.uid = 0x4dd040,
@@ -40,9 +61,31 @@
 	.shutdown = genphy_shutdown,
 };
 
+static struct phy_driver AR8031_driver =  {
+	.name = "AR8031",
+	.uid = 0x4dd074,
+	.mask = 0xfffff0,
+	.features = PHY_GBIT_FEATURES,
+	.config = genphy_config,
+	.startup = genphy_startup,
+	.shutdown = genphy_shutdown,
+};
+
+static struct phy_driver AR8035_driver =  {
+	.name = "AR8035",
+	.uid = 0x4dd072,
+	.mask = 0x4fffff,
+	.features = PHY_GBIT_FEATURES,
+	.config = ar8035_config,
+	.startup = genphy_startup,
+	.shutdown = genphy_shutdown,
+};
+
 int phy_atheros_init(void)
 {
 	phy_register(&AR8021_driver);
+	phy_register(&AR8031_driver);
+	phy_register(&AR8035_driver);
 
 	return 0;
 }
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
new file mode 100644
index 0000000..dd5c592
--- /dev/null
+++ b/drivers/net/phy/icplus.c
@@ -0,0 +1,94 @@
+/*
+ * ICPlus PHY drivers
+ *
+ * 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
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ */
+#include <phy.h>
+
+/* IP101A/G - IP1001 */
+#define IP10XX_SPEC_CTRL_STATUS         16      /* Spec. Control Register */
+#define IP1001_SPEC_CTRL_STATUS_2       20      /* IP1001 Spec. Control Reg 2 */
+#define IP1001_PHASE_SEL_MASK           3       /* IP1001 RX/TXPHASE_SEL */
+#define IP1001_APS_ON                   11      /* IP1001 APS Mode  bit */
+#define IP101A_G_APS_ON                 2       /* IP101A/G APS Mode bit */
+#define IP101A_G_IRQ_CONF_STATUS        0x11    /* Conf Info IRQ & Status Reg */
+#define IP101A_G_IRQ_PIN_USED           (1<<15) /* INTR pin used */
+#define IP101A_G_IRQ_DEFAULT            IP101A_G_IRQ_PIN_USED
+
+static int ip1001_config(struct phy_device *phydev)
+{
+	int c;
+
+	/* Enable Auto Power Saving mode */
+	c = phy_read(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2);
+	if (c < 0)
+		return c;
+	c |= IP1001_APS_ON;
+	c = phy_write(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2, c);
+	if (c < 0)
+		return c;
+
+	/* INTR pin used: speed/link/duplex will cause an interrupt */
+	c = phy_write(phydev, MDIO_DEVAD_NONE, IP101A_G_IRQ_CONF_STATUS,
+		      IP101A_G_IRQ_DEFAULT);
+	if (c < 0)
+		return c;
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+		/*
+		 * Additional delay (2ns) used to adjust RX clock phase
+		 * at RGMII interface
+		 */
+		c = phy_read(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS);
+		if (c < 0)
+			return c;
+
+		c |= IP1001_PHASE_SEL_MASK;
+		c = phy_write(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS,
+			      c);
+		if (c < 0)
+			return c;
+	}
+
+	return 0;
+}
+
+static int ip1001_startup(struct phy_device *phydev)
+{
+	genphy_update_link(phydev);
+	genphy_parse_link(phydev);
+
+	return 0;
+}
+static struct phy_driver IP1001_driver = {
+	.name = "ICPlus IP1001",
+	.uid = 0x02430d90,
+	.mask = 0x0ffffff0,
+	.features = PHY_GBIT_FEATURES,
+	.config = &ip1001_config,
+	.startup = &ip1001_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+int phy_icplus_init(void)
+{
+	phy_register(&IP1001_driver);
+
+	return 0;
+}
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 46801c7..8397e32 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -89,6 +89,12 @@
 
 #define MIIM_88E1149_PHY_PAGE	29
 
+/* 88E1310 PHY defines */
+#define MIIM_88E1310_PHY_LED_CTRL	16
+#define MIIM_88E1310_PHY_IRQ_EN		18
+#define MIIM_88E1310_PHY_RGMII_CTRL	21
+#define MIIM_88E1310_PHY_PAGE		22
+
 /* Marvell 88E1011S */
 static int m88e1011s_config(struct phy_device *phydev)
 {
@@ -394,6 +400,37 @@
 	return 0;
 }
 
+/* Marvell 88E1310 */
+static int m88e1310_config(struct phy_device *phydev)
+{
+	u16 reg;
+
+	/* LED link and activity */
+	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
+	reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL);
+	reg = (reg & ~0xf) | 0x1;
+	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg);
+
+	/* Set LED2/INT to INT mode, low active */
+	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
+	reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN);
+	reg = (reg & 0x77ff) | 0x0880;
+	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg);
+
+	/* Set RGMII delay */
+	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002);
+	reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL);
+	reg |= 0x0030;
+	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg);
+
+	/* Ensure to return to page 0 */
+	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000);
+
+	genphy_config_aneg(phydev);
+	phy_reset(phydev);
+
+	return 0;
+}
 
 static struct phy_driver M88E1011S_driver = {
 	.name = "Marvell 88E1011S",
@@ -475,8 +512,19 @@
 	.shutdown = &genphy_shutdown,
 };
 
+static struct phy_driver M88E1310_driver = {
+	.name = "Marvell 88E1310",
+	.uid = 0x01410e90,
+	.mask = 0xffffff0,
+	.features = PHY_GBIT_FEATURES,
+	.config = &m88e1310_config,
+	.startup = &m88e1011s_startup,
+	.shutdown = &genphy_shutdown,
+};
+
 int phy_marvell_init(void)
 {
+	phy_register(&M88E1310_driver);
 	phy_register(&M88E1149S_driver);
 	phy_register(&M88E1145_driver);
 	phy_register(&M88E1121R_driver);
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 30f3264..aa9cbcf 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -18,6 +18,7 @@
  *
  * Copyright 2010-2011 Freescale Semiconductor, Inc.
  * author Andy Fleming
+ * (C) 2012 NetModule AG, David Andrey, added KSZ9031
  *
  */
 #include <config.h>
@@ -52,16 +53,46 @@
 };
 #endif
 
+
+/**
+ * KSZ9021 - KSZ9031 common
+ */
+
+#define MII_KSZ90xx_PHY_CTL		0x1f
+#define MIIM_KSZ90xx_PHYCTL_1000	(1 << 6)
+#define MIIM_KSZ90xx_PHYCTL_100		(1 << 5)
+#define MIIM_KSZ90xx_PHYCTL_10		(1 << 4)
+#define MIIM_KSZ90xx_PHYCTL_DUPLEX	(1 << 3)
+
+static int ksz90xx_startup(struct phy_device *phydev)
+{
+	unsigned phy_ctl;
+	genphy_update_link(phydev);
+	phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL);
+
+	if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX)
+		phydev->duplex = DUPLEX_FULL;
+	else
+		phydev->duplex = DUPLEX_HALF;
+
+	if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000)
+		phydev->speed = SPEED_1000;
+	else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100)
+		phydev->speed = SPEED_100;
+	else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10)
+		phydev->speed = SPEED_10;
+	return 0;
+}
 #ifdef CONFIG_PHY_MICREL_KSZ9021
-/* ksz9021 PHY Registers */
+
+/*
+ * KSZ9021
+ */
+
+/* PHY Registers */
 #define MII_KSZ9021_EXTENDED_CTRL	0x0b
 #define MII_KSZ9021_EXTENDED_DATAW	0x0c
 #define MII_KSZ9021_EXTENDED_DATAR	0x0d
-#define MII_KSZ9021_PHY_CTL		0x1f
-#define MIIM_KSZ9021_PHYCTL_1000	(1 << 6)
-#define MIIM_KSZ9021_PHYCTL_100		(1 << 5)
-#define MIIM_KSZ9021_PHYCTL_10		(1 << 4)
-#define MIIM_KSZ9021_PHYCTL_DUPLEX	(1 << 3)
 
 #define CTRL1000_PREFER_MASTER		(1 << 10)
 #define CTRL1000_CONFIG_MASTER		(1 << 11)
@@ -106,37 +137,64 @@
 	return 0;
 }
 
-static int ksz9021_startup(struct phy_device *phydev)
-{
-	unsigned phy_ctl;
-	genphy_update_link(phydev);
-	phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_PHY_CTL);
-
-	if (phy_ctl & MIIM_KSZ9021_PHYCTL_DUPLEX)
-		phydev->duplex = DUPLEX_FULL;
-	else
-		phydev->duplex = DUPLEX_HALF;
-
-	if (phy_ctl & MIIM_KSZ9021_PHYCTL_1000)
-		phydev->speed = SPEED_1000;
-	else if (phy_ctl & MIIM_KSZ9021_PHYCTL_100)
-		phydev->speed = SPEED_100;
-	else if (phy_ctl & MIIM_KSZ9021_PHYCTL_10)
-		phydev->speed = SPEED_10;
-	return 0;
-}
-
 static struct phy_driver ksz9021_driver = {
 	.name = "Micrel ksz9021",
 	.uid  = 0x221610,
 	.mask = 0xfffff0,
 	.features = PHY_GBIT_FEATURES,
 	.config = &ksz9021_config,
-	.startup = &ksz9021_startup,
+	.startup = &ksz90xx_startup,
 	.shutdown = &genphy_shutdown,
 };
 #endif
 
+/**
+ * KSZ9031
+ */
+/* PHY Registers */
+#define MII_KSZ9031_MMD_ACCES_CTRL	0x0d
+#define MII_KSZ9031_MMD_REG_DATA	0x0e
+
+/* Accessors to extended registers*/
+int ksz9031_phy_extended_write(struct phy_device *phydev,
+			       int devaddr, int regnum, u16 mode, u16 val)
+{
+	/*select register addr for mmd*/
+	phy_write(phydev, MDIO_DEVAD_NONE,
+		  MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
+	/*select register for mmd*/
+	phy_write(phydev, MDIO_DEVAD_NONE,
+		  MII_KSZ9031_MMD_REG_DATA, regnum);
+	/*setup mode*/
+	phy_write(phydev, MDIO_DEVAD_NONE,
+		  MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr));
+	/*write the value*/
+	return	phy_write(phydev, MDIO_DEVAD_NONE,
+		MII_KSZ9031_MMD_REG_DATA, val);
+}
+
+int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
+			      int regnum, u16 mode)
+{
+	phy_write(phydev, MDIO_DEVAD_NONE,
+		  MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
+	phy_write(phydev, MDIO_DEVAD_NONE,
+		  MII_KSZ9031_MMD_REG_DATA, regnum);
+	phy_write(phydev, MDIO_DEVAD_NONE,
+		  MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode));
+	return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA);
+}
+
+static struct phy_driver ksz9031_driver = {
+	.name = "Micrel ksz9031",
+	.uid  = 0x221620,
+	.mask = 0xfffffe,
+	.features = PHY_GBIT_FEATURES,
+	.config   = &genphy_config,
+	.startup  = &ksz90xx_startup,
+	.shutdown = &genphy_shutdown,
+};
+
 int phy_micrel_init(void)
 {
 	phy_register(&KSZ804_driver);
@@ -145,5 +203,6 @@
 #else
 	phy_register(&KS8721_driver);
 #endif
+	phy_register(&ksz9031_driver);
 	return 0;
 }
diff --git a/drivers/net/phy/natsemi.c b/drivers/net/phy/natsemi.c
index ea60ac1..6dc7ed5 100644
--- a/drivers/net/phy/natsemi.c
+++ b/drivers/net/phy/natsemi.c
@@ -22,6 +22,42 @@
  */
 #include <phy.h>
 
+/* NatSemi DP83630 */
+
+#define DP83630_PHY_PAGESEL_REG		0x13
+#define DP83630_PHY_PTP_COC_REG		0x14
+#define DP83630_PHY_PTP_CLKOUT_EN	(1<<15)
+#define DP83630_PHY_RBR_REG		0x17
+
+static int dp83630_config(struct phy_device *phydev)
+{
+	int ptp_coc_reg;
+
+	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
+	phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0x6);
+	ptp_coc_reg = phy_read(phydev, MDIO_DEVAD_NONE,
+			       DP83630_PHY_PTP_COC_REG);
+	ptp_coc_reg &= ~DP83630_PHY_PTP_CLKOUT_EN;
+	phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PTP_COC_REG,
+		  ptp_coc_reg);
+	phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0);
+
+	genphy_config_aneg(phydev);
+
+	return 0;
+}
+
+static struct phy_driver DP83630_driver = {
+	.name = "NatSemi DP83630",
+	.uid = 0x20005ce1,
+	.mask = 0xfffffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &dp83630_config,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+
 /* DP83865 Link and Auto-Neg Status Register */
 #define MIIM_DP83865_LANR      0x11
 #define MIIM_DP83865_SPD_MASK  0x0018
@@ -90,6 +126,7 @@
 
 int phy_natsemi_init(void)
 {
+	phy_register(&DP83630_driver);
 	phy_register(&DP83865_driver);
 
 	return 0;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index f8c5481..7c0eaec 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -75,6 +75,10 @@
 		adv |= ADVERTISE_PAUSE_CAP;
 	if (advertise & ADVERTISED_Asym_Pause)
 		adv |= ADVERTISE_PAUSE_ASYM;
+	if (advertise & ADVERTISED_1000baseX_Half)
+		adv |= ADVERTISE_1000XHALF;
+	if (advertise & ADVERTISED_1000baseX_Full)
+		adv |= ADVERTISE_1000XFULL;
 
 	if (adv != oldadv) {
 		err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv);
@@ -280,7 +284,7 @@
  *
  * Stolen from Linux's mii.c and phy_device.c
  */
-static int genphy_parse_link(struct phy_device *phydev)
+int genphy_parse_link(struct phy_device *phydev)
 {
 	int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
 
@@ -288,6 +292,7 @@
 	if (mii_reg & BMSR_ANEGCAPABLE) {
 		u32 lpa = 0;
 		u32 gblpa = 0;
+		u32 estatus = 0;
 
 		/* Check for gigabit capability */
 		if (mii_reg & BMSR_ERCAP) {
@@ -327,6 +332,18 @@
 
 		} else if (lpa & LPA_10FULL)
 			phydev->duplex = DUPLEX_FULL;
+
+		if (mii_reg & BMSR_ESTATEN)
+			estatus = phy_read(phydev, MDIO_DEVAD_NONE,
+					   MII_ESTATUS);
+
+		if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_XHALF |
+				ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
+			phydev->speed = SPEED_1000;
+			if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_TFULL))
+				phydev->duplex = DUPLEX_FULL;
+		}
+
 	} else {
 		u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
 
@@ -384,6 +401,10 @@
 			features |= SUPPORTED_1000baseT_Full;
 		if (val & ESTATUS_1000_THALF)
 			features |= SUPPORTED_1000baseT_Half;
+		if (val & ESTATUS_1000_XFULL)
+			features |= SUPPORTED_1000baseX_Full;
+		if (val & ESTATUS_1000_XHALF)
+			features |= SUPPORTED_1000baseX_Full;
 	}
 
 	phydev->supported = features;
@@ -433,6 +454,9 @@
 #ifdef CONFIG_PHY_ET1011C
 	phy_et1011c_init();
 #endif
+#ifdef CONFIG_PHY_ICPLUS
+	phy_icplus_init();
+#endif
 #ifdef CONFIG_PHY_LXT
 	phy_lxt_init();
 #endif
diff --git a/drivers/net/sunxi_wemac.c b/drivers/net/sunxi_wemac.c
new file mode 100644
index 0000000..1db3529
--- /dev/null
+++ b/drivers/net/sunxi_wemac.c
@@ -0,0 +1,533 @@
+/*
+ * sunxi_wemac.c -- Allwinner A10 ethernet driver
+ *
+ * (C) Copyright 2012, Stefan Roese <sr@denx.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.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+
+/* EMAC register  */
+struct wemac_regs {
+	u32 ctl;	/* 0x00 */
+	u32 tx_mode;	/* 0x04 */
+	u32 tx_flow;	/* 0x08 */
+	u32 tx_ctl0;	/* 0x0c */
+	u32 tx_ctl1;	/* 0x10 */
+	u32 tx_ins;	/* 0x14 */
+	u32 tx_pl0;	/* 0x18 */
+	u32 tx_pl1;	/* 0x1c */
+	u32 tx_sta;	/* 0x20 */
+	u32 tx_io_data;	/* 0x24 */
+	u32 tx_io_data1; /* 0x28 */
+	u32 tx_tsvl0;	/* 0x2c */
+	u32 tx_tsvh0;	/* 0x30 */
+	u32 tx_tsvl1;	/* 0x34 */
+	u32 tx_tsvh1;	/* 0x38 */
+	u32 rx_ctl;	/* 0x3c */
+	u32 rx_hash0;	/* 0x40 */
+	u32 rx_hash1;	/* 0x44 */
+	u32 rx_sta;	/* 0x48 */
+	u32 rx_io_data;	/* 0x4c */
+	u32 rx_fbc;	/* 0x50 */
+	u32 int_ctl;	/* 0x54 */
+	u32 int_sta;	/* 0x58 */
+	u32 mac_ctl0;	/* 0x5c */
+	u32 mac_ctl1;	/* 0x60 */
+	u32 mac_ipgt;	/* 0x64 */
+	u32 mac_ipgr;	/* 0x68 */
+	u32 mac_clrt;	/* 0x6c */
+	u32 mac_maxf;	/* 0x70 */
+	u32 mac_supp;	/* 0x74 */
+	u32 mac_test;	/* 0x78 */
+	u32 mac_mcfg;	/* 0x7c */
+	u32 mac_mcmd;	/* 0x80 */
+	u32 mac_madr;	/* 0x84 */
+	u32 mac_mwtd;	/* 0x88 */
+	u32 mac_mrdd;	/* 0x8c */
+	u32 mac_mind;	/* 0x90 */
+	u32 mac_ssrr;	/* 0x94 */
+	u32 mac_a0;	/* 0x98 */
+	u32 mac_a1;	/* 0x9c */
+};
+
+/* SRAMC register  */
+struct sunxi_sramc_regs {
+	u32 ctrl0;
+	u32 ctrl1;
+};
+
+/* 0: Disable       1: Aborted frame enable(default) */
+#define EMAC_TX_AB_M		(0x1 << 0)
+/* 0: CPU           1: DMA(default) */
+#define EMAC_TX_TM		(0x1 << 1)
+
+#define EMAC_TX_SETUP		(0)
+
+/* 0: DRQ asserted  1: DRQ automatically(default) */
+#define EMAC_RX_DRQ_MODE	(0x1 << 1)
+/* 0: CPU           1: DMA(default) */
+#define EMAC_RX_TM		(0x1 << 2)
+/* 0: Normal(default)        1: Pass all Frames */
+#define EMAC_RX_PA		(0x1 << 4)
+/* 0: Normal(default)        1: Pass Control Frames */
+#define EMAC_RX_PCF		(0x1 << 5)
+/* 0: Normal(default)        1: Pass Frames with CRC Error */
+#define EMAC_RX_PCRCE		(0x1 << 6)
+/* 0: Normal(default)        1: Pass Frames with Length Error */
+#define EMAC_RX_PLE		(0x1 << 7)
+/* 0: Normal                 1: Pass Frames length out of range(default) */
+#define EMAC_RX_POR		(0x1 << 8)
+/* 0: Not accept             1: Accept unicast Packets(default) */
+#define EMAC_RX_UCAD		(0x1 << 16)
+/* 0: Normal(default)        1: DA Filtering */
+#define EMAC_RX_DAF		(0x1 << 17)
+/* 0: Not accept             1: Accept multicast Packets(default) */
+#define EMAC_RX_MCO		(0x1 << 20)
+/* 0: Disable(default)       1: Enable Hash filter */
+#define EMAC_RX_MHF		(0x1 << 21)
+/* 0: Not accept             1: Accept Broadcast Packets(default) */
+#define EMAC_RX_BCO		(0x1 << 22)
+/* 0: Disable(default)       1: Enable SA Filtering */
+#define EMAC_RX_SAF		(0x1 << 24)
+/* 0: Normal(default)        1: Inverse Filtering */
+#define EMAC_RX_SAIF		(0x1 << 25)
+
+#define EMAC_RX_SETUP		(EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \
+				 EMAC_RX_MCO | EMAC_RX_BCO)
+
+/* 0: Disable                1: Enable Receive Flow Control(default) */
+#define EMAC_MAC_CTL0_RFC	(0x1 << 2)
+/* 0: Disable                1: Enable Transmit Flow Control(default) */
+#define EMAC_MAC_CTL0_TFC	(0x1 << 3)
+
+#define EMAC_MAC_CTL0_SETUP	(EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC)
+
+/* 0: Disable                1: Enable MAC Frame Length Checking(default) */
+#define EMAC_MAC_CTL1_FLC	(0x1 << 1)
+/* 0: Disable(default)       1: Enable Huge Frame */
+#define EMAC_MAC_CTL1_HF	(0x1 << 2)
+/* 0: Disable(default)       1: Enable MAC Delayed CRC */
+#define EMAC_MAC_CTL1_DCRC	(0x1 << 3)
+/* 0: Disable                1: Enable MAC CRC(default) */
+#define EMAC_MAC_CTL1_CRC	(0x1 << 4)
+/* 0: Disable                1: Enable MAC PAD Short frames(default) */
+#define EMAC_MAC_CTL1_PC	(0x1 << 5)
+/* 0: Disable(default)       1: Enable MAC PAD Short frames and append CRC */
+#define EMAC_MAC_CTL1_VC	(0x1 << 6)
+/* 0: Disable(default)       1: Enable MAC auto detect Short frames */
+#define EMAC_MAC_CTL1_ADP	(0x1 << 7)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_PRE	(0x1 << 8)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_LPE	(0x1 << 9)
+/* 0: Disable(default)       1: Enable no back off */
+#define EMAC_MAC_CTL1_NB	(0x1 << 12)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_BNB	(0x1 << 13)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_ED	(0x1 << 14)
+
+#define EMAC_MAC_CTL1_SETUP	(EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \
+				 EMAC_MAC_CTL1_PC)
+
+#define EMAC_MAC_IPGT		0x15
+
+#define EMAC_MAC_NBTB_IPG1	0xC
+#define EMAC_MAC_NBTB_IPG2	0x12
+
+#define EMAC_MAC_CW		0x37
+#define EMAC_MAC_RM		0xF
+
+#define EMAC_MAC_MFL		0x0600
+
+/* Receive status */
+#define EMAC_CRCERR		(1 << 4)
+#define EMAC_LENERR		(3 << 5)
+
+#define DMA_CPU_TRRESHOLD	2000
+
+struct wemac_eth_dev {
+	u32 speed;
+	u32 duplex;
+	u32 phy_configured;
+	int link_printed;
+};
+
+struct wemac_rxhdr {
+	s16 rx_len;
+	u16 rx_status;
+};
+
+static void wemac_inblk_32bit(void *reg, void *data, int count)
+{
+	int cnt = (count + 3) >> 2;
+
+	if (cnt) {
+		u32 *buf = data;
+
+		do {
+			u32 x = readl(reg);
+			*buf++ = x;
+		} while (--cnt);
+	}
+}
+
+static void wemac_outblk_32bit(void *reg, void *data, int count)
+{
+	int cnt = (count + 3) >> 2;
+
+	if (cnt) {
+		const u32 *buf = data;
+
+		do {
+			writel(*buf++, reg);
+		} while (--cnt);
+	}
+}
+
+/*
+ * Read a word from phyxcer
+ */
+static int wemac_phy_read(const char *devname, unsigned char addr,
+			  unsigned char reg, unsigned short *value)
+{
+	struct eth_device *dev = eth_get_dev_by_name(devname);
+	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+	/* issue the phy address and reg */
+	writel(addr << 8 | reg, &regs->mac_madr);
+
+	/* pull up the phy io line */
+	writel(0x1, &regs->mac_mcmd);
+
+	/* Wait read complete */
+	mdelay(1);
+
+	/* push down the phy io line */
+	writel(0x0, &regs->mac_mcmd);
+
+	/* and write data */
+	*value = readl(&regs->mac_mrdd);
+
+	return 0;
+}
+
+/*
+ * Write a word to phyxcer
+ */
+static int wemac_phy_write(const char *devname, unsigned char addr,
+			   unsigned char reg, unsigned short value)
+{
+	struct eth_device *dev = eth_get_dev_by_name(devname);
+	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+	/* issue the phy address and reg */
+	writel(addr << 8 | reg, &regs->mac_madr);
+
+	/* pull up the phy io line */
+	writel(0x1, &regs->mac_mcmd);
+
+	/* Wait write complete */
+	mdelay(1);
+
+	/* push down the phy io line */
+	writel(0x0, &regs->mac_mcmd);
+
+	/* and write data */
+	writel(value, &regs->mac_mwtd);
+
+	return 0;
+}
+
+static void emac_setup(struct eth_device *dev)
+{
+	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+	u32 reg_val;
+	u16 phy_val;
+	u32 duplex_flag;
+
+	/* Set up TX */
+	writel(EMAC_TX_SETUP, &regs->tx_mode);
+
+	/* Set up RX */
+	writel(EMAC_RX_SETUP, &regs->rx_ctl);
+
+	/* Set MAC */
+	/* Set MAC CTL0 */
+	writel(EMAC_MAC_CTL0_SETUP, &regs->mac_ctl0);
+
+	/* Set MAC CTL1 */
+	wemac_phy_read(dev->name, 1, 0, &phy_val);
+	debug("PHY SETUP, reg 0 value: %x\n", phy_val);
+	duplex_flag = !!(phy_val & (1 << 8));
+
+	reg_val = 0;
+	if (duplex_flag)
+		reg_val = (0x1 << 0);
+	writel(EMAC_MAC_CTL1_SETUP | reg_val, &regs->mac_ctl1);
+
+	/* Set up IPGT */
+	writel(EMAC_MAC_IPGT, &regs->mac_ipgt);
+
+	/* Set up IPGR */
+	writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), &regs->mac_ipgr);
+
+	/* Set up Collison window */
+	writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), &regs->mac_clrt);
+
+	/* Set up Max Frame Length */
+	writel(EMAC_MAC_MFL, &regs->mac_maxf);
+}
+
+static void wemac_reset(struct eth_device *dev)
+{
+	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+	debug("resetting device\n");
+
+	/* RESET device */
+	writel(0, &regs->ctl);
+	udelay(200);
+
+	writel(1, &regs->ctl);
+	udelay(200);
+}
+
+static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd)
+{
+	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+	struct wemac_eth_dev *priv = dev->priv;
+	u16 phy_reg;
+
+	/* Init EMAC */
+
+	/* Flush RX FIFO */
+	setbits_le32(&regs->rx_ctl, 0x8);
+	udelay(1);
+
+	/* Init MAC */
+
+	/* Soft reset MAC */
+	clrbits_le32(&regs->mac_ctl0, 1 << 15);
+
+	/* Set MII clock */
+	clrsetbits_le32(&regs->mac_mcfg, 0xf << 2, 0xd << 2);
+
+	/* Clear RX counter */
+	writel(0x0, &regs->rx_fbc);
+	udelay(1);
+
+	/* Set up EMAC */
+	emac_setup(dev);
+
+	writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
+	       dev->enetaddr[2], &regs->mac_a1);
+	writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
+	       dev->enetaddr[5], &regs->mac_a0);
+
+	mdelay(1);
+
+	wemac_reset(dev);
+
+	/* PHY POWER UP */
+	wemac_phy_read(dev->name, 1, 0, &phy_reg);
+	wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11)));
+	mdelay(1);
+
+	wemac_phy_read(dev->name, 1, 0, &phy_reg);
+
+	priv->speed = miiphy_speed(dev->name, 0);
+	priv->duplex = miiphy_duplex(dev->name, 0);
+
+	/* Print link status only once */
+	if (!priv->link_printed) {
+		printf("ENET Speed is %d Mbps - %s duplex connection\n",
+		       priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
+		priv->link_printed = 1;
+	}
+
+	/* Set EMAC SPEED depend on PHY */
+	clrsetbits_le32(&regs->mac_supp, 1 << 8,
+			((phy_reg & (1 << 13)) >> 13) << 8);
+
+	/* Set duplex depend on phy */
+	clrsetbits_le32(&regs->mac_ctl1, 1 << 0,
+			((phy_reg & (1 << 8)) >> 8) << 0);
+
+	/* Enable RX/TX */
+	setbits_le32(&regs->ctl, 0x7);
+
+	return 0;
+}
+
+static void sunxi_wemac_eth_halt(struct eth_device *dev)
+{
+	/* Nothing to do here */
+}
+
+static int sunxi_wemac_eth_recv(struct eth_device *dev)
+{
+	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+	struct wemac_rxhdr rxhdr;
+	u32 rxcount;
+	u32 reg_val;
+	int rx_len;
+	int rx_status;
+	int good_packet;
+
+	/* Check packet ready or not */
+
+	/*
+	 * Race warning: The first packet might arrive with
+	 * the interrupts disabled, but the second will fix
+	 */
+	rxcount = readl(&regs->rx_fbc);
+	if (!rxcount) {
+		/* Had one stuck? */
+		rxcount = readl(&regs->rx_fbc);
+		if (!rxcount)
+			return 0;
+	}
+
+	reg_val = readl(&regs->rx_io_data);
+	if (reg_val != 0x0143414d) {
+		/* Disable RX */
+		clrbits_le32(&regs->ctl, 1 << 2);
+
+		/* Flush RX FIFO */
+		setbits_le32(&regs->rx_ctl, 1 << 3);
+		while (readl(&regs->rx_ctl) & (1 << 3))
+			;
+
+		/* Enable RX */
+		setbits_le32(&regs->ctl, 1 << 2);
+
+		return 0;
+	}
+
+	/*
+	 * A packet ready now
+	 * Get status/length
+	 */
+	good_packet = 1;
+
+	wemac_inblk_32bit(&regs->rx_io_data, &rxhdr, sizeof(rxhdr));
+
+	rx_len = rxhdr.rx_len;
+	rx_status = rxhdr.rx_status;
+
+	/* Packet Status check */
+	if (rx_len < 0x40) {
+		good_packet = 0;
+		debug("RX: Bad Packet (runt)\n");
+	}
+
+	/* rx_status is identical to RSR register. */
+	if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) {
+		good_packet = 0;
+		if (rx_status & EMAC_CRCERR)
+			printf("crc error\n");
+		if (rx_status & EMAC_LENERR)
+			printf("length error\n");
+	}
+
+	/* Move data from WEMAC */
+	if (good_packet) {
+		if (rx_len > DMA_CPU_TRRESHOLD) {
+			printf("Received packet is too big (len=%d)\n", rx_len);
+		} else {
+			wemac_inblk_32bit((void *)&regs->rx_io_data,
+					  NetRxPackets[0], rx_len);
+
+			/* Pass to upper layer */
+			NetReceive(NetRxPackets[0], rx_len);
+			return rx_len;
+		}
+	}
+
+	return 0;
+}
+
+static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len)
+{
+	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+	/* Select channel 0 */
+	writel(0, &regs->tx_ins);
+
+	/* Write packet */
+	wemac_outblk_32bit((void *)&regs->tx_io_data, packet, len);
+
+	/* Set TX len */
+	writel(len, &regs->tx_pl0);
+
+	/* Start translate from fifo to phy */
+	setbits_le32(&regs->tx_ctl0, 1);
+
+	return 0;
+}
+
+int sunxi_wemac_initialize(void)
+{
+	struct sunxi_ccm_reg *const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	struct sunxi_sramc_regs *sram =
+		(struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
+	struct eth_device *dev;
+	struct wemac_eth_dev *priv;
+	int pin;
+
+	dev = malloc(sizeof(*dev));
+	if (dev == NULL)
+		return -ENOMEM;
+
+	priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev));
+	if (!priv) {
+		free(dev);
+		return -ENOMEM;
+	}
+
+	memset(dev, 0, sizeof(*dev));
+	memset(priv, 0, sizeof(struct wemac_eth_dev));
+
+	/* Map SRAM to EMAC */
+	setbits_le32(&sram->ctrl1, 0x5 << 2);
+
+	/* Configure pin mux settings for MII Ethernet */
+	for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++)
+		sunxi_gpio_set_cfgpin(pin, 2);
+
+	/* Set up clock gating */
+	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC);
+
+	dev->iobase = SUNXI_EMAC_BASE;
+	dev->priv = priv;
+	dev->init = sunxi_wemac_eth_init;
+	dev->halt = sunxi_wemac_eth_halt;
+	dev->send = sunxi_wemac_eth_send;
+	dev->recv = sunxi_wemac_eth_recv;
+	strcpy(dev->name, "wemac");
+
+	eth_register(dev);
+
+	miiphy_register(dev->name, wemac_phy_read, wemac_phy_write);
+
+	return 0;
+}
diff --git a/include/command.h b/include/command.h
index 65692fd..9e05ddc 100644
--- a/include/command.h
+++ b/include/command.h
@@ -110,6 +110,8 @@
 }
 #endif
 
+extern int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
 extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,
 			   char *const argv[]);
 
diff --git a/include/configs/at91sam9n12ek.h b/include/configs/at91sam9n12ek.h
index 8d2673d..b4b1c31 100644
--- a/include/configs/at91sam9n12ek.h
+++ b/include/configs/at91sam9n12ek.h
@@ -167,6 +167,10 @@
 #define CONFIG_DOS_PARTITION
 #endif
 
+/* Ethernet */
+#define CONFIG_KS8851_MLL
+#define CONFIG_KS8851_MLL_BASEADDR	0x30000000 /* use NCS2 */
+
 #define CONFIG_SYS_LOAD_ADDR		0x22000000 /* load address */
 
 #define CONFIG_SYS_MEMTEST_START	CONFIG_SYS_SDRAM_BASE
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index fcb20fe..f6dbdb0 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -580,6 +580,8 @@
 #define SUPPORTED_10000baseKX4_Full	(1 << 18)
 #define SUPPORTED_10000baseKR_Full	(1 << 19)
 #define SUPPORTED_10000baseR_FEC	(1 << 20)
+#define SUPPORTED_1000baseX_Half	(1 << 21)
+#define SUPPORTED_1000baseX_Full	(1 << 22)
 
 /* Indicates what features are advertised by the interface. */
 #define ADVERTISED_10baseT_Half		(1 << 0)
@@ -603,6 +605,8 @@
 #define ADVERTISED_10000baseKX4_Full	(1 << 18)
 #define ADVERTISED_10000baseKR_Full	(1 << 19)
 #define ADVERTISED_10000baseR_FEC	(1 << 20)
+#define ADVERTISED_1000baseX_Half	(1 << 21)
+#define ADVERTISED_1000baseX_Full	(1 << 22)
 
 /* The following are all involved in forcing a particular link
  * mode for the device for setting things.  When getting the
diff --git a/include/linux/mii.h b/include/linux/mii.h
index 8b92692..66b83d8 100644
--- a/include/linux/mii.h
+++ b/include/linux/mii.h
@@ -115,6 +115,8 @@
 #define EXPANSION_MFAULTS	0x0010	/* Multiple faults detected    */
 #define EXPANSION_RESV		0xffe0	/* Unused...		       */
 
+#define ESTATUS_1000_XFULL	0x8000	/* Can do 1000BX Full */
+#define ESTATUS_1000_XHALF	0x4000	/* Can do 1000BX Half */
 #define ESTATUS_1000_TFULL	0x2000	/* Can do 1000BT Full */
 #define ESTATUS_1000_THALF	0x1000	/* Can do 1000BT Half */
 
diff --git a/include/micrel.h b/include/micrel.h
index 25e8a46..e1c62d8 100644
--- a/include/micrel.h
+++ b/include/micrel.h
@@ -8,9 +8,20 @@
 #define MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW	0x105
 #define MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW	0x106
 #define MII_KSZ9021_EXT_ANALOG_TEST		0x107
+/* Register operations */
+#define MII_KSZ9031_MOD_REG			0x0000
+/* Data operations */
+#define MII_KSZ9031_MOD_DATA_NO_POST_INC	0x4000
+#define MII_KSZ9031_MOD_DATA_POST_INC_RW	0x8000
+#define MII_KSZ9031_MOD_DATA_POST_INC_W		0xC000
 
 struct phy_device;
 int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val);
 int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum);
 
+int ksz9031_phy_extended_write(struct phy_device *phydev, int devaddr,
+			       int regnum, u16 mode, u16 val);
+int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
+			      int regnum, u16 mode);
+
 #endif
diff --git a/include/net.h b/include/net.h
index 23fb947..7673470 100644
--- a/include/net.h
+++ b/include/net.h
@@ -39,7 +39,7 @@
 #define PKTALIGN	ARCH_DMA_MINALIGN
 
 /* IPv4 addresses are always 32 bits in size */
-typedef u32		IPaddr_t;
+typedef __be32		IPaddr_t;
 
 
 /**
diff --git a/include/netdev.h b/include/netdev.h
index df454b5..917d874 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -67,10 +67,12 @@
 int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr);
 int ftgmac100_initialize(bd_t *bits);
 int ftmac100_initialize(bd_t *bits);
+int ftmac110_initialize(bd_t *bits);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
 int ks8695_eth_initialize(void);
+int ks8851_mll_initialize(u8 dev_num, int base_addr);
 int lan91c96_initialize(u8 dev_num, int base_addr);
 int macb_eth_initialize(int id, void *regs, unsigned int phy_addr);
 int mcdmafec_initialize(bd_t *bis);
@@ -93,6 +95,7 @@
 int skge_initialize(bd_t *bis);
 int smc91111_initialize(u8 dev_num, int base_addr);
 int smc911x_initialize(u8 dev_num, int base_addr);
+int sunxi_wemac_initialize(bd_t *bis);
 int tsi108_eth_initialize(bd_t *bis);
 int uec_standard_init(bd_t *bis);
 int uli526x_initialize(bd_t *bis);
diff --git a/include/phy.h b/include/phy.h
index 75bf3b4..dbf3274 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -214,6 +214,7 @@
 int genphy_config_aneg(struct phy_device *phydev);
 int genphy_restart_aneg(struct phy_device *phydev);
 int genphy_update_link(struct phy_device *phydev);
+int genphy_parse_link(struct phy_device *phydev);
 int genphy_config(struct phy_device *phydev);
 int genphy_startup(struct phy_device *phydev);
 int genphy_shutdown(struct phy_device *phydev);
diff --git a/net/link_local.c b/net/link_local.c
index 1ba796e..4152fae 100644
--- a/net/link_local.c
+++ b/net/link_local.c
@@ -206,6 +206,7 @@
 {
 	int source_ip_conflict;
 	int target_ip_conflict;
+	IPaddr_t null_ip = 0;
 
 	if (state == DISABLED)
 		return;
@@ -267,10 +268,18 @@
 	) {
 		source_ip_conflict = 1;
 	}
-	if (arp->ar_op == htons(ARPOP_REQUEST)
-	 && memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0
-	 && memcmp(&arp->ar_tha, NetOurEther, ARP_HLEN) != 0
-	) {
+
+	/*
+	 * According to RFC 3927, section 2.2.1:
+	 * Check if packet is an ARP probe by checking for a null source IP
+	 * then check that target IP is equal to ours and source hw addr
+	 * is not equal to ours. This condition should cause a conflict only
+	 * during probe.
+	 */
+	if (arp->ar_op == htons(ARPOP_REQUEST) &&
+	    memcmp(&arp->ar_spa, &null_ip, ARP_PLEN) == 0 &&
+	    memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0 &&
+	    memcmp(&arp->ar_sha, NetOurEther, ARP_HLEN) != 0) {
 		target_ip_conflict = 1;
 	}
 
diff --git a/net/nfs.c b/net/nfs.c
index 7f2393f..381b75f 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -37,10 +37,14 @@
 # define NFS_TIMEOUT CONFIG_NFS_TIMEOUT
 #endif
 
+#define NFS_RPC_ERR	1
+#define NFS_RPC_DROP	124
+
 static int fs_mounted;
 static unsigned long rpc_id;
 static int nfs_offset = -1;
 static int nfs_len;
+static ulong nfs_timeout = NFS_TIMEOUT;
 
 static char dirfh[NFS_FHSIZE];	/* file handle of directory */
 static char filefh[NFS_FHSIZE]; /* file handle of kernel image */
@@ -399,8 +403,10 @@
 
 	debug("%s\n", __func__);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
@@ -428,8 +434,10 @@
 
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
@@ -452,8 +460,10 @@
 
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
@@ -475,8 +485,10 @@
 
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
@@ -499,8 +511,10 @@
 
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
@@ -534,8 +548,10 @@
 
 	memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply));
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
@@ -574,7 +590,8 @@
 		NetStartAgain();
 	} else {
 		puts("T ");
-		NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
+		NetSetTimeout(nfs_timeout + NFS_TIMEOUT * NfsTimeoutCount,
+			      NfsTimeout);
 		NfsSend();
 	}
 }
@@ -583,6 +600,7 @@
 NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
 {
 	int rlen;
+	int reply;
 
 	debug("%s\n", __func__);
 
@@ -591,19 +609,24 @@
 
 	switch (NfsState) {
 	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
-		rpc_lookup_reply(PROG_MOUNT, pkt, len);
+		if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP)
+			break;
 		NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ;
 		NfsSend();
 		break;
 
 	case STATE_PRCLOOKUP_PROG_NFS_REQ:
-		rpc_lookup_reply(PROG_NFS, pkt, len);
+		if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP)
+			break;
 		NfsState = STATE_MOUNT_REQ;
 		NfsSend();
 		break;
 
 	case STATE_MOUNT_REQ:
-		if (nfs_mount_reply(pkt, len)) {
+		reply = nfs_mount_reply(pkt, len);
+		if (reply == -NFS_RPC_DROP)
+			break;
+		else if (reply == -NFS_RPC_ERR) {
 			puts("*** ERROR: Cannot mount\n");
 			/* just to be sure... */
 			NfsState = STATE_UMOUNT_REQ;
@@ -615,7 +638,10 @@
 		break;
 
 	case STATE_UMOUNT_REQ:
-		if (nfs_umountall_reply(pkt, len)) {
+		reply = nfs_umountall_reply(pkt, len);
+		if (reply == -NFS_RPC_DROP)
+			break;
+		else if (reply == -NFS_RPC_ERR) {
 			puts("*** ERROR: Cannot umount\n");
 			net_set_state(NETLOOP_FAIL);
 		} else {
@@ -625,7 +651,10 @@
 		break;
 
 	case STATE_LOOKUP_REQ:
-		if (nfs_lookup_reply(pkt, len)) {
+		reply = nfs_lookup_reply(pkt, len);
+		if (reply == -NFS_RPC_DROP)
+			break;
+		else if (reply == -NFS_RPC_ERR) {
 			puts("*** ERROR: File lookup fail\n");
 			NfsState = STATE_UMOUNT_REQ;
 			NfsSend();
@@ -638,7 +667,10 @@
 		break;
 
 	case STATE_READLINK_REQ:
-		if (nfs_readlink_reply(pkt, len)) {
+		reply = nfs_readlink_reply(pkt, len);
+		if (reply == -NFS_RPC_DROP)
+			break;
+		else if (reply == -NFS_RPC_ERR) {
 			puts("*** ERROR: Symlink fail\n");
 			NfsState = STATE_UMOUNT_REQ;
 			NfsSend();
@@ -654,7 +686,7 @@
 
 	case STATE_READ_REQ:
 		rlen = nfs_read_reply(pkt, len);
-		NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
+		NetSetTimeout(nfs_timeout, NfsTimeout);
 		if (rlen > 0) {
 			nfs_offset += rlen;
 			NfsSend();
@@ -738,7 +770,7 @@
 	printf("\nLoad address: 0x%lx\n"
 		"Loading: *\b", load_addr);
 
-	NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
+	NetSetTimeout(nfs_timeout, NfsTimeout);
 	net_set_udp_handler(NfsHandler);
 
 	NfsTimeoutCount = 0;
diff --git a/net/tftp.c b/net/tftp.c
index 09790eb..6d333d5 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -446,8 +446,8 @@
 TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
 	    unsigned len)
 {
-	ushort proto;
-	ushort *s;
+	__be16 proto;
+	__be16 *s;
 	int i;
 
 	if (dest != TftpOurPort) {
@@ -465,7 +465,7 @@
 		return;
 	len -= 2;
 	/* warning: don't use increment (++) in ntohs() macros!! */
-	s = (ushort *)pkt;
+	s = (__be16 *)pkt;
 	proto = *s++;
 	pkt = (uchar *)s;
 	switch (ntohs(proto)) {
@@ -556,7 +556,7 @@
 		if (len < 2)
 			return;
 		len -= 2;
-		TftpBlock = ntohs(*(ushort *)pkt);
+		TftpBlock = ntohs(*(__be16 *)pkt);
 
 		update_block_number();
 
@@ -644,9 +644,9 @@
 
 	case TFTP_ERROR:
 		printf("\nTFTP error: '%s' (%d)\n",
-		       pkt + 2, ntohs(*(ushort *)pkt));
+		       pkt + 2, ntohs(*(__be16 *)pkt));
 
-		switch (ntohs(*(ushort *)pkt)) {
+		switch (ntohs(*(__be16 *)pkt)) {
 		case TFTP_ERR_FILE_NOT_FOUND:
 		case TFTP_ERR_ACCESS_DENIED:
 			puts("Not retrying...\n");