diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index 168f2efa33e5fe4f5eaab52503dbb724fd2f5528..b6aae3718a19f81baaa4a7616ec1231d67c3e80e 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -45,11 +45,6 @@ void __udelay(unsigned long usec)
 	os_usleep(usec);
 }
 
-unsigned long __attribute__((no_instrument_function)) timer_get_us(void)
-{
-	return os_get_nsec() / 1000;
-}
-
 int cleanup_before_linux(void)
 {
 	return 0;
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 4d5f8057533e89f2ed6edd0298ac4c69038360eb..e6dd17e9efc7c62777bc6e4210c367abb2471435 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -24,6 +24,7 @@
 #include <asm/sections.h>
 #include <asm/state.h>
 #include <os.h>
+#include <rtc_def.h>
 
 /* Operating System Interface */
 
@@ -537,3 +538,20 @@ int os_jump_to_image(const void *dest, int size)
 
 	return unlink(fname);
 }
+
+void os_localtime(struct rtc_time *rt)
+{
+	time_t t = time(NULL);
+	struct tm *tm;
+
+	tm = localtime(&t);
+	rt->tm_sec = tm->tm_sec;
+	rt->tm_min = tm->tm_min;
+	rt->tm_hour = tm->tm_hour;
+	rt->tm_mday = tm->tm_mday;
+	rt->tm_mon = tm->tm_mon + 1;
+	rt->tm_year = tm->tm_year + 1900;
+	rt->tm_wday = tm->tm_wday;
+	rt->tm_yday = tm->tm_yday;
+	rt->tm_isdst = tm->tm_isdst;
+}
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c
index ec010402d77f47f40b2ca3950d4cb9a5e52355c4..b23d08b5a1bb33ace30f67029b3336f0c6ed8564 100644
--- a/arch/sandbox/cpu/start.c
+++ b/arch/sandbox/cpu/start.c
@@ -77,12 +77,18 @@ int sandbox_main_loop_init(void)
 	struct sandbox_state *state = state_get_current();
 
 	/* Execute command if required */
-	if (state->cmd) {
-		int retval;
+	if (state->cmd || state->run_distro_boot) {
+		int retval = 0;
 
 		cli_init();
 
-		retval = run_command_list(state->cmd, -1, 0);
+		if (state->cmd)
+			retval = run_command_list(state->cmd, -1, 0);
+
+		if (state->run_distro_boot)
+			retval = cli_simple_run_command("run distro_bootcmd",
+							0);
+
 		if (!state->interactive)
 			os_exit(retval);
 	}
@@ -90,6 +96,14 @@ int sandbox_main_loop_init(void)
 	return 0;
 }
 
+static int sandbox_cmdline_cb_boot(struct sandbox_state *state,
+				      const char *arg)
+{
+	state->run_distro_boot = true;
+	return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(boot, 'b', 0, "Run distro boot commands");
+
 static int sandbox_cmdline_cb_command(struct sandbox_state *state,
 				      const char *arg)
 {
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index efa2097b2d67c33f68d8f70c11754fb09af3ff72..82d186ee5b0660e5c82f8acd843f677c0256c589 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -8,7 +8,9 @@
 
 	aliases {
 		eth5 = "/eth@90000000";
+		i2c0 = &i2c_0;
 		pci0 = &pci;
+		rtc0 = &rtc_0;
 	};
 
 	chosen {
@@ -90,7 +92,7 @@
 		num-gpios = <10>;
 	};
 
-	i2c@0 {
+	i2c_0: i2c@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		reg = <0 0>;
@@ -105,6 +107,14 @@
 				sandbox,size = <128>;
 			};
 		};
+
+		rtc_0: rtc@43 {
+			reg = <0x43>;
+			compatible = "sandbox-rtc";
+			emul {
+				compatible = "sandbox,i2c-rtc";
+			};
+		};
 	};
 
 	spi@0 {
diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h
index 4b79ede9b99ca8f9dcff7018f54c49cb462fcd60..88804fb8e2647677d85f4da9c05c516c2e61da4e 100644
--- a/arch/sandbox/include/asm/eth.h
+++ b/arch/sandbox/include/asm/eth.h
@@ -12,4 +12,6 @@
 
 void sandbox_eth_disable_response(int index, bool disable);
 
+void sandbox_eth_skip_timeout(void);
+
 #endif /* __ETH_H */
diff --git a/arch/sandbox/include/asm/rtc.h b/arch/sandbox/include/asm/rtc.h
new file mode 100644
index 0000000000000000000000000000000000000000..5ed4584641c1ddde96d7b7c25d480d6fda5053a2
--- /dev/null
+++ b/arch/sandbox/include/asm/rtc.h
@@ -0,0 +1,28 @@
+/*
+ * Simulate an I2C real time clock
+ *
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __asm_rtc_h
+#define __asm_rtc_h
+
+/* Register numbers in the sandbox RTC */
+enum {
+	REG_SEC		= 5,
+	REG_MIN,
+	REG_HOUR,
+	REG_MDAY,
+	REG_MON,
+	REG_YEAR,
+	REG_WDAY,
+
+	REG_RESET	= 0x20,
+
+	REG_COUNT	= 0x80,
+};
+
+#endif
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index a0c24ba1e053fec66990626812332a60302b6276..a57480a996f33bf9b5b419e50235fdd44f4305f7 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -42,6 +42,7 @@ struct sandbox_spi_info {
 struct sandbox_state {
 	const char *cmd;		/* Command to execute */
 	bool interactive;		/* Enable cmdline after execute */
+	bool run_distro_boot;		/* Automatically run distro bootcommands */
 	const char *fdt_fname;		/* Filename of FDT binary */
 	const char *parse_err;		/* Error to report from parsing */
 	int argc;			/* Program arguments */
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 8e490e96d7ae6cf9fb6f055ad30437862f872fb1..91a5c79ad2fb14767e239c921594934f2e8810bd 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -17,6 +17,16 @@
 #define SANDBOX_PCI_CLASS_CODE		PCI_CLASS_CODE_COMM
 #define SANDBOX_PCI_CLASS_SUB_CODE	PCI_CLASS_SUB_CODE_COMM_SERIAL
 
+/**
+ * sandbox_i2c_set_test_mode() - set test mode for running unit tests
+ *
+ * See sandbox_i2c_xfer() for the behaviour changes.
+ *
+ * @bus:	sandbox I2C bus to adjust
+ * @test_mode:	true to select test mode, false to run normally
+ */
+void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode);
+
 enum sandbox_i2c_eeprom_test_mode {
 	SIE_TEST_MODE_NONE,
 	/* Permits read/write of only one byte per I2C transaction */
@@ -28,4 +38,33 @@ void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev,
 
 void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len);
 
+/*
+ * sandbox_timer_add_offset()
+ *
+ * Allow tests to add to the time reported through lib/time.c functions
+ * offset: number of milliseconds to advance the system time
+ */
+void sandbox_timer_add_offset(unsigned long offset);
+
+/**
+ * sandbox_i2c_rtc_set_offset() - set the time offset from system/base time
+ *
+ * @dev:		RTC device to adjust
+ * @use_system_time:	true to use system time, false to use @base_time
+ * @offset:		RTC offset from current system/base time (-1 for no
+ *			change)
+ * @return old value of RTC offset
+ */
+long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
+				int offset);
+
+/**
+ * sandbox_i2c_rtc_get_set_base_time() - get and set the base time
+ *
+ * @dev:		RTC device to adjust
+ * @base_time:		New base system time (set to -1 for no change)
+ * @return old base time
+ */
+long sandbox_i2c_rtc_get_set_base_time(struct udevice *dev, long base_time);
+
 #endif
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
index 2227f1c1214a97ae078fe18dac950dfe1a835b90..80eaa6334cb56cccbeadaee9e0a3bf68c9a07c40 100644
--- a/board/sandbox/sandbox.c
+++ b/board/sandbox/sandbox.c
@@ -7,6 +7,7 @@
 #include <cros_ec.h>
 #include <dm.h>
 #include <os.h>
+#include <asm/test.h>
 #include <asm/u-boot-sandbox.h>
 
 /*
@@ -25,9 +26,17 @@ void flush_cache(unsigned long start, unsigned long size)
 {
 }
 
+/* system timer offset in ms */
+static unsigned long sandbox_timer_offset;
+
+void sandbox_timer_add_offset(unsigned long offset)
+{
+	sandbox_timer_offset += offset;
+}
+
 unsigned long timer_read_counter(void)
 {
-	return os_get_nsec() / 1000;
+	return os_get_nsec() / 1000 + sandbox_timer_offset * 1000;
 }
 
 int dram_init(void)
diff --git a/common/cmd_date.c b/common/cmd_date.c
index 4a653e5bcfab8e24c35608aa256c8c8161b2b291..61727e3d1f257c53fce37bb2f5dd41cb9087c783 100644
--- a/common/cmd_date.c
+++ b/common/cmd_date.c
@@ -10,6 +10,7 @@
  */
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <rtc.h>
 #include <i2c.h>
 
@@ -33,10 +34,18 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	struct rtc_time tm;
 	int rcode = 0;
-	int old_bus;
+	int old_bus __maybe_unused;
 
 	/* switch to correct I2C bus */
-#ifdef CONFIG_SYS_I2C
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+
+	rcode = uclass_get_device(UCLASS_RTC, 0, &dev);
+	if (rcode) {
+		printf("Cannot find RTC: err=%d\n", rcode);
+		return CMD_RET_FAILURE;
+	}
+#elif defined(CONFIG_SYS_I2C)
 	old_bus = i2c_get_bus_num();
 	i2c_set_bus_num(CONFIG_SYS_RTC_BUS_NUM);
 #else
@@ -48,32 +57,50 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	case 2:			/* set date & time */
 		if (strcmp(argv[1],"reset") == 0) {
 			puts ("Reset RTC...\n");
-			rtc_reset ();
+#ifdef CONFIG_DM_I2C
+			rcode = dm_rtc_reset(dev);
+			if (!rcode)
+				rcode = dm_rtc_set(dev, &default_tm);
+#else
+			rtc_reset();
 			rcode = rtc_set(&default_tm);
+#endif
 			if (rcode)
 				puts("## Failed to set date after RTC reset\n");
 		} else {
 			/* initialize tm with current time */
-			rcode = rtc_get (&tm);
-
-			if(!rcode) {
+#ifdef CONFIG_DM_I2C
+			rcode = dm_rtc_get(dev, &tm);
+#else
+			rcode = rtc_get(&tm);
+#endif
+			if (!rcode) {
 				/* insert new date & time */
-				if (mk_date (argv[1], &tm) != 0) {
+				if (mk_date(argv[1], &tm) != 0) {
 					puts ("## Bad date format\n");
 					break;
 				}
 				/* and write to RTC */
-				rcode = rtc_set (&tm);
-				if(rcode)
-					puts("## Set date failed\n");
+#ifdef CONFIG_DM_I2C
+				rcode = dm_rtc_set(dev, &tm);
+#else
+				rcode = rtc_set(&tm);
+#endif
+				if (rcode) {
+					printf("## Set date failed: err=%d\n",
+					       rcode);
+				}
 			} else {
 				puts("## Get date failed\n");
 			}
 		}
 		/* FALL TROUGH */
 	case 1:			/* get date & time */
-		rcode = rtc_get (&tm);
-
+#ifdef CONFIG_DM_I2C
+		rcode = dm_rtc_get(dev, &tm);
+#else
+		rcode = rtc_get(&tm);
+#endif
 		if (rcode) {
 			puts("## Get date failed\n");
 			break;
@@ -93,11 +120,11 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	/* switch back to original I2C bus */
 #ifdef CONFIG_SYS_I2C
 	i2c_set_bus_num(old_bus);
-#else
+#elif !defined(CONFIG_DM_I2C)
 	I2C_SET_BUS(old_bus);
 #endif
 
-	return rcode;
+	return rcode ? CMD_RET_FAILURE : 0;
 }
 
 /*
@@ -201,7 +228,7 @@ int mk_date (const char *datestr, struct rtc_time *tmp)
 		tmp->tm_min  = val;
 
 		/* calculate day of week */
-		GregorianDay (tmp);
+		rtc_calc_weekday(tmp);
 
 		return (0);
 	default:
diff --git a/common/fdt_support.c b/common/fdt_support.c
index c5ed5ad89eec13d0f6b1b04cbaf3a2631f25a060..9e501484625d8583cd1d122e8e6c83f9c6948ac5 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -1533,7 +1533,7 @@ int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
 	if (ret < 0)
 		return ret;
 
-	snprintf(name, sizeof(name), "framebuffer@%llx", base_address);
+	snprintf(name, sizeof(name), "framebuffer@%" PRIx64, base_address);
 	ret = fdt_set_name(fdt, node, name);
 	if (ret < 0)
 		return ret;
diff --git a/common/image.c b/common/image.c
index abc0d890f289d622503f7e028ade7a48dc55478c..fdec496c4bf0e936f26e8876f621d9103c19595c 100644
--- a/common/image.c
+++ b/common/image.c
@@ -533,7 +533,7 @@ void genimg_print_time(time_t timestamp)
 #ifndef USE_HOSTCC
 	struct rtc_time tm;
 
-	to_tm(timestamp, &tm);
+	rtc_to_tm(timestamp, &tm);
 	printf("%4d-%02d-%02d  %2d:%02d:%02d UTC\n",
 			tm.tm_year, tm.tm_mon, tm.tm_mday,
 			tm.tm_hour, tm.tm_min, tm.tm_sec);
diff --git a/common/usb.c b/common/usb.c
index a4820d3e949a17c15c7deda9a3b0209abd0b3b74..1b26bfab367d2675a2dcc79bc62e81cc66762714 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -946,13 +946,18 @@ static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
 	 * send 64-byte GET-DEVICE-DESCRIPTOR request.  Since the descriptor is
 	 * only 18 bytes long, this will terminate with a short packet.  But if
 	 * the maxpacket size is 8 or 16 the device may be waiting to transmit
-	 * some more, or keeps on retransmitting the 8 byte header. */
+	 * some more, or keeps on retransmitting the 8 byte header.
+	 */
 
-	dev->descriptor.bMaxPacketSize0 = 64;	    /* Start off at 64 bytes  */
-	/* Default to 64 byte max packet size */
-	dev->maxpacketsize = PACKET_SIZE_64;
-	dev->epmaxpacketin[0] = 64;
-	dev->epmaxpacketout[0] = 64;
+	if (dev->speed == USB_SPEED_LOW) {
+		dev->descriptor.bMaxPacketSize0 = 8;
+		dev->maxpacketsize = PACKET_SIZE_8;
+	} else {
+		dev->descriptor.bMaxPacketSize0 = 64;
+		dev->maxpacketsize = PACKET_SIZE_64;
+	}
+	dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
+	dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
 
 	if (do_read) {
 		int err;
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 5de7fbedb4e0cc2a390e82a057aebcaa3b39af42..70ae5313b66c778089880568b88e94b911e27f51 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -26,3 +26,5 @@ CONFIG_TPM_TIS_SANDBOX=y
 CONFIG_SOUND=y
 CONFIG_CMD_SOUND=y
 CONFIG_SOUND_SANDBOX=y
+CONFIG_DM_RTC=y
+CONFIG_CMD_UT_TIME=y
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
index ed899d47770ca5f00ff2cecebb1fe8b0f8071a20..a8b83c51bc398a61f89377b3305cc9474a14c9e2 100644
--- a/drivers/i2c/i2c-gpio.c
+++ b/drivers/i2c/i2c-gpio.c
@@ -41,18 +41,19 @@ static int i2c_gpio_sda_get(struct gpio_desc *sda)
 
 static void i2c_gpio_sda_set(struct gpio_desc *sda, int bit)
 {
-	if (bit) {
+	if (bit)
 		dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
-	} else {
+	else
 		dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
-		dm_gpio_set_value(sda, 0);
-	}
 }
 
 static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit)
 {
-	dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
-	dm_gpio_set_value(scl, bit);
+	ulong flags = GPIOD_IS_OUT;
+
+	if (bit)
+		flags |= GPIOD_IS_OUT_ACTIVE;
+	dm_gpio_set_dir_flags(scl, flags);
 }
 
 static void i2c_gpio_write_bit(struct gpio_desc *scl, struct gpio_desc *sda,
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index f2e95c0881a76d82436df7f3114e67a2d5632457..b8eb2d613f2fb33a896d35668e4605b0bd15c4b9 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -186,6 +186,25 @@ int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
 	}
 }
 
+int dm_i2c_reg_read(struct udevice *dev, uint offset)
+{
+	uint8_t val;
+	int ret;
+
+	ret = dm_i2c_read(dev, offset, &val, 1);
+	if (ret < 0)
+		return ret;
+
+	return val;
+}
+
+int dm_i2c_reg_write(struct udevice *dev, uint offset, uint value)
+{
+	uint8_t val = value;
+
+	return dm_i2c_write(dev, offset, &val, 1);
+}
+
 /**
  * i2c_probe_chip() - probe for a chip on a bus
  *
diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
index d6adc0f721b85cb6b352d1993641da444aa62919..dd1c7e59e4b886fcb638d7e270cdfc78dcf34f23 100644
--- a/drivers/i2c/sandbox_i2c.c
+++ b/drivers/i2c/sandbox_i2c.c
@@ -18,8 +18,8 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-struct dm_sandbox_i2c_emul_priv {
-	struct udevice *emul;
+struct sandbox_i2c_priv {
+	bool test_mode;
 };
 
 static int get_emul(struct udevice *dev, struct udevice **devp,
@@ -47,17 +47,25 @@ static int get_emul(struct udevice *dev, struct udevice **devp,
 	return 0;
 }
 
+void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode)
+{
+	struct sandbox_i2c_priv *priv = dev_get_priv(bus);
+
+	priv->test_mode = test_mode;
+}
+
 static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
 			    int nmsgs)
 {
 	struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
+	struct sandbox_i2c_priv *priv = dev_get_priv(bus);
 	struct dm_i2c_ops *ops;
 	struct udevice *emul, *dev;
 	bool is_read;
 	int ret;
 
 	/* Special test code to return success but with no emulation */
-	if (msg->addr == SANDBOX_I2C_TEST_ADDR)
+	if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR)
 		return 0;
 
 	ret = i2c_get_chip(bus, msg->addr, 1, &dev);
@@ -68,13 +76,18 @@ static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
 	if (ret)
 		return ret;
 
-	/*
-	 * For testing, don't allow writing above 100KHz for writes and
-	 * 400KHz for reads
-	 */
-	is_read = nmsgs > 1;
-	if (i2c->speed_hz > (is_read ? 400000 : 100000))
-		return -EINVAL;
+	if (priv->test_mode) {
+		/*
+		* For testing, don't allow writing above 100KHz for writes and
+		* 400KHz for reads.
+		*/
+		is_read = nmsgs > 1;
+		if (i2c->speed_hz > (is_read ? 400000 : 100000)) {
+			debug("%s: Max speed exceeded\n", __func__);
+			return -EINVAL;
+		}
+	}
+
 	return ops->xfer(emul, msg, nmsgs);
 }
 
