Merge git://git.denx.de/u-boot-net
diff --git a/configs/Lamobo_R1_defconfig b/configs/Lamobo_R1_defconfig
index 4cc4dc4..805d4b7 100644
--- a/configs/Lamobo_R1_defconfig
+++ b/configs/Lamobo_R1_defconfig
@@ -23,3 +23,6 @@
 CONFIG_SCSI=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y
+CONFIG_B53_SWITCH=y
+CONFIG_B53_CPU_PORT=8
+CONFIG_B53_PHY_PORTS=0x1f
diff --git a/configs/alt_defconfig b/configs/alt_defconfig
index bf51e53..157d830 100644
--- a/configs/alt_defconfig
+++ b/configs/alt_defconfig
@@ -24,7 +24,8 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_PHY_MICREL=y
 CONFIG_BAUDRATE=38400
 CONFIG_SCIF_CONSOLE=y
diff --git a/configs/ap_sh4a_4a_defconfig b/configs/ap_sh4a_4a_defconfig
index ef14121..976680a 100644
--- a/configs/ap_sh4a_4a_defconfig
+++ b/configs/ap_sh4a_4a_defconfig
@@ -25,6 +25,7 @@
 # CONFIG_CMD_MISC is not set
 CONFIG_ENV_IS_IN_FLASH=y
 CONFIG_MTD_NOR_FLASH=y
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USE_PRIVATE_LIBGCC=y
diff --git a/configs/armadillo-800eva_defconfig b/configs/armadillo-800eva_defconfig
index d9a5169..14d6c84 100644
--- a/configs/armadillo-800eva_defconfig
+++ b/configs/armadillo-800eva_defconfig
@@ -27,6 +27,7 @@
 # CONFIG_CMD_MISC is not set
 CONFIG_ENV_IS_IN_FLASH=y
 # CONFIG_MMC is not set
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_OF_LIBFDT=y
diff --git a/configs/ecovec_defconfig b/configs/ecovec_defconfig
index 5d65e9d..5c6c55f 100644
--- a/configs/ecovec_defconfig
+++ b/configs/ecovec_defconfig
@@ -29,7 +29,8 @@
 CONFIG_CMD_FAT=y
 CONFIG_ENV_IS_IN_FLASH=y
 CONFIG_MTD_NOR_FLASH=y
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USB=y
 CONFIG_USB_STORAGE=y
diff --git a/configs/espt_defconfig b/configs/espt_defconfig
index 520bc9f..32ba9d0 100644
--- a/configs/espt_defconfig
+++ b/configs/espt_defconfig
@@ -25,6 +25,7 @@
 # CONFIG_CMD_MISC is not set
 CONFIG_ENV_IS_IN_FLASH=y
 CONFIG_MTD_NOR_FLASH=y
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USE_PRIVATE_LIBGCC=y
diff --git a/configs/gose_defconfig b/configs/gose_defconfig
index bc32990..5f10d9a 100644
--- a/configs/gose_defconfig
+++ b/configs/gose_defconfig
@@ -24,8 +24,9 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHYLIB=y
 CONFIG_PHY_MICREL=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_BAUDRATE=38400
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USB=y
diff --git a/configs/koelsch_defconfig b/configs/koelsch_defconfig
index 5def33b..acc7289 100644
--- a/configs/koelsch_defconfig
+++ b/configs/koelsch_defconfig
@@ -24,8 +24,9 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHYLIB=y
 CONFIG_PHY_MICREL=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_BAUDRATE=38400
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USB=y
diff --git a/configs/lager_defconfig b/configs/lager_defconfig
index 5072045..c0778ee 100644
--- a/configs/lager_defconfig
+++ b/configs/lager_defconfig
@@ -24,8 +24,9 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHYLIB=y
 CONFIG_PHY_MICREL=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_BAUDRATE=38400
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USB=y
diff --git a/configs/porter_defconfig b/configs/porter_defconfig
index ac36dca..7374a30 100644
--- a/configs/porter_defconfig
+++ b/configs/porter_defconfig
@@ -24,8 +24,9 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHYLIB=y
 CONFIG_PHY_MICREL=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_BAUDRATE=38400
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USB=y
diff --git a/configs/r0p7734_defconfig b/configs/r0p7734_defconfig
index e0b19bb..342365d 100644
--- a/configs/r0p7734_defconfig
+++ b/configs/r0p7734_defconfig
@@ -25,6 +25,7 @@
 # CONFIG_CMD_MISC is not set
 CONFIG_ENV_IS_IN_FLASH=y
 CONFIG_MTD_NOR_FLASH=y
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USE_PRIVATE_LIBGCC=y
diff --git a/configs/sh7752evb_defconfig b/configs/sh7752evb_defconfig
index 3152859..9e4f5aa 100644
--- a/configs/sh7752evb_defconfig
+++ b/configs/sh7752evb_defconfig
@@ -34,6 +34,7 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
 CONFIG_SPI_FLASH_STMICRO=y
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USE_PRIVATE_LIBGCC=y
diff --git a/configs/sh7753evb_defconfig b/configs/sh7753evb_defconfig
index 259d6a7..631f241 100644
--- a/configs/sh7753evb_defconfig
+++ b/configs/sh7753evb_defconfig
@@ -33,6 +33,7 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
 CONFIG_SPI_FLASH_STMICRO=y
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USE_PRIVATE_LIBGCC=y
diff --git a/configs/sh7757lcr_defconfig b/configs/sh7757lcr_defconfig
index b2e7362..c7e30af 100644
--- a/configs/sh7757lcr_defconfig
+++ b/configs/sh7757lcr_defconfig
@@ -33,6 +33,7 @@
 CONFIG_MMC=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_STMICRO=y
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USE_PRIVATE_LIBGCC=y
diff --git a/configs/sh7763rdp_defconfig b/configs/sh7763rdp_defconfig
index 693a873..a211e4c 100644
--- a/configs/sh7763rdp_defconfig
+++ b/configs/sh7763rdp_defconfig
@@ -26,6 +26,7 @@
 CONFIG_CMD_JFFS2=y
 CONFIG_ENV_IS_IN_FLASH=y
 CONFIG_MTD_NOR_FLASH=y
-CONFIG_PHYLIB=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USE_PRIVATE_LIBGCC=y
diff --git a/configs/silk_defconfig b/configs/silk_defconfig
index 8af1e19..ffe1d8b 100644
--- a/configs/silk_defconfig
+++ b/configs/silk_defconfig
@@ -24,8 +24,9 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHYLIB=y
 CONFIG_PHY_MICREL=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_BAUDRATE=38400
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USB=y
diff --git a/configs/stout_defconfig b/configs/stout_defconfig
index b6e71e7..6750dcd 100644
--- a/configs/stout_defconfig
+++ b/configs/stout_defconfig
@@ -24,8 +24,9 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHYLIB=y
 CONFIG_PHY_MICREL=y
+CONFIG_NETDEVICES=y
+CONFIG_SH_ETHER=y
 CONFIG_BAUDRATE=38400
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USB=y
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 5d440ce..f346cc1 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -103,6 +103,13 @@
 					      out_args);
 }
 
+int dev_count_phandle_with_args(struct udevice *dev, const char *list_name,
+				const char *cells_name)
+{
+	return ofnode_count_phandle_with_args(dev_ofnode(dev), list_name,
+					      cells_name);
+}
+
 int dev_read_addr_cells(struct udevice *dev)
 {
 	return ofnode_read_addr_cells(dev_ofnode(dev));
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 46b17b1..de1947c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -185,6 +185,13 @@
 	  GEM (Gigabit Ethernet MAC) found in some ARM SoC devices.
 	  Say Y to include support for the MACB/GEM chip.
 
+config MACB_ZYNQ
+	bool "Cadence MACB/GEM Ethernet Interface for Xilinx Zynq"
+	depends on MACB
+	help
+	  The Cadence MACB ethernet interface was used on Zynq platform.
+	  Say Y to enable support for the MACB/GEM in Zynq chip.
+
 config PCH_GBE
 	bool "Intel Platform Controller Hub EG20T GMAC driver"
 	depends on DM_ETH && DM_PCI
@@ -269,6 +276,12 @@
 	  It can be found in H3/A64/A83T based SoCs and compatible with both
 	  External and Internal PHYs.
 
+config SH_ETHER
+	bool "Renesas SH Ethernet MAC"
+	select PHYLIB
+	help
+	  This driver supports the Ethernet for Renesas SH and ARM SoCs.
+
 config XILINX_AXIEMAC
 	depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP)
 	select PHYLIB
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 036d231..6d53071 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -10,6 +10,7 @@
  */
 
 #include <common.h>
+#include <clk.h>
 #include <dm.h>
 #include <errno.h>
 #include <miiphy.h>
@@ -17,6 +18,7 @@
 #include <pci.h>
 #include <linux/compiler.h>
 #include <linux/err.h>
+#include <linux/kernel.h>
 #include <asm/io.h>
 #include <power/regulator.h>
 #include "designware.h"
@@ -343,6 +345,8 @@
 	return 0;
 }
 
+#define ETH_ZLEN	60
+
 static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length)
 {
 	struct eth_dma_regs *dma_p = priv->dma_regs_p;
@@ -369,6 +373,8 @@
 		return -EPERM;
 	}
 
+	length = max(length, ETH_ZLEN);
+
 	memcpy((void *)data_start, packet, length);
 
 	/* Flush data to be sent */
@@ -661,6 +667,35 @@
 	u32 iobase = pdata->iobase;
 	ulong ioaddr;
 	int ret;
+#ifdef CONFIG_CLK
+	int i, err, clock_nb;
+
+	priv->clock_count = 0;
+	clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
+	if (clock_nb > 0) {
+		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
+					    GFP_KERNEL);
+		if (!priv->clocks)
+			return -ENOMEM;
+
+		for (i = 0; i < clock_nb; i++) {
+			err = clk_get_by_index(dev, i, &priv->clocks[i]);
+			if (err < 0)
+				break;
+
+			err = clk_enable(&priv->clocks[i]);
+			if (err) {
+				pr_err("failed to enable clock %d\n", i);
+				clk_free(&priv->clocks[i]);
+				goto clk_err;
+			}
+			priv->clock_count++;
+		}
+	} else if (clock_nb != -ENOENT) {
+		pr_err("failed to get clock phandle(%d)\n", clock_nb);
+		return clock_nb;
+	}
+#endif
 
 #if defined(CONFIG_DM_REGULATOR)
 	struct udevice *phy_supply;
@@ -707,6 +742,15 @@
 	debug("%s, ret=%d\n", __func__, ret);
 
 	return ret;
+
+#ifdef CONFIG_CLK
+clk_err:
+	ret = clk_release_all(priv->clocks, priv->clock_count);
+	if (ret)
+		pr_err("failed to disable all clocks\n");
+
+	return err;
+#endif
 }
 
 static int designware_eth_remove(struct udevice *dev)
@@ -717,7 +761,11 @@
 	mdio_unregister(priv->bus);
 	mdio_free(priv->bus);
 
+#ifdef CONFIG_CLK
+	return clk_release_all(priv->clocks, priv->clock_count);
+#else
 	return 0;
+#endif
 }
 
 const struct eth_ops designware_eth_ops = {
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index 7992d0e..252cd24 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -239,6 +239,10 @@
 #ifdef CONFIG_DM_GPIO
 	struct gpio_desc reset_gpio;
 #endif
+#ifdef CONFIG_CLK
+	struct clk *clocks;	/* clock list */
+	int clock_count;	/* number of clock in clock list */
+#endif
 
 	struct phy_device *phydev;
 	struct mii_dev *bus;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index f9373db..e62aefc 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -52,6 +52,22 @@
 #define MACB_TX_TIMEOUT		1000
 #define MACB_AUTONEG_TIMEOUT	5000000
 
+#ifdef CONFIG_MACB_ZYNQ
+/* INCR4 AHB bursts */
+#define MACB_ZYNQ_GEM_DMACR_BLENGTH		0x00000004
+/* Use full configured addressable space (8 Kb) */
+#define MACB_ZYNQ_GEM_DMACR_RXSIZE		0x00000300
+/* Use full configured addressable space (4 Kb) */
+#define MACB_ZYNQ_GEM_DMACR_TXSIZE		0x00000400
+/* Set RXBUF with use of 128 byte */
+#define MACB_ZYNQ_GEM_DMACR_RXBUF		0x00020000
+#define MACB_ZYNQ_GEM_DMACR_INIT \
+				(MACB_ZYNQ_GEM_DMACR_BLENGTH | \
+				MACB_ZYNQ_GEM_DMACR_RXSIZE | \
+				MACB_ZYNQ_GEM_DMACR_TXSIZE | \
+				MACB_ZYNQ_GEM_DMACR_RXBUF)
+#endif
+
 struct macb_dma_desc {
 	u32	addr;
 	u32	ctrl;
@@ -461,13 +477,25 @@
 		phy_id = macb_mdio_read(macb, MII_PHYSID1);
 		if (phy_id != 0xffff) {
 			printf("%s: PHY present at %d\n", name, i);
-			return 1;
+			return 0;
 		}
 	}
 
 	/* PHY isn't up to snuff */
 	printf("%s: PHY not found\n", name);
 
+	return -ENODEV;
+}
+
+/**
+ * macb_linkspd_cb - Linkspeed change callback function
+ * @regs:	Base Register of MACB devices
+ * @speed:	Linkspeed
+ * Returns 0 when operation success and negative errno number
+ * when operation failed.
+ */
+int __weak macb_linkspd_cb(void *regs, unsigned int speed)
+{
 	return 0;
 }
 
@@ -483,18 +511,20 @@
 	u32 ncfgr;
 	u16 phy_id, status, adv, lpa;
 	int media, speed, duplex;
+	int ret;
 	int i;
 
 	arch_get_mdio_control(name);
 	/* Auto-detect phy_addr */
-	if (!macb_phy_find(macb, name))
-		return 0;
+	ret = macb_phy_find(macb, name);
+	if (ret)
+		return ret;
 
 	/* Check if the PHY is up to snuff... */
 	phy_id = macb_mdio_read(macb, MII_PHYSID1);
 	if (phy_id == 0xffff) {
 		printf("%s: No PHY present\n", name);
-		return 0;
+		return -ENODEV;
 	}
 
 #ifdef CONFIG_PHYLIB
@@ -530,7 +560,7 @@
 	if (!(status & BMSR_LSTATUS)) {
 		printf("%s: link down (status: 0x%04x)\n",
 		       name, status);
-		return 0;
+		return -ENETDOWN;
 	}
 
 	/* First check for GMAC and that it is GiB capable */
@@ -554,7 +584,11 @@
 
 			macb_writel(macb, NCFGR, ncfgr);
 
+			ret = macb_linkspd_cb(macb->regs, _1000BASET);
+			if (ret)
+				return ret;
+
-			return 1;
+			return 0;
 		}
 	}
 
@@ -573,13 +607,21 @@
 
 	ncfgr = macb_readl(macb, NCFGR);
 	ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE));
-	if (speed)
+	if (speed) {
 		ncfgr |= MACB_BIT(SPD);
+		ret = macb_linkspd_cb(macb->regs, _100BASET);
+	} else {
+		ret = macb_linkspd_cb(macb->regs, _10BASET);
+	}
+
+	if (ret)
+		return ret;
+
 	if (duplex)
 		ncfgr |= MACB_BIT(FD);
 	macb_writel(macb, NCFGR, ncfgr);
 
-	return 1;
+	return 0;
 }
 
 static int gmac_init_multi_queues(struct macb_device *macb)
@@ -616,6 +658,7 @@
 	struct macb_device *macb = dev_get_priv(dev);
 #endif
 	unsigned long paddr;
+	int ret;
 	int i;
 
 	/*
@@ -649,6 +692,10 @@
 	macb->tx_tail = 0;
 	macb->next_rx_tail = 0;
 
+#ifdef CONFIG_MACB_ZYNQ
+	macb_writel(macb, DMACFG, MACB_ZYNQ_GEM_DMACR_INIT);
+#endif
+
 	macb_writel(macb, RBQP, macb->rx_ring_dma);
 	macb_writel(macb, TBQP, macb->tx_ring_dma);
 
@@ -709,11 +756,12 @@
 	}
 
 #ifdef CONFIG_DM_ETH
-	if (!macb_phy_init(dev, name))
+	ret = macb_phy_init(dev, name);
 #else
-	if (!macb_phy_init(macb, name))
+	ret = macb_phy_init(macb, name);
 #endif
-		return -1;
+	if (ret)
+		return ret;
 
 	/* Enable TX and RX */
 	macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE));
@@ -1013,9 +1061,15 @@
 	if (ret)
 		return -EINVAL;
 
+	/*
+	 * Zynq clock driver didn't support for enable or disable
+	 * clock. Hence, clk_enable() didn't apply for Zynq
+	 */
+#ifndef CONFIG_MACB_ZYNQ
 	ret = clk_enable(&clk);
 	if (ret)
 		return ret;
+#endif
 
 	clk_rate = clk_get_rate(&clk);
 	if (!clk_rate)
@@ -1080,6 +1134,17 @@
 	mdio_unregister(macb->bus);
 	mdio_free(macb->bus);
 
+	return 0;
+}
+
+/**
+ * macb_late_eth_ofdata_to_platdata
+ * @dev:	udevice struct
+ * Returns 0 when operation success and negative errno number
+ * when operation failed.
+ */
+int __weak macb_late_eth_ofdata_to_platdata(struct udevice *dev)
+{
 	return 0;
 }
 
@@ -1088,7 +1153,8 @@
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 
 	pdata->iobase = devfdt_get_addr(dev);
-	return 0;
+
+	return macb_late_eth_ofdata_to_platdata(dev);
 }
 
 static const struct udevice_id macb_eth_ids[] = {
@@ -1097,6 +1163,7 @@
 	{ .compatible = "atmel,sama5d2-gem" },
 	{ .compatible = "atmel,sama5d3-gem" },
 	{ .compatible = "atmel,sama5d4-gem" },
+	{ .compatible = "cdns,zynq-gem" },
 	{ }
 };
 
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 5bb48f4..c39554d 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -11,6 +11,7 @@
 #define MACB_NCFGR				0x0004
 #define MACB_NSR				0x0008
 #define GEM_UR					0x000c
+#define MACB_DMACFG				0x0010
 #define MACB_TSR				0x0014
 #define MACB_RBQP				0x0018
 #define MACB_TBQP				0x001c
diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c
index f1be952..83e3153 100644
--- a/drivers/net/mvneta.c
+++ b/drivers/net/mvneta.c
@@ -1654,7 +1654,11 @@
 		 */
 		*packetp = data;
 
-		mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done);
+		/*
+		 * Only mark one descriptor as free
+		 * since only one was processed
+		 */
+		mvneta_rxq_desc_num_update(pp, rxq, 1, 1);
 	}
 
 	return rx_bytes;
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index e9dbedf..028fca9 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -153,14 +153,17 @@
 		len = sizeof(input_buffer) - input_size;
 
 	end = input_offset + input_size;
-	if (end > sizeof(input_buffer))
+	if (end >= sizeof(input_buffer))
 		end -= sizeof(input_buffer);
 
 	chunk = len;
-	if (end + len > sizeof(input_buffer)) {
+	/* Check if packet will wrap in input_buffer */
+	if (end + len >= sizeof(input_buffer)) {
 		chunk = sizeof(input_buffer) - end;
+		/* Copy the second part of the pkt to start of input_buffer */
 		memcpy(input_buffer, pkt + chunk, len - chunk);
 	}
+	/* Copy first (or only) part of pkt after end of current valid input*/
 	memcpy(input_buffer + end, pkt, chunk);
 
 	input_size += len;
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index e32f1eb..95b7534 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -12,6 +12,23 @@
 
 if PHYLIB
 
+config B53_SWITCH
+	bool "Broadcom BCM53xx (RoboSwitch) Ethernet switch PHY support."
+	help
+	  Enable support for Broadcom BCM53xx (RoboSwitch) Ethernet switches.
+	  This currently supports BCM53125 and similar models.
+
+if B53_SWITCH
+
+config B53_CPU_PORT
+	int "CPU port"
+	default 8
+
+config B53_PHY_PORTS
+	hex "Bitmask of PHY ports"
+
+endif # B53_SWITCH
+
 config MV88E61XX_SWITCH
 	bool "Marvel MV88E61xx Ethernet switch PHY support."
 
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 1e264b2..f198037 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -6,6 +6,7 @@
 #
 
 obj-$(CONFIG_BITBANGMII) += miiphybb.o
+obj-$(CONFIG_B53_SWITCH) += b53.o
 obj-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o
 obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6352.o
 
diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c
index b34cdd3..d7e76de 100644
--- a/drivers/net/phy/atheros.c
+++ b/drivers/net/phy/atheros.c
@@ -19,6 +19,7 @@
 
 static int ar8021_config(struct phy_device *phydev)
 {
+	phy_write(phydev, MDIO_DEVAD_NONE, 0x00, 0x1200);
 	phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
 	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x3D47);
 
diff --git a/drivers/net/phy/b53.c b/drivers/net/phy/b53.c
new file mode 100644
index 0000000..f7f2d9f
--- /dev/null
+++ b/drivers/net/phy/b53.c
@@ -0,0 +1,768 @@
+/*
+ * Copyright (C) 2017
+ * Broadcom
+ * Florian Fainelli <f.fainelli@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * PHY driver for Broadcom BCM53xx (roboswitch) Ethernet switches.
+ *
+ * This driver configures the b53 for basic use as a PHY. The switch supports
+ * vendor tags and VLAN configuration that can affect the switching decisions.
+ * This driver uses a simple configuration in which all ports are only allowed
+ * to send frames to the CPU port and receive frames from the CPU port this
+ * providing port isolation (no cross talk).
+ *
+ * The configuration determines which PHY ports to activate using the
+ * CONFIG_B53_PHY_PORTS bitmask. Set bit N will active port N and so on.
+ *
+ * This driver was written primarily for the Lamobo R1 platform using a BCM53152
+ * switch but the BCM53xx being largely register compatible, extending it to
+ * cover other switches would be trivial.
+ */
+
+#include <common.h>
+
+#include <errno.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <netdev.h>
+
+/* Pseudo-PHY address (non configurable) to access internal registers */
+#define BRCM_PSEUDO_PHY_ADDR		30
+
+/* Maximum number of ports possible */
+#define B53_N_PORTS			9
+
+#define B53_CTRL_PAGE			0x00 /* Control */
+#define B53_MGMT_PAGE			0x02 /* Management Mode */
+/* Port VLAN Page */
+#define B53_PVLAN_PAGE			0x31
+
+/* Control Page registers */
+#define B53_PORT_CTRL(i)		(0x00 + (i))
+#define   PORT_CTRL_RX_DISABLE		BIT(0)
+#define   PORT_CTRL_TX_DISABLE		BIT(1)
+#define   PORT_CTRL_RX_BCST_EN		BIT(2) /* Broadcast RX (P8 only) */
+#define   PORT_CTRL_RX_MCST_EN		BIT(3) /* Multicast RX (P8 only) */
+#define   PORT_CTRL_RX_UCST_EN		BIT(4) /* Unicast RX (P8 only) */
+
+/* Switch Mode Control Register (8 bit) */
+#define B53_SWITCH_MODE			0x0b
+#define   SM_SW_FWD_MODE		BIT(0)	/* 1 = Managed Mode */
+#define   SM_SW_FWD_EN			BIT(1)	/* Forwarding Enable */
+
+/* IMP Port state override register (8 bit) */
+#define B53_PORT_OVERRIDE_CTRL		0x0e
+#define   PORT_OVERRIDE_LINK		BIT(0)
+#define   PORT_OVERRIDE_FULL_DUPLEX	BIT(1) /* 0 = Half Duplex */
+#define   PORT_OVERRIDE_SPEED_S		2
+#define   PORT_OVERRIDE_SPEED_10M	(0 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_SPEED_100M	(1 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_SPEED_1000M	(2 << PORT_OVERRIDE_SPEED_S)
+/* BCM5325 only */
+#define   PORT_OVERRIDE_RV_MII_25	BIT(4)
+#define   PORT_OVERRIDE_RX_FLOW		BIT(4)
+#define   PORT_OVERRIDE_TX_FLOW		BIT(5)
+/* BCM5301X only, requires setting 1000M */
+#define   PORT_OVERRIDE_SPEED_2000M	BIT(6)
+#define   PORT_OVERRIDE_EN		BIT(7) /* Use the register contents */
+
+#define B53_RGMII_CTRL_IMP		0x60
+#define   RGMII_CTRL_ENABLE_GMII	BIT(7)
+#define   RGMII_CTRL_TIMING_SEL		BIT(2)
+#define   RGMII_CTRL_DLL_RXC		BIT(1)
+#define   RGMII_CTRL_DLL_TXC		BIT(0)
+
+/* Switch control (8 bit) */
+#define B53_SWITCH_CTRL			0x22
+#define  B53_MII_DUMB_FWDG_EN		BIT(6)
+
+/* Software reset register (8 bit) */
+#define B53_SOFTRESET			0x79
+#define   SW_RST			BIT(7)
+#define   EN_CH_RST			BIT(6)
+#define   EN_SW_RST			BIT(4)
+
+/* Fast Aging Control register (8 bit) */
+#define B53_FAST_AGE_CTRL		0x88
+#define   FAST_AGE_STATIC		BIT(0)
+#define   FAST_AGE_DYNAMIC		BIT(1)
+#define   FAST_AGE_PORT			BIT(2)
+#define   FAST_AGE_VLAN			BIT(3)
+#define   FAST_AGE_STP			BIT(4)
+#define   FAST_AGE_MC			BIT(5)
+#define   FAST_AGE_DONE			BIT(7)
+
+/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
+#define B53_PVLAN_PORT_MASK(i)		((i) * 2)
+
+/* MII registers */
+#define REG_MII_PAGE    0x10    /* MII Page register */
+#define REG_MII_ADDR    0x11    /* MII Address register */
+#define REG_MII_DATA0   0x18    /* MII Data register 0 */
+#define REG_MII_DATA1   0x19    /* MII Data register 1 */
+#define REG_MII_DATA2   0x1a    /* MII Data register 2 */
+#define REG_MII_DATA3   0x1b    /* MII Data register 3 */
+
+#define REG_MII_PAGE_ENABLE     BIT(0)
+#define REG_MII_ADDR_WRITE      BIT(0)
+#define REG_MII_ADDR_READ       BIT(1)
+
+struct b53_device {
+	struct mii_dev	*bus;
+	unsigned int cpu_port;
+};
+
+static int b53_mdio_op(struct mii_dev *bus, u8 page, u8 reg, u16 op)
+{
+	int ret;
+	int i;
+	u16 v;
+
+	/* set page number */
+	v = (page << 8) | REG_MII_PAGE_ENABLE;
+	ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+			 REG_MII_PAGE, v);
+	if (ret)
+		return ret;
+
+	/* set register address */
+	v = (reg << 8) | op;
+	ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+			 REG_MII_ADDR, v);
+	if (ret)
+		return ret;
+
+	/* check if operation completed */
+	for (i = 0; i < 5; ++i) {
+		v = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+			      REG_MII_ADDR);
+		if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
+			break;
+
+		udelay(100);
+	}
+
+	if (i == 5)
+		return -EIO;
+
+	return 0;
+}
+
+static int b53_mdio_read8(struct mii_dev *bus, u8 page, u8 reg, u8 *val)
+{
+	int ret;
+
+	ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+			 REG_MII_DATA0) & 0xff;
+
+	return 0;
+}
+
+static int b53_mdio_read16(struct mii_dev *bus, u8 page, u8 reg, u16 *val)
+{
+	int ret;
+
+	ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+			 REG_MII_DATA0);
+
+	return 0;
+}
+
+static int b53_mdio_read32(struct mii_dev *bus, u8 page, u8 reg, u32 *val)
+{
+	int ret;
+
+	ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+			 REG_MII_DATA0);
+	*val |= bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+			  REG_MII_DATA1) << 16;
+
+	return 0;
+}
+
+static int b53_mdio_read48(struct mii_dev *bus, u8 page, u8 reg, u64 *val)
+{
+	u64 temp = 0;
+	int i;
+	int ret;
+
+	ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	for (i = 2; i >= 0; i--) {
+		temp <<= 16;
+		temp |= bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+				  REG_MII_DATA0 + i);
+	}
+
+	*val = temp;
+
+	return 0;
+}
+
+static int b53_mdio_read64(struct mii_dev *bus, u8 page, u8 reg, u64 *val)
+{
+	u64 temp = 0;
+	int i;
+	int ret;
+
+	ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	for (i = 3; i >= 0; i--) {
+		temp <<= 16;
+		temp |= bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+				  REG_MII_DATA0 + i);
+	}
+
+	*val = temp;
+
+	return 0;
+}
+
+static int b53_mdio_write8(struct mii_dev *bus, u8 page, u8 reg, u8 value)
+{
+	int ret;
+
+	ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+			 REG_MII_DATA0, value);
+	if (ret)
+		return ret;
+
+	return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write16(struct mii_dev *bus, u8 page, u8 reg,
+			    u16 value)
+{
+	int ret;
+
+	ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
+			 REG_MII_DATA0, value);
+	if (ret)
+		return ret;
+
+	return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write32(struct mii_dev *bus, u8 page, u8 reg,
+			    u32 value)
+{
+	unsigned int i;
+	u32 temp = value;
+
+	for (i = 0; i < 2; i++) {
+		int ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR,
+				     MDIO_DEVAD_NONE,
+				     REG_MII_DATA0 + i, temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write48(struct mii_dev *bus, u8 page, u8 reg,
+			    u64 value)
+{
+	unsigned int i;
+	u64 temp = value;
+
+	for (i = 0; i < 3; i++) {
+		int ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR,
+				     MDIO_DEVAD_NONE,
+				     REG_MII_DATA0 + i, temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write64(struct mii_dev *bus, u8 page, u8 reg,
+			    u64 value)
+{
+	unsigned int i;
+	u64 temp = value;
+
+	for (i = 0; i < 4; i++) {
+		int ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR,
+				     MDIO_DEVAD_NONE,
+				     REG_MII_DATA0 + i, temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static inline int b53_read8(struct b53_device *dev, u8 page,
+			    u8 reg, u8 *value)
+{
+	return b53_mdio_read8(dev->bus, page, reg, value);
+}
+
+static inline int b53_read16(struct b53_device *dev, u8 page,
+			     u8 reg, u16 *value)
+{
+	return b53_mdio_read16(dev->bus, page, reg, value);
+}
+
+static inline int b53_read32(struct b53_device *dev, u8 page,
+			     u8 reg, u32 *value)
+{
+	return b53_mdio_read32(dev->bus, page, reg, value);
+}
+
+static inline int b53_read48(struct b53_device *dev, u8 page,
+			     u8 reg, u64 *value)
+{
+	return b53_mdio_read48(dev->bus, page, reg, value);
+}
+
+static inline int b53_read64(struct b53_device *dev, u8 page,
+			     u8 reg, u64 *value)
+{
+	return b53_mdio_read64(dev->bus, page, reg, value);
+}
+
+static inline int b53_write8(struct b53_device *dev, u8 page,
+			     u8 reg, u8 value)
+{
+	return b53_mdio_write8(dev->bus, page, reg, value);
+}
+
+static inline int b53_write16(struct b53_device *dev, u8 page,
+			      u8 reg, u16 value)
+{
+	return b53_mdio_write16(dev->bus, page, reg, value);
+}
+
+static inline int b53_write32(struct b53_device *dev, u8 page,
+			      u8 reg, u32 value)
+{
+	return b53_mdio_write32(dev->bus, page, reg, value);
+}
+
+static inline int b53_write48(struct b53_device *dev, u8 page,
+			      u8 reg, u64 value)
+{
+	return b53_mdio_write48(dev->bus, page, reg, value);
+}
+
+static inline int b53_write64(struct b53_device *dev, u8 page,
+			      u8 reg, u64 value)
+{
+	return b53_mdio_write64(dev->bus, page, reg, value);
+}
+
+static int b53_flush_arl(struct b53_device *dev, u8 mask)
+{
+	unsigned int i;
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
+		   FAST_AGE_DONE | FAST_AGE_DYNAMIC | mask);
+
+	for (i = 0; i < 10; i++) {
+		u8 fast_age_ctrl;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
+			  &fast_age_ctrl);
+
+		if (!(fast_age_ctrl & FAST_AGE_DONE))
+			goto out;
+
+		mdelay(1);
+	}
+
+	return -ETIMEDOUT;
+out:
+	/* Only age dynamic entries (default behavior) */
+	b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, FAST_AGE_DYNAMIC);
+	return 0;
+}
+
+static int b53_switch_reset(struct phy_device *phydev)
+{
+	struct b53_device *dev = phydev->priv;
+	unsigned int timeout = 1000;
+	u8 mgmt;
+	u8 reg;
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SOFTRESET, &reg);
+	reg |= SW_RST | EN_SW_RST | EN_CH_RST;
+	b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, reg);
+
+	do {
+		b53_read8(dev, B53_CTRL_PAGE, B53_SOFTRESET, &reg);
+		if (!(reg & SW_RST))
+			break;
+
+		mdelay(1);
+	} while (timeout-- > 0);
+
+	if (timeout == 0)
+		return -ETIMEDOUT;
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+	if (!(mgmt & SM_SW_FWD_EN)) {
+		mgmt &= ~SM_SW_FWD_MODE;
+		mgmt |= SM_SW_FWD_EN;
+
+		b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+		b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+		if (!(mgmt & SM_SW_FWD_EN)) {
+			printf("Failed to enable switch!\n");
+			return -EINVAL;
+		}
+	}
+
+	/* Include IMP port in dumb forwarding mode when no tagging protocol
+	 * is configured
+	 */
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, &mgmt);
+	mgmt |= B53_MII_DUMB_FWDG_EN;
+	b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
+
+	return b53_flush_arl(dev, FAST_AGE_STATIC);
+}
+
+static void b53_enable_cpu_port(struct phy_device *phydev)
+{
+	struct b53_device *dev = phydev->priv;
+	u8 port_ctrl;
+
+	port_ctrl = PORT_CTRL_RX_BCST_EN |
+		    PORT_CTRL_RX_MCST_EN |
+		    PORT_CTRL_RX_UCST_EN;
+	b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(dev->cpu_port), port_ctrl);
+
+	port_ctrl = PORT_OVERRIDE_EN | PORT_OVERRIDE_LINK |
+		    PORT_OVERRIDE_FULL_DUPLEX | PORT_OVERRIDE_SPEED_1000M;
+	b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, port_ctrl);
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_IMP, &port_ctrl);
+}
+
+static void b53_imp_vlan_setup(struct b53_device *dev, int cpu_port)
+{
+	unsigned int port;
+	u16 pvlan;
+
+	/* Enable the IMP port to be in the same VLAN as the other ports
+	 * on a per-port basis such that we only have Port i and IMP in
+	 * the same VLAN.
+	 */
+	for (port = 0; port < B53_N_PORTS; port++) {
+		if (!((1 << port) & CONFIG_B53_PHY_PORTS))
+			continue;
+
+		b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port),
+			   &pvlan);
+		pvlan |= BIT(cpu_port);
+		b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port),
+			    pvlan);
+	}
+}
+
+static int b53_port_enable(struct phy_device *phydev, unsigned int port)
+{
+	struct b53_device *dev = phydev->priv;
+	unsigned int cpu_port = dev->cpu_port;
+	u16 pvlan;
+
+	/* Clear the Rx and Tx disable bits and set to no spanning tree */
+	b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0);
+
+	/* Set this port, and only this one to be in the default VLAN */
+	b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan);
+	pvlan &= ~0x1ff;
+	pvlan |= BIT(port);
+	b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan);
+
+	b53_imp_vlan_setup(dev, cpu_port);
+
+	return 0;
+}
+
+static int b53_switch_init(struct phy_device *phydev)
+{
+	static int init;
+	int ret;
+
+	if (init)
+		return 0;
+
+	ret = b53_switch_reset(phydev);
+	if (ret < 0)
+		return ret;
+
+	b53_enable_cpu_port(phydev);
+
+	init = 1;
+
+	return 0;
+}
+
+static int b53_probe(struct phy_device *phydev)
+{
+	struct b53_device *dev;
+	int ret;
+
+	dev = malloc(sizeof(*dev));
+	if (!dev)
+		return -ENOMEM;
+
+	memset(dev, 0, sizeof(*dev));
+
+	phydev->priv = dev;
+	dev->bus = phydev->bus;
+	dev->cpu_port = CONFIG_B53_CPU_PORT;
+
+	ret = b53_switch_reset(phydev);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int b53_phy_config(struct phy_device *phydev)
+{
+	unsigned int port;
+	int res;
+
+	res = b53_switch_init(phydev);
+	if (res < 0)
+		return res;
+
+	for (port = 0; port < B53_N_PORTS; port++) {
+		if (!((1 << port) & CONFIG_B53_PHY_PORTS))
+			continue;
+
+		res = b53_port_enable(phydev, port);
+		if (res < 0) {
+			printf("Error enabling port %i\n", port);
+			continue;
+		}
+
+		res = genphy_config_aneg(phydev);
+		if (res < 0) {
+			printf("Error setting PHY %i autoneg\n", port);
+			continue;
+		}
+
+		res = 0;
+	}
+
+	return res;
+}
+
+static int b53_phy_startup(struct phy_device *phydev)
+{
+	unsigned int port;
+	int res;
+
+	for (port = 0; port < B53_N_PORTS; port++) {
+		if (!((1 << port) & CONFIG_B53_PHY_PORTS))
+			continue;
+
+		phydev->addr = port;
+
+		res = genphy_startup(phydev);
+		if (res < 0)
+			continue;
+		else
+			break;
+	}
+
+	/* Since we are connected directly to the switch, hardcode the link
+	 * parameters to match those of the CPU port configured in
+	 * b53_enable_cpu_port, we cannot be dependent on the user-facing port
+	 * settings (e.g: 100Mbits/sec would not work here)
+	 */
+	phydev->speed = 1000;
+	phydev->duplex = 1;
+	phydev->link = 1;
+
+	return 0;
+}
+
+static struct phy_driver b53_driver = {
+	.name = "Broadcom BCM53125",
+	.uid = 0x03625c00,
+	.mask = 0xfffffc00,
+	.features = PHY_GBIT_FEATURES,
+	.probe = b53_probe,
+	.config = b53_phy_config,
+	.startup = b53_phy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+int phy_b53_init(void)
+{
+	phy_register(&b53_driver);
+
+	return 0;
+}
+
+int do_b53_reg_read(const char *name, int argc, char * const argv[])
+{
+	u8 page, offset, width;
+	struct mii_dev *bus;
+	int ret = -EINVAL;
+	u64 value64 = 0;
+	u32 value32 = 0;
+	u16 value16 = 0;
+	u8 value8 = 0;
+
+	bus = miiphy_get_dev_by_name(name);
+	if (!bus) {
+		printf("unable to find MDIO bus: %s\n", name);
+		return ret;
+	}
+
+	page = simple_strtoul(argv[1], NULL, 16);
+	offset = simple_strtoul(argv[2], NULL, 16);
+	width = simple_strtoul(argv[3], NULL, 10);
+
+	switch (width) {
+	case 8:
+		ret = b53_mdio_read8(bus, page, offset, &value8);
+		printf("page=0x%02x, offset=0x%02x, value=0x%02x\n",
+		       page, offset, value8);
+		break;
+	case 16:
+		ret = b53_mdio_read16(bus, page, offset, &value16);
+		printf("page=0x%02x, offset=0x%02x, value=0x%04x\n",
+		       page, offset, value16);
+		break;
+	case 32:
+		ret = b53_mdio_read32(bus, page, offset, &value32);
+		printf("page=0x%02x, offset=0x%02x, value=0x%08x\n",
+		       page, offset, value32);
+		break;
+	case 48:
+		ret = b53_mdio_read48(bus, page, offset, &value64);
+		printf("page=0x%02x, offset=0x%02x, value=0x%012llx\n",
+		       page, offset, value64);
+		break;
+	case 64:
+		ret = b53_mdio_read48(bus, page, offset, &value64);
+		printf("page=0x%02x, offset=0x%02x, value=0x%016llx\n",
+		       page, offset, value64);
+		break;
+	default:
+		printf("Unsupported width: %d\n", width);
+		break;
+	}
+
+	return ret;
+}
+
+int do_b53_reg_write(const char *name, int argc, char * const argv[])
+{
+	u8 page, offset, width;
+	struct mii_dev *bus;
+	int ret = -EINVAL;
+	u64 value64 = 0;
+	u32 value = 0;
+
+	bus = miiphy_get_dev_by_name(name);
+	if (!bus) {
+		printf("unable to find MDIO bus: %s\n", name);
+		return ret;
+	}
+
+	page = simple_strtoul(argv[1], NULL, 16);
+	offset = simple_strtoul(argv[2], NULL, 16);
+	width = simple_strtoul(argv[3], NULL, 10);
+	if (width == 48 || width == 64)
+		value64 = simple_strtoull(argv[4], NULL, 16);
+	else
+		value = simple_strtoul(argv[4], NULL, 16);
+
+	switch (width) {
+	case 8:
+		ret = b53_mdio_write8(bus, page, offset, value & 0xff);
+		break;
+	case 16:
+		ret = b53_mdio_write16(bus, page, offset, value);
+		break;
+	case 32:
+		ret = b53_mdio_write32(bus, page, offset, value);
+		break;
+	case 48:
+		ret = b53_mdio_write48(bus, page, offset, value64);
+		break;
+	case 64:
+		ret = b53_mdio_write64(bus, page, offset, value64);
+		break;
+	default:
+		printf("Unsupported width: %d\n", width);
+		break;
+	}
+
+	return ret;
+}
+
+int do_b53_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	const char *cmd, *mdioname;
+	int ret = 0;
+
+	if (argc < 2)
+		return cmd_usage(cmdtp);
+
+	cmd = argv[1];
+	--argc;
+	++argv;
+
+	if (!strcmp(cmd, "write")) {
+		if (argc < 4)
+			return cmd_usage(cmdtp);
+		mdioname = argv[1];
+		--argc;
+		++argv;
+		ret = do_b53_reg_write(mdioname, argc, argv);
+	} else if (!strcmp(cmd, "read")) {
+		if (argc < 5)
+			return cmd_usage(cmdtp);
+		mdioname = argv[1];
+		--argc;
+		++argv;
+		ret = do_b53_reg_read(mdioname, argc, argv);
+	} else {
+		return cmd_usage(cmdtp);
+	}
+
+	return ret;
+}
+
+U_BOOT_CMD(b53_reg, 7, 1, do_b53_reg,
+	   "Broadcom B53 switch register access",
+	   "write mdioname page (hex) offset (hex) width (dec) value (hex)\n"
+	   "read mdioname page (hex) offset (hex) width (dec)\n"
+	  );
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index b7f300e..0b9a9fc 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -104,6 +104,31 @@
 #define MIIM_88E151x_MODE_SGMII		1
 #define MIIM_88E151x_RESET_OFFS		15
 
+static int m88e1xxx_phy_extread(struct phy_device *phydev, int addr,
+				int devaddr, int regnum)
+{
+	int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE);
+	int val;
+
+	phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr);
+	val = phy_read(phydev, MDIO_DEVAD_NONE, regnum);
+	phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage);
+
+	return val;
+}
+
+static int m88e1xxx_phy_extwrite(struct phy_device *phydev, int addr,
+				 int devaddr, int regnum, u16 val)
+{
+	int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE);
+
+	phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr);
+	phy_write(phydev, MDIO_DEVAD_NONE, regnum, val);
+	phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage);
+
+	return 0;
+}
+
 /* Marvell 88E1011S */
 static int m88e1011s_config(struct phy_device *phydev)
 {
@@ -669,6 +694,8 @@
 	.config = &m88e1510_config,
 	.startup = &m88e1011s_startup,
 	.shutdown = &genphy_shutdown,
+	.readext = &m88e1xxx_phy_extread,
+	.writeext = &m88e1xxx_phy_extwrite,
 };
 
 /*
@@ -684,6 +711,8 @@
 	.config = &m88e1518_config,
 	.startup = &m88e1011s_startup,
 	.shutdown = &genphy_shutdown,
+	.readext = &m88e1xxx_phy_extread,
+	.writeext = &m88e1xxx_phy_extwrite,
 };
 
 static struct phy_driver M88E1310_driver = {
diff --git a/drivers/net/phy/miiphybb.c b/drivers/net/phy/miiphybb.c
index af676b9..d617224 100644
--- a/drivers/net/phy/miiphybb.c
+++ b/drivers/net/phy/miiphybb.c
@@ -232,7 +232,7 @@
  */
 int bb_miiphy_read(struct mii_dev *miidev, int addr, int devad, int reg)
 {
-	short rdreg; /* register working value */
+	unsigned short rdreg; /* register working value */
 	int v;
 	int j; /* counter */
 	struct bb_miiphy_bus *bus;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index fd3dd55..e31f3aa 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -461,6 +461,9 @@
 
 int phy_init(void)
 {
+#ifdef CONFIG_B53_SWITCH
+	phy_b53_init();
+#endif
 #ifdef CONFIG_MV88E61XX_SWITCH
 	phy_mv88e61xx_init();
 #endif
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 970d730..6edb51e 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -29,7 +29,8 @@
 
 #if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && !defined(CONFIG_SYS_DCACHE_OFF)
 #define flush_cache_wback(addr, len)    \
-		flush_dcache_range((u32)addr, (u32)(addr + len - 1))
+		flush_dcache_range((u32)addr, \
+		(u32)(addr + ALIGN(len, CONFIG_SH_ETHER_ALIGNE_SIZE)))
 #else
 #define flush_cache_wback(...)
 #endif
@@ -67,7 +68,7 @@
 
 	/* packet must be a 4 byte boundary */
 	if ((int)packet & 3) {
-		printf(SHETHER_NAME ": %s: packet not 4 byte alligned\n"
+		printf(SHETHER_NAME ": %s: packet not 4 byte aligned\n"
 				, __func__);
 		ret = -EFAULT;
 		goto err;
@@ -86,8 +87,8 @@
 	flush_cache_wback(port_info->tx_desc_cur, sizeof(struct tx_desc_s));
 
 	/* Restart the transmitter if disabled */
-	if (!(sh_eth_read(eth, EDTRR) & EDTRR_TRNS))
-		sh_eth_write(eth, EDTRR_TRNS, EDTRR);
+	if (!(sh_eth_read(port_info, EDTRR) & EDTRR_TRNS))
+		sh_eth_write(port_info, EDTRR_TRNS, EDTRR);
 
 	/* Wait until packet is transmitted */
 	timeout = TIMEOUT_CNT;
@@ -147,24 +148,25 @@
 	}
 
 	/* Restart the receiver if disabled */
-	if (!(sh_eth_read(eth, EDRRR) & EDRRR_R))
-		sh_eth_write(eth, EDRRR_R, EDRRR);
+	if (!(sh_eth_read(port_info, EDRRR) & EDRRR_R))
+		sh_eth_write(port_info, EDRRR_R, EDRRR);
 
 	return len;
 }
 
 static int sh_eth_reset(struct sh_eth_dev *eth)
 {
+	struct sh_eth_info *port_info = &eth->port_info[eth->port];
 #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ)
 	int ret = 0, i;
 
 	/* Start e-dmac transmitter and receiver */
-	sh_eth_write(eth, EDSR_ENALL, EDSR);
+	sh_eth_write(port_info, EDSR_ENALL, EDSR);
 
 	/* Perform a software reset and wait for it to complete */
-	sh_eth_write(eth, EDMR_SRST, EDMR);
+	sh_eth_write(port_info, EDMR_SRST, EDMR);
 	for (i = 0; i < TIMEOUT_CNT; i++) {
-		if (!(sh_eth_read(eth, EDMR) & EDMR_SRST))
+		if (!(sh_eth_read(port_info, EDMR) & EDMR_SRST))
 			break;
 		udelay(1000);
 	}
@@ -176,9 +178,10 @@
 
 	return ret;
 #else
-	sh_eth_write(eth, sh_eth_read(eth, EDMR) | EDMR_SRST, EDMR);
+	sh_eth_write(port_info, sh_eth_read(port_info, EDMR) | EDMR_SRST, EDMR);
 	udelay(3000);
-	sh_eth_write(eth, sh_eth_read(eth, EDMR) & ~EDMR_SRST, EDMR);
+	sh_eth_write(port_info,
+		     sh_eth_read(port_info, EDMR) & ~EDMR_SRST, EDMR);
 
 	return 0;
 #endif
@@ -203,7 +206,7 @@
 		goto err;
 	}
 
-	flush_cache_wback((u32)port_info->tx_desc_alloc, alloc_desc_size);
+	flush_cache_wback(port_info->tx_desc_alloc, alloc_desc_size);
 
 	/* Make sure we use a P2 address (non-cacheable) */
 	port_info->tx_desc_base =
@@ -222,13 +225,15 @@
 	cur_tx_desc--;
 	cur_tx_desc->td0 |= TD_TDLE;
 
-	/* Point the controller to the tx descriptor list. Must use physical
-	   addresses */
-	sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDLAR);
+	/*
+	 * Point the controller to the tx descriptor list. Must use physical
+	 * addresses
+	 */
+	sh_eth_write(port_info, ADDR_TO_PHY(port_info->tx_desc_base), TDLAR);
 #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ)
-	sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDFAR);
-	sh_eth_write(eth, ADDR_TO_PHY(cur_tx_desc), TDFXR);
-	sh_eth_write(eth, 0x01, TDFFR);/* Last discriptor bit */
+	sh_eth_write(port_info, ADDR_TO_PHY(port_info->tx_desc_base), TDFAR);
+	sh_eth_write(port_info, ADDR_TO_PHY(cur_tx_desc), TDFXR);
+	sh_eth_write(port_info, 0x01, TDFFR);/* Last discriptor bit */
 #endif
 
 err:
@@ -237,7 +242,7 @@
 
 static int sh_eth_rx_desc_init(struct sh_eth_dev *eth)
 {
-	int port = eth->port, i , ret = 0;
+	int port = eth->port, i, ret = 0;
 	u32 alloc_desc_size = NUM_RX_DESC * sizeof(struct rx_desc_s);
 	struct sh_eth_info *port_info = &eth->port_info[port];
 	struct rx_desc_s *cur_rx_desc;
@@ -283,7 +288,7 @@
 	     i < NUM_RX_DESC; cur_rx_desc++, rx_buf += MAX_BUF_SIZE, i++) {
 		cur_rx_desc->rd0 = RD_RACT;
 		cur_rx_desc->rd1 = MAX_BUF_SIZE << 16;
-		cur_rx_desc->rd2 = (u32) ADDR_TO_PHY(rx_buf);
+		cur_rx_desc->rd2 = (u32)ADDR_TO_PHY(rx_buf);
 	}
 
 	/* Mark the end of the descriptors */
@@ -291,11 +296,11 @@
 	cur_rx_desc->rd0 |= RD_RDLE;
 
 	/* Point the controller to the rx descriptor list */
-	sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDLAR);
+	sh_eth_write(port_info, ADDR_TO_PHY(port_info->rx_desc_base), RDLAR);
 #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ)
-	sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDFAR);
-	sh_eth_write(eth, ADDR_TO_PHY(cur_rx_desc), RDFXR);
-	sh_eth_write(eth, RDFFR_RDLF, RDFFR);
+	sh_eth_write(port_info, ADDR_TO_PHY(port_info->rx_desc_base), RDFAR);
+	sh_eth_write(port_info, ADDR_TO_PHY(cur_rx_desc), RDFXR);
+	sh_eth_write(port_info, RDFFR_RDLF, RDFFR);
 #endif
 
 	return ret;
@@ -371,7 +376,7 @@
 	return ret;
 }
 
-static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
+static int sh_eth_config(struct sh_eth_dev *eth)
 {
 	int port = eth->port, ret = 0;
 	u32 val;
@@ -380,45 +385,45 @@
 	struct phy_device *phy;
 
 	/* Configure e-dmac registers */
-	sh_eth_write(eth, (sh_eth_read(eth, EDMR) & ~EMDR_DESC_R) |
+	sh_eth_write(port_info, (sh_eth_read(port_info, EDMR) & ~EMDR_DESC_R) |
 			(EMDR_DESC | EDMR_EL), EDMR);
 
-	sh_eth_write(eth, 0, EESIPR);
-	sh_eth_write(eth, 0, TRSCER);
-	sh_eth_write(eth, 0, TFTR);
-	sh_eth_write(eth, (FIFO_SIZE_T | FIFO_SIZE_R), FDR);
-	sh_eth_write(eth, RMCR_RST, RMCR);
+	sh_eth_write(port_info, 0, EESIPR);
+	sh_eth_write(port_info, 0, TRSCER);
+	sh_eth_write(port_info, 0, TFTR);
+	sh_eth_write(port_info, (FIFO_SIZE_T | FIFO_SIZE_R), FDR);
+	sh_eth_write(port_info, RMCR_RST, RMCR);
 #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ)
-	sh_eth_write(eth, 0, RPADIR);
+	sh_eth_write(port_info, 0, RPADIR);
 #endif
-	sh_eth_write(eth, (FIFO_F_D_RFF | FIFO_F_D_RFD), FCFTR);
+	sh_eth_write(port_info, (FIFO_F_D_RFF | FIFO_F_D_RFD), FCFTR);
 
 	/* Configure e-mac registers */
-	sh_eth_write(eth, 0, ECSIPR);
+	sh_eth_write(port_info, 0, ECSIPR);
 
 	/* Set Mac address */
 	val = dev->enetaddr[0] << 24 | dev->enetaddr[1] << 16 |
 	    dev->enetaddr[2] << 8 | dev->enetaddr[3];
-	sh_eth_write(eth, val, MAHR);
+	sh_eth_write(port_info, val, MAHR);
 
 	val = dev->enetaddr[4] << 8 | dev->enetaddr[5];
-	sh_eth_write(eth, val, MALR);
+	sh_eth_write(port_info, val, MALR);
 
-	sh_eth_write(eth, RFLR_RFL_MIN, RFLR);
+	sh_eth_write(port_info, RFLR_RFL_MIN, RFLR);
 #if defined(SH_ETH_TYPE_GETHER)
-	sh_eth_write(eth, 0, PIPR);
+	sh_eth_write(port_info, 0, PIPR);
 #endif
 #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ)
-	sh_eth_write(eth, APR_AP, APR);
-	sh_eth_write(eth, MPR_MP, MPR);
-	sh_eth_write(eth, TPAUSER_TPAUSE, TPAUSER);
+	sh_eth_write(port_info, APR_AP, APR);
+	sh_eth_write(port_info, MPR_MP, MPR);
+	sh_eth_write(port_info, TPAUSER_TPAUSE, TPAUSER);
 #endif
 
 #if defined(CONFIG_CPU_SH7734) || defined(CONFIG_R8A7740)
-	sh_eth_write(eth, CONFIG_SH_ETHER_SH7734_MII, RMII_MII);
+	sh_eth_write(port_info, CONFIG_SH_ETHER_SH7734_MII, RMII_MII);
 #elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
 	defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
-	sh_eth_write(eth, sh_eth_read(eth, RMIIMR) | 0x1, RMIIMR);
+	sh_eth_write(port_info, sh_eth_read(port_info, RMIIMR) | 0x1, RMIIMR);
 #endif
 	/* Configure phy */
 	ret = sh_eth_phy_config(eth);
@@ -439,9 +444,9 @@
 	if (phy->speed == 100) {
 		printf(SHETHER_NAME ": 100Base/");
 #if defined(SH_ETH_TYPE_GETHER)
-		sh_eth_write(eth, GECMR_100B, GECMR);
+		sh_eth_write(port_info, GECMR_100B, GECMR);
 #elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)
-		sh_eth_write(eth, 1, RTRATE);
+		sh_eth_write(port_info, 1, RTRATE);
 #elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_R8A7790) || \
 		defined(CONFIG_R8A7791) || defined(CONFIG_R8A7793) || \
 		defined(CONFIG_R8A7794)
@@ -450,26 +455,29 @@
 	} else if (phy->speed == 10) {
 		printf(SHETHER_NAME ": 10Base/");
 #if defined(SH_ETH_TYPE_GETHER)
-		sh_eth_write(eth, GECMR_10B, GECMR);
+		sh_eth_write(port_info, GECMR_10B, GECMR);
 #elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)
-		sh_eth_write(eth, 0, RTRATE);
+		sh_eth_write(port_info, 0, RTRATE);
 #endif
 	}
 #if defined(SH_ETH_TYPE_GETHER)
 	else if (phy->speed == 1000) {
 		printf(SHETHER_NAME ": 1000Base/");
-		sh_eth_write(eth, GECMR_1000B, GECMR);
+		sh_eth_write(port_info, GECMR_1000B, GECMR);
 	}
 #endif
 
 	/* Check if full duplex mode is supported by the phy */
 	if (phy->duplex) {
 		printf("Full\n");
-		sh_eth_write(eth, val | (ECMR_CHG_DM|ECMR_RE|ECMR_TE|ECMR_DM),
+		sh_eth_write(port_info,
+			     val | (ECMR_CHG_DM | ECMR_RE | ECMR_TE | ECMR_DM),
 			     ECMR);
 	} else {
 		printf("Half\n");
-		sh_eth_write(eth, val | (ECMR_CHG_DM|ECMR_RE|ECMR_TE), ECMR);
+		sh_eth_write(port_info,
+			     val | (ECMR_CHG_DM | ECMR_RE | ECMR_TE),
+			     ECMR);
 	}
 
 	return ret;
@@ -480,16 +488,20 @@
 
 static void sh_eth_start(struct sh_eth_dev *eth)
 {
+	struct sh_eth_info *port_info = &eth->port_info[eth->port];
+
 	/*
 	 * Enable the e-dmac receiver only. The transmitter will be enabled when
 	 * we have something to transmit
 	 */
-	sh_eth_write(eth, EDRRR_R, EDRRR);
+	sh_eth_write(port_info, EDRRR_R, EDRRR);
 }
 
 static void sh_eth_stop(struct sh_eth_dev *eth)
 {
-	sh_eth_write(eth, ~EDRRR_R, EDRRR);
+	struct sh_eth_info *port_info = &eth->port_info[eth->port];
+
+	sh_eth_write(port_info, ~EDRRR_R, EDRRR);
 }
 
 int sh_eth_init(struct eth_device *dev, bd_t *bd)
@@ -505,7 +517,7 @@
 	if (ret)
 		goto err;
 
-	ret = sh_eth_config(eth, bd);
+	ret = sh_eth_config(eth);
 	if (ret)
 		goto err_config;
 
@@ -524,6 +536,7 @@
 void sh_eth_halt(struct eth_device *dev)
 {
 	struct sh_eth_dev *eth = dev->priv;
+
 	sh_eth_stop(eth);
 }
 
@@ -532,6 +545,7 @@
 	int ret = 0;
 	struct sh_eth_dev *eth = NULL;
 	struct eth_device *dev = NULL;
+	struct mii_dev *mdiodev;
 
 	eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev));
 	if (!eth) {
@@ -551,6 +565,8 @@
 
 	eth->port = CONFIG_SH_ETHER_USE_PORT;
 	eth->port_info[eth->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR;
+	eth->port_info[eth->port].iobase =
+		(void __iomem *)(BASE_IO_ADDR + 0x800 * eth->port);
 
 	dev->priv = (void *)eth;
 	dev->iobase = 0;
@@ -566,17 +582,16 @@
 	eth_register(dev);
 
 	bb_miiphy_buses[0].priv = eth;
-	int retval;
-	struct mii_dev *mdiodev = mdio_alloc();
+	mdiodev = mdio_alloc();
 	if (!mdiodev)
 		return -ENOMEM;
 	strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
 	mdiodev->read = bb_miiphy_read;
 	mdiodev->write = bb_miiphy_write;
 
-	retval = mdio_register(mdiodev);
-	if (retval < 0)
-		return retval;
+	ret = mdio_register(mdiodev);
+	if (ret < 0)
+		return ret;
 
 	if (!eth_env_get_enetaddr("ethaddr", dev->enetaddr))
 		puts("Please set MAC address\n");
@@ -603,8 +618,9 @@
 static int sh_eth_bb_mdio_active(struct bb_miiphy_bus *bus)
 {
 	struct sh_eth_dev *eth = bus->priv;
+	struct sh_eth_info *port_info = &eth->port_info[eth->port];
 
-	sh_eth_write(eth, sh_eth_read(eth, PIR) | PIR_MMD, PIR);
+	sh_eth_write(port_info, sh_eth_read(port_info, PIR) | PIR_MMD, PIR);
 
 	return 0;
 }
@@ -612,8 +628,9 @@
 static int sh_eth_bb_mdio_tristate(struct bb_miiphy_bus *bus)
 {
 	struct sh_eth_dev *eth = bus->priv;
+	struct sh_eth_info *port_info = &eth->port_info[eth->port];
 
-	sh_eth_write(eth, sh_eth_read(eth, PIR) & ~PIR_MMD, PIR);
+	sh_eth_write(port_info, sh_eth_read(port_info, PIR) & ~PIR_MMD, PIR);
 
 	return 0;
 }
@@ -621,11 +638,14 @@
 static int sh_eth_bb_set_mdio(struct bb_miiphy_bus *bus, int v)
 {
 	struct sh_eth_dev *eth = bus->priv;
+	struct sh_eth_info *port_info = &eth->port_info[eth->port];
 
 	if (v)
-		sh_eth_write(eth, sh_eth_read(eth, PIR) | PIR_MDO, PIR);
+		sh_eth_write(port_info,
+			     sh_eth_read(port_info, PIR) | PIR_MDO, PIR);
 	else
-		sh_eth_write(eth, sh_eth_read(eth, PIR) & ~PIR_MDO, PIR);
+		sh_eth_write(port_info,
+			     sh_eth_read(port_info, PIR) & ~PIR_MDO, PIR);
 
 	return 0;
 }
@@ -633,8 +653,9 @@
 static int sh_eth_bb_get_mdio(struct bb_miiphy_bus *bus, int *v)
 {
 	struct sh_eth_dev *eth = bus->priv;
+	struct sh_eth_info *port_info = &eth->port_info[eth->port];
 
-	*v = (sh_eth_read(eth, PIR) & PIR_MDI) >> 3;
+	*v = (sh_eth_read(port_info, PIR) & PIR_MDI) >> 3;
 
 	return 0;
 }
@@ -642,11 +663,14 @@
 static int sh_eth_bb_set_mdc(struct bb_miiphy_bus *bus, int v)
 {
 	struct sh_eth_dev *eth = bus->priv;
+	struct sh_eth_info *port_info = &eth->port_info[eth->port];
 
 	if (v)
-		sh_eth_write(eth, sh_eth_read(eth, PIR) | PIR_MDC, PIR);
+		sh_eth_write(port_info,
+			     sh_eth_read(port_info, PIR) | PIR_MDC, PIR);
 	else
-		sh_eth_write(eth, sh_eth_read(eth, PIR) & ~PIR_MDC, PIR);
+		sh_eth_write(port_info,
+			     sh_eth_read(port_info, PIR) & ~PIR_MDC, PIR);
 
 	return 0;
 }
@@ -670,4 +694,5 @@
 		.delay		= sh_eth_bb_delay,
 	}
 };
+
 int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index 3645f0e..a0dcfca 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -25,8 +25,10 @@
 #define ADDR_TO_PHY(addr)	((int)(addr) & ~0xe0000000)
 #endif
 #elif defined(CONFIG_ARM)
-#define inl		readl
+#ifndef inl
+#define inl	readl
 #define outl	writel
+#endif
 #define ADDR_TO_PHY(addr)	((int)(addr))
 #define ADDR_TO_P2(addr)	(addr)
 #endif /* defined(CONFIG_SH) */
@@ -90,6 +92,7 @@
 	u8 phy_addr;
 	struct eth_device *dev;
 	struct phy_device *phydev;
+	void __iomem *iobase;
 };
 
 struct sh_eth_dev {
@@ -226,61 +229,6 @@
 	[RMII_MII] =  0x0790,
 };
 
-#if defined(SH_ETH_TYPE_RZ)
-static const u16 sh_eth_offset_rz[SH_ETH_MAX_REGISTER_OFFSET] = {
-	[EDSR]	= 0x0000,
-	[EDMR]	= 0x0400,
-	[EDTRR]	= 0x0408,
-	[EDRRR]	= 0x0410,
-	[EESR]	= 0x0428,
-	[EESIPR]	= 0x0430,
-	[TDLAR]	= 0x0010,
-	[TDFAR]	= 0x0014,
-	[TDFXR]	= 0x0018,
-	[TDFFR]	= 0x001c,
-	[RDLAR]	= 0x0030,
-	[RDFAR]	= 0x0034,
-	[RDFXR]	= 0x0038,
-	[RDFFR]	= 0x003c,
-	[TRSCER]	= 0x0438,
-	[RMFCR]	= 0x0440,
-	[TFTR]	= 0x0448,
-	[FDR]	= 0x0450,
-	[RMCR]	= 0x0458,
-	[RPADIR]	= 0x0460,
-	[FCFTR]	= 0x0468,
-	[CSMR] = 0x04E4,
-
-	[ECMR]	= 0x0500,
-	[ECSR]	= 0x0510,
-	[ECSIPR]	= 0x0518,
-	[PSR]	= 0x0528,
-	[PIPR]	= 0x052c,
-	[RFLR]	= 0x0508,
-	[APR]	= 0x0554,
-	[MPR]	= 0x0558,
-	[PFTCR]	= 0x055c,
-	[PFRCR]	= 0x0560,
-	[TPAUSER]	= 0x0564,
-	[GECMR]	= 0x05b0,
-	[BCULR]	= 0x05b4,
-	[MAHR]	= 0x05c0,
-	[MALR]	= 0x05c8,
-	[TROCR]	= 0x0700,
-	[CDCR]	= 0x0708,
-	[LCCR]	= 0x0710,
-	[CEFCR]	= 0x0740,
-	[FRECR]	= 0x0748,
-	[TSFRCR]	= 0x0750,
-	[TLFRCR]	= 0x0758,
-	[RFCR]	= 0x0760,
-	[CERCR]	= 0x0768,
-	[CEECR]	= 0x0770,
-	[MAFCR]	= 0x0778,
-	[RMII_MII] =  0x0790,
-};
-#endif
-
 static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
 	[ECMR]	= 0x0100,
 	[RFLR]	= 0x0108,
@@ -654,29 +602,27 @@
 	FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007,
 };
 
-static inline unsigned long sh_eth_reg_addr(struct sh_eth_dev *eth,
+static inline unsigned long sh_eth_reg_addr(struct sh_eth_info *port,
 					    int enum_index)
 {
-#if defined(SH_ETH_TYPE_GETHER)
+#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ)
 	const u16 *reg_offset = sh_eth_offset_gigabit;
 #elif defined(SH_ETH_TYPE_ETHER)
 	const u16 *reg_offset = sh_eth_offset_fast_sh4;
-#elif defined(SH_ETH_TYPE_RZ)
-	const u16 *reg_offset = sh_eth_offset_rz;
 #else
 #error
 #endif
-	return BASE_IO_ADDR + reg_offset[enum_index] + 0x800 * eth->port;
+	return (unsigned long)port->iobase + reg_offset[enum_index];
 }
 
-static inline void sh_eth_write(struct sh_eth_dev *eth, unsigned long data,
+static inline void sh_eth_write(struct sh_eth_info *port, unsigned long data,
 				int enum_index)
 {
-	outl(data, sh_eth_reg_addr(eth, enum_index));
+	outl(data, sh_eth_reg_addr(port, enum_index));
 }
 
-static inline unsigned long sh_eth_read(struct sh_eth_dev *eth,
+static inline unsigned long sh_eth_read(struct sh_eth_info *port,
 					int enum_index)
 {
-	return inl(sh_eth_reg_addr(eth, enum_index));
+	return inl(sh_eth_reg_addr(port, enum_index));
 }
diff --git a/include/configs/alt.h b/include/configs/alt.h
index 35518da..e35ddc8 100644
--- a/include/configs/alt.h
+++ b/include/configs/alt.h
@@ -44,7 +44,6 @@
 #define CONFIG_SPI_FLASH_QUAD
 
 /* SH Ether */
-#define CONFIG_SH_ETHER
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	0x1
 #define CONFIG_SH_ETHER_PHY_MODE PHY_INTERFACE_MODE_RMII
diff --git a/include/configs/ap_sh4a_4a.h b/include/configs/ap_sh4a_4a.h
index 37aaec3..2a01000 100644
--- a/include/configs/ap_sh4a_4a.h
+++ b/include/configs/ap_sh4a_4a.h
@@ -18,7 +18,6 @@
 #undef  CONFIG_SHOW_BOOT_PROGRESS
 
 /* Ether */
-#define CONFIG_SH_ETHER 1
 #define CONFIG_SH_ETHER_USE_PORT (0)
 #define CONFIG_SH_ETHER_PHY_ADDR (0x0)
 #define CONFIG_SH_ETHER_PHY_MODE (PHY_INTERFACE_MODE_GMII)
diff --git a/include/configs/armadillo-800eva.h b/include/configs/armadillo-800eva.h
index 66ae76b..94aecb7 100644
--- a/include/configs/armadillo-800eva.h
+++ b/include/configs/armadillo-800eva.h
@@ -88,7 +88,6 @@
 #define CONFIG_ENV_SIZE_REDUND	(CONFIG_ENV_SECT_SIZE)
 
 /* SH Ether */
-#define CONFIG_SH_ETHER
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	0x0
 #define CONFIG_SH_ETHER_BASE_ADDR	0xe9a00000
diff --git a/include/configs/ecovec.h b/include/configs/ecovec.h
index c6fb59f..32d679d 100644
--- a/include/configs/ecovec.h
+++ b/include/configs/ecovec.h
@@ -44,7 +44,6 @@
 #define CONFIG_SH_I2C_CLOCK  	41666666
 
 /* Ether */
-#define CONFIG_SH_ETHER 1
 #define CONFIG_SH_ETHER_USE_PORT (0)
 #define CONFIG_SH_ETHER_PHY_ADDR (0x1f)
 #define CONFIG_PHY_SMSC 1
diff --git a/include/configs/espt.h b/include/configs/espt.h
index a5ac8cb..65221fc 100644
--- a/include/configs/espt.h
+++ b/include/configs/espt.h
@@ -77,7 +77,6 @@
 #define CONFIG_SYS_TMU_CLK_DIV      4
 
 /* Ether */
-#define CONFIG_SH_ETHER 1
 #define CONFIG_SH_ETHER_USE_PORT (1)
 #define CONFIG_SH_ETHER_PHY_ADDR (0x00)
 #define CONFIG_BITBANGMII
diff --git a/include/configs/gose.h b/include/configs/gose.h
index 610ba1a..fab0edd 100644
--- a/include/configs/gose.h
+++ b/include/configs/gose.h
@@ -44,7 +44,6 @@
 #define CONFIG_SH_QSPI
 
 /* SH Ether */
-#define CONFIG_SH_ETHER
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	0x1
 #define CONFIG_SH_ETHER_PHY_MODE PHY_INTERFACE_MODE_RMII
diff --git a/include/configs/koelsch.h b/include/configs/koelsch.h
index b9214d2..c449e43 100644
--- a/include/configs/koelsch.h
+++ b/include/configs/koelsch.h
@@ -44,7 +44,6 @@
 #define CONFIG_SH_QSPI
 
 /* SH Ether */
-#define CONFIG_SH_ETHER
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	0x1
 #define CONFIG_SH_ETHER_PHY_MODE PHY_INTERFACE_MODE_RMII
diff --git a/include/configs/lager.h b/include/configs/lager.h
index 291b03c..000e5cd 100644
--- a/include/configs/lager.h
+++ b/include/configs/lager.h
@@ -44,7 +44,6 @@
 #define CONFIG_SH_QSPI
 
 /* SH Ether */
-#define CONFIG_SH_ETHER
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	0x1
 #define CONFIG_SH_ETHER_PHY_MODE PHY_INTERFACE_MODE_RMII
diff --git a/include/configs/porter.h b/include/configs/porter.h
index 451d9dd..10dce6b 100644
--- a/include/configs/porter.h
+++ b/include/configs/porter.h
@@ -45,7 +45,6 @@
 #define CONFIG_SPI_FLASH_QUAD
 
 /* SH Ether */
-#define CONFIG_SH_ETHER
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	0x1
 #define CONFIG_SH_ETHER_PHY_MODE PHY_INTERFACE_MODE_RMII
diff --git a/include/configs/r0p7734.h b/include/configs/r0p7734.h
index 9258a3b..f9800ec 100644
--- a/include/configs/r0p7734.h
+++ b/include/configs/r0p7734.h
@@ -18,7 +18,6 @@
 #undef  CONFIG_SHOW_BOOT_PROGRESS
 
 /* Ether */
-#define CONFIG_SH_ETHER 1
 #define CONFIG_SH_ETHER_USE_PORT (0)
 #define CONFIG_SH_ETHER_PHY_ADDR (0x0)
 #define CONFIG_PHY_SMSC 1
diff --git a/include/configs/sh7752evb.h b/include/configs/sh7752evb.h
index 2f81cc5..ee57eb2 100644
--- a/include/configs/sh7752evb.h
+++ b/include/configs/sh7752evb.h
@@ -47,7 +47,6 @@
 #define CONFIG_SYS_BOOTMAPSZ		(8 * 1024 * 1024)
 
 /* Ether */
-#define CONFIG_SH_ETHER			1
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	18
 #define CONFIG_SH_ETHER_CACHE_WRITEBACK	1
diff --git a/include/configs/sh7753evb.h b/include/configs/sh7753evb.h
index bcb85a6..e7f9f61 100644
--- a/include/configs/sh7753evb.h
+++ b/include/configs/sh7753evb.h
@@ -47,7 +47,6 @@
 #define CONFIG_SYS_BOOTMAPSZ		(8 * 1024 * 1024)
 
 /* Ether */
-#define CONFIG_SH_ETHER			1
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	18
 #define CONFIG_SH_ETHER_CACHE_WRITEBACK	1
diff --git a/include/configs/sh7757lcr.h b/include/configs/sh7757lcr.h
index bee1a1d..a2b3307 100644
--- a/include/configs/sh7757lcr.h
+++ b/include/configs/sh7757lcr.h
@@ -48,7 +48,6 @@
 #define CONFIG_SYS_BOOTMAPSZ		(8 * 1024 * 1024)
 
 /* Ether */
-#define CONFIG_SH_ETHER			1
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	1
 #define CONFIG_SH_ETHER_CACHE_WRITEBACK	1
diff --git a/include/configs/sh7763rdp.h b/include/configs/sh7763rdp.h
index 0598b25..de4a587 100644
--- a/include/configs/sh7763rdp.h
+++ b/include/configs/sh7763rdp.h
@@ -77,7 +77,6 @@
 #define CONFIG_SYS_TMU_CLK_DIV		(4)	/* 4 (default), 16, 64, 256 or 1024 */
 
 /* Ether */
-#define CONFIG_SH_ETHER 1
 #define CONFIG_SH_ETHER_USE_PORT (1)
 #define CONFIG_SH_ETHER_PHY_ADDR (0x01)
 #define CONFIG_BITBANGMII
diff --git a/include/configs/silk.h b/include/configs/silk.h
index 0384325..79a4f06 100644
--- a/include/configs/silk.h
+++ b/include/configs/silk.h
@@ -45,7 +45,6 @@
 #define CONFIG_SPI_FLASH_QUAD
 
 /* SH Ether */
-#define CONFIG_SH_ETHER
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	0x1
 #define CONFIG_SH_ETHER_PHY_MODE PHY_INTERFACE_MODE_RMII
diff --git a/include/configs/stout.h b/include/configs/stout.h
index 9422c04..789f364 100644
--- a/include/configs/stout.h
+++ b/include/configs/stout.h
@@ -48,7 +48,6 @@
 #define CONFIG_SPI_FLASH_QUAD
 
 /* SH Ether */
-#define CONFIG_SH_ETHER
 #define CONFIG_SH_ETHER_USE_PORT	0
 #define CONFIG_SH_ETHER_PHY_ADDR	0x1
 #define CONFIG_SH_ETHER_PHY_MODE PHY_INTERFACE_MODE_RMII
diff --git a/include/phy.h b/include/phy.h
index 50f1e12..0543ec1 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -257,6 +257,7 @@
 int gen10g_shutdown(struct phy_device *phydev);
 int gen10g_discover_mmds(struct phy_device *phydev);
 
+int phy_b53_init(void);
 int phy_mv88e61xx_init(void);
 int phy_aquantia_init(void);
 int phy_atheros_init(void);
diff --git a/net/bootp.c b/net/bootp.c
index 73370a1..efa9599 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -14,7 +14,6 @@
 #include <net.h>
 #include <net/tftp.h>
 #include "bootp.h"
-#include "nfs.h"
 #ifdef CONFIG_LED_STATUS
 #include <status_led.h>
 #endif
@@ -387,12 +386,19 @@
 
 	if (time_taken >= time_taken_max) {
 #ifdef CONFIG_BOOTP_MAY_FAIL
-		puts("\nRetry time exceeded\n");
-		net_set_state(NETLOOP_FAIL);
-#else
-		puts("\nRetry time exceeded; starting again\n");
-		net_start_again();
+		char *ethrotate;
+
+		ethrotate = env_get("ethrotate");
+		if ((ethrotate && strcmp(ethrotate, "no") == 0) ||
+		    net_restart_wrap) {
+			puts("\nRetry time exceeded\n");
+			net_set_state(NETLOOP_FAIL);
+		} else
 #endif
+		{
+			puts("\nRetry time exceeded; starting again\n");
+			net_start_again();
+		}
 	} else {
 		bootp_timeout *= 2;
 		if (bootp_timeout > 2000)
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index 4e87d66..394243b 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -1924,7 +1924,6 @@
 CONFIG_SHOW_BOOT_PROGRESS
 CONFIG_SH_CMT_CLK_FREQ
 CONFIG_SH_DSP
-CONFIG_SH_ETHER
 CONFIG_SH_ETHER_ALIGNE_SIZE
 CONFIG_SH_ETHER_BASE_ADDR
 CONFIG_SH_ETHER_CACHE_INVALIDATE