Merge git://git.denx.de/u-boot-marvell
diff --git a/Makefile b/Makefile
index 9ca0a56..54ef2cd 100644
--- a/Makefile
+++ b/Makefile
@@ -1259,7 +1259,7 @@
 
 spl/u-boot-spl.bin: spl/u-boot-spl
 	@:
-spl/u-boot-spl: tools prepare
+spl/u-boot-spl: tools prepare $(if $(CONFIG_OF_SEPARATE),dts/dt.dtb)
 	$(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
 
 spl/sunxi-spl.bin: spl/u-boot-spl
diff --git a/arch/arm/cpu/u-boot-spl.lds b/arch/arm/cpu/u-boot-spl.lds
index a8be204..c5b4f7c 100644
--- a/arch/arm/cpu/u-boot-spl.lds
+++ b/arch/arm/cpu/u-boot-spl.lds
@@ -32,17 +32,17 @@
 	}
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*_i2c_*)));
-	}
-
-	. = .;
 #ifdef CONFIG_SPL_DM
 	.u_boot_list : {
 		KEEP(*(SORT(.u_boot_list_*_driver_*)));
 		KEEP(*(SORT(.u_boot_list_*_uclass_*)));
 	}
 #endif
+	. = .;
+	.u_boot_list : {
+		KEEP(*(SORT(.u_boot_list*_i2c_*)));
+	}
+
 	. = ALIGN(4);
 
 	__image_copy_end = .;
@@ -66,7 +66,7 @@
 		 . = ALIGN(4);
 		__bss_end = .;
 	}
-
+	__bss_size = __bss_end - __bss_start;
 	.dynsym _image_binary_end : { *(.dynsym) }
 	.dynbss : { *(.dynbss) }
 	.dynstr : { *(.dynstr*) }
diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c
index d2885dc..6444be8 100644
--- a/arch/arm/mach-zynq/clk.c
+++ b/arch/arm/mach-zynq/clk.c
@@ -48,11 +48,11 @@
 struct clk;
 
 /**
- * struct clk_ops:
+ * struct zynq_clk_ops:
  * @set_rate:	Function pointer to set_rate() implementation
  * @get_rate:	Function pointer to get_rate() implementation
  */
-struct clk_ops {
+struct zynq_clk_ops {
 	int (*set_rate)(struct clk *clk, unsigned long rate);
 	unsigned long (*get_rate)(struct clk *clk);
 };
@@ -72,7 +72,7 @@
 	enum zynq_clk	parent;
 	unsigned int	flags;
 	u32		*reg;
-	struct clk_ops	ops;
+	struct zynq_clk_ops	ops;
 };
 #define ZYNQ_CLK_FLAGS_HAS_2_DIVS	1
 
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index e6ddb17..3a7f5a0 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -20,7 +20,7 @@
 unsigned long map_len;
 #endif
 
-void reset_cpu(ulong ignored)
+void sandbox_exit(void)
 {
 	/* Do this here while it still has an effect */
 	os_fd_restore();
@@ -34,13 +34,6 @@
 	os_exit(0);
 }
 
-int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-	reset_cpu(0);
-
-	return 0;
-}
-
 /* delay x useconds */
 void __udelay(unsigned long usec)
 {
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index cae731c..7e5d03e 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -345,6 +345,10 @@
 	state->ram_buf = os_malloc(state->ram_size);
 	assert(state->ram_buf);
 
+	/* No reset yet, so mark it as such. Always allow power reset */
+	state->last_reset = RESET_COUNT;
+	state->reset_allowed[RESET_POWER] = true;
+
 	/*
 	 * Example of how to use GPIOs:
 	 *
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index c25614a..c948df8 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -4,7 +4,7 @@
 	model = "sandbox";
 	compatible = "sandbox";
 	#address-cells = <1>;
-	#size-cells = <0>;
+	#size-cells = <1>;
 
 	aliases {
 		console = &uart0;
@@ -28,7 +28,7 @@
 	};
 
 	a-test {
-		reg = <0>;
+		reg = <0 1>;
 		compatible = "denx,u-boot-fdt-test";
 		ping-expect = <0>;
 		ping-add = <0>;
@@ -41,16 +41,16 @@
 	};
 
 	junk {
-		reg = <1>;
+		reg = <1 1>;
 		compatible = "not,compatible";
 	};
 
 	no-compatible {
-		reg = <2>;
+		reg = <2 1>;
 	};
 
 	b-test {
-		reg = <3>;
+		reg = <3 1>;
 		compatible = "denx,u-boot-fdt-test";
 		ping-expect = <3>;
 		ping-add = <3>;
@@ -60,7 +60,7 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "denx,u-boot-test-bus";
-		reg = <3>;
+		reg = <3 1>;
 		ping-expect = <4>;
 		ping-add = <4>;
 		c-test@5 {
@@ -84,14 +84,14 @@
 	};
 
 	d-test {
-		reg = <3>;
+		reg = <3 1>;
 		ping-expect = <6>;
 		ping-add = <6>;
 		compatible = "google,another-fdt-test";
 	};
 
 	e-test {
-		reg = <3>;
+		reg = <3 1>;
 		ping-expect = <6>;
 		ping-add = <6>;
 		compatible = "google,another-fdt-test";
@@ -105,6 +105,10 @@
 		compatible = "denx,u-boot-fdt-test";
 	};
 
+	clk@0 {
+		compatible = "sandbox,clk";
+	};
+
 	eth@10002000 {
 		compatible = "sandbox,eth";
 		reg = <0x10002000 0x1000>;
@@ -142,7 +146,7 @@
 	i2c@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		reg = <0>;
+		reg = <0 1>;
 		compatible = "sandbox,i2c";
 		clock-frequency = <100000>;
 		eeprom@2c {
@@ -176,6 +180,24 @@
 		};
 	};
 
+	leds {
+		compatible = "gpio-leds";
+
+		iracibble {
+			gpios = <&gpio_a 1 0>;
+			label = "sandbox:red";
+		};
+
+		martinet {
+			gpios = <&gpio_a 2 0>;
+			label = "sandbox:green";
+		};
+	};
+
+	mmc {
+		compatible = "sandbox,mmc";
+	};
+
 	pci: pci-controller {
 		compatible = "sandbox,pci";
 		device_type = "pci";
@@ -192,10 +214,22 @@
 		};
 	};
 
+	ram {
+		compatible = "sandbox,ram";
+	};
+
+	reset@0 {
+		compatible = "sandbox,warm-reset";
+	};
+
+	reset@1 {
+		compatible = "sandbox,reset";
+	};
+
 	spi@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		reg = <0>;
+		reg = <0 1>;
 		compatible = "sandbox,spi";
 		cs-gpios = <0>, <&gpio_a 0>;
 		spi.bin@0 {
@@ -206,6 +240,19 @@
 		};
 	};
 
+	syscon@0 {
+		compatible = "sandbox,syscon0";
+		reg = <0x10 4>;
+	};
+
+	syscon@1 {
+		compatible = "sandbox,syscon1";
+		reg = <0x20 5
+			0x28 6
+			0x30 7
+			0x38 8>;
+	};
+
 	uart0: serial {
 		compatible = "sandbox,serial";
 		u-boot,dm-pre-reloc;
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index a57480a..2bd28f6 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -7,6 +7,7 @@
 #define __SANDBOX_STATE_H
 
 #include <config.h>
+#include <reset.h>
 #include <stdbool.h>
 #include <linux/stringify.h>
 
@@ -59,6 +60,8 @@
 	bool write_state;		/* Write sandbox state on exit */
 	bool ignore_missing_state_on_read;	/* No error if state missing */
 	bool show_lcd;			/* Show LCD on start-up */
+	enum reset_t last_reset;	/* Last reset type */
+	bool reset_allowed[RESET_COUNT];	/* Allowed reset types */
 	enum state_terminal_raw term_raw;	/* Terminal raw/cooked */
 
 	/* Pointer to information for each SPI bus/cs */
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 91a5c79..d3c7851 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -17,6 +17,25 @@
 #define SANDBOX_PCI_CLASS_CODE		PCI_CLASS_CODE_COMM
 #define SANDBOX_PCI_CLASS_SUB_CODE	PCI_CLASS_SUB_CODE_COMM_SERIAL
 
+#define SANDBOX_CLK_RATE		32768
+
+enum {
+	PERIPH_ID_FIRST = 0,
+	PERIPH_ID_SPI = PERIPH_ID_FIRST,
+	PERIPH_ID_I2C,
+	PERIPH_ID_PCI,
+
+	PERIPH_ID_COUNT,
+};
+
+/* System controller driver data */
+enum {
+	SYSCON0		= 32,
+	SYSCON1,
+
+	SYSCON_COUNT
+};
+
 /**
  * sandbox_i2c_set_test_mode() - set test mode for running unit tests
  *
diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h
index da87cc3..2f3c3f9 100644
--- a/arch/sandbox/include/asm/u-boot-sandbox.h
+++ b/arch/sandbox/include/asm/u-boot-sandbox.h
@@ -83,4 +83,7 @@
  */
 int sandbox_read_fdt_from_file(void);
 
+/* Exit sandbox (quit U-Boot) */
+void sandbox_exit(void);
+
 #endif	/* _U_BOOT_SANDBOX_H_ */
diff --git a/arch/x86/include/asm/interrupt.h b/arch/x86/include/asm/interrupt.h
index 0a75f89..00cbe07 100644
--- a/arch/x86/include/asm/interrupt.h
+++ b/arch/x86/include/asm/interrupt.h
@@ -16,10 +16,6 @@
 /* arch/x86/cpu/interrupts.c */
 void set_vector(u8 intnum, void *routine);
 
-/* arch/x86/lib/interrupts.c */
-void disable_irq(int irq);
-void enable_irq(int irq);
-
 /* Architecture specific functions */
 void mask_irq(int irq);
 void unmask_irq(int irq);
diff --git a/common/cmd_tsi148.c b/common/cmd_tsi148.c
index dc488b2..ea96d0f 100644
--- a/common/cmd_tsi148.c
+++ b/common/cmd_tsi148.c
@@ -16,8 +16,8 @@
 
 #include <tsi148.h>
 
-#define PCI_VENDOR PCI_VENDOR_ID_TUNDRA
-#define PCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148
+#define LPCI_VENDOR PCI_VENDOR_ID_TUNDRA
+#define LPCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148
 
 typedef struct _TSI148_DEV TSI148_DEV;
 
@@ -41,7 +41,7 @@
 	pci_dev_t busdevfn;
 	unsigned int val;
 
-	busdevfn = pci_find_device(PCI_VENDOR, PCI_DEVICE, 0);
+	busdevfn = pci_find_device(LPCI_VENDOR, LPCI_DEVICE, 0);
 	if (busdevfn == -1) {
 		puts("Tsi148: No Tundra Tsi148 found!\n");
 		return -1;
@@ -68,7 +68,7 @@
 	/* check mapping */
 	debug("Tsi148: Read via mapping, PCI_ID = %08X\n",
 	      readl(&dev->uregs->pci_id));
-	if (((PCI_DEVICE << 16) | PCI_VENDOR) != readl(&dev->uregs->pci_id)) {
+	if (((LPCI_DEVICE << 16) | LPCI_VENDOR) != readl(&dev->uregs->pci_id)) {
 		printf("Tsi148: Cannot read PCI-ID via Mapping: %08x\n",
 		       readl(&dev->uregs->pci_id));
 		result = -1;
diff --git a/common/cmd_usb.c b/common/cmd_usb.c
index eab55cd..0ade775 100644
--- a/common/cmd_usb.c
+++ b/common/cmd_usb.c
@@ -22,8 +22,8 @@
 #ifdef CONFIG_USB_STORAGE
 static int usb_stor_curr_dev = -1; /* current device */
 #endif
-#ifdef CONFIG_USB_HOST_ETHER
-static int usb_ether_curr_dev = -1; /* current ethernet device */
+#if defined(CONFIG_USB_HOST_ETHER) && !defined(CONFIG_DM_ETH)
+static int __maybe_unused usb_ether_curr_dev = -1; /* current ethernet device */
 #endif
 
 /* some display routines (info command) */
@@ -355,12 +355,12 @@
 #endif
 	/* check if we are the last one */
 #ifdef CONFIG_DM_USB
-	last_child = device_is_last_sibling(dev->dev);
+	/* Not the root of the usb tree? */
+	if (device_get_uclass_id(dev->dev->parent) != UCLASS_USB) {
+		last_child = device_is_last_sibling(dev->dev);
 #else
-	last_child = (dev->parent != NULL);
-#endif
-	if (last_child) {
-#ifndef CONFIG_DM_USB
+	if (dev->parent != NULL) { /* not root? */
+		last_child = 1;
 		for (i = 0; i < dev->parent->maxchild; i++) {
 			/* search for children */
 			if (dev->parent->children[i] == dev) {
@@ -530,11 +530,14 @@
 	/* try to recognize storage devices immediately */
 	usb_stor_curr_dev = usb_stor_scan(1);
 #endif
-#endif
 #ifdef CONFIG_USB_HOST_ETHER
+# ifdef CONFIG_DM_ETH
+#  error "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH"
+# endif
 	/* try to recognize ethernet devices immediately */
 	usb_ether_curr_dev = usb_host_eth_scan(1);
 #endif
+#endif
 #ifdef CONFIG_USB_KEYBOARD
 	drv_usb_kbd_init();
 #endif
@@ -630,12 +633,11 @@
 		     bus;
 		     uclass_next_device(&bus)) {
 			struct usb_device *udev;
-			struct udevice *hub;
+			struct udevice *dev;
 
-			device_find_first_child(bus, &hub);
-			if (device_get_uclass_id(hub) == UCLASS_USB_HUB &&
-			    device_active(hub)) {
-				udev = dev_get_parentdata(hub);
+			device_find_first_child(bus, &dev);
+			if (dev && device_active(dev)) {
+				udev = dev_get_parentdata(dev);
 				usb_show_tree(udev);
 			}
 		}
diff --git a/common/console.c b/common/console.c
index 0058222..ace206c 100644
--- a/common/console.c
+++ b/common/console.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <debug_uart.h>
 #include <stdarg.h>
 #include <iomux.h>
 #include <malloc.h>
@@ -455,11 +456,19 @@
 void putc(const char c)
 {
 #ifdef CONFIG_SANDBOX
+	/* sandbox can send characters to stdout before it has a console */
 	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
 		os_putc(c);
 		return;
 	}
 #endif
+#ifdef CONFIG_DEBUG_UART
+	/* if we don't have a console yet, use the debug UART */
+	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
+		printch(c);
+		return;
+	}
+#endif
 #ifdef CONFIG_SILENT_CONSOLE
 	if (gd->flags & GD_FLG_SILENT)
 		return;
@@ -491,7 +500,18 @@
 		return;
 	}
 #endif
+#ifdef CONFIG_DEBUG_UART
+	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
+		while (*s) {
+			int ch = *s++;
 
+			printch(ch);
+			if (ch == '\n')
+				printch('\r');
+		}
+		return;
+	}
+#endif
 #ifdef CONFIG_SILENT_CONSOLE
 	if (gd->flags & GD_FLG_SILENT)
 		return;
@@ -521,11 +541,6 @@
 	uint i;
 	char printbuffer[CONFIG_SYS_PBSIZE];
 
-#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_PRE_CONSOLE_BUFFER)
-	if (!gd->have_console)
-		return 0;
-#endif
-
 	va_start(args, fmt);
 
 	/* For this to work, printbuffer must be larger than
diff --git a/common/image.c b/common/image.c
index f0f0135..9efacf8 100644
--- a/common/image.c
+++ b/common/image.c
@@ -543,6 +543,15 @@
 }
 #endif
 
+const table_entry_t *get_table_entry(const table_entry_t *table, int id)
+{
+	for (; table->id >= 0; ++table) {
+		if (table->id == id)
+			return table;
+	}
+	return NULL;
+}
+
 /**
  * get_table_entry_name - translate entry id to long name
  * @table: pointer to a translation table for entries of a specific type
@@ -559,15 +568,14 @@
  */
 char *get_table_entry_name(const table_entry_t *table, char *msg, int id)
 {
-	for (; table->id >= 0; ++table) {
-		if (table->id == id)
+	table = get_table_entry(table, id);
+	if (!table)
+		return msg;
 #if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
-			return table->lname;
+	return table->lname;
 #else
-			return table->lname + gd->reloc_off;
+	return table->lname + gd->reloc_off;
 #endif
-	}
-	return (msg);
 }
 
 const char *genimg_get_os_name(uint8_t os)
@@ -586,6 +594,20 @@
 	return (get_table_entry_name(uimage_type, "Unknown Image", type));
 }
 
+const char *genimg_get_type_short_name(uint8_t type)
+{
+	const table_entry_t *table;
+
+	table = get_table_entry(uimage_type, type);
+	if (!table)
+		return "unknown";
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+	return table->sname;
+#else
+	return table->sname + gd->reloc_off;
+#endif
+}
+
 const char *genimg_get_comp_name(uint8_t comp)
 {
 	return (get_table_entry_name(uimage_comp, "Unknown Compression",
@@ -610,34 +632,18 @@
 		const char *table_name, const char *name)
 {
 	const table_entry_t *t;
-#ifdef USE_HOSTCC
-	int first = 1;
 
 	for (t = table; t->id >= 0; ++t) {
-		if (t->sname && strcasecmp(t->sname, name) == 0)
-			return(t->id);
-	}
-
-	fprintf(stderr, "\nInvalid %s Type - valid names are", table_name);
-	for (t = table; t->id >= 0; ++t) {
-		if (t->sname == NULL)
-			continue;
-		fprintf(stderr, "%c %s", (first) ? ':' : ',', t->sname);
-		first = 0;
-	}
-	fprintf(stderr, "\n");
-#else
-	for (t = table; t->id >= 0; ++t) {
 #ifdef CONFIG_NEEDS_MANUAL_RELOC
-		if (t->sname && strcmp(t->sname + gd->reloc_off, name) == 0)
+		if (t->sname && strcasecmp(t->sname + gd->reloc_off, name) == 0)
 #else
-		if (t->sname && strcmp(t->sname, name) == 0)
+		if (t->sname && strcasecmp(t->sname, name) == 0)
 #endif
 			return (t->id);
 	}
 	debug("Invalid %s Type: %s\n", table_name, name);
-#endif /* USE_HOSTCC */
-	return (-1);
+
+	return -1;
 }
 
 int genimg_get_os_id(const char *name)
diff --git a/common/spl/spl.c b/common/spl/spl.c
index aeb0645..94b01da 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -148,18 +148,12 @@
 }
 #endif
 
-void board_init_r(gd_t *dummy1, ulong dummy2)
+int spl_init(void)
 {
-	u32 boot_device;
 	int ret;
 
-	debug(">>spl:board_init_r()\n");
-
-#if defined(CONFIG_SYS_SPL_MALLOC_START)
-	mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
-			CONFIG_SYS_SPL_MALLOC_SIZE);
-	gd->flags |= GD_FLG_FULL_MALLOC_INIT;
-#elif defined(CONFIG_SYS_MALLOC_F_LEN)
+	debug("spl_init()\n");
+#if defined(CONFIG_SYS_MALLOC_F_LEN)
 	gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;
 	gd->malloc_ptr = 0;
 #endif
@@ -168,17 +162,36 @@
 		ret = fdtdec_setup();
 		if (ret) {
 			debug("fdtdec_setup() returned error %d\n", ret);
-			hang();
+			return ret;
 		}
 	}
 	if (IS_ENABLED(CONFIG_SPL_DM)) {
 		ret = dm_init_and_scan(true);
 		if (ret) {
 			debug("dm_init_and_scan() returned error %d\n", ret);
-			hang();
+			return ret;
 		}
 	}
+	gd->flags |= GD_FLG_SPL_INIT;
 
+	return 0;
+}
+
+void board_init_r(gd_t *dummy1, ulong dummy2)
+{
+	u32 boot_device;
+
+	debug(">>spl:board_init_r()\n");
+
+#if defined(CONFIG_SYS_SPL_MALLOC_START)
+	mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
+			CONFIG_SYS_SPL_MALLOC_SIZE);
+	gd->flags |= GD_FLG_FULL_MALLOC_INIT;
+#endif
+	if (!(gd->flags & GD_FLG_SPL_INIT)) {
+		if (spl_init())
+			hang();
+	}
 #ifndef CONFIG_PPC
 	/*
 	 * timer_init() does not exist on PPC systems. The timer is initialized
@@ -285,6 +298,7 @@
 	      gd->malloc_ptr / 1024);
 #endif
 
+	debug("loaded - jumping to U-Boot...");
 	jump_to_image_no_args(&spl_image);
 }
 
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 552f80d..5f1cfbf 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -7,6 +7,7 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 #include <common.h>
+#include <dm.h>
 #include <spl.h>
 #include <linux/compiler.h>
 #include <asm/u-boot.h>
@@ -26,11 +27,14 @@
 
 	/* read image header to find the image size & load address */
 	count = mmc->block_dev.block_read(0, sector, 1, header);
+	debug("read sector %lx, count=%lu\n", sector, count);
 	if (count == 0)
 		goto end;
 
-	if (image_get_magic(header) != IH_MAGIC)
+	if (image_get_magic(header) != IH_MAGIC) {
+		puts("bad magic\n");
 		return -1;
+	}
 
 	spl_parse_image_header(header);
 
@@ -40,7 +44,9 @@
 
 	/* Read the header too to avoid extra memcpy */
 	count = mmc->block_dev.block_read(0, sector, image_size_sectors,
-					  (void *) spl_image.load_addr);
+					  (void *)spl_image.load_addr);
+	debug("read %x sectors to %x\n", image_size_sectors,
+	      spl_image.load_addr);
 
 end:
 	if (count == 0) {
@@ -96,9 +102,18 @@
 {
 	struct mmc *mmc;
 	u32 boot_mode;
-	int err;
+	int err = 0;
 	__maybe_unused int part;
 
+#ifdef CONFIG_DM_MMC
+	struct udevice *dev;
+
+	mmc_initialize(NULL);
+	err = uclass_get_device(UCLASS_MMC, 0, &dev);
+	mmc = NULL;
+	if (!err)
+		mmc = mmc_get_mmc_dev(dev);
+#else
 	mmc_initialize(gd->bd);
 
 	/* We register only one device. So, the dev id is always 0 */
@@ -109,8 +124,11 @@
 #endif
 		hang();
 	}
+#endif
 
-	err = mmc_init(mmc);
+	if (!err)
+		err = mmc_init(mmc);
+
 	if (err) {
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
 		printf("spl: mmc init failed with error: %d\n", err);
diff --git a/common/usb.c b/common/usb.c
index 7ff8ac5..fbaf8ec 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -911,26 +911,24 @@
 }
 #endif /* !CONFIG_DM_USB */
 
-#ifndef CONFIG_DM_USB
-int usb_legacy_port_reset(struct usb_device *hub, int portnr)
+static int usb_hub_port_reset(struct usb_device *dev, struct usb_device *hub)
 {
 	if (hub) {
 		unsigned short portstatus;
 		int err;
 
 		/* reset the port for the second time */
-		err = legacy_hub_port_reset(hub, portnr - 1, &portstatus);
+		err = legacy_hub_port_reset(hub, dev->portnr - 1, &portstatus);
 		if (err < 0) {
-			printf("\n     Couldn't reset port %i\n", portnr);
+			printf("\n     Couldn't reset port %i\n", dev->portnr);
 			return err;
 		}
 	} else {
-		usb_reset_root_port();
+		usb_reset_root_port(dev);
 	}
 
 	return 0;
 }
-#endif
 
 static int get_descriptor_len(struct usb_device *dev, int len, int expect_len)
 {
@@ -1032,7 +1030,7 @@
 }
 
 static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
-			      struct usb_device *parent, int portnr)
+			      struct usb_device *parent)
 {
 	int err;
 
@@ -1050,7 +1048,7 @@
 	err = usb_setup_descriptor(dev, do_read);
 	if (err)
 		return err;
-	err = usb_legacy_port_reset(parent, portnr);
+	err = usb_hub_port_reset(dev, parent);
 	if (err)
 		return err;
 
@@ -1128,7 +1126,7 @@
 }
 
 int usb_setup_device(struct usb_device *dev, bool do_read,
-		     struct usb_device *parent, int portnr)
+		     struct usb_device *parent)
 {
 	int addr;
 	int ret;
@@ -1137,7 +1135,7 @@
 	addr = dev->devnum;
 	dev->devnum = 0;
 
-	ret = usb_prepare_device(dev, addr, do_read, parent, portnr);
+	ret = usb_prepare_device(dev, addr, do_read, parent);
 	if (ret)
 		return ret;
 	ret = usb_select_config(dev);
@@ -1167,7 +1165,7 @@
 #ifdef CONFIG_USB_XHCI
 	do_read = false;
 #endif
-	err = usb_setup_device(dev, do_read, dev->parent, dev->portnr);
+	err = usb_setup_device(dev, do_read, dev->parent);
 	if (err)
 		return err;
 
diff --git a/common/usb_hub.c b/common/usb_hub.c
index be01f4f..f621ddb 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -652,6 +652,6 @@
 	{ }	/* Terminating entry */
 };
 
-USB_DEVICE(usb_generic_hub, hub_id_table);
+U_BOOT_USB_DEVICE(usb_generic_hub, hub_id_table);
 
 #endif
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index e2af67d..0227024 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -540,8 +540,8 @@
 	debug("%s: Probing for keyboard\n", __func__);
 #ifdef CONFIG_DM_USB
 	/*
-	 * TODO: We should add USB_DEVICE() declarations to each USB ethernet
-	 * driver and then most of this file can be removed.
+	 * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB
+	 * keyboard driver and then most of this file can be removed.
 	 */
 	struct udevice *bus;
 	struct uclass *uc;
diff --git a/common/usb_storage.c b/common/usb_storage.c
index cc9b3e3..b978430 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -1442,6 +1442,6 @@
 	{ }		/* Terminating entry */
 };
 
-USB_DEVICE(usb_mass_storage, mass_storage_id_table);
+U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);
 
 #endif
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 598519d..5535746 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -18,6 +18,7 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_SANDBOX=y
 CONFIG_CMD_CROS_EC=y
+CONFIG_CMD_DHRYSTONE=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_SANDBOX=y
 CONFIG_DM_ETH=y
@@ -44,3 +45,10 @@
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_UT_ENV=y
+CONFIG_CLK=y
+CONFIG_RESET=y
+CONFIG_RAM=y
+CONFIG_DM_MMC=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_SYSCON=y
diff --git a/doc/device-tree-bindings/leds/common.txt b/doc/device-tree-bindings/leds/common.txt
new file mode 100644
index 0000000..2d88816
--- /dev/null
+++ b/doc/device-tree-bindings/leds/common.txt
@@ -0,0 +1,23 @@
+Common leds properties.
+
+Optional properties for child nodes:
+- label : The label for this LED.  If omitted, the label is
+  taken from the node name (excluding the unit address).
+
+- linux,default-trigger :  This parameter, if present, is a
+    string defining the trigger assigned to the LED.  Current triggers are:
+     "backlight" - LED will act as a back-light, controlled by the framebuffer
+		   system
+     "default-on" - LED will turn on (but for leds-gpio see "default-state"
+		    property in Documentation/devicetree/bindings/gpio/led.txt)
+     "heartbeat" - LED "double" flashes at a load average based rate
+     "ide-disk" - LED indicates disk activity
+     "timer" - LED flashes at a fixed, configurable rate
+
+Examples:
+
+system-status {
+	label = "Status";
+	linux,default-trigger = "heartbeat";
+	...
+};
diff --git a/doc/device-tree-bindings/leds/leds-gpio.txt b/doc/device-tree-bindings/leds/leds-gpio.txt
new file mode 100644
index 0000000..df1b308
--- /dev/null
+++ b/doc/device-tree-bindings/leds/leds-gpio.txt
@@ -0,0 +1,52 @@
+LEDs connected to GPIO lines
+
+Required properties:
+- compatible : should be "gpio-leds".
+
+Each LED is represented as a sub-node of the gpio-leds device.  Each
+node's name represents the name of the corresponding LED.
+
+LED sub-node properties:
+- gpios :  Should specify the LED's GPIO, see "gpios property" in
+  Documentation/devicetree/bindings/gpio/gpio.txt.  Active low LEDs should be
+  indicated using flags in the GPIO specifier.
+- label :  (optional)
+  see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger :  (optional)
+  see Documentation/devicetree/bindings/leds/common.txt
+- default-state:  (optional) The initial state of the LED.  Valid
+  values are "on", "off", and "keep".  If the LED is already on or off
+  and the default-state property is set the to same value, then no
+  glitch should be produced where the LED momentarily turns off (or
+  on).  The "keep" setting will keep the LED at whatever its current
+  state is, without producing a glitch.  The default is off if this
+  property is not present.
+
+Examples:
+
+leds {
+	compatible = "gpio-leds";
+	hdd {
+		label = "IDE Activity";
+		gpios = <&mcu_pio 0 1>; /* Active low */
+		linux,default-trigger = "ide-disk";
+	};
+
+	fault {
+		gpios = <&mcu_pio 1 0>;
+		/* Keep LED on if BIOS detected hardware fault */
+		default-state = "keep";
+	};
+};
+
+run-control {
+	compatible = "gpio-leds";
+	red {
+		gpios = <&mpc8572 6 0>;
+		default-state = "off";
+	};
+	green {
+		gpios = <&mpc8572 7 0>;
+		default-state = "on";
+	};
+};
diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index f0276b1..b891e84 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -301,6 +301,15 @@
 Platform Data
 -------------
 
+*** Note: platform data is the old way of doing things. It is
+*** basically a C structure which is passed to drivers to tell them about
+*** platform-specific settings like the address of its registers, bus
+*** speed, etc. Device tree is now the preferred way of handling this.
+*** Unless you have a good reason not to use device tree (the main one
+*** being you need serial support in SPL and don't have enough SRAM for
+*** the cut-down device tree and libfdt libraries) you should stay away
+*** from platform data.
+
 Platform data is like Linux platform data, if you are familiar with that.
 It provides the board-specific information to start up a device.
 
@@ -366,8 +375,12 @@
 -----------
 
 While platdata is useful, a more flexible way of providing device data is
-by using device tree. With device tree we replace the above code with the
-following device tree fragment:
+by using device tree. In U-Boot you should use this where possible. Avoid
+sending patches which make use of the U_BOOT_DEVICE() macro unless strictly
+necessary.
+
+With device tree we replace the above code with the following device tree
+fragment:
 
 	red-square {
 		compatible = "demo-shape";
diff --git a/drivers/Kconfig b/drivers/Kconfig
index c7e526c..092bc02 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,7 @@
 menu "Device Drivers"
 
+source "drivers/clk/Kconfig"
+
 source "drivers/core/Kconfig"
 
 source "drivers/cpu/Kconfig"
@@ -20,6 +22,8 @@
 
 source "drivers/input/Kconfig"
 
+source "drivers/led/Kconfig"
+
 source "drivers/serial/Kconfig"
 
 source "drivers/tpm/Kconfig"
@@ -32,6 +36,8 @@
 
 source "drivers/power/Kconfig"
 
+source "drivers/ram/Kconfig"
+
 source "drivers/hwmon/Kconfig"
 
 source "drivers/watchdog/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 405b64b..5a35148 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_CLK) += clk/
 obj-$(CONFIG_DM) += core/
 obj-$(CONFIG_DM_DEMO) += demo/
 obj-$(CONFIG_BIOSEMU) += bios_emulator/
@@ -7,9 +8,11 @@
 obj-y += crypto/
 obj-$(CONFIG_FPGA) += fpga/
 obj-y += hwmon/
+obj-$(CONFIG_LED) += led/
 obj-y += misc/
 obj-y += pcmcia/
 obj-y += dfu/
+obj-$(CONFIG_RAM) += ram/
 obj-y += rtc/
 obj-y += sound/
 obj-y += tpm/
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
new file mode 100644
index 0000000..07eb54c
--- /dev/null
+++ b/drivers/clk/Kconfig
@@ -0,0 +1,19 @@
+config CLK
+	bool "Enable clock driver support"
+	depends on DM
+	help
+	  This allows drivers to be provided for clock generators, including
+	  oscillators and PLLs. Devices can use a common clock API to request
+	  a particular clock rate and check on available clocks. Clocks can
+	  feed into other clocks in a tree structure, with multiplexers to
+	  choose the source for each clock.
+
+config SPL_CLK_SUPPORT
+	bool "Enable clock support in SPL"
+	depends on CLK
+	help
+	  The clock subsystem adds a small amount of overhead to the image.
+	  If this is acceptable and you have a need to use clock drivers in
+	  SPL, enable this option. It might provide a cleaner interface to
+	  setting up clocks within SPL, and allows the same drivers to be
+	  used as U-Boot proper.
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
new file mode 100644
index 0000000..bb89fb9
--- /dev/null
+++ b/drivers/clk/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+obj-$(CONFIG_CLK) += clk-uclass.o
+obj-$(CONFIG_SANDBOX) += clk_sandbox.o
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
new file mode 100644
index 0000000..73dfd7d
--- /dev/null
+++ b/drivers/clk/clk-uclass.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+ulong clk_get_rate(struct udevice *dev)
+{
+	struct clk_ops *ops = clk_get_ops(dev);
+
+	if (!ops->get_rate)
+		return -ENOSYS;
+
+	return ops->get_rate(dev);
+}
+
+ulong clk_set_rate(struct udevice *dev, ulong rate)
+{
+	struct clk_ops *ops = clk_get_ops(dev);
+
+	if (!ops->set_rate)
+		return -ENOSYS;
+
+	return ops->set_rate(dev, rate);
+}
+
+ulong clk_get_periph_rate(struct udevice *dev, int periph)
+{
+	struct clk_ops *ops = clk_get_ops(dev);
+
+	if (!ops->get_periph_rate)
+		return -ENOSYS;
+
+	return ops->get_periph_rate(dev, periph);
+}
+
+ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+{
+	struct clk_ops *ops = clk_get_ops(dev);
+
+	if (!ops->set_periph_rate)
+		return -ENOSYS;
+
+	return ops->set_periph_rate(dev, periph, rate);
+}
+
+UCLASS_DRIVER(clk) = {
+	.id		= UCLASS_CLK,
+	.name		= "clk",
+};
diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c
new file mode 100644
index 0000000..058225a
--- /dev/null
+++ b/drivers/clk/clk_sandbox.c
@@ -0,0 +1,85 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/test.h>
+
+struct sandbox_clk_priv {
+	ulong rate;
+	ulong periph_rate[PERIPH_ID_COUNT];
+};
+
+static ulong sandbox_clk_get_rate(struct udevice *dev)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	return priv->rate;
+}
+
+static ulong sandbox_clk_set_rate(struct udevice *dev, ulong rate)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	if (!rate)
+		return -EINVAL;
+	priv->rate = rate;
+	return 0;
+}
+
+ulong sandbox_get_periph_rate(struct udevice *dev, int periph)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT)
+		return -EINVAL;
+	return priv->periph_rate[periph];
+}
+
+ulong sandbox_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+	ulong old_rate;
+
+	if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT)
+		return -EINVAL;
+	old_rate = priv->periph_rate[periph];
+	priv->periph_rate[periph] = rate;
+
+	return old_rate;
+}
+
+static int sandbox_clk_probe(struct udevice *dev)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	priv->rate = SANDBOX_CLK_RATE;
+
+	return 0;
+}
+
+static struct clk_ops sandbox_clk_ops = {
+	.get_rate	= sandbox_clk_get_rate,
+	.set_rate	= sandbox_clk_set_rate,
+	.get_periph_rate = sandbox_get_periph_rate,
+	.set_periph_rate = sandbox_set_periph_rate,
+};
+
+static const struct udevice_id sandbox_clk_ids[] = {
+	{ .compatible = "sandbox,clk" },
+	{ }
+};
+
+U_BOOT_DRIVER(clk_sandbox) = {
+	.name		= "clk_sandbox",
+	.id		= UCLASS_CLK,
+	.of_match	= sandbox_clk_ids,
+	.ops		= &sandbox_clk_ops,
+	.priv_auto_alloc_size = sizeof(struct sandbox_clk_priv),
+	.probe		= sandbox_clk_probe,
+};
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 2861b43..e40372d 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -38,6 +38,10 @@
 	  device. This is not normally required in SPL, so by default this
 	  option is disabled for SPL.
 
+	  Note that this may have undesirable results in the USB subsystem as
+	  it causes unplugged devices to linger around in the dm-tree, and it
+	  causes USB host controllers to not be stopped when booting the OS.
+
 config DM_STDIO
 	bool "Support stdio registration"
 	depends on DM
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index a3fec38..5c2ead8 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -4,8 +4,11 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-obj-$(CONFIG_DM)	+= device.o lists.o root.o uclass.o util.o
+obj-y	+= device.o lists.o root.o uclass.o util.o
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_OF_CONTROL) += simple-bus.o
 endif
 obj-$(CONFIG_DM_DEVICE_REMOVE)	+= device-remove.o
+obj-$(CONFIG_DM)	+= dump.o
+obj-$(CONFIG_OF_CONTROL)	+= regmap.o
+obj-$(CONFIG_OF_CONTROL)	+= syscon-uclass.o
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 6a16b4f..6b87f86 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -18,16 +18,7 @@
 #include <dm/uclass-internal.h>
 #include <dm/util.h>
 
-/**
- * device_chld_unbind() - Unbind all device's children from the device
- *
- * On error, the function continues to unbind all children, and reports the
- * first error.
- *
- * @dev:	The device that is to be stripped of its children
- * @return 0 on success, -ve on error
- */
-static int device_chld_unbind(struct udevice *dev)
+int device_unbind_children(struct udevice *dev)
 {
 	struct udevice *pos, *n;
 	int ret, saved_ret = 0;
@@ -43,12 +34,7 @@
 	return saved_ret;
 }
 
-/**
- * device_chld_remove() - Stop all device's children
- * @dev:	The device whose children are to be removed
- * @return 0 on success, -ve on error
- */
-static int device_chld_remove(struct udevice *dev)
+int device_remove_children(struct udevice *dev)
 {
 	struct udevice *pos, *n;
 	int ret;
@@ -84,7 +70,7 @@
 			return ret;
 	}
 
-	ret = device_chld_unbind(dev);
+	ret = device_unbind_children(dev);
 	if (ret)
 		return ret;
 
@@ -159,7 +145,7 @@
 	if (ret)
 		return ret;
 
-	ret = device_chld_remove(dev);
+	ret = device_remove_children(dev);
 	if (ret)
 		goto err;
 
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 85fd1fc..51b1b44 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -284,7 +284,6 @@
 			goto fail;
 	}
 
-	dev->flags |= DM_FLAG_ACTIVATED;
 	if (drv->probe) {
 		ret = drv->probe(dev);
 		if (ret) {
@@ -330,7 +329,7 @@
 void *dev_get_parent_platdata(struct udevice *dev)
 {
 	if (!dev) {
-		dm_warn("%s: null device", __func__);
+		dm_warn("%s: null device\n", __func__);
 		return NULL;
 	}
 
@@ -340,7 +339,7 @@
 void *dev_get_uclass_platdata(struct udevice *dev)
 {
 	if (!dev) {
-		dm_warn("%s: null device", __func__);
+		dm_warn("%s: null device\n", __func__);
 		return NULL;
 	}
 
@@ -459,17 +458,42 @@
 	return -ENODEV;
 }
 
-int device_get_child_by_of_offset(struct udevice *parent, int seq,
+int device_get_child_by_of_offset(struct udevice *parent, int node,
 				  struct udevice **devp)
 {
 	struct udevice *dev;
 	int ret;
 
 	*devp = NULL;
-	ret = device_find_child_by_of_offset(parent, seq, &dev);
+	ret = device_find_child_by_of_offset(parent, node, &dev);
 	return device_get_device_tail(dev, ret, devp);
 }
 
+static struct udevice *_device_find_global_by_of_offset(struct udevice *parent,
+							int of_offset)
+{
+	struct udevice *dev, *found;
+
+	if (parent->of_offset == of_offset)
+		return parent;
+
+	list_for_each_entry(dev, &parent->child_head, sibling_node) {
+		found = _device_find_global_by_of_offset(dev, of_offset);
+		if (found)
+			return found;
+	}
+
+	return NULL;
+}
+
+int device_get_global_by_of_offset(int of_offset, struct udevice **devp)
+{
+	struct udevice *dev;
+
+	dev = _device_find_global_by_of_offset(gd->dm_root, of_offset);
+	return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
+}
+
 int device_find_first_child(struct udevice *parent, struct udevice **devp)
 {
 	if (list_empty(&parent->child_head)) {
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
new file mode 100644
index 0000000..fd4596e
--- /dev/null
+++ b/drivers/core/dump.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <dm/root.h>
+
+static void show_devices(struct udevice *dev, int depth, int last_flag)
+{
+	int i, is_last;
+	struct udevice *child;
+	char class_name[12];
+
+	/* print the first 11 characters to not break the tree-format. */
+	strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name));
+	printf(" %-11s [ %c ]    ", class_name,
+	       dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ');
+
+	for (i = depth; i >= 0; i--) {
+		is_last = (last_flag >> i) & 1;
+		if (i) {
+			if (is_last)
+				printf("    ");
+			else
+				printf("|   ");
+		} else {
+			if (is_last)
+				printf("`-- ");
+			else
+				printf("|-- ");
+		}
+	}
+
+	printf("%s\n", dev->name);
+
+	list_for_each_entry(child, &dev->child_head, sibling_node) {
+		is_last = list_is_last(&child->sibling_node, &dev->child_head);
+		show_devices(child, depth + 1, (last_flag << 1) | is_last);
+	}
+}
+
+void dm_dump_all(void)
+{
+	struct udevice *root;
+
+	root = dm_root();
+	if (root) {
+		printf(" Class       Probed   Name\n");
+		printf("----------------------------------------\n");
+		show_devices(root, -1, 0);
+	}
+}
+
+/**
+ * dm_display_line() - Display information about a single device
+ *
+ * Displays a single line of information with an option prefix
+ *
+ * @dev:	Device to display
+ */
+static void dm_display_line(struct udevice *dev)
+{
+	printf("- %c %s @ %08lx",
+	       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
+	       dev->name, (ulong)map_to_sysmem(dev));
+	if (dev->seq != -1 || dev->req_seq != -1)
+		printf(", seq %d, (req %d)", dev->seq, dev->req_seq);
+	puts("\n");
+}
+
+void dm_dump_uclass(void)
+{
+	struct uclass *uc;
+	int ret;
+	int id;
+
+	for (id = 0; id < UCLASS_COUNT; id++) {
+		struct udevice *dev;
+
+		ret = uclass_get(id, &uc);
+		if (ret)
+			continue;
+
+		printf("uclass %d: %s\n", id, uc->uc_drv->name);
+		if (list_empty(&uc->dev_head))
+			continue;
+		list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+			dm_display_line(dev);
+		}
+		puts("\n");
+	}
+}
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 0c49d99..2e52500 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -86,13 +86,13 @@
 
 	drv = lists_driver_lookup_name(drv_name);
 	if (!drv) {
-		printf("Cannot find driver '%s'\n", drv_name);
+		debug("Cannot find driver '%s'\n", drv_name);
 		return -ENOENT;
 	}
 	ret = device_bind(parent, drv, dev_name, NULL, node, devp);
 	if (ret) {
-		printf("Cannot create device named '%s' (err=%d)\n",
-		       dev_name, ret);
+		debug("Cannot create device named '%s' (err=%d)\n",
+		      dev_name, ret);
 		return ret;
 	}
 
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
new file mode 100644
index 0000000..519832f
--- /dev/null
+++ b/drivers/core/regmap.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <regmap.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
+{
+	const void *blob = gd->fdt_blob;
+	struct regmap_range *range;
+	const fdt32_t *cell;
+	struct regmap *map;
+	int count;
+	int addr_len, size_len, both_len;
+	int parent;
+	int len;
+
+	parent = dev->parent->of_offset;
+	addr_len = fdt_address_cells(blob, parent);
+	size_len = fdt_size_cells(blob, parent);
+	both_len = addr_len + size_len;
+
+	cell = fdt_getprop(blob, dev->of_offset, "reg", &len);
+	len /= sizeof(*cell);
+	count = len / both_len;
+	if (!cell || !count)
+		return -EINVAL;
+
+	map = malloc(sizeof(struct regmap));
+	if (!map)
+		return -ENOMEM;
+
+	if (count <= 1) {
+		map->range = &map->base_range;
+	} else {
+		map->range = malloc(count * sizeof(struct regmap_range));
+		if (!map->range) {
+			free(map);
+			return -ENOMEM;
+		}
+	}
+
+	map->base = fdtdec_get_number(cell, addr_len);
+	map->range_count = count;
+
+	for (range = map->range; count > 0;
+	     count--, cell += both_len, range++) {
+		range->start = fdtdec_get_number(cell, addr_len);
+		range->size = fdtdec_get_number(cell + addr_len, size_len);
+	}
+
+	*mapp = map;
+
+	return 0;
+}
+
+void *regmap_get_range(struct regmap *map, unsigned int range_num)
+{
+	struct regmap_range *range;
+
+	if (range_num >= map->range_count)
+		return NULL;
+	range = &map->range[range_num];
+
+	return map_sysmem(range->start, range->size);
+}
+
+int regmap_uninit(struct regmap *map)
+{
+	if (map->range_count > 1)
+		free(map->range);
+	free(map);
+
+	return 0;
+}
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
new file mode 100644
index 0000000..686c320
--- /dev/null
+++ b/drivers/core/syscon-uclass.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <syscon.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/err.h>
+
+struct regmap *syscon_get_regmap(struct udevice *dev)
+{
+	struct syscon_uc_info *priv;
+
+	if (device_get_uclass_id(dev) != UCLASS_SYSCON)
+		return ERR_PTR(-ENOEXEC);
+	priv = dev_get_uclass_priv(dev);
+	return priv->regmap;
+}
+
+static int syscon_pre_probe(struct udevice *dev)
+{
+	struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
+
+	return regmap_init_mem(dev, &priv->regmap);
+}
+
+struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_SYSCON, &uc);
+	if (ret)
+		return ERR_PTR(ret);
+	uclass_foreach_dev(dev, uc) {
+		if (dev->driver_data == driver_data) {
+			struct syscon_uc_info *priv;
+			int ret;
+
+			ret = device_probe(dev);
+			if (ret)
+				return ERR_PTR(ret);
+			priv = dev_get_uclass_priv(dev);
+
+			return priv->regmap;
+		}
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
+void *syscon_get_first_range(ulong driver_data)
+{
+	struct regmap *map;
+
+	map = syscon_get_regmap_by_driver_data(driver_data);
+	if (IS_ERR(map))
+		return map;
+	return regmap_get_range(map, 0);
+}
+
+UCLASS_DRIVER(syscon) = {
+	.id		= UCLASS_SYSCON,
+	.name		= "syscon",
+	.per_device_auto_alloc_size = sizeof(struct syscon_uc_info),
+	.pre_probe = syscon_pre_probe,
+};
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 7de8173..aba9880 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -56,8 +56,8 @@
 	*ucp = NULL;
 	uc_drv = lists_uclass_lookup(id);
 	if (!uc_drv) {
-		dm_warn("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
-			id);
+		debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
+		      id);
 		return -ENOENT;
 	}
 	uc = calloc(1, sizeof(*uc));
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 5864850..67c6374 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -6,13 +6,9 @@
 #
 
 ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_DM_GPIO)		+= gpio-uclass.o
 obj-$(CONFIG_AXP_GPIO)		+= axp_gpio.o
 endif
-/* TODO(sjg@chromium.org): Only tegra supports driver model in SPL */
-ifdef CONFIG_TEGRA_GPIO
 obj-$(CONFIG_DM_GPIO)		+= gpio-uclass.o
-endif
 
 obj-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
 obj-$(CONFIG_INTEL_ICH6_GPIO)	+= intel_ich6_gpio.o
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index bf982b9..4efda31 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -48,8 +48,7 @@
 	return ret ? ret : -ENOENT;
 }
 
-int gpio_lookup_name(const char *name, struct udevice **devp,
-		     unsigned int *offsetp, unsigned int *gpiop)
+int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
 {
 	struct gpio_dev_priv *uc_priv = NULL;
 	struct udevice *dev;
@@ -57,8 +56,6 @@
 	int numeric;
 	int ret;
 
-	if (devp)
-		*devp = NULL;
 	numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1;
 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
 	     dev;
@@ -84,12 +81,33 @@
 	if (!dev)
 		return ret ? ret : -EINVAL;
 
+	desc->dev = dev;
+	desc->offset = offset;
+
+	return 0;
+}
+
+int gpio_lookup_name(const char *name, struct udevice **devp,
+		     unsigned int *offsetp, unsigned int *gpiop)
+{
+	struct gpio_desc desc;
+	int ret;
+
 	if (devp)
-		*devp = dev;
+		*devp = NULL;
+	ret = dm_gpio_lookup_name(name, &desc);
+	if (ret)
+		return ret;
+
+	if (devp)
+		*devp = desc.dev;
 	if (offsetp)
-		*offsetp = offset;
-	if (gpiop)
-		*gpiop = uc_priv->gpio_base + offset;
+		*offsetp = desc.offset;
+	if (gpiop) {
+		struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc.dev);
+
+		*gpiop = uc_priv->gpio_base + desc.offset;
+	}
 
 	return 0;
 }
@@ -109,7 +127,7 @@
 	return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0;
 }
 
-static int dm_gpio_request(struct gpio_desc *desc, const char *label)
+int dm_gpio_request(struct gpio_desc *desc, const char *label)
 {
 	struct udevice *dev = desc->dev;
 	struct gpio_dev_priv *uc_priv;
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig
new file mode 100644
index 0000000..de5feea
--- /dev/null
+++ b/drivers/led/Kconfig
@@ -0,0 +1,26 @@
+config LED
+	bool "Enable LED support"
+	depends on DM
+	help
+	  Many boards have LEDs which can be used to signal status or alerts.
+	  U-Boot provides a uclass API to implement this feature. LED drivers
+	  can provide access to board-specific LEDs. Use of the device tree
+	  for configuration is encouraged.
+
+config SPL_LED_SUPPORT
+	bool "Enable LED support in SPL"
+	depends on LED
+	help
+	  The LED subsystem adds a small amount of overhead to the image.
+	  If this is acceptable and you have a need to use LEDs in SPL,
+	  enable this option. You will need to enable device tree in SPL
+	  for this to work.
+
+config LED_GPIO
+	bool "LED support for GPIO-connected LEDs"
+	depends on LED && DM_GPIO
+	help
+	  Enable support for LEDs which are connected to GPIO lines. These
+	  GPIOs may be on the SoC or some other device which provides GPIOs.
+	  The GPIO driver must used driver model. LEDs are configured using
+	  the device tree.
diff --git a/drivers/led/Makefile b/drivers/led/Makefile
new file mode 100644
index 0000000..990129e
--- /dev/null
+++ b/drivers/led/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_LED) += led-uclass.o
+obj-$(CONFIG_LED_GPIO) += led_gpio.o
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c
new file mode 100644
index 0000000..784ac87
--- /dev/null
+++ b/drivers/led/led-uclass.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <led.h>
+#include <dm/root.h>
+#include <dm/uclass-internal.h>
+
+int led_get_by_label(const char *label, struct udevice **devp)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_LED, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(dev, uc) {
+		struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev);
+
+		/* Ignore the top-level LED node */
+		if (uc_plat->label && !strcmp(label, uc_plat->label))
+			return uclass_get_device_tail(dev, 0, devp);
+	}
+
+	return -ENODEV;
+}
+
+int led_set_on(struct udevice *dev, int on)
+{
+	struct led_ops *ops = led_get_ops(dev);
+
+	if (!ops->set_on)
+		return -ENOSYS;
+
+	return ops->set_on(dev, on);
+}
+
+UCLASS_DRIVER(led) = {
+	.id		= UCLASS_LED,
+	.name		= "led",
+	.per_device_platdata_auto_alloc_size = sizeof(struct led_uclass_plat),
+};
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c
new file mode 100644
index 0000000..cb6e996
--- /dev/null
+++ b/drivers/led/led_gpio.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <led.h>
+#include <asm/gpio.h>
+#include <dm/lists.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct led_gpio_priv {
+	struct gpio_desc gpio;
+};
+
+static int gpio_led_set_on(struct udevice *dev, int on)
+{
+	struct led_gpio_priv *priv = dev_get_priv(dev);
+
+	if (!dm_gpio_is_valid(&priv->gpio))
+		return -EREMOTEIO;
+
+	return dm_gpio_set_value(&priv->gpio, on);
+}
+
+static int led_gpio_probe(struct udevice *dev)
+{
+	struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev);
+	struct led_gpio_priv *priv = dev_get_priv(dev);
+
+	/* Ignore the top-level LED node */
+	if (!uc_plat->label)
+		return 0;
+	return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
+}
+
+static int led_gpio_remove(struct udevice *dev)
+{
+	/*
+	 * The GPIO driver may have already been removed. We will need to
+	 * address this more generally.
+	 */
+#ifndef CONFIG_SANDBOX
+	struct led_gpio_priv *priv = dev_get_priv(dev);
+
+	if (dm_gpio_is_valid(&priv->gpio))
+		dm_gpio_free(dev, &priv->gpio);
+#endif
+
+	return 0;
+}
+
+static int led_gpio_bind(struct udevice *parent)
+{
+	const void *blob = gd->fdt_blob;
+	struct udevice *dev;
+	int node;
+	int ret;
+
+	for (node = fdt_first_subnode(blob, parent->of_offset);
+	     node > 0;
+	     node = fdt_next_subnode(blob, node)) {
+		struct led_uclass_plat *uc_plat;
+		const char *label;
+
+		label = fdt_getprop(blob, node, "label", NULL);
+		if (!label) {
+			debug("%s: node %s has no label\n", __func__,
+			      fdt_get_name(blob, node, NULL));
+			return -EINVAL;
+		}
+		ret = device_bind_driver_to_node(parent, "gpio_led",
+						 fdt_get_name(blob, node, NULL),
+						 node, &dev);
+		if (ret)
+			return ret;
+		uc_plat = dev_get_uclass_platdata(dev);
+		uc_plat->label = label;
+	}
+
+	return 0;
+}
+
+static const struct led_ops gpio_led_ops = {
+	.set_on		= gpio_led_set_on,
+};
+
+static const struct udevice_id led_gpio_ids[] = {
+	{ .compatible = "gpio-leds" },
+	{ }
+};
+
+U_BOOT_DRIVER(led_gpio) = {
+	.name	= "gpio_led",
+	.id	= UCLASS_LED,
+	.of_match = led_gpio_ids,
+	.ops	= &gpio_led_ops,
+	.priv_auto_alloc_size = sizeof(struct led_gpio_priv),
+	.bind	= led_gpio_bind,
+	.probe	= led_gpio_probe,
+	.remove	= led_gpio_remove,
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 64b07a3..3b7f76a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -73,3 +73,12 @@
 	default 0x60
 	help
 	  The I2C address of the PCA9551 LED controller.
+
+config RESET
+	bool "Enable support for reset drivers"
+	depends on DM
+	help
+	  Enable reset drivers which can be used to reset the CPU or board.
+	  Each driver can provide a reset method which will be called to
+	  effect a reset. The uclass will try all available drivers when
+	  reset_walk() is called.
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 120babc..5218b91 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -22,13 +22,16 @@
 obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
 obj-$(CONFIG_NS87308) += ns87308.o
 obj-$(CONFIG_PDSP188x) += pdsp188x.o
+obj-$(CONFIG_SANDBOX) += reset_sandbox.o
 ifdef CONFIG_DM_I2C
 obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
 endif
 obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
 obj-$(CONFIG_STATUS_LED) += status_led.o
 obj-$(CONFIG_SANDBOX) += swap_case.o
+obj-$(CONFIG_SANDBOX) += syscon_sandbox.o
 obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
 obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
 obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
 obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
+obj-$(CONFIG_RESET) += reset-uclass.o
diff --git a/drivers/misc/reset-uclass.c b/drivers/misc/reset-uclass.c
new file mode 100644
index 0000000..fdb5c6f
--- /dev/null
+++ b/drivers/misc/reset-uclass.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <reset.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/err.h>
+
+int reset_request(struct udevice *dev, enum reset_t type)
+{
+	struct reset_ops *ops = reset_get_ops(dev);
+
+	if (!ops->request)
+		return -ENOSYS;
+
+	return ops->request(dev, type);
+}
+
+int reset_walk(enum reset_t type)
+{
+	struct udevice *dev;
+	int ret = -ENOSYS;
+
+	while (ret != -EINPROGRESS && type < RESET_COUNT) {
+		for (uclass_first_device(UCLASS_RESET, &dev);
+		     dev;
+		     uclass_next_device(&dev)) {
+			ret = reset_request(dev, type);
+			if (ret == -EINPROGRESS)
+				break;
+		}
+		type++;
+	}
+
+	return ret;
+}
+
+void reset_walk_halt(enum reset_t type)
+{
+	int ret;
+
+	ret = reset_walk(type);
+
+	/* Wait for the reset to take effect */
+	if (ret == -EINPROGRESS)
+		mdelay(100);
+
+	/* Still no reset? Give up */
+	printf("Reset not supported on this platform\n");
+	hang();
+}
+
+/**
+ * reset_cpu() - calls reset_walk(RESET_WARM)
+ */
+void reset_cpu(ulong addr)
+{
+	reset_walk_halt(RESET_WARM);
+}
+
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	reset_walk_halt(RESET_WARM);
+
+	return 0;
+}
+
+UCLASS_DRIVER(reset) = {
+	.id		= UCLASS_RESET,
+	.name		= "reset",
+};
diff --git a/drivers/misc/reset_sandbox.c b/drivers/misc/reset_sandbox.c
new file mode 100644
index 0000000..917121b
--- /dev/null
+++ b/drivers/misc/reset_sandbox.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset.h>
+#include <asm/state.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_warm_reset_request(struct udevice *dev, enum reset_t type)
+{
+	struct sandbox_state *state = state_get_current();
+
+	switch (type) {
+	case RESET_WARM:
+		state->last_reset = type;
+		break;
+	default:
+		return -ENOSYS;
+	}
+	if (!state->reset_allowed[type])
+		return -EACCES;
+
+	return -EINPROGRESS;
+}
+
+static int sandbox_reset_request(struct udevice *dev, enum reset_t type)
+{
+	struct sandbox_state *state = state_get_current();
+
+	/*
+	 * If we have a device tree, the device we created from platform data
+	 * (see the U_BOOT_DEVICE() declaration below) should not do anything.
+	 * If we are that device, return an error.
+	 */
+	if (gd->fdt_blob && dev->of_offset == -1)
+		return -ENODEV;
+
+	switch (type) {
+	case RESET_COLD:
+		state->last_reset = type;
+		break;
+	case RESET_POWER:
+		state->last_reset = type;
+		if (!state->reset_allowed[type])
+			return -EACCES;
+		sandbox_exit();
+		break;
+	default:
+		return -ENOSYS;
+	}
+	if (!state->reset_allowed[type])
+		return -EACCES;
+
+	return -EINPROGRESS;
+}
+
+static struct reset_ops sandbox_reset_ops = {
+	.request	= sandbox_reset_request,
+};
+
+static const struct udevice_id sandbox_reset_ids[] = {
+	{ .compatible = "sandbox,reset" },
+	{ }
+};
+
+U_BOOT_DRIVER(reset_sandbox) = {
+	.name		= "reset_sandbox",
+	.id		= UCLASS_RESET,
+	.of_match	= sandbox_reset_ids,
+	.ops		= &sandbox_reset_ops,
+};
+
+static struct reset_ops sandbox_warm_reset_ops = {
+	.request	= sandbox_warm_reset_request,
+};
+
+static const struct udevice_id sandbox_warm_reset_ids[] = {
+	{ .compatible = "sandbox,warm-reset" },
+	{ }
+};
+
+U_BOOT_DRIVER(warm_reset_sandbox) = {
+	.name		= "warm_reset_sandbox",
+	.id		= UCLASS_RESET,
+	.of_match	= sandbox_warm_reset_ids,
+	.ops		= &sandbox_warm_reset_ops,
+};
+
+/* This is here in case we don't have a device tree */
+U_BOOT_DEVICE(reset_sandbox_non_fdt) = {
+	.name = "reset_sandbox",
+};
diff --git a/drivers/misc/syscon_sandbox.c b/drivers/misc/syscon_sandbox.c
new file mode 100644
index 0000000..ccfab3e
--- /dev/null
+++ b/drivers/misc/syscon_sandbox.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/lists.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct udevice_id sandbox_syscon_ids[] = {
+	{ .compatible = "sandbox,syscon0", .data = SYSCON0 },
+	{ .compatible = "sandbox,syscon1", .data = SYSCON1 },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_syscon) = {
+	.name	= "sandbox_syscon",
+	.id	= UCLASS_SYSCON,
+	.of_match = sandbox_syscon_ids,
+};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 7ba85a2..3e835f7 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -1,5 +1,15 @@
 menu "MMC Host controller Support"
 
+config DM_MMC
+	bool "Enable MMC controllers using Driver Model"
+	depends on DM
+	help
+	  This enables the MultiMediaCard (MMC) uclass which suports MMC and
+	  Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.)
+	  and non-removable (e.g. eMMC chip) devices are supported. These
+	  appear as block devices in U-Boot and can support filesystems such
+	  as EXT4 and FAT.
+
 config SH_SDHI
 	bool "SuperH/Renesas ARM SoCs on-chip SDHI host controller support"
 	depends on RMOBILE
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index ed73687..286df2f 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -5,6 +5,8 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+obj-$(CONFIG_DM_MMC) += mmc-uclass.o
+
 obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
 obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
 obj-$(CONFIG_BFIN_SDH) += bfin_sdh.o
@@ -29,6 +31,7 @@
 obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
 obj-$(CONFIG_S3C_SDI) += s3c_sdi.o
 obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
+obj-$(CONFIG_SANDBOX) += sandbox_mmc.o
 obj-$(CONFIG_SDHCI) += sdhci.o
 obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
 obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
new file mode 100644
index 0000000..777489f
--- /dev/null
+++ b/drivers/mmc/mmc-uclass.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+struct mmc *mmc_get_mmc_dev(struct udevice *dev)
+{
+	struct mmc_uclass_priv *upriv;
+
+	if (!device_active(dev))
+		return NULL;
+	upriv = dev_get_uclass_priv(dev);
+	return upriv->mmc;
+}
+
+U_BOOT_DRIVER(mmc) = {
+	.name	= "mmc",
+	.id	= UCLASS_MMC,
+};
+
+UCLASS_DRIVER(mmc) = {
+	.id		= UCLASS_MMC,
+	.name		= "mmc",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.per_device_auto_alloc_size = sizeof(struct mmc_uclass_priv),
+};
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 79e6fee..da47037 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -250,14 +250,18 @@
 		return 0;
 	}
 
-	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
+	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
+		debug("%s: Failed to set blocklen\n", __func__);
 		return 0;
+	}
 
 	do {
 		cur = (blocks_todo > mmc->cfg->b_max) ?
 			mmc->cfg->b_max : blocks_todo;
-		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
+		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
+			debug("%s: Failed to read blocks\n", __func__);
 			return 0;
+		}
 		blocks_todo -= cur;
 		start += cur;
 		dst += cur * mmc->read_bl_len;
@@ -1761,8 +1765,10 @@
 	INIT_LIST_HEAD (&mmc_devices);
 	cur_dev_num = 0;
 
+#ifndef CONFIG_DM_MMC
 	if (board_mmc_init(bis) < 0)
 		cpu_mmc_init(bis);
+#endif
 
 #ifndef CONFIG_SPL_BUILD
 	print_mmc_devices(',');
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c
new file mode 100644
index 0000000..f4646a8
--- /dev/null
+++ b/drivers/mmc/sandbox_mmc.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <mmc.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct udevice_id sandbox_mmc_ids[] = {
+	{ .compatible = "sandbox,mmc" },
+	{ }
+};
+
+U_BOOT_DRIVER(warm_mmc_sandbox) = {
+	.name		= "mmc_sandbox",
+	.id		= UCLASS_MMC,
+	.of_match	= sandbox_mmc_ids,
+};
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 645ca64..bcae842 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -528,7 +528,7 @@
 	return _dw_eth_send(priv, packet, length);
 }
 
-static int designware_eth_recv(struct udevice *dev, uchar **packetp)
+static int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct dw_eth_dev *priv = dev_get_priv(dev);
 
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index 958488c..7b6e20f 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -41,10 +41,13 @@
  * Modified to use le32_to_cpu and cpu_to_le32 properly
  */
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <malloc.h>
 #include <net.h>
+#ifndef CONFIG_DM_ETH
 #include <netdev.h>
+#endif
 #include <asm/io.h>
 #include <pci.h>
 
@@ -281,6 +284,8 @@
 	u32 buf_Haddr;
 };
 
+static unsigned char rxdata[RX_BUF_LEN];
+
 #define RTL8169_DESC_SIZE 16
 
 #if ARCH_DMA_MINALIGN > 256
@@ -299,7 +304,8 @@
  * the driver to allocate descriptors from a pool of non-cached memory.
  */
 #if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN
-#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \
+	!defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86)
 #warning cache-line size is larger than descriptor size
 #endif
 #endif
@@ -317,6 +323,7 @@
 DEFINE_ALIGN_BUFFER(u8, rxb, NUM_RX_DESC * RX_BUF_SIZE, RTL8169_ALIGN);
 
 struct rtl8169_private {
+	ulong iobase;
 	void *mmio_addr;	/* memory map physical address */
 	int chipset;
 	unsigned long cur_rx;	/* Index into the Rx descriptor buffer of next Rx pkt. */
@@ -338,9 +345,9 @@
     (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
 
 static struct pci_device_id supported[] = {
-	{PCI_VENDOR_ID_REALTEK, 0x8167},
-	{PCI_VENDOR_ID_REALTEK, 0x8168},
-	{PCI_VENDOR_ID_REALTEK, 0x8169},
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169) },
 	{}
 };
 
@@ -380,7 +387,7 @@
 	return value;
 }
 
-static int rtl8169_init_board(struct eth_device *dev)
+static int rtl8169_init_board(unsigned long dev_iobase, const char *name)
 {
 	int i;
 	u32 tmp;
@@ -388,7 +395,7 @@
 #ifdef DEBUG_RTL8169
 	printf ("%s\n", __FUNCTION__);
 #endif
-	ioaddr = dev->iobase;
+	ioaddr = dev_iobase;
 
 	/* Soft reset the chip. */
 	RTL_W8(ChipCmd, CmdReset);
@@ -412,7 +419,8 @@
 	}
 
 	/* if unknown chip, assume array element #0, original RTL-8169 in this case */
-	printf("PCI device %s: unknown chip version, assuming RTL-8169\n", dev->name);
+	printf("PCI device %s: unknown chip version, assuming RTL-8169\n",
+	       name);
 	printf("PCI device: TxConfig = 0x%lX\n", (unsigned long) RTL_R32(TxConfig));
 	tpc->chipset = 0;
 
@@ -504,7 +512,8 @@
 /**************************************************************************
 RECV - Receive a frame
 ***************************************************************************/
-static int rtl_recv(struct eth_device *dev)
+static int rtl_recv_common(pci_dev_t bdf, unsigned long dev_iobase,
+			   uchar **packetp)
 {
 	/* return true if there's an ethernet packet ready to read */
 	/* nic->packet should contain data on return */
@@ -515,7 +524,7 @@
 #ifdef DEBUG_RTL8169_RX
 	printf ("%s\n", __FUNCTION__);
 #endif
-	ioaddr = dev->iobase;
+	ioaddr = dev_iobase;
 
 	cur_rx = tpc->cur_rx;
 
@@ -523,7 +532,6 @@
 
 	if ((le32_to_cpu(tpc->RxDescArray[cur_rx].status) & OWNbit) == 0) {
 		if (!(le32_to_cpu(tpc->RxDescArray[cur_rx].status) & RxRES)) {
-			unsigned char rxdata[RX_BUF_LEN];
 			length = (int) (le32_to_cpu(tpc->RxDescArray[cur_rx].
 						status) & 0x00001FFF) - 4;
 
@@ -536,17 +544,22 @@
 			else
 				tpc->RxDescArray[cur_rx].status =
 					cpu_to_le32(OWNbit + RX_BUF_SIZE);
-			tpc->RxDescArray[cur_rx].buf_addr =
-				cpu_to_le32(bus_to_phys(tpc->RxBufferRing[cur_rx]));
+			tpc->RxDescArray[cur_rx].buf_addr = cpu_to_le32(
+				pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long)
+				tpc->RxBufferRing[cur_rx]));
 			rtl_flush_rx_desc(&tpc->RxDescArray[cur_rx]);
-
+#ifdef CONFIG_DM_ETH
+			*packetp = rxdata;
+#else
 			net_process_received_packet(rxdata, length);
+#endif
 		} else {
 			puts("Error Rx");
+			length = -EIO;
 		}
 		cur_rx = (cur_rx + 1) % NUM_RX_DESC;
 		tpc->cur_rx = cur_rx;
-		return 1;
+		return length;
 
 	} else {
 		ushort sts = RTL_R8(IntrStatus);
@@ -557,11 +570,26 @@
 	return (0);		/* initially as this is called to flush the input */
 }
 
+#ifdef CONFIG_DM_ETH
+int rtl8169_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct rtl8169_private *priv = dev_get_priv(dev);
+
+	return rtl_recv_common(pci_get_bdf(dev), priv->iobase, packetp);
+}
+#else
+static int rtl_recv(struct eth_device *dev)
+{
+	return rtl_recv_common((pci_dev_t)dev->priv, dev->iobase, NULL);
+}
+#endif /* nCONFIG_DM_ETH */
+
 #define HZ 1000
 /**************************************************************************
 SEND - Transmit a frame
 ***************************************************************************/
-static int rtl_send(struct eth_device *dev, void *packet, int length)
+static int rtl_send_common(pci_dev_t bdf, unsigned long dev_iobase,
+			   void *packet, int length)
 {
 	/* send the packet to destination */
 
@@ -577,7 +605,7 @@
 	printf("sending %d bytes\n", len);
 #endif
 
-	ioaddr = dev->iobase;
+	ioaddr = dev_iobase;
 
 	/* point to the current txb incase multiple tx_rings are used */
 	ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
@@ -588,7 +616,8 @@
 		ptxb[len++] = '\0';
 
 	tpc->TxDescArray[entry].buf_Haddr = 0;
-	tpc->TxDescArray[entry].buf_addr = cpu_to_le32(bus_to_phys(ptxb));
+	tpc->TxDescArray[entry].buf_addr = cpu_to_le32(
+		pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long)ptxb));
 	if (entry != (NUM_TX_DESC - 1)) {
 		tpc->TxDescArray[entry].status =
 			cpu_to_le32((OWNbit | FSbit | LSbit) |
@@ -625,7 +654,23 @@
 	return ret;
 }
 
-static void rtl8169_set_rx_mode(struct eth_device *dev)
+#ifdef CONFIG_DM_ETH
+int rtl8169_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct rtl8169_private *priv = dev_get_priv(dev);
+
+	return rtl_send_common(pci_get_bdf(dev), priv->iobase, packet, length);
+}
+
+#else
+static int rtl_send(struct eth_device *dev, void *packet, int length)
+{
+	return rtl_send_common((pci_dev_t)dev->priv, dev->iobase, packet,
+			       length);
+}
+#endif
+
+static void rtl8169_set_rx_mode(void)
 {
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int rx_mode;
@@ -648,7 +693,7 @@
 	RTL_W32(MAR0 + 4, mc_filter[1]);
 }
 
-static void rtl8169_hw_start(struct eth_device *dev)
+static void rtl8169_hw_start(pci_dev_t bdf)
 {
 	u32 i;
 
@@ -693,9 +738,11 @@
 
 	tpc->cur_rx = 0;
 
-	RTL_W32(TxDescStartAddrLow, bus_to_phys(tpc->TxDescArray));
+	RTL_W32(TxDescStartAddrLow, pci_mem_to_phys(bdf,
+			(pci_addr_t)(unsigned long)tpc->TxDescArray));
 	RTL_W32(TxDescStartAddrHigh, (unsigned long)0);
-	RTL_W32(RxDescStartAddrLow, bus_to_phys(tpc->RxDescArray));
+	RTL_W32(RxDescStartAddrLow, pci_mem_to_phys(
+			bdf, (pci_addr_t)(unsigned long)tpc->RxDescArray));
 	RTL_W32(RxDescStartAddrHigh, (unsigned long)0);
 
 	/* RTL-8169sc/8110sc or later version */
@@ -707,7 +754,7 @@
 
 	RTL_W32(RxMissed, 0);
 
-	rtl8169_set_rx_mode(dev);
+	rtl8169_set_rx_mode();
 
 	/* no early-rx interrupts */
 	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
@@ -717,7 +764,7 @@
 #endif
 }
 
-static void rtl8169_init_ring(struct eth_device *dev)
+static void rtl8169_init_ring(pci_dev_t bdf)
 {
 	int i;
 
@@ -745,8 +792,8 @@
 				cpu_to_le32(OWNbit + RX_BUF_SIZE);
 
 		tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
-		tpc->RxDescArray[i].buf_addr =
-			cpu_to_le32(bus_to_phys(tpc->RxBufferRing[i]));
+		tpc->RxDescArray[i].buf_addr = cpu_to_le32(pci_mem_to_phys(
+			bdf, (pci_addr_t)(unsigned long)tpc->RxBufferRing[i]));
 		rtl_flush_rx_desc(&tpc->RxDescArray[i]);
 	}
 
@@ -755,10 +802,7 @@
 #endif
 }
 
-/**************************************************************************
-RESET - Finish setting up the ethernet interface
-***************************************************************************/
-static int rtl_reset(struct eth_device *dev, bd_t *bis)
+static void rtl8169_common_start(pci_dev_t bdf, unsigned char *enetaddr)
 {
 	int i;
 
@@ -767,30 +811,47 @@
 	printf ("%s\n", __FUNCTION__);
 #endif
 
-	rtl8169_init_ring(dev);
-	rtl8169_hw_start(dev);
+	rtl8169_init_ring(bdf);
+	rtl8169_hw_start(bdf);
 	/* Construct a perfect filter frame with the mac address as first match
 	 * and broadcast for all others */
 	for (i = 0; i < 192; i++)
 		txb[i] = 0xFF;
 
-	txb[0] = dev->enetaddr[0];
-	txb[1] = dev->enetaddr[1];
-	txb[2] = dev->enetaddr[2];
-	txb[3] = dev->enetaddr[3];
-	txb[4] = dev->enetaddr[4];
-	txb[5] = dev->enetaddr[5];
+	txb[0] = enetaddr[0];
+	txb[1] = enetaddr[1];
+	txb[2] = enetaddr[2];
+	txb[3] = enetaddr[3];
+	txb[4] = enetaddr[4];
+	txb[5] = enetaddr[5];
 
 #ifdef DEBUG_RTL8169
 	printf("%s elapsed time : %lu\n", __func__, currticks()-stime);
 #endif
-	return 0;
 }
 
+#ifdef CONFIG_DM_ETH
+static int rtl8169_eth_start(struct udevice *dev)
+{
+	struct eth_pdata *plat = dev_get_platdata(dev);
+
+	rtl8169_common_start(pci_get_bdf(dev), plat->enetaddr);
+
+	return 0;
+}
+#else
 /**************************************************************************
-HALT - Turn off ethernet interface
+RESET - Finish setting up the ethernet interface
 ***************************************************************************/
-static void rtl_halt(struct eth_device *dev)
+static int rtl_reset(struct eth_device *dev, bd_t *bis)
+{
+	rtl8169_common_start((pci_dev_t)dev->priv, dev->enetaddr);
+
+	return 0;
+}
+#endif /* nCONFIG_DM_ETH */
+
+static void rtl_halt_common(unsigned long dev_iobase)
 {
 	int i;
 
@@ -798,7 +859,7 @@
 	printf ("%s\n", __FUNCTION__);
 #endif
 
-	ioaddr = dev->iobase;
+	ioaddr = dev_iobase;
 
 	/* Stop the chip's Tx and Rx DMA processes. */
 	RTL_W8(ChipCmd, 0x00);
@@ -813,13 +874,31 @@
 	}
 }
 
+#ifdef CONFIG_DM_ETH
+void rtl8169_eth_stop(struct udevice *dev)
+{
+	struct rtl8169_private *priv = dev_get_priv(dev);
+
+	rtl_halt_common(priv->iobase);
+}
+#else
+/**************************************************************************
+HALT - Turn off ethernet interface
+***************************************************************************/
+static void rtl_halt(struct eth_device *dev)
+{
+	rtl_halt_common(dev->iobase);
+}
+#endif
+
 /**************************************************************************
 INIT - Look for an adapter, this routine's visible to the outside
 ***************************************************************************/
 
 #define board_found 1
 #define valid_link 0
-static int rtl_init(struct eth_device *dev, bd_t *bis)
+static int rtl_init(unsigned long dev_ioaddr, const char *name,
+		    unsigned char *enetaddr)
 {
 	static int board_idx = -1;
 	int i, rc;
@@ -828,33 +907,32 @@
 #ifdef DEBUG_RTL8169
 	printf ("%s\n", __FUNCTION__);
 #endif
-
-	ioaddr = dev->iobase;
+	ioaddr = dev_ioaddr;
 
 	board_idx++;
 
 	/* point to private storage */
 	tpc = &tpx;
 
-	rc = rtl8169_init_board(dev);
+	rc = rtl8169_init_board(ioaddr, name);
 	if (rc)
 		return rc;
 
 	/* Get MAC address.  FIXME: read EEPROM */
 	for (i = 0; i < MAC_ADDR_LEN; i++)
-		dev->enetaddr[i] = RTL_R8(MAC0 + i);
+		enetaddr[i] = RTL_R8(MAC0 + i);
 
 #ifdef DEBUG_RTL8169
 	printf("chipset = %d\n", tpc->chipset);
 	printf("MAC Address");
 	for (i = 0; i < MAC_ADDR_LEN; i++)
-		printf(":%02x", dev->enetaddr[i]);
+		printf(":%02x", enetaddr[i]);
 	putc('\n');
 #endif
 
 #ifdef DEBUG_RTL8169
 	/* Print out some hardware info */
-	printf("%s: at ioaddr 0x%lx\n", dev->name, ioaddr);
+	printf("%s: at ioaddr 0x%lx\n", name, ioaddr);
 #endif
 
 	/* if TBI is not endbled */
@@ -964,6 +1042,7 @@
 	return 0;
 }
 
+#ifndef CONFIG_DM_ETH
 int rtl8169_initialize(bd_t *bis)
 {
 	pci_dev_t devno;
@@ -1014,7 +1093,7 @@
 		dev->send = rtl_send;
 		dev->recv = rtl_recv;
 
-		err = rtl_init(dev, bis);
+		err = rtl_init(dev->iobase, dev->name, dev->enetaddr);
 		if (err < 0) {
 			printf(pr_fmt("failed to initialize card: %d\n"), err);
 			free(dev);
@@ -1027,3 +1106,62 @@
 	}
 	return card_number;
 }
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int rtl8169_eth_probe(struct udevice *dev)
+{
+	struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
+	struct rtl8169_private *priv = dev_get_priv(dev);
+	struct eth_pdata *plat = dev_get_platdata(dev);
+	u32 iobase;
+	int region;
+	int ret;
+
+	debug("rtl8169: REALTEK RTL8169 @0x%x\n", iobase);
+	switch (pplat->device) {
+	case 0x8168:
+		region = 2;
+		break;
+	default:
+		region = 1;
+		break;
+	}
+	pci_read_config32(pci_get_bdf(dev), PCI_BASE_ADDRESS_0 + region * 4,
+			  &iobase);
+	iobase &= ~0xf;
+	priv->iobase = (int)pci_mem_to_phys(pci_get_bdf(dev), iobase);
+
+	ret = rtl_init(priv->iobase, dev->name, plat->enetaddr);
+	if (ret < 0) {
+		printf(pr_fmt("failed to initialize card: %d\n"), ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct eth_ops rtl8169_eth_ops = {
+	.start	= rtl8169_eth_start,
+	.send	= rtl8169_eth_send,
+	.recv	= rtl8169_eth_recv,
+	.stop	= rtl8169_eth_stop,
+};
+
+static const struct udevice_id rtl8169_eth_ids[] = {
+	{ .compatible = "realtek,rtl8169" },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_rtl8169) = {
+	.name	= "eth_rtl8169",
+	.id	= UCLASS_ETH,
+	.of_match = rtl8169_eth_ids,
+	.probe	= rtl8169_eth_probe,
+	.ops	= &rtl8169_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct rtl8169_private),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+U_BOOT_PCI_DEVICE(eth_rtl8169, supported);
+#endif
diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c
index 45c3b18..5912427 100644
--- a/drivers/net/sandbox-raw.c
+++ b/drivers/net/sandbox-raw.c
@@ -65,7 +65,7 @@
 	return sandbox_eth_raw_os_send(packet, length, priv);
 }
 
-static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp)
+static int sb_eth_raw_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 	struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c
index 4e083d3..6763a24 100644
--- a/drivers/net/sandbox.c
+++ b/drivers/net/sandbox.c
@@ -152,7 +152,7 @@
 	return 0;
 }
 
-static int sb_eth_recv(struct udevice *dev, uchar **packetp)
+static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
 
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
index e939bf2..11cd0ea 100644
--- a/drivers/net/sunxi_emac.c
+++ b/drivers/net/sunxi_emac.c
@@ -527,7 +527,7 @@
 	return _sunxi_emac_eth_send(priv, packet, length);
 }
 
-static int sunxi_emac_eth_recv(struct udevice *dev, uchar **packetp)
+static int sunxi_emac_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct emac_eth_dev *priv = dev_get_priv(dev);
 	int rx_len;
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 5b91fe3..3be76c9 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -30,6 +30,14 @@
 	return dev_get_uclass_priv(bus);
 }
 
+pci_dev_t pci_get_bdf(struct udevice *dev)
+{
+	struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
+	struct udevice *bus = dev->parent;
+
+	return PCI_ADD_BUS(bus->seq, pplat->devfn);
+}
+
 /**
  * pci_get_bus_max() - returns the bus number of the last active bus
  *
@@ -295,19 +303,14 @@
 	for (ret = device_find_first_child(bus, &dev);
 	     !ret && dev;
 	     ret = device_find_next_child(&dev)) {
-		struct pci_child_platdata *pplat;
 		struct pci_controller *ctlr_hose;
-
-		pplat = dev_get_parent_platdata(dev);
 		unsigned int max_bus;
-		pci_dev_t bdf;
 
-		bdf = PCI_ADD_BUS(bus->seq, pplat->devfn);
 		debug("%s: device %s\n", __func__, dev->name);
 
 		/* The root controller has the region information */
 		ctlr_hose = hose->ctlr->uclass_priv;
-		max_bus = pciauto_config_device(ctlr_hose, bdf);
+		max_bus = pciauto_config_device(ctlr_hose, pci_get_bdf(dev));
 		sub_bus = max(sub_bus, max_bus);
 	}
 	debug("%s: done\n", __func__);
@@ -353,6 +356,101 @@
 	return sub_bus;
 }
 
+/**
+ * pci_match_one_device - Tell if a PCI device structure has a matching
+ *                        PCI device id structure
+ * @id: single PCI device id structure to match
+ * @dev: the PCI device structure to match against
+ *
+ * Returns the matching pci_device_id structure or %NULL if there is no match.
+ */
+static bool pci_match_one_id(const struct pci_device_id *id,
+			     const struct pci_device_id *find)
+{
+	if ((id->vendor == PCI_ANY_ID || id->vendor == find->vendor) &&
+	    (id->device == PCI_ANY_ID || id->device == find->device) &&
+	    (id->subvendor == PCI_ANY_ID || id->subvendor == find->subvendor) &&
+	    (id->subdevice == PCI_ANY_ID || id->subdevice == find->subdevice) &&
+	    !((id->class ^ find->class) & id->class_mask))
+		return true;
+
+	return false;
+}
+
+/**
+ * pci_find_and_bind_driver() - Find and bind the right PCI driver
+ *
+ * This only looks at certain fields in the descriptor.
+ */
+static int pci_find_and_bind_driver(struct udevice *parent,
+				    struct pci_device_id *find_id, int devfn,
+				    struct udevice **devp)
+{
+	struct pci_driver_entry *start, *entry;
+	const char *drv;
+	int n_ents;
+	int ret;
+	char name[30], *str;
+
+	*devp = NULL;
+
+	debug("%s: Searching for driver: vendor=%x, device=%x\n", __func__,
+	      find_id->vendor, find_id->device);
+	start = ll_entry_start(struct pci_driver_entry, pci_driver_entry);
+	n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry);
+	for (entry = start; entry != start + n_ents; entry++) {
+		const struct pci_device_id *id;
+		struct udevice *dev;
+		const struct driver *drv;
+
+		for (id = entry->match;
+		     id->vendor || id->subvendor || id->class_mask;
+		     id++) {
+			if (!pci_match_one_id(id, find_id))
+				continue;
+
+			drv = entry->driver;
+			/*
+			 * We could pass the descriptor to the driver as
+			 * platdata (instead of NULL) and allow its bind()
+			 * method to return -ENOENT if it doesn't support this
+			 * device. That way we could continue the search to
+			 * find another driver. For now this doesn't seem
+			 * necesssary, so just bind the first match.
+			 */
+			ret = device_bind(parent, drv, drv->name, NULL, -1,
+					  &dev);
+			if (ret)
+				goto error;
+			debug("%s: Match found: %s\n", __func__, drv->name);
+			dev->driver_data = find_id->driver_data;
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	/* Bind a generic driver so that the device can be used */
+	sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(devfn),
+		PCI_FUNC(devfn));
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	drv = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI ? "pci_bridge_drv" :
+			"pci_generic_drv";
+	ret = device_bind_driver(parent, drv, str, devp);
+	if (ret) {
+		debug("%s: Failed to bind generic driver: %d", __func__, ret);
+		return ret;
+	}
+	debug("%s: No match found: bound generic driver instead\n", __func__);
+
+	return 0;
+
+error:
+	debug("%s: No match found: error %d\n", __func__, ret);
+	return ret;
+}
+
 int pci_bind_bus_devices(struct udevice *bus)
 {
 	ulong vendor, device;
@@ -387,25 +485,33 @@
 		      bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));
 		pci_bus_read_config(bus, devfn, PCI_DEVICE_ID, &device,
 				    PCI_SIZE_16);
-		pci_bus_read_config(bus, devfn, PCI_CLASS_DEVICE, &class,
-				    PCI_SIZE_16);
+		pci_bus_read_config(bus, devfn, PCI_CLASS_REVISION, &class,
+				    PCI_SIZE_32);
+		class >>= 8;
 
 		/* Find this device in the device tree */
 		ret = pci_bus_find_devfn(bus, devfn, &dev);
 
+		/* Search for a driver */
+
 		/* If nothing in the device tree, bind a generic device */
 		if (ret == -ENODEV) {
-			char name[30], *str;
-			const char *drv;
+			struct pci_device_id find_id;
+			ulong val;
 
-			sprintf(name, "pci_%x:%x.%x", bus->seq,
-				PCI_DEV(devfn), PCI_FUNC(devfn));
-			str = strdup(name);
-			if (!str)
-				return -ENOMEM;
-			drv = class == PCI_CLASS_BRIDGE_PCI ?
-				"pci_bridge_drv" : "pci_generic_drv";
-			ret = device_bind_driver(bus, drv, str, &dev);
+			memset(&find_id, '\0', sizeof(find_id));
+			find_id.vendor = vendor;
+			find_id.device = device;
+			find_id.class = class;
+			if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) {
+				pci_bus_read_config(bus, devfn,
+						    PCI_SUBSYSTEM_VENDOR_ID,
+						    &val, PCI_SIZE_32);
+				find_id.subvendor = val & 0xffff;
+				find_id.subdevice = val >> 16;
+			}
+			ret = pci_find_and_bind_driver(bus, &find_id, devfn,
+						       &dev);
 		}
 		if (ret)
 			return ret;
diff --git a/drivers/pci/pci_compat.c b/drivers/pci/pci_compat.c
index d6938c1..05c3510 100644
--- a/drivers/pci/pci_compat.c
+++ b/drivers/pci/pci_compat.c
@@ -31,13 +31,9 @@
 
 pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
 {
-	struct pci_child_platdata *pplat;
-	struct udevice *bus, *dev;
+	struct udevice *dev;
 
 	if (pci_find_device_id(ids, index, &dev))
 		return -1;
-	bus = dev->parent;
-	pplat = dev_get_parent_platdata(dev);
-
-	return PCI_ADD_BUS(bus->seq, pplat->devfn);
+	return pci_get_bdf(dev);
 }
diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c
index 812ac13..d99cb9a 100644
--- a/drivers/power/pmic/pmic-uclass.c
+++ b/drivers/power/pmic/pmic-uclass.c
@@ -9,6 +9,7 @@
 #include <fdtdec.h>
 #include <errno.h>
 #include <dm.h>
+#include <vsprintf.h>
 #include <dm/lists.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
@@ -17,16 +18,6 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static ulong str_get_num(const char *ptr, const char *maxptr)
-{
-	if (!ptr || !maxptr)
-		return 0;
-
-	while (!isdigit(*ptr) && ptr++ < maxptr);
-
-	return simple_strtoul(ptr, NULL, 0);
-}
-
 int pmic_bind_children(struct udevice *pmic, int offset,
 		       const struct pmic_child_info *child_info)
 {
@@ -35,7 +26,6 @@
 	struct driver *drv;
 	struct udevice *child;
 	const char *node_name;
-	int node_name_len;
 	int bind_count = 0;
 	int node;
 	int prefix_len;
@@ -47,19 +37,19 @@
 	for (node = fdt_first_subnode(blob, offset);
 	     node > 0;
 	     node = fdt_next_subnode(blob, node)) {
-		node_name = fdt_get_name(blob, node, &node_name_len);
+		node_name = fdt_get_name(blob, node, NULL);
 
 		debug("* Found child node: '%s' at offset:%d\n", node_name,
 								 node);
 
 		child = NULL;
 		for (info = child_info; info->prefix && info->driver; info++) {
-			prefix_len = strlen(info->prefix);
-			if (strncasecmp(info->prefix, node_name, prefix_len))
-				continue;
-
 			debug("  - compatible prefix: '%s'\n", info->prefix);
 
+			prefix_len = strlen(info->prefix);
+			if (strncmp(info->prefix, node_name, prefix_len))
+				continue;
+
 			drv = lists_driver_lookup_name(info->driver);
 			if (!drv) {
 				debug("  - driver: '%s' not found!\n",
@@ -78,10 +68,7 @@
 
 			debug("  - bound child device: '%s'\n", child->name);
 
-			child->driver_data = str_get_num(node_name +
-							 prefix_len,
-							 node_name +
-							 node_name_len);
+			child->driver_data = trailing_strtol(node_name);
 
 			debug("  - set 'child->driver_data': %lu\n",
 			      child->driver_data);
@@ -139,6 +126,38 @@
 	return ops->write(dev, reg, buffer, len);
 }
 
+int pmic_reg_read(struct udevice *dev, uint reg)
+{
+	u8 byte;
+	int ret;
+
+	ret = pmic_read(dev, reg, &byte, 1);
+	debug("%s: reg=%x, value=%x\n", __func__, reg, byte);
+
+	return ret ? ret : byte;
+}
+
+int pmic_reg_write(struct udevice *dev, uint reg, uint value)
+{
+	u8 byte = value;
+
+	debug("%s: reg=%x, value=%x\n", __func__, reg, value);
+	return pmic_read(dev, reg, &byte, 1);
+}
+
+int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set)
+{
+	u8 byte;
+	int ret;
+
+	ret = pmic_reg_read(dev, reg);
+	if (ret < 0)
+		return ret;
+	byte = (ret & ~clr) | set;
+
+	return pmic_reg_write(dev, reg, byte);
+}
+
 UCLASS_DRIVER(pmic) = {
 	.id		= UCLASS_PMIC,
 	.name		= "pmic",
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
index 31ffd44..12e141b 100644
--- a/drivers/power/regulator/regulator-uclass.c
+++ b/drivers/power/regulator/regulator-uclass.c
@@ -138,87 +138,57 @@
 	return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
 }
 
-static int failed(int ret, bool verbose, const char *fmt, ...)
+int regulator_autoset(struct udevice *dev)
 {
-	va_list args;
-	char buf[64];
+	struct dm_regulator_uclass_platdata *uc_pdata;
+	int ret = 0;
 
-	if (verbose == false)
-		return ret;
+	uc_pdata = dev_get_uclass_platdata(dev);
+	if (!uc_pdata->always_on && !uc_pdata->boot_on)
+		return -EMEDIUMTYPE;
 
-	va_start(args, fmt);
-	vscnprintf(buf, sizeof(buf), fmt, args);
-	va_end(args);
-
-	printf(buf);
+	if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
+		ret = regulator_set_value(dev, uc_pdata->min_uV);
+	if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
+		ret = regulator_set_current(dev, uc_pdata->min_uA);
 
 	if (!ret)
-		return 0;
-
-	printf(" (ret: %d)", ret);
+		ret = regulator_set_enable(dev, true);
 
 	return ret;
 }
 
-int regulator_autoset(const char *platname,
-		      struct udevice **devp,
-		      bool verbose)
+static void regulator_show(struct udevice *dev, int ret)
 {
 	struct dm_regulator_uclass_platdata *uc_pdata;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+
+	printf("%s@%s: ", dev->name, uc_pdata->name);
+	if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
+		printf("set %d uV", uc_pdata->min_uV);
+	if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA)
+		printf("; set %d uA", uc_pdata->min_uA);
+	printf("; enabling");
+	if (ret)
+		printf(" (ret: %d)\n", ret);
+	printf("\n");
+}
+
+int regulator_autoset_by_name(const char *platname, struct udevice **devp)
+{
 	struct udevice *dev;
 	int ret;
 
-	if (devp)
-		*devp = NULL;
-
 	ret = regulator_get_by_platname(platname, &dev);
+	if (devp)
+		*devp = dev;
 	if (ret) {
-		error("Can get the regulator: %s!", platname);
+		debug("Can get the regulator: %s!", platname);
 		return ret;
 	}
 
-	uc_pdata = dev_get_uclass_platdata(dev);
-	if (!uc_pdata) {
-		error("Can get the regulator %s uclass platdata!", platname);
-		return -ENXIO;
-	}
-
-	if (!uc_pdata->always_on && !uc_pdata->boot_on)
-		goto retdev;
-
-	if (verbose)
-		printf("%s@%s: ", dev->name, uc_pdata->name);
-
-	/* Those values are optional (-ENODATA if unset) */
-	if ((uc_pdata->min_uV != -ENODATA) &&
-	    (uc_pdata->max_uV != -ENODATA) &&
-	    (uc_pdata->min_uV == uc_pdata->max_uV)) {
-		ret = regulator_set_value(dev, uc_pdata->min_uV);
-		if (failed(ret, verbose, "set %d uV", uc_pdata->min_uV))
-			goto exit;
-	}
-
-	/* Those values are optional (-ENODATA if unset) */
-	if ((uc_pdata->min_uA != -ENODATA) &&
-	    (uc_pdata->max_uA != -ENODATA) &&
-	    (uc_pdata->min_uA == uc_pdata->max_uA)) {
-		ret = regulator_set_current(dev, uc_pdata->min_uA);
-		if (failed(ret, verbose, "; set %d uA", uc_pdata->min_uA))
-			goto exit;
-	}
-
-	ret = regulator_set_enable(dev, true);
-	if (failed(ret, verbose, "; enabling", uc_pdata->min_uA))
-		goto exit;
-
-retdev:
-	if (devp)
-		*devp = dev;
-exit:
-	if (verbose)
-		printf("\n");
-
-	return ret;
+	return regulator_autoset(dev);
 }
 
 int regulator_list_autoset(const char *list_platname[],
@@ -229,7 +199,9 @@
 	int error = 0, i = 0, ret;
 
 	while (list_platname[i]) {
-		ret = regulator_autoset(list_platname[i], &dev, verbose);
+		ret = regulator_autoset_by_name(list_platname[i], &dev);
+		if (ret != -EMEDIUMTYPE && verbose)
+			regulator_show(dev, ret);
 		if (ret & !error)
 			error = ret;
 
@@ -290,7 +262,7 @@
 	if (regulator_name_is_unique(dev, uc_pdata->name))
 		return 0;
 
-	error("\"%s\" of dev: \"%s\", has nonunique value: \"%s\"",
+	debug("\"%s\" of dev: \"%s\", has nonunique value: \"%s\"",
 	      property, dev->name, uc_pdata->name);
 
 	return -EINVAL;
@@ -319,9 +291,43 @@
 	uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset,
 					    "regulator-boot-on");
 
+	/* Those values are optional (-ENODATA if unset) */
+	if ((uc_pdata->min_uV != -ENODATA) &&
+	    (uc_pdata->max_uV != -ENODATA) &&
+	    (uc_pdata->min_uV == uc_pdata->max_uV))
+		uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UV;
+
+	/* Those values are optional (-ENODATA if unset) */
+	if ((uc_pdata->min_uA != -ENODATA) &&
+	    (uc_pdata->max_uA != -ENODATA) &&
+	    (uc_pdata->min_uA == uc_pdata->max_uA))
+		uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
+
 	return 0;
 }
 
+int regulators_enable_boot_on(bool verbose)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_REGULATOR, &uc);
+	if (ret)
+		return ret;
+	for (uclass_first_device(UCLASS_REGULATOR, &dev);
+	     dev && !ret;
+	     uclass_next_device(&dev)) {
+		ret = regulator_autoset(dev);
+		if (ret == -EMEDIUMTYPE)
+			continue;
+		if (verbose)
+			regulator_show(dev, ret);
+	}
+
+	return ret;
+}
+
 UCLASS_DRIVER(regulator) = {
 	.id		= UCLASS_REGULATOR,
 	.name		= "regulator",
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
new file mode 100644
index 0000000..642a2d8
--- /dev/null
+++ b/drivers/ram/Kconfig
@@ -0,0 +1,18 @@
+config RAM
+	bool "Enable RAM drivers using Driver Model"
+	depends on DM
+	help
+	  This allows drivers to be provided for SDRAM and other RAM
+	  controllers and their type to be specified in the board's device
+	  tree. Generally some parameters are required to set up the RAM and
+	  the RAM size can either be statically defined or dynamically
+	  detected.
+
+config SPL_RAM_SUPPORT
+	bool "Enable RAM support in SPL"
+	depends on RAM
+	help
+	  The RAM subsystem adds a small amount of overhead to the image.
+	  If this is acceptable and you have a need to use RAM drivers in
+	  SPL, enable this option. It might provide a cleaner interface to
+	  setting up RAM (e.g. SDRAM / DDR) within SPL.
diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
new file mode 100644
index 0000000..0e10249
--- /dev/null
+++ b/drivers/ram/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+obj-$(CONFIG_RAM) += ram-uclass.o
+obj-$(CONFIG_SANDBOX) += sandbox_ram.o
diff --git a/drivers/ram/ram-uclass.c b/drivers/ram/ram-uclass.c
new file mode 100644
index 0000000..2f1fbe7
--- /dev/null
+++ b/drivers/ram/ram-uclass.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <ram.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+int ram_get_info(struct udevice *dev, struct ram_info *info)
+{
+	struct ram_ops *ops = ram_get_ops(dev);
+
+	if (!ops->get_info)
+		return -ENOSYS;
+
+	return ops->get_info(dev, info);
+}
+
+UCLASS_DRIVER(ram) = {
+	.id		= UCLASS_RAM,
+	.name		= "ram",
+};
diff --git a/drivers/ram/sandbox_ram.c b/drivers/ram/sandbox_ram.c
new file mode 100644
index 0000000..06bf3ec
--- /dev/null
+++ b/drivers/ram/sandbox_ram.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <ram.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_get_info(struct udevice *dev, struct ram_info *info)
+{
+	info->base = 0;
+	info->size = gd->ram_size;
+
+	return 0;
+}
+
+static const struct ram_ops sandbox_ram_ops = {
+	.get_info	= sandbox_get_info,
+};
+
+static const struct udevice_id sandbox_ram_ids[] = {
+	{ .compatible = "sandbox,ram" },
+	{ }
+};
+
+U_BOOT_DRIVER(warm_ram_sandbox) = {
+	.name		= "ram_sandbox",
+	.id		= UCLASS_RAM,
+	.of_match	= sandbox_ram_ids,
+	.ops		= &sandbox_ram_ops,
+};
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 9b044a3..c8a77e2 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -246,6 +246,17 @@
 
 #include <debug_uart.h>
 
+#define serial_dout(reg, value)	\
+	serial_out_shift((char *)com_port + \
+		((char *)reg - (char *)com_port) * \
+			(1 << CONFIG_DEBUG_UART_SHIFT), \
+		CONFIG_DEBUG_UART_SHIFT, value)
+#define serial_din(reg) \
+	serial_in_shift((char *)com_port + \
+		((char *)reg - (char *)com_port) * \
+			(1 << CONFIG_DEBUG_UART_SHIFT), \
+		CONFIG_DEBUG_UART_SHIFT)
+
 void debug_uart_init(void)
 {
 	struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
@@ -259,28 +270,23 @@
 	 */
 	baud_divisor = calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
 				    CONFIG_BAUDRATE);
-	serial_out_shift(&com_port->ier, CONFIG_DEBUG_UART_SHIFT,
-			 CONFIG_SYS_NS16550_IER);
-	serial_out_shift(&com_port->mcr, CONFIG_DEBUG_UART_SHIFT, UART_MCRVAL);
-	serial_out_shift(&com_port->fcr, CONFIG_DEBUG_UART_SHIFT, UART_FCRVAL);
+	serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER);
+	serial_dout(&com_port->mcr, UART_MCRVAL);
+	serial_dout(&com_port->fcr, UART_FCRVAL);
 
-	serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT,
-			 UART_LCR_BKSE | UART_LCRVAL);
-	serial_out_shift(&com_port->dll, CONFIG_DEBUG_UART_SHIFT,
-			 baud_divisor & 0xff);
-	serial_out_shift(&com_port->dlm, CONFIG_DEBUG_UART_SHIFT,
-			 (baud_divisor >> 8) & 0xff);
-	serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT,
-			 UART_LCRVAL);
+	serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
+	serial_dout(&com_port->dll, baud_divisor & 0xff);
+	serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
+	serial_dout(&com_port->lcr, UART_LCRVAL);
 }
 
 static inline void _debug_uart_putc(int ch)
 {
 	struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
 
-	while (!(serial_in_shift(&com_port->lsr, 0) & UART_LSR_THRE))
+	while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
 		;
-	serial_out_shift(&com_port->thr, CONFIG_DEBUG_UART_SHIFT, ch);
+	serial_dout(&com_port->thr, ch);
 }
 
 DEBUG_UART_FUNCS
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 737ae64..d666272 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -95,13 +95,13 @@
 	return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
 }
 
-int spi_post_bind(struct udevice *dev)
+static int spi_post_bind(struct udevice *dev)
 {
 	/* Scan the bus for devices */
 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
-int spi_child_post_bind(struct udevice *dev)
+static int spi_child_post_bind(struct udevice *dev)
 {
 	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
 
@@ -111,7 +111,7 @@
 	return spi_slave_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
 }
 
-int spi_post_probe(struct udevice *bus)
+static int spi_post_probe(struct udevice *bus)
 {
 	struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
 
@@ -121,7 +121,7 @@
 	return 0;
 }
 
-int spi_child_pre_probe(struct udevice *dev)
+static int spi_child_pre_probe(struct udevice *dev)
 {
 	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
 	struct spi_slave *slave = dev_get_parentdata(dev);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 637ef3d..3fa5b2e 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -46,8 +46,8 @@
 
 	  Much of the code is shared but with this option enabled the USB
 	  uclass takes care of device enumeration. USB devices can be
-	  declared with the USB_DEVICE() macro and will be automatically
-	  probed when found on the bus.
+	  declared with the U_BOOT_USB_DEVICE() macro and will be
+	  automatically probed when found on the bus.
 
 source "drivers/usb/host/Kconfig"
 
diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c
index c8697ae..72ec41e 100644
--- a/drivers/usb/eth/asix.c
+++ b/drivers/usb/eth/asix.c
@@ -5,11 +5,11 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <usb.h>
+#include <malloc.h>
 #include <linux/mii.h>
 #include "usb_ether.h"
-#include <malloc.h>
-
 
 /* ASIX AX8817X based USB 2.0 Ethernet Devices */
 
@@ -92,14 +92,20 @@
 #define FLAG_TYPE_AX88772B	(1U << 2)
 #define FLAG_EEPROM_MAC		(1U << 3) /* initial mac address in eeprom */
 
-/* local vars */
-static int curr_eth_dev; /* index for name of next device detected */
 
 /* driver private */
 struct asix_private {
 	int flags;
+#ifdef CONFIG_DM_ETH
+	struct ueth_data ueth;
+#endif
 };
 
+#ifndef CONFIG_DM_ETH
+/* local vars */
+static int curr_eth_dev; /* index for name of next device detected */
+#endif
+
 /*
  * Asix infrastructure commands
  */
@@ -284,13 +290,12 @@
 	return ret;
 }
 
-static int asix_write_hwaddr(struct eth_device *eth)
+static int asix_write_hwaddr_common(struct ueth_data *dev, uint8_t *enetaddr)
 {
-	struct ueth_data *dev = (struct ueth_data *)eth->priv;
 	int ret;
 	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
 
-	memcpy(buf, eth->enetaddr, ETH_ALEN);
+	memcpy(buf, enetaddr, ETH_ALEN);
 
 	ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf);
 	if (ret < 0)
@@ -325,12 +330,11 @@
 	return r;
 }
 
-static int asix_read_mac(struct eth_device *eth)
+static int asix_read_mac_common(struct ueth_data *dev,
+				struct asix_private *priv, uint8_t *enetaddr)
 {
-	struct ueth_data *dev = (struct ueth_data *)eth->priv;
-	struct asix_private *priv = (struct asix_private *)dev->dev_priv;
-	int i;
 	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
+	int i;
 
 	if (priv->flags & FLAG_EEPROM_MAC) {
 		for (i = 0; i < (ETH_ALEN >> 1); i++) {
@@ -339,7 +343,7 @@
 				debug("Failed to read SROM address 04h.\n");
 				return -1;
 			}
-			memcpy((eth->enetaddr + i * 2), buf, 2);
+			memcpy(enetaddr + i * 2, buf, 2);
 		}
 	} else {
 		if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)
@@ -347,7 +351,7 @@
 			debug("Failed to read MAC address.\n");
 			return -1;
 		}
-		memcpy(eth->enetaddr, buf, ETH_ALEN);
+		memcpy(enetaddr, buf, ETH_ALEN);
 	}
 
 	return 0;
@@ -414,12 +418,8 @@
 	return 0;
 }
 
-/*
- * Asix callbacks
- */
-static int asix_init(struct eth_device *eth, bd_t *bd)
+static int asix_init_common(struct ueth_data *dev)
 {
-	struct ueth_data	*dev = (struct ueth_data *)eth->priv;
 	int timeout = 0;
 #define TIMEOUT_RESOLUTION 50	/* ms */
 	int link_detected;
@@ -452,9 +452,8 @@
 	return -1;
 }
 
-static int asix_send(struct eth_device *eth, void *packet, int length)
+static int asix_send_common(struct ueth_data *dev, void *packet, int length)
 {
-	struct ueth_data *dev = (struct ueth_data *)eth->priv;
 	int err;
 	u32 packet_len;
 	int actual_len;
@@ -481,6 +480,24 @@
 	return err;
 }
 
+#ifndef CONFIG_DM_ETH
+/*
+ * Asix callbacks
+ */
+static int asix_init(struct eth_device *eth, bd_t *bd)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_init_common(dev);
+}
+
+static int asix_send(struct eth_device *eth, void *packet, int length)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_send_common(dev, packet, length);
+}
+
 static int asix_recv(struct eth_device *eth)
 {
 	struct ueth_data *dev = (struct ueth_data *)eth->priv;
@@ -552,6 +569,13 @@
 	debug("** %s()\n", __func__);
 }
 
+static int asix_write_hwaddr(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_write_hwaddr_common(dev, eth->enetaddr);
+}
+
 /*
  * Asix probing functions
  */
@@ -694,9 +718,180 @@
 		return 0;
 
 	/* Get the MAC address */
-	if (asix_read_mac(eth))
+	if (asix_read_mac_common(ss, priv, eth->enetaddr))
 		return 0;
 	debug("MAC %pM\n", eth->enetaddr);
 
 	return 1;
 }
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int asix_eth_start(struct udevice *dev)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	return asix_init_common(&priv->ueth);
+}
+
+void asix_eth_stop(struct udevice *dev)
+{
+	debug("** %s()\n", __func__);
+}
+
+int asix_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	return asix_send_common(&priv->ueth, packet, length);
+}
+
+int asix_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	uint8_t *ptr;
+	int ret, len;
+	u32 packet_len;
+
+	len = usb_ether_get_rx_bytes(ueth, &ptr);
+	debug("%s: first try, len=%d\n", __func__, len);
+	if (!len) {
+		if (!(flags & ETH_RECV_CHECK_DEVICE))
+			return -EAGAIN;
+		ret = usb_ether_receive(ueth, AX_RX_URB_SIZE);
+		if (ret == -EAGAIN)
+			return ret;
+
+		len = usb_ether_get_rx_bytes(ueth, &ptr);
+		debug("%s: second try, len=%d\n", __func__, len);
+	}
+
+	/*
+	 * 1st 4 bytes contain the length of the actual data as two
+	 * complementary 16-bit words. Extract the length of the data.
+	 */
+	if (len < sizeof(packet_len)) {
+		debug("Rx: incomplete packet length\n");
+		goto err;
+	}
+	memcpy(&packet_len, ptr, sizeof(packet_len));
+	le32_to_cpus(&packet_len);
+	if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
+		debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
+		      packet_len, (~packet_len >> 16) & 0x7ff,
+		      packet_len & 0x7ff);
+		goto err;
+	}
+	packet_len = packet_len & 0x7ff;
+	if (packet_len > len - sizeof(packet_len)) {
+		debug("Rx: too large packet: %d\n", packet_len);
+		goto err;
+	}
+
+	*packetp = ptr + sizeof(packet_len);
+	return packet_len;
+
+err:
+	usb_ether_advance_rxbuf(ueth, -1);
+	return -EINVAL;
+}
+
+static int asix_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	if (packet_len & 1)
+		packet_len++;
+	usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
+
+	return 0;
+}
+
+int asix_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct asix_private *priv = dev_get_priv(dev);
+
+	if (priv->flags & FLAG_TYPE_AX88172)
+		return -ENOSYS;
+
+	return asix_write_hwaddr_common(&priv->ueth, pdata->enetaddr);
+}
+
+static int asix_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ss = &priv->ueth;
+	int ret;
+
+	priv->flags = dev->driver_data;
+	ret = usb_ether_register(dev, ss, AX_RX_URB_SIZE);
+	if (ret)
+		return ret;
+
+	ret = asix_basic_reset(ss);
+	if (ret)
+		goto err;
+
+	/* Get the MAC address */
+	ret = asix_read_mac_common(ss, priv, pdata->enetaddr);
+	if (ret)
+		goto err;
+	debug("MAC %pM\n", pdata->enetaddr);
+
+	return 0;
+
+err:
+	return usb_ether_deregister(ss);
+}
+
+static const struct eth_ops asix_eth_ops = {
+	.start	= asix_eth_start,
+	.send	= asix_eth_send,
+	.recv	= asix_eth_recv,
+	.free_pkt = asix_free_pkt,
+	.stop	= asix_eth_stop,
+	.write_hwaddr = asix_write_hwaddr,
+};
+
+U_BOOT_DRIVER(asix_eth) = {
+	.name	= "asix_eth",
+	.id	= UCLASS_ETH,
+	.probe = asix_eth_probe,
+	.ops	= &asix_eth_ops,
+	.priv_auto_alloc_size = sizeof(struct asix_private),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id asix_eth_id_table[] = {
+	/* Apple USB Ethernet Adapter */
+	{ USB_DEVICE(0x05ac, 0x1402), .driver_info = FLAG_TYPE_AX88772 },
+	/* D-Link DUB-E100 H/W Ver B1 */
+	{ USB_DEVICE(0x07d1, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
+	/* D-Link DUB-E100 H/W Ver C1 */
+	{ USB_DEVICE(0x2001, 0x1a02), .driver_info = FLAG_TYPE_AX88772 },
+	/* Cables-to-Go USB Ethernet Adapter */
+	{ USB_DEVICE(0x0b95, 0x772a), .driver_info = FLAG_TYPE_AX88772 },
+	/* Trendnet TU2-ET100 V3.0R */
+	{ USB_DEVICE(0x0b95, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
+	/* SMC */
+	{ USB_DEVICE(0x0b95, 0x1720), .driver_info = FLAG_TYPE_AX88172 },
+	/* MSI - ASIX 88772a */
+	{ USB_DEVICE(0x0db0, 0xa877), .driver_info = FLAG_TYPE_AX88772 },
+	/* Linksys 200M v2.1 */
+	{ USB_DEVICE(0x13b1, 0x0018), .driver_info = FLAG_TYPE_AX88172 },
+	/* 0Q0 cable ethernet */
+	{ USB_DEVICE(0x1557, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
+	/* DLink DUB-E100 H/W Ver B1 Alternate */
+	{ USB_DEVICE(0x2001, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
+	/* ASIX 88772B */
+	{ USB_DEVICE(0x0b95, 0x772b),
+		.driver_info = FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
+	{ USB_DEVICE(0x0b95, 0x7e2b), .driver_info = FLAG_TYPE_AX88772B },
+	{ }		/* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(asix_eth, asix_eth_id_table);
+#endif
diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c
index c72b7e4..63785a9 100644
--- a/drivers/usb/eth/usb_ether.c
+++ b/drivers/usb/eth/usb_ether.c
@@ -6,11 +6,137 @@
 
 #include <common.h>
 #include <dm.h>
+#include <malloc.h>
 #include <usb.h>
 #include <dm/device-internal.h>
 
 #include "usb_ether.h"
 
+#ifdef CONFIG_DM_ETH
+
+#define USB_BULK_RECV_TIMEOUT 500
+
+int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize)
+{
+	struct usb_device *udev = dev_get_parentdata(dev);
+	struct usb_interface_descriptor *iface_desc;
+	bool ep_in_found = false, ep_out_found = false;
+	struct usb_interface *iface;
+	const int ifnum = 0; /* Always use interface 0 */
+	int ret, i;
+
+	iface = &udev->config.if_desc[ifnum];
+	iface_desc = &udev->config.if_desc[ifnum].desc;
+
+	/* Initialize the ueth_data structure with some useful info */
+	ueth->ifnum = ifnum;
+	ueth->subclass = iface_desc->bInterfaceSubClass;
+	ueth->protocol = iface_desc->bInterfaceProtocol;
+
+	/*
+	 * We are expecting a minimum of 3 endpoints - in, out (bulk), and int.
+	 * We will ignore any others.
+	 */
+	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+		int ep_addr = iface->ep_desc[i].bEndpointAddress;
+
+		/* is it an BULK endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+			if (ep_addr & USB_DIR_IN && !ep_in_found) {
+				ueth->ep_in = ep_addr &
+					USB_ENDPOINT_NUMBER_MASK;
+				ep_in_found = true;
+			} else if (!(ep_addr & USB_DIR_IN) && !ep_out_found) {
+				ueth->ep_out = ep_addr &
+					USB_ENDPOINT_NUMBER_MASK;
+				ep_out_found = true;
+			}
+		}
+
+		/* is it an interrupt endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+			ueth->ep_int = iface->ep_desc[i].bEndpointAddress &
+				USB_ENDPOINT_NUMBER_MASK;
+			ueth->irqinterval = iface->ep_desc[i].bInterval;
+		}
+	}
+	debug("Endpoints In %d Out %d Int %d\n", ueth->ep_in, ueth->ep_out,
+	      ueth->ep_int);
+
+	/* Do some basic sanity checks, and bail if we find a problem */
+	if (!ueth->ep_in || !ueth->ep_out || !ueth->ep_int) {
+		debug("%s: %s: Cannot find endpoints\n", __func__, dev->name);
+		return -ENXIO;
+	}
+
+	ueth->rxsize = rxsize;
+	ueth->rxbuf = memalign(rxsize, ARCH_DMA_MINALIGN);
+	if (!ueth->rxbuf)
+		return -ENOMEM;
+
+	ret = usb_set_interface(udev, iface_desc->bInterfaceNumber, ifnum);
+	if (ret) {
+		debug("%s: %s: Cannot set interface: %d\n", __func__, dev->name,
+		      ret);
+		return ret;
+	}
+	ueth->pusb_dev = udev;
+
+	return 0;
+}
+
+int usb_ether_deregister(struct ueth_data *ueth)
+{
+	return 0;
+}
+
+int usb_ether_receive(struct ueth_data *ueth, int rxsize)
+{
+	int actual_len;
+	int ret;
+
+	if (rxsize > ueth->rxsize)
+		return -EINVAL;
+	ret = usb_bulk_msg(ueth->pusb_dev,
+			   usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in),
+			   ueth->rxbuf, rxsize, &actual_len,
+			   USB_BULK_RECV_TIMEOUT);
+	debug("Rx: len = %u, actual = %u, err = %d\n", rxsize, actual_len, ret);
+	if (ret) {
+		printf("Rx: failed to receive: %d\n", ret);
+		return ret;
+	}
+	if (actual_len > rxsize) {
+		debug("Rx: received too many bytes %d\n", actual_len);
+		return -ENOSPC;
+	}
+	ueth->rxlen = actual_len;
+	ueth->rxptr = 0;
+
+	return actual_len ? 0 : -EAGAIN;
+}
+
+void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes)
+{
+	ueth->rxptr += num_bytes;
+	if (num_bytes < 0 || ueth->rxptr >= ueth->rxlen)
+		ueth->rxlen = 0;
+}
+
+int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp)
+{
+	if (!ueth->rxlen)
+		return 0;
+
+	*ptrp = &ueth->rxbuf[ueth->rxptr];
+
+	return ueth->rxlen - ueth->rxptr;
+}
+
+#else
+
 typedef void (*usb_eth_before_probe)(void);
 typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum,
 			struct ueth_data *ss);
@@ -140,8 +266,8 @@
 	usb_max_eth_dev = 0;
 #ifdef CONFIG_DM_USB
 	/*
-	 * TODO: We should add USB_DEVICE() declarations to each USB ethernet
-	 * driver and then most of this file can be removed.
+	 * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB
+	 * Ethernet driver and then most of this file can be removed.
 	 */
 	struct udevice *bus;
 	struct uclass *uc;
@@ -197,3 +323,4 @@
 		return 0;
 	return -1;
 }
+#endif
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index bf02221..3a0d32e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -5,20 +5,7 @@
  *
  * All rights reserved.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:	GPL-2.0
  */
 #include <common.h>
 #include <dm.h>
@@ -321,7 +308,7 @@
 		struct udevice *dev = parent;
 
 		if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
-			printf("ehci: Error cannot find high speed parent of usb-1 device\n");
+			printf("ehci: Error cannot find high-speed parent of usb-1 device\n");
 			return;
 		}
 
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index b9eabc5..0cb9fcc 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -2,29 +2,49 @@
  * Copyright (c) 2007-2008, Juniper Networks, Inc.
  * All rights reserved.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:	GPL-2.0
  */
 
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <pci.h>
 #include <usb.h>
 
 #include "ehci.h"
 
+/* Information about a USB port */
+struct ehci_pci_priv {
+	struct ehci_ctrl ehci;
+};
+
+static void ehci_pci_common_init(pci_dev_t pdev, struct ehci_hccr **ret_hccr,
+				 struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	uint32_t cmd;
+
+	hccr = (struct ehci_hccr *)pci_map_bar(pdev,
+			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+	hcor = (struct ehci_hcor *)((uint32_t) hccr +
+			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
+	      (uint32_t)hccr, (uint32_t)hcor,
+	      (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	/* enable busmaster */
+	pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER;
+	pci_write_config_dword(pdev, PCI_COMMAND, cmd);
+}
+
+#ifndef CONFIG_DM_USB
+
 #ifdef CONFIG_PCI_EHCI_DEVICE
 static struct pci_device_id ehci_pci_ids[] = {
 	/* Please add supported PCI EHCI controller ids here */
@@ -33,7 +53,6 @@
 	{0x12D8, 0x400F},	/* Pericom */
 	{0, 0}
 };
-#else
 #endif
 
 /*
@@ -44,9 +63,6 @@
 		struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor)
 {
 	pci_dev_t pdev;
-	uint32_t cmd;
-	struct ehci_hccr *hccr;
-	struct ehci_hcor *hcor;
 
 #ifdef CONFIG_PCI_EHCI_DEVICE
 	pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
@@ -57,23 +73,8 @@
 		printf("EHCI host controller not found\n");
 		return -1;
 	}
+	ehci_pci_common_init(pdev, ret_hccr, ret_hcor);
 
-	hccr = (struct ehci_hccr *)pci_map_bar(pdev,
-			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
-	hcor = (struct ehci_hcor *)((uint32_t) hccr +
-			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
-	debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
-			(uint32_t)hccr, (uint32_t)hcor,
-			(uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
-	*ret_hccr = hccr;
-	*ret_hcor = hcor;
-
-	/* enable busmaster */
-	pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
-	cmd |= PCI_COMMAND_MASTER;
-	pci_write_config_dword(pdev, PCI_COMMAND, cmd);
 	return 0;
 }
 
@@ -85,3 +86,46 @@
 {
 	return 0;
 }
+#endif /* nCONFIG_DM_USB */
+
+#ifdef CONFIG_DM_USB
+static int ehci_pci_probe(struct udevice *dev)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+
+	ehci_pci_common_init(pci_get_bdf(dev), &hccr, &hcor);
+
+	return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static int ehci_pci_remove(struct udevice *dev)
+{
+	int ret;
+
+	ret = ehci_deregister(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(ehci_pci) = {
+	.name	= "ehci_pci",
+	.id	= UCLASS_USB,
+	.probe = ehci_pci_probe,
+	.remove = ehci_pci_remove,
+	.ops	= &ehci_usb_ops,
+	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
+	.priv_auto_alloc_size = sizeof(struct ehci_pci_priv),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+static struct pci_device_id ehci_pci_supported[] = {
+	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0) },
+	{},
+};
+
+U_BOOT_PCI_DEVICE(ehci_pci, ehci_pci_supported);
+
+#endif /* CONFIG_DM_USB */
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 774282d..3379c29 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -3,20 +3,7 @@
  * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
  * All rights reserved.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:	GPL-2.0
  */
 
 #ifndef USB_EHCI_H
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 6f33456..373e04c 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -3,19 +3,7 @@
  *
  * Copyright (C) 2008  Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
+ * SPDX-License-Identifier:	GPL-2.0
  */
 
 #include <common.h>
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index ca1b671..67dc3c4 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -3,19 +3,7 @@
  *
  * Copyright (C) 2008  Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
+ * SPDX-License-Identifier:	GPL-2.0
  */
 
 #ifndef __R8A66597_H__
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 6e86f4a..c5d1e7f 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -128,6 +128,17 @@
 	return ops->alloc_device(bus, udev);
 }
 
+int usb_reset_root_port(struct usb_device *udev)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->reset_root_port)
+		return -ENOSYS;
+
+	return ops->reset_root_port(bus, udev);
+}
+
 int usb_stop(void)
 {
 	struct udevice *bus;
@@ -146,6 +157,9 @@
 		ret = device_remove(bus);
 		if (ret && !err)
 			err = ret;
+		ret = device_unbind_children(bus);
+		if (ret && !err)
+			err = ret;
 	}
 
 #ifdef CONFIG_SANDBOX
@@ -265,11 +279,6 @@
 	return usb_started ? 0 : -1;
 }
 
-int usb_reset_root_port(void)
-{
-	return -ENOSYS;
-}
-
 static struct usb_device *find_child_devnum(struct udevice *parent, int devnum)
 {
 	struct usb_device *udev;
@@ -294,14 +303,14 @@
 
 struct usb_device *usb_get_dev_index(struct udevice *bus, int index)
 {
-	struct udevice *hub;
+	struct udevice *dev;
 	int devnum = index + 1; /* Addresses are allocated from 1 on USB */
 
-	device_find_first_child(bus, &hub);
-	if (device_get_uclass_id(hub) == UCLASS_USB_HUB)
-		return find_child_devnum(hub, devnum);
+	device_find_first_child(bus, &dev);
+	if (!dev)
+		return NULL;
 
-	return NULL;
+	return find_child_devnum(dev, devnum);
 }
 
 int usb_post_bind(struct udevice *dev)
@@ -310,35 +319,6 @@
 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
-int usb_port_reset(struct usb_device *parent, int portnr)
-{
-	unsigned short portstatus;
-	int ret;
-
-	debug("%s: start\n", __func__);
-
-	if (parent) {
-		/* reset the port for the second time */
-		assert(portnr > 0);
-		debug("%s: reset %d\n", __func__, portnr - 1);
-		ret = legacy_hub_port_reset(parent, portnr - 1, &portstatus);
-		if (ret < 0) {
-			printf("\n     Couldn't reset port %i\n", portnr);
-			return ret;
-		}
-	} else {
-		debug("%s: reset root\n", __func__);
-		usb_reset_root_port();
-	}
-
-	return 0;
-}
-
-int usb_legacy_port_reset(struct usb_device *parent, int portnr)
-{
-	return usb_port_reset(parent, portnr);
-}
-
 int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
 {
 	struct usb_platdata *plat;
@@ -511,15 +491,14 @@
 }
 
 /**
- * usb_find_child() - Find an existing device which matches our needs
- *
- *
+ * usb_find_emul_child() - Find an existing device for emulated devices
  */
-static int usb_find_child(struct udevice *parent,
-			  struct usb_device_descriptor *desc,
-			  struct usb_interface_descriptor *iface,
-			  struct udevice **devp)
+static int usb_find_emul_child(struct udevice *parent,
+			       struct usb_device_descriptor *desc,
+			       struct usb_interface_descriptor *iface,
+			       struct udevice **devp)
 {
+#ifdef CONFIG_SANDBOX
 	struct udevice *dev;
 
 	*devp = NULL;
@@ -538,7 +517,7 @@
 			return 0;
 		}
 	}
-
+#endif
 	return -ENOENT;
 }
 
@@ -594,12 +573,12 @@
 	debug("Calling usb_setup_device(), portnr=%d\n", udev->portnr);
 	parent_udev = device_get_uclass_id(parent) == UCLASS_USB_HUB ?
 		dev_get_parentdata(parent) : NULL;
-	ret = usb_setup_device(udev, priv->desc_before_addr, parent_udev, port);
+	ret = usb_setup_device(udev, priv->desc_before_addr, parent_udev);
 	debug("read_descriptor for '%s': ret=%d\n", parent->name, ret);
 	if (ret)
 		return ret;
-	ret = usb_find_child(parent, &udev->descriptor, iface, &dev);
-	debug("** usb_find_child returns %d\n", ret);
+	ret = usb_find_emul_child(parent, &udev->descriptor, iface, &dev);
+	debug("** usb_find_emul_child returns %d\n", ret);
 	if (ret) {
 		if (ret != -ENOENT)
 			return ret;
diff --git a/drivers/usb/musb-new/am35x.c b/drivers/usb/musb-new/am35x.c
index 857d7eb..d158454 100644
--- a/drivers/usb/musb-new/am35x.c
+++ b/drivers/usb/musb-new/am35x.c
@@ -100,7 +100,11 @@
 /*
  * am35x_musb_enable - enable interrupts
  */
+#ifndef __UBOOT__
 static void am35x_musb_enable(struct musb *musb)
+#else
+static int am35x_musb_enable(struct musb *musb)
+#endif
 {
 	void __iomem *reg_base = musb->ctrl_base;
 	u32 epmask;
@@ -116,6 +120,9 @@
 	if (is_otg_enabled(musb))
 		musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
 			    AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
+#ifdef __UBOOT__
+	return 0;
+#endif
 }
 
 /*
diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c
index 242cc30..f530af4 100644
--- a/drivers/usb/musb-new/musb_core.c
+++ b/drivers/usb/musb-new/musb_core.c
@@ -926,10 +926,17 @@
 /*
 * Program the HDRC to start (enable interrupts, dma, etc.).
 */
+#ifndef __UBOOT__
 void musb_start(struct musb *musb)
+#else
+int musb_start(struct musb *musb)
+#endif
 {
 	void __iomem	*regs = musb->mregs;
 	u8		devctl = musb_readb(regs, MUSB_DEVCTL);
+#ifdef __UBOOT__
+	int ret;
+#endif
 
 	dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
 
@@ -972,8 +979,21 @@
 		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
 			musb->is_active = 1;
 	}
+
+#ifndef __UBOOT__
 	musb_platform_enable(musb);
+#else
+	ret = musb_platform_enable(musb);
+	if (ret) {
+		musb->is_active = 0;
+		return ret;
+	}
+#endif
 	musb_writeb(regs, MUSB_DEVCTL, devctl);
+
+#ifdef __UBOOT__
+	return 0;
+#endif
 }
 
 
diff --git a/drivers/usb/musb-new/musb_core.h b/drivers/usb/musb-new/musb_core.h
index 2695742..8727f64 100644
--- a/drivers/usb/musb-new/musb_core.h
+++ b/drivers/usb/musb-new/musb_core.h
@@ -231,7 +231,11 @@
 	int	(*init)(struct musb *musb);
 	int	(*exit)(struct musb *musb);
 
+#ifndef __UBOOT__
 	void	(*enable)(struct musb *musb);
+#else
+	int	(*enable)(struct musb *musb);
+#endif
 	void	(*disable)(struct musb *musb);
 
 	int	(*set_mode)(struct musb *musb, u8 mode);
@@ -546,7 +550,11 @@
 
 extern const char musb_driver_name[];
 
+#ifndef __UBOOT__
 extern void musb_start(struct musb *musb);
+#else
+extern int musb_start(struct musb *musb);
+#endif
 extern void musb_stop(struct musb *musb);
 
 extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
@@ -564,11 +572,21 @@
 		musb->ops->set_vbus(musb, is_on);
 }
 
+#ifndef __UBOOT__
 static inline void musb_platform_enable(struct musb *musb)
 {
 	if (musb->ops->enable)
 		musb->ops->enable(musb);
 }
+#else
+static inline int musb_platform_enable(struct musb *musb)
+{
+	if (!musb->ops->enable)
+		return 0;
+
+	return musb->ops->enable(musb);
+}
+#endif
 
 static inline void musb_platform_disable(struct musb *musb)
 {
diff --git a/drivers/usb/musb-new/musb_dsps.c b/drivers/usb/musb-new/musb_dsps.c
index 17ed224..8959397 100644
--- a/drivers/usb/musb-new/musb_dsps.c
+++ b/drivers/usb/musb-new/musb_dsps.c
@@ -156,7 +156,11 @@
 /**
  * dsps_musb_enable - enable interrupts
  */
+#ifndef __UBOOT__
 static void dsps_musb_enable(struct musb *musb)
+#else
+static int dsps_musb_enable(struct musb *musb)
+#endif
 {
 #ifndef __UBOOT__
 	struct device *dev = musb->controller;
@@ -181,6 +185,8 @@
 	if (is_otg_enabled(musb))
 		dsps_writel(reg_base, wrp->coreintr_set,
 			    (1 << wrp->drvvbus) << wrp->usb_shift);
+#else
+	return 0;
 #endif
 }
 
diff --git a/drivers/usb/musb-new/musb_gadget_ep0.c b/drivers/usb/musb-new/musb_gadget_ep0.c
index 5a71501..415a9f2 100644
--- a/drivers/usb/musb-new/musb_gadget_ep0.c
+++ b/drivers/usb/musb-new/musb_gadget_ep0.c
@@ -43,6 +43,7 @@
 #else
 #include <common.h>
 #include "linux-compat.h"
+#include <asm/processor.h>
 #endif
 
 #include "musb_core.h"
diff --git a/drivers/usb/musb-new/musb_host.c b/drivers/usb/musb-new/musb_host.c
index 437309c..40b9c66 100644
--- a/drivers/usb/musb-new/musb_host.c
+++ b/drivers/usb/musb-new/musb_host.c
@@ -2067,7 +2067,11 @@
 
 	/* precompute addressing for external hub/tt ports */
 	if (musb->is_multipoint) {
+#ifndef __UBOOT__
 		struct usb_device	*parent = urb->dev->parent;
+#else
+		struct usb_device	*parent = usb_dev_get_parent(urb->dev);
+#endif
 
 #ifndef __UBOOT__
 		if (parent != hcd->self.root_hub) {
diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index d1ee5f8..9b56e90 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -13,6 +13,7 @@
 #include "musb_core.h"
 #include "musb_host.h"
 #include "musb_gadget.h"
+#include "musb_uboot.h"
 
 #ifdef CONFIG_MUSB_HOST
 struct int_queue {
@@ -20,9 +21,9 @@
 	struct urb urb;
 };
 
-static struct musb *host;
-static struct usb_hcd hcd;
-static enum usb_device_speed host_speed;
+#ifndef CONFIG_DM_USB
+struct musb_host_data musb_host;
+#endif
 
 static void musb_host_complete_urb(struct urb *urb)
 {
@@ -30,9 +31,6 @@
 	urb->dev->act_len = urb->actual_length;
 }
 
-static struct usb_host_endpoint hep;
-static struct urb urb;
-
 static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
 			  struct usb_device *dev, int endpoint_type,
 			  unsigned long pipe, void *buffer, int len,
@@ -90,38 +88,40 @@
 	return urb->status;
 }
 
-int submit_control_msg(struct usb_device *dev, unsigned long pipe,
-			void *buffer, int len, struct devrequest *setup)
+static int _musb_submit_control_msg(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe,
+	void *buffer, int len, struct devrequest *setup)
 {
-	construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe,
-		      buffer, len, setup, 0);
+	construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_CONTROL,
+		      pipe, buffer, len, setup, 0);
 
 	/* Fix speed for non hub-attached devices */
-	if (!dev->parent)
-		dev->speed = host_speed;
+	if (!usb_dev_get_parent(dev))
+		dev->speed = host->host_speed;
 
-	return submit_urb(&hcd, &urb);
+	return submit_urb(&host->hcd, &host->urb);
 }
 
-
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
-					void *buffer, int len)
+static int _musb_submit_bulk_msg(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe, void *buffer, int len)
 {
-	construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_BULK, pipe,
-		      buffer, len, NULL, 0);
-	return submit_urb(&hcd, &urb);
+	construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_BULK,
+		      pipe, buffer, len, NULL, 0);
+	return submit_urb(&host->hcd, &host->urb);
 }
 
-int submit_int_msg(struct usb_device *dev, unsigned long pipe,
-				void *buffer, int len, int interval)
+static int _musb_submit_int_msg(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe,
+	void *buffer, int len, int interval)
 {
-	construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_INT, pipe,
+	construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_INT, pipe,
 		      buffer, len, NULL, interval);
-	return submit_urb(&hcd, &urb);
+	return submit_urb(&host->hcd, &host->urb);
 }
 
-struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
-	int queuesize, int elementsize, void *buffer, int interval)
+static struct int_queue *_musb_create_int_queue(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe, int queuesize,
+	int elementsize, void *buffer, int interval)
 {
 	struct int_queue *queue;
 	int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe);
@@ -143,7 +143,7 @@
 	construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT,
 		      pipe, buffer, elementsize, NULL, interval);
 
-	ret = musb_urb_enqueue(&hcd, &queue->urb, 0);
+	ret = musb_urb_enqueue(&host->hcd, &queue->urb, 0);
 	if (ret < 0) {
 		printf("Failed to enqueue URB to controller\n");
 		free(queue);
@@ -154,25 +154,27 @@
 	return queue;
 }
 
-int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+static int _musb_destroy_int_queue(struct musb_host_data *host,
+	struct usb_device *dev, struct int_queue *queue)
 {
 	int index = usb_pipein(queue->urb.pipe) * 16 + 
 		    usb_pipeendpoint(queue->urb.pipe);
 
 	if (queue->urb.status == -EINPROGRESS)
-		musb_urb_dequeue(&hcd, &queue->urb, -ETIME);
+		musb_urb_dequeue(&host->hcd, &queue->urb, -ETIME);
 
 	dev->int_pending &= ~(1 << index);
 	free(queue);
 	return 0;
 }
 
-void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+static void *_musb_poll_int_queue(struct musb_host_data *host,
+	struct usb_device *dev, struct int_queue *queue)
 {
 	if (queue->urb.status != -EINPROGRESS)
 		return NULL; /* URB has already completed in a prev. poll */
 
-	host->isr(0, host);
+	host->host->isr(0, host->host);
 
 	if (queue->urb.status != -EINPROGRESS)
 		return queue->urb.transfer_buffer; /* Done */
@@ -180,9 +182,10 @@
 	return NULL; /* URB still pending */
 }
 
-int usb_reset_root_port(void)
+static int _musb_reset_root_port(struct musb_host_data *host,
+	struct usb_device *dev)
 {
-	void *mbase = host->mregs;
+	void *mbase = host->host->mregs;
 	u8 power;
 
 	power = musb_readb(mbase, MUSB_POWER);
@@ -202,29 +205,33 @@
 #ifdef CONFIG_ARCH_SUNXI
 	sunxi_usb_phy_enable_squelch_detect(0, 1);
 #endif
-	host->isr(0, host);
-	host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
+	host->host->isr(0, host->host);
+	host->host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
 			USB_SPEED_HIGH :
 			(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
 			USB_SPEED_FULL : USB_SPEED_LOW;
-	mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
+	mdelay((host->host_speed == USB_SPEED_LOW) ? 200 : 50);
 
 	return 0;
 }
 
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+int musb_lowlevel_init(struct musb_host_data *host)
 {
 	void *mbase;
 	/* USB spec says it may take up to 1 second for a device to connect */
 	unsigned long timeout = get_timer(0) + 1000;
+	int ret;
 
-	if (!host) {
+	if (!host->host) {
 		printf("MUSB host is not registered\n");
 		return -ENODEV;
 	}
 
-	musb_start(host);
-	mbase = host->mregs;
+	ret = musb_start(host->host);
+	if (ret)
+		return ret;
+
+	mbase = host->host->mregs;
 	do {
 		if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM)
 			break;
@@ -232,23 +239,135 @@
 	if (get_timer(0) >= timeout)
 		return -ENODEV;
 
-	usb_reset_root_port();
-	host->is_active = 1;
-	hcd.hcd_priv = host;
+	_musb_reset_root_port(host, NULL);
+	host->host->is_active = 1;
+	host->hcd.hcd_priv = host->host;
 
 	return 0;
 }
 
+#ifndef CONFIG_DM_USB
 int usb_lowlevel_stop(int index)
 {
-	if (!host) {
+	if (!musb_host.host) {
 		printf("MUSB host is not registered\n");
 		return -ENODEV;
 	}
 
-	musb_stop(host);
+	musb_stop(musb_host.host);
 	return 0;
 }
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+			    void *buffer, int length)
+{
+	return _musb_submit_bulk_msg(&musb_host, dev, pipe, buffer, length);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
+		       void *buffer, int length, struct devrequest *setup)
+{
+	return _musb_submit_control_msg(&musb_host, dev, pipe, buffer, length, setup);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+		   void *buffer, int length, int interval)
+{
+	return _musb_submit_int_msg(&musb_host, dev, pipe, buffer, length, interval);
+}
+
+struct int_queue *create_int_queue(struct usb_device *dev,
+		unsigned long pipe, int queuesize, int elementsize,
+		void *buffer, int interval)
+{
+	return _musb_create_int_queue(&musb_host, dev, pipe, queuesize, elementsize,
+				      buffer, interval);
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _musb_poll_int_queue(&musb_host, dev, queue);
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _musb_destroy_int_queue(&musb_host, dev, queue);
+}
+
+int usb_reset_root_port(struct usb_device *dev)
+{
+	return _musb_reset_root_port(&musb_host, dev);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+	return musb_lowlevel_init(&musb_host);
+}
+#endif /* !CONFIG_DM_USB */
+
+#ifdef CONFIG_DM_USB
+static int musb_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+				   unsigned long pipe, void *buffer, int length,
+				   struct devrequest *setup)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_submit_control_msg(host, udev, pipe, buffer, length, setup);
+}
+
+static int musb_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+				unsigned long pipe, void *buffer, int length)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_submit_bulk_msg(host, udev, pipe, buffer, length);
+}
+
+static int musb_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+			       unsigned long pipe, void *buffer, int length,
+			       int interval)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_submit_int_msg(host, udev, pipe, buffer, length, interval);
+}
+
+static struct int_queue *musb_create_int_queue(struct udevice *dev,
+		struct usb_device *udev, unsigned long pipe, int queuesize,
+		int elementsize, void *buffer, int interval)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_create_int_queue(host, udev, pipe, queuesize, elementsize,
+				      buffer, interval);
+}
+
+static void *musb_poll_int_queue(struct udevice *dev, struct usb_device *udev,
+				 struct int_queue *queue)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_poll_int_queue(host, udev, queue);
+}
+
+static int musb_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
+				  struct int_queue *queue)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_destroy_int_queue(host, udev, queue);
+}
+
+static int musb_reset_root_port(struct udevice *dev, struct usb_device *udev)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_reset_root_port(host, udev);
+}
+
+struct dm_usb_ops musb_usb_ops = {
+	.control = musb_submit_control_msg,
+	.bulk = musb_submit_bulk_msg,
+	.interrupt = musb_submit_int_msg,
+	.create_int_queue = musb_create_int_queue,
+	.poll_int_queue = musb_poll_int_queue,
+	.destroy_int_queue = musb_destroy_int_queue,
+	.reset_root_port = musb_reset_root_port,
+};
+#endif /* CONFIG_DM_USB */
 #endif /* CONFIG_MUSB_HOST */
 
 #ifdef CONFIG_MUSB_GADGET
@@ -309,9 +428,9 @@
 	struct musb **musbp;
 
 	switch (plat->mode) {
-#ifdef CONFIG_MUSB_HOST
+#if defined(CONFIG_MUSB_HOST) && !defined(CONFIG_DM_USB)
 	case MUSB_HOST:
-		musbp = &host;
+		musbp = &musb_host.host;
 		break;
 #endif
 #ifdef CONFIG_MUSB_GADGET
diff --git a/drivers/usb/musb-new/musb_uboot.h b/drivers/usb/musb-new/musb_uboot.h
new file mode 100644
index 0000000..6312cd2
--- /dev/null
+++ b/drivers/usb/musb-new/musb_uboot.h
@@ -0,0 +1,28 @@
+/*
+ * MUSB OTG driver u-boot specific functions
+ *
+ * Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef __MUSB_UBOOT_H__
+#define __MUSB_UBOOT_H__
+
+#include <usb.h>
+#include "linux-compat.h"
+#include "usb-compat.h"
+#include "musb_core.h"
+
+struct musb_host_data {
+	struct musb *host;
+	struct usb_hcd hcd;
+	enum usb_device_speed host_speed;
+	struct usb_host_endpoint hep;
+	struct urb urb;
+};
+
+extern struct dm_usb_ops musb_usb_ops;
+
+int musb_lowlevel_init(struct musb_host_data *host);
+
+#endif
diff --git a/drivers/usb/musb-new/omap2430.c b/drivers/usb/musb-new/omap2430.c
index 31a280e..77273a4 100644
--- a/drivers/usb/musb-new/omap2430.c
+++ b/drivers/usb/musb-new/omap2430.c
@@ -400,7 +400,11 @@
 	return status;
 }
 
+#ifndef __UBOOT__
 static void omap2430_musb_enable(struct musb *musb)
+#else
+static int omap2430_musb_enable(struct musb *musb)
+#endif
 {
 #ifndef __UBOOT__
 	u8		devctl;
@@ -445,6 +449,7 @@
 				__PRETTY_FUNCTION__);
 	}
 #endif
+	return 0;
 #endif
 }
 
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 052e065..c123d61 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -199,12 +199,12 @@
 /* musb_core does not call enable / disable in a balanced manner <sigh> */
 static bool enabled = false;
 
-static void sunxi_musb_enable(struct musb *musb)
+static int sunxi_musb_enable(struct musb *musb)
 {
 	pr_debug("%s():\n", __func__);
 
 	if (enabled)
-		return;
+		return 0;
 
 	/* select PIO mode */
 	musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
@@ -215,6 +215,7 @@
 	USBC_ForceVbusValidToHigh(musb->mregs);
 
 	enabled = true;
+	return 0;
 }
 
 static void sunxi_musb_disable(struct musb *musb)
diff --git a/drivers/usb/musb-new/usb-compat.h b/drivers/usb/musb-new/usb-compat.h
index 50bad37..53fe4ff 100644
--- a/drivers/usb/musb-new/usb-compat.h
+++ b/drivers/usb/musb-new/usb-compat.h
@@ -1,6 +1,7 @@
 #ifndef __USB_COMPAT_H__
 #define __USB_COMPAT_H__
 
+#include <dm.h>
 #include "usb.h"
 
 struct usb_hcd {
@@ -66,6 +67,68 @@
 	return 0;
 }
 
+#ifdef CONFIG_DM_USB
+static inline u16 find_tt(struct usb_device *udev)
+{
+	struct udevice *parent;
+	struct usb_device *uparent, *ttdev;
+
+	/*
+	 * When called from usb-uclass.c: usb_scan_device() udev->dev points
+	 * to the parent udevice, not the actual udevice belonging to the
+	 * udev as the device is not instantiated yet. So when searching
+	 * for the first usb-2 parent start with udev->dev not
+	 * udev->dev->parent .
+	 */
+	ttdev = udev;
+	parent = udev->dev;
+	uparent = dev_get_parentdata(parent);
+
+	while (uparent->speed != USB_SPEED_HIGH) {
+		struct udevice *dev = parent;
+
+		if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
+			printf("musb: Error cannot find high speed parent of usb-1 device\n");
+			return 0;
+		}
+
+		ttdev = dev_get_parentdata(dev);
+		parent = dev->parent;
+		uparent = dev_get_parentdata(parent);
+	}
+
+	return (uparent->devnum << 8) | (ttdev->portnr - 1);
+}
+
+static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev)
+{
+	struct udevice *parent = udev->dev->parent;
+
+	/*
+	 * When called from usb-uclass.c: usb_scan_device() udev->dev points
+	 * to the parent udevice, not the actual udevice belonging to the
+	 * udev as the device is not instantiated yet.
+	 *
+	 * If dev is an usb-bus, then we are called from usb_scan_device() for
+	 * an usb-device plugged directly into the root port, return NULL.
+	 */
+	if (device_get_uclass_id(udev->dev) == UCLASS_USB)
+		return NULL;
+
+	/*
+	 * If these 2 are not the same we are being called from
+	 * usb_scan_device() and udev itself is the parent.
+	 */
+	if (dev_get_parentdata(udev->dev) != udev)
+		return udev;
+
+	/* We are being called normally, use the parent pointer */
+	if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
+		return dev_get_parentdata(parent);
+
+	return NULL;
+}
+#else
 static inline u16 find_tt(struct usb_device *dev)
 {
 	u8 chid;
@@ -86,4 +149,11 @@
 
 	return (hub << 8) | chid;
 }
+
+static inline struct usb_device *usb_dev_get_parent(struct usb_device *dev)
+{
+	return dev->parent;
+}
+#endif
+
 #endif /* __USB_COMPAT_H__ */
diff --git a/dts/Kconfig b/dts/Kconfig
index 957f5c7..09cfefb 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -56,4 +56,16 @@
 	  It can be overridden from the command line:
 	  $ make DEVICE_TREE=<device-tree-name>
 
+config OF_SPL_REMOVE_PROPS
+	string "List of device tree properties to drop for SPL"
+	depends on OF_CONTROL && SPL
+	default "pinctrl-0 pinctrl-names clocks clock-names interrupt-parent"
+	help
+	  Since SPL normally runs in a reduced memory space, the device tree
+	  is cut down to only what is needed to load and start U-Boot. Only
+	  nodes marked with the property "u-boot,dm-pre-reloc" will be
+	  included. In addition, some properties are not used by U-Boot and
+	  can be discarded. This option defines the list of properties to
+	  discard.
+
 endmenu
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index db0550b..7ef3e25 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -116,5 +116,6 @@
 #define GD_FLG_ENV_READY	0x00080	/* Env. imported into hash table   */
 #define GD_FLG_SERIAL_READY	0x00100	/* Pre-reloc serial console ready  */
 #define GD_FLG_FULL_MALLOC_INIT	0x00200	/* Full malloc() is ready	   */
+#define GD_FLG_SPL_INIT		0x00400	/* spl_init() has been called	   */
 
 #endif /* __ASM_GENERIC_GBL_DATA_H */
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index de91e57..0af599f 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -322,6 +322,19 @@
 const char *gpio_get_bank_info(struct udevice *dev, int *offset_count);
 
 /**
+ * dm_gpio_lookup_name() - Look up a named GPIO and return its description
+ *
+ * The name of a GPIO is typically its bank name followed by a number from 0.
+ * For example A0 is the first GPIO in bank A. Each bank is a separate driver
+ * model device.
+ *
+ * @name:	Name to look up
+ * @desc:	Returns description, on success
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc);
+
+/**
  * gpio_lookup_name - Look up a GPIO name and return its details
  *
  * This is used to convert a named GPIO into a device, offset and GPIO
@@ -421,6 +434,18 @@
 			      int flags);
 
 /**
+ * dm_gpio_request() - manually request a GPIO
+ *
+ * Note: This function should only be used for testing / debugging. Instead.
+ * use gpio_request_by_name() to pull GPIOs from the device tree.
+ *
+ * @desc:	GPIO description of GPIO to request (see dm_gpio_lookup_name())
+ * @label:	Label to attach to the GPIO while claimed
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpio_request(struct gpio_desc *desc, const char *label);
+
+/**
  * gpio_get_list_count() - Returns the number of GPIOs in a list
  *
  * Counts the GPIOs in a list. See gpio_request_by_name() for additional
diff --git a/include/clk.h b/include/clk.h
index df4570c..254ad2b 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -1,6 +1,86 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
 #ifndef _CLK_H_
 #define _CLK_H_
 
 int soc_clk_dump(void);
 
+struct clk_ops {
+	/**
+	 * get_rate() - Get current clock rate
+	 *
+	 * @dev:	Device to check (UCLASS_CLK)
+	 * @return clock rate in Hz, or -ve error code
+	 */
+	ulong (*get_rate)(struct udevice *dev);
+
+	/**
+	 * set_rate() - Set current clock rate
+	 *
+	 * @dev:	Device to adjust
+	 * @rate:	New clock rate in Hz
+	 * @return new rate, or -ve error code
+	 */
+	ulong (*set_rate)(struct udevice *dev, ulong rate);
+
+	/**
+	* clk_set_periph_rate() - Set clock rate for a peripheral
+	*
+	* @dev:	Device to adjust (UCLASS_CLK)
+	* @rate:	New clock rate in Hz
+	* @return new clock rate in Hz, or -ve error code
+	*/
+	ulong (*get_periph_rate)(struct udevice *dev, int periph);
+
+	/**
+	 * clk_set_periph_rate() - Set current clock rate for a peripheral
+	 *
+	 * @dev:	Device to update (UCLASS_CLK)
+	 * @periph:	Peripheral ID to cupdate
+	 * @return new clock rate in Hz, or -ve error code
+	 */
+	ulong (*set_periph_rate)(struct udevice *dev, int periph, ulong rate);
+};
+
+#define clk_get_ops(dev)	((struct clk_ops *)(dev)->driver->ops)
+
+/**
+ * clk_get_rate() - Get current clock rate
+ *
+ * @dev:	Device to check (UCLASS_CLK)
+ * @return clock rate in Hz, or -ve error code
+ */
+ulong clk_get_rate(struct udevice *dev);
+
+/**
+ * set_rate() - Set current clock rate
+ *
+ * @dev:	Device to adjust
+ * @rate:	New clock rate in Hz
+ * @return new rate, or -ve error code
+ */
+ulong clk_set_rate(struct udevice *dev, ulong rate);
+
+/**
+ * clk_get_periph_rate() - Get current clock rate for a peripheral
+ *
+ * @dev:	Device to check (UCLASS_CLK)
+ * @return clock rate in Hz, -ve error code
+ */
+ulong clk_get_periph_rate(struct udevice *dev, int periph);
+
+/**
+ * clk_set_periph_rate() - Set current clock rate for a peripheral
+ *
+ * @dev:	Device to update (UCLASS_CLK)
+ * @periph:	Peripheral ID to cupdate
+ * @return new clock rate in Hz, or -ve error code
+ */
+ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate);
+
 #endif /* _CLK_H_ */
diff --git a/include/common.h b/include/common.h
index 8f4b2ec..4566bd1 100644
--- a/include/common.h
+++ b/include/common.h
@@ -1010,6 +1010,17 @@
 #define DEFINE_CACHE_ALIGN_BUFFER(type, name, size)			\
 	DEFINE_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
 
+/*
+ * check_member() - Check the offset of a structure member
+ *
+ * @structure:	Name of structure (e.g. global_data)
+ * @member:	Name of member (e.g. baudrate)
+ * @offset:	Expected offset in bytes
+ */
+#define check_member(structure, member, offset) _Static_assert( \
+	offsetof(struct structure, member) == offset, \
+	"`struct " #structure "` offset for `" #member "` is not " #offset)
+
 /* Pull in stuff for the build system */
 #ifdef DO_DEPS_ONLY
 # include <environment.h>
diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h
index af36ac5..4781e79 100644
--- a/include/configs/minnowmax.h
+++ b/include/configs/minnowmax.h
@@ -60,9 +60,6 @@
 #define CONFIG_FIT_SIGNATURE
 #define CONFIG_RSA
 
-/* Avoid a warning in the Realtek Ethernet driver */
-#define CONFIG_SYS_CACHELINE_SIZE 16
-
 #define CONFIG_ENV_SECT_SIZE		0x1000
 #define CONFIG_ENV_OFFSET		0x007fe000
 
diff --git a/include/debug_uart.h b/include/debug_uart.h
index f56797b..a75e377 100644
--- a/include/debug_uart.h
+++ b/include/debug_uart.h
@@ -10,8 +10,6 @@
 #ifndef _DEBUG_UART_H
 #define _DEBUG_UART_H
 
-#include <linux/linkage.h>
-
 /*
  * The debug UART is intended for use very early in U-Boot to debug problems
  * when an ICE or other debug mechanism is not available.
@@ -64,46 +62,46 @@
  *
  * @ch:		Character to output
  */
-asmlinkage void printch(int ch);
+void printch(int ch);
 
 /**
  * printascii() - Output an ASCII string to the debug UART
  *
  * @str:	String to output
  */
-asmlinkage void printascii(const char *str);
+void printascii(const char *str);
 
 /**
  * printhex2() - Output a 2-digit hex value
  *
  * @value:	Value to output
  */
-asmlinkage void printhex2(uint value);
+void printhex2(uint value);
 
 /**
  * printhex4() - Output a 4-digit hex value
  *
  * @value:	Value to output
  */
-asmlinkage void printhex4(uint value);
+void printhex4(uint value);
 
 /**
  * printhex8() - Output a 8-digit hex value
  *
  * @value:	Value to output
  */
-asmlinkage void printhex8(uint value);
+void printhex8(uint value);
 
 /*
  * Now define some functions - this should be inserted into the serial driver
  */
 #define DEBUG_UART_FUNCS \
-	asmlinkage void printch(int ch) \
+	void printch(int ch) \
 	{ \
 		_debug_uart_putc(ch); \
 	} \
 \
-	asmlinkage void printascii(const char *str) \
+	void printascii(const char *str) \
 	{ \
 		while (*str) \
 			_debug_uart_putc(*str++); \
@@ -121,17 +119,17 @@
 			printhex1(value >> (4 * digits)); \
 	} \
 \
-	asmlinkage void printhex2(uint value) \
+	void printhex2(uint value) \
 	{ \
 		printhex(value, 2); \
 	} \
 \
-	asmlinkage void printhex4(uint value) \
+	void printhex4(uint value) \
 	{ \
 		printhex(value, 4); \
 	} \
 \
-	asmlinkage void printhex8(uint value) \
+	void printhex8(uint value) \
 	{ \
 		printhex(value, 8); \
 	}
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 687462b..402304f 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -107,6 +107,32 @@
 static inline int device_unbind(struct udevice *dev) { return 0; }
 #endif
 
+/**
+ * device_remove_children() - Stop all device's children
+ * @dev:	The device whose children are to be removed
+ * @return 0 on success, -ve on error
+ */
+#ifdef CONFIG_DM_DEVICE_REMOVE
+int device_remove_children(struct udevice *dev);
+#else
+static inline int device_remove_children(struct udevice *dev) { return 0; }
+#endif
+
+/**
+ * device_unbind_children() - Unbind all device's children from the device
+ *
+ * On error, the function continues to unbind all children, and reports the
+ * first error.
+ *
+ * @dev:	The device that is to be stripped of its children
+ * @return 0 on success, -ve on error
+ */
+#ifdef CONFIG_DM_DEVICE_REMOVE
+int device_unbind_children(struct udevice *dev);
+#else
+static inline int device_unbind_children(struct udevice *dev) { return 0; }
+#endif
+
 #ifdef CONFIG_DM_DEVICE_REMOVE
 void device_free(struct udevice *dev);
 #else
diff --git a/include/dm/device.h b/include/dm/device.h
index 18296bb..9fa0048 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -386,10 +386,24 @@
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
  * @return 0 if OK, -ve on error
  */
-int device_get_child_by_of_offset(struct udevice *parent, int seq,
+int device_get_child_by_of_offset(struct udevice *parent, int of_offset,
 				  struct udevice **devp);
 
 /**
+ * device_get_global_by_of_offset() - Get a device based on FDT offset
+ *
+ * Locates a device by its device tree offset, searching globally throughout
+ * the all driver model devices.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @of_offset: Device tree offset to find
+ * @devp: Returns pointer to device if found, otherwise this is set to NULL
+ * @return 0 if OK, -ve on error
+ */
+int device_get_global_by_of_offset(int of_offset, struct udevice **devp);
+
+/**
  * device_find_first_child() - Find the first child of a device
  *
  * @parent: Parent device to search
diff --git a/include/dm/platdata.h b/include/dm/platdata.h
index fbc8a6b..6f4f001 100644
--- a/include/dm/platdata.h
+++ b/include/dm/platdata.h
@@ -16,6 +16,10 @@
 /**
  * struct driver_info - Information required to instantiate a device
  *
+ * NOTE: Avoid using this except in extreme circumstances, where device tree
+ * is not feasible (e.g. serial driver in SPL where <8KB of SRAM is
+ * available). U-Boot's driver model uses device tree for configuration.
+ *
  * @name:	Driver name
  * @platdata:	Driver-specific platform data
  */
@@ -24,6 +28,11 @@
 	const void *platdata;
 };
 
+/**
+ * NOTE: Avoid using these except in extreme circumstances, where device tree
+ * is not feasible (e.g. serial driver in SPL where <8KB of SRAM is
+ * available). U-Boot's driver model uses device tree for configuration.
+ */
 #define U_BOOT_DEVICE(__name)						\
 	ll_entry_declare(struct driver_info, __name, driver_info)
 
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index c7310d7..bc057d7 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -25,27 +25,33 @@
 	UCLASS_SIMPLE_BUS,	/* bus with child devices */
 
 	/* U-Boot uclasses start here - in alphabetical order */
+	UCLASS_CLK,		/* Clock source, e.g. used by peripherals */
 	UCLASS_CPU,		/* CPU, typically part of an SoC */
 	UCLASS_CROS_EC,		/* Chrome OS EC */
 	UCLASS_DISPLAY_PORT,	/* Display port video */
+	UCLASS_RAM,		/* RAM controller */
 	UCLASS_ETH,		/* Ethernet device */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
 	UCLASS_I2C,		/* I2C bus */
 	UCLASS_I2C_EEPROM,	/* I2C EEPROM device */
 	UCLASS_I2C_GENERIC,	/* Generic I2C device */
+	UCLASS_LED,		/* Light-emitting diode (LED) */
 	UCLASS_LPC,		/* x86 'low pin count' interface */
 	UCLASS_MASS_STORAGE,	/* Mass storage device */
+	UCLASS_MMC,		/* SD / MMC card or chip */
 	UCLASS_MOD_EXP,		/* RSA Mod Exp device */
 	UCLASS_PCH,		/* x86 platform controller hub */
 	UCLASS_PCI,		/* PCI bus */
 	UCLASS_PCI_GENERIC,	/* Generic PCI bus device */
 	UCLASS_PMIC,		/* PMIC I/O device */
 	UCLASS_REGULATOR,	/* Regulator device */
+	UCLASS_RESET,		/* Reset device */
 	UCLASS_RTC,		/* Real time clock device */
 	UCLASS_SERIAL,		/* Serial UART */
 	UCLASS_SPI,		/* SPI bus */
 	UCLASS_SPI_FLASH,	/* SPI flash */
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
+	UCLASS_SYSCON,		/* System configuration device */
 	UCLASS_THERMAL,		/* Thermal sensor */
 	UCLASS_USB,		/* USB bus */
 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
diff --git a/include/dm/util.h b/include/dm/util.h
index 0cec17b..7dbed67 100644
--- a/include/dm/util.h
+++ b/include/dm/util.h
@@ -33,4 +33,10 @@
  */
 int list_count_items(struct list_head *head);
 
+/* Dump out a tree of all devices */
+void dm_dump_all(void);
+
+/* Dump out a list of uclasses and their devices */
+void dm_dump_uclass(void);
+
 #endif
diff --git a/include/dwmmc.h b/include/dwmmc.h
index 86a5491..7a7555a 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -129,8 +129,24 @@
 /* quirks */
 #define DWMCI_QUIRK_DISABLE_SMU		(1 << 0)
 
+/**
+ * struct dwmci_host - Information about a designware MMC host
+ *
+ * @name:	Device name
+ * @ioaddr:	Base I/O address of controller
+ * @quirks:	Quick flags - see DWMCI_QUIRK_...
+ * @caps:	Capabilities - see MMC_MODE_...
+ * @bus_hz:	Bus speed in Hz, if @get_mmc_clk() is NULL
+ * @div:	Arbitrary clock divider value for use by controller
+ * @dev_index:	Arbitrary device index for use by controller
+ * @dev_id:	Arbitrary device ID for use by controller
+ * @buswidth:	Bus width in bits (8 or 4)
+ * @fifoth_val:	Value for FIFOTH register (or 0 to leave unset)
+ * @mmc:	Pointer to generic MMC structure for this device
+ * @priv:	Private pointer for use by controller
+ */
 struct dwmci_host {
-	char *name;
+	const char *name;
 	void *ioaddr;
 	unsigned int quirks;
 	unsigned int caps;
diff --git a/include/image.h b/include/image.h
index b6eb57e..63c3d37 100644
--- a/include/image.h
+++ b/include/image.h
@@ -246,6 +246,8 @@
 #define IH_TYPE_LPC32XXIMAGE	21	/* x86 setup.bin Image		*/
 #define IH_TYPE_LOADABLE	22	/* A list of typeless images	*/
 
+#define IH_TYPE_COUNT		23	/* Number of image types */
+
 /*
  * Compression Types
  */
@@ -411,6 +413,15 @@
 const char *genimg_get_os_name(uint8_t os);
 const char *genimg_get_arch_name(uint8_t arch);
 const char *genimg_get_type_name(uint8_t type);
+
+/**
+ * genimg_get_type_short_name() - get the short name for an image type
+ *
+ * @param type	Image type (IH_TYPE_...)
+ * @return image short name, or "unknown" if unknown
+ */
+const char *genimg_get_type_short_name(uint8_t type);
+
 const char *genimg_get_comp_name(uint8_t comp);
 int genimg_get_os_id(const char *name);
 int genimg_get_arch_id(const char *name);
diff --git a/include/led.h b/include/led.h
new file mode 100644
index 0000000..b929d0c
--- /dev/null
+++ b/include/led.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __LED_H
+#define __LED_H
+
+/**
+ * struct led_uclass_plat - Platform data the uclass stores about each device
+ *
+ * @label:	LED label
+ */
+struct led_uclass_plat {
+	const char *label;
+};
+
+struct led_ops {
+	/**
+	 * set_on() - set the state of an LED
+	 *
+	 * @dev:	LED device to change
+	 * @on:		1 to turn the LED on, 0 to turn it off
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*set_on)(struct udevice *dev, int on);
+};
+
+#define led_get_ops(dev)	((struct led_ops *)(dev)->driver->ops)
+
+/**
+ * led_get_by_label() - Find an LED device by label
+ *
+ * @label:	LED label to look up
+ * @devp:	Returns the associated device, if found
+ * @return 0 if found, -ENODEV if not found, other -ve on error
+ */
+int led_get_by_label(const char *label, struct udevice **devp);
+
+/**
+ * led_set_on() - set the state of an LED
+ *
+ * @dev:	LED device to change
+ * @on:		1 to turn the LED on, 0 to turn it off
+ * @return 0 if OK, -ve on error
+ */
+int led_set_on(struct udevice *dev, int on);
+
+#endif
diff --git a/include/libfdt.h b/include/libfdt.h
index 421d64f..e48c21a 100644
--- a/include/libfdt.h
+++ b/include/libfdt.h
@@ -121,7 +121,12 @@
 	/* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
 	 * or similar property with a bad format or value */
 
-#define FDT_ERR_MAX		14
+#define FDT_ERR_TOODEEP		15
+	/* FDT_ERR_TOODEEP: The depth of a node has exceeded the internal
+	 * libfdt limit. This can happen if you have more than
+	 * FDT_MAX_DEPTH nested nodes. */
+
+#define FDT_ERR_MAX		15
 
 /**********************************************************************/
 /* Low-level functions (you probably don't need these)                */
@@ -1646,11 +1651,99 @@
 
 const char *fdt_strerror(int errval);
 
+/**
+ * fdt_remove_unused_strings() - Remove any unused strings from an FDT
+ *
+ * This creates a new device tree in @new with unused strings removed. The
+ * called can then use fdt_pack() to minimise the space consumed.
+ *
+ * @old:	Old device tree blog
+ * @new:	Place to put new device tree blob, which must be as large as
+ *		@old
+ * @return
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, corrupt device tree
+ *	-FDT_ERR_NOSPACE, out of space, which should not happen unless there
+ *		is something very wrong with the device tree input
+ */
+int fdt_remove_unused_strings(const void *old, void *new);
+
 struct fdt_region {
 	int offset;
 	int size;
 };
 
+/*
+ * Flags for fdt_find_regions()
+ *
+ * Add a region for the string table (always the last region)
+ */
+#define FDT_REG_ADD_STRING_TAB		(1 << 0)
+
+/*
+ * Add all supernodes of a matching node/property, useful for creating a
+ * valid subset tree
+ */
+#define FDT_REG_SUPERNODES		(1 << 1)
+
+/* Add the FDT_BEGIN_NODE tags of subnodes, including their names */
+#define FDT_REG_DIRECT_SUBNODES	(1 << 2)
+
+/* Add all subnodes of a matching node */
+#define FDT_REG_ALL_SUBNODES		(1 << 3)
+
+/* Add a region for the mem_rsvmap table (always the first region) */
+#define FDT_REG_ADD_MEM_RSVMAP		(1 << 4)
+
+/* Indicates what an fdt part is (node, property, value) */
+#define FDT_IS_NODE			(1 << 0)
+#define FDT_IS_PROP			(1 << 1)
+#define FDT_IS_VALUE			(1 << 2)	/* not supported */
+#define FDT_IS_COMPAT			(1 << 3)	/* used internally */
+#define FDT_NODE_HAS_PROP		(1 << 4)	/* node contains prop */
+
+#define FDT_ANY_GLOBAL		(FDT_IS_NODE | FDT_IS_PROP | FDT_IS_VALUE | \
+					FDT_IS_COMPAT)
+#define FDT_IS_ANY			0x1f		/* all the above */
+
+/* We set a reasonable limit on the number of nested nodes */
+#define FDT_MAX_DEPTH			32
+
+/* Decribes what we want to include from the current tag */
+enum want_t {
+	WANT_NOTHING,
+	WANT_NODES_ONLY,		/* No properties */
+	WANT_NODES_AND_PROPS,		/* Everything for one level */
+	WANT_ALL_NODES_AND_PROPS	/* Everything for all levels */
+};
+
+/* Keeps track of the state at parent nodes */
+struct fdt_subnode_stack {
+	int offset;		/* Offset of node */
+	enum want_t want;	/* The 'want' value here */
+	int included;		/* 1 if we included this node, 0 if not */
+};
+
+struct fdt_region_ptrs {
+	int depth;			/* Current tree depth */
+	int done;			/* What we have completed scanning */
+	enum want_t want;		/* What we are currently including */
+	char *end;			/* Pointer to end of full node path */
+	int nextoffset;			/* Next node offset to check */
+};
+
+/* The state of our finding algortihm */
+struct fdt_region_state {
+	struct fdt_subnode_stack stack[FDT_MAX_DEPTH];	/* node stack */
+	struct fdt_region *region;	/* Contains list of regions found */
+	int count;			/* Numnber of regions found */
+	const void *fdt;		/* FDT blob */
+	int max_regions;		/* Maximum regions to find */
+	int can_merge;		/* 1 if we can merge with previous region */
+	int start;			/* Start position of current region */
+	struct fdt_region_ptrs ptrs;	/* Pointers for what we are up to */
+};
+
 /**
  * fdt_find_regions() - find regions in device tree
  *
@@ -1710,4 +1803,165 @@
 		     struct fdt_region region[], int max_regions,
 		     char *path, int path_len, int add_string_tab);
 
+/**
+ * fdt_first_region() - find regions in device tree
+ *
+ * Given a nodes and properties to include and properties to exclude, find
+ * the regions of the device tree which describe those included parts.
+ *
+ * The use for this function is twofold. Firstly it provides a convenient
+ * way of performing a structure-aware grep of the tree. For example it is
+ * possible to grep for a node and get all the properties associated with
+ * that node. Trees can be subsetted easily, by specifying the nodes that
+ * are required, and then writing out the regions returned by this function.
+ * This is useful for small resource-constrained systems, such as boot
+ * loaders, which want to use an FDT but do not need to know about all of
+ * it.
+ *
+ * Secondly it makes it easy to hash parts of the tree and detect changes.
+ * The intent is to get a list of regions which will be invariant provided
+ * those parts are invariant. For example, if you request a list of regions
+ * for all nodes but exclude the property "data", then you will get the
+ * same region contents regardless of any change to "data" properties.
+ *
+ * This function can be used to produce a byte-stream to send to a hashing
+ * function to verify that critical parts of the FDT have not changed.
+ * Note that semantically null changes in order could still cause false
+ * hash misses. Such reordering might happen if the tree is regenerated
+ * from source, and nodes are reordered (the bytes-stream will be emitted
+ * in a different order and mnay hash functions will detect this). However
+ * if an existing tree is modified using libfdt functions, such as
+ * fdt_add_subnode() and fdt_setprop(), then this problem is avoided.
+ *
+ * The nodes/properties to include/exclude are defined by a function
+ * provided by the caller. This function is called for each node and
+ * property, and must return:
+ *
+ *    0 - to exclude this part
+ *    1 - to include this part
+ *   -1 - for FDT_IS_PROP only: no information is available, so include
+ *		if its containing node is included
+ *
+ * The last case is only used to deal with properties. Often a property is
+ * included if its containing node is included - this is the case where
+ * -1 is returned.. However if the property is specifically required to be
+ * included/excluded, then 0 or 1 can be returned. Note that including a
+ * property when the FDT_REG_SUPERNODES flag is given will force its
+ * containing node to be included since it is not valid to have a property
+ * that is not in a node.
+ *
+ * Using the information provided, the inclusion of a node can be controlled
+ * either by a node name or its compatible string, or any other property
+ * that the function can determine.
+ *
+ * As an example, including node "/" means to include the root node and all
+ * root properties. A flag provides a way of also including supernodes (of
+ * which there is none for the root node), and another flag includes
+ * immediate subnodes, so in this case we would get the FDT_BEGIN_NODE and
+ * FDT_END_NODE of all subnodes of /.
+ *
+ * The subnode feature helps in a hashing situation since it prevents the
+ * root node from changing at all. Any change to non-excluded properties,
+ * names of subnodes or number of subnodes would be detected.
+ *
+ * When used with FITs this provides the ability to hash and sign parts of
+ * the FIT based on different configurations in the FIT. Then it is
+ * impossible to change anything about that configuration (include images
+ * attached to the configuration), but it may be possible to add new
+ * configurations, new images or new signatures within the existing
+ * framework.
+ *
+ * Adding new properties to a device tree may result in the string table
+ * being extended (if the new property names are different from those
+ * already added). This function can optionally include a region for
+ * the string table so that this can be part of the hash too. This is always
+ * the last region.
+ *
+ * The FDT also has a mem_rsvmap table which can also be included, and is
+ * always the first region if so.
+ *
+ * The device tree header is not included in the region list. Since the
+ * contents of the FDT are changing (shrinking, often), the caller will need
+ * to regenerate the header anyway.
+ *
+ * @fdt:	Device tree to check
+ * @h_include:	Function to call to determine whether to include a part or
+ *		not:
+ *
+ *		@priv: Private pointer as passed to fdt_find_regions()
+ *		@fdt: Pointer to FDT blob
+ *		@offset: Offset of this node / property
+ *		@type: Type of this part, FDT_IS_...
+ *		@data: Pointer to data (node name, property name, compatible
+ *			string, value (not yet supported)
+ *		@size: Size of data, or 0 if none
+ *		@return 0 to exclude, 1 to include, -1 if no information is
+ *		available
+ * @priv:	Private pointer passed to h_include
+ * @region:	Returns list of regions, sorted by offset
+ * @max_regions: Maximum length of region list
+ * @path:	Pointer to a temporary string for the function to use for
+ *		building path names
+ * @path_len:	Length of path, must be large enough to hold the longest
+ *		path in the tree
+ * @flags:	Various flags that control the region algortihm, see
+ *		FDT_REG_...
+ * @return number of regions in list. If this is >max_regions then the
+ * region array was exhausted. You should increase max_regions and try
+ * the call again. Only the first max_regions elements are available in the
+ * array.
+ *
+ * On error a -ve value is return, which can be:
+ *
+ *	-FDT_ERR_BADSTRUCTURE (too deep or more END tags than BEGIN tags
+ *	-FDT_ERR_BADLAYOUT
+ *	-FDT_ERR_NOSPACE (path area is too small)
+ */
+int fdt_first_region(const void *fdt,
+		int (*h_include)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		void *priv, struct fdt_region *region,
+		char *path, int path_len, int flags,
+		struct fdt_region_state *info);
+
+/** fdt_next_region() - find next region
+ *
+ * See fdt_first_region() for full description. This function finds the
+ * next region according to the provided parameters, which must be the same
+ * as passed to fdt_first_region().
+ *
+ * This function can additionally return -FDT_ERR_NOTFOUND when there are no
+ * more regions
+ */
+int fdt_next_region(const void *fdt,
+		int (*h_include)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		void *priv, struct fdt_region *region,
+		char *path, int path_len, int flags,
+		struct fdt_region_state *info);
+
+/**
+ * fdt_add_alias_regions() - find aliases that point to existing regions
+ *
+ * Once a device tree grep is complete some of the nodes will be present
+ * and some will have been dropped. This function checks all the alias nodes
+ * to figure out which points point to nodes which are still present. These
+ * aliases need to be kept, along with the nodes they reference.
+ *
+ * Given a list of regions function finds the aliases that still apply and
+ * adds more regions to the list for these. This function is called after
+ * fdt_next_region() has finished returning regions and requires the same
+ * state.
+ *
+ * @fdt:	Device tree file to reference
+ * @region:	List of regions that will be kept
+ * @count:	Number of regions
+ * @max_regions: Number of entries that can fit in @region
+ * @info:	Region state as returned from fdt_next_region()
+ * @return new number of regions in @region (i.e. count + the number added)
+ * or -FDT_ERR_NOSPACE if there was not enough space.
+ */
+int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
+			  int max_regions, struct fdt_region_state *info);
+
 #endif /* _LIBFDT_H */
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 6ff3915..fbebf91 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -36,10 +36,25 @@
 #define KERN_INFO
 #define KERN_DEBUG
 
+#define GFP_ATOMIC ((gfp_t) 0)
+#define GFP_KERNEL ((gfp_t) 0)
+#define GFP_NOFS ((gfp_t) 0)
+#define GFP_USER ((gfp_t) 0)
+#define __GFP_NOWARN ((gfp_t) 0)
+#define __GFP_ZERO	((__force gfp_t)0x8000u)	/* Return zeroed page on success */
+
 void *kmalloc(size_t size, int flags);
-void *kzalloc(size_t size, int flags);
+
+static inline void *kzalloc(size_t size, gfp_t flags)
+{
+	return kmalloc(size, flags | __GFP_ZERO);
+}
 #define vmalloc(size)	kmalloc(size, 0)
 #define __vmalloc(size, flags, pgsz)	kmalloc(size, flags)
+static inline void *vzalloc(unsigned long size)
+{
+	return kzalloc(size, 0);
+}
 #define kfree(ptr)	free(ptr)
 #define vfree(ptr)	free(ptr)
 
@@ -73,13 +88,6 @@
 /* drivers/char/random.c */
 #define get_random_bytes(...)
 
-/* idr.c */
-#define GFP_ATOMIC ((gfp_t) 0)
-#define GFP_KERNEL ((gfp_t) 0)
-#define GFP_NOFS ((gfp_t) 0)
-#define GFP_USER ((gfp_t) 0)
-#define __GFP_NOWARN ((gfp_t) 0)
-
 /* include/linux/leds.h */
 struct led_trigger {};
 
@@ -189,8 +197,6 @@
 unsigned long copy_from_user(void *dest, const void *src,
 			     unsigned long count);
 
-void *vzalloc(unsigned long size);
-
 typedef unused_t spinlock_t;
 typedef int	wait_queue_head_t;
 
@@ -315,8 +321,6 @@
 
 typedef unsigned long dmaaddr_t;
 
-#define cpu_relax() do {} while (0)
-
 #define pm_runtime_get_sync(dev) do {} while (0)
 #define pm_runtime_put(dev) do {} while (0)
 #define pm_runtime_put_sync(dev) do {} while (0)
diff --git a/include/mmc.h b/include/mmc.h
index dd98b3b..cda9a19 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -266,6 +266,28 @@
 #define MMC_NUM_BOOT_PARTITION	2
 #define MMC_PART_RPMB           3       /* RPMB partition number */
 
+/* Driver model support */
+
+/**
+ * struct mmc_uclass_priv - Holds information about a device used by the uclass
+ */
+struct mmc_uclass_priv {
+	struct mmc *mmc;
+};
+
+/**
+ * mmc_get_mmc_dev() - get the MMC struct pointer for a device
+ *
+ * Provided that the device is already probed and ready for use, this value
+ * will be available.
+ *
+ * @dev:	Device
+ * @return associated mmc struct pointer if available, else NULL
+ */
+struct mmc *mmc_get_mmc_dev(struct udevice *dev);
+
+/* End of driver model support */
+
 struct mmc_cid {
 	unsigned long psn;
 	unsigned short oid;
diff --git a/include/net.h b/include/net.h
index d17173d..d09bec9 100644
--- a/include/net.h
+++ b/include/net.h
@@ -93,6 +93,14 @@
 	int phy_interface;
 };
 
+enum eth_recv_flags {
+	/*
+	 * Check hardware device for new packets (otherwise only return those
+	 * which are already in the memory buffer ready to process)
+	 */
+	ETH_RECV_CHECK_DEVICE		= 1 << 0,
+};
+
 /**
  * struct eth_ops - functions of Ethernet MAC controllers
  *
@@ -111,7 +119,9 @@
  * mcast: Join or leave a multicast group (for TFTP) - optional
  * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux
  *		 on some platforms like ARM). This function expects the
- *		 eth_pdata::enetaddr field to be populated - optional
+ *		 eth_pdata::enetaddr field to be populated. The method can
+ *		 return -ENOSYS to indicate that this is not implemented for
+		 this hardware - optional.
  * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a
  *		    ROM on the board. This is how the driver should expose it
  *		    to the network stack. This function should fill in the
@@ -120,7 +130,7 @@
 struct eth_ops {
 	int (*start)(struct udevice *dev);
 	int (*send)(struct udevice *dev, void *packet, int length);
-	int (*recv)(struct udevice *dev, uchar **packetp);
+	int (*recv)(struct udevice *dev, int flags, uchar **packetp);
 	int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
 	void (*stop)(struct udevice *dev);
 #ifdef CONFIG_MCAST_TFTP
diff --git a/include/pci.h b/include/pci.h
index 542e68b..94bca97 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -468,7 +468,10 @@
 #define PCI_ANY_ID		(~0)
 
 struct pci_device_id {
-	unsigned int vendor, device;		/* Vendor and device ID or PCI_ANY_ID */
+	unsigned int vendor, device;	/* Vendor and device ID or PCI_ANY_ID */
+	unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
+	unsigned int class, class_mask;	/* (class,subclass,prog-if) triplet */
+	unsigned long driver_data;	/* Data private to the driver */
 };
 
 struct pci_controller;
@@ -805,6 +808,14 @@
 #define pci_get_ops(dev)	((struct dm_pci_ops *)(dev)->driver->ops)
 
 /**
+ * pci_get_bdf() - Get the BDF value for a device
+ *
+ * @dev:	Device to check
+ * @return bus/device/function value (see PCI_BDF())
+ */
+pci_dev_t pci_get_bdf(struct udevice *dev);
+
+/**
  * pci_bind_bus_devices() - scan a PCI bus and bind devices
  *
  * Scan a PCI bus looking for devices. Bind each one that is found. If
@@ -1101,7 +1112,79 @@
 int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn,
 			 struct udevice **emulp);
 
-#endif
+#endif /* CONFIG_DM_PCI */
+
+/**
+ * PCI_DEVICE - macro used to describe a specific pci device
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device.  The subvendor and subdevice fields will be set to
+ * PCI_ANY_ID.
+ */
+#define PCI_DEVICE(vend, dev) \
+	.vendor = (vend), .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+/**
+ * PCI_DEVICE_SUB - macro used to describe a specific pci device with subsystem
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ * @subvend: the 16 bit PCI Subvendor ID
+ * @subdev: the 16 bit PCI Subdevice ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device with subsystem information.
+ */
+#define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \
+	.vendor = (vend), .device = (dev), \
+	.subvendor = (subvend), .subdevice = (subdev)
+
+/**
+ * PCI_DEVICE_CLASS - macro used to describe a specific pci device class
+ * @dev_class: the class, subclass, prog-if triple for this device
+ * @dev_class_mask: the class mask for this device
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI class.  The vendor, device, subvendor, and subdevice
+ * fields will be set to PCI_ANY_ID.
+ */
+#define PCI_DEVICE_CLASS(dev_class, dev_class_mask) \
+	.class = (dev_class), .class_mask = (dev_class_mask), \
+	.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+/**
+ * PCI_VDEVICE - macro used to describe a specific pci device in short form
+ * @vend: the vendor name
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI device.  The subvendor, and subdevice fields will be set
+ * to PCI_ANY_ID. The macro allows the next field to follow as the device
+ * private data.
+ */
+
+#define PCI_VDEVICE(vend, dev) \
+	.vendor = PCI_VENDOR_ID_##vend, .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0
+
+/**
+ * struct pci_driver_entry - Matches a driver to its pci_device_id list
+ * @driver: Driver to use
+ * @match: List of match records for this driver, terminated by {}
+ */
+struct pci_driver_entry {
+	struct driver *driver;
+	const struct pci_device_id *match;
+};
+
+#define U_BOOT_PCI_DEVICE(__name, __match)				\
+	ll_entry_declare(struct pci_driver_entry, __name, pci_driver_entry) = {\
+		.driver = llsym(struct driver, __name, driver), \
+		.match = __match, \
+		}
 
 #endif /* __ASSEMBLY__ */
 #endif /* _PCI_H */
diff --git a/include/power/pmic.h b/include/power/pmic.h
index eb152ef..6ba4b6e 100644
--- a/include/power/pmic.h
+++ b/include/power/pmic.h
@@ -264,6 +264,40 @@
  */
 int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len);
 int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len);
+
+/**
+ * pmic_reg_read() - read a PMIC register value
+ *
+ * @dev:	PMIC device to read
+ * @reg:	Register to read
+ * @return value read on success or negative value of errno.
+ */
+int pmic_reg_read(struct udevice *dev, uint reg);
+
+/**
+ * pmic_reg_write() - write a PMIC register value
+ *
+ * @dev:	PMIC device to write
+ * @reg:	Register to write
+ * @value:	Value to write
+ * @return 0 on success or negative value of errno.
+ */
+int pmic_reg_write(struct udevice *dev, uint reg, uint value);
+
+/**
+ * pmic_clrsetbits() - clear and set bits in a PMIC register
+ *
+ * This reads a register, optionally clears some bits, optionally sets some
+ * bits, then writes the register.
+ *
+ * @dev:	PMIC device to update
+ * @reg:	Register to update
+ * @clr:	Bit mask to clear (set those bits that you want cleared)
+ * @set:	Bit mask to set (set those bits that you want set)
+ * @return 0 on success or negative value of errno.
+ */
+int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set);
+
 #endif /* CONFIG_DM_PMIC */
 
 #ifdef CONFIG_POWER
diff --git a/include/power/regulator.h b/include/power/regulator.h
index 03a2cef..0152290 100644
--- a/include/power/regulator.h
+++ b/include/power/regulator.h
@@ -128,6 +128,11 @@
 	const char *name;
 };
 
+enum regulator_flag {
+	REGULATOR_FLAG_AUTOSET_UV	= 1 << 0,
+	REGULATOR_FLAG_AUTOSET_UA	= 1 << 1,
+};
+
 /**
  * struct dm_regulator_uclass_platdata - pointed by dev->uclass_platdata, and
  * allocated on each regulator bind. This structure holds an information
@@ -143,6 +148,8 @@
  * @max_uA*    - maximum amperage (micro Amps)
  * @always_on* - bool type, true or false
  * @boot_on*   - bool type, true or false
+ * TODO(sjg@chromium.org): Consider putting the above two into @flags
+ * @flags:     - flags value (see REGULATOR_FLAG_...)
  * @name**     - fdt regulator name - should be taken from the device tree
  *
  * Note:
@@ -162,6 +169,7 @@
 	bool always_on;
 	bool boot_on;
 	const char *name;
+	int flags;
 };
 
 /* Regulator device operations */
@@ -308,9 +316,39 @@
 int regulator_set_mode(struct udevice *dev, int mode_id);
 
 /**
- * regulator_autoset: setup the regulator given by its uclass's platform data
- * name field. The setup depends on constraints found in device's uclass's
- * platform data (struct dm_regulator_uclass_platdata):
+ * regulators_enable_boot_on() - enable regulators needed for boot
+ *
+ * This enables all regulators which are marked to be on at boot time. This
+ * only works for regulators which don't have a range for voltage/current,
+ * since in that case it is not possible to know which value to use.
+ *
+ * This effectively calls regulator_autoset() for every regulator.
+ */
+int regulators_enable_boot_on(bool verbose);
+
+/**
+ * regulator_autoset: setup the voltage/current on a regulator
+ *
+ * The setup depends on constraints found in device's uclass's platform data
+ * (struct dm_regulator_uclass_platdata):
+ *
+ * - Enable - will set - if any of: 'always_on' or 'boot_on' is set to true,
+ *   or if both are unset, then the function returns
+ * - Voltage value - will set - if '.min_uV' and '.max_uV' values are equal
+ * - Current limit - will set - if '.min_uA' and '.max_uA' values are equal
+ *
+ * The function returns on the first-encountered error.
+ *
+ * @platname - expected string for dm_regulator_uclass_platdata .name field
+ * @devp     - returned pointer to the regulator device - if non-NULL passed
+ * @return: 0 on success or negative value of errno.
+ */
+int regulator_autoset(struct udevice *dev);
+
+/**
+ * regulator_autoset_by_name: setup the regulator given by its uclass's
+ * platform data name field. The setup depends on constraints found in device's
+ * uclass's platform data (struct dm_regulator_uclass_platdata):
  * - Enable - will set - if any of: 'always_on' or 'boot_on' is set to true,
  *   or if both are unset, then the function returns
  * - Voltage value - will set - if '.min_uV' and '.max_uV' values are equal
@@ -320,21 +358,18 @@
  *
  * @platname - expected string for dm_regulator_uclass_platdata .name field
  * @devp     - returned pointer to the regulator device - if non-NULL passed
- * @verbose  - (true/false) print regulator setup info, or be quiet
  * @return: 0 on success or negative value of errno.
  *
  * The returned 'regulator' device can be used with:
  * - regulator_get/set_*
  */
-int regulator_autoset(const char *platname,
-		      struct udevice **devp,
-		      bool verbose);
+int regulator_autoset_by_name(const char *platname, struct udevice **devp);
 
 /**
  * regulator_list_autoset: setup the regulators given by list of their uclass's
  * platform data name field. The setup depends on constraints found in device's
  * uclass's platform data. The function loops with calls to:
- * regulator_autoset() for each name from the list.
+ * regulator_autoset_by_name() for each name from the list.
  *
  * @list_platname - an array of expected strings for .name field of each
  *                  regulator's uclass platdata
@@ -375,7 +410,7 @@
  * Search by name, found in regulator uclass platdata.
  *
  * @platname - expected string for uc_pdata->name of regulator uclass platdata
- * @devp     - returned pointer to the regulator device
+ * @devp     - returns pointer to the regulator device or NULL on error
  * @return 0 on success or negative value of errno.
  *
  * The returned 'regulator' device is probed and can be used with:
diff --git a/include/power/sandbox_pmic.h b/include/power/sandbox_pmic.h
index ae14292..8547674 100644
--- a/include/power/sandbox_pmic.h
+++ b/include/power/sandbox_pmic.h
@@ -117,11 +117,11 @@
 
 /*
  * Expected regulators setup after call of:
- * - regulator_autoset()
+ * - regulator_autoset_by_name()
  * - regulator_list_autoset()
  */
 
-/* BUCK1: for testing regulator_autoset() */
+/* BUCK1: for testing regulator_autoset_by_name() */
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_UV	1200000
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_UA	200000
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_ENABLE	true
diff --git a/include/ram.h b/include/ram.h
new file mode 100644
index 0000000..e2172a8
--- /dev/null
+++ b/include/ram.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __RAM_H
+#define __RAM_H
+
+struct ram_info {
+	phys_addr_t base;
+	size_t size;
+};
+
+struct ram_ops {
+	/**
+	 * get_info() - Get basic memory info
+	 *
+	 * @dev:	Device to check (UCLASS_RAM)
+	 * @info:	Place to put info
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*get_info)(struct udevice *dev, struct ram_info *info);
+};
+
+#define ram_get_ops(dev)        ((struct ram_ops *)(dev)->driver->ops)
+
+/**
+ * ram_get_info() - Get information about a RAM device
+ *
+ * @dev:	Device to check (UCLASS_RAM)
+ * @info:	Returns RAM info
+ * @return 0 if OK, -ve on error
+ */
+int ram_get_info(struct udevice *dev, struct ram_info *info);
+
+#endif
diff --git a/include/rc4.h b/include/rc4.h
new file mode 100644
index 0000000..ea409c2
--- /dev/null
+++ b/include/rc4.h
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __RC4_H
+#define __RC4_H
+
+/**
+ * rc4_encode() - encode a buf with the RC4 cipher
+ *
+ * @buf:	Buffer to encode (it is overwrite in the process
+ * @len:	Length of buffer in bytes
+ * @key:	16-byte key to use
+ */
+void rc4_encode(unsigned char *buf, unsigned int len, unsigned char key[16]);
+
+#endif
diff --git a/include/regmap.h b/include/regmap.h
new file mode 100644
index 0000000..eccf770
--- /dev/null
+++ b/include/regmap.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __REGMAP_H
+#define __REGMAP_H
+
+/**
+ * struct regmap_range - a register map range
+ *
+ * @start:	Start address
+ * @size:	Size in bytes
+ */
+struct regmap_range {
+	ulong start;
+	ulong size;
+};
+
+/**
+ * struct regmap - a way of accessing hardware/bus registers
+ *
+ * @base:	Base address of register map
+ * @range_count: Number of ranges available within the map
+ * @range:	Pointer to the list of ranges, allocated if @range_count > 1
+ * @base_range:	If @range_count is <= 1, @range points here
+ */
+struct regmap {
+	phys_addr_t base;
+	int range_count;
+	struct regmap_range *range, base_range;
+};
+
+/*
+ * Interface to provide access to registers either through a direct memory
+ * bus or through a peripheral bus like I2C, SPI.
+ */
+int regmap_write(struct regmap *map, uint offset, uint val);
+int regmap_read(struct regmap *map, uint offset, uint *valp);
+
+#define regmap_write32(map, ptr, member, val) \
+	regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val)
+
+#define regmap_read32(map, ptr, member, valp) \
+	regmap_read(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), valp)
+
+/**
+ * regmap_init_mem() - Set up a new register map that uses memory access
+ *
+ * Use regmap_uninit() to free it.
+ *
+ * @dev:	Device that uses this map
+ * @mapp:	Returns allocated map
+ */
+int regmap_init_mem(struct udevice *dev, struct regmap **mapp);
+
+/**
+ * regmap_get_range() - Obtain the base memory address of a regmap range
+ *
+ * @map:	Regmap to query
+ * @range_num:	Range to look up
+ */
+void *regmap_get_range(struct regmap *map, unsigned int range_num);
+
+/**
+ * regmap_uninit() - free a previously inited regmap
+ */
+int regmap_uninit(struct regmap *map);
+
+#endif
diff --git a/include/reset.h b/include/reset.h
new file mode 100644
index 0000000..383761e
--- /dev/null
+++ b/include/reset.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __RESET_H
+#define __RESET_H
+
+enum reset_t {
+	RESET_WARM,	/* Reset CPU, keep GPIOs active */
+	RESET_COLD,	/* Reset CPU and GPIOs */
+	RESET_POWER,	/* Reset PMIC (remove and restore power) */
+
+	RESET_COUNT,
+};
+
+struct reset_ops {
+	/**
+	 * request() - request a reset of the given type
+	 *
+	 * Note that this function may return before the reset takes effect.
+	 *
+	 * @type:	Reset type to request
+	 * @return -EINPROGRESS if the reset has been started and
+	 *		will complete soon, -EPROTONOSUPPORT if not supported
+	 *		by this device, 0 if the reset has already happened
+	 *		(in which case this method will not actually return)
+	 */
+	int (*request)(struct udevice *dev, enum reset_t type);
+};
+
+#define reset_get_ops(dev)        ((struct reset_ops *)(dev)->driver->ops)
+
+/**
+ * reset_request() - request a reset
+ *
+ * @type:	Reset type to request
+ * @return 0 if OK, -EPROTONOSUPPORT if not supported by this device
+ */
+int reset_request(struct udevice *dev, enum reset_t type);
+
+/**
+ * reset_walk() - cause a reset
+ *
+ * This works through the available reset devices until it finds one that can
+ * perform a reset. If the provided reset type is not available, the next one
+ * will be tried.
+ *
+ * If this function fails to reset, it will display a message and halt
+ *
+ * @type:	Reset type to request
+ * @return -EINPROGRESS if a reset is in progress, -ENOSYS if not available
+ */
+int reset_walk(enum reset_t type);
+
+/**
+ * reset_walk_halt() - try to reset, otherwise halt
+ *
+ * This calls reset_walk(). If it returns, indicating that reset is not
+ * supported, it prints a message and halts.
+ */
+void reset_walk_halt(enum reset_t type);
+
+/**
+ * reset_cpu() - calls reset_walk(RESET_WARM)
+ */
+void reset_cpu(ulong addr);
+
+#endif
diff --git a/include/spl.h b/include/spl.h
index d19940f..8e53426 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -81,6 +81,18 @@
 int spl_load_image_ext(block_dev_desc_t *block_dev, int partition, const char *filename);
 int spl_load_image_ext_os(block_dev_desc_t *block_dev, int partition);
 
+/**
+ * spl_init() - Set up device tree and driver model in SPL if enabled
+ *
+ * Call this function in board_init_f() if you want to use device tree and
+ * driver model early, before board_init_r() is called. This function will
+ * be called from board_init_r() if not called earlier.
+ *
+ * If this is not called, then driver model will be inactive in SPL's
+ * board_init_f(), and no device tree will be available.
+ */
+int spl_init(void);
+
 #ifdef CONFIG_SPL_BOARD_INIT
 void spl_board_init(void);
 #endif
diff --git a/include/syscon.h b/include/syscon.h
new file mode 100644
index 0000000..c62ccd6
--- /dev/null
+++ b/include/syscon.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __SYSCON_H
+#define __SYSCON_H
+
+/**
+ * struct syscon_uc_info - Information stored by the syscon UCLASS_UCLASS
+ *
+ * @regmap:	Register map for this controller
+ */
+struct syscon_uc_info {
+	struct regmap *regmap;
+};
+
+/* So far there are no ops so this is a placeholder */
+struct syscon_ops {
+};
+
+#define syscon_get_ops(dev)        ((struct syscon_ops *)(dev)->driver->ops)
+
+/**
+ * syscon_get_regmap() - Get access to a register map
+ *
+ * @dev:	Device to check (UCLASS_SCON)
+ * @info:	Returns regmap for the device
+ * @return 0 if OK, -ve on error
+ */
+struct regmap *syscon_get_regmap(struct udevice *dev);
+
+/**
+ * syscon_get_regmap_by_driver_data() - Look up a controller by its ID
+ *
+ * Each system controller can be accessed by its driver data, which is
+ * assumed to be unique through the scope of all system controllers that
+ * are in use. This function looks up the regmap given this driver data.
+ *
+ * @driver_data:	Driver data value to look up
+ * @return register map correponding to @driver_data, or -ve error code
+ */
+struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data);
+
+/**
+ * syscon_get_first_range() - get the first memory range from a syscon regmap
+ *
+ * @driver_data:	Driver data value to look up
+ * @return first region of register map correponding to @driver_data, or
+ *			-ve error code
+ */
+void *syscon_get_first_range(ulong driver_data);
+
+#endif
diff --git a/include/test/ut.h b/include/test/ut.h
index 5e5aa6c..da7c1a9 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -9,6 +9,8 @@
 #ifndef __TEST_UT_H
 #define __TEST_UT_H
 
+#include <linux/err.h>
+
 struct unit_test_state;
 
 /**
@@ -101,6 +103,19 @@
 	}								\
 }
 
+/* Assert that a pointer is not an error pointer */
+#define ut_assertok_ptr(expr) {					\
+	const void *val = (expr);					\
+									\
+	if (IS_ERR(val)) {						\
+		ut_failf(uts, __FILE__, __LINE__, __func__,		\
+			 #expr " = NULL",				\
+			 "Expected pointer, got error %ld",		\
+			 PTR_ERR(val));					\
+		return CMD_RET_FAILURE;					\
+	}								\
+}
+
 /* Assert that an operation succeeds (returns 0) */
 #define ut_assertok(cond)	ut_asserteq(0, cond)
 
diff --git a/include/usb.h b/include/usb.h
index dca512d..cf00ffd 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -175,9 +175,9 @@
 int usb_lowlevel_stop(int index);
 
 #if defined(CONFIG_MUSB_HOST) || defined(CONFIG_DM_USB)
-int usb_reset_root_port(void);
+int usb_reset_root_port(struct usb_device *dev);
 #else
-#define usb_reset_root_port()
+#define usb_reset_root_port(dev)
 #endif
 
 int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
@@ -493,15 +493,31 @@
 
 /**
  * struct usb_driver_entry - Matches a driver to its usb_device_ids
- * @compatible: Compatible string
- * @data: Data for this compatible string
+ * @driver: Driver to use
+ * @match: List of match records for this driver, terminated by {}
  */
 struct usb_driver_entry {
 	struct driver *driver;
 	const struct usb_device_id *match;
 };
 
-#define USB_DEVICE(__name, __match)					\
+#define USB_DEVICE_ID_MATCH_DEVICE \
+		(USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
+
+/**
+ * USB_DEVICE - macro used to describe a specific usb device
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific device.
+ */
+#define USB_DEVICE(vend, prod) \
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
+	.idVendor = (vend), \
+	.idProduct = (prod)
+
+#define U_BOOT_USB_DEVICE(__name, __match) \
 	ll_entry_declare(struct usb_driver_entry, __name, usb_driver_entry) = {\
 		.driver = llsym(struct driver, __name, driver), \
 		.match = __match, \
@@ -705,15 +721,16 @@
 	 * is read). This should be NULL for EHCI, which does not need this.
 	 */
 	int (*alloc_device)(struct udevice *bus, struct usb_device *udev);
+
+	/**
+	 * reset_root_port() - Reset usb root port
+	 */
+	int (*reset_root_port)(struct udevice *bus, struct usb_device *udev);
 };
 
 #define usb_get_ops(dev)	((struct dm_usb_ops *)(dev)->driver->ops)
 #define usb_get_emul_ops(dev)	((struct dm_usb_ops *)(dev)->driver->ops)
 
-#ifdef CONFIG_MUSB_HOST
-int usb_reset_root_port(void);
-#endif
-
 /**
  * usb_get_dev_index() - look up a device index number
  *
@@ -730,26 +747,18 @@
 struct usb_device *usb_get_dev_index(struct udevice *bus, int index);
 
 /**
- * usb_legacy_port_reset() - Legacy function to reset a hub port
- *
- * @hub:	Hub device
- * @portnr:	Port number (1=first)
- */
-int usb_legacy_port_reset(struct usb_device *hub, int portnr);
-
-/**
  * usb_setup_device() - set up a device ready for use
  *
  * @dev:	USB device pointer. This need not be a real device - it is
  *		common for it to just be a local variable with its ->dev
- *		member (i.e. @dev->dev) set to the parent device
+ *		member (i.e. @dev->dev) set to the parent device and
+ *		dev->portnr set to the port number on the hub (1=first)
  * @do_read:	true to read the device descriptor before an address is set
  *		(should be false for XHCI buses, true otherwise)
  * @parent:	Parent device (either UCLASS_USB or UCLASS_USB_HUB)
- * @portnr:	Port number on hub (1=first) or 0 for none
  * @return 0 if OK, -ve on error */
 int usb_setup_device(struct usb_device *dev, bool do_read,
-		     struct usb_device *parent, int portnr);
+		     struct usb_device *parent);
 
 /**
  * usb_hub_scan() - Scan a hub and find its devices
diff --git a/include/usb_ether.h b/include/usb_ether.h
index 23507e1..c6d1416 100644
--- a/include/usb_ether.h
+++ b/include/usb_ether.h
@@ -19,25 +19,91 @@
 #define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
 #define ETH_FRAME_LEN	PKTSIZE_ALIGN	/* Max. octets in frame sans FCS */
 
+/* TODO(sjg@chromium.org): Remove @pusb_dev when all boards use CONFIG_DM_ETH */
 struct ueth_data {
 	/* eth info */
-	struct eth_device eth_dev;		/* used with eth_register */
-	int phy_id;						/* mii phy id */
+#ifdef CONFIG_DM_ETH
+	uint8_t *rxbuf;
+	int rxsize;
+	int rxlen;			/* Total bytes available in rxbuf */
+	int rxptr;			/* Current position in rxbuf */
+#else
+	struct eth_device eth_dev;	/* used with eth_register */
+	/* driver private */
+	void *dev_priv;
+#endif
+	int phy_id;			/* mii phy id */
 
 	/* usb info */
 	struct usb_device *pusb_dev;	/* this usb_device */
-	unsigned char	ifnum;			/* interface number */
-	unsigned char	ep_in;			/* in endpoint */
-	unsigned char	ep_out;			/* out ....... */
-	unsigned char	ep_int;			/* interrupt . */
-	unsigned char	subclass;		/* as in overview */
-	unsigned char	protocol;		/* .............. */
+	unsigned char	ifnum;		/* interface number */
+	unsigned char	ep_in;		/* in endpoint */
+	unsigned char	ep_out;		/* out ....... */
+	unsigned char	ep_int;		/* interrupt . */
+	unsigned char	subclass;	/* as in overview */
+	unsigned char	protocol;	/* .............. */
 	unsigned char	irqinterval;	/* Intervall for IRQ Pipe */
-
-	/* driver private */
-	void *dev_priv;
 };
 
+#ifdef CONFIG_DM_ETH
+/**
+ * usb_ether_register() - register a new USB ethernet device
+ *
+ * This selects the correct USB interface and figures out the endpoints to use.
+ *
+ * @dev:	USB device
+ * @ss:		Place to put USB ethernet data
+ * @rxsize:	Maximum size to allocate for the receive buffer
+ * @return 0 if OK, -ve on error
+ */
+int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize);
+
+/**
+ * usb_ether_deregister() - deregister a USB ethernet device
+ *
+ * @ueth:	USB Ethernet device
+ * @return 0
+ */
+int usb_ether_deregister(struct ueth_data *ueth);
+
+/**
+ * usb_ether_receive() - recieve a packet from the bulk in endpoint
+ *
+ * The packet is stored in the internal buffer ready for processing.
+ *
+ * @ueth:	USB Ethernet device
+ * @rxsize:	Maximum size to receive
+ * @return 0 if a packet was received, -EAGAIN if not, -ENOSPC if @rxsize is
+ * larger than the size passed ot usb_ether_register(), other -ve on error
+ */
+int usb_ether_receive(struct ueth_data *ueth, int rxsize);
+
+/**
+ * usb_ether_get_rx_bytes() - obtain bytes from the internal packet buffer
+ *
+ * This should be called repeatedly to obtain packet data until it returns 0.
+ * After each packet is processed, call usb_ether_advance_rxbuf() to move to
+ * the next one.
+ *
+ * @ueth:	USB Ethernet device
+ * @ptrp:	Returns a pointer to the start of the next packet if there is
+ *		one available
+ * @return number of bytes available, or 0 if none
+ */
+int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp);
+
+/**
+ * usb_ether_advance_rxbuf() - Advance to the next packet in the internal buffer
+ *
+ * After processing the data returned by usb_ether_get_rx_bytes(), call this
+ * function to move to the next packet. You must specify the number of bytes
+ * you have processed in @num_bytes.
+ *
+ * @ueth:	USB Ethernet device
+ * @num_bytes:	Number of bytes to skip, or -1 to skip all bytes
+ */
+void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes);
+#else
 /*
  * Function definitions for each USB ethernet driver go here
  * (declaration is unconditional, compilation is conditional)
@@ -65,5 +131,6 @@
 			struct ueth_data *ss);
 int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
 			struct eth_device *eth);
+#endif
 
 #endif /* __USB_ETHER_H__ */
diff --git a/include/vsprintf.h b/include/vsprintf.h
index d2fcca3..b5bc9c1 100644
--- a/include/vsprintf.h
+++ b/include/vsprintf.h
@@ -41,6 +41,32 @@
 long simple_strtol(const char *cp, char **endp, unsigned int base);
 
 /**
+ * trailing_strtol() - extract a trailing integer from a string
+ *
+ * Given a string this finds a trailing number on the string and returns it.
+ * For example, "abc123" would return 123.
+ *
+ * @str:	String to exxamine
+ * @return training number if found, else -1
+ */
+long trailing_strtol(const char *str);
+
+/**
+ * trailing_strtoln() - extract a trailing integer from a fixed-length string
+ *
+ * Given a fixed-length string this finds a trailing number on the string
+ * and returns it. For example, "abc123" would return 123. Only the
+ * characters between @str and @end - 1 are examined. If @end is NULL, it is
+ * set to str + strlen(str).
+ *
+ * @str:	String to exxamine
+ * @end:	Pointer to end of string to examine, or NULL to use the
+ *		whole string
+ * @return training number if found, else -1
+ */
+long trailing_strtoln(const char *str, const char *end);
+
+/**
  * panic() - Print a message and reset/hang
  *
  * Prints a message on the console(s) and then resets. If CONFIG_PANIC_HANG is
diff --git a/lib/Kconfig b/lib/Kconfig
index c98d3997..972ac17 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -50,6 +50,8 @@
 	help
 	  This library provides pseudo-random number generator functions.
 
+source lib/dhry/Kconfig
+
 source lib/rsa/Kconfig
 
 menu "Hashing Support"
diff --git a/lib/Makefile b/lib/Makefile
index 97ed398..fd106b9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -15,12 +15,15 @@
 obj-$(CONFIG_TIZEN) += tizen/
 obj-$(CONFIG_OF_LIBFDT) += libfdt/
 obj-$(CONFIG_FIT) += libfdt/
+obj-$(CONFIG_FIT) += libfdt/
+obj-$(CONFIG_CMD_DHRYSTONE) += dhry/
 
 obj-$(CONFIG_AES) += aes.o
 obj-$(CONFIG_USB_TTY) += circbuf.o
 obj-y += crc7.o
 obj-y += crc8.o
 obj-y += crc16.o
+obj-$(CONFIG_ERRNO_STR) += errno_str.o
 obj-$(CONFIG_FIT) += fdtdec_common.o
 obj-$(CONFIG_OF_CONTROL) += fdtdec_common.o
 obj-$(CONFIG_OF_CONTROL) += fdtdec.o
@@ -34,6 +37,7 @@
 obj-y += net_utils.o
 obj-$(CONFIG_PHYSMEM) += physmem.o
 obj-y += qsort.o
+obj-y += rc4.o
 obj-$(CONFIG_SHA1) += sha1.o
 obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o
 obj-$(CONFIG_SHA256) += sha256.o
@@ -57,7 +61,6 @@
 obj-$(CONFIG_ADDR_MAP) += addr_map.o
 obj-y += hashtable.o
 obj-y += errno.o
-obj-$(CONFIG_ERRNO_STR) += errno_str.o
 obj-y += display_options.o
 obj-$(CONFIG_BCH) += bch.o
 obj-y += crc32.o
diff --git a/lib/dhry/Kconfig b/lib/dhry/Kconfig
new file mode 100644
index 0000000..641b806
--- /dev/null
+++ b/lib/dhry/Kconfig
@@ -0,0 +1,7 @@
+config CMD_DHRYSTONE
+	bool "Support the 'dhry' command to run the dhrystone benchmark"
+	help
+	  Dhrystone is an old benchmark in the public domain that gives a
+	  rough idea of CPU performance. This enables a 'dhry' command
+	  which runs this benchmark within U-Boot and reports the performance.
+	  The number of 'Dhrystone MIPS' is also reported.
diff --git a/lib/dhry/Makefile b/lib/dhry/Makefile
new file mode 100644
index 0000000..926c0d6
--- /dev/null
+++ b/lib/dhry/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2015 Google, Inc
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += cmd_dhry.o dhry_1.o dhry_2.o
diff --git a/lib/dhry/cmd_dhry.c b/lib/dhry/cmd_dhry.c
new file mode 100644
index 0000000..5dc191e
--- /dev/null
+++ b/lib/dhry/cmd_dhry.c
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include "dhry.h"
+
+static int do_dhry(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	ulong start, duration, dhry_per_sec, vax_mips;
+	int iterations = 1000000;
+
+	if (argc > 1)
+		iterations = simple_strtoul(argv[1], NULL, 10);
+
+	start = get_timer(0);
+	dhry(iterations);
+	duration = get_timer(start);
+	dhry_per_sec = iterations * 1000 / duration;
+	vax_mips = dhry_per_sec / 1757;
+	printf("%d iterations in %lu ms: %lu/s, %lu DMIPS\n", iterations,
+	       duration, dhry_per_sec, vax_mips);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	dhry,	2,	1,	do_dhry,
+	"[iterations] - run dhrystone benchmark",
+	"\n    - run the Dhrystone 2.1 benchmark, a rough measure of CPU speed\n"
+);
diff --git a/lib/dhry/dhry.h b/lib/dhry/dhry.h
new file mode 100644
index 0000000..49d4223
--- /dev/null
+++ b/lib/dhry/dhry.h
@@ -0,0 +1,442 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Dhrystone is widely available in the public domain. A GPL license is
+ * chosen for U-Boot.
+ */
+
+/*****************************************************************************
+ *  The BYTE UNIX Benchmarks - Release 3
+ *          Module: dhry.h   SID: 3.4 5/15/91 19:30:21
+ *          
+ *****************************************************************************
+ * Bug reports, patches, comments, suggestions should be sent to:
+ *
+ *	Ben Smith, Rick Grehan or Tom Yager
+ *	ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
+ *
+ *****************************************************************************
+ *  Modification Log:
+ *  addapted from:
+ *
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *                                                                            
+ *  Version:    C, Version 2.1
+ *                                                                            
+ *  File:       dhry.h (part 1 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *                      Siemens AG, AUT E 51
+ *                      Postfach 3220
+ *                      8520 Erlangen
+ *                      Germany (West)
+ *                              Phone:  [+49]-9131-7-20330
+ *                                      (8-17 Central European Time)
+ *                              Usenet: ..!mcvax!unido!estevax!weicker
+ *
+ *              Original Version (in Ada) published in
+ *              "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
+ *              pp. 1013 - 1030, together with the statistics
+ *              on which the distribution of statements etc. is based.
+ *
+ *              In this C version, the following C library functions are used:
+ *              - strcpy, strcmp (inside the measurement loop)
+ *              - printf, scanf (outside the measurement loop)
+ *              In addition, Berkeley UNIX system calls "times ()" or "time ()"
+ *              are used for execution time measurement. For measurements
+ *              on other systems, these calls have to be changed.
+ *
+ *  Collection of Results:
+ *              Reinhold Weicker (address see above) and
+ *              
+ *              Rick Richardson
+ *              PC Research. Inc.
+ *              94 Apple Orchard Drive
+ *              Tinton Falls, NJ 07724
+ *                      Phone:  (201) 834-1378 (9-17 EST)               
+ *                      Usenet: ...!seismo!uunet!pcrat!rick
+ *
+ *      Please send results to Rick Richardson and/or Reinhold Weicker.
+ *      Complete information should be given on hardware and software used.
+ *      Hardware information includes: Machine type, CPU, type and size
+ *      of caches; for microprocessors: clock frequency, memory speed
+ *      (number of wait states).
+ *      Software information includes: Compiler (and runtime library)
+ *      manufacturer and version, compilation switches, OS version.
+ *      The Operating System version may give an indication about the
+ *      compiler; Dhrystone itself performs no OS calls in the measurement loop.
+ *
+ *      The complete output generated by the program should be mailed
+ *      such that at least some checks for correctness can be made.
+ *
+ ***************************************************************************
+ *
+ *  History:    This version C/2.1 has been made for two reasons:
+ *
+ *              1) There is an obvious need for a common C version of
+ *              Dhrystone, since C is at present the most popular system
+ *              programming language for the class of processors
+ *              (microcomputers, minicomputers) where Dhrystone is used most.
+ *              There should be, as far as possible, only one C version of
+ *              Dhrystone such that results can be compared without
+ *              restrictions. In the past, the C versions distributed
+ *              by Rick Richardson (Version 1.1) and by Reinhold Weicker
+ *              had small (though not significant) differences.
+ *
+ *              2) As far as it is possible without changes to the Dhrystone
+ *              statistics, optimizing compilers should be prevented from
+ *              removing significant statements.
+ *
+ *              This C version has been developed in cooperation with
+ *              Rick Richardson (Tinton Falls, NJ), it incorporates many
+ *              ideas from the "Version 1.1" distributed previously by
+ *              him over the UNIX network Usenet.
+ *              I also thank Chaim Benedelac (National Semiconductor),
+ *              David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
+ *              Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
+ *              for their help with comments on earlier versions of the
+ *              benchmark.
+ *
+ *  Changes:    In the initialization part, this version follows mostly
+ *              Rick Richardson's version distributed via Usenet, not the
+ *              version distributed earlier via floppy disk by Reinhold Weicker.
+ *              As a concession to older compilers, names have been made
+ *              unique within the first 8 characters.
+ *              Inside the measurement loop, this version follows the
+ *              version previously distributed by Reinhold Weicker.
+ *
+ *              At several places in the benchmark, code has been added,
+ *              but within the measurement loop only in branches that 
+ *              are not executed. The intention is that optimizing compilers
+ *              should be prevented from moving code out of the measurement
+ *              loop, or from removing code altogether. Since the statements
+ *              that are executed within the measurement loop have NOT been
+ *              changed, the numbers defining the "Dhrystone distribution"
+ *              (distribution of statements, operand types and locality)
+ *              still hold. Except for sophisticated optimizing compilers,
+ *              execution times for this version should be the same as
+ *              for previous versions.
+ *              
+ *              Since it has proven difficult to subtract the time for the
+ *              measurement loop overhead in a correct way, the loop check
+ *              has been made a part of the benchmark. This does have
+ *              an impact - though a very minor one - on the distribution
+ *              statistics which have been updated for this version.
+ *
+ *              All changes within the measurement loop are described
+ *              and discussed in the companion paper "Rationale for
+ *              Dhrystone version 2".
+ *
+ *              Because of the self-imposed limitation that the order and
+ *              distribution of the executed statements should not be
+ *              changed, there are still cases where optimizing compilers
+ *              may not generate code for some statements. To a certain
+ *              degree, this is unavoidable for small synthetic benchmarks.
+ *              Users of the benchmark are advised to check code listings
+ *              whether code is generated for all statements of Dhrystone.
+ *
+ *              Version 2.1 is identical to version 2.0 distributed via
+ *              the UNIX network Usenet in March 1988 except that it corrects
+ *              some minor deficiencies that were found by users of version 2.0.
+ *              The only change within the measurement loop is that a
+ *              non-executed "else" part was added to the "if" statement in
+ *              Func_3, and a non-executed "else" part removed from Proc_3.
+ *
+ ***************************************************************************
+ *
+ * Defines:     The following "Defines" are possible:
+ *              -DREG=register          (default: Not defined)
+ *                      As an approximation to what an average C programmer
+ *                      might do, the "register" storage class is applied
+ *                      (if enabled by -DREG=register)
+ *                      - for local variables, if they are used (dynamically)
+ *                        five or more times
+ *                      - for parameters if they are used (dynamically)
+ *                        six or more times
+ *                      Note that an optimal "register" strategy is
+ *                      compiler-dependent, and that "register" declarations
+ *                      do not necessarily lead to faster execution.
+ *              -DNOSTRUCTASSIGN        (default: Not defined)
+ *                      Define if the C compiler does not support
+ *                      assignment of structures.
+ *              -DNOENUMS               (default: Not defined)
+ *                      Define if the C compiler does not support
+ *                      enumeration types.
+ *              -DTIMES                 (default)
+ *              -DTIME
+ *                      The "times" function of UNIX (returning process times)
+ *                      or the "time" function (returning wallclock time)
+ *                      is used for measurement. 
+ *                      For single user machines, "time ()" is adequate. For
+ *                      multi-user machines where you cannot get single-user
+ *                      access, use the "times ()" function. If you have
+ *                      neither, use a stopwatch in the dead of night.
+ *                      "printf"s are provided marking the points "Start Timer"
+ *                      and "Stop Timer". DO NOT use the UNIX "time(1)"
+ *                      command, as this will measure the total time to
+ *                      run this program, which will (erroneously) include
+ *                      the time to allocate storage (malloc) and to perform
+ *                      the initialization.
+ *              -DHZ=nnn
+ *                      In Berkeley UNIX, the function "times" returns process
+ *                      time in 1/HZ seconds, with HZ = 60 for most systems.
+ *                      CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY
+ *                      A VALUE.
+ *
+ ***************************************************************************
+ *
+ *  Compilation model and measurement (IMPORTANT):
+ *
+ *  This C version of Dhrystone consists of three files:
+ *  - dhry.h (this file, containing global definitions and comments)
+ *  - dhry_1.c (containing the code corresponding to Ada package Pack_1)
+ *  - dhry_2.c (containing the code corresponding to Ada package Pack_2)
+ *
+ *  The following "ground rules" apply for measurements:
+ *  - Separate compilation
+ *  - No procedure merging
+ *  - Otherwise, compiler optimizations are allowed but should be indicated
+ *  - Default results are those without register declarations
+ *  See the companion paper "Rationale for Dhrystone Version 2" for a more
+ *  detailed discussion of these ground rules.
+ *
+ *  For 16-Bit processors (e.g. 80186, 80286), times for all compilation
+ *  models ("small", "medium", "large" etc.) should be given if possible,
+ *  together with a definition of these models for the compiler system used.
+ *
+ **************************************************************************
+ *
+ *  Dhrystone (C version) statistics:
+ *
+ *  [Comment from the first distribution, updated for version 2.
+ *   Note that because of language differences, the numbers are slightly
+ *   different from the Ada version.]
+ *
+ *  The following program contains statements of a high level programming
+ *  language (here: C) in a distribution considered representative:           
+ *
+ *    assignments                  52 (51.0 %)
+ *    control statements           33 (32.4 %)
+ *    procedure, function calls    17 (16.7 %)
+ *
+ *  103 statements are dynamically executed. The program is balanced with
+ *  respect to the three aspects:                                             
+ *
+ *    - statement type
+ *    - operand type
+ *    - operand locality
+ *         operand global, local, parameter, or constant.                     
+ *
+ *  The combination of these three aspects is balanced only approximately.    
+ *
+ *  1. Statement Type:                                                        
+ *  -----------------             number
+ *
+ *     V1 = V2                     9
+ *       (incl. V1 = F(..)
+ *     V = Constant               12
+ *     Assignment,                 7
+ *       with array element
+ *     Assignment,                 6
+ *       with record component
+ *                                --
+ *                                34       34
+ *
+ *     X = Y +|-|"&&"|"|" Z        5
+ *     X = Y +|-|"==" Constant     6
+ *     X = X +|- 1                 3
+ *     X = Y *|/ Z                 2
+ *     X = Expression,             1
+ *           two operators
+ *     X = Expression,             1
+ *           three operators
+ *                                --
+ *                                18       18
+ *
+ *     if ....                    14
+ *       with "else"      7
+ *       without "else"   7
+ *           executed        3
+ *           not executed    4
+ *     for ...                     7  |  counted every time
+ *     while ...                   4  |  the loop condition
+ *     do ... while                1  |  is evaluated
+ *     switch ...                  1
+ *     break                       1
+ *     declaration with            1
+ *       initialization
+ *                                --
+ *                                34       34
+ *
+ *     P (...)  procedure call    11
+ *       user procedure      10
+ *       library procedure    1
+ *     X = F (...)
+ *             function  call      6
+ *       user function        5                                         
+ *       library function     1                                               
+ *                                --                                          
+ *                                17       17
+ *                                        ---
+ *                                        103
+ *
+ *    The average number of parameters in procedure or function calls
+ *    is 1.82 (not counting the function values as implicit parameters).
+ *
+ *
+ *  2. Operators
+ *  ------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *    Arithmetic             32          50.8                                 
+ *
+ *       +                     21          33.3                              
+ *       -                      7          11.1                              
+ *       *                      3           4.8
+ *       / (int div)            1           1.6
+ *
+ *    Comparison             27           42.8
+ *
+ *       ==                     9           14.3
+ *       /=                     4            6.3
+ *       >                      1            1.6
+ *       <                      3            4.8
+ *       >=                     1            1.6
+ *       <=                     9           14.3
+ *
+ *    Logic                   4            6.3
+ *
+ *       && (AND-THEN)          1            1.6
+ *       |  (OR)                1            1.6
+ *       !  (NOT)               2            3.2
+ * 
+ *                           --          -----
+ *                           63          100.1
+ *
+ *
+ *  3. Operand Type (counted once per operand reference):
+ *  ---------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *     Integer               175        72.3 %
+ *     Character              45        18.6 %
+ *     Pointer                12         5.0 %
+ *     String30                6         2.5 %
+ *     Array                   2         0.8 %
+ *     Record                  2         0.8 %
+ *                           ---       -------
+ *                           242       100.0 %
+ *
+ *  When there is an access path leading to the final operand (e.g. a record
+ *  component), only the final data type on the access path is counted.       
+ *
+ *
+ *  4. Operand Locality:                                                      
+ *  -------------------
+ *                                number    approximate
+ *                                          percentage
+ *
+ *     local variable              114        47.1 %
+ *     global variable              22         9.1 %
+ *     parameter                    45        18.6 %
+ *        value                        23         9.5 %
+ *        reference                    22         9.1 %
+ *     function result               6         2.5 %
+ *     constant                     55        22.7 %
+ *                                 ---       -------
+ *                                 242       100.0 %
+ *
+ *
+ *  The program does not compute anything meaningful, but it is syntactically
+ *  and semantically correct. All variables have a value assigned to them
+ *  before they are used as a source operand.
+ *
+ *  There has been no explicit effort to account for the effects of a
+ *  cache, or to balance the use of long or short displacements for code or
+ *  data.
+ *
+ ***************************************************************************
+ */
+
+
+/* Compiler and system dependent definitions: */
+
+#ifndef TIME
+#define TIMES
+#endif
+                /* Use times(2) time function unless    */
+                /* explicitly defined otherwise         */
+
+#define Mic_secs_Per_Second     1000000.0
+                /* Berkeley UNIX C returns process times in seconds/HZ */
+
+#ifdef  NOSTRUCTASSIGN
+#define structassign(d, s)      memcpy(&(d), &(s), sizeof(d))
+#else
+#define structassign(d, s)      d = s
+#endif
+
+#ifdef  NOENUM
+#define Ident_1 0
+#define Ident_2 1
+#define Ident_3 2
+#define Ident_4 3
+#define Ident_5 4
+  typedef int   Enumeration;
+#else
+  typedef       enum    {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
+                Enumeration;
+#endif
+        /* for boolean and enumeration types in Ada, Pascal */
+
+/* General definitions: */
+
+#define Null 0 
+                /* Value of a Null pointer */
+#define true  1
+#define false 0
+
+typedef int     One_Thirty;
+typedef int     One_Fifty;
+typedef char    Capital_Letter;
+typedef int     Boolean;
+typedef char    Str_30 [31];
+typedef int     Arr_1_Dim [50];
+typedef int     Arr_2_Dim [50] [50];
+
+typedef struct record 
+    {
+    struct record *Ptr_Comp;
+    Enumeration    Discr;
+    union {
+          struct {
+                  Enumeration Enum_Comp;
+                  int         Int_Comp;
+                  char        Str_Comp [31];
+                  } var_1;
+          struct {
+                  Enumeration E_Comp_2;
+                  char        Str_2_Comp [31];
+                  } var_2;
+          struct {
+                  char        Ch_1_Comp;
+                  char        Ch_2_Comp;
+                  } var_3;
+          } variant;
+      } Rec_Type, *Rec_Pointer;
+
+
+/*
+ * dhry() - run dhrystone for a given number of iterations
+ *
+ * @iterations:	Number of iterations to run
+ */
+void dhry(int iterations);
diff --git a/lib/dhry/dhry_1.c b/lib/dhry/dhry_1.c
new file mode 100644
index 0000000..be63710
--- /dev/null
+++ b/lib/dhry/dhry_1.c
@@ -0,0 +1,421 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Dhrystone is widely available in the public domain. A GPL license is
+ * chosen for U-Boot.
+ */
+
+/*****************************************************************************
+ *  The BYTE UNIX Benchmarks - Release 3
+ *          Module: dhry_1.c   SID: 3.4 5/15/91 19:30:21
+ *          
+ *****************************************************************************
+ * Bug reports, patches, comments, suggestions should be sent to:
+ *
+ *	Ben Smith, Rick Grehan or Tom Yager
+ *	ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
+ *
+ *****************************************************************************
+ *
+ * *** WARNING ****  With BYTE's modifications applied, results obtained with
+ *     *******       this version of the Dhrystone program may not be applicable
+ *                   to other versions.
+ *                  
+ *  Modification Log:
+ *  10/22/97 - code cleanup to remove ANSI C compiler warnings
+ *             Andy Kahn <kahn@zk3.dec.com>
+ *
+ *  Adapted from:
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *                                                                            
+ *  Version:    C, Version 2.1
+ *                                                                            
+ *  File:       dhry_1.c (part 2 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ***************************************************************************/
+char SCCSid[] = "@(#) @(#)dhry_1.c:3.4 -- 5/15/91 19:30:21";
+
+#include <common.h>
+#include <malloc.h>
+
+#include "dhry.h"
+
+unsigned long Run_Index;
+
+void report(void)
+{
+	printf("%ld loops\n", Run_Index);
+}
+
+/* Global Variables: */
+
+Rec_Pointer     Ptr_Glob,
+                Next_Ptr_Glob;
+int             Int_Glob;
+Boolean         Bool_Glob;
+char            Ch_1_Glob,
+                Ch_2_Glob;
+int             Arr_1_Glob [50];
+int             Arr_2_Glob [50] [50];
+
+Enumeration     Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val);
+  /* forward declaration necessary since Enumeration may not simply be int */
+
+#ifndef REG
+        Boolean Reg = false;
+#define REG
+        /* REG becomes defined as empty */
+        /* i.e. no register variables   */
+#else
+        Boolean Reg = true;
+#endif
+
+/* variables for time measurement: */
+
+#ifdef TIMES
+#define Too_Small_Time 120
+                /* Measurements should last at least about 2 seconds */
+#endif
+#ifdef TIME
+extern long     time();
+                /* see library function "time"  */
+#define Too_Small_Time 2
+                /* Measurements should last at least 2 seconds */
+#endif
+
+long            Begin_Time,
+                End_Time,
+                User_Time;
+
+/* end of variables for time measurement */
+
+void Proc_1 (REG Rec_Pointer Ptr_Val_Par);
+void Proc_2 (One_Fifty   *Int_Par_Ref);
+void Proc_3 (Rec_Pointer *Ptr_Ref_Par);
+void Proc_4 (void);
+void Proc_5 (void);
+
+
+extern Boolean Func_2(Str_30, Str_30);
+extern void Proc_6(Enumeration, Enumeration *);
+extern void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
+extern void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
+
+void dhry(int Number_Of_Runs)
+  /* main program, corresponds to procedures        */
+  /* Main and Proc_0 in the Ada version             */
+{
+        One_Fifty       Int_1_Loc;
+  REG   One_Fifty       Int_2_Loc;
+        One_Fifty       Int_3_Loc;
+  REG   char            Ch_Index;
+        Enumeration     Enum_Loc;
+        Str_30          Str_1_Loc;
+        Str_30          Str_2_Loc;
+
+  /* Initializations */
+
+  Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+  Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+
+  Ptr_Glob->Ptr_Comp                    = Next_Ptr_Glob;
+  Ptr_Glob->Discr                       = Ident_1;
+  Ptr_Glob->variant.var_1.Enum_Comp     = Ident_3;
+  Ptr_Glob->variant.var_1.Int_Comp      = 40;
+  strcpy (Ptr_Glob->variant.var_1.Str_Comp, 
+          "DHRYSTONE PROGRAM, SOME STRING");
+  strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
+
+  Arr_2_Glob [8][7] = 10;
+        /* Was missing in published program. Without this statement,    */
+        /* Arr_2_Glob [8][7] would have an undefined value.             */
+        /* Warning: With 16-Bit processors and Number_Of_Runs > 32000,  */
+        /* overflow may occur for this array element.                   */
+
+#ifdef PRATTLE
+  printf ("\n");
+  printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
+  printf ("\n");
+  if (Reg)
+  {
+    printf ("Program compiled with 'register' attribute\n");
+    printf ("\n");
+  }
+  else
+  {
+    printf ("Program compiled without 'register' attribute\n");
+    printf ("\n");
+  }
+  printf ("Please give the number of runs through the benchmark: ");
+  {
+    int n;
+    scanf ("%d", &n);
+    Number_Of_Runs = n;
+  }
+  printf ("\n");
+
+  printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
+#endif /* PRATTLE */
+
+  Run_Index = 0;
+
+  /***************/
+  /* Start timer */
+  /***************/
+ 
+#ifdef SELF_TIMED
+#ifdef TIMES
+  times (&time_info);
+  Begin_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  Begin_Time = time ( (long *) 0);
+#endif
+#endif /* SELF_TIMED */
+
+  for (Run_Index = 1; Run_Index < Number_Of_Runs; ++Run_Index)
+  {
+
+    Proc_5();
+    Proc_4();
+      /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
+    Int_1_Loc = 2;
+    Int_2_Loc = 3;
+    strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
+    Enum_Loc = Ident_2;
+    Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
+      /* Bool_Glob == 1 */
+    while (Int_1_Loc < Int_2_Loc)  /* loop body executed once */
+    {
+      Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
+        /* Int_3_Loc == 7 */
+      Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
+        /* Int_3_Loc == 7 */
+      Int_1_Loc += 1;
+    } /* while */
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
+      /* Int_Glob == 5 */
+    Proc_1 (Ptr_Glob);
+    for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
+                             /* loop body executed twice */
+    {
+      if (Enum_Loc == Func_1 (Ch_Index, 'C'))
+          /* then, not executed */
+        {
+        Proc_6 (Ident_1, &Enum_Loc);
+        strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
+        Int_2_Loc = Run_Index;
+        Int_Glob = Run_Index;
+        }
+    }
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Int_2_Loc = Int_2_Loc * Int_1_Loc;
+    Int_1_Loc = Int_2_Loc / Int_3_Loc;
+    Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
+      /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
+    Proc_2 (&Int_1_Loc);
+      /* Int_1_Loc == 5 */
+
+  } /* loop "for Run_Index" */
+
+  /**************/
+  /* Stop timer */
+  /**************/
+#ifdef SELF_TIMED 
+#ifdef TIMES
+  times (&time_info);
+  End_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  End_Time = time ( (long *) 0);
+#endif
+#endif /* SELF_TIMED */
+
+  /* BYTE version never executes this stuff */
+#ifdef SELF_TIMED
+  printf ("Execution ends\n");
+  printf ("\n");
+  printf ("Final values of the variables used in the benchmark:\n");
+  printf ("\n");
+  printf ("Int_Glob:            %d\n", Int_Glob);
+  printf ("        should be:   %d\n", 5);
+  printf ("Bool_Glob:           %d\n", Bool_Glob);
+  printf ("        should be:   %d\n", 1);
+  printf ("Ch_1_Glob:           %c\n", Ch_1_Glob);
+  printf ("        should be:   %c\n", 'A');
+  printf ("Ch_2_Glob:           %c\n", Ch_2_Glob);
+  printf ("        should be:   %c\n", 'B');
+  printf ("Arr_1_Glob[8]:       %d\n", Arr_1_Glob[8]);
+  printf ("        should be:   %d\n", 7);
+  printf ("Arr_2_Glob[8][7]:    %d\n", Arr_2_Glob[8][7]);
+  printf ("        should be:   Number_Of_Runs + 10\n");
+  printf ("Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent)\n");
+  printf ("  Discr:             %d\n", Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 2);
+  printf ("  Int_Comp:          %d\n", Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 17);
+  printf ("  Str_Comp:          %s\n", Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Next_Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent), same as above\n");
+  printf ("  Discr:             %d\n", Next_Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 1);
+  printf ("  Int_Comp:          %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 18);
+  printf ("  Str_Comp:          %s\n",
+                                Next_Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Int_1_Loc:           %d\n", Int_1_Loc);
+  printf ("        should be:   %d\n", 5);
+  printf ("Int_2_Loc:           %d\n", Int_2_Loc);
+  printf ("        should be:   %d\n", 13);
+  printf ("Int_3_Loc:           %d\n", Int_3_Loc);
+  printf ("        should be:   %d\n", 7);
+  printf ("Enum_Loc:            %d\n", Enum_Loc);
+  printf ("        should be:   %d\n", 1);
+  printf ("Str_1_Loc:           %s\n", Str_1_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 1'ST STRING\n");
+  printf ("Str_2_Loc:           %s\n", Str_2_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 2'ND STRING\n");
+  printf ("\n");
+
+  User_Time = End_Time - Begin_Time;
+
+  if (User_Time < Too_Small_Time)
+  {
+    printf ("Measured time too small to obtain meaningful results\n");
+    printf ("Please increase number of runs\n");
+    printf ("\n");
+  }
+  else
+  {
+#ifdef TIME
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / (float) Number_Of_Runs;
+    Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
+#else
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / ((float) HZ * ((float) Number_Of_Runs));
+    Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
+                        / (float) User_Time;
+#endif
+    printf ("Microseconds for one run through Dhrystone: ");
+    printf ("%6.1f \n", Microseconds);
+    printf ("Dhrystones per Second:                      ");
+    printf ("%6.1f \n", Dhrystones_Per_Second);
+    printf ("\n");
+  }
+#endif /* SELF_TIMED */
+}
+
+
+void Proc_1 (REG Rec_Pointer Ptr_Val_Par)
+    /* executed once */
+{
+  REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;  
+                                        /* == Ptr_Glob_Next */
+  /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp,    */
+  /* corresponds to "rename" in Ada, "with" in Pascal           */
+  
+  structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); 
+  Ptr_Val_Par->variant.var_1.Int_Comp = 5;
+  Next_Record->variant.var_1.Int_Comp 
+        = Ptr_Val_Par->variant.var_1.Int_Comp;
+  Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
+  Proc_3 (&Next_Record->Ptr_Comp);
+    /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp 
+                        == Ptr_Glob->Ptr_Comp */
+  if (Next_Record->Discr == Ident_1)
+    /* then, executed */
+  {
+    Next_Record->variant.var_1.Int_Comp = 6;
+    Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, 
+           &Next_Record->variant.var_1.Enum_Comp);
+    Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
+    Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, 
+           &Next_Record->variant.var_1.Int_Comp);
+  }
+  else /* not executed */
+    structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
+} /* Proc_1 */
+
+
+void Proc_2 (One_Fifty   *Int_Par_Ref)
+    /* executed once */
+    /* *Int_Par_Ref == 1, becomes 4 */
+{
+  One_Fifty  Int_Loc;  
+  Enumeration   Enum_Loc;
+
+  Enum_Loc = 0;
+
+  Int_Loc = *Int_Par_Ref + 10;
+  do /* executed once */
+    if (Ch_1_Glob == 'A')
+      /* then, executed */
+    {
+      Int_Loc -= 1;
+      *Int_Par_Ref = Int_Loc - Int_Glob;
+      Enum_Loc = Ident_1;
+    } /* if */
+  while (Enum_Loc != Ident_1); /* true */
+} /* Proc_2 */
+
+
+void Proc_3 (Rec_Pointer *Ptr_Ref_Par)
+    /* executed once */
+    /* Ptr_Ref_Par becomes Ptr_Glob */
+{
+  if (Ptr_Glob != Null)
+    /* then, executed */
+    *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
+  Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
+} /* Proc_3 */
+
+
+void Proc_4 (void) /* without parameters */
+    /* executed once */
+{
+  Boolean Bool_Loc;
+
+  Bool_Loc = Ch_1_Glob == 'A';
+  Bool_Glob = Bool_Loc | Bool_Glob;
+  Ch_2_Glob = 'B';
+} /* Proc_4 */
+
+void Proc_5 (void) /* without parameters */
+/*******/
+    /* executed once */
+{
+  Ch_1_Glob = 'A';
+  Bool_Glob = false;
+} /* Proc_5 */
+
+
+        /* Procedure for the assignment of structures,          */
+        /* if the C compiler doesn't support this feature       */
+#ifdef  NOSTRUCTASSIGN
+memcpy (d, s, l)
+register char   *d;
+register char   *s;
+register int    l;
+{
+        while (l--) *d++ = *s++;
+}
+#endif
diff --git a/lib/dhry/dhry_2.c b/lib/dhry/dhry_2.c
new file mode 100644
index 0000000..59aa458
--- /dev/null
+++ b/lib/dhry/dhry_2.c
@@ -0,0 +1,217 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Dhrystone is widely available in the public domain. A GPL license is
+ * chosen for U-Boot.
+ */
+
+/*****************************************************************************
+ *  The BYTE UNIX Benchmarks - Release 3
+ *          Module: dhry_2.c   SID: 3.4 5/15/91 19:30:22
+ *          
+ *****************************************************************************
+ * Bug reports, patches, comments, suggestions should be sent to:
+ *
+ *	Ben Smith, Rick Grehan or Tom Yager
+ *	ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
+ *
+ *****************************************************************************
+ *  Modification Log:
+ *  10/22/97 - code cleanup to remove ANSI C compiler warnings
+ *             Andy Kahn <kahn@zk3.dec.com>
+ *
+ *  Adapted from:
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ * **** WARNING **** See warning in n.dhry_1.c
+ *                                                                            
+ *  Version:    C, Version 2.1
+ *                                                                            
+ *  File:       dhry_2.c (part 3 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ****************************************************************************/
+/* SCCSid is defined in dhry_1.c */
+
+#include <common.h>
+#include "dhry.h"
+
+#ifndef REG
+#define REG
+        /* REG becomes defined as empty */
+        /* i.e. no register variables   */
+#endif
+
+extern  int     Int_Glob;
+extern  char    Ch_1_Glob;
+
+void Proc_6(Enumeration, Enumeration *);
+void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
+void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
+Enumeration Func_1(Capital_Letter, Capital_Letter);
+Boolean Func_2(Str_30, Str_30);
+Boolean Func_3(Enumeration);
+
+void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par)
+    /* executed once */
+    /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
+{
+  *Enum_Ref_Par = Enum_Val_Par;
+  if (! Func_3 (Enum_Val_Par))
+    /* then, not executed */
+    *Enum_Ref_Par = Ident_4;
+  switch (Enum_Val_Par)
+  {
+    case Ident_1: 
+      *Enum_Ref_Par = Ident_1;
+      break;
+    case Ident_2: 
+      if (Int_Glob > 100)
+        /* then */
+      *Enum_Ref_Par = Ident_1;
+      else *Enum_Ref_Par = Ident_4;
+      break;
+    case Ident_3: /* executed */
+      *Enum_Ref_Par = Ident_2;
+      break;
+    case Ident_4: break;
+    case Ident_5: 
+      *Enum_Ref_Par = Ident_3;
+      break;
+  } /* switch */
+} /* Proc_6 */
+
+void Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
+One_Fifty       Int_1_Par_Val;
+One_Fifty       Int_2_Par_Val;
+One_Fifty      *Int_Par_Ref;
+/**********************************************/
+    /* executed three times                                      */ 
+    /* first call:      Int_1_Par_Val == 2, Int_2_Par_Val == 3,  */
+    /*                  Int_Par_Ref becomes 7                    */
+    /* second call:     Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
+    /*                  Int_Par_Ref becomes 17                   */
+    /* third call:      Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
+    /*                  Int_Par_Ref becomes 18                   */
+{
+  One_Fifty Int_Loc;
+
+  Int_Loc = Int_1_Par_Val + 2;
+  *Int_Par_Ref = Int_2_Par_Val + Int_Loc;
+} /* Proc_7 */
+
+
+void Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
+/*********************************************************************/
+    /* executed once      */
+    /* Int_Par_Val_1 == 3 */
+    /* Int_Par_Val_2 == 7 */
+Arr_1_Dim       Arr_1_Par_Ref;
+Arr_2_Dim       Arr_2_Par_Ref;
+int             Int_1_Par_Val;
+int             Int_2_Par_Val;
+{
+  REG One_Fifty Int_Index;
+  REG One_Fifty Int_Loc;
+
+  Int_Loc = Int_1_Par_Val + 5;
+  Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
+  Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
+  Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
+  for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
+    Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
+  Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
+  Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
+  Int_Glob = 5;
+} /* Proc_8 */
+
+
+Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val)
+/*************************************************/
+    /* executed three times                                         */
+    /* first call:      Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R'    */
+    /* second call:     Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C'    */
+    /* third call:      Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C'    */
+{
+  Capital_Letter        Ch_1_Loc;
+  Capital_Letter        Ch_2_Loc;
+
+  Ch_1_Loc = Ch_1_Par_Val;
+  Ch_2_Loc = Ch_1_Loc;
+  if (Ch_2_Loc != Ch_2_Par_Val)
+    /* then, executed */
+    return (Ident_1);
+  else  /* not executed */
+  {
+    Ch_1_Glob = Ch_1_Loc;
+    return (Ident_2);
+   }
+} /* Func_1 */
+
+
+
+Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
+/*************************************************/
+    /* executed once */
+    /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
+    /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
+
+Str_30  Str_1_Par_Ref;
+Str_30  Str_2_Par_Ref;
+{
+  REG One_Thirty        Int_Loc;
+      Capital_Letter    Ch_Loc;
+
+  Ch_Loc = 'A';
+  Int_Loc = 2;
+  while (Int_Loc <= 2) /* loop body executed once */
+    if (Func_1 (Str_1_Par_Ref[Int_Loc],
+                Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
+      /* then, executed */
+    {
+      Ch_Loc = 'A';
+      Int_Loc += 1;
+    } /* if, while */
+  if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
+    /* then, not executed */
+    Int_Loc = 7;
+  if (Ch_Loc == 'R')
+    /* then, not executed */
+    return (true);
+  else /* executed */
+  {
+    if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
+      /* then, not executed */
+    {
+      Int_Loc += 7;
+      Int_Glob = Int_Loc;
+      return (true);
+    }
+    else /* executed */
+      return (false);
+  } /* if Ch_Loc */
+} /* Func_2 */
+
+
+Boolean Func_3 (Enum_Par_Val)
+/***************************/
+    /* executed once        */
+    /* Enum_Par_Val == Ident_3 */
+Enumeration Enum_Par_Val;
+{
+  Enumeration Enum_Loc;
+
+  Enum_Loc = Enum_Par_Val;
+  if (Enum_Loc == Ident_3)
+    /* then, executed */
+    return (true);
+  else /* not executed */
+    return (false);
+} /* Func_3 */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 9c6b361..232ca74 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -505,8 +505,7 @@
 		const char *prop;
 		const char *name;
 		const char *slash;
-		const char *p;
-		int len;
+		int len, val;
 
 		prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
 		debug("   - %s, %s\n", name, prop);
@@ -517,12 +516,11 @@
 		slash = strrchr(prop, '/');
 		if (strcmp(slash + 1, find_name))
 			continue;
-		for (p = name + strlen(name) - 1; p > name; p--) {
-			if (!isdigit(*p)) {
-				*seqp = simple_strtoul(p + 1, NULL, 10);
-				debug("Found seq %d\n", *seqp);
-				return 0;
-			}
+		val = trailing_strtol(name);
+		if (val != -1) {
+			*seqp = val;
+			debug("Found seq %d\n", *seqp);
+			return 0;
 		}
 	}
 
@@ -570,6 +568,13 @@
 		puts("Missing DTB\n");
 #else
 		puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
+# ifdef DEBUG
+		if (gd->fdt_blob) {
+			printf("fdt_blob=%p\n", gd->fdt_blob);
+			print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
+				     32, 0);
+		}
+# endif
 #endif
 		return -1;
 	}
diff --git a/lib/libfdt/Makefile b/lib/libfdt/Makefile
index 2f5413f..934d614 100644
--- a/lib/libfdt/Makefile
+++ b/lib/libfdt/Makefile
@@ -6,4 +6,4 @@
 #
 
 obj-y += fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o fdt_wip.o \
-	fdt_empty_tree.o fdt_addresses.o
+	fdt_empty_tree.o fdt_addresses.o fdt_region.o
diff --git a/lib/libfdt/fdt_region.c b/lib/libfdt/fdt_region.c
new file mode 100644
index 0000000..9fea775
--- /dev/null
+++ b/lib/libfdt/fdt_region.c
@@ -0,0 +1,492 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2013 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ * SPDX-License-Identifier:	GPL-2.0+ BSD-2-Clause
+ */
+
+#include "libfdt_env.h"
+
+#ifndef USE_HOSTCC
+#include <fdt.h>
+#include <libfdt.h>
+#else
+#include "fdt_host.h"
+#endif
+
+#include "libfdt_internal.h"
+
+/**
+ * fdt_add_region() - Add a new region to our list
+ *
+ * The region is added if there is space, but in any case we increment the
+ * count. If permitted, and the new region overlaps the last one, we merge
+ * them.
+ *
+ * @info: State information
+ * @offset: Start offset of region
+ * @size: Size of region
+ */
+static int fdt_add_region(struct fdt_region_state *info, int offset, int size)
+{
+	struct fdt_region *reg;
+
+	reg = info->region ? &info->region[info->count - 1] : NULL;
+	if (info->can_merge && info->count &&
+	    info->count <= info->max_regions &&
+	    reg && offset <= reg->offset + reg->size) {
+		reg->size = offset + size - reg->offset;
+	} else if (info->count++ < info->max_regions) {
+		if (reg) {
+			reg++;
+			reg->offset = offset;
+			reg->size = size;
+		}
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int region_list_contains_offset(struct fdt_region_state *info,
+				       const void *fdt, int target)
+{
+	struct fdt_region *reg;
+	int num;
+
+	target += fdt_off_dt_struct(fdt);
+	for (reg = info->region, num = 0; num < info->count; reg++, num++) {
+		if (target >= reg->offset && target < reg->offset + reg->size)
+			return 1;
+	}
+
+	return 0;
+}
+
+int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
+			  int max_regions, struct fdt_region_state *info)
+{
+	int base = fdt_off_dt_struct(fdt);
+	int node, node_end, offset;
+	int did_alias_header;
+
+	node = fdt_subnode_offset(fdt, 0, "aliases");
+	if (node < 0)
+		return -FDT_ERR_NOTFOUND;
+
+	/* The aliases node must come before the others */
+	node_end = fdt_next_subnode(fdt, node);
+	if (node_end <= 0)
+		return -FDT_ERR_BADLAYOUT;
+	node_end -= sizeof(fdt32_t);
+
+	did_alias_header = 0;
+	info->region = region;
+	info->count = count;
+	info->can_merge = 0;
+	info->max_regions = max_regions;
+
+	for (offset = fdt_first_property_offset(fdt, node);
+	     offset >= 0;
+	     offset = fdt_next_property_offset(fdt, offset)) {
+		const struct fdt_property *prop;
+		const char *name;
+		int target, next;
+
+		prop = fdt_get_property_by_offset(fdt, offset, NULL);
+		name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+		target = fdt_path_offset(fdt, name);
+		if (!region_list_contains_offset(info, fdt, target))
+			continue;
+		next = fdt_next_property_offset(fdt, offset);
+		if (next < 0)
+			next = node_end - sizeof(fdt32_t);
+
+		if (!did_alias_header) {
+			fdt_add_region(info, base + node, 12);
+			did_alias_header = 1;
+		}
+		fdt_add_region(info, base + offset, next - offset);
+	}
+
+	/* Add the 'end' tag */
+	if (did_alias_header)
+		fdt_add_region(info, base + node_end, sizeof(fdt32_t));
+
+	return info->count < max_regions ? info->count : -FDT_ERR_NOSPACE;
+}
+
+/**
+ * fdt_include_supernodes() - Include supernodes required by this node
+ *
+ * When we decided to include a node or property which is not at the top
+ * level, this function forces the inclusion of higher level nodes. For
+ * example, given this tree:
+ *
+ * / {
+ *     testing {
+ *     }
+ * }
+ *
+ * If we decide to include testing then we need the root node to have a valid
+ * tree. This function adds those regions.
+ *
+ * @info: State information
+ * @depth: Current stack depth
+ */
+static int fdt_include_supernodes(struct fdt_region_state *info, int depth)
+{
+	int base = fdt_off_dt_struct(info->fdt);
+	int start, stop_at;
+	int i;
+
+	/*
+	 * Work down the stack looking for supernodes that we didn't include.
+	 * The algortihm here is actually pretty simple, since we know that
+	 * no previous subnode had to include these nodes, or if it did, we
+	 * marked them as included (on the stack) already.
+	 */
+	for (i = 0; i <= depth; i++) {
+		if (!info->stack[i].included) {
+			start = info->stack[i].offset;
+
+			/* Add the FDT_BEGIN_NODE tag of this supernode */
+			fdt_next_tag(info->fdt, start, &stop_at);
+			if (fdt_add_region(info, base + start, stop_at - start))
+				return -1;
+
+			/* Remember that this supernode is now included */
+			info->stack[i].included = 1;
+			info->can_merge = 1;
+		}
+
+		/* Force (later) generation of the FDT_END_NODE tag */
+		if (!info->stack[i].want)
+			info->stack[i].want = WANT_NODES_ONLY;
+	}
+
+	return 0;
+}
+
+enum {
+	FDT_DONE_NOTHING,
+	FDT_DONE_MEM_RSVMAP,
+	FDT_DONE_STRUCT,
+	FDT_DONE_END,
+	FDT_DONE_STRINGS,
+	FDT_DONE_ALL,
+};
+
+int fdt_first_region(const void *fdt,
+		int (*h_include)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		void *priv, struct fdt_region *region,
+		char *path, int path_len, int flags,
+		struct fdt_region_state *info)
+{
+	struct fdt_region_ptrs *p = &info->ptrs;
+
+	/* Set up our state */
+	info->fdt = fdt;
+	info->can_merge = 1;
+	info->max_regions = 1;
+	info->start = -1;
+	p->want = WANT_NOTHING;
+	p->end = path;
+	*p->end = '\0';
+	p->nextoffset = 0;
+	p->depth = -1;
+	p->done = FDT_DONE_NOTHING;
+
+	return fdt_next_region(fdt, h_include, priv, region,
+			       path, path_len, flags, info);
+}
+
+/*
+ * Theory of operation
+ *
+ *
+ *
+
+Note: in this description 'included' means that a node (or other part of
+the tree) should be included in the region list, i.e. it will have a region
+which covers its part of the tree.
+
+This function maintains some state from the last time it is called. It
+checks the next part of the tree that it is supposed to look at
+(p.nextoffset) to see if that should be included or not. When it finds
+something to include, it sets info->start to its offset. This marks the
+start of the region we want to include.
+
+Once info->start is set to the start (i.e. not -1), we continue scanning
+until we find something that we don't want included. This will be the end
+of a region. At this point we can close off the region and add it to the
+list. So we do so, and reset info->start to -1.
+
+One complication here is that we want to merge regions. So when we come to
+add another region later, we may in fact merge it with the previous one if
+one ends where the other starts.
+
+The function fdt_add_region() will return -1 if it fails to add the region,
+because we already have a region ready to be returned, and the new one
+cannot be merged in with it. In this case, we must return the region we
+found, and wait for another call to this function. When it comes, we will
+repeat the processing of the tag and again try to add a region. This time it
+will succeed.
+
+The current state of the pointers (stack, offset, etc.) is maintained in
+a ptrs member. At the start of every loop iteration we make a copy of it.
+The copy is then updated as the tag is processed. Only if we get to the end
+of the loop iteration (and successfully call fdt_add_region() if we need
+to) can we commit the changes we have made to these pointers. For example,
+if we see an FDT_END_NODE tag we will decrement the depth value. But if we
+need to add a region for this tag (let's say because the previous tag is
+included and this FDT_END_NODE tag is not included) then we will only commit
+the result if we were able to add the region. That allows us to retry again
+next time.
+
+We keep track of a variable called 'want' which tells us what we want to
+include when there is no specific information provided by the h_include
+function for a particular property. This basically handles the inclusion of
+properties which are pulled in by virtue of the node they are in. So if you
+include a node, its properties are also included. In this case 'want' will
+be WANT_NODES_AND_PROPS. The FDT_REG_DIRECT_SUBNODES feature also makes use
+of 'want'. While we are inside the subnode, 'want' will be set to
+WANT_NODES_ONLY, so that only the subnode's FDT_BEGIN_NODE and FDT_END_NODE
+tags will be included, and properties will be skipped. If WANT_NOTHING is
+selected, then we will just rely on what the h_include() function tells us.
+
+Using 'want' we work out 'include', which tells us whether this current tag
+should be included or not. As you can imagine, if the value of 'include'
+changes, that means we are on a boundary between nodes to include and nodes
+to exclude. At this point we either close off a previous region and add it
+to the list, or mark the start of a new region.
+
+Apart from the nodes, we have mem_rsvmap, the FDT_END tag and the string
+list. Each of these dealt with as a whole (i.e. we create a region for each
+if it is to be included). For mem_rsvmap we don't allow it to merge with
+the first struct region. For the stringlist we don't allow it to merge with
+the last struct region (which contains at minimum the FDT_END tag).
+*/
+int fdt_next_region(const void *fdt,
+		int (*h_include)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		void *priv, struct fdt_region *region,
+		char *path, int path_len, int flags,
+		struct fdt_region_state *info)
+{
+	int base = fdt_off_dt_struct(fdt);
+	int last_node = 0;
+	const char *str;
+
+	info->region = region;
+	info->count = 0;
+	if (info->ptrs.done < FDT_DONE_MEM_RSVMAP &&
+	    (flags & FDT_REG_ADD_MEM_RSVMAP)) {
+		/* Add the memory reserve map into its own region */
+		if (fdt_add_region(info, fdt_off_mem_rsvmap(fdt),
+				   fdt_off_dt_struct(fdt) -
+				   fdt_off_mem_rsvmap(fdt)))
+			return 0;
+		info->can_merge = 0;	/* Don't allow merging with this */
+		info->ptrs.done = FDT_DONE_MEM_RSVMAP;
+	}
+
+	/*
+	 * Work through the tags one by one, deciding whether each needs to
+	 * be included or not. We set the variable 'include' to indicate our
+	 * decision. 'want' is used to track what we want to include - it
+	 * allows us to pick up all the properties (and/or subnode tags) of
+	 * a node.
+	 */
+	while (info->ptrs.done < FDT_DONE_STRUCT) {
+		const struct fdt_property *prop;
+		struct fdt_region_ptrs p;
+		const char *name;
+		int include = 0;
+		int stop_at = 0;
+		uint32_t tag;
+		int offset;
+		int val;
+		int len;
+
+		/*
+		 * Make a copy of our pointers. If we make it to the end of
+		 * this block then we will commit them back to info->ptrs.
+		 * Otherwise we can try again from the same starting state
+		 * next time we are called.
+		 */
+		p = info->ptrs;
+
+		/*
+		 * Find the tag, and the offset of the next one. If we need to
+		 * stop including tags, then by default we stop *after*
+		 * including the current tag
+		 */
+		offset = p.nextoffset;
+		tag = fdt_next_tag(fdt, offset, &p.nextoffset);
+		stop_at = p.nextoffset;
+
+		switch (tag) {
+		case FDT_PROP:
+			stop_at = offset;
+			prop = fdt_get_property_by_offset(fdt, offset, NULL);
+			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+			val = h_include(priv, fdt, last_node, FDT_IS_PROP, str,
+					    strlen(str) + 1);
+			if (val == -1) {
+				include = p.want >= WANT_NODES_AND_PROPS;
+			} else {
+				include = val;
+				/*
+				 * Make sure we include the } for this block.
+				 * It might be more correct to have this done
+				 * by the call to fdt_include_supernodes() in
+				 * the case where it adds the node we are
+				 * currently in, but this is equivalent.
+				 */
+				if ((flags & FDT_REG_SUPERNODES) && val &&
+				    !p.want)
+					p.want = WANT_NODES_ONLY;
+			}
+
+			/* Value grepping is not yet supported */
+			break;
+
+		case FDT_NOP:
+			include = p.want >= WANT_NODES_AND_PROPS;
+			stop_at = offset;
+			break;
+
+		case FDT_BEGIN_NODE:
+			last_node = offset;
+			p.depth++;
+			if (p.depth == FDT_MAX_DEPTH)
+				return -FDT_ERR_TOODEEP;
+			name = fdt_get_name(fdt, offset, &len);
+			if (p.end - path + 2 + len >= path_len)
+				return -FDT_ERR_NOSPACE;
+
+			/* Build the full path of this node */
+			if (p.end != path + 1)
+				*p.end++ = '/';
+			strcpy(p.end, name);
+			p.end += len;
+			info->stack[p.depth].want = p.want;
+			info->stack[p.depth].offset = offset;
+
+			/*
+			 * If we are not intending to include this node unless
+			 * it matches, make sure we stop *before* its tag.
+			 */
+			if (p.want == WANT_NODES_ONLY ||
+			    !(flags & (FDT_REG_DIRECT_SUBNODES |
+				       FDT_REG_ALL_SUBNODES))) {
+				stop_at = offset;
+				p.want = WANT_NOTHING;
+			}
+			val = h_include(priv, fdt, offset, FDT_IS_NODE, path,
+					p.end - path + 1);
+
+			/* Include this if requested */
+			if (val) {
+				p.want = (flags & FDT_REG_ALL_SUBNODES) ?
+					WANT_ALL_NODES_AND_PROPS :
+					WANT_NODES_AND_PROPS;
+			}
+
+			/* If not requested, decay our 'p.want' value */
+			else if (p.want) {
+				if (p.want != WANT_ALL_NODES_AND_PROPS)
+					p.want--;
+
+			/* Not including this tag, so stop now */
+			} else {
+				stop_at = offset;
+			}
+
+			/*
+			 * Decide whether to include this tag, and update our
+			 * stack with the state for this node
+			 */
+			include = p.want;
+			info->stack[p.depth].included = include;
+			break;
+
+		case FDT_END_NODE:
+			include = p.want;
+			if (p.depth < 0)
+				return -FDT_ERR_BADSTRUCTURE;
+
+			/*
+			 * If we don't want this node, stop right away, unless
+			 * we are including subnodes
+			 */
+			if (!p.want && !(flags & FDT_REG_DIRECT_SUBNODES))
+				stop_at = offset;
+			p.want = info->stack[p.depth].want;
+			p.depth--;
+			while (p.end > path && *--p.end != '/')
+				;
+			*p.end = '\0';
+			break;
+
+		case FDT_END:
+			/* We always include the end tag */
+			include = 1;
+			p.done = FDT_DONE_STRUCT;
+			break;
+		}
+
+		/* If this tag is to be included, mark it as region start */
+		if (include && info->start == -1) {
+			/* Include any supernodes required by this one */
+			if (flags & FDT_REG_SUPERNODES) {
+				if (fdt_include_supernodes(info, p.depth))
+					return 0;
+			}
+			info->start = offset;
+		}
+
+		/*
+		 * If this tag is not to be included, finish up the current
+		 * region.
+		 */
+		if (!include && info->start != -1) {
+			if (fdt_add_region(info, base + info->start,
+					   stop_at - info->start))
+				return 0;
+			info->start = -1;
+			info->can_merge = 1;
+		}
+
+		/* If we have made it this far, we can commit our pointers */
+		info->ptrs = p;
+	}
+
+	/* Add a region for the END tag and a separate one for string table */
+	if (info->ptrs.done < FDT_DONE_END) {
+		if (info->ptrs.nextoffset != fdt_size_dt_struct(fdt))
+			return -FDT_ERR_BADSTRUCTURE;
+
+		if (fdt_add_region(info, base + info->start,
+				   info->ptrs.nextoffset - info->start))
+			return 0;
+		info->ptrs.done++;
+	}
+	if (info->ptrs.done < FDT_DONE_STRINGS) {
+		if (flags & FDT_REG_ADD_STRING_TAB) {
+			info->can_merge = 0;
+			if (fdt_off_dt_strings(fdt) <
+			    base + info->ptrs.nextoffset)
+				return -FDT_ERR_BADLAYOUT;
+			if (fdt_add_region(info, fdt_off_dt_strings(fdt),
+					   fdt_size_dt_strings(fdt)))
+				return 0;
+		}
+		info->ptrs.done++;
+	}
+
+	return info->count > 0 ? 0 : -FDT_ERR_NOTFOUND;
+}
diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c
index bec8b8a..1a358a8 100644
--- a/lib/libfdt/fdt_rw.c
+++ b/lib/libfdt/fdt_rw.c
@@ -449,3 +449,35 @@
 
 	return 0;
 }
+
+int fdt_remove_unused_strings(const void *old, void *new)
+{
+	const struct fdt_property *old_prop;
+	struct fdt_property *new_prop;
+	int size = fdt_totalsize(old);
+	int next_offset, offset;
+	const char *str;
+	int ret;
+	int tag = FDT_PROP;
+
+	/* Make a copy and remove the strings */
+	memcpy(new, old, size);
+	fdt_set_size_dt_strings(new, 0);
+
+	/* Add every property name back into the new string table */
+	for (offset = 0; tag != FDT_END; offset = next_offset) {
+		tag = fdt_next_tag(old, offset, &next_offset);
+		if (tag != FDT_PROP)
+			continue;
+		old_prop = fdt_get_property_by_offset(old, offset, NULL);
+		new_prop = (struct fdt_property *)(unsigned long)
+			fdt_get_property_by_offset(new, offset, NULL);
+		str = fdt_string(old, fdt32_to_cpu(old_prop->nameoff));
+		ret = _fdt_find_add_string(new, str);
+		if (ret < 0)
+			return ret;
+		new_prop->nameoff = cpu_to_fdt32(ret);
+	}
+
+	return 0;
+}
diff --git a/lib/linux_compat.c b/lib/linux_compat.c
index a3d4675..a936a7e 100644
--- a/lib/linux_compat.c
+++ b/lib/linux_compat.c
@@ -16,19 +16,13 @@
 
 void *kmalloc(size_t size, int flags)
 {
-	return memalign(ARCH_DMA_MINALIGN, size);
-}
+	void *p;
 
-void *kzalloc(size_t size, int flags)
-{
-	void *ptr = kmalloc(size, flags);
-	memset(ptr, 0, size);
-	return ptr;
-}
+	p = memalign(ARCH_DMA_MINALIGN, size);
+	if (flags & __GFP_ZERO)
+		memset(p, 0, size);
 
-void *vzalloc(unsigned long size)
-{
-	return kzalloc(size, 0);
+	return p;
 }
 
 struct kmem_cache *get_mem(int element_sz)
diff --git a/lib/rc4.c b/lib/rc4.c
new file mode 100644
index 0000000..89d15f3
--- /dev/null
+++ b/lib/rc4.c
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ *
+ * Rivest Cipher 4 (RC4) implementation
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef USE_HOSTCC
+#include <common.h>
+#endif
+#include <rc4.h>
+
+void rc4_encode(unsigned char *buf, unsigned int len, unsigned char key[16])
+{
+	unsigned char s[256], k[256], temp;
+	unsigned short i, j, t;
+	int ptr;
+
+	j = 0;
+	for (i = 0; i < 256; i++) {
+		s[i] = (unsigned char)i;
+		j &= 0x0f;
+		k[i] = key[j];
+		j++;
+	}
+
+	j = 0;
+	for (i = 0; i < 256; i++) {
+		j = (j + s[i] + k[i]) % 256;
+		temp = s[i];
+		s[i] = s[j];
+		s[j] = temp;
+	}
+
+	i = 0;
+	j = 0;
+	for (ptr = 0; ptr < len; ptr++) {
+		i = (i + 1) % 256;
+		j = (j + s[i]) % 256;
+		temp = s[i];
+		s[i] = s[j];
+		s[j] = temp;
+		t = (s[i] + (s[j] % 256)) % 256;
+		buf[ptr] = buf[ptr] ^ s[t];
+	}
+}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index a9b8a3a..4c82837 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -166,6 +166,25 @@
 	return result;
 }
 
+long trailing_strtoln(const char *str, const char *end)
+{
+	const char *p;
+
+	if (!end)
+		end = str + strlen(str);
+	for (p = end - 1; p > str; p--) {
+		if (!isdigit(*p))
+			return simple_strtoul(p + 1, NULL, 10);
+	}
+
+	return -1;
+}
+
+long trailing_strtol(const char *str)
+{
+	return trailing_strtoln(str, NULL);
+}
+
 /* we use this so that we can do without the ctype library */
 #define is_digit(c)	((c) >= '0' && (c) <= '9')
 
diff --git a/net/eth.c b/net/eth.c
index 953b731..d3ec8d6 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -287,7 +287,13 @@
 			return -EINVAL;
 		}
 
+		/*
+		 * Drivers are allowed to decide not to implement this at
+		 * run-time. E.g. Some devices may use it and some may not.
+		 */
 		ret = eth_get_ops(dev)->write_hwaddr(dev);
+		if (ret == -ENOSYS)
+			ret = 0;
 		if (ret)
 			printf("\nWarning: %s failed to set MAC address\n",
 			       dev->name);
@@ -404,6 +410,7 @@
 {
 	struct udevice *current;
 	uchar *packet;
+	int flags;
 	int ret;
 	int i;
 
@@ -415,8 +422,10 @@
 		return -EINVAL;
 
 	/* Process up to 32 packets at one time */
+	flags = ETH_RECV_CHECK_DEVICE;
 	for (i = 0; i < 32; i++) {
-		ret = eth_get_ops(current)->recv(current, &packet);
+		ret = eth_get_ops(current)->recv(current, flags, &packet);
+		flags = 0;
 		if (ret > 0)
 			net_process_received_packet(packet, ret);
 		if (ret >= 0 && eth_get_ops(current)->free_pkt)
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 481ee5e..b1047b5 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -54,6 +54,7 @@
 libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
 libs-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/
 libs-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/
+libs-$(CONFIG_SPL_CLK_SUPPORT) += drivers/clk/
 libs-$(CONFIG_SPL_DM) += drivers/core/
 libs-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/
 libs-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/
@@ -65,8 +66,10 @@
 libs-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/
 libs-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/
 libs-y += fs/
+libs-$(CONFIG_SPL_LED_SUPPORT) += drivers/led/
 libs-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/
 libs-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/ drivers/power/pmic/
+libs-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/regulator/
 libs-$(CONFIG_SPL_MTD_SUPPORT) += drivers/mtd/
 libs-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/
 libs-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += drivers/misc/
@@ -77,6 +80,7 @@
 libs-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/
 libs-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/phy/
 libs-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/net/phy/
+libs-$(CONFIG_SPL_RAM_SUPPORT) += drivers/ram/
 libs-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/
 libs-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/
 libs-$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/
@@ -152,6 +156,8 @@
 
 ALL-y	+= $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN).cfg
 
+ALL-$(CONFIG_OF_SEPARATE) += $(obj)/$(SPL_BIN)-pad.bin $(obj)/$(SPL_BIN)-dtb.bin
+
 ifdef CONFIG_SAMSUNG
 ALL-y	+= $(obj)/$(BOARD)-spl.bin
 endif
@@ -166,6 +172,32 @@
 
 all:	$(ALL-y)
 
+quiet_cmd_cat = CAT     $@
+cmd_cat = cat $(filter-out $(PHONY), $^) > $@
+
+$(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN)-pad.bin \
+		$(obj)/$(SPL_BIN).dtb FORCE
+	$(call if_changed,cat)
+
+# Create a file that pads from the end of u-boot-spl.bin to bss_end
+$(obj)/$(SPL_BIN)-pad.bin: $(obj)/$(SPL_BIN)
+	@bss_size_str=$(shell $(NM) $< | awk 'BEGIN {size = 0} /__bss_size/ {size = $$1} END {print "ibase=16; " toupper(size)}' | bc); \
+	dd if=/dev/zero of=$@ bs=1 count=$${bss_size_str} 2>/dev/null;
+
+# Pass the original device tree file through fdtgrep twice. The first pass
+# removes any unwanted nodes (i.e. those which don't have the
+# 'u-boot,dm-pre-reloc' property and thus are not needed by SPL. The second
+# pass removes various unused properties from the remaining nodes.
+# The output is typically a much smaller device tree file.
+quiet_cmd_fdtgrep = FDTGREP $@
+      cmd_fdtgrep = $(objtree)/tools/fdtgrep -b u-boot,dm-pre-reloc -RT $< \
+		-n /chosen -O dtb | \
+	$(objtree)/tools/fdtgrep -r -O dtb - -o $@ \
+		$(addprefix -P ,$(subst $\",,$(CONFIG_OF_SPL_REMOVE_PROPS)))
+
+$(obj)/$(SPL_BIN).dtb: dts/dt.dtb
+	$(call cmd,fdtgrep)
+
 quiet_cmd_cpp_cfg = CFG     $@
 cmd_cpp_cfg = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) -ansi \
 	-DDO_DEPS_ONLY -D__ASSEMBLY__ -x assembler-with-cpp -P -dM -E -o $@ $<
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 19ad2fb..eda9643 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -15,13 +15,20 @@
 # subsystem you must add sandbox tests here.
 obj-$(CONFIG_UT_DM) += core.o
 ifneq ($(CONFIG_SANDBOX),)
+obj-$(CONFIG_CLK) += clk.o
 obj-$(CONFIG_DM_ETH) += eth.o
 obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_I2C) += i2c.o
+obj-$(CONFIG_LED) += led.o
+obj-$(CONFIG_DM_MMC) += mmc.o
 obj-$(CONFIG_DM_PCI) += pci.o
+obj-$(CONFIG_RAM) += ram.o
+obj-y += regmap.o
+obj-$(CONFIG_RESET) += reset.o
 obj-$(CONFIG_DM_RTC) += rtc.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 obj-$(CONFIG_DM_SPI) += spi.o
+obj-y += syscon.o
 obj-$(CONFIG_DM_USB) += usb.o
 obj-$(CONFIG_DM_PMIC) += pmic.o
 obj-$(CONFIG_DM_REGULATOR) += regulator.o
diff --git a/test/dm/clk.c b/test/dm/clk.c
new file mode 100644
index 0000000..9ff6d95
--- /dev/null
+++ b/test/dm/clk.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <linux/err.h>
+#include <test/ut.h>
+
+/* Test that we can find and adjust clocks */
+static int dm_test_clk_base(struct unit_test_state *uts)
+{
+	struct udevice *clk;
+	ulong rate;
+
+	ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk));
+	rate = clk_get_rate(clk);
+	ut_asserteq(SANDBOX_CLK_RATE, rate);
+	ut_asserteq(-EINVAL, clk_set_rate(clk, 0));
+	ut_assertok(clk_set_rate(clk, rate * 2));
+	ut_asserteq(SANDBOX_CLK_RATE * 2, clk_get_rate(clk));
+
+	return 0;
+}
+DM_TEST(dm_test_clk_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that peripheral clocks work as expected */
+static int dm_test_clk_periph(struct unit_test_state *uts)
+{
+	struct udevice *clk;
+	ulong rate;
+
+	ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk));
+	rate = clk_set_periph_rate(clk, PERIPH_ID_COUNT, 123);
+	ut_asserteq(-EINVAL, rate);
+	ut_asserteq(1, IS_ERR_VALUE(rate));
+
+	rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 123);
+	ut_asserteq(0, rate);
+	ut_asserteq(123, clk_get_periph_rate(clk, PERIPH_ID_SPI));
+
+	rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234);
+	ut_asserteq(123, rate);
+
+	rate = clk_set_periph_rate(clk, PERIPH_ID_I2C, 567);
+
+	rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234);
+	ut_asserteq(1234, rate);
+
+	ut_asserteq(567, clk_get_periph_rate(clk, PERIPH_ID_I2C));
+
+	return 0;
+}
+DM_TEST(dm_test_clk_periph, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c
index 5bb2a99..5c501ec 100644
--- a/test/dm/cmd_dm.c
+++ b/test/dm/cmd_dm.c
@@ -14,96 +14,20 @@
 #include <errno.h>
 #include <asm/io.h>
 #include <dm/root.h>
-#include <dm/uclass-internal.h>
-
-static void show_devices(struct udevice *dev, int depth, int last_flag)
-{
-	int i, is_last;
-	struct udevice *child;
-	char class_name[12];
-
-	/* print the first 11 characters to not break the tree-format. */
-	strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name));
-	printf(" %-11s [ %c ]    ", class_name,
-	       dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ');
-
-	for (i = depth; i >= 0; i--) {
-		is_last = (last_flag >> i) & 1;
-		if (i) {
-			if (is_last)
-				printf("    ");
-			else
-				printf("|   ");
-		} else {
-			if (is_last)
-				printf("`-- ");
-			else
-				printf("|-- ");
-		}
-	}
-
-	printf("%s\n", dev->name);
-
-	list_for_each_entry(child, &dev->child_head, sibling_node) {
-		is_last = list_is_last(&child->sibling_node, &dev->child_head);
-		show_devices(child, depth + 1, (last_flag << 1) | is_last);
-	}
-}
+#include <dm/util.h>
 
 static int do_dm_dump_all(cmd_tbl_t *cmdtp, int flag, int argc,
 			  char * const argv[])
 {
-	struct udevice *root;
-
-	root = dm_root();
-	if (root) {
-		printf(" Class       Probed   Name\n");
-		printf("----------------------------------------\n");
-		show_devices(root, -1, 0);
-	}
+	dm_dump_all();
 
 	return 0;
 }
 
-/**
- * dm_display_line() - Display information about a single device
- *
- * Displays a single line of information with an option prefix
- *
- * @dev:	Device to display
- */
-static void dm_display_line(struct udevice *dev)
-{
-	printf("- %c %s @ %08lx",
-	       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
-	       dev->name, (ulong)map_to_sysmem(dev));
-	if (dev->seq != -1 || dev->req_seq != -1)
-		printf(", seq %d, (req %d)", dev->seq, dev->req_seq);
-	puts("\n");
-}
-
 static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc,
 			     char * const argv[])
 {
-	struct uclass *uc;
-	int ret;
-	int id;
-
-	for (id = 0; id < UCLASS_COUNT; id++) {
-		struct udevice *dev;
-
-		ret = uclass_get(id, &uc);
-		if (ret)
-			continue;
-
-		printf("uclass %d: %s\n", id, uc->uc_drv->name);
-		if (list_empty(&uc->dev_head))
-			continue;
-		list_for_each_entry(dev, &uc->dev_head, uclass_node) {
-			dm_display_line(dev);
-		}
-		puts("\n");
-	}
+	dm_dump_uclass();
 
 	return 0;
 }
diff --git a/test/dm/led.c b/test/dm/led.c
new file mode 100644
index 0000000..8ee075c
--- /dev/null
+++ b/test/dm/led.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <led.h>
+#include <asm/gpio.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Base test of the led uclass */
+static int dm_test_led_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	/* Get the top-level device */
+	ut_assertok(uclass_get_device(UCLASS_LED, 0, &dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 2, &dev));
+	ut_asserteq(-ENODEV, uclass_get_device(UCLASS_LED, 3, &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_led_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test of the led uclass using the led_gpio driver */
+static int dm_test_led_gpio(struct unit_test_state *uts)
+{
+	const int offset = 1;
+	struct udevice *dev, *gpio;
+
+	/*
+	 * Check that we can manipulate an LED. LED 1 is connected to GPIO
+	 * bank gpio_a, offset 1.
+	 */
+	ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
+	ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio));
+	ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+	led_set_on(dev, 1);
+	ut_asserteq(1, sandbox_gpio_get_value(gpio, offset));
+	led_set_on(dev, 0);
+	ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+
+	return 0;
+}
+DM_TEST(dm_test_led_gpio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test obtaining an LED by label */
+static int dm_test_led_label(struct unit_test_state *uts)
+{
+	struct udevice *dev, *cmp;
+
+	ut_assertok(led_get_by_label("sandbox:red", &dev));
+	ut_asserteq(1, device_active(dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 1, &cmp));
+	ut_asserteq_ptr(dev, cmp);
+
+	ut_assertok(led_get_by_label("sandbox:green", &dev));
+	ut_asserteq(1, device_active(dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 2, &cmp));
+	ut_asserteq_ptr(dev, cmp);
+
+	ut_asserteq(-ENODEV, led_get_by_label("sandbox:blue", &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_led_label, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/mmc.c b/test/dm/mmc.c
new file mode 100644
index 0000000..0461423
--- /dev/null
+++ b/test/dm/mmc.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mmc.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Basic test of the mmc uclass. We could expand this by implementing an MMC
+ * stack for sandbox, or at least implementing the basic operation.
+ */
+static int dm_test_mmc_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_mmc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/ram.c b/test/dm/ram.c
new file mode 100644
index 0000000..3a7c5ff
--- /dev/null
+++ b/test/dm/ram.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Basic test of the ram uclass */
+static int dm_test_ram_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	struct ram_info info;
+
+	ut_assertok(uclass_get_device(UCLASS_RAM, 0, &dev));
+	ut_assertok(ram_get_info(dev, &info));
+	ut_asserteq(0, info.base);
+	ut_asserteq(gd->ram_size, info.size);
+
+	return 0;
+}
+DM_TEST(dm_test_ram_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/regmap.c b/test/dm/regmap.c
new file mode 100644
index 0000000..7f66058
--- /dev/null
+++ b/test/dm/regmap.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+2 *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Base test of register maps */
+static int dm_test_regmap_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	struct regmap *map;
+	int i;
+
+	ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
+	map = syscon_get_regmap(dev);
+	ut_assertok_ptr(map);
+	ut_asserteq(1, map->range_count);
+	ut_asserteq(0x10, map->base);
+	ut_asserteq(0x10, map->range->start);
+	ut_asserteq(4, map->range->size);
+	ut_asserteq_ptr(&map->base_range, map->range);
+	ut_asserteq(0x10, map_to_sysmem(regmap_get_range(map, 0)));
+
+	ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev));
+	map = syscon_get_regmap(dev);
+	ut_assertok_ptr(map);
+	ut_asserteq(4, map->range_count);
+	ut_asserteq(0x20, map->base);
+	ut_assert(&map->base_range != map->range);
+	for (i = 0; i < 4; i++) {
+		const unsigned long addr = 0x20 + 8 * i;
+
+		ut_asserteq(addr, map->range[i].start);
+		ut_asserteq(5 + i, map->range[i].size);
+		ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i)));
+	}
+
+	/* Check that we can't pretend a different device is a syscon */
+	ut_assertok(uclass_get_device(UCLASS_I2C, 0, &dev));
+	map = syscon_get_regmap(dev);
+	ut_asserteq_ptr(ERR_PTR(-ENOEXEC), map);
+
+	return 0;
+}
+DM_TEST(dm_test_regmap_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test we can access a regmap through syscon */
+static int dm_test_regmap_syscon(struct unit_test_state *uts)
+{
+	struct regmap *map;
+
+	map = syscon_get_regmap_by_driver_data(SYSCON0);
+	ut_assertok_ptr(map);
+	ut_asserteq(1, map->range_count);
+
+	map = syscon_get_regmap_by_driver_data(SYSCON1);
+	ut_assertok_ptr(map);
+	ut_asserteq(4, map->range_count);
+
+	map = syscon_get_regmap_by_driver_data(SYSCON_COUNT);
+	ut_asserteq_ptr(ERR_PTR(-ENODEV), map);
+
+	ut_asserteq(0x10, map_to_sysmem(syscon_get_first_range(SYSCON0)));
+	ut_asserteq(0x20, map_to_sysmem(syscon_get_first_range(SYSCON1)));
+	ut_asserteq_ptr(ERR_PTR(-ENODEV),
+			syscon_get_first_range(SYSCON_COUNT));
+
+	return 0;
+}
+
+DM_TEST(dm_test_regmap_syscon, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/regulator.c b/test/dm/regulator.c
index d279c04..3d0056f 100644
--- a/test/dm/regulator.c
+++ b/test/dm/regulator.c
@@ -210,7 +210,7 @@
 	 * Expected output state: uV=1200000; uA=200000; output enabled
 	 */
 	platname = regulator_names[BUCK1][PLATNAME];
-	ut_assertok(regulator_autoset(platname, &dev_autoset, false));
+	ut_assertok(regulator_autoset_by_name(platname, &dev_autoset));
 
 	/* Check, that the returned device is proper */
 	ut_assertok(regulator_get_by_platname(platname, &dev));
diff --git a/test/dm/reset.c b/test/dm/reset.c
new file mode 100644
index 0000000..5d53f25
--- /dev/null
+++ b/test/dm/reset.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <reset.h>
+#include <asm/state.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Test that we can use particular reset devices */
+static int dm_test_reset_base(struct unit_test_state *uts)
+{
+	struct sandbox_state *state = state_get_current();
+	struct udevice *dev;
+
+	/* Device 0 is the platform data device - it should never respond */
+	ut_assertok(uclass_get_device(UCLASS_RESET, 0, &dev));
+	ut_asserteq(-ENODEV, reset_request(dev, RESET_WARM));
+	ut_asserteq(-ENODEV, reset_request(dev, RESET_COLD));
+	ut_asserteq(-ENODEV, reset_request(dev, RESET_POWER));
+
+	/* Device 1 is the warm reset device */
+	ut_assertok(uclass_get_device(UCLASS_RESET, 1, &dev));
+	ut_asserteq(-EACCES, reset_request(dev, RESET_WARM));
+	ut_asserteq(-ENOSYS, reset_request(dev, RESET_COLD));
+	ut_asserteq(-ENOSYS, reset_request(dev, RESET_POWER));
+
+	state->reset_allowed[RESET_WARM] = true;
+	ut_asserteq(-EINPROGRESS, reset_request(dev, RESET_WARM));
+	state->reset_allowed[RESET_WARM] = false;
+
+	/* Device 2 is the cold reset device */
+	ut_assertok(uclass_get_device(UCLASS_RESET, 2, &dev));
+	ut_asserteq(-ENOSYS, reset_request(dev, RESET_WARM));
+	ut_asserteq(-EACCES, reset_request(dev, RESET_COLD));
+	state->reset_allowed[RESET_POWER] = false;
+	ut_asserteq(-EACCES, reset_request(dev, RESET_POWER));
+	state->reset_allowed[RESET_POWER] = true;
+
+	return 0;
+}
+DM_TEST(dm_test_reset_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that we can walk through the reset devices */
+static int dm_test_reset_walk(struct unit_test_state *uts)
+{
+	struct sandbox_state *state = state_get_current();
+
+	/* If we generate a power reset, we will exit sandbox! */
+	state->reset_allowed[RESET_POWER] = false;
+	ut_asserteq(-EACCES, reset_walk(RESET_WARM));
+	ut_asserteq(-EACCES, reset_walk(RESET_COLD));
+	ut_asserteq(-EACCES, reset_walk(RESET_POWER));
+
+	/*
+	 * Enable cold reset - this should make cold reset work, plus a warm
+	 * reset should be promoted to cold, since this is the next step
+	 * along.
+	 */
+	state->reset_allowed[RESET_COLD] = true;
+	ut_asserteq(-EINPROGRESS, reset_walk(RESET_WARM));
+	ut_asserteq(-EINPROGRESS, reset_walk(RESET_COLD));
+	ut_asserteq(-EACCES, reset_walk(RESET_POWER));
+	state->reset_allowed[RESET_COLD] = false;
+	state->reset_allowed[RESET_POWER] = true;
+
+	return 0;
+}
+DM_TEST(dm_test_reset_walk, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/syscon.c b/test/dm/syscon.c
new file mode 100644
index 0000000..3642481
--- /dev/null
+++ b/test/dm/syscon.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Base test of system controllers */
+static int dm_test_syscon_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
+	ut_asserteq(SYSCON0, dev->driver_data);
+
+	ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev));
+	ut_asserteq(SYSCON1, dev->driver_data);
+
+	ut_asserteq(-ENODEV, uclass_get_device(UCLASS_SYSCON, 2, &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_syscon_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-main.c b/test/dm/test-main.c
index 0477d2f..0e43ab9 100644
--- a/test/dm/test-main.c
+++ b/test/dm/test-main.c
@@ -76,6 +76,7 @@
 	struct unit_test_state *uts = &global_dm_test_state;
 	uts->priv = &_global_priv_dm_test_state;
 	struct unit_test *test;
+	int run_count;
 
 	/*
 	 * If we have no device tree, or it only has a root node, then these
@@ -90,10 +91,17 @@
 	if (!test_name)
 		printf("Running %d driver model tests\n", n_ents);
 
+	run_count = 0;
 	for (test = tests; test < tests + n_ents; test++) {
-		if (test_name && strcmp(test_name, test->name))
+		const char *name = test->name;
+
+		/* All tests have this prefix */
+		if (!strncmp(name, "dm_test_", 8))
+			name += 8;
+		if (test_name && strcmp(test_name, name))
 			continue;
 		printf("Test: %s\n", test->name);
+		run_count++;
 		ut_assertok(dm_test_init(uts));
 
 		uts->start = mallinfo();
@@ -109,7 +117,10 @@
 		ut_assertok(dm_test_destroy(uts));
 	}
 
-	printf("Failures: %d\n", uts->fail_count);
+	if (test_name && !run_count)
+		printf("Test '%s' not found\n", test_name);
+	else
+		printf("Failures: %d\n", uts->fail_count);
 
 	gd->dm_root = NULL;
 	ut_assertok(dm_init());
diff --git a/tools/Makefile b/tools/Makefile
index 8ff9c2e..98414f7 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -58,7 +58,8 @@
 FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := common/image-sig.o
 # Flattened device tree objects
 LIBFDT_OBJS := $(addprefix lib/libfdt/, \
-			fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o)
+			fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o \
+			fdt_region.o)
 RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \
 					rsa-sign.o rsa-verify.o rsa-checksum.o \
 					rsa-mod-exp.o)
@@ -155,6 +156,9 @@
 hostprogs-y += proftool
 hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela
 
+hostprogs-y += fdtgrep
+fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o
+
 # We build some files with extra pedantic flags to try to minimize things
 # that won't build on some weird host compiler -- though there are lots of
 # exceptions for files that aren't complaint.
diff --git a/tools/fdtgrep.c b/tools/fdtgrep.c
new file mode 100644
index 0000000..caaf600
--- /dev/null
+++ b/tools/fdtgrep.c
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Perform a grep of an FDT either displaying the source subset or producing
+ * a new .dtb subset which can be used as required.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <../include/libfdt.h>
+#include <libfdt_internal.h>
+
+/* Define DEBUG to get some debugging output on stderr */
+#ifdef DEBUG
+#define debug(a, b...) fprintf(stderr, a, ## b)
+#else
+#define debug(a, b...)
+#endif
+
+/* A linked list of values we are grepping for */
+struct value_node {
+	int type;		/* Types this value matches (FDT_IS... mask) */
+	int include;		/* 1 to include matches, 0 to exclude */
+	const char *string;	/* String to match */
+	struct value_node *next;	/* Pointer to next node, or NULL */
+};
+
+/* Output formats we support */
+enum output_t {
+	OUT_DTS,		/* Device tree source */
+	OUT_DTB,		/* Valid device tree binary */
+	OUT_BIN,		/* Fragment of .dtb, for hashing */
+};
+
+/* Holds information which controls our output and options */
+struct display_info {
+	enum output_t output;	/* Output format */
+	int add_aliases;	/* Add aliases node to output */
+	int all;		/* Display all properties/nodes */
+	int colour;		/* Display output in ANSI colour */
+	int region_list;	/* Output a region list */
+	int flags;		/* Flags (FDT_REG_...) */
+	int list_strings;	/* List strings in string table */
+	int show_offset;	/* Show offset */
+	int show_addr;		/* Show address */
+	int header;		/* Output an FDT header */
+	int diff;		/* Show +/- diff markers */
+	int include_root;	/* Include the root node and all properties */
+	int remove_strings;	/* Remove unused strings */
+	int show_dts_version;	/* Put '/dts-v1/;' on the first line */
+	int types_inc;		/* Mask of types that we include (FDT_IS...) */
+	int types_exc;		/* Mask of types that we exclude (FDT_IS...) */
+	int invert;		/* Invert polarity of match */
+	struct value_node *value_head;	/* List of values to match */
+	const char *output_fname;	/* Output filename */
+	FILE *fout;		/* File to write dts/dtb output */
+};
+
+static void report_error(const char *where, int err)
+{
+	fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
+}
+
+/* Supported ANSI colours */
+enum {
+	COL_BLACK,
+	COL_RED,
+	COL_GREEN,
+	COL_YELLOW,
+	COL_BLUE,
+	COL_MAGENTA,
+	COL_CYAN,
+	COL_WHITE,
+
+	COL_NONE = -1,
+};
+
+/**
+ * print_ansi_colour() - Print out the ANSI sequence for a colour
+ *
+ * @fout:	Output file
+ * @col:	Colour to output (COL_...), or COL_NONE to reset colour
+ */
+static void print_ansi_colour(FILE *fout, int col)
+{
+	if (col == COL_NONE)
+		fprintf(fout, "\033[0m");
+	else
+		fprintf(fout, "\033[1;%dm", col + 30);
+}
+
+
+/**
+ * value_add() - Add a new value to our list of things to grep for
+ *
+ * @disp:	Display structure, holding info about our options
+ * @headp:	Pointer to header pointer of list
+ * @type:	Type of this value (FDT_IS_...)
+ * @include:	1 if we want to include matches, 0 to exclude
+ * @str:	String value to match
+ */
+static int value_add(struct display_info *disp, struct value_node **headp,
+		     int type, int include, const char *str)
+{
+	struct value_node *node;
+
+	/*
+	 * Keep track of which types we are excluding/including. We don't
+	 * allow both including and excluding things, because it doesn't make
+	 * sense. 'Including' means that everything not mentioned is
+	 * excluded. 'Excluding' means that everything not mentioned is
+	 * included. So using the two together would be meaningless.
+	 */
+	if (include)
+		disp->types_inc |= type;
+	else
+		disp->types_exc |= type;
+	if (disp->types_inc & disp->types_exc & type) {
+		fprintf(stderr,
+			"Cannot use both include and exclude for '%s'\n", str);
+		return -1;
+	}
+
+	str = strdup(str);
+	node = malloc(sizeof(*node));
+	if (!str || !node) {
+		fprintf(stderr, "Out of memory\n");
+		return -1;
+	}
+	node->next = *headp;
+	node->type = type;
+	node->include = include;
+	node->string = str;
+	*headp = node;
+
+	return 0;
+}
+
+static bool util_is_printable_string(const void *data, int len)
+{
+	const char *s = data;
+	const char *ss, *se;
+
+	/* zero length is not */
+	if (len == 0)
+		return 0;
+
+	/* must terminate with zero */
+	if (s[len - 1] != '\0')
+		return 0;
+
+	se = s + len;
+
+	while (s < se) {
+		ss = s;
+		while (s < se && *s && isprint((unsigned char)*s))
+			s++;
+
+		/* not zero, or not done yet */
+		if (*s != '\0' || s == ss)
+			return 0;
+
+		s++;
+	}
+
+	return 1;
+}
+
+static void utilfdt_print_data(const char *data, int len)
+{
+	int i;
+	const char *p = data;
+	const char *s;
+
+	/* no data, don't print */
+	if (len == 0)
+		return;
+
+	if (util_is_printable_string(data, len)) {
+		printf(" = ");
+
+		s = data;
+		do {
+			printf("\"%s\"", s);
+			s += strlen(s) + 1;
+			if (s < data + len)
+				printf(", ");
+		} while (s < data + len);
+
+	} else if ((len % 4) == 0) {
+		const uint32_t *cell = (const uint32_t *)data;
+
+		printf(" = <");
+		for (i = 0, len /= 4; i < len; i++)
+			printf("0x%08x%s", fdt32_to_cpu(cell[i]),
+			       i < (len - 1) ? " " : "");
+		printf(">");
+	} else {
+		printf(" = [");
+		for (i = 0; i < len; i++)
+			printf("%02x%s", *p++, i < len - 1 ? " " : "");
+		printf("]");
+	}
+}
+
+/**
+ * display_fdt_by_regions() - Display regions of an FDT source
+ *
+ * This dumps an FDT as source, but only certain regions of it. This is the
+ * final stage of the grep - we have a list of regions we want to display,
+ * and this function displays them.
+ *
+ * @disp:	Display structure, holding info about our options
+ * @blob:	FDT blob to display
+ * @region:	List of regions to display
+ * @count:	Number of regions
+ */
+static int display_fdt_by_regions(struct display_info *disp, const void *blob,
+		struct fdt_region region[], int count)
+{
+	struct fdt_region *reg = region, *reg_end = region + count;
+	uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
+	int base = fdt_off_dt_struct(blob);
+	int version = fdt_version(blob);
+	int offset, nextoffset;
+	int tag, depth, shift;
+	FILE *f = disp->fout;
+	uint64_t addr, size;
+	int in_region;
+	int file_ofs;
+	int i;
+
+	if (disp->show_dts_version)
+		fprintf(f, "/dts-v1/;\n");
+
+	if (disp->header) {
+		fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
+		fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
+			fdt_totalsize(blob));
+		fprintf(f, "// off_dt_struct:\t0x%x\n",
+			fdt_off_dt_struct(blob));
+		fprintf(f, "// off_dt_strings:\t0x%x\n",
+			fdt_off_dt_strings(blob));
+		fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
+		fprintf(f, "// version:\t\t%d\n", version);
+		fprintf(f, "// last_comp_version:\t%d\n",
+			fdt_last_comp_version(blob));
+		if (version >= 2) {
+			fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
+				fdt_boot_cpuid_phys(blob));
+		}
+		if (version >= 3) {
+			fprintf(f, "// size_dt_strings:\t0x%x\n",
+				fdt_size_dt_strings(blob));
+		}
+		if (version >= 17) {
+			fprintf(f, "// size_dt_struct:\t0x%x\n",
+				fdt_size_dt_struct(blob));
+		}
+		fprintf(f, "\n");
+	}
+
+	if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
+		const struct fdt_reserve_entry *p_rsvmap;
+
+		p_rsvmap = (const struct fdt_reserve_entry *)
+				((const char *)blob + off_mem_rsvmap);
+		for (i = 0; ; i++) {
+			addr = fdt64_to_cpu(p_rsvmap[i].address);
+			size = fdt64_to_cpu(p_rsvmap[i].size);
+			if (addr == 0 && size == 0)
+				break;
+
+			fprintf(f, "/memreserve/ %llx %llx;\n",
+				(unsigned long long)addr,
+				(unsigned long long)size);
+		}
+	}
+
+	depth = 0;
+	nextoffset = 0;
+	shift = 4;	/* 4 spaces per indent */
+	do {
+		const struct fdt_property *prop;
+		const char *name;
+		int show;
+		int len;
+
+		offset = nextoffset;
+
+		/*
+		 * Work out the file offset of this offset, and decide
+		 * whether it is in the region list or not
+		 */
+		file_ofs = base + offset;
+		if (reg < reg_end && file_ofs >= reg->offset + reg->size)
+			reg++;
+		in_region = reg < reg_end && file_ofs >= reg->offset &&
+				file_ofs < reg->offset + reg->size;
+		tag = fdt_next_tag(blob, offset, &nextoffset);
+
+		if (tag == FDT_END)
+			break;
+		show = in_region || disp->all;
+		if (show && disp->diff)
+			fprintf(f, "%c", in_region ? '+' : '-');
+
+		if (!show) {
+			/* Do this here to avoid 'if (show)' in every 'case' */
+			if (tag == FDT_BEGIN_NODE)
+				depth++;
+			else if (tag == FDT_END_NODE)
+				depth--;
+			continue;
+		}
+		if (tag != FDT_END) {
+			if (disp->show_addr)
+				fprintf(f, "%4x: ", file_ofs);
+			if (disp->show_offset)
+				fprintf(f, "%4x: ", file_ofs - base);
+		}
+
+		/* Green means included, red means excluded */
+		if (disp->colour)
+			print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);
+
+		switch (tag) {
+		case FDT_PROP:
+			prop = fdt_get_property_by_offset(blob, offset, NULL);
+			name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
+			fprintf(f, "%*s%s", depth * shift, "", name);
+			utilfdt_print_data(prop->data,
+					   fdt32_to_cpu(prop->len));
+			fprintf(f, ";");
+			break;
+
+		case FDT_NOP:
+			fprintf(f, "%*s// [NOP]", depth * shift, "");
+			break;
+
+		case FDT_BEGIN_NODE:
+			name = fdt_get_name(blob, offset, &len);
+			fprintf(f, "%*s%s {", depth++ * shift, "",
+				*name ? name : "/");
+			break;
+
+		case FDT_END_NODE:
+			fprintf(f, "%*s};", --depth * shift, "");
+			break;
+		}
+
+		/* Reset colour back to normal before end of line */
+		if (disp->colour)
+			print_ansi_colour(f, COL_NONE);
+		fprintf(f, "\n");
+	} while (1);
+
+	/* Print a list of strings if requested */
+	if (disp->list_strings) {
+		const char *str;
+		int str_base = fdt_off_dt_strings(blob);
+
+		for (offset = 0; offset < fdt_size_dt_strings(blob);
+				offset += strlen(str) + 1) {
+			str = fdt_string(blob, offset);
+			int len = strlen(str) + 1;
+			int show;
+
+			/* Only print strings that are in the region */
+			file_ofs = str_base + offset;
+			in_region = reg < reg_end &&
+					file_ofs >= reg->offset &&
+					file_ofs + len < reg->offset +
+						reg->size;
+			show = in_region || disp->all;
+			if (show && disp->diff)
+				printf("%c", in_region ? '+' : '-');
+			if (disp->show_addr)
+				printf("%4x: ", file_ofs);
+			if (disp->show_offset)
+				printf("%4x: ", offset);
+			printf("%s\n", str);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * dump_fdt_regions() - Dump regions of an FDT as binary data
+ *
+ * This dumps an FDT as binary, but only certain regions of it. This is the
+ * final stage of the grep - we have a list of regions we want to dump,
+ * and this function dumps them.
+ *
+ * The output of this function may or may not be a valid FDT. To ensure it
+ * is, these disp->flags must be set:
+ *
+ *   FDT_REG_SUPERNODES: ensures that subnodes are preceeded by their
+ *		parents. Without this option, fragments of subnode data may be
+ *		output without the supernodes above them. This is useful for
+ *		hashing but cannot produce a valid FDT.
+ *   FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
+ *		Without this none of the properties will have names
+ *   FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
+ *		without this.
+ *
+ * @disp:	Display structure, holding info about our options
+ * @blob:	FDT blob to display
+ * @region:	List of regions to display
+ * @count:	Number of regions
+ * @out:	Output destination
+ */
+static int dump_fdt_regions(struct display_info *disp, const void *blob,
+		struct fdt_region region[], int count, char *out)
+{
+	struct fdt_header *fdt;
+	int size, struct_start;
+	int ptr;
+	int i;
+
+	/* Set up a basic header (even if we don't actually write it) */
+	fdt = (struct fdt_header *)out;
+	memset(fdt, '\0', sizeof(*fdt));
+	fdt_set_magic(fdt, FDT_MAGIC);
+	struct_start = FDT_ALIGN(sizeof(struct fdt_header),
+					sizeof(struct fdt_reserve_entry));
+	fdt_set_off_mem_rsvmap(fdt, struct_start);
+	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+
+	/*
+	 * Calculate the total size of the regions we are writing out. The
+	 * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
+	 * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
+	 * is set.
+	 */
+	for (i = size = 0; i < count; i++)
+		size += region[i].size;
+
+	/* Bring in the mem_rsvmap section from the old file if requested */
+	if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
+		struct_start += region[0].size;
+		size -= region[0].size;
+	}
+	fdt_set_off_dt_struct(fdt, struct_start);
+
+	/* Update the header to have the correct offsets/sizes */
+	if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
+		int str_size;
+
+		str_size = region[count - 1].size;
+		fdt_set_size_dt_struct(fdt, size - str_size);
+		fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
+		fdt_set_size_dt_strings(fdt, str_size);
+		fdt_set_totalsize(fdt, struct_start + size);
+	}
+
+	/* Write the header if required */
+	ptr = 0;
+	if (disp->header) {
+		ptr = sizeof(*fdt);
+		while (ptr < fdt_off_mem_rsvmap(fdt))
+			out[ptr++] = '\0';
+	}
+
+	/* Output all the nodes including any mem_rsvmap/string table */
+	for (i = 0; i < count; i++) {
+		struct fdt_region *reg = &region[i];
+
+		memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
+		ptr += reg->size;
+	}
+
+	return ptr;
+}
+
+/**
+ * show_region_list() - Print out a list of regions
+ *
+ * The list includes the region offset (absolute offset from start of FDT
+ * blob in bytes) and size
+ *
+ * @reg:	List of regions to print
+ * @count:	Number of regions
+ */
+static void show_region_list(struct fdt_region *reg, int count)
+{
+	int i;
+
+	printf("Regions: %d\n", count);
+	for (i = 0; i < count; i++, reg++) {
+		printf("%d:  %-10x  %-10x\n", i, reg->offset,
+		       reg->offset + reg->size);
+	}
+}
+
+static int check_type_include(void *priv, int type, const char *data, int size)
+{
+	struct display_info *disp = priv;
+	struct value_node *val;
+	int match, none_match = FDT_IS_ANY;
+
+	/* If none of our conditions mention this type, we know nothing */
+	debug("type=%x, data=%s\n", type, data ? data : "(null)");
+	if (!((disp->types_inc | disp->types_exc) & type)) {
+		debug("   - not in any condition\n");
+		return -1;
+	}
+
+	/*
+	 * Go through the list of conditions. For inclusive conditions, we
+	 * return 1 at the first match. For exclusive conditions, we must
+	 * check that there are no matches.
+	 */
+	for (val = disp->value_head; val; val = val->next) {
+		if (!(type & val->type))
+			continue;
+		match = fdt_stringlist_contains(data, size, val->string);
+		debug("      - val->type=%x, str='%s', match=%d\n",
+		      val->type, val->string, match);
+		if (match && val->include) {
+			debug("   - match inc %s\n", val->string);
+			return 1;
+		}
+		if (match)
+			none_match &= ~val->type;
+	}
+
+	/*
+	 * If this is an exclusive condition, and nothing matches, then we
+	 * should return 1.
+	 */
+	if ((type & disp->types_exc) && (none_match & type)) {
+		debug("   - match exc\n");
+		/*
+		 * Allow FDT_IS_COMPAT to make the final decision in the
+		 * case where there is no specific type
+		 */
+		if (type == FDT_IS_NODE && disp->types_exc == FDT_ANY_GLOBAL) {
+			debug("   - supressed exc node\n");
+			return -1;
+		}
+		return 1;
+	}
+
+	/*
+	 * Allow FDT_IS_COMPAT to make the final decision in the
+	 * case where there is no specific type (inclusive)
+	 */
+	if (type == FDT_IS_NODE && disp->types_inc == FDT_ANY_GLOBAL)
+		return -1;
+
+	debug("   - no match, types_inc=%x, types_exc=%x, none_match=%x\n",
+	      disp->types_inc, disp->types_exc, none_match);
+
+	return 0;
+}
+
+/**
+ * h_include() - Include handler function for fdt_find_regions()
+ *
+ * This function decides whether to include or exclude a node, property or
+ * compatible string. The function is defined by fdt_find_regions().
+ *
+ * The algorithm is documented in the code - disp->invert is 0 for normal
+ * operation, and 1 to invert the sense of all matches.
+ *
+ * See
+ */
+static int h_include(void *priv, const void *fdt, int offset, int type,
+		     const char *data, int size)
+{
+	struct display_info *disp = priv;
+	int inc, len;
+
+	inc = check_type_include(priv, type, data, size);
+	if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc)
+		return 1;
+
+	/*
+	 * If the node name does not tell us anything, check the
+	 * compatible string
+	 */
+	if (inc == -1 && type == FDT_IS_NODE) {
+		debug("   - checking compatible2\n");
+		data = fdt_getprop(fdt, offset, "compatible", &len);
+		inc = check_type_include(priv, FDT_IS_COMPAT, data, len);
+	}
+
+	/* If we still have no idea, check for properties in the node */
+	if (inc != 1 && type == FDT_IS_NODE &&
+	    (disp->types_inc & FDT_NODE_HAS_PROP)) {
+		debug("   - checking node '%s'\n",
+		      fdt_get_name(fdt, offset, NULL));
+		for (offset = fdt_first_property_offset(fdt, offset);
+		     offset > 0 && inc != 1;
+		     offset = fdt_next_property_offset(fdt, offset)) {
+			const struct fdt_property *prop;
+			const char *str;
+
+			prop = fdt_get_property_by_offset(fdt, offset, NULL);
+			if (!prop)
+				continue;
+			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+			inc = check_type_include(priv, FDT_NODE_HAS_PROP, str,
+						 strlen(str));
+		}
+		if (inc == -1)
+			inc = 0;
+	}
+
+	switch (inc) {
+	case 1:
+		inc = !disp->invert;
+		break;
+	case 0:
+		inc = disp->invert;
+		break;
+	}
+	debug("   - returning %d\n", inc);
+
+	return inc;
+}
+
+static int h_cmp_region(const void *v1, const void *v2)
+{
+	const struct fdt_region *region1 = v1, *region2 = v2;
+
+	return region1->offset - region2->offset;
+}
+
+static int fdtgrep_find_regions(const void *fdt,
+		int (*include_func)(void *priv, const void *fdt, int offset,
+				 int type, const char *data, int size),
+		struct display_info *disp, struct fdt_region *region,
+		int max_regions, char *path, int path_len, int flags)
+{
+	struct fdt_region_state state;
+	int count;
+	int ret;
+
+	count = 0;
+	ret = fdt_first_region(fdt, include_func, disp,
+			&region[count++], path, path_len,
+			disp->flags, &state);
+	while (ret == 0) {
+		ret = fdt_next_region(fdt, include_func, disp,
+				count < max_regions ? &region[count] : NULL,
+				path, path_len, disp->flags, &state);
+		if (!ret)
+			count++;
+	}
+
+	/* Find all the aliases and add those regions back in */
+	if (disp->add_aliases && count < max_regions) {
+		int new_count;
+
+		new_count = fdt_add_alias_regions(fdt, region, count,
+						  max_regions, &state);
+		if (new_count > max_regions) {
+			region = malloc(new_count * sizeof(struct fdt_region));
+			if (!region) {
+				fprintf(stderr,
+					"Out of memory for %d regions\n",
+					count);
+				return -1;
+			}
+			memcpy(region, state.region,
+			       count * sizeof(struct fdt_region));
+			free(state.region);
+			new_count = fdt_add_alias_regions(fdt, region, count,
+							  max_regions, &state);
+		}
+
+		/*
+		 * The alias regions will now be at the end of the list. Sort
+		 * the regions by offset to get things into the right order
+		 */
+		qsort(region, new_count, sizeof(struct fdt_region),
+		      h_cmp_region);
+		count = new_count;
+	}
+
+	if (ret != -FDT_ERR_NOTFOUND)
+		return ret;
+
+	return count;
+}
+
+int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
+{
+	int fd = 0;	/* assume stdin */
+	char *buf = NULL;
+	off_t bufsize = 1024, offset = 0;
+	int ret = 0;
+
+	*buffp = NULL;
+	if (strcmp(filename, "-") != 0) {
+		fd = open(filename, O_RDONLY);
+		if (fd < 0)
+			return errno;
+	}
+
+	/* Loop until we have read everything */
+	buf = malloc(bufsize);
+	if (!buf)
+		return -ENOMEM;
+	do {
+		/* Expand the buffer to hold the next chunk */
+		if (offset == bufsize) {
+			bufsize *= 2;
+			buf = realloc(buf, bufsize);
+			if (!buf)
+				return -ENOMEM;
+		}
+
+		ret = read(fd, &buf[offset], bufsize - offset);
+		if (ret < 0) {
+			ret = errno;
+			break;
+		}
+		offset += ret;
+	} while (ret != 0);
+
+	/* Clean up, including closing stdin; return errno on error */
+	close(fd);
+	if (ret)
+		free(buf);
+	else
+		*buffp = buf;
+	*len = bufsize;
+	return ret;
+}
+
+int utilfdt_read_err(const char *filename, char **buffp)
+{
+	off_t len;
+	return utilfdt_read_err_len(filename, buffp, &len);
+}
+
+char *utilfdt_read_len(const char *filename, off_t *len)
+{
+	char *buff;
+	int ret = utilfdt_read_err_len(filename, &buff, len);
+
+	if (ret) {
+		fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
+			strerror(ret));
+		return NULL;
+	}
+	/* Successful read */
+	return buff;
+}
+
+char *utilfdt_read(const char *filename)
+{
+	off_t len;
+	return utilfdt_read_len(filename, &len);
+}
+
+/**
+ * Run the main fdtgrep operation, given a filename and valid arguments
+ *
+ * @param disp		Display information / options
+ * @param filename	Filename of blob file
+ * @param return 0 if ok, -ve on error
+ */
+static int do_fdtgrep(struct display_info *disp, const char *filename)
+{
+	struct fdt_region *region;
+	int max_regions;
+	int count = 100;
+	char path[1024];
+	char *blob;
+	int i, ret;
+
+	blob = utilfdt_read(filename);
+	if (!blob)
+		return -1;
+	ret = fdt_check_header(blob);
+	if (ret) {
+		fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
+		return ret;
+	}
+
+	/* Allow old files, but they are untested */
+	if (fdt_version(blob) < 17 && disp->value_head) {
+		fprintf(stderr,
+			"Warning: fdtgrep does not fully support version %d files\n",
+			fdt_version(blob));
+	}
+
+	/*
+	 * We do two passes, since we don't know how many regions we need.
+	 * The first pass will count the regions, but if it is too many,
+	 * we do another pass to actually record them.
+	 */
+	for (i = 0; i < 2; i++) {
+		region = malloc(count * sizeof(struct fdt_region));
+		if (!region) {
+			fprintf(stderr, "Out of memory for %d regions\n",
+				count);
+			return -1;
+		}
+		max_regions = count;
+		count = fdtgrep_find_regions(blob,
+				h_include, disp,
+				region, max_regions, path, sizeof(path),
+				disp->flags);
+		if (count < 0) {
+			report_error("fdt_find_regions", count);
+			return -1;
+		}
+		if (count <= max_regions)
+			break;
+		free(region);
+	}
+
+	/* Optionally print a list of regions */
+	if (disp->region_list)
+		show_region_list(region, count);
+
+	/* Output either source .dts or binary .dtb */
+	if (disp->output == OUT_DTS) {
+		ret = display_fdt_by_regions(disp, blob, region, count);
+	} else {
+		void *fdt;
+		/* Allow reserved memory section to expand slightly */
+		int size = fdt_totalsize(blob) + 16;
+
+		fdt = malloc(size);
+		if (!fdt) {
+			fprintf(stderr, "Out_of_memory\n");
+			ret = -1;
+			goto err;
+		}
+		size = dump_fdt_regions(disp, blob, region, count, fdt);
+		if (disp->remove_strings) {
+			void *out;
+
+			out = malloc(size);
+			if (!out) {
+				fprintf(stderr, "Out_of_memory\n");
+				ret = -1;
+				goto err;
+			}
+			ret = fdt_remove_unused_strings(fdt, out);
+			if (ret < 0) {
+				fprintf(stderr,
+					"Failed to remove unused strings: err=%d\n",
+					ret);
+				goto err;
+			}
+			free(fdt);
+			fdt = out;
+			ret = fdt_pack(fdt);
+			if (ret < 0) {
+				fprintf(stderr, "Failed to pack: err=%d\n",
+					ret);
+				goto err;
+			}
+			size = fdt_totalsize(fdt);
+		}
+
+		if (size != fwrite(fdt, 1, size, disp->fout)) {
+			fprintf(stderr, "Write failure, %d bytes\n", size);
+			free(fdt);
+			ret = 1;
+			goto err;
+		}
+		free(fdt);
+	}
+err:
+	free(blob);
+	free(region);
+
+	return ret;
+}
+
+static const char usage_synopsis[] =
+	"fdtgrep - extract portions from device tree\n"
+	"\n"
+	"Usage:\n"
+	"	fdtgrep <options> <dt file>|-\n\n"
+	"Output formats are:\n"
+	"\tdts - device tree soure text\n"
+	"\tdtb - device tree blob (sets -Hmt automatically)\n"
+	"\tbin - device tree fragment (may not be a valid .dtb)";
+
+/* Helper for usage_short_opts string constant */
+#define USAGE_COMMON_SHORT_OPTS "hV"
+
+/* Helper for aligning long_opts array */
+#define a_argument required_argument
+
+/* Helper for usage_long_opts option array */
+#define USAGE_COMMON_LONG_OPTS \
+	{"help",      no_argument, NULL, 'h'}, \
+	{"version",   no_argument, NULL, 'V'}, \
+	{NULL,        no_argument, NULL, 0x0}
+
+/* Helper for usage_opts_help array */
+#define USAGE_COMMON_OPTS_HELP \
+	"Print this help and exit", \
+	"Print version and exit", \
+	NULL
+
+/* Helper for getopt case statements */
+#define case_USAGE_COMMON_FLAGS \
+	case 'h': usage(NULL); \
+	case 'V': util_version(); \
+	case '?': usage("unknown option");
+
+static const char usage_short_opts[] =
+		"haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
+		USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+	{"show-address",	no_argument, NULL, 'a'},
+	{"colour",		no_argument, NULL, 'A'},
+	{"include-node-with-prop", a_argument, NULL, 'b'},
+	{"include-compat",	a_argument, NULL, 'c'},
+	{"exclude-compat",	a_argument, NULL, 'C'},
+	{"diff",		no_argument, NULL, 'd'},
+	{"enter-node",		no_argument, NULL, 'e'},
+	{"show-offset",		no_argument, NULL, 'f'},
+	{"include-match",	a_argument, NULL, 'g'},
+	{"exclude-match",	a_argument, NULL, 'G'},
+	{"show-header",		no_argument, NULL, 'H'},
+	{"show-version",	no_argument, NULL, 'I'},
+	{"list-regions",	no_argument, NULL, 'l'},
+	{"list-strings",	no_argument, NULL, 'L'},
+	{"include-mem",		no_argument, NULL, 'm'},
+	{"include-node",	a_argument, NULL, 'n'},
+	{"exclude-node",	a_argument, NULL, 'N'},
+	{"include-prop",	a_argument, NULL, 'p'},
+	{"exclude-prop",	a_argument, NULL, 'P'},
+	{"remove-strings",	no_argument, NULL, 'r'},
+	{"include-root",	no_argument, NULL, 'R'},
+	{"show-subnodes",	no_argument, NULL, 's'},
+	{"skip-supernodes",	no_argument, NULL, 'S'},
+	{"show-stringtab",	no_argument, NULL, 't'},
+	{"show-aliases",	no_argument, NULL, 'T'},
+	{"out",			a_argument, NULL, 'o'},
+	{"out-format",		a_argument, NULL, 'O'},
+	{"invert-match",	no_argument, NULL, 'v'},
+	USAGE_COMMON_LONG_OPTS,
+};
+static const char * const usage_opts_help[] = {
+	"Display address",
+	"Show all nodes/tags, colour those that match",
+	"Include contains containing property",
+	"Compatible nodes to include in grep",
+	"Compatible nodes to exclude in grep",
+	"Diff: Mark matching nodes with +, others with -",
+	"Enter direct subnode names of matching nodes",
+	"Display offset",
+	"Node/property/compatible string to include in grep",
+	"Node/property/compatible string to exclude in grep",
+	"Output a header",
+	"Put \"/dts-v1/;\" on first line of dts output",
+	"Output a region list",
+	"List strings in string table",
+	"Include mem_rsvmap section in binary output",
+	"Node to include in grep",
+	"Node to exclude in grep",
+	"Property to include in grep",
+	"Property to exclude in grep",
+	"Remove unused strings from string table",
+	"Include root node and all properties",
+	"Show all subnodes matching nodes",
+	"Don't include supernodes of matching nodes",
+	"Include string table in binary output",
+	"Include matching aliases in output",
+	"-o <output file>",
+	"-O <output format>",
+	"Invert the sense of matching (select non-matching lines)",
+	USAGE_COMMON_OPTS_HELP
+};
+
+/**
+ * Call getopt_long() with standard options
+ *
+ * Since all util code runs getopt in the same way, provide a helper.
+ */
+#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
+				       usage_long_opts, NULL)
+
+void util_usage(const char *errmsg, const char *synopsis,
+		const char *short_opts, struct option const long_opts[],
+		const char * const opts_help[])
+{
+	FILE *fp = errmsg ? stderr : stdout;
+	const char a_arg[] = "<arg>";
+	size_t a_arg_len = strlen(a_arg) + 1;
+	size_t i;
+	int optlen;
+
+	fprintf(fp,
+		"Usage: %s\n"
+		"\n"
+		"Options: -[%s]\n", synopsis, short_opts);
+
+	/* prescan the --long opt length to auto-align */
+	optlen = 0;
+	for (i = 0; long_opts[i].name; ++i) {
+		/* +1 is for space between --opt and help text */
+		int l = strlen(long_opts[i].name) + 1;
+		if (long_opts[i].has_arg == a_argument)
+			l += a_arg_len;
+		if (optlen < l)
+			optlen = l;
+	}
+
+	for (i = 0; long_opts[i].name; ++i) {
+		/* helps when adding new applets or options */
+		assert(opts_help[i] != NULL);
+
+		/* first output the short flag if it has one */
+		if (long_opts[i].val > '~')
+			fprintf(fp, "      ");
+		else
+			fprintf(fp, "  -%c, ", long_opts[i].val);
+
+		/* then the long flag */
+		if (long_opts[i].has_arg == no_argument) {
+			fprintf(fp, "--%-*s", optlen, long_opts[i].name);
+		} else {
+			fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
+				(int)(optlen - strlen(long_opts[i].name) -
+				a_arg_len), "");
+		}
+
+		/* finally the help text */
+		fprintf(fp, "%s\n", opts_help[i]);
+	}
+
+	if (errmsg) {
+		fprintf(fp, "\nError: %s\n", errmsg);
+		exit(EXIT_FAILURE);
+	} else {
+		exit(EXIT_SUCCESS);
+	}
+}
+
+/**
+ * Show usage and exit
+ *
+ * If you name all your usage variables with usage_xxx, then you can call this
+ * help macro rather than expanding all arguments yourself.
+ *
+ * @param errmsg	If non-NULL, an error message to display
+ */
+#define usage(errmsg) \
+	util_usage(errmsg, usage_synopsis, usage_short_opts, \
+		   usage_long_opts, usage_opts_help)
+
+void util_version(void)
+{
+	printf("Version: %s\n", "(U-Boot)");
+	exit(0);
+}
+
+static void scan_args(struct display_info *disp, int argc, char *argv[])
+{
+	int opt;
+
+	while ((opt = util_getopt_long()) != EOF) {
+		int type = 0;
+		int inc = 1;
+
+		switch (opt) {
+		case_USAGE_COMMON_FLAGS
+		case 'a':
+			disp->show_addr = 1;
+			break;
+		case 'A':
+			disp->all = 1;
+			break;
+		case 'b':
+			type = FDT_NODE_HAS_PROP;
+			break;
+		case 'C':
+			inc = 0;
+			/* no break */
+		case 'c':
+			type = FDT_IS_COMPAT;
+			break;
+		case 'd':
+			disp->diff = 1;
+			break;
+		case 'e':
+			disp->flags |= FDT_REG_DIRECT_SUBNODES;
+			break;
+		case 'f':
+			disp->show_offset = 1;
+			break;
+		case 'G':
+			inc = 0;
+			/* no break */
+		case 'g':
+			type = FDT_ANY_GLOBAL;
+			break;
+		case 'H':
+			disp->header = 1;
+			break;
+		case 'l':
+			disp->region_list = 1;
+			break;
+		case 'L':
+			disp->list_strings = 1;
+			break;
+		case 'm':
+			disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
+			break;
+		case 'N':
+			inc = 0;
+			/* no break */
+		case 'n':
+			type = FDT_IS_NODE;
+			break;
+		case 'o':
+			disp->output_fname = optarg;
+			break;
+		case 'O':
+			if (!strcmp(optarg, "dtb"))
+				disp->output = OUT_DTB;
+			else if (!strcmp(optarg, "dts"))
+				disp->output = OUT_DTS;
+			else if (!strcmp(optarg, "bin"))
+				disp->output = OUT_BIN;
+			else
+				usage("Unknown output format");
+			break;
+		case 'P':
+			inc = 0;
+			/* no break */
+		case 'p':
+			type = FDT_IS_PROP;
+			break;
+		case 'r':
+			disp->remove_strings = 1;
+			break;
+		case 'R':
+			disp->include_root = 1;
+			break;
+		case 's':
+			disp->flags |= FDT_REG_ALL_SUBNODES;
+			break;
+		case 'S':
+			disp->flags &= ~FDT_REG_SUPERNODES;
+			break;
+		case 't':
+			disp->flags |= FDT_REG_ADD_STRING_TAB;
+			break;
+		case 'T':
+			disp->add_aliases = 1;
+			break;
+		case 'v':
+			disp->invert = 1;
+			break;
+		case 'I':
+			disp->show_dts_version = 1;
+			break;
+		}
+
+		if (type && value_add(disp, &disp->value_head, type, inc,
+				      optarg))
+			usage("Cannot add value");
+	}
+
+	if (disp->invert && disp->types_exc)
+		usage("-v has no meaning when used with 'exclude' conditions");
+}
+
+int main(int argc, char *argv[])
+{
+	char *filename = NULL;
+	struct display_info disp;
+	int ret;
+
+	/* set defaults */
+	memset(&disp, '\0', sizeof(disp));
+	disp.flags = FDT_REG_SUPERNODES;	/* Default flags */
+
+	scan_args(&disp, argc, argv);
+
+	/* Show matched lines in colour if we can */
+	disp.colour = disp.all && isatty(0);
+
+	/* Any additional arguments can match anything, just like -g */
+	while (optind < argc - 1) {
+		if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
+			      argv[optind++]))
+			usage("Cannot add value");
+	}
+
+	if (optind < argc)
+		filename = argv[optind++];
+	if (!filename)
+		usage("Missing filename");
+
+	/* If a valid .dtb is required, set flags to ensure we get one */
+	if (disp.output == OUT_DTB) {
+		disp.header = 1;
+		disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
+	}
+
+	if (disp.output_fname) {
+		disp.fout = fopen(disp.output_fname, "w");
+		if (!disp.fout)
+			usage("Cannot open output file");
+	} else {
+		disp.fout = stdout;
+	}
+
+	/* Run the grep and output the results */
+	ret = do_fdtgrep(&disp, filename);
+	if (disp.output_fname)
+		fclose(disp.fout);
+	if (ret)
+		return 1;
+
+	return 0;
+}
diff --git a/tools/imagetool.h b/tools/imagetool.h
index b7874f4..99bbf2f 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -59,6 +59,7 @@
 	const char *keydest;	/* Destination .dtb for public key */
 	const char *comment;	/* Comment to add to signature node */
 	int require_keys;	/* 1 to mark signing keys as 'required' */
+	int file_size;		/* Total size of output file */
 };
 
 /*
diff --git a/tools/mkimage.c b/tools/mkimage.c
index 5ccd951..e81d455 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -26,8 +26,48 @@
 	.imagename2 = "",
 };
 
-int
-main (int argc, char **argv)
+static int h_compare_image_name(const void *vtype1, const void *vtype2)
+{
+	const int *type1 = vtype1;
+	const int *type2 = vtype2;
+	const char *name1 = genimg_get_type_short_name(*type1);
+	const char *name2 = genimg_get_type_short_name(*type2);
+
+	return strcmp(name1, name2);
+}
+
+/* Show all image types supported by mkimage */
+static void show_image_types(void)
+{
+	struct image_type_params *tparams;
+	int order[IH_TYPE_COUNT];
+	int count;
+	int type;
+	int i;
+
+	/* Sort the names in order of short name for easier reading */
+	memset(order, '\0', sizeof(order));
+	for (count = 0, type = 0; type < IH_TYPE_COUNT; type++) {
+		tparams = imagetool_get_type(type);
+		if (tparams)
+			order[count++] = type;
+	}
+	qsort(order, count, sizeof(int), h_compare_image_name);
+
+	fprintf(stderr, "\nInvalid image type. Supported image types:\n");
+	for (i = 0; i < count; i++) {
+		type = order[i];
+		tparams = imagetool_get_type(type);
+		if (tparams) {
+			fprintf(stderr, "\t%-15s  %s\n",
+				genimg_get_type_short_name(type),
+				genimg_get_type_name(type));
+		}
+	}
+	fprintf(stderr, "\n");
+}
+
+int main(int argc, char **argv)
 {
 	int ifd = -1;
 	struct stat sbuf;
@@ -35,6 +75,7 @@
 	int retval = 0;
 	struct image_type_params *tparams = NULL;
 	int pad_len = 0;
+	int dfd;
 
 	params.cmdname = *argv;
 	params.addr = params.ep = 0;
@@ -75,12 +116,16 @@
 					usage ();
 				goto NXTARG;
 			case 'T':
-				if ((--argc <= 0) ||
-					(params.type =
-					genimg_get_type_id (*++argv)) < 0)
-					usage ();
+				params.type = -1;
+				if (--argc >= 0 && argv[1]) {
+					params.type =
+						genimg_get_type_id(*++argv);
+				}
+				if (params.type < 0) {
+					show_image_types();
+					usage();
+				}
 				goto NXTARG;
-
 			case 'a':
 				if (--argc <= 0)
 					usage ();
@@ -266,6 +311,22 @@
 		exit (retval);
 	}
 
+	dfd = open(params.datafile, O_RDONLY | O_BINARY);
+	if (dfd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			params.cmdname, params.datafile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			params.cmdname, params.datafile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	params.file_size = sbuf.st_size + tparams->header_size;
+	close(dfd);
+
 	/*
 	 * In case there an header with a variable
 	 * length will be added, the corresponding
@@ -365,6 +426,7 @@
 			params.cmdname, params.imagefile, strerror(errno));
 		exit (EXIT_FAILURE);
 	}
+	params.file_size = sbuf.st_size;
 
 	ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
 	if (ptr == MAP_FAILED) {
@@ -546,6 +608,7 @@
 #endif
 	fprintf (stderr, "       %s -V ==> print version information and exit\n",
 		params.cmdname);
+	fprintf(stderr, "Use -T to see a list of available image types\n");
 
 	exit (EXIT_FAILURE);
 }