@@ -92,4 +105,5 @@ U_BOOT_DRIVER(i2c_sandbox) = {
 	.id	= UCLASS_I2C,
 	.of_match = sandbox_i2c_ids,
 	.ops	= &sandbox_i2c_ops,
+	.priv_auto_alloc_size = sizeof(struct sandbox_i2c_priv),
 };
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 982bac788d52b1b52948a525018a585bcb225d8c..4b6ac6a6c01f75d97db362c0a169654c7377dd35 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -986,7 +986,8 @@ int cros_ec_register(struct udevice *dev)
 	}
 
 	/* Remember this device for use by the cros_ec command */
-	debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
+	debug("Google Chrome EC v%d CROS-EC driver ready, id '%s'\n",
+	      cdev->protocol_version, id);
 
 	return 0;
 }
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
index ac2ee86edae62c8dc8a30bbd7a97c7f826cf2eda..0686925aaf1392d74ddd5d529f77d1ef24e0f8e5 100644
--- a/drivers/misc/cros_ec_spi.c
+++ b/drivers/misc/cros_ec_spi.c
@@ -25,6 +25,8 @@ int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
 {
 	struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
 	struct spi_slave *slave = dev_get_parentdata(dev->dev);
+	ulong start;
+	uint8_t byte;
 	int rv;
 
 	/* Do the transfer */
@@ -33,10 +35,25 @@ int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
 		return -1;
 	}
 
-	rv = spi_xfer(slave, max(out_bytes, in_bytes) * 8,
-		      dev->dout, dev->din,
-		      SPI_XFER_BEGIN | SPI_XFER_END);
+	rv = spi_xfer(slave, out_bytes * 8, dev->dout, NULL, SPI_XFER_BEGIN);
+	if (rv)
+		goto done;
+	start = get_timer(0);
+	while (1) {
+		rv = spi_xfer(slave, 8, NULL, &byte, 0);
+		if (byte == SPI_PREAMBLE_END_BYTE)
+			break;
+		if (rv)
+			goto done;
+		if (get_timer(start) > 100) {
+			rv = -ETIMEDOUT;
+			goto done;
+		}
+	}
 
+	rv = spi_xfer(slave, in_bytes * 8, NULL, dev->din, 0);
+done:
+	spi_xfer(slave, 0, NULL, NULL, SPI_XFER_END);
 	spi_release_bus(slave);
 
 	if (rv) {
diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
index 4b25902b8dcd42d579a7925a9ec26347e90bdfc4..350e21aa7d65fd81d21378136b2b197a1eefc0a4 100644
--- a/drivers/mtd/spi/sf-uclass.c
+++ b/drivers/mtd/spi/sf-uclass.c
@@ -53,10 +53,10 @@ int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
 {
 	struct spi_slave *slave;
 	struct udevice *bus;
-	char name[20], *str;
+	char name[30], *str;
 	int ret;
 
-	snprintf(name, sizeof(name), "%d:%d", busnum, cs);
+	snprintf(name, sizeof(name), "spi_flash@%d:%d", busnum, cs);
 	str = strdup(name);
 	ret = spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode,
 				  "spi_flash_std", str, &bus, &slave);
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c
index e239ff44479d07cbd04d3906c46646bae2f3c9c1..4e083d32ae6fe7aad839b84c5875ed98bbc4d627 100644
--- a/drivers/net/sandbox.c
+++ b/drivers/net/sandbox.c
@@ -11,6 +11,7 @@
 #include <dm.h>
 #include <malloc.h>
 #include <net.h>
+#include <asm/test.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -30,6 +31,7 @@ struct eth_sandbox_priv {
 };
 
 static bool disabled[8] = {false};
+static bool skip_timeout;
 
 /*
  * sandbox_eth_disable_response()
@@ -42,6 +44,16 @@ void sandbox_eth_disable_response(int index, bool disable)
 	disabled[index] = disable;
 }
 
+/*
+ * sandbox_eth_skip_timeout()
+ *
+ * When the first packet read is attempted, fast-forward time
+ */
+void sandbox_eth_skip_timeout(void)
+{
+	skip_timeout = true;
+}
+
 static int sb_eth_start(struct udevice *dev)
 {
 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
@@ -144,6 +156,11 @@ static int sb_eth_recv(struct udevice *dev, uchar **packetp)
 {
 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
 
+	if (skip_timeout) {
+		sandbox_timer_add_offset(10000UL);
+		skip_timeout = false;
+	}
+
 	if (priv->recv_packet_length) {
 		int lcl_recv_packet_length = priv->recv_packet_length;
 
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bd63621e37162b085bbf2f15c12f33b55b988022 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -0,0 +1,8 @@
+config DM_RTC
+	bool "Enable Driver Model for RTC drivers"
+	depends on DM
+	help
+	  Enable drver model for real-time-clock drivers. The RTC uclass
+	  then provides the rtc_get()/rtc_set() interface, delegating to
+	  drivers to perform the actual functions. See rtc.h for a
+	  description of the API.
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index fdcbc002953f4ea8f2a531b8dea3b63ed29c524e..3092de1d9c6a542485ac94fc45ddd955212c7ad7 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -7,6 +7,8 @@
 
 #ccflags-y += -DDEBUG
 
+obj-$(CONFIG_DM_RTC) += rtc-uclass.o
+
 obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
 obj-$(CONFIG_RTC_BFIN) += bfin_rtc.o
 obj-y += date.o
@@ -24,6 +26,7 @@ obj-$(CONFIG_RTC_DS164x) += ds164x.o
 obj-$(CONFIG_RTC_DS174x) += ds174x.o
 obj-$(CONFIG_RTC_DS3231) += ds3231.o
 obj-$(CONFIG_RTC_FTRTC010) += ftrtc010.o
+obj-$(CONFIG_SANDBOX) += i2c_rtc_emul.o
 obj-$(CONFIG_RTC_IMXDI) += imxdi.o
 obj-$(CONFIG_RTC_ISL1208) += isl1208.o
 obj-$(CONFIG_RTC_M41T11) += m41t11.o
@@ -49,4 +52,5 @@ obj-$(CONFIG_RTC_RTC4543) += rtc4543.o
 obj-$(CONFIG_RTC_RV3029) += rv3029.o
 obj-$(CONFIG_RTC_RX8025) += rx8025.o
 obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
+obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
 obj-$(CONFIG_RTC_X1205) += x1205.o
diff --git a/drivers/rtc/at91sam9_rtt.c b/drivers/rtc/at91sam9_rtt.c
index 714dd2a34f53268687db5b534febe16d3356e6e8..a684ad6a6f774da84af6cbf9df62775c593ba714 100644
--- a/drivers/rtc/at91sam9_rtt.c
+++ b/drivers/rtc/at91sam9_rtt.c
@@ -44,7 +44,7 @@ int rtc_get (struct rtc_time *tmp)
 	} while (tim!=tim2);
 	off = readl(&gpbr->reg[AT91_GPBR_INDEX_TIMEOFF]);
 	/* off==0 means time is invalid, but we ignore that */
-	to_tm (tim+off, tmp);
+	rtc_to_tm(tim+off, tmp);
 	return 0;
 }
 
@@ -54,8 +54,7 @@ int rtc_set (struct rtc_time *tmp)
 	at91_gpbr_t *gpbr = (at91_gpbr_t *) ATMEL_BASE_GPBR;
 	ulong tim;
 
-	tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
-		      tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+	tim = rtc_mktime(tmp);
 
 	/* clear alarm, set prescaler to 32768, clear counter */
 	writel(32768+AT91_RTT_RTTRST, &rtt->mr);
diff --git a/drivers/rtc/bfin_rtc.c b/drivers/rtc/bfin_rtc.c
index 4cf2d834b219683c1839a4d51a79f5b71641657b..a079a1d472365c95e72e5d00f2d216d0aeb6c9f1 100644
--- a/drivers/rtc/bfin_rtc.c
+++ b/drivers/rtc/bfin_rtc.c
@@ -67,8 +67,7 @@ int rtc_set(struct rtc_time *tmp)
 	wait_for_complete();
 
 	/* Calculate number of seconds this incoming time represents */
-	remain = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
-			tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+	remain = rtc_mktime(tmp);
 
 	/* Figure out how many days since epoch */
 	days = remain / NUM_SECS_IN_DAY;
@@ -114,7 +113,7 @@ int rtc_get(struct rtc_time *tmp)
 
 	/* Calculate the total number of seconds since epoch */
 	time_in_sec = (tm_sec) + MIN_TO_SECS(tm_min) + HRS_TO_SECS(tm_hr) + DAYS_TO_SECS(tm_day);
-	to_tm(time_in_sec, tmp);
+	rtc_to_tm(time_in_sec, tmp);
 
 	return 0;
 }
diff --git a/drivers/rtc/date.c b/drivers/rtc/date.c
index 15e6db06b2d4fd03c617de8a82ba3a6346b7052d..8c643a0b460c81afe4aeb9113bb020d16033aa68 100644
--- a/drivers/rtc/date.c
+++ b/drivers/rtc/date.c
@@ -11,6 +11,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <errno.h>
 #include <rtc.h>
 
 #if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
@@ -30,13 +31,15 @@ static int month_days[12] = {
 /*
  * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
  */
-void GregorianDay(struct rtc_time * tm)
+int rtc_calc_weekday(struct rtc_time *tm)
 {
 	int leapsToDate;
 	int lastYear;
 	int day;
 	int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
 
+	if (tm->tm_year < 1753)
+		return -EINVAL;
 	lastYear=tm->tm_year-1;
 
 	/*
@@ -64,9 +67,11 @@ void GregorianDay(struct rtc_time * tm)
 	day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday;
 
 	tm->tm_wday=day%7;
+
+	return 0;
 }
 
-void to_tm(int tim, struct rtc_time * tm)
+int rtc_to_tm(int tim, struct rtc_time *tm)
 {
 	register int    i;
 	register long   hms, day;
@@ -98,10 +103,14 @@ void to_tm(int tim, struct rtc_time * tm)
 	/* Days are what is left over (+1) from all that. */
 	tm->tm_mday = day + 1;
 
+	/* Zero unused fields */
+	tm->tm_yday = 0;
+	tm->tm_isdst = 0;
+
 	/*
 	 * Determine the day of week
 	 */
-	GregorianDay(tm);
+	return rtc_calc_weekday(tm);
 }
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -119,22 +128,23 @@ void to_tm(int tim, struct rtc_time * tm)
  * machines were long is 32-bit! (However, as time_t is signed, we
  * will already get problems at other places on 2038-01-19 03:14:08)
  */
-unsigned long
-mktime (unsigned int year, unsigned int mon,
-	unsigned int day, unsigned int hour,
-	unsigned int min, unsigned int sec)
+unsigned long rtc_mktime(const struct rtc_time *tm)
 {
-	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+	int mon = tm->tm_mon;
+	int year = tm->tm_year;
+	int days, hours;
+
+	mon -= 2;
+	if (0 >= (int)mon) {	/* 1..12 -> 11,12,1..10 */
 		mon += 12;		/* Puts Feb last since it has leap day */
 		year -= 1;
 	}
 
-	return (((
-		(unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
-			year*365 - 719499
-	    )*24 + hour /* now have hours */
-	  )*60 + min /* now have minutes */
-	)*60 + sec; /* finally seconds */
+	days = (unsigned long)(year / 4 - year / 100 + year / 400 +
+			367 * mon / 12 + tm->tm_mday) +
+			year * 365 - 719499;
+	hours = days * 24 + tm->tm_hour;
+	return (hours * 60 + tm->tm_min) * 60 + tm->tm_sec;
 }
 
 #endif
diff --git a/drivers/rtc/ds1306.c b/drivers/rtc/ds1306.c
index 1ec1837cb4e1e79405d6ba7357d8fc0b51f307f0..7dd3e19028e217b7a5664276c5cd9e8251f983ef 100644
--- a/drivers/rtc/ds1306.c
+++ b/drivers/rtc/ds1306.c
@@ -110,7 +110,7 @@ int rtc_get (struct rtc_time *tmp)
 	immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;	/* Disable DS1306 Chip */
 	udelay (10);
 
-	GregorianDay (tmp);	/* Determine the day of week */
+	rtc_calc_weekday(tmp);	/* Determine the day of week */
 
 	debug ("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
 	       tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -180,8 +180,7 @@ int rtc_set (struct rtc_time *tmp)
 	{
 		ulong tim;
 
-		tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
-			      tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+		tim = rtc_mktime(tmp);
 
 		immap->im_sitk.sitk_rtck = KAPWR_KEY;
 		immap->im_sit.sit_rtc = tim;
diff --git a/drivers/rtc/ds1374.c b/drivers/rtc/ds1374.c
index 427b1eb8d0a5f82541e99578d00e7a48c7a009c6..78473570b9df6c9292466705709a45581e97a801 100644
--- a/drivers/rtc/ds1374.c
+++ b/drivers/rtc/ds1374.c
@@ -118,7 +118,7 @@ int rtc_get (struct rtc_time *tm){
 
 	DEBUGR ("Get RTC s since 1.1.1970: %ld\n", time1);
 
-	to_tm(time1, tm); /* To Gregorian Date */
+	rtc_to_tm(time1, tm); /* To Gregorian Date */
 
 	if (rtc_read(RTC_SR_ADDR) & RTC_SR_BIT_OSF) {
 		printf ("### Warning: RTC oscillator has stopped\n");
@@ -147,9 +147,7 @@ int rtc_set (struct rtc_time *tmp){
 	if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
 		printf("WARNING: year should be between 1970 and 2069!\n");
 
-	time = mktime(tmp->tm_year, tmp->tm_mon,
-			tmp->tm_mday, tmp->tm_hour,
-			tmp->tm_min, tmp->tm_sec);
+	time = rtc_mktime(tmp);
 
 	DEBUGR ("Set RTC s since 1.1.1970: %ld (0x%02lx)\n", time, time);
 
diff --git a/drivers/rtc/ftrtc010.c b/drivers/rtc/ftrtc010.c
index 713dad274f1cb5e938e613d72b5118864b2a66f3..7d0cfb3ba8c7320f6102ec533a5dde4e2aded88e 100644
--- a/drivers/rtc/ftrtc010.c
+++ b/drivers/rtc/ftrtc010.c
@@ -86,7 +86,7 @@ int rtc_get(struct rtc_time *tmp)
 	now = ftrtc010_time() + readl(&rtc->record);
 #endif
 
-	to_tm(now, tmp);
+	rtc_to_tm(now, tmp);
 
 	return 0;
 }
@@ -104,8 +104,7 @@ int rtc_set(struct rtc_time *tmp)
 	      tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
 	      tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 
-	new = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_hour,
-		     tmp->tm_min, tmp->tm_sec);
+	new = rtc_mktime(tmp);
 
 	now = ftrtc010_time();
 
diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c
new file mode 100644
index 0000000000000000000000000000000000000000..20827fdff135b8a6e60bc570b8a50f531a69364e
--- /dev/null
+++ b/drivers/rtc/i2c_rtc_emul.c
@@ -0,0 +1,236 @@
+/*
+ * Simulate an I2C real time clock
+ *
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * This is a test driver. It starts off with the current time of the machine,
+ * but also supports setting the time, using an offset from the current
+ * clock. This driver is only intended for testing, not accurate
+ * time-keeping. It does not change the system time.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <os.h>
+#include <rtc.h>
+#include <asm/rtc.h>
+#include <asm/test.h>
+
+#ifdef DEBUG
+#define debug_buffer print_buffer
+#else
+#define debug_buffer(x, ...)
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct sandbox_i2c_rtc_plat_data - platform data for the RTC
+ *
+ * @base_time:		Base system time when RTC device was bound
+ * @offset:		RTC offset from current system time
+ * @use_system_time:	true to use system time, false to use @base_time
+ * @reg:		Register values
+ */
+struct sandbox_i2c_rtc_plat_data {
+	long base_time;
+	long offset;
+	bool use_system_time;
+	u8 reg[REG_COUNT];
+};
+
+struct sandbox_i2c_rtc {
+	unsigned int offset_secs;
+};
+
+long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
+				int offset)
+{
+	struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+	long old_offset;
+
+	old_offset = plat->offset;
+	plat->use_system_time = use_system_time;
+	if (offset != -1)
+		plat->offset = offset;
+
+	return old_offset;
+}
+
+long sandbox_i2c_rtc_get_set_base_time(struct udevice *dev, long base_time)
+{
+	struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+	long old_base_time;
+
+	old_base_time = plat->base_time;
+	if (base_time != -1)
+		plat->base_time = base_time;
+
+	return old_base_time;
+}
+
+static void reset_time(struct udevice *dev)
+{
+	struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+	struct rtc_time now;
+
+	os_localtime(&now);
+	plat->base_time = rtc_mktime(&now);
+	plat->offset = 0;
+	plat->use_system_time = true;
+}
+
+static int sandbox_i2c_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+	struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+	struct rtc_time tm_now;
+	long now;
+
+	if (plat->use_system_time) {
+		os_localtime(&tm_now);
+		now = rtc_mktime(&tm_now);
+	} else {
+		now = plat->base_time;
+	}
+
+	return rtc_to_tm(now + plat->offset, time);
+}
+
+static int sandbox_i2c_rtc_set(struct udevice *dev, const struct rtc_time *time)
+{
+	struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+	struct rtc_time tm_now;
+	long now;
+
+	if (plat->use_system_time) {
+		os_localtime(&tm_now);
+		now = rtc_mktime(&tm_now);
+	} else {
+		now = plat->base_time;
+	}
+	plat->offset = rtc_mktime(time) - now;
+
+	return 0;
+}
+
+/* Update the current time in the registers */
+static int sandbox_i2c_rtc_prepare_read(struct udevice *emul)
+{
+	struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
+	struct rtc_time time;
+	int ret;
+
+	ret = sandbox_i2c_rtc_get(emul, &time);
+	if (ret)
+		return ret;
+
+	plat->reg[REG_SEC] = time.tm_sec;
+	plat->reg[REG_MIN] = time.tm_min;
+	plat->reg[REG_HOUR] = time.tm_hour;
+	plat->reg[REG_MDAY] = time.tm_mday;
+	plat->reg[REG_MON] = time.tm_mon;
+	plat->reg[REG_YEAR] = time.tm_year - 1900;
+	plat->reg[REG_WDAY] = time.tm_wday;
+
+	return 0;
+}
+
+static int sandbox_i2c_rtc_complete_write(struct udevice *emul)
+{
+	struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
+	struct rtc_time time;
+	int ret;
+
+	time.tm_sec = plat->reg[REG_SEC];
+	time.tm_min = plat->reg[REG_MIN];
+	time.tm_hour = plat->reg[REG_HOUR];
+	time.tm_mday = plat->reg[REG_MDAY];
+	time.tm_mon = plat->reg[REG_MON];
+	time.tm_year = plat->reg[REG_YEAR] + 1900;
+	time.tm_wday = plat->reg[REG_WDAY];
+
+	ret = sandbox_i2c_rtc_set(emul, &time);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int sandbox_i2c_rtc_xfer(struct udevice *emul, struct i2c_msg *msg,
+				int nmsgs)
+{
+	struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
+	uint offset = 0;
+	int ret;
+
+	debug("\n%s\n", __func__);
+	ret = sandbox_i2c_rtc_prepare_read(emul);
+	if (ret)
+		return ret;
+	for (; nmsgs > 0; nmsgs--, msg++) {
+		int len;
+		u8 *ptr;
+
+		len = msg->len;
+		debug("   %s: msg->len=%d",
+		      msg->flags & I2C_M_RD ? "read" : "write",
+		      msg->len);
+		if (msg->flags & I2C_M_RD) {
+			debug(", offset %x, len %x: ", offset, len);
+
+			/* Read the register */
+			memcpy(msg->buf, plat->reg + offset, len);
+			memset(msg->buf + len, '\xff', msg->len - len);
+			debug_buffer(0, msg->buf, 1, msg->len, 0);
+		} else if (len >= 1) {
+			ptr = msg->buf;
+			offset = *ptr++ & (REG_COUNT - 1);
+			len--;
+			debug(", set offset %x: ", offset);
+			debug_buffer(0, msg->buf, 1, msg->len, 0);
+
+			/* Write the register */
+			memcpy(plat->reg + offset, ptr, len);
+			if (offset == REG_RESET)
+				reset_time(emul);
+		}
+	}
+	ret = sandbox_i2c_rtc_complete_write(emul);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct dm_i2c_ops sandbox_i2c_rtc_emul_ops = {
+	.xfer = sandbox_i2c_rtc_xfer,
+};
+
+static int sandbox_i2c_rtc_bind(struct udevice *dev)
+{
+	reset_time(dev);
+
+	return 0;
+}
+
+static const struct udevice_id sandbox_i2c_rtc_ids[] = {
+	{ .compatible = "sandbox,i2c-rtc" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_i2c_rtc_emul) = {
+	.name		= "sandbox_i2c_rtc_emul",
+	.id		= UCLASS_I2C_EMUL,
+	.of_match	= sandbox_i2c_rtc_ids,
+	.bind		= sandbox_i2c_rtc_bind,
+	.priv_auto_alloc_size = sizeof(struct sandbox_i2c_rtc),
+	.platdata_auto_alloc_size = sizeof(struct sandbox_i2c_rtc_plat_data),
+	.ops		= &sandbox_i2c_rtc_emul_ops,
+};
diff --git a/drivers/rtc/imxdi.c b/drivers/rtc/imxdi.c
index 0d7d736eff510970183b7af84f2aacb54098bcb7..17519ce2c057d7ee66077ba637124ff8c228d460 100644
--- a/drivers/rtc/imxdi.c
+++ b/drivers/rtc/imxdi.c
@@ -192,7 +192,7 @@ int rtc_get(struct rtc_time *tmp)
 	}
 
 	now = __raw_readl(&data.regs->dtcmr);
-	to_tm(now, tmp);
+	rtc_to_tm(now, tmp);
 
 err:
 	return rc;
@@ -209,8 +209,7 @@ int rtc_set(struct rtc_time *tmp)
 			goto err;
 	}
 
-	now = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
-		     tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+	now = rtc_mktime(tmp);
 	/* zero the fractional part first */
 	rc = DI_WRITE_WAIT(0, dtclr);
 	if (rc == 0)
diff --git a/drivers/rtc/mc13xxx-rtc.c b/drivers/rtc/mc13xxx-rtc.c
index 528247ac86e09399dc1ad7f9ddf10cded566edd9..3e463368b09c864c7c05e8ef30d983cc8645193a 100644
--- a/drivers/rtc/mc13xxx-rtc.c
+++ b/drivers/rtc/mc13xxx-rtc.c
@@ -36,7 +36,7 @@ int rtc_get(struct rtc_time *rtc)
 
 	tim = day1 * 86400 + time;
 
-	to_tm(tim, rtc);
+	rtc_to_tm(tim, rtc);
 
 	rtc->tm_yday = 0;
 	rtc->tm_isdst = 0;
@@ -51,8 +51,7 @@ int rtc_set(struct rtc_time *rtc)
 	if (!p)
 		return -1;
 
-	time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday,
-		      rtc->tm_hour, rtc->tm_min, rtc->tm_sec);
+	time = rtc_mktime(rtc);
 	day = time / 86400;
 	time %= 86400;
 
diff --git a/drivers/rtc/mcfrtc.c b/drivers/rtc/mcfrtc.c
index 8961ca4f8b6708fcf6989bf2561f1f10a11bbf83..e02e29793e03a85b2734a7b359aaa32a6c2a8b3d 100644
--- a/drivers/rtc/mcfrtc.c
+++ b/drivers/rtc/mcfrtc.c
@@ -38,7 +38,7 @@ int rtc_get(struct rtc_time *tmp)
 	tim = (tim * 60) + rtc_mins;
 	tim = (tim * 60) + rtc->seconds;
 
-	to_tm(tim, tmp);
+	rtc_to_tm(tim, tmp);
 
 	tmp->tm_yday = 0;
 	tmp->tm_isdst = 0;
diff --git a/drivers/rtc/mpc8xx.c b/drivers/rtc/mpc8xx.c
index d239daee1b08db54fa5297293d381b9e46643746..147a225c6b0a651c5694e7b45ffc1af26601bcfd 100644
--- a/drivers/rtc/mpc8xx.c
+++ b/drivers/rtc/mpc8xx.c
@@ -26,7 +26,7 @@ int rtc_get (struct rtc_time *tmp)
 
 	tim = immr->im_sit.sit_rtc;
 
-	to_tm (tim, tmp);
+	rtc_to_tm(tim, tmp);
 
 	debug ( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
 		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -44,8 +44,7 @@ int rtc_set (struct rtc_time *tmp)
 		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
 		tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 
-	tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
-		      tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+	tim = rtc_mktime(tmp);
 
 	immr->im_sitk.sitk_rtck = KAPWR_KEY;
 	immr->im_sit.sit_rtc = tim;
diff --git a/drivers/rtc/mx27rtc.c b/drivers/rtc/mx27rtc.c
index ae6595b86037744f2153051410c6d4c215132add..29ccdf17301b174241feffadd7fb4e92084a4b18 100644
--- a/drivers/rtc/mx27rtc.c
+++ b/drivers/rtc/mx27rtc.c
@@ -30,7 +30,7 @@ int rtc_get(struct rtc_time *time)
 
 	sec += min * 60 + hour * 3600 + day * 24 * 3600;
 
-	to_tm(sec, time);
+	rtc_to_tm(sec, time);
 
 	return 0;
 }
@@ -40,8 +40,7 @@ int rtc_set(struct rtc_time *time)
 	struct rtc_regs *rtc_regs = (struct rtc_regs *)IMX_RTC_BASE;
 	uint32_t day, hour, min, sec;
 
-	sec = mktime(time->tm_year, time->tm_mon, time->tm_mday,
-		time->tm_hour, time->tm_min, time->tm_sec);
+	sec = rtc_mktime(time);
 
 	day  = sec / (24 * 3600);
 	sec  = sec % (24 * 3600);
diff --git a/drivers/rtc/mxsrtc.c b/drivers/rtc/mxsrtc.c
index 32ba8a3062ce07f1d2cb4db9af8dcd0ac2020e65..6e32154f47b40bc21475e6d68b7cc03c80e2e6f5 100644
--- a/drivers/rtc/mxsrtc.c
+++ b/drivers/rtc/mxsrtc.c
@@ -43,7 +43,7 @@ int rtc_get(struct rtc_time *time)
 	uint32_t secs;
 
 	secs = readl(&rtc_regs->hw_rtc_seconds);
-	to_tm(secs, time);
+	rtc_to_tm(secs, time);
 
 	return 0;
 }
@@ -52,8 +52,7 @@ int rtc_set(struct rtc_time *time)
 {
 	uint32_t secs;
 
-	secs = mktime(time->tm_year, time->tm_mon, time->tm_mday,
-		time->tm_hour, time->tm_min, time->tm_sec);
+	secs = rtc_mktime(time);
 
 	return mxs_rtc_set_time(secs);
 }
diff --git a/drivers/rtc/pl031.c b/drivers/rtc/pl031.c
index c4d1259a898d2e885eea0d76a6f16ad1c07e7434..fc83049ecd2ebcfed6e746a25d8edda92ace3a32 100644
--- a/drivers/rtc/pl031.c
+++ b/drivers/rtc/pl031.c
@@ -72,8 +72,7 @@ int rtc_set(struct rtc_time *tmp)
 	}
 
 	/* Calculate number of seconds this incoming time represents */
-	tim = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
-			tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+	tim = rtc_mktime(tmp);
 
 	RTC_WRITE_REG(RTC_LR, tim);
 
@@ -97,7 +96,7 @@ int rtc_get(struct rtc_time *tmp)
 
 	tim = RTC_READ_REG(RTC_DR);
 
-	to_tm (tim, tmp);
+	rtc_to_tm(tim, tmp);
 
 	debug ( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
 		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
diff --git a/drivers/rtc/rtc-uclass.c b/drivers/rtc/rtc-uclass.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe74c69f97ec3a3ebb9164a0e585b482b6d66628
--- /dev/null
+++ b/drivers/rtc/rtc-uclass.c
@@ -0,0 +1,96 @@
+/*
+ * (C) Copyright 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 <rtc.h>
+
+int dm_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+	struct rtc_ops *ops = rtc_get_ops(dev);
+
+	assert(ops);
+	if (!ops->get)
+		return -ENOSYS;
+	return ops->get(dev, time);
+}
+
+int dm_rtc_set(struct udevice *dev, struct rtc_time *time)
+{
+	struct rtc_ops *ops = rtc_get_ops(dev);
+
+	assert(ops);
+	if (!ops->set)
+		return -ENOSYS;
+	return ops->set(dev, time);
+}
+
+int dm_rtc_reset(struct udevice *dev)
+{
+	struct rtc_ops *ops = rtc_get_ops(dev);
+
+	assert(ops);
+	if (!ops->reset)
+		return -ENOSYS;
+	return ops->reset(dev);
+}
+
+int rtc_read8(struct udevice *dev, unsigned int reg)
+{
+	struct rtc_ops *ops = rtc_get_ops(dev);
+
+	assert(ops);
+	if (!ops->read8)
+		return -ENOSYS;
+	return ops->read8(dev, reg);
+}
+
+int rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+	struct rtc_ops *ops = rtc_get_ops(dev);
+
+	assert(ops);
+	if (!ops->write8)
+		return -ENOSYS;
+	return ops->write8(dev, reg, val);
+}
+
+int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep)
+{
+	u32 value = 0;
+	int ret;
+	int i;
+
+	for (i = 0; i < sizeof(value); i++) {
+		ret = rtc_read8(dev, reg + i);
+		if (ret)
+			return ret;
+		value |= ret << (i << 3);
+	}
+
+	*valuep = value;
+	return 0;
+}
+
+int rtc_write32(struct udevice *dev, unsigned int reg, u32 value)
+{
+	int i, ret;
+
+	for (i = 0; i < sizeof(value); i++) {
+		ret = rtc_write8(dev, reg + i, (value >> (i << 3)) & 0xff);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+UCLASS_DRIVER(rtc) = {
+	.name		= "rtc",
+	.id		= UCLASS_RTC,
+};
diff --git a/drivers/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c
new file mode 100644
index 0000000000000000000000000000000000000000..f292fbe9b66fbbd77214e948278844213527ed0f
--- /dev/null
+++ b/drivers/rtc/sandbox_rtc.c
@@ -0,0 +1,106 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+#include <asm/rtc.h>
+
+#define REG_COUNT 0x80
+
+static int sandbox_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+	time->tm_sec = dm_i2c_reg_read(dev, REG_SEC);
+	if (time->tm_sec < 0)
+		return time->tm_sec;
+	time->tm_min = dm_i2c_reg_read(dev, REG_MIN);
+	if (time->tm_min < 0)
+		return time->tm_min;
+	time->tm_hour = dm_i2c_reg_read(dev, REG_HOUR);
+	if (time->tm_hour < 0)
+		return time->tm_hour;
+	time->tm_mday = dm_i2c_reg_read(dev, REG_MDAY);
+	if (time->tm_mday < 0)
+		return time->tm_mday;
+	time->tm_mon = dm_i2c_reg_read(dev, REG_MON);
+	if (time->tm_mon < 0)
+		return time->tm_mon;
+	time->tm_year = dm_i2c_reg_read(dev, REG_YEAR);
+	if (time->tm_year < 0)
+		return time->tm_year;
+	time->tm_year += 1900;
+	time->tm_wday = dm_i2c_reg_read(dev, REG_WDAY);
+	if (time->tm_wday < 0)
+		return time->tm_wday;
+
+	return 0;
+}
+
+static int sandbox_rtc_set(struct udevice *dev, const struct rtc_time *time)
+{
+	int ret;
+
+	ret = dm_i2c_reg_write(dev, REG_SEC, time->tm_sec);
+	if (ret < 0)
+		return ret;
+	ret = dm_i2c_reg_write(dev, REG_MIN, time->tm_min);
+	if (ret < 0)
+		return ret;
+	ret = dm_i2c_reg_write(dev, REG_HOUR, time->tm_hour);
+	if (ret < 0)
+		return ret;
+	ret = dm_i2c_reg_write(dev, REG_MDAY, time->tm_mday);
+	if (ret < 0)
+		return ret;
+	ret = dm_i2c_reg_write(dev, REG_MON, time->tm_mon);
+	if (ret < 0)
+		return ret;
+	ret = dm_i2c_reg_write(dev, REG_YEAR, time->tm_year - 1900);
+	if (ret < 0)
+		return ret;
+	ret = dm_i2c_reg_write(dev, REG_WDAY, time->tm_wday);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int sandbox_rtc_reset(struct udevice *dev)
+{
+	return dm_i2c_reg_write(dev, REG_RESET, 0);
+}
+
+static int sandbox_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+	return dm_i2c_reg_read(dev, reg);
+}
+
+static int sandbox_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+	return dm_i2c_reg_write(dev, reg, val);
+}
+
+static const struct rtc_ops sandbox_rtc_ops = {
+	.get = sandbox_rtc_get,
+	.set = sandbox_rtc_set,
+	.reset = sandbox_rtc_reset,
+	.read8 = sandbox_rtc_read8,
+	.write8 = sandbox_rtc_write8,
+};
+
+static const struct udevice_id sandbox_rtc_ids[] = {
+	{ .compatible = "sandbox-rtc" },
+	{ }
+};
+
+U_BOOT_DRIVER(rtc_sandbox) = {
+	.name	= "rtc-sandbox",
+	.id	= UCLASS_RTC,
+	.of_match = sandbox_rtc_ids,
+	.ops	= &sandbox_rtc_ops,
+};
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 83fe8e0d69ae9d8d6972f99a72e4294fa4aa0848..737ae64052acace832e332ba16ea69e3ddc8adc6 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -63,9 +63,12 @@ int spi_claim_bus(struct spi_slave *slave)
 	}
 	if (!speed)
 		speed = 100000;
-	ret = spi_set_speed_mode(bus, speed, slave->mode);
-	if (ret)
-		return ret;
+	if (speed != slave->speed) {
+		ret = spi_set_speed_mode(bus, speed, slave->mode);
+		if (ret)
+			return ret;
+		slave->speed = speed;
+	}
 
 	return ops->claim_bus ? ops->claim_bus(dev) : 0;
 }
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 86cf6312febc30b7e142146c3b4763a6a871d5a6..18e9251b64f5c1cadd5e4121fb99a753c70a75a6 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -25,14 +25,12 @@
 /* Declare global data pointer */
 DECLARE_GLOBAL_DATA_PTR;
 
-#ifdef CONFIG_DM_USB
 struct exynos_ehci_platdata {
 	struct usb_platdata usb_plat;
 	fdt_addr_t hcd_base;
 	fdt_addr_t phy_base;
 	struct gpio_desc vbus_gpio;
 };
-#endif
 
 /**
  * Contains pointers to register base addresses
@@ -42,16 +40,8 @@ struct exynos_ehci {
 	struct ehci_ctrl ctrl;
 	struct exynos_usb_phy *usb;
 	struct ehci_hccr *hcd;
-#ifndef CONFIG_DM_USB
-	struct gpio_desc vbus_gpio;
-#endif
 };
 
-#ifndef CONFIG_DM_USB
-static struct exynos_ehci exynos;
-#endif
-
-#ifdef CONFIG_DM_USB
 static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
 {
 	struct exynos_ehci_platdata *plat = dev_get_platdata(dev);
@@ -91,55 +81,6 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
 
 	return 0;
 }
-#else
-static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
-{
-	fdt_addr_t addr;
-	unsigned int node;
-	int depth;
-
-	node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_EHCI);
-	if (node <= 0) {
-		debug("EHCI: Can't get device node for ehci\n");
-		return -ENODEV;
-	}
-
-	/*
-	 * Get the base address for EHCI controller from the device node
-	 */
-	addr = fdtdec_get_addr(blob, node, "reg");
-	if (addr == FDT_ADDR_T_NONE) {
-		debug("Can't get the EHCI register address\n");
-		return -ENXIO;
-	}
-
-	exynos->hcd = (struct ehci_hccr *)addr;
-
-	/* Vbus gpio */
-	gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
-				   &exynos->vbus_gpio, GPIOD_IS_OUT);
-
-	depth = 0;
-	node = fdtdec_next_compatible_subnode(blob, node,
-					COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth);
-	if (node <= 0) {
-		debug("EHCI: Can't get device node for usb-phy controller\n");
-		return -ENODEV;
-	}
-
-	/*
-	 * Get the base address for usbphy from the device node
-	 */
-	exynos->usb = (struct exynos_usb_phy *)fdtdec_get_addr(blob, node,
-								"reg");
-	if (exynos->usb == NULL) {
-		debug("Can't get the usbphy register address\n");
-		return -ENXIO;
-	}
-
-	return 0;
-}
-#endif
 
 static void exynos5_setup_usb_phy(struct exynos_usb_phy *usb)
 {
@@ -270,63 +211,6 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)
 	set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE);
 }
 
-#ifndef CONFIG_DM_USB
-/*
- * EHCI-initialization
- * Create the appropriate control structures to manage
- * a new EHCI host controller.
- */
-int ehci_hcd_init(int index, enum usb_init_type init,
-		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
-{
-	struct exynos_ehci *ctx = &exynos;
-
-#ifdef CONFIG_OF_CONTROL
-	if (exynos_usb_parse_dt(gd->fdt_blob, ctx)) {
-		debug("Unable to parse device tree for ehci-exynos\n");
-		return -ENODEV;
-	}
-#else
-	ctx->usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy();
-	ctx->hcd = (struct ehci_hccr *)samsung_get_base_usb_ehci();
-#endif
-
-#ifdef CONFIG_OF_CONTROL
-	/* setup the Vbus gpio here */
-	if (dm_gpio_is_valid(&ctx->vbus_gpio))
-		dm_gpio_set_value(&ctx->vbus_gpio, 1);
-#endif
-
-	setup_usb_phy(ctx->usb);
-
-	board_usb_init(index, init);
-
-	*hccr = ctx->hcd;
-	*hcor = (struct ehci_hcor *)((uint32_t) *hccr
-				+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
-
-	debug("Exynos5-ehci: init hccr %x and hcor %x hc_length %d\n",
-		(uint32_t)*hccr, (uint32_t)*hcor,
-		(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
-
-	return 0;
-}
-
-/*
- * Destroy the appropriate control structures corresponding
- * the EHCI host controller.
- */
-int ehci_hcd_stop(int index)
-{
-	struct exynos_ehci *ctx = &exynos;
-
-	reset_usb_phy(ctx->usb);
-
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_DM_USB
 static int ehci_usb_probe(struct udevice *dev)
 {
 	struct exynos_ehci_platdata *plat = dev_get_platdata(dev);
@@ -377,4 +261,3 @@ U_BOOT_DRIVER(usb_ehci) = {
 	.platdata_auto_alloc_size = sizeof(struct exynos_ehci_platdata),
 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
 };
-#endif
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index bd9861dd68e352450c476949bca59253b31e95ec..46d01d40e84a773bfb03de537e2ce639563f88bc 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -125,14 +125,7 @@ static struct descriptor {
 static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev)
 {
 #ifdef CONFIG_DM_USB
-	struct udevice *dev;
-
-	/* Find the USB controller */
-	for (dev = udev->dev;
-	     device_get_uclass_id(dev) != UCLASS_USB;
-	     dev = dev->parent)
-		;
-	return dev_get_priv(dev);
+	return dev_get_priv(usb_get_bus(udev->dev));
 #else
 	return udev->controller;
 #endif
@@ -310,23 +303,33 @@ static void ehci_update_endpt2_dev_n_port(struct usb_device *udev,
 	 * in the tree before that one!
 	 */
 #ifdef CONFIG_DM_USB
+	/*
+	 * 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 .
+	 */
 	struct udevice *parent;
+	struct usb_device *uparent;
+
+	ttdev = udev;
+	parent = udev->dev;
+	uparent = dev_get_parentdata(parent);
 
-	for (ttdev = udev; ; ) {
-		struct udevice *dev = ttdev->dev;
+	while (uparent->speed != USB_SPEED_HIGH) {
+		struct udevice *dev = parent;
 
-		if (dev->parent &&
-		    device_get_uclass_id(dev->parent) == UCLASS_USB_HUB)
-			parent = dev->parent;
-		else
-			parent = NULL;
-		if (!parent)
+		if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
+			printf("ehci: Error cannot find high speed parent of usb-1 device\n");
 			return;
-		ttdev = dev_get_parentdata(parent);
-		if (!ttdev->speed != USB_SPEED_HIGH)
-			break;
+		}
+
+		ttdev = dev_get_parentdata(dev);
+		parent = dev->parent;
+		uparent = dev_get_parentdata(parent);
 	}
-	parent_devnum = ttdev->devnum;
+	parent_devnum = uparent->devnum;
 #else
 	ttdev = udev;
 	while (ttdev->parent && ttdev->parent->speed != USB_SPEED_HIGH)
@@ -1576,12 +1579,15 @@ int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
 		  struct ehci_hcor *hcor, const struct ehci_ops *ops,
 		  uint tweaks, enum usb_init_type init)
 {
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
 	struct ehci_ctrl *ctrl = dev_get_priv(dev);
 	int ret;
 
 	debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p, init=%d\n", __func__,
 	      dev->name, ctrl, hccr, hcor, init);
 
+	priv->desc_before_addr = true;
+
 	ehci_setup_ops(ctrl, ops);
 	ctrl->hccr = hccr;
 	ctrl->hcor = hcor;
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 97a7edeb53998713985a626faac565779d89b985..494b76076111897512822b23ee4e59f0e07eb4d5 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -103,16 +103,91 @@ static struct pci_device_id ehci_pci_ids[] = {
 # define m32_swap(x) cpu_to_le32(x)
 #endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */
 
+#ifdef CONFIG_DM_USB
+/*
+ * We really should do proper cache flushing everywhere, but for now we only
+ * do it for new (driver-model) usb code to avoid regressions.
+ */
+#define flush_dcache_buffer(addr, size) \
+	flush_dcache_range((unsigned long)(addr), \
+		ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
+#define invalidate_dcache_buffer(addr, size) \
+	invalidate_dcache_range((unsigned long)(addr), \
+		ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
+#else
+#define flush_dcache_buffer(addr, size)
+#define invalidate_dcache_buffer(addr, size)
+#endif
+
+/* Do not use sizeof(ed / td) as our ed / td structs contain extra members */
+#define flush_dcache_ed(addr) flush_dcache_buffer(addr, 16)
+#define flush_dcache_td(addr) flush_dcache_buffer(addr, 16)
+#define flush_dcache_iso_td(addr) flush_dcache_buffer(addr, 32)
+#define flush_dcache_hcca(addr) flush_dcache_buffer(addr, 256)
+#define invalidate_dcache_ed(addr) invalidate_dcache_buffer(addr, 16)
+#define invalidate_dcache_td(addr) invalidate_dcache_buffer(addr, 16)
+#define invalidate_dcache_iso_td(addr) invalidate_dcache_buffer(addr, 32)
+#define invalidate_dcache_hcca(addr) invalidate_dcache_buffer(addr, 256)
+
 /* global ohci_t */
 static ohci_t gohci;
 /* this must be aligned to a 256 byte boundary */
 struct ohci_hcca ghcca[1];
-/* a pointer to the aligned storage */
-struct ohci_hcca *phcca;
-/* this allocates EDs for all possible endpoints */
-struct ohci_device ohci_dev;
-/* device which was disconnected */
-struct usb_device *devgone;
+
+/* mapping of the OHCI CC status to error codes */
+static int cc_to_error[16] = {
+	/* No  Error  */	       0,
+	/* CRC Error  */	       USB_ST_CRC_ERR,
+	/* Bit Stuff  */	       USB_ST_BIT_ERR,
+	/* Data Togg  */	       USB_ST_CRC_ERR,
+	/* Stall      */	       USB_ST_STALLED,
+	/* DevNotResp */	       -1,
+	/* PIDCheck   */	       USB_ST_BIT_ERR,
+	/* UnExpPID   */	       USB_ST_BIT_ERR,
+	/* DataOver   */	       USB_ST_BUF_ERR,
+	/* DataUnder  */	       USB_ST_BUF_ERR,
+	/* reservd    */	       -1,
+	/* reservd    */	       -1,
+	/* BufferOver */	       USB_ST_BUF_ERR,
+	/* BuffUnder  */	       USB_ST_BUF_ERR,
+	/* Not Access */	       -1,
+	/* Not Access */	       -1
+};
+
+static const char *cc_to_string[16] = {
+	"No Error",
+	"CRC: Last data packet from endpoint contained a CRC error.",
+	"BITSTUFFING: Last data packet from endpoint contained a bit " \
+		     "stuffing violation",
+	"DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
+		     "that did not match the expected value.",
+	"STALL: TD was moved to the Done Queue because the endpoint returned" \
+		     " a STALL PID",
+	"DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
+		     "not provide a handshake (OUT)",
+	"PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
+		     "(IN) or handshake (OUT)",
+	"UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
+		     "value is not defined.",
+	"DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
+		     "either the size of the maximum data packet allowed\n" \
+		     "from the endpoint (found in MaximumPacketSize field\n" \
+		     "of ED) or the remaining buffer size.",
+	"DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
+		     "and that amount was not sufficient to fill the\n" \
+		     "specified buffer",
+	"reserved1",
+	"reserved2",
+	"BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
+		     "than it could be written to system memory",
+	"BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
+		     "system memory fast enough to keep up with data USB " \
+		     "data rate.",
+	"NOT ACCESSED: This code is set by software before the TD is placed" \
+		     "on a list to be processed by the HC.(1)",
+	"NOT ACCESSED: This code is set by software before the TD is placed" \
+		     "on a list to be processed by the HC.(2)",
+};
 
 static inline u32 roothub_a(struct ohci *hc)
 	{ return ohci_readl(&hc->regs->roothub.a); }
@@ -124,11 +199,42 @@ static inline u32 roothub_portstatus(struct ohci *hc, int i)
 	{ return ohci_readl(&hc->regs->roothub.portstatus[i]); }
 
 /* forward declaration */
-static int hc_interrupt(void);
-static void td_submit_job(struct usb_device *dev, unsigned long pipe,
-			  void *buffer, int transfer_len,
+static int hc_interrupt(ohci_t *ohci);
+static void td_submit_job(ohci_t *ohci, struct usb_device *dev,
+			  unsigned long pipe, void *buffer, int transfer_len,
 			  struct devrequest *setup, urb_priv_t *urb,
 			  int interval);
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev,
+		       unsigned long pipe, int interval, int load);
+
+/*-------------------------------------------------------------------------*/
+
+/* TDs ... */
+static struct td *td_alloc(ohci_dev_t *ohci_dev, struct usb_device *usb_dev)
+{
+	int i;
+	struct td *td;
+
+	td = NULL;
+	for (i = 0; i < NUM_TD; i++)
+	{
+		if (ohci_dev->tds[i].usb_dev == NULL)
+		{
+			td = &ohci_dev->tds[i];
+			td->usb_dev = usb_dev;
+			break;
+		}
+	}
+
+	return td;
+}
+
+static inline void ed_free(struct ed *ed)
+{
+	ed->usb_dev = NULL;
+}
 
 /*-------------------------------------------------------------------------*
  * URB support functions
@@ -158,18 +264,18 @@ static void urb_free_priv(urb_priv_t *urb)
 /*-------------------------------------------------------------------------*/
 
 #ifdef DEBUG
-static int sohci_get_current_frame_number(struct usb_device *dev);
+static int sohci_get_current_frame_number(ohci_t *ohci);
 
 /* debug| print the main components of an URB
  * small: 0) header + data packets 1) just header */
 
-static void pkt_print(urb_priv_t *purb, struct usb_device *dev,
+static void pkt_print(ohci_t *ohci, urb_priv_t *purb, struct usb_device *dev,
 		      unsigned long pipe, void *buffer, int transfer_len,
 		      struct devrequest *setup, char *str, int small)
 {
 	dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d stat:%#lx",
 			str,
-			sohci_get_current_frame_number(dev),
+			sohci_get_current_frame_number(ohci),
 			usb_pipedevice(pipe),
 			usb_pipeendpoint(pipe),
 			usb_pipeout(pipe)? 'O': 'I',
@@ -213,9 +319,11 @@ void ep_print_int_eds(ohci_t *ohci, char *str)
 		ed_p = &(ohci->hcca->int_table [i]);
 		if (*ed_p == 0)
 		    continue;
+		invalidate_dcache_ed(ed_p);
 		printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i);
 		while (*ed_p != 0 && j--) {
 			ed_t *ed = (ed_t *)m32_swap(ed_p);
+			invalidate_dcache_ed(ed);
 			printf(" ed: %4x;", ed->hwINFO);
 			ed_p = &ed->hwNextED;
 		}
@@ -246,6 +354,7 @@ static void maybe_print_eds(char *label, __u32 value)
 
 	if (value) {
 		dbg("%s %08x", label, value);
+		invalidate_dcache_ed(edp);
 		dbg("%08x", edp->hwINFO);
 		dbg("%08x", edp->hwTailP);
 		dbg("%08x", edp->hwHeadP);
@@ -380,6 +489,7 @@ static void ohci_dump(ohci_t *controller, int verbose)
 	ohci_dump_status(controller);
 	if (verbose)
 		ep_print_int_eds(controller, "hcca");
+	invalidate_dcache_hcca(controller->hcca);
 	dbg("hcca frame #%04x", controller->hcca->frame_no);
 	ohci_dump_roothub(controller, 1);
 }
@@ -391,9 +501,9 @@ static void ohci_dump(ohci_t *controller, int verbose)
 
 /* get a transfer request */
 
-int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
+int sohci_submit_job(ohci_t *ohci, ohci_dev_t *ohci_dev, urb_priv_t *urb,
+		     struct devrequest *setup)
 {
-	ohci_t *ohci;
 	ed_t *ed;
 	urb_priv_t *purb_priv = urb;
 	int i, size = 0;
@@ -403,8 +513,6 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
 	int transfer_len = urb->transfer_buffer_length;
 	int interval = urb->interval;
 
-	ohci = &gohci;
-
 	/* when controller's hung, permit only roothub cleanup attempts
 	 * such as powering down ports */
 	if (ohci->disabled) {
@@ -417,7 +525,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
 	urb->finished = 0;
 
 	/* every endpoint has a ed, locate and fill it */
-	ed = ep_add_ed(dev, pipe, interval, 1);
+	ed = ep_add_ed(ohci_dev, dev, pipe, interval, 1);
 	if (!ed) {
 		err("sohci_submit_job: ENOMEM");
 		return -1;
@@ -453,7 +561,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
 	/* allocate the TDs */
 	/* note that td[0] was allocated in ep_add_ed */
 	for (i = 0; i < size; i++) {
-		purb_priv->td[i] = td_alloc(dev);
+		purb_priv->td[i] = td_alloc(ohci_dev, dev);
 		if (!purb_priv->td[i]) {
 			purb_priv->length = i;
 			urb_free_priv(purb_priv);
@@ -473,7 +581,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
 		ep_link(ohci, ed);
 
 	/* fill the TDs and link it to the ed */
-	td_submit_job(dev, pipe, buffer, transfer_len,
+	td_submit_job(ohci, dev, pipe, buffer, transfer_len,
 		      setup, purb_priv, interval);
 
 	return 0;
@@ -495,7 +603,7 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
 			ohci_readl(&regs->intrdisable); /* PCI posting flush */
 		}
 		urb->actual_length = 0;
-		td_submit_job(
+		td_submit_job(  hc,
 				urb->dev,
 				urb->pipe,
 				urb->transfer_buffer,
@@ -517,11 +625,9 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
 
 #ifdef DEBUG
 /* tell us the current USB frame number */
-
-static int sohci_get_current_frame_number(struct usb_device *usb_dev)
+static int sohci_get_current_frame_number(ohci_t *ohci)
 {
-	ohci_t *ohci = &gohci;
-
+	invalidate_dcache_hcca(ohci->hcca);
 	return m16_swap(ohci->hcca->frame_no);
 }
 #endif
@@ -600,6 +706,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
 	switch (ed->type) {
 	case PIPE_CONTROL:
 		ed->hwNextED = 0;
+		flush_dcache_ed(ed);
 		if (ohci->ed_controltail == NULL)
 			ohci_writel(ed, &ohci->regs->ed_controlhead);
 		else
@@ -617,6 +724,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
 
 	case PIPE_BULK:
 		ed->hwNextED = 0;
+		flush_dcache_ed(ed);
 		if (ohci->ed_bulktail == NULL)
 			ohci_writel(ed, &ohci->regs->ed_bulkhead);
 		else
@@ -649,7 +757,9 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
 					inter = ep_rev(6,
 						 ((ed_t *)ed_p)->int_interval);
 			ed->hwNextED = *ed_p;
+			flush_dcache_ed(ed);
 			*ed_p = m32_swap((unsigned long)ed);
+			flush_dcache_hcca(ohci->hcca);
 		}
 		break;
 	}
@@ -662,6 +772,8 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
 static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
 			    unsigned index, unsigned period)
 {
+	__maybe_unused unsigned long aligned_ed_p;
+
 	for (; index < NUM_INTS; index += period) {
 		__u32	*ed_p = &ohci->hcca->int_table [index];
 
@@ -670,6 +782,12 @@ static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
 			if (((struct ed *)
 					m32_swap((unsigned long)ed_p)) == ed) {
 				*ed_p = ed->hwNextED;
+#ifdef CONFIG_DM_USB
+				aligned_ed_p = (unsigned long)ed_p;
+				aligned_ed_p &= ~(ARCH_DMA_MINALIGN - 1);
+				flush_dcache_range(aligned_ed_p,
+					aligned_ed_p + ARCH_DMA_MINALIGN);
+#endif
 				break;
 			}
 			ed_p = &(((struct ed *)
@@ -689,6 +807,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
 	int i;
 
 	ed->hwINFO |= m32_swap(OHCI_ED_SKIP);
+	flush_dcache_ed(ed);
 
 	switch (ed->type) {
 	case PIPE_CONTROL:
@@ -702,6 +821,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
 				&ohci->regs->ed_controlhead);
 		} else {
 			ed->ed_prev->hwNextED = ed->hwNextED;
+			flush_dcache_ed(ed->ed_prev);
 		}
 		if (ohci->ed_controltail == ed) {
 			ohci->ed_controltail = ed->ed_prev;
@@ -722,6 +842,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
 			       &ohci->regs->ed_bulkhead);
 		} else {
 			ed->ed_prev->hwNextED = ed->hwNextED;
+			flush_dcache_ed(ed->ed_prev);
 		}
 		if (ohci->ed_bulktail == ed) {
 			ohci->ed_bulktail = ed->ed_prev;
@@ -751,14 +872,14 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
  * info fields are setted anyway even though most of them should not
  * change
  */
-static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
-			int interval, int load)
+static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev,
+		       unsigned long pipe, int interval, int load)
 {
 	td_t *td;
 	ed_t *ed_ret;
 	volatile ed_t *ed;
 
-	ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint(pipe) << 1) |
+	ed = ed_ret = &ohci_dev->ed[(usb_pipeendpoint(pipe) << 1) |
 			(usb_pipecontrol(pipe)? 0: usb_pipeout(pipe))];
 
 	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
@@ -769,12 +890,12 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
 
 	if (ed->state == ED_NEW) {
 		/* dummy td; end of td list for ed */
-		td = td_alloc(usb_dev);
+		td = td_alloc(ohci_dev, usb_dev);
 		ed->hwTailP = m32_swap((unsigned long)td);
 		ed->hwHeadP = ed->hwTailP;
 		ed->state = ED_UNLINK;
 		ed->type = usb_pipetype(pipe);
-		ohci_dev.ed_cnt++;
+		ohci_dev->ed_cnt++;
 	}
 
 	ed->hwINFO = m32_swap(usb_pipedevice(pipe)
@@ -790,6 +911,8 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
 		ed->int_load = load;
 	}
 
+	flush_dcache_ed(ed);
+
 	return ed_ret;
 }
 
@@ -815,6 +938,7 @@ static void td_fill(ohci_t *ohci, unsigned int info,
 	/* use this td as the next dummy */
 	td_pt = urb_priv->td [index];
 	td_pt->hwNextTD = 0;
+	flush_dcache_td(td_pt);
 
 	/* fill the old dummy TD */
 	td = urb_priv->td [index] =
@@ -842,27 +966,30 @@ static void td_fill(ohci_t *ohci, unsigned int info,
 		td->hwBE = 0;
 
 	td->hwNextTD = m32_swap((unsigned long)td_pt);
+	flush_dcache_td(td);
 
 	/* append to queue */
 	td->ed->hwTailP = td->hwNextTD;
+	flush_dcache_ed(td->ed);
 }
 
 /*-------------------------------------------------------------------------*/
 
 /* prepare all TDs of a transfer */
 
-static void td_submit_job(struct usb_device *dev, unsigned long pipe,
-			  void *buffer, int transfer_len,
+static void td_submit_job(ohci_t *ohci, struct usb_device *dev,
+			  unsigned long pipe, void *buffer, int transfer_len,
 			  struct devrequest *setup, urb_priv_t *urb,
 			  int interval)
 {
-	ohci_t *ohci = &gohci;
 	int data_len = transfer_len;
 	void *data;
 	int cnt = 0;
 	__u32 info = 0;
 	unsigned int toggle = 0;
 
+	flush_dcache_buffer(buffer, data_len);
+
 	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle
 	 * bits for reseting */
 	if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
@@ -902,6 +1029,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
 	case PIPE_CONTROL:
 		/* Setup phase */
 		info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+		flush_dcache_buffer(setup, 8);
 		td_fill(ohci, info, setup, 8, dev, cnt++, urb);
 
 		/* Optional Data phase */
@@ -914,7 +1042,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
 		}
 
 		/* Status phase */
-		info = usb_pipeout(pipe)?
+		info = (usb_pipeout(pipe) || data_len == 0) ?
 			TD_CC | TD_DP_IN | TD_T_DATA1:
 			TD_CC | TD_DP_OUT | TD_T_DATA1;
 		td_fill(ohci, info, data, 0, dev, cnt++, urb);
@@ -973,6 +1101,7 @@ static void check_status(td_t *td_list)
 	if (cc) {
 		err(" USB-error: %s (%x)", cc_to_string[cc], cc);
 
+		invalidate_dcache_ed(td_list->ed);
 		if (*phwHeadP & m32_swap(0x1)) {
 			if (lurb_priv &&
 			    ((td_list->index + 1) < urb_len)) {
@@ -985,9 +1114,11 @@ static void check_status(td_t *td_list)
 						     td_list->index - 1;
 			} else
 				*phwHeadP &= m32_swap(0xfffffff2);
+			flush_dcache_ed(td_list->ed);
 		}
 #ifdef CONFIG_MPC5200
 		td_list->hwNextTD = 0;
+		flush_dcache_td(td_list);
 #endif
 	}
 }
@@ -1000,11 +1131,14 @@ static td_t *dl_reverse_done_list(ohci_t *ohci)
 	td_t *td_rev = NULL;
 	td_t *td_list = NULL;
 
+	invalidate_dcache_hcca(ohci->hcca);
 	td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0;
 	ohci->hcca->done_head = 0;
+	flush_dcache_hcca(ohci->hcca);
 
 	while (td_list_hc) {
 		td_list = (td_t *)td_list_hc;
+		invalidate_dcache_td(td_list);
 		check_status(td_list);
 		td_list->next_dl_td = td_rev;
 		td_rev = td_list;
@@ -1039,6 +1173,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list)
 	urb_priv_t *lurb_priv;
 	__u32 tdINFO, edHeadP, edTailP;
 
+	invalidate_dcache_td(td_list);
 	tdINFO = m32_swap(td_list->hwINFO);
 
 	ed = td_list->ed;
@@ -1064,6 +1199,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list)
 		lurb_priv->td_cnt, lurb_priv->length);
 
 	if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) {
+		invalidate_dcache_ed(ed);
 		edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0;
 		edTailP = m32_swap(ed->hwTailP);
 
@@ -1100,16 +1236,16 @@ static int dl_done_list(ohci_t *ohci)
 #define OK(x)			len = (x); break
 #ifdef DEBUG
 #define WR_RH_STAT(x)		{info("WR:status %#8x", (x)); ohci_writel((x), \
-						&gohci.regs->roothub.status); }
+						&ohci->regs->roothub.status); }
 #define WR_RH_PORTSTAT(x)	{info("WR:portstatus[%d] %#8x", wIndex-1, \
-	(x)); ohci_writel((x), &gohci.regs->roothub.portstatus[wIndex-1]); }
+	(x)); ohci_writel((x), &ohci->regs->roothub.portstatus[wIndex-1]); }
 #else
-#define WR_RH_STAT(x)		ohci_writel((x), &gohci.regs->roothub.status)
+#define WR_RH_STAT(x)		ohci_writel((x), &ohci->regs->roothub.status)
 #define WR_RH_PORTSTAT(x)	ohci_writel((x), \
-				    &gohci.regs->roothub.portstatus[wIndex-1])
+				    &ohci->regs->roothub.portstatus[wIndex-1])
 #endif
-#define RD_RH_STAT		roothub_status(&gohci)
-#define RD_RH_PORTSTAT		roothub_portstatus(&gohci, wIndex-1)
+#define RD_RH_STAT		roothub_status(ohci)
+#define RD_RH_PORTSTAT		roothub_portstatus(ohci, wIndex-1)
 
 /* request to virtual root hub */
 
@@ -1137,8 +1273,9 @@ int rh_check_port_status(ohci_t *controller)
 	return res;
 }
 
-static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
-		void *buffer, int transfer_len, struct devrequest *cmd)
+static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev,
+	unsigned long pipe, void *buffer, int transfer_len,
+	struct devrequest *cmd)
 {
 	void *data = buffer;
 	int leni = transfer_len;
@@ -1151,7 +1288,7 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
 	ALLOC_ALIGN_BUFFER(__u8, databuf, 16, sizeof(u32));
 
 #ifdef DEBUG
-pkt_print(NULL, dev, pipe, buffer, transfer_len,
+pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len,
 	  cmd, "SUB(rh)", usb_pipein(pipe));
 #else
 	mdelay(1);
@@ -1245,7 +1382,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 		break;
 
 	case RH_SET_ADDRESS:
-		gohci.rh.devnum = wValue;
+		ohci->rh.devnum = wValue;
 		OK(0);
 
 	case RH_GET_DESCRIPTOR:
@@ -1290,7 +1427,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 
 	case RH_GET_DESCRIPTOR | RH_CLASS:
 	{
-		__u32 temp = roothub_a(&gohci);
+		__u32 temp = roothub_a(ohci);
 
 		databuf[0] = 9;		/* min length; */
 		databuf[1] = 0x29;
@@ -1309,7 +1446,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 		databuf[4] = 0;
 		databuf[5] = (temp & RH_A_POTPGT) >> 24;
 		databuf[6] = 0;
-		temp = roothub_b(&gohci);
+		temp = roothub_b(ohci);
 		databuf[7] = temp & RH_B_DR;
 		if (databuf[2] < 7) {
 			databuf[8] = 0xff;
@@ -1338,7 +1475,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 	}
 
 #ifdef	DEBUG
-	ohci_dump_roothub(&gohci, 1);
+	ohci_dump_roothub(ohci, 1);
 #else
 	mdelay(1);
 #endif
@@ -1350,7 +1487,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 	dev->status = stat;
 
 #ifdef DEBUG
-	pkt_print(NULL, dev, pipe, buffer,
+	pkt_print(ohci, NULL, dev, pipe, buffer,
 		  transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
 #else
 	mdelay(1);
@@ -1363,8 +1500,9 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 
 /* common code for handling submit messages - used for all but root hub */
 /* accesses. */
-int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-		int transfer_len, struct devrequest *setup, int interval)
+static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
+		unsigned long pipe, void *buffer, int transfer_len,
+		struct devrequest *setup, int interval)
 {
 	int stat = 0;
 	int maxsize = usb_maxpacket(dev, pipe);
@@ -1380,15 +1518,9 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 	urb->transfer_buffer_length = transfer_len;
 	urb->interval = interval;
 
-	/* device pulled? Shortcut the action. */
-	if (devgone == dev) {
-		dev->status = USB_ST_CRC_ERR;
-		return 0;
-	}
-
 #ifdef DEBUG
 	urb->actual_length = 0;
-	pkt_print(urb, dev, pipe, buffer, transfer_len,
+	pkt_print(ohci, urb, dev, pipe, buffer, transfer_len,
 		  setup, "SUB", usb_pipein(pipe));
 #else
 	mdelay(1);
@@ -1399,14 +1531,14 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 		return -1;
 	}
 
-	if (sohci_submit_job(urb, setup) < 0) {
+	if (sohci_submit_job(ohci, &ohci->ohci_dev, urb, setup) < 0) {
 		err("sohci_submit_job failed");
 		return -1;
 	}
 
 #if 0
 	mdelay(10);
-	/* ohci_dump_status(&gohci); */
+	/* ohci_dump_status(ohci); */
 #endif
 
 	timeout = USB_TIMEOUT_MS(pipe);
@@ -1414,7 +1546,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 	/* wait for it to complete */
 	for (;;) {
 		/* check whether the controller is done */
-		stat = hc_interrupt();
+		stat = hc_interrupt(ohci);
 		if (stat < 0) {
 			stat = USB_ST_CRC_ERR;
 			break;
@@ -1440,7 +1572,8 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 				dbg("*");
 
 		} else {
-			err("CTL:TIMEOUT ");
+			if (!usb_pipeint(pipe))
+				err("CTL:TIMEOUT ");
 			dbg("submit_common_msg: TO status %x\n", stat);
 			urb->finished = 1;
 			stat = USB_ST_CRC_ERR;
@@ -1451,8 +1584,11 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 	dev->status = stat;
 	dev->act_len = urb->actual_length;
 
+	if (usb_pipein(pipe) && dev->status == 0 && dev->act_len)
+		invalidate_dcache_buffer(buffer, dev->act_len);
+
 #ifdef DEBUG
-	pkt_print(urb, dev, pipe, buffer, transfer_len,
+	pkt_print(ohci, urb, dev, pipe, buffer, transfer_len,
 		  setup, "RET(ctlr)", usb_pipein(pipe));
 #else
 	mdelay(1);
@@ -1469,17 +1605,27 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 		int transfer_len)
 {
 	info("submit_bulk_msg");
-	return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+	return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len,
+				 NULL, 0);
 }
 
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-		int transfer_len, struct devrequest *setup)
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, int interval)
+{
+	info("submit_int_msg");
+	return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len, NULL,
+			interval);
+}
+
+static int _ohci_submit_control_msg(ohci_t *ohci, struct usb_device *dev,
+	unsigned long pipe, void *buffer, int transfer_len,
+	struct devrequest *setup)
 {
 	int maxsize = usb_maxpacket(dev, pipe);
 
 	info("submit_control_msg");
 #ifdef DEBUG
-	pkt_print(NULL, dev, pipe, buffer, transfer_len,
+	pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len,
 		  setup, "SUB", usb_pipein(pipe));
 #else
 	mdelay(1);
@@ -1489,22 +1635,15 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 			pipe);
 		return -1;
 	}
-	if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
-		gohci.rh.dev = dev;
+	if (((pipe >> 8) & 0x7f) == ohci->rh.devnum) {
+		ohci->rh.dev = dev;
 		/* root hub - redirect */
-		return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
-			setup);
+		return ohci_submit_rh_msg(ohci, dev, pipe, buffer,
+					  transfer_len, setup);
 	}
 
-	return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
-}
-
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-		int transfer_len, int interval)
-{
-	info("submit_int_msg");
-	return submit_common_msg(dev, pipe, buffer, transfer_len, NULL,
-			interval);
+	return submit_common_msg(ohci, dev, pipe, buffer, transfer_len,
+				 setup, 0);
 }
 
 /*-------------------------------------------------------------------------*
@@ -1648,13 +1787,14 @@ static int hc_start(ohci_t *ohci)
 
 /* an interrupt happens */
 
-static int hc_interrupt(void)
+static int hc_interrupt(ohci_t *ohci)
 {
-	ohci_t *ohci = &gohci;
 	struct ohci_regs *regs = ohci->regs;
 	int ints;
 	int stat = -1;
 
+	invalidate_dcache_hcca(ohci->hcca);
+
 	if ((ohci->hcca->done_head != 0) &&
 				!(m32_swap(ohci->hcca->done_head) & 0x01)) {
 		ints =  OHCI_INTR_WDH;
@@ -1702,7 +1842,7 @@ static int hc_interrupt(void)
 		mdelay(1);
 		ohci_writel(OHCI_INTR_WDH, &regs->intrdisable);
 		(void)ohci_readl(&regs->intrdisable); /* flush */
-		stat = dl_done_list(&gohci);
+		stat = dl_done_list(ohci);
 		ohci_writel(OHCI_INTR_WDH, &regs->intrenable);
 		(void)ohci_readl(&regs->intrdisable); /* flush */
 	}
@@ -1772,21 +1912,9 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 		err("HCCA not aligned!!");
 		return -1;
 	}
-	phcca = &ghcca[0];
-	info("aligned ghcca %p", phcca);
-	memset(&ohci_dev, 0, sizeof(struct ohci_device));
-	if ((__u32)&ohci_dev.ed[0] & 0x7) {
-		err("EDs not aligned!!");
-		return -1;
-	}
-	memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
-	if ((__u32)gtd & 0x7) {
-		err("TDs not aligned!!");
-		return -1;
-	}
-	ptd = gtd;
-	gohci.hcca = phcca;
-	memset(phcca, 0, sizeof(struct ohci_hcca));
+	gohci.hcca = &ghcca[0];
+	info("aligned ghcca %p", gohci.hcca);
+	memset(gohci.hcca, 0, sizeof(struct ohci_hcca));
 
 	gohci.disabled = 1;
 	gohci.sleeping = 0;
@@ -1880,3 +2008,10 @@ int usb_lowlevel_stop(int index)
 	ohci_inited = 0;
 	return 0;
 }
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
+	void *buffer, int transfer_len, struct devrequest *setup)
+{
+	return _ohci_submit_control_msg(&gohci, dev, pipe, buffer,
+					transfer_len, setup);
+}
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 9a4a2c24759111adf185be7cebdbffa0bd1f29b8..f52b4c1bb535e60d92be11528ff0fdef202e46d4 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -18,6 +18,18 @@
 # define ohci_writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a))
 #endif /* CONFIG_SYS_OHCI_SWAP_REG_ACCESS */
 
+#if defined CONFIG_DM_USB && ARCH_DMA_MINALIGN > 16
+#define ED_ALIGNMENT ARCH_DMA_MINALIGN
+#else
+#define ED_ALIGNMENT 16
+#endif
+
+#if defined CONFIG_DM_USB && ARCH_DMA_MINALIGN > 32
+#define TD_ALIGNMENT ARCH_DMA_MINALIGN
+#else
+#define TD_ALIGNMENT 32
+#endif
+
 /* functions for doing board or CPU specific setup/cleanup */
 int usb_board_stop(void);
 
@@ -25,64 +37,7 @@ int usb_cpu_init(void);
 int usb_cpu_stop(void);
 int usb_cpu_init_fail(void);
 
-static int cc_to_error[16] = {
-
-/* mapping of the OHCI CC status to error codes */
-	/* No  Error  */	       0,
-	/* CRC Error  */	       USB_ST_CRC_ERR,
-	/* Bit Stuff  */	       USB_ST_BIT_ERR,
-	/* Data Togg  */	       USB_ST_CRC_ERR,
-	/* Stall      */	       USB_ST_STALLED,
-	/* DevNotResp */	       -1,
-	/* PIDCheck   */	       USB_ST_BIT_ERR,
-	/* UnExpPID   */	       USB_ST_BIT_ERR,
-	/* DataOver   */	       USB_ST_BUF_ERR,
-	/* DataUnder  */	       USB_ST_BUF_ERR,
-	/* reservd    */	       -1,
-	/* reservd    */	       -1,
-	/* BufferOver */	       USB_ST_BUF_ERR,
-	/* BuffUnder  */	       USB_ST_BUF_ERR,
-	/* Not Access */	       -1,
-	/* Not Access */	       -1
-};
-
-static const char *cc_to_string[16] = {
-	"No Error",
-	"CRC: Last data packet from endpoint contained a CRC error.",
-	"BITSTUFFING: Last data packet from endpoint contained a bit " \
-		     "stuffing violation",
-	"DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
-		     "that did not match the expected value.",
-	"STALL: TD was moved to the Done Queue because the endpoint returned" \
-		     " a STALL PID",
-	"DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
-		     "not provide a handshake (OUT)",
-	"PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
-		     "(IN) or handshake (OUT)",
-	"UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
-		     "value is not defined.",
-	"DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
-		     "either the size of the maximum data packet allowed\n" \
-		     "from the endpoint (found in MaximumPacketSize field\n" \
-		     "of ED) or the remaining buffer size.",
-	"DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
-		     "and that amount was not sufficient to fill the\n" \
-		     "specified buffer",
-	"reserved1",
-	"reserved2",
-	"BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
-		     "than it could be written to system memory",
-	"BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
-		     "system memory fast enough to keep up with data USB " \
-		     "data rate.",
-	"NOT ACCESSED: This code is set by software before the TD is placed" \
-		     "on a list to be processed by the HC.(1)",
-	"NOT ACCESSED: This code is set by software before the TD is placed" \
-		     "on a list to be processed by the HC.(2)",
-};
-
 /* ED States */
-
 #define ED_NEW		0x00
 #define ED_UNLINK	0x01
 #define ED_OPER		0x02
@@ -109,7 +64,7 @@ struct ed {
 	struct usb_device *usb_dev;
 	void *purb;
 	__u32 unused[2];
-} __attribute__((aligned(16)));
+} __attribute__((aligned(ED_ALIGNMENT)));
 typedef struct ed ed_t;
 
 
@@ -169,7 +124,7 @@ struct td {
 	__u32 data;
 
 	__u32 unused2[2];
-} __attribute__((aligned(32)));
+} __attribute__((aligned(TD_ALIGNMENT)));
 typedef struct td td_t;
 
 #define OHCI_ED_SKIP	(1 << 14)
@@ -408,6 +363,16 @@ typedef struct
 } urb_priv_t;
 #define URB_DEL 1
 
+#define NUM_EDS 8		/* num of preallocated endpoint descriptors */
+
+#define NUM_TD 64		/* we need more TDs than EDs */
+
+typedef struct ohci_device {
+	ed_t ed[NUM_EDS] __aligned(ED_ALIGNMENT);
+	td_t tds[NUM_TD] __aligned(TD_ALIGNMENT);
+	int ed_cnt;
+} ohci_dev_t;
+
 /*
  * This is the full ohci controller description
  *
@@ -417,6 +382,8 @@ typedef struct
 
 
 typedef struct ohci {
+	/* this allocates EDs for all possible endpoints */
+	struct ohci_device ohci_dev __aligned(TD_ALIGNMENT);
 	struct ohci_hcca *hcca;		/* hcca */
 	/*dma_addr_t hcca_dma;*/
 
@@ -438,54 +405,3 @@ typedef struct ohci {
 
 	const char	*slot_name;
 } ohci_t;
-
-#define NUM_EDS 8		/* num of preallocated endpoint descriptors */
-
-struct ohci_device {
-	ed_t	ed[NUM_EDS];
-	int ed_cnt;
-};
-
-/* hcd */
-/* endpoint */
-static int ep_link(ohci_t * ohci, ed_t * ed);
-static int ep_unlink(ohci_t * ohci, ed_t * ed);
-static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe,
-		int interval, int load);
-
-/*-------------------------------------------------------------------------*/
-
-/* we need more TDs than EDs */
-#define NUM_TD 64
-
-/* +1 so we can align the storage */
-td_t gtd[NUM_TD+1];
-/* pointers to aligned storage */
-td_t *ptd;
-
-/* TDs ... */
-static inline struct td *
-td_alloc (struct usb_device *usb_dev)
-{
-	int i;
-	struct td	*td;
-
-	td = NULL;
-	for (i = 0; i < NUM_TD; i++)
-	{
-		if (ptd[i].usb_dev == NULL)
-		{
-			td = &ptd[i];
-			td->usb_dev = usb_dev;
-			break;
-		}
-	}
-
-	return td;
-}
-
-static inline void
-ed_free (struct ed *ed)
-{
-	ed->usb_dev = NULL;
-}
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 714bc0e9588fb99899d0c42fe8d5dc9c203baa7e..c5ece584070b123b999e7ca2b03ae05b3a7377d4 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -145,9 +145,8 @@ int usb_init(void)
 
 	uclass_foreach_dev(bus, uc) {
 		/* init low_level USB */
+		printf("USB%d:   ", count);
 		count++;
-		printf("USB");
-		printf("%d:   ", bus->seq);
 		ret = device_probe(bus);
 		if (ret == -ENODEV) {	/* No such device. */
 			puts("Port not available.\n");
@@ -477,9 +476,7 @@ int usb_scan_device(struct udevice *parent, int port,
 
 	*devp = NULL;
 	memset(udev, '\0', sizeof(*udev));
-	ret = usb_get_bus(parent, &udev->controller_dev);
-	if (ret)
-		return ret;
+	udev->controller_dev = usb_get_bus(parent);
 	priv = dev_get_uclass_priv(udev->controller_dev);
 
 	/*
@@ -536,11 +533,7 @@ int usb_scan_device(struct udevice *parent, int port,
 	plat = dev_get_parent_platdata(dev);
 	debug("%s: Probing '%s', plat=%p\n", __func__, dev->name, plat);
 	plat->devnum = udev->devnum;
-	plat->speed = udev->speed;
-	plat->slot_id = udev->slot_id;
-	plat->portnr = port;
-	debug("** device '%s': stashing slot_id=%d\n", dev->name,
-	      plat->slot_id);
+	plat->udev = udev;
 	priv->next_addr++;
 	ret = device_probe(dev);
 	if (ret) {
@@ -579,45 +572,55 @@ int usb_child_post_bind(struct udevice *dev)
 	return 0;
 }
 
-int usb_get_bus(struct udevice *dev, struct udevice **busp)
+struct udevice *usb_get_bus(struct udevice *dev)
 {
 	struct udevice *bus;
 
-	*busp = NULL;
 	for (bus = dev; bus && device_get_uclass_id(bus) != UCLASS_USB; )
 		bus = bus->parent;
 	if (!bus) {
 		/* By design this cannot happen */
 		assert(bus);
 		debug("USB HUB '%s' does not have a controller\n", dev->name);
-		return -EXDEV;
 	}
-	*busp = bus;
 
-	return 0;
+	return bus;
 }
 
 int usb_child_pre_probe(struct udevice *dev)
 {
-	struct udevice *bus;
 	struct usb_device *udev = dev_get_parentdata(dev);
 	struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
 	int ret;
 
-	ret = usb_get_bus(dev, &bus);
-	if (ret)
-		return ret;
-	udev->controller_dev = bus;
-	udev->dev = dev;
-	udev->devnum = plat->devnum;
-	udev->slot_id = plat->slot_id;
-	udev->portnr = plat->portnr;
-	udev->speed = plat->speed;
-	debug("** device '%s': getting slot_id=%d\n", dev->name, plat->slot_id);
-
-	ret = usb_select_config(udev);
-	if (ret)
-		return ret;
+	if (plat->udev) {
+		/*
+		 * Copy over all the values set in the on stack struct
+		 * usb_device in usb_scan_device() to our final struct
+		 * usb_device for this dev.
+		 */
+		*udev = *(plat->udev);
+		/* And clear plat->udev as it will not be valid for long */
+		plat->udev = NULL;
+		udev->dev = dev;
+	} else {
+		/*
+		 * This happens with devices which are explicitly bound
+		 * instead of being discovered through usb_scan_device()
+		 * such as sandbox emul devices.
+		 */
+		udev->dev = dev;
+		udev->controller_dev = usb_get_bus(dev);
+		udev->devnum = plat->devnum;
+
+		/*
+		 * udev did not go through usb_scan_device(), so we need to
+		 * select the config and read the config descriptors.
+		 */
+		ret = usb_select_config(udev);
+		if (ret)
+			return ret;
+	}
 
 	return 0;
 }
diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
index 23c7ecc5d8699714b83a9dabc8be59a8df4fc104..a27a79632b896aa1257dbfcc61d0b29bba687785 100644
--- a/drivers/usb/host/xhci-exynos5.c
+++ b/drivers/usb/host/xhci-exynos5.c
@@ -33,36 +33,24 @@
 /* Declare global data pointer */
 DECLARE_GLOBAL_DATA_PTR;
 
-#ifdef CONFIG_DM_USB
 struct exynos_xhci_platdata {
 	fdt_addr_t hcd_base;
 	fdt_addr_t phy_base;
 	struct gpio_desc vbus_gpio;
 };
-#endif
 
 /**
  * Contains pointers to register base addresses
  * for the usb controller.
  */
 struct exynos_xhci {
-#ifdef CONFIG_DM_USB
 	struct usb_platdata usb_plat;
-#endif
 	struct xhci_ctrl ctrl;
 	struct exynos_usb3_phy *usb3_phy;
 	struct xhci_hccr *hcd;
 	struct dwc3 *dwc3_reg;
-#ifndef CONFIG_DM_USB
-	struct gpio_desc vbus_gpio;
-#endif
 };
 
-#ifndef CONFIG_DM_USB
-static struct exynos_xhci exynos;
-#endif
-
-#ifdef CONFIG_DM_USB
 static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
 {
 	struct exynos_xhci_platdata *plat = dev_get_platdata(dev);
@@ -102,54 +90,6 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
 
 	return 0;
 }
-#else
-static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
-{
-	fdt_addr_t addr;
-	unsigned int node;
-	int depth;
-
-	node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_XHCI);
-	if (node <= 0) {
-		debug("XHCI: Can't get device node for xhci\n");
-		return -ENODEV;
-	}
-
-	/*
-	 * Get the base address for XHCI controller from the device node
-	 */
-	addr = fdtdec_get_addr(blob, node, "reg");
-	if (addr == FDT_ADDR_T_NONE) {
-		debug("Can't get the XHCI register base address\n");
-		return -ENXIO;
-	}
-	exynos->hcd = (struct xhci_hccr *)addr;
-
-	/* Vbus gpio */
-	gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
-				   &exynos->vbus_gpio, GPIOD_IS_OUT);
-
-	depth = 0;
-	node = fdtdec_next_compatible_subnode(blob, node,
-				COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth);
-	if (node <= 0) {
-		debug("XHCI: Can't get device node for usb3-phy controller\n");
-		return -ENODEV;
-	}
-
-	/*
-	 * Get the base address for usbphy from the device node
-	 */
-	exynos->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node,
-								"reg");
-	if (exynos->usb3_phy == NULL) {
-		debug("Can't get the usbphy register address\n");
-		return -ENXIO;
-	}
-
-	return 0;
-}
-#endif
 
 static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
 {
@@ -340,53 +280,6 @@ static void exynos_xhci_core_exit(struct exynos_xhci *exynos)
 	exynos5_usb3_phy_exit(exynos->usb3_phy);
 }
 
-#ifndef CONFIG_DM_USB
-int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
-{
-	struct exynos_xhci *ctx = &exynos;
-	int ret;
-
-#ifdef CONFIG_OF_CONTROL
-	exynos_usb3_parse_dt(gd->fdt_blob, ctx);
-#else
-	ctx->usb3_phy = (struct exynos_usb3_phy *)samsung_get_base_usb3_phy();
-	ctx->hcd = (struct xhci_hccr *)samsung_get_base_usb_xhci();
-#endif
-
-	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
-
-#ifdef CONFIG_OF_CONTROL
-	/* setup the Vbus gpio here */
-	if (dm_gpio_is_valid(&ctx->vbus_gpio))
-		dm_gpio_set_value(&ctx->vbus_gpio, 1);
-#endif
-
-	ret = exynos_xhci_core_init(ctx);
-	if (ret) {
-		puts("XHCI: failed to initialize controller\n");
-		return -EINVAL;
-	}
-
-	*hccr = (ctx->hcd);
-	*hcor = (struct xhci_hcor *)((uint32_t) *hccr
-				+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
-
-	debug("Exynos5-xhci: init hccr %x and hcor %x hc_length %d\n",
-		(uint32_t)*hccr, (uint32_t)*hcor,
-		(uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
-
-	return 0;
-}
-
-void xhci_hcd_stop(int index)
-{
-	struct exynos_xhci *ctx = &exynos;
-
-	exynos_xhci_core_exit(ctx);
-}
-#endif
-
-#ifdef CONFIG_DM_USB
 static int xhci_usb_probe(struct udevice *dev)
 {
 	struct exynos_xhci_platdata *plat = dev_get_platdata(dev);
@@ -443,4 +336,3 @@ U_BOOT_DRIVER(usb_xhci) = {
 	.priv_auto_alloc_size = sizeof(struct exynos_xhci),
 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
 };
-#endif
diff --git a/include/bcd.h b/include/bcd.h
index af4aa9c7baf8ace2f80e0a0ecb043d40d8b3f144..9ecd328284e9de20a293a96dff9bc655c6d529ea 100644
--- a/include/bcd.h
+++ b/include/bcd.h
@@ -10,14 +10,12 @@
 #ifndef _BCD_H
 #define _BCD_H
 
-#include <linux/types.h>
-
-static inline unsigned int bcd2bin(u8 val)
+static inline unsigned int bcd2bin(unsigned int val)
 {
-	return ((val) & 0x0f) + ((val) >> 4) * 10;
+	return ((val) & 0x0f) + ((val & 0xff) >> 4) * 10;
 }
 
-static inline u8 bin2bcd (unsigned int val)
+static inline unsigned int bin2bcd(unsigned int val)
 {
 	return (((val / 10) << 4) | (val % 10));
 }
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 3bf45a224d292747b7ddb8ba5cd9ebe0a26d1e40..f5361d1091b659d11b14e3a2f580fff003d48c18 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -125,6 +125,8 @@
 	func(HOST, host, 1) \
 	func(HOST, host, 0)
 
+#define CONFIG_BOOTCOMMAND ""
+
 #include <config_distro_bootcmd.h>
 
 #define CONFIG_KEEP_SERVERADDR
@@ -207,5 +209,6 @@
 
 #define CONFIG_CMD_LZMADEC
 #define CONFIG_CMD_USB
+#define CONFIG_CMD_DATE
 
 #endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 395e25a43135835821b4c72cffaea2588d9ea352..08f1bad938589c07bac088da19d181566bd8de7e 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -46,6 +46,7 @@ enum uclass_id {
 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
 	UCLASS_MASS_STORAGE,	/* Mass storage device */
 	UCLASS_CPU,		/* CPU, typically part of an SoC */
+	UCLASS_RTC,		/* Real time clock device */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 659047097a1001ca5f007e55b16343ddc214ca78..f11475b5fddf43fe75e27b58b57ceec4c78c78f0 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -145,8 +145,6 @@ enum fdt_compat_id {
 	COMPAT_SAMSUNG_EXYNOS5_SOUND,	/* Exynos Sound */
 	COMPAT_WOLFSON_WM8994_CODEC,	/* Wolfson WM8994 Sound Codec */
 	COMPAT_GOOGLE_CROS_EC_KEYB,	/* Google CROS_EC Keyboard */
-	COMPAT_SAMSUNG_EXYNOS_EHCI,	/* Exynos EHCI controller */
-	COMPAT_SAMSUNG_EXYNOS5_XHCI,	/* Exynos5 XHCI controller */
 	COMPAT_SAMSUNG_EXYNOS_USB_PHY,	/* Exynos phy controller for usb2.0 */
 	COMPAT_SAMSUNG_EXYNOS5_USB3_PHY,/* Exynos phy controller for usb3.0 */
 	COMPAT_SAMSUNG_EXYNOS_TMU,	/* Exynos TMU */
diff --git a/include/i2c.h b/include/i2c.h
index 6fd73fae4ccc01c3c1aa5a45023b04dd22e24b37..1e259861b7869efd7a327d1725f333af6fcb30a1 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -54,6 +54,7 @@ struct dm_i2c_chip {
 	uint flags;
 #ifdef CONFIG_SANDBOX
 	struct udevice *emul;
+	bool test_mode;
 #endif
 };
 
@@ -123,6 +124,27 @@ int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
 int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
 		 struct udevice **devp);
 
+/**
+ * dm_i2c_reg_read() - Read a value from an I2C register
+ *
+ * This reads a single value from the given address in an I2C chip
+ *
+ * @addr:	Address to read from
+ * @return value read, or -ve on error
+ */
+int dm_i2c_reg_read(struct udevice *dev, uint offset);
+
+/**
+ * dm_i2c_reg_write() - Write a value to an I2C register
+ *
+ * This writes a single value to the given address in an I2C chip
+ *
+ * @addr:	Address to write to
+ * @val:	Value to write (normally a byte)
+ * @return 0 on success, -ve on error
+ */
+int dm_i2c_reg_write(struct udevice *dev, uint offset, unsigned int val);
+
 /**
  * dm_i2c_set_bus_speed() - set the speed of a bus
  *
diff --git a/include/os.h b/include/os.h
index a758f099aab622f4aba9696de3213bbdc67a9843..ffbdce84643e0f593f8d6d684753b1b32af13447 100644
--- a/include/os.h
+++ b/include/os.h
@@ -13,6 +13,7 @@
 
 #include <linux/types.h>
 
+struct rtc_time;
 struct sandbox_state;
 
 /**
@@ -277,4 +278,14 @@ int os_read_ram_buf(const char *fname);
  */
 int os_jump_to_image(const void *dest, int size);
 
+/**
+ * Read the current system time
+ *
+ * This reads the current Local Time and places it into the provided
+ * structure.
+ *
+ * @param rt		Place to put system time
+ */
+void os_localtime(struct rtc_time *rt);
+
 #endif
diff --git a/include/rtc.h b/include/rtc.h
index 54e361ea5e83ee28593dddd8178a361b5e1b53f2..bd8621d60b93d4491d33ee477ccd04b7438c65a7 100644
--- a/include/rtc.h
+++ b/include/rtc.h
@@ -15,41 +15,143 @@
  * it there instead of in evey single driver */
 
 #include <bcd.h>
+#include <rtc_def.h>
 
-/*
- * The struct used to pass data from the generic interface code to
- * the hardware dependend low-level code ande vice versa. Identical
- * to struct rtc_time used by the Linux kernel.
- *
- * Note that there are small but significant differences to the
- * common "struct time":
- *
- *		struct time:		struct rtc_time:
- * tm_mon	0 ... 11		1 ... 12
- * tm_year	years since 1900	years since 0
- */
-
-struct rtc_time {
-	int tm_sec;
-	int tm_min;
-	int tm_hour;
-	int tm_mday;
-	int tm_mon;
-	int tm_year;
-	int tm_wday;
-	int tm_yday;
-	int tm_isdst;
+#ifdef CONFIG_DM_RTC
+
+struct rtc_ops {
+	/**
+	 * get() - get the current time
+	 *
+	 * Returns the current time read from the RTC device. The driver
+	 * is responsible for setting up every field in the structure.
+	 *
+	 * @dev:	Device to read from
+	 * @time:	Place to put the time that is read
+	 */
+	int (*get)(struct udevice *dev, struct rtc_time *time);
+
+	/**
+	 * set() - set the current time
+	 *
+	 * Sets the time in the RTC device. The driver can expect every
+	 * field to be set correctly.
+	 *
+	 * @dev:	Device to read from
+	 * @time:	Time to write
+	 */
+	int (*set)(struct udevice *dev, const struct rtc_time *time);
+
+	/**
+	 * reset() - reset the RTC to a known-good state
+	 *
+	 * This function resets the RTC to a known-good state. The time may
+	 * be unset by this method, so should be set after this method is
+	 * called.
+	 *
+	 * @dev:	Device to read from
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*reset)(struct udevice *dev);
+
+	/**
+	 * read8() - Read an 8-bit register
+	 *
+	 * @dev:	Device to read from
+	 * @reg:	Register to read
+	 * @return value read, or -ve on error
+	 */
+	int (*read8)(struct udevice *dev, unsigned int reg);
+
+	/**
+	* write8() - Write an 8-bit register
+	*
+	* @dev:		Device to write to
+	* @reg:		Register to write
+	* @value:	Value to write
+	* @return 0 if OK, -ve on error
+	*/
+	int (*write8)(struct udevice *dev, unsigned int reg, int val);
 };
 
+/* Access the operations for an RTC device */
+#define rtc_get_ops(dev)	((struct rtc_ops *)(dev)->driver->ops)
+
+/**
+ * dm_rtc_get() - Read the time from an RTC
+ *
+ * @dev:	Device to read from
+ * @time:	Place to put the current time
+ * @return 0 if OK, -ve on error
+ */
+int dm_rtc_get(struct udevice *dev, struct rtc_time *time);
+
+/**
+ * dm_rtc_put() - Write a time to an RTC
+ *
+ * @dev:	Device to read from
+ * @time:	Time to write into the RTC
+ * @return 0 if OK, -ve on error
+ */
+int dm_rtc_set(struct udevice *dev, struct rtc_time *time);
+
+/**
+ * dm_rtc_reset() - reset the RTC to a known-good state
+ *
+ * If the RTC appears to be broken (e.g. it is not counting up in seconds)
+ * it may need to be reset to a known good state. This function achieves this.
+ * After resetting the RTC the time should then be set to a known value by
+ * the caller.
+ *
+ * @dev:	Device to read from
+ * @return 0 if OK, -ve on error
+ */
+int dm_rtc_reset(struct udevice *dev);
+
+/**
+ * rtc_read8() - Read an 8-bit register
+ *
+ * @dev:	Device to read from
+ * @reg:	Register to read
+ * @return value read, or -ve on error
+ */
+int rtc_read8(struct udevice *dev, unsigned int reg);
+
+/**
+ * rtc_write8() - Write an 8-bit register
+ *
+ * @dev:	Device to write to
+ * @reg:	Register to write
+ * @value:	Value to write
+ * @return 0 if OK, -ve on error
+ */
+int rtc_write8(struct udevice *dev, unsigned int reg, int val);
+
+/**
+ * rtc_read32() - Read a 32-bit value from the RTC
+ *
+ * @dev:	Device to read from
+ * @reg:	Offset to start reading from
+ * @valuep:	Place to put the value that is read
+ * @return 0 if OK, -ve on error
+ */
+int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep);
+
+/**
+ * rtc_write32() - Write a 32-bit value to the RTC
+ *
+ * @dev:	Device to write to
+ * @reg:	Register to start writing to
+ * @value:	Value to write
+ * @return 0 if OK, -ve on error
+ */
+int rtc_write32(struct udevice *dev, unsigned int reg, u32 value);
+
+#else
 int rtc_get (struct rtc_time *);
 int rtc_set (struct rtc_time *);
 void rtc_reset (void);
 
-void GregorianDay (struct rtc_time *);
-void to_tm (int, struct rtc_time *);
-unsigned long mktime (unsigned int, unsigned int, unsigned int,
-		      unsigned int, unsigned int, unsigned int);
-
 /**
  * rtc_read8() - Read an 8-bit register
  *
@@ -86,5 +188,44 @@ void rtc_write32(int reg, u32 value);
  * rtc_init() - Set up the real time clock ready for use
  */
 void rtc_init(void);
+#endif
+
+/**
+ * rtc_calc_weekday() - Work out the weekday from a time
+ *
+ * This only works for the Gregorian calendar - i.e. after 1752 (in the UK).
+ * It sets time->tm_wdaay to the correct day of the week.
+ *
+ * @time:	Time to inspect. tm_wday is updated
+ * @return 0 if OK, -EINVAL if the weekday could not be determined
+ */
+int rtc_calc_weekday(struct rtc_time *time);
+
+/**
+ * rtc_to_tm() - Convert a time_t value into a broken-out time
+ *
+ * The following fields are set up by this function:
+ *	tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday
+ *
+ * Note that tm_yday and tm_isdst are set to 0.
+ *
+ * @time_t:	Number of seconds since 1970-01-01 00:00:00
+ * @time:	Place to put the broken-out time
+ * @return 0 if OK, -EINVAL if the weekday could not be determined
+ */
+int rtc_to_tm(int time_t, struct rtc_time *time);
+
+/**
+ * rtc_mktime() - Convert a broken-out time into a time_t value
+ *
+ * The following fields need to be valid for this function to work:
+ *	tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year
+ *
+ * Note that tm_wday and tm_yday are ignored.
+ *
+ * @time:	Broken-out time to convert
+ * @return corresponding time_t value, seconds since 1970-01-01 00:00:00
+ */
+unsigned long rtc_mktime(const struct rtc_time *time);
 
 #endif	/* _RTC_H_ */
diff --git a/include/rtc_def.h b/include/rtc_def.h
new file mode 100644
index 0000000000000000000000000000000000000000..61797972670cce1be4d04d4d1b339622bca15dd1
--- /dev/null
+++ b/include/rtc_def.h
@@ -0,0 +1,36 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __rtc_def_h
+#define __rtc_def_h
+
+/*
+ * The struct used to pass data from the generic interface code to
+ * the hardware dependend low-level code ande vice versa. Identical
+ * to struct rtc_time used by the Linux kernel.
+ *
+ * Note that there are small but significant differences to the
+ * common "struct time":
+ *
+ *		struct time:		struct rtc_time:
+ * tm_mon	0 ... 11		1 ... 12
+ * tm_year	years since 1900	years since 0
+ */
+
+struct rtc_time {
+	int tm_sec;
+	int tm_min;
+	int tm_hour;
+	int tm_mday;
+	int tm_mon;
+	int tm_year;
+	int tm_wday;
+	int tm_yday;
+	int tm_isdst;
+};
+
+#endif
diff --git a/include/spi.h b/include/spi.h
index 9495ca53c9b6649acd7e04879261eb40c4344d8e..f4b93e6a1398294d1364c17cbdf21b0047f6c25d 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -100,6 +100,8 @@ struct dm_spi_slave_platdata {
  * @dev:		SPI slave device
  * @max_hz:		Maximum speed for this slave
  * @mode:		SPI mode to use for this slave (see SPI mode flags)
+ * @speed:		Current bus speed. This is 0 until the bus is first
+ *			claimed.
  * @bus:		ID of the bus that the slave is attached to. For
  *			driver model this is the sequence number of the SPI
  *			bus (bus->seq) so does not need to be stored
@@ -117,6 +119,7 @@ struct spi_slave {
 #ifdef CONFIG_DM_SPI
 	struct udevice *dev;	/* struct spi_slave is dev->parentdata */
 	uint max_hz;
+	uint speed;
 	uint mode;
 #else
 	unsigned int bus;
@@ -613,7 +616,7 @@ int sandbox_spi_get_emul(struct sandbox_state *state,
 			 struct udevice *bus, struct udevice *slave,
 			 struct udevice **emulp);
 
-/* Access the serial operations for a device */
+/* Access the operations for a SPI device */
 #define spi_get_ops(dev)	((struct dm_spi_ops *)(dev)->driver->ops)
 #define spi_emul_get_ops(dev)	((struct dm_spi_emul_ops *)(dev)->driver->ops)
 #endif /* CONFIG_DM_SPI */
diff --git a/include/usb.h b/include/usb.h
index 1984e8f590c72743df72e86f7f99c6214d3b3f1f..4c210502031eb0585c863418380e640dfa65aa24 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -571,20 +571,23 @@ struct usb_platdata {
  * This is used by sandbox to provide emulation data also.
  *
  * @id:		ID used to match this device
- * @speed:	Stores the speed associated with a USB device
  * @devnum:	Device address on the USB bus
- * @slot_id:	USB3 slot ID, which is separate from the device address
- * @portnr:	Port number of this device on its parent hub, numbered from 1
- *		(0 mean this device is the root hub)
+ * @udev:	usb-uclass internal use only do NOT use
  * @strings:	List of descriptor strings (for sandbox emulation purposes)
  * @desc_list:	List of descriptors (for sandbox emulation purposes)
  */
 struct usb_dev_platdata {
 	struct usb_device_id id;
-	enum usb_device_speed speed;
 	int devnum;
-	int slot_id;
-	int portnr;	/* Hub port number, 1..n */
+	/*
+	 * This pointer is used to pass the usb_device used in usb_scan_device,
+	 * to get the usb descriptors before the driver is known, to the
+	 * actual udevice once the driver is known and the udevice is created.
+	 * This will be NULL except during probe, do NOT use.
+	 *
+	 * This should eventually go away.
+	 */
+	struct usb_device *udev;
 #ifdef CONFIG_SANDBOX
 	struct usb_string *strings;
 	/* NULL-terminated list of descriptor pointers */
@@ -742,11 +745,10 @@ int usb_scan_device(struct udevice *parent, int port,
  * will be a device with uclass UCLASS_USB.
  *
  * @dev:	Device to check
- * @busp:	Returns bus, or NULL if not found
- * @return 0 if OK, -EXDEV is somehow this bus does not have a controller (this
- *	indicates a critical error in the USB stack
+ * @return The bus, or NULL if not found (this indicates a critical error in
+ *	the USB stack
  */
-int usb_get_bus(struct udevice *dev, struct udevice **busp);
+struct udevice *usb_get_bus(struct udevice *dev);
 
 /**
  * usb_select_config() - Set up a device ready for use
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 80b897a21cd69a88ce5d3fe1398d23da11339f67..b76d9cad83fba04d67775cf7cd500d68e0a33fd0 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -44,8 +44,6 @@ static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
 	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
 	COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
-	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
-	COMPAT(SAMSUNG_EXYNOS5_XHCI, "samsung,exynos5250-xhci"),
 	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
 	COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"),
 	COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
diff --git a/net/sntp.c b/net/sntp.c
index 6422eef72ef2b694177115a7634364b1fd05b34b..9c8ee34a4ed7838ced1fa01eda84dcc1b9735bcf 100644
--- a/net/sntp.c
+++ b/net/sntp.c
@@ -7,6 +7,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <net.h>
 #include <rtc.h>
 
@@ -68,9 +69,20 @@ static void sntp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 	 */
 	memcpy(&seconds, &rpktp->transmit_timestamp, sizeof(ulong));
 
-	to_tm(ntohl(seconds) - 2208988800UL + net_ntp_time_offset, &tm);
+	rtc_to_tm(ntohl(seconds) - 2208988800UL + net_ntp_time_offset, &tm);
 #if defined(CONFIG_CMD_DATE)
+#  ifdef CONFIG_DM_RTC
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device(UCLASS_RTC, 0, &dev);
+	if (ret)
+		printf("SNTP: cannot find RTC: err=%d\n", ret);
+	else
+		dm_rtc_set(dev, &tm);
+#  else
 	rtc_set(&tm);
+#  endif
 #endif
 	printf("Date: %4d-%02d-%02d Time: %2d:%02d:%02d\n",
 	       tm.tm_year, tm.tm_mon, tm.tm_mday,
diff --git a/post/drivers/rtc.c b/post/drivers/rtc.c
index cd19f7568df39984e982c190d767276ee0a859af..c2e73917ec51141b20290fb3aa7249fccfc0d809 100644
--- a/post/drivers/rtc.c
+++ b/post/drivers/rtc.c
@@ -59,11 +59,10 @@ static int rtc_post_skip (ulong * diff)
 
 static void rtc_post_restore (struct rtc_time *tm, unsigned int sec)
 {
-	time_t t = mktime (tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
-					   tm->tm_min, tm->tm_sec) + sec;
+	time_t t = rtc_mktime(tm) + sec;
 	struct rtc_time ntm;
 
-	to_tm (t, &ntm);
+	rtc_to_tm(t, &ntm);
 
 	rtc_set (&ntm);
 }
@@ -116,10 +115,17 @@ int rtc_post_test (int flags)
 	rtc_get (&svtm);
 
 	for (i = 0; i < 12; i++) {
-		time_t t = mktime (ynl, i + 1, daysnl[i], 23, 59, 59);
+		time_t t;
 		struct rtc_time tm;
 
-		to_tm (t, &tm);
+		tm.tm_year = ynl;
+		tm.tm_mon = i + 1;
+		tm.tm_mday = daysnl[i];
+		tm.tm_hour = 23;
+		tm.tm_min = 59;
+		tm.tm_sec = 59;
+		t = rtc_mktime(&tm);
+		rtc_to_tm(t, &tm);
 		rtc_set (&tm);
 
 		skipped++;
@@ -140,10 +146,18 @@ int rtc_post_test (int flags)
 	}
 
 	for (i = 0; i < 12; i++) {
-		time_t t = mktime (yl, i + 1, daysl[i], 23, 59, 59);
+		time_t t;
 		struct rtc_time tm;
 
-		to_tm (t, &tm);
+		tm.tm_year = yl;
+		tm.tm_mon = i + 1;
+		tm.tm_mday = daysl[i];
+		tm.tm_hour = 23;
+		tm.tm_min = 59;
+		tm.tm_sec = 59;
+		t = rtc_mktime(&tm);
+
+		rtc_to_tm(t, &tm);
 		rtc_set (&tm);
 
 		skipped++;
diff --git a/test/Kconfig b/test/Kconfig
index 1fb1716a4ad59196742f0fbb18b81ee8723c6ba4..3270c84213b033fc666b52d990228f0ce9dc85e1 100644
--- a/test/Kconfig
+++ b/test/Kconfig
@@ -1 +1,9 @@
+config CMD_UT_TIME
+	bool "Unit tests for time functions"
+	help
+	  Enables the 'ut_time' command which tests that the time functions
+	  work correctly. The test is fairly simple and will not catch all
+	  problems. But if you are having problems with udelay() and the like,
+	  this is a good place to start.
+
 source "test/dm/Kconfig"
diff --git a/test/Makefile b/test/Makefile
index 9c95805c44e06e2f8230635adc0773033ef6b70f..08330e020c5d3450ebc5d549bf98c62459cdcdd9 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -6,3 +6,4 @@
 
 obj-$(CONFIG_SANDBOX) += command_ut.o
 obj-$(CONFIG_SANDBOX) += compression.o
+obj-$(CONFIG_CMD_UT_TIME) += time_ut.o
diff --git a/test/dm/Makefile b/test/dm/Makefile
index fd9e29f201c468b58da41648219f2b31287739ac..a0cc2c6de5f903a0a7a8e03862e174ab863f5157 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_DM_ETH) += eth.o
 obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_I2C) += i2c.o
 obj-$(CONFIG_DM_PCI) += pci.o
+obj-$(CONFIG_DM_RTC) += rtc.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 obj-$(CONFIG_DM_SPI) += spi.o
 obj-$(CONFIG_DM_USB) += usb.o
diff --git a/test/dm/eth.c b/test/dm/eth.c
index 4891f3ad34f7eb028fed60831c31e62a15520417..196eba85a2bbc860ce3ded5bf94ed1c7a7f4305b 100644
--- a/test/dm/eth.c
+++ b/test/dm/eth.c
@@ -135,6 +135,7 @@ static int dm_test_net_retry(struct dm_test_state *dms)
 	sandbox_eth_disable_response(1, true);
 	setenv("ethact", "eth@10004000");
 	setenv("netretry", "yes");
+	sandbox_eth_skip_timeout();
 	ut_assertok(net_loop(PING));
 	ut_asserteq_str("eth@10002000", getenv("ethact"));
 
@@ -144,6 +145,7 @@ static int dm_test_net_retry(struct dm_test_state *dms)
 	 */
 	setenv("ethact", "eth@10004000");
 	setenv("netretry", "no");
+	sandbox_eth_skip_timeout();
 	ut_asserteq(-ETIMEDOUT, net_loop(PING));
 	ut_asserteq_str("eth@10004000", getenv("ethact"));
 
diff --git a/test/dm/i2c.c b/test/dm/i2c.c
index 541b73b8037e0134078cb0817abcf5d202d54c87..c5939a165e90155d1c528fcdc94e2f285f085410 100644
--- a/test/dm/i2c.c
+++ b/test/dm/i2c.c
@@ -66,6 +66,9 @@ static int dm_test_i2c_speed(struct dm_test_state *dms)
 	uint8_t buf[5];
 
 	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+
+	/* Use test mode so we create the required errors for invalid speeds */
+	sandbox_i2c_set_test_mode(bus, true);
 	ut_assertok(i2c_get_chip(bus, chip, 1, &dev));
 	ut_assertok(dm_i2c_set_bus_speed(bus, 100000));
 	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
@@ -73,6 +76,7 @@ static int dm_test_i2c_speed(struct dm_test_state *dms)
 	ut_asserteq(400000, dm_i2c_get_bus_speed(bus));
 	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_asserteq(-EINVAL, dm_i2c_write(dev, 0, buf, 5));
+	sandbox_i2c_set_test_mode(bus, false);
 
 	return 0;
 }
@@ -100,7 +104,11 @@ static int dm_test_i2c_probe_empty(struct dm_test_state *dms)
 	struct udevice *bus, *dev;
 
 	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+
+	/* Use test mode so that this chip address will always probe */
+	sandbox_i2c_set_test_mode(bus, true);
 	ut_assertok(dm_i2c_probe(bus, SANDBOX_I2C_TEST_ADDR, 0, &dev));
+	sandbox_i2c_set_test_mode(bus, false);
 
 	return 0;
 }
diff --git a/test/dm/rtc.c b/test/dm/rtc.c
new file mode 100644
index 0000000000000000000000000000000000000000..9397cf72a731536f8efc20024c7434a6853a6dc7
--- /dev/null
+++ b/test/dm/rtc.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <dm/test.h>
+#include <dm/ut.h>
+#include <asm/test.h>
+
+/* Simple RTC sanity check */
+static int dm_test_rtc_base(struct dm_test_state *dms)
+{
+	struct udevice *dev;
+
+	ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_RTC, 2, &dev));
+	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
+	ut_assertok(uclass_get_device(UCLASS_RTC, 1, &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_rtc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static void show_time(const char *msg, struct rtc_time *time)
+{
+	printf("%s: %02d/%02d/%04d %02d:%02d:%02d\n", msg,
+	       time->tm_mday, time->tm_mon, time->tm_year,
+	       time->tm_hour, time->tm_min, time->tm_sec);
+}
+
+static int cmp_times(struct rtc_time *expect, struct rtc_time *time, bool show)
+{
+	bool same;
+
+	same = expect->tm_sec == time->tm_sec;
+	same &= expect->tm_min == time->tm_min;
+	same &= expect->tm_hour == time->tm_hour;
+	same &= expect->tm_mday == time->tm_mday;
+	same &= expect->tm_mon == time->tm_mon;
+	same &= expect->tm_year == time->tm_year;
+	if (!same && show) {
+		show_time("expected", expect);
+		show_time("actual", time);
+	}
+
+	return same ? 0 : -EINVAL;
+}
+
+/* Set and get the time */
+static int dm_test_rtc_set_get(struct dm_test_state *dms)
+{
+	struct rtc_time now, time, cmp;
+	struct udevice *dev, *emul;
+	long offset, old_offset, old_base_time;
+
+	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
+	ut_assertok(dm_rtc_get(dev, &now));
+
+	ut_assertok(device_find_first_child(dev, &emul));
+	ut_assert(emul != NULL);
+
+	/* Tell the RTC to go into manual mode */
+	old_offset = sandbox_i2c_rtc_set_offset(emul, false, 0);
+	old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
+
+	memset(&time, '\0', sizeof(time));
+	time.tm_mday = 25;
+	time.tm_mon = 8;
+	time.tm_year = 2004;
+	time.tm_sec = 0;
+	time.tm_min = 18;
+	time.tm_hour = 18;
+	ut_assertok(dm_rtc_set(dev, &time));
+
+	memset(&cmp, '\0', sizeof(cmp));
+	ut_assertok(dm_rtc_get(dev, &cmp));
+	ut_assertok(cmp_times(&time, &cmp, true));
+
+	/* Increment by 1 second */
+	offset = sandbox_i2c_rtc_set_offset(emul, false, 0);
+	sandbox_i2c_rtc_set_offset(emul, false, offset + 1);
+
+	memset(&cmp, '\0', sizeof(cmp));
+	ut_assertok(dm_rtc_get(dev, &cmp));
+	ut_asserteq(1, cmp.tm_sec);
+
+	/* Check against original offset */
+	sandbox_i2c_rtc_set_offset(emul, false, old_offset);
+	ut_assertok(dm_rtc_get(dev, &cmp));
+	ut_assertok(cmp_times(&now, &cmp, true));
+
+	/* Back to the original offset */
+	sandbox_i2c_rtc_set_offset(emul, false, 0);
+	memset(&cmp, '\0', sizeof(cmp));
+	ut_assertok(dm_rtc_get(dev, &cmp));
+	ut_assertok(cmp_times(&now, &cmp, true));
+
+	/* Increment the base time by 1 emul */
+	sandbox_i2c_rtc_get_set_base_time(emul, old_base_time + 1);
+	memset(&cmp, '\0', sizeof(cmp));
+	ut_assertok(dm_rtc_get(dev, &cmp));
+	if (now.tm_sec == 59) {
+		ut_asserteq(0, cmp.tm_sec);
+	} else {
+		ut_asserteq(now.tm_sec + 1, cmp.tm_sec);
+	}
+
+	old_offset = sandbox_i2c_rtc_set_offset(emul, true, 0);
+
+	return 0;
+}
+DM_TEST(dm_test_rtc_set_get, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Reset the time */
+static int dm_test_rtc_reset(struct dm_test_state *dms)
+{
+	struct rtc_time now;
+	struct udevice *dev, *emul;
+	long old_base_time, base_time;
+
+	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
+	ut_assertok(dm_rtc_get(dev, &now));
+
+	ut_assertok(device_find_first_child(dev, &emul));
+	ut_assert(emul != NULL);
+
+	old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, 0);
+
+	ut_asserteq(0, sandbox_i2c_rtc_get_set_base_time(emul, -1));
+
+	/* Resetting the RTC should put he base time back to normal */
+	ut_assertok(dm_rtc_reset(dev));
+	base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
+	ut_asserteq(old_base_time, base_time);
+
+	return 0;
+}
+DM_TEST(dm_test_rtc_reset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Check that two RTC devices can be used independently */
+static int dm_test_rtc_dual(struct dm_test_state *dms)
+{
+	struct rtc_time now1, now2, cmp;
+	struct udevice *dev1, *dev2;
+	struct udevice *emul1, *emul2;
+	long offset;
+
+	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev1));
+	ut_assertok(dm_rtc_get(dev1, &now1));
+	ut_assertok(uclass_get_device(UCLASS_RTC, 1, &dev2));
+	ut_assertok(dm_rtc_get(dev2, &now2));
+
+	ut_assertok(device_find_first_child(dev1, &emul1));
+	ut_assert(emul1 != NULL);
+	ut_assertok(device_find_first_child(dev2, &emul2));
+	ut_assert(emul2 != NULL);
+
+	offset = sandbox_i2c_rtc_set_offset(emul1, false, -1);
+	sandbox_i2c_rtc_set_offset(emul2, false, offset + 1);
+	memset(&cmp, '\0', sizeof(cmp));
+	ut_assertok(dm_rtc_get(dev2, &cmp));
+	ut_asserteq(-EINVAL, cmp_times(&now1, &cmp, false));
+
+	memset(&cmp, '\0', sizeof(cmp));
+	ut_assertok(dm_rtc_get(dev1, &cmp));
+	ut_assertok(cmp_times(&now1, &cmp, true));
+
+	return 0;
+}
+DM_TEST(dm_test_rtc_dual, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test.dts b/test/dm/test.dts
index d0c40be6b0ad69cc641ba3d56477db5eb3eaa09c..008584865c0592705f8c318fdece12ce6adf1280 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -8,18 +8,20 @@
 
 	aliases {
 		console = &uart0;
+		eth0 = "/eth@10002000";
+		eth5 = &eth_5;
 		i2c0 = "/i2c@0";
-		spi0 = "/spi@0";
 		pci0 = &pci;
-		testfdt6 = "/e-test";
+		spi0 = "/spi@0";
 		testbus3 = "/some-bus";
 		testfdt0 = "/some-bus/c-test@0";
 		testfdt1 = "/some-bus/c-test@1";
 		testfdt3 = "/b-test";
 		testfdt5 = "/some-bus/c-test@5";
+		testfdt6 = "/e-test";
 		testfdt8 = "/a-test";
-		eth0 = "/eth@10002000";
-		eth5 = &eth_5;
+		rtc0 = &rtc_0;
+		rtc1 = &rtc_1;
 		usb0 = &usb_0;
 		usb1 = &usb_1;
 		usb2 = &usb_2;
@@ -139,6 +141,22 @@
 				sandbox,size = <256>;
 			};
 		};
+
+		rtc_0: rtc@43 {
+			reg = <0x43>;
+			compatible = "sandbox-rtc";
+			emul {
+				compatible = "sandbox,i2c-rtc";
+			};
+		};
+
+		rtc_1: rtc@61 {
+			reg = <0x61>;
+			compatible = "sandbox-rtc";
+			emul {
+				compatible = "sandbox,i2c-rtc";
+			};
+		};
 	};
 
 	pci: pci-controller {
diff --git a/test/time_ut.c b/test/time_ut.c
new file mode 100644
index 0000000000000000000000000000000000000000..6b52245d7ffa55f9b3c453d2a078c2da93c67a01
--- /dev/null
+++ b/test/time_ut.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+
+static int test_get_timer(void)
+{
+	ulong base, start, next, diff;
+	int iter;
+
+	base = get_timer(0);
+	start = get_timer(0);
+	for (iter = 0; iter < 10; iter++) {
+		do {
+			next = get_timer(0);
+		} while (start == next);
+
+		if (start + 1 != next) {
+			printf("%s: iter=%d, start=%lu, next=%lu, expected a difference of 1\n",
+			       __func__, iter, start, next);
+			return -EINVAL;
+		}
+		start++;
+	}
+
+	/*
+	 * Check that get_timer(base) matches our elapsed time, allowing that
+	 * an extra millisecond may have passed.
+	 */
+	diff = get_timer(base);
+	if (diff != iter && diff != iter + 1) {
+		printf("%s: expected get_timer(base) to match elapsed time: diff=%lu, expected=%d\n",
+		       __func__, diff, iter);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int test_timer_get_us(void)
+{
+	ulong prev, next, min = 1000000;
+	long delta;
+	int iter;
+
+	/* Find the minimum delta we can measure, in microseconds */
+	prev = timer_get_us();
+	for (iter = 0; iter < 100; ) {
+		next = timer_get_us();
+		if (next != prev) {
+			delta = next - prev;
+			if (delta < 0) {
+				printf("%s: timer_get_us() went backwards from %lu to %lu\n",
+				       __func__, prev, next);
+				return -EINVAL;
+			} else if (delta != 0) {
+				if (delta < min)
+					min = delta;
+				prev = next;
+				iter++;
+			}
+		}
+	}
+
+	if (min != 1) {
+		printf("%s: Minimum microsecond delta should be 1 but is %lu\n",
+		       __func__, min);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int test_time_comparison(void)
+{
+	ulong start_us, end_us, delta_us;
+	long error;
+	ulong start;
+
+	start = get_timer(0);
+	start_us = timer_get_us();
+	while (get_timer(start) < 1000)
+		;
+	end_us = timer_get_us();
+	delta_us = end_us - start_us;
+	error = delta_us - 1000000;
+	printf("%s: Microsecond time for 1 second: %lu, error = %ld\n",
+	       __func__, delta_us, error);
+	if (abs(error) > 1000)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int test_udelay(void)
+{
+	long error;
+	ulong start, delta;
+	int iter;
+
+	start = get_timer(0);
+	for (iter = 0; iter < 1000; iter++)
+		udelay(1000);
+	delta = get_timer(start);
+	error = delta - 1000;
+	printf("%s: Delay time for 1000 udelay(1000): %lu ms, error = %ld\n",
+	       __func__, delta, error);
+	if (abs(error) > 100)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int ret = 0;
+
+	ret |= test_get_timer();
+	ret |= test_timer_get_us();
+	ret |= test_time_comparison();
+	ret |= test_udelay();
+
+	printf("Test %s\n", ret ? "failed" : "passed");
+
+	return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+	ut_time,	1,	1,	do_ut_time,
+	"Very basic test of time functions",
+	""
+);