Merge git://www.denx.de/git/u-boot-ppc4xx
diff --git a/arch/arm/dts/dra7-evm.dts b/arch/arm/dts/dra7-evm.dts
index 8b77a76..06b7b36 100644
--- a/arch/arm/dts/dra7-evm.dts
+++ b/arch/arm/dts/dra7-evm.dts
@@ -415,6 +415,7 @@
 		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
+		u-boot,i2c-offset-len = <0>;
 	};
 
 };
diff --git a/arch/arm/dts/dra72-evm.dts b/arch/arm/dts/dra72-evm.dts
index c7c5d40..e78ec2e 100644
--- a/arch/arm/dts/dra72-evm.dts
+++ b/arch/arm/dts/dra72-evm.dts
@@ -348,6 +348,7 @@
 		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
+		u-boot,i2c-offset-len = <0>;
 	};
 };
 
@@ -369,6 +370,7 @@
 		 * VIN6_SEL_S0 is low, thus selecting McASP3 over VIN6
 		 */
 		lines-initial-states = <0x0f2b>;
+		u-boot,i2c-offset-len = <0>;
 	};
 };
 
@@ -576,6 +578,7 @@
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&cpsw_default>;
 	pinctrl-1 = <&cpsw_sleep>;
+	mode-gpios = <&pcf_gpio_21 4 GPIO_ACTIVE_HIGH>;
 };
 
 &cpsw_emac1 {
@@ -587,7 +590,6 @@
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&davinci_mdio_default>;
 	pinctrl-1 = <&davinci_mdio_sleep>;
-	active_slave = <1>;
 };
 
 &dcan1 {
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index d66892e..b52ba9c 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -8,6 +8,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm/device.h>
 #include <efi_loader.h>
 #include <errno.h>
 #include <libfdt.h>
@@ -265,18 +266,30 @@
 	char devname[32] = { 0 }; /* dp->str is u16[32] long */
 	char *colon;
 
-	/* Assemble the condensed device name we use in efi_disk.c */
-	snprintf(devname, sizeof(devname), "%s%s", dev, devnr);
+#if defined(CONFIG_BLK) || defined(CONFIG_ISO_PARTITION)
+	desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10));
+#endif
+
+#ifdef CONFIG_BLK
+	if (desc) {
+		snprintf(devname, sizeof(devname), "%s", desc->bdev->name);
+	} else
+#endif
+
+	{
+		/* Assemble the condensed device name we use in efi_disk.c */
+		snprintf(devname, sizeof(devname), "%s%s", dev, devnr);
+	}
+
 	colon = strchr(devname, ':');
 
 #ifdef CONFIG_ISO_PARTITION
 	/* For ISOs we create partition block devices */
-	desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10));
 	if (desc && (desc->type != DEV_TYPE_UNKNOWN) &&
 	    (desc->part_type == PART_TYPE_ISO)) {
 		if (!colon)
-			snprintf(devname, sizeof(devname), "%s%s:1", dev,
-				 devnr);
+			snprintf(devname, sizeof(devname), "%s:1", devname);
+
 		colon = NULL;
 	}
 #endif
diff --git a/common/spl/spl_nor.c b/common/spl/spl_nor.c
index da2422f..8ea874c 100644
--- a/common/spl/spl_nor.c
+++ b/common/spl/spl_nor.c
@@ -40,11 +40,11 @@
 
 			/*
 			 * Copy DT blob (fdt) to SDRAM. Passing pointer to
-			 * flash doesn't work (16 KiB should be enough for DT)
+			 * flash doesn't work
 			 */
 			memcpy((void *)CONFIG_SYS_SPL_ARGS_ADDR,
 			       (void *)(CONFIG_SYS_FDT_BASE),
-			       (16 << 10));
+			       CONFIG_SYS_FDT_SIZE);
 
 			return 0;
 		} else {
diff --git a/configs/dra7xx_evm_defconfig b/configs/dra7xx_evm_defconfig
index 1d27e52..81d2a0e 100644
--- a/configs/dra7xx_evm_defconfig
+++ b/configs/dra7xx_evm_defconfig
@@ -58,3 +58,4 @@
 CONFIG_SPL_LOAD_FIT=y
 CONFIG_OF_LIST="dra7-evm dra72-evm"
 CONFIG_DM_I2C=y
+CONFIG_PCF8575_GPIO=y
diff --git a/configs/dra7xx_hs_evm_defconfig b/configs/dra7xx_hs_evm_defconfig
index faf9cd5..ab68b1c 100644
--- a/configs/dra7xx_hs_evm_defconfig
+++ b/configs/dra7xx_hs_evm_defconfig
@@ -61,3 +61,4 @@
 CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
 CONFIG_OF_LIST="dra7-evm dra72-evm"
 CONFIG_DM_I2C=y
+CONFIG_PCF8575_GPIO=y
diff --git a/configs/k2e_evm_defconfig b/configs/k2e_evm_defconfig
index 65561b1..04c52f0 100644
--- a/configs/k2e_evm_defconfig
+++ b/configs/k2e_evm_defconfig
@@ -37,3 +37,5 @@
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_LIB_RAND=y
+CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/configs/k2hk_evm_defconfig b/configs/k2hk_evm_defconfig
index 8623e1c..c050f07 100644
--- a/configs/k2hk_evm_defconfig
+++ b/configs/k2hk_evm_defconfig
@@ -37,3 +37,5 @@
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_LIB_RAND=y
+CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/configs/k2l_evm_defconfig b/configs/k2l_evm_defconfig
index 9aa429c..e1386f7 100644
--- a/configs/k2l_evm_defconfig
+++ b/configs/k2l_evm_defconfig
@@ -37,3 +37,5 @@
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_LIB_RAND=y
+CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/doc/device-tree-bindings/gpio/gpio-pcf857x.txt b/doc/device-tree-bindings/gpio/gpio-pcf857x.txt
new file mode 100644
index 0000000..ada4e29
--- /dev/null
+++ b/doc/device-tree-bindings/gpio/gpio-pcf857x.txt
@@ -0,0 +1,71 @@
+* PCF857x-compatible I/O expanders
+
+The PCF857x-compatible chips have "quasi-bidirectional" I/O lines that can be
+driven high by a pull-up current source or driven low to ground. This combines
+the direction and output level into a single bit per line, which can't be read
+back. We can't actually know at initialization time whether a line is configured
+(a) as output and driving the signal low/high, or (b) as input and reporting a
+low/high value, without knowing the last value written since the chip came out
+of reset (if any). The only reliable solution for setting up line direction is
+thus to do it explicitly.
+
+Required Properties:
+
+  - compatible: should be one of the following.
+    - "maxim,max7328": For the Maxim MAX7378
+    - "maxim,max7329": For the Maxim MAX7329
+    - "nxp,pca8574": For the NXP PCA8574
+    - "nxp,pca8575": For the NXP PCA8575
+    - "nxp,pca9670": For the NXP PCA9670
+    - "nxp,pca9671": For the NXP PCA9671
+    - "nxp,pca9672": For the NXP PCA9672
+    - "nxp,pca9673": For the NXP PCA9673
+    - "nxp,pca9674": For the NXP PCA9674
+    - "nxp,pca9675": For the NXP PCA9675
+    - "nxp,pcf8574": For the NXP PCF8574
+    - "nxp,pcf8574a": For the NXP PCF8574A
+    - "nxp,pcf8575": For the NXP PCF8575
+    - "ti,tca9554": For the TI TCA9554
+
+  - reg: I2C slave address.
+
+  - gpio-controller: Marks the device node as a gpio controller.
+  - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
+    cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
+    GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
+
+Optional Properties:
+
+  - lines-initial-states: Bitmask that specifies the initial state of each
+  line. When a bit is set to zero, the corresponding line will be initialized to
+  the input (pulled-up) state. When the  bit is set to one, the line will be
+  initialized the low-level output state. If the property is not specified
+  all lines will be initialized to the input state.
+
+  The I/O expander can detect input state changes, and thus optionally act as
+  an interrupt controller. When the expander interrupt line is connected all the
+  following properties must be set. For more information please see the
+  interrupt controller device tree bindings documentation available at
+  Documentation/devicetree/bindings/interrupt-controller/interrupts.txt.
+
+  - interrupt-controller: Identifies the node as an interrupt controller.
+  - #interrupt-cells: Number of cells to encode an interrupt source, shall be 2.
+  - interrupt-parent: phandle of the parent interrupt controller.
+  - interrupts: Interrupt specifier for the controllers interrupt.
+
+
+Please refer to gpio.txt in this directory for details of the common GPIO
+bindings used by client devices.
+
+Example: PCF8575 I/O expander node
+
+	pcf8575: gpio@20 {
+		compatible = "nxp,pcf8575";
+		reg = <0x20>;
+		interrupt-parent = <&irqpin2>;
+		interrupts = <3 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 73b862d..64cf221 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -79,6 +79,13 @@
 	  Power and reset buttons are placed in "pm8916_key" bank and
           have gpio numbers 0 and 1 respectively.
 
+config PCF8575_GPIO
+	bool "PCF8575 I2C GPIO Expander driver"
+	depends on DM_GPIO && DM_I2C
+	help
+	 Support for PCF8575 I2C 16-bit GPIO expander. Most of these
+	 chips are from NXP and TI.
+
 config ROCKCHIP_GPIO
 	bool "Rockchip GPIO driver"
 	depends on DM_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 792d191..8939226 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -56,4 +56,5 @@
 obj-$(CONFIG_PIC32_GPIO)	+= pic32_gpio.o
 obj-$(CONFIG_MVEBU_GPIO)	+= mvebu_gpio.o
 obj-$(CONFIG_MSM_GPIO)		+= msm_gpio.o
+obj-$(CONFIG_$(SPL_)PCF8575_GPIO)	+= pcf8575_gpio.o
 obj-$(CONFIG_PM8916_GPIO)	+= pm8916_gpio.o
diff --git a/drivers/gpio/pcf8575_gpio.c b/drivers/gpio/pcf8575_gpio.c
new file mode 100644
index 0000000..2bda0ff
--- /dev/null
+++ b/drivers/gpio/pcf8575_gpio.c
@@ -0,0 +1,180 @@
+/*
+ * PCF8575 I2C GPIO EXPANDER DRIVER
+ *
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Vignesh R <vigneshr@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ *
+ *
+ * Driver for TI PCF-8575 16-bit I2C gpio expander. Based on
+ * gpio-pcf857x Linux Kernel(v4.7) driver.
+ *
+ * Copyright (C) 2007 David Brownell
+ *
+ */
+
+/*
+ * NOTE: The driver and devicetree bindings are borrowed from Linux
+ * Kernel, but driver does not support all PCF857x devices. It currently
+ * supports PCF8575 16-bit expander by TI and NXP.
+ *
+ * TODO(vigneshr@ti.com):
+ * Support 8 bit PCF857x compatible expanders.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <asm-generic/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pcf8575_chip {
+	int gpio_count;		/* No. GPIOs supported by the chip */
+
+	/* NOTE:  these chips have strange "quasi-bidirectional" I/O pins.
+	 * We can't actually know whether a pin is configured (a) as output
+	 * and driving the signal low, or (b) as input and reporting a low
+	 * value ... without knowing the last value written since the chip
+	 * came out of reset (if any).  We can't read the latched output.
+	 * In short, the only reliable solution for setting up pin direction
+	 * is to do it explicitly.
+	 *
+	 * Using "out" avoids that trouble.  When left initialized to zero,
+	 * our software copy of the "latch" then matches the chip's all-ones
+	 * reset state.  Otherwise it flags pins to be driven low.
+	 */
+	unsigned int out;	/* software latch */
+	const char *bank_name;	/* Name of the expander bank */
+};
+
+/* Read/Write to 16-bit I/O expander */
+
+static int pcf8575_i2c_write_le16(struct udevice *dev, unsigned int word)
+{
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+	u8 buf[2] = { word & 0xff, word >> 8, };
+	int ret;
+
+	ret = dm_i2c_write(dev, 0, buf, 2);
+	if (ret)
+		printf("%s i2c write failed to addr %x\n", __func__,
+		       chip->chip_addr);
+
+	return ret;
+}
+
+static int pcf8575_i2c_read_le16(struct udevice *dev)
+{
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+	u8 buf[2];
+	int ret;
+
+	ret = dm_i2c_read(dev, 0, buf, 2);
+	if (ret) {
+		printf("%s i2c read failed from addr %x\n", __func__,
+		       chip->chip_addr);
+		return ret;
+	}
+
+	return (buf[1] << 8) | buf[0];
+}
+
+static int pcf8575_direction_input(struct udevice *dev, unsigned offset)
+{
+	struct pcf8575_chip *plat = dev_get_platdata(dev);
+	int status;
+
+	plat->out |= BIT(offset);
+	status = pcf8575_i2c_write_le16(dev, plat->out);
+
+	return status;
+}
+
+static int pcf8575_direction_output(struct udevice *dev,
+				    unsigned int offset, int value)
+{
+	struct pcf8575_chip *plat = dev_get_platdata(dev);
+	int ret;
+
+	if (value)
+		plat->out |= BIT(offset);
+	else
+		plat->out &= ~BIT(offset);
+
+	ret = pcf8575_i2c_write_le16(dev, plat->out);
+
+	return ret;
+}
+
+static int pcf8575_get_value(struct udevice *dev, unsigned int offset)
+{
+	int             value;
+
+	value = pcf8575_i2c_read_le16(dev);
+
+	return (value < 0) ? value : ((value & BIT(offset)) >> offset);
+}
+
+static int pcf8575_set_value(struct udevice *dev, unsigned int offset,
+			     int value)
+{
+	return pcf8575_direction_output(dev, offset, value);
+}
+
+static int pcf8575_ofdata_platdata(struct udevice *dev)
+{
+	struct pcf8575_chip *plat = dev_get_platdata(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	int n_latch;
+
+	uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+					     "gpio-count", 16);
+	uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset,
+					 "gpio-bank-name", NULL);
+	if (!uc_priv->bank_name)
+		uc_priv->bank_name = fdt_get_name(gd->fdt_blob,
+						  dev->of_offset, NULL);
+
+	n_latch = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
+				  "lines-initial-states", 0);
+	plat->out = ~n_latch;
+
+	return 0;
+}
+
+static int pcf8575_gpio_probe(struct udevice  *dev)
+{
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	debug("%s GPIO controller with %d gpios probed\n",
+	      uc_priv->bank_name, uc_priv->gpio_count);
+
+	return 0;
+}
+
+static const struct dm_gpio_ops pcf8575_gpio_ops = {
+	.direction_input	= pcf8575_direction_input,
+	.direction_output	= pcf8575_direction_output,
+	.get_value		= pcf8575_get_value,
+	.set_value		= pcf8575_set_value,
+};
+
+static const struct udevice_id pcf8575_gpio_ids[] = {
+	{ .compatible = "nxp,pcf8575" },
+	{ .compatible = "ti,pcf8575" },
+	{ }
+};
+
+U_BOOT_DRIVER(gpio_pcf8575) = {
+	.name	= "gpio_pcf8575",
+	.id	= UCLASS_GPIO,
+	.ops	= &pcf8575_gpio_ops,
+	.of_match = pcf8575_gpio_ids,
+	.ofdata_to_platdata = pcf8575_ofdata_platdata,
+	.probe	= pcf8575_gpio_probe,
+	.platdata_auto_alloc_size = sizeof(struct pcf8575_chip),
+};
diff --git a/drivers/i2c/i2c-uclass-compat.c b/drivers/i2c/i2c-uclass-compat.c
index 5606d1f..de78db6 100644
--- a/drivers/i2c/i2c-uclass-compat.c
+++ b/drivers/i2c/i2c-uclass-compat.c
@@ -9,7 +9,7 @@
 #include <errno.h>
 #include <i2c.h>
 
-static int cur_busnum;
+static int cur_busnum __attribute__((section(".data")));
 
 static int i2c_compat_get_device(uint chip_addr, int alen,
 				 struct udevice **devp)
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index 2ce4ec6..774b021 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -22,6 +22,7 @@
 #include <netdev.h>
 #include <cpsw.h>
 #include <asm/errno.h>
+#include <asm/gpio.h>
 #include <asm/io.h>
 #include <phy.h>
 #include <asm/arch/cpu.h>
@@ -1152,12 +1153,14 @@
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 	struct cpsw_priv *priv = dev_get_priv(dev);
+	struct gpio_desc *mode_gpios;
 	const char *phy_mode;
 	const void *fdt = gd->fdt_blob;
 	int node = dev->of_offset;
 	int subnode;
 	int slave_index = 0;
 	int active_slave;
+	int num_mode_gpios;
 	int ret;
 
 	pdata->iobase = dev_get_addr(dev);
@@ -1203,6 +1206,15 @@
 		return -ENOENT;
 	}
 
+	num_mode_gpios = gpio_get_list_count(dev, "mode-gpios");
+	if (num_mode_gpios > 0) {
+		mode_gpios = malloc(sizeof(struct gpio_desc) *
+				    num_mode_gpios);
+		gpio_request_list_by_name(dev, "mode-gpios", mode_gpios,
+					  num_mode_gpios, GPIOD_IS_OUT);
+		free(mode_gpios);
+	}
+
 	active_slave = fdtdec_get_int(fdt, node, "active_slave", 0);
 	priv->data.active_slave = active_slave;
 
diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c
index 6b28df0..e41b7d1 100644
--- a/drivers/net/keystone_net.c
+++ b/drivers/net/keystone_net.c
@@ -11,6 +11,7 @@
 #include <console.h>
 
 #include <dm.h>
+#include <dm/lists.h>
 
 #include <net.h>
 #include <phy.h>
@@ -765,6 +766,8 @@
 	hw_config_streaming_switch();
 
 	if (priv->has_mdio) {
+		keystone2_mdio_reset(priv->mdio_bus);
+
 		phy_startup(priv->phydev);
 		if (priv->phydev->link == 0) {
 			error("phy startup failed\n");
@@ -906,27 +909,38 @@
 		pll_pa_clk_sel();
 
 
-	priv->net_rx_buffs.buff_ptr = rx_buffs,
-	priv->net_rx_buffs.num_buffs = RX_BUFF_NUMS,
-	priv->net_rx_buffs.buff_len = RX_BUFF_LEN,
+	priv->net_rx_buffs.buff_ptr = rx_buffs;
+	priv->net_rx_buffs.num_buffs = RX_BUFF_NUMS;
+	priv->net_rx_buffs.buff_len = RX_BUFF_LEN;
 
-	/* Register MDIO bus */
-	mdio_bus = mdio_alloc();
-	if (!mdio_bus) {
-		error("MDIO alloc failed\n");
-		return -ENOMEM;
-	}
-	priv->mdio_bus = mdio_bus;
-	mdio_bus->read	= keystone2_mdio_read;
-	mdio_bus->write	= keystone2_mdio_write;
-	mdio_bus->reset	= keystone2_mdio_reset;
-	mdio_bus->priv	= priv->mdio_base;
-	sprintf(mdio_bus->name, "ethernet-mdio");
+	if (priv->slave_port == 1) {
+		/*
+		 * Register MDIO bus for slave 0 only, other slave have
+		 * to re-use the same
+		 */
+		mdio_bus = mdio_alloc();
+		if (!mdio_bus) {
+			error("MDIO alloc failed\n");
+			return -ENOMEM;
+		}
+		priv->mdio_bus = mdio_bus;
+		mdio_bus->read	= keystone2_mdio_read;
+		mdio_bus->write	= keystone2_mdio_write;
+		mdio_bus->reset	= keystone2_mdio_reset;
+		mdio_bus->priv	= priv->mdio_base;
+		sprintf(mdio_bus->name, "ethernet-mdio");
 
-	ret = mdio_register(mdio_bus);
-	if (ret) {
-		error("MDIO bus register failed\n");
-		return ret;
+		ret = mdio_register(mdio_bus);
+		if (ret) {
+			error("MDIO bus register failed\n");
+			return ret;
+		}
+	} else {
+		/* Get the MDIO bus from slave 0 device */
+		struct ks2_eth_priv *parent_priv;
+
+		parent_priv = dev_get_priv(dev->parent);
+		priv->mdio_bus = parent_priv->mdio_bus;
 	}
 
 #ifndef CONFIG_SOC_K2G
@@ -935,8 +949,11 @@
 
 	priv->netcp_pktdma = &netcp_pktdma;
 
-	priv->phydev = phy_connect(mdio_bus, priv->phy_addr, dev, priv->phy_if);
-	phy_config(priv->phydev);
+	if (priv->has_mdio) {
+		priv->phydev = phy_connect(priv->mdio_bus, priv->phy_addr,
+					   dev, priv->phy_if);
+		phy_config(priv->phydev);
+	}
 
 	return 0;
 }
@@ -962,39 +979,103 @@
 	.write_hwaddr		= ks2_eth_write_hwaddr,
 };
 
-
-static int ks2_eth_ofdata_to_platdata(struct udevice *dev)
+static int ks2_eth_bind_slaves(struct udevice *dev, int gbe, int *gbe_0)
 {
-	struct ks2_eth_priv *priv = dev_get_priv(dev);
-	struct eth_pdata *pdata = dev_get_platdata(dev);
 	const void *fdt = gd->fdt_blob;
+	struct udevice *sl_dev;
 	int interfaces;
-	int interface_0;
-	int netcp_gbe_0;
-	int phy;
+	int sec_slave;
+	int slave;
+	int ret;
+	char *slave_name;
+
+	interfaces = fdt_subnode_offset(fdt, gbe, "interfaces");
+	fdt_for_each_subnode(fdt, slave, interfaces) {
+		int slave_no;
+
+		slave_no = fdtdec_get_int(fdt, slave, "slave-port", -ENOENT);
+		if (slave_no == -ENOENT)
+			continue;
+
+		if (slave_no == 0) {
+			/* This is the current eth device */
+			*gbe_0 = slave;
+		} else {
+			/* Slave devices to be registered */
+			slave_name = malloc(20);
+			snprintf(slave_name, 20, "netcp@slave-%d", slave_no);
+			ret = device_bind_driver_to_node(dev, "eth_ks2_sl",
+							 slave_name, slave,
+							 &sl_dev);
+			if (ret) {
+				error("ks2_net - not able to bind slave interfaces\n");
+				return ret;
+			}
+		}
+	}
+
+	sec_slave = fdt_subnode_offset(fdt, gbe, "secondary-slave-ports");
+	fdt_for_each_subnode(fdt, slave, sec_slave) {
+		int slave_no;
+
+		slave_no = fdtdec_get_int(fdt, slave, "slave-port", -ENOENT);
+		if (slave_no == -ENOENT)
+			continue;
+
+		/* Slave devices to be registered */
+		slave_name = malloc(20);
+		snprintf(slave_name, 20, "netcp@slave-%d", slave_no);
+		ret = device_bind_driver_to_node(dev, "eth_ks2_sl", slave_name,
+						 slave, &sl_dev);
+		if (ret) {
+			error("ks2_net - not able to bind slave interfaces\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int ks2_eth_parse_slave_interface(int netcp, int slave,
+					 struct ks2_eth_priv *priv,
+					 struct eth_pdata *pdata)
+{
+	const void *fdt = gd->fdt_blob;
 	int mdio;
-	u32 dma_channel[6];
+	int phy;
+	int dma_count;
+	u32 dma_channel[8];
 
-	interfaces = fdt_subnode_offset(fdt, dev->of_offset,
-					"netcp-interfaces");
-	interface_0 = fdt_subnode_offset(fdt, interfaces, "interface-0");
+	priv->slave_port = fdtdec_get_int(fdt, slave, "slave-port", -1);
+	priv->net_rx_buffs.rx_flow = priv->slave_port * 8;
 
-	netcp_gbe_0 = fdtdec_lookup_phandle(fdt, interface_0, "netcp-gbe");
-	priv->link_type = fdtdec_get_int(fdt, netcp_gbe_0,
-					 "link-interface", -1);
-	priv->slave_port = fdtdec_get_int(fdt, netcp_gbe_0, "slave-port", -1);
 	/* U-Boot slave port number starts with 1 instead of 0 */
 	priv->slave_port += 1;
 
-	phy = fdtdec_lookup_phandle(fdt, netcp_gbe_0, "phy-handle");
-	priv->phy_addr = fdtdec_get_int(fdt, phy, "reg", -1);
+	dma_count = fdtdec_get_int_array_count(fdt, netcp,
+					       "ti,navigator-dmas",
+					       dma_channel, 8);
 
-	mdio = fdt_parent_offset(fdt, phy);
-	if (mdio < 0) {
-		error("mdio dt not found\n");
-		return -ENODEV;
+	if (dma_count > (2 * priv->slave_port)) {
+		int dma_idx;
+
+		dma_idx = priv->slave_port * 2 - 1;
+		priv->net_rx_buffs.rx_flow = dma_channel[dma_idx];
 	}
-	priv->mdio_base = (void *)fdtdec_get_addr(fdt, mdio, "reg");
+
+	priv->link_type = fdtdec_get_int(fdt, slave, "link-interface", -1);
+
+	phy = fdtdec_lookup_phandle(fdt, slave, "phy-handle");
+	if (phy >= 0) {
+		priv->phy_addr = fdtdec_get_int(fdt, phy, "reg", -1);
+
+		mdio = fdt_parent_offset(fdt, phy);
+		if (mdio < 0) {
+			error("mdio dt not found\n");
+			return -ENODEV;
+		}
+		priv->mdio_base = (void *)fdtdec_get_addr(fdt, mdio, "reg");
+	}
 
 	if (priv->link_type == LINK_TYPE_MAC_TO_PHY_MODE) {
 		priv->phy_if = PHY_INTERFACE_MODE_SGMII;
@@ -1002,11 +1083,51 @@
 		priv->sgmii_link_type = SGMII_LINK_MAC_PHY;
 		priv->has_mdio = true;
 	}
-	pdata->iobase = dev_get_addr(dev);
 
-	fdtdec_get_int_array(fdt, dev->of_offset, "ti,navigator-dmas",
-			     dma_channel, 6);
-	priv->net_rx_buffs.rx_flow = dma_channel[1];
+	return 0;
+}
+
+static int ks2_sl_eth_ofdata_to_platdata(struct udevice *dev)
+{
+	struct ks2_eth_priv *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	const void *fdt = gd->fdt_blob;
+	int slave = dev->of_offset;
+	int interfaces;
+	int gbe;
+	int netcp_devices;
+	int netcp;
+
+	interfaces = fdt_parent_offset(fdt, slave);
+	gbe = fdt_parent_offset(fdt, interfaces);
+	netcp_devices = fdt_parent_offset(fdt, gbe);
+	netcp = fdt_parent_offset(fdt, netcp_devices);
+
+	ks2_eth_parse_slave_interface(netcp, slave, priv, pdata);
+
+	pdata->iobase = fdtdec_get_addr(fdt, netcp, "reg");
+
+	return 0;
+}
+
+static int ks2_eth_ofdata_to_platdata(struct udevice *dev)
+{
+	struct ks2_eth_priv *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	const void *fdt = gd->fdt_blob;
+	int gbe_0 = -ENODEV;
+	int netcp_devices;
+	int gbe;
+
+	netcp_devices = fdt_subnode_offset(fdt, dev->of_offset,
+					   "netcp-devices");
+	gbe = fdt_subnode_offset(fdt, netcp_devices, "gbe");
+
+	ks2_eth_bind_slaves(dev, gbe, &gbe_0);
+
+	ks2_eth_parse_slave_interface(dev->of_offset, gbe_0, priv, pdata);
+
+	pdata->iobase = dev_get_addr(dev);
 
 	return 0;
 }
@@ -1016,6 +1137,17 @@
 	{ }
 };
 
+U_BOOT_DRIVER(eth_ks2_slave) = {
+	.name	= "eth_ks2_sl",
+	.id	= UCLASS_ETH,
+	.ofdata_to_platdata = ks2_sl_eth_ofdata_to_platdata,
+	.probe	= ks2_eth_probe,
+	.remove	= ks2_eth_remove,
+	.ops	= &ks2_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct ks2_eth_priv),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
 
 U_BOOT_DRIVER(eth_ks2) = {
 	.name	= "eth_ks2",
diff --git a/include/configs/a3m071.h b/include/configs/a3m071.h
index 8f17dd1..ab2477c 100644
--- a/include/configs/a3m071.h
+++ b/include/configs/a3m071.h
@@ -334,6 +334,7 @@
 
 #define CONFIG_SYS_OS_BASE	0xfc200000
 #define CONFIG_SYS_FDT_BASE	0xfc1e0000
+#define CONFIG_SYS_FDT_SIZE	(16<<10)
 
 #define	CONFIG_EXTRA_ENV_SETTINGS					\
 	"netdev=eth0\0"							\
diff --git a/include/configs/microblaze-generic.h b/include/configs/microblaze-generic.h
index 047e756..e5bf700 100644
--- a/include/configs/microblaze-generic.h
+++ b/include/configs/microblaze-generic.h
@@ -305,6 +305,7 @@
 					 0x60000)
 #define CONFIG_SYS_FDT_BASE		(CONFIG_SYS_FLASH_BASE + \
 					 0x40000)
+#define CONFIG_SYS_FDT_SIZE		(16<<10)
 #define CONFIG_SYS_SPL_ARGS_ADDR	(CONFIG_SYS_TEXT_BASE + \
 					 0x1000000)
 
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index c434c92..d8ddcc9 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -31,6 +31,8 @@
 	struct efi_device_path_file_path *dp;
 	/* Offset into disk for simple partitions */
 	lbaint_t offset;
+	/* Internal block device */
+	const struct blk_desc *desc;
 };
 
 static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
@@ -78,8 +80,7 @@
 	unsigned long n;
 
 	diskobj = container_of(this, struct efi_disk_obj, ops);
-	if (!(desc = blk_get_dev(diskobj->ifname, diskobj->dev_index)))
-		return EFI_EXIT(EFI_DEVICE_ERROR);
+	desc = (struct blk_desc *) diskobj->desc;
 	blksz = desc->blksz;
 	blocks = buffer_size / blksz;
 	lba += diskobj->offset;
@@ -201,6 +202,10 @@
 	struct efi_device_path_file_path *dp;
 	int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2);
 
+	/* Don't add empty devices */
+	if (!desc->lba)
+		return;
+
 	diskobj = calloc(1, objlen);
 
 	/* Fill in object data */
@@ -213,13 +218,14 @@
 	diskobj->ifname = if_typename;
 	diskobj->dev_index = dev_index;
 	diskobj->offset = offset;
+	diskobj->desc = desc;
 
 	/* Fill in EFI IO Media info (for read/write callbacks) */
 	diskobj->media.removable_media = desc->removable;
 	diskobj->media.media_present = 1;
 	diskobj->media.block_size = desc->blksz;
 	diskobj->media.io_align = desc->blksz;
-	diskobj->media.last_block = desc->lba;
+	diskobj->media.last_block = desc->lba - offset;
 	diskobj->ops.media = &diskobj->media;
 
 	/* Fill in device path */
@@ -240,7 +246,8 @@
 
 static int efi_disk_create_eltorito(struct blk_desc *desc,
 				    const char *if_typename,
-				    int diskid)
+				    int diskid,
+				    const char *pdevname)
 {
 	int disks = 0;
 #ifdef CONFIG_ISO_PARTITION
@@ -252,8 +259,8 @@
 		return 0;
 
 	while (!part_get_info(desc, part, &info)) {
-		snprintf(devname, sizeof(devname), "%s%d:%d", if_typename,
-			 diskid, part);
+		snprintf(devname, sizeof(devname), "%s:%d", pdevname,
+			 part);
 		efi_disk_add_dev(devname, if_typename, desc, diskid,
 				 info.start);
 		part++;
@@ -296,7 +303,7 @@
 		* so let's create them here
 		*/
 		disks += efi_disk_create_eltorito(desc, if_typename,
-						  desc->devnum);
+						  desc->devnum, dev->name);
 	}
 #else
 	int i, if_type;
@@ -331,7 +338,8 @@
 			 * El Torito images show up as block devices
 			 * in an EFI world, so let's create them here
 			 */
-			disks += efi_disk_create_eltorito(desc, if_typename, i);
+			disks += efi_disk_create_eltorito(desc, if_typename,
+							  i, devname);
 		}
 	}
 #endif
diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c
index 1aa43ab..30ac759 100644
--- a/lib/tiny-printf.c
+++ b/lib/tiny-printf.c
@@ -13,29 +13,33 @@
 #include <stdarg.h>
 #include <serial.h>
 
-/*
- * This code in here may execute before the DRAM is initialised, so
- * we should make sure that it doesn't touch BSS, which some boards
- * put in DRAM.
- */
-static char *bf __attribute__ ((section(".data")));
-static char zs __attribute__ ((section(".data")));
+struct printf_info {
+	char *bf;	/* Digit buffer */
+	char zs;	/* non-zero if a digit has been written */
+	char *outstr;	/* Next output position for sprintf() */
 
-/* Current position in sprintf() output string */
-static char *outstr __attribute__ ((section(".data")));
+	/* Output a character */
+	void (*putc)(struct printf_info *info, char ch);
+};
 
-static void out(char c)
+void putc_normal(struct printf_info *info, char ch)
 {
-	*bf++ = c;
+	putc(ch);
 }
 
-static void out_dgt(char dgt)
+static void out(struct printf_info *info, char c)
 {
-	out(dgt + (dgt < 10 ? '0' : 'a' - 10));
-	zs = 1;
+	*info->bf++ = c;
 }
 
-static void div_out(unsigned int *num, unsigned int div)
+static void out_dgt(struct printf_info *info, char dgt)
+{
+	out(info, dgt + (dgt < 10 ? '0' : 'a' - 10));
+	info->zs = 1;
+}
+
+static void div_out(struct printf_info *info, unsigned int *num,
+		    unsigned int div)
 {
 	unsigned char dgt = 0;
 
@@ -44,11 +48,11 @@
 		dgt++;
 	}
 
-	if (zs || dgt > 0)
-		out_dgt(dgt);
+	if (info->zs || dgt > 0)
+		out_dgt(info, dgt);
 }
 
-int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch))
+int _vprintf(struct printf_info *info, const char *fmt, va_list va)
 {
 	char ch;
 	char *p;
@@ -58,7 +62,7 @@
 
 	while ((ch = *(fmt++))) {
 		if (ch != '%') {
-			putc(ch);
+			info->putc(info, ch);
 		} else {
 			bool lz = false;
 			int width = 0;
@@ -76,9 +80,9 @@
 					ch = *fmt++;
 				}
 			}
-			bf = buf;
-			p = bf;
-			zs = 0;
+			info->bf = buf;
+			p = info->bf;
+			info->zs = 0;
 
 			switch (ch) {
 			case '\0':
@@ -88,45 +92,45 @@
 				num = va_arg(va, unsigned int);
 				if (ch == 'd' && (int)num < 0) {
 					num = -(int)num;
-					out('-');
+					out(info, '-');
 				}
 				if (!num) {
-					out_dgt(0);
+					out_dgt(info, 0);
 				} else {
 					for (div = 1000000000; div; div /= 10)
-						div_out(&num, div);
+						div_out(info, &num, div);
 				}
 				break;
 			case 'x':
 				num = va_arg(va, unsigned int);
 				if (!num) {
-					out_dgt(0);
+					out_dgt(info, 0);
 				} else {
 					for (div = 0x10000000; div; div /= 0x10)
-						div_out(&num, div);
+						div_out(info, &num, div);
 				}
 				break;
 			case 'c':
-				out((char)(va_arg(va, int)));
+				out(info, (char)(va_arg(va, int)));
 				break;
 			case 's':
 				p = va_arg(va, char*);
 				break;
 			case '%':
-				out('%');
+				out(info, '%');
 			default:
 				break;
 			}
 
-			*bf = 0;
-			bf = p;
-			while (*bf++ && width > 0)
+			*info->bf = 0;
+			info->bf = p;
+			while (*info->bf++ && width > 0)
 				width--;
 			while (width-- > 0)
-				putc(lz ? '0' : ' ');
+				info->putc(info, lz ? '0' : ' ');
 			if (p) {
 				while ((ch = *p++))
-					putc(ch);
+					info->putc(info, ch);
 			}
 		}
 	}
@@ -137,36 +141,44 @@
 
 int vprintf(const char *fmt, va_list va)
 {
-	return _vprintf(fmt, va, putc);
+	struct printf_info info;
+
+	info.putc = putc_normal;
+	return _vprintf(&info, fmt, va);
 }
 
 int printf(const char *fmt, ...)
 {
+	struct printf_info info;
+
 	va_list va;
 	int ret;
 
+	info.putc = putc_normal;
 	va_start(va, fmt);
-	ret = _vprintf(fmt, va, putc);
+	ret = _vprintf(&info, fmt, va);
 	va_end(va);
 
 	return ret;
 }
 
-static void putc_outstr(char ch)
+static void putc_outstr(struct printf_info *info, char ch)
 {
-	*outstr++ = ch;
+	*info->outstr++ = ch;
 }
 
 int sprintf(char *buf, const char *fmt, ...)
 {
+	struct printf_info info;
 	va_list va;
 	int ret;
 
 	va_start(va, fmt);
-	outstr = buf;
-	ret = _vprintf(fmt, va, putc_outstr);
+	info.outstr = buf;
+	info.putc = putc_outstr;
+	ret = _vprintf(&info, fmt, va);
 	va_end(va);
-	*outstr = '\0';
+	*info.outstr = '\0';
 
 	return ret;
 }
@@ -174,14 +186,16 @@
 /* Note that size is ignored */
 int snprintf(char *buf, size_t size, const char *fmt, ...)
 {
+	struct printf_info info;
 	va_list va;
 	int ret;
 
 	va_start(va, fmt);
-	outstr = buf;
-	ret = _vprintf(fmt, va, putc_outstr);
+	info.outstr = buf;
+	info.putc = putc_outstr;
+	ret = _vprintf(&info, fmt, va);
 	va_end(va);
-	*outstr = '\0';
+	*info.outstr = '\0';
 
 	return ret;
 }