Merge branch 'master' of http://git.denx.de/u-boot-sunxi
diff --git a/Kconfig b/Kconfig
index 3ceff25..ef12f9f 100644
--- a/Kconfig
+++ b/Kconfig
@@ -114,6 +114,15 @@
 	  Warning:
 	  When disabling this, please check if malloc calls, maybe
 	  should be replaced by calloc - if one expects zeroed memory.
+
+config TOOLS_DEBUG
+	bool "Enable debug information for tools"
+	help
+	  Enable generation of debug information for tools such as mkimage.
+	  This can be used for debugging purposes. With debug information
+	  it is possible to set breakpoints on particular lines, single-step
+	  debug through the source code, etc.
+
 endif
 endmenu		# General setup
 
@@ -313,6 +322,20 @@
 	  particular it can handle selecting from multiple device tree
 	  and passing the correct one to U-Boot.
 
+config SPL_FIT_IMAGE_POST_PROCESS
+	bool "Enable post-processing of FIT artifacts after loading by the SPL"
+	depends on SPL_LOAD_FIT && TI_SECURE_DEVICE
+	help
+	  Allows doing any sort of manipulation to blobs after they got extracted
+	  from the U-Boot FIT image like stripping off headers or modifying the
+	  size of the blob, verification, authentication, decryption etc. in a
+	  platform or board specific way. In order to use this feature a platform
+	  or board-specific implementation of board_fit_image_post_process() must
+	  be provided. Also, anything done during this post-processing step would
+	  need to be comprehended in how the images were prepared before being
+	  injected into the FIT creation (i.e. the blobs would have been pre-
+	  processed before being added to the FIT image).
+
 config SYS_CLK_FREQ
 	depends on ARC || ARCH_SUNXI
 	int "CPU clock frequency"
diff --git a/Makefile b/Makefile
index 88128ec..7ce933c 100644
--- a/Makefile
+++ b/Makefile
@@ -256,7 +256,8 @@
 
 HOSTCC       = cc
 HOSTCXX      = c++
-HOSTCFLAGS   = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+HOSTCFLAGS   = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer \
+		$(if $(CONFIG_TOOLS_DEBUG),-g)
 HOSTCXXFLAGS = -O2
 
 ifeq ($(HOSTOS),cygwin)
@@ -801,7 +802,7 @@
 cmd_pad_cat = $(cmd_objcopy) && $(append) || rm -f $@
 
 all:		$(ALL-y)
-ifeq ($(CONFIG_DM_I2C_COMPAT),y)
+ifeq ($(CONFIG_DM_I2C_COMPAT)$(CONFIG_SANDBOX),y)
 	@echo "===================== WARNING ======================"
 	@echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove"
 	@echo "(possibly in a subsequent patch in your series)"
@@ -1318,7 +1319,8 @@
 
 spl/u-boot-spl.bin: spl/u-boot-spl
 	@:
-spl/u-boot-spl: tools prepare $(if $(CONFIG_OF_SEPARATE),dts/dt.dtb)
+spl/u-boot-spl: tools prepare \
+		$(if $(CONFIG_OF_SEPARATE)$(CONFIG_SPL_OF_PLATDATA),dts/dt.dtb)
 	$(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
 
 spl/sunxi-spl.bin: spl/u-boot-spl
diff --git a/README b/README
index 26d5ad2..e906253 100644
--- a/README
+++ b/README
@@ -3835,9 +3835,6 @@
 		The memory will be freed (or in fact just forgotten) when
 		U-Boot relocates itself.
 
-		Pre-relocation malloc() is only supported on ARM and sandbox
-		at present but is fairly easy to enable for other archs.
-
 - CONFIG_SYS_MALLOC_SIMPLE
 		Provides a simple and small malloc() and calloc() for those
 		boards which do not use the full malloc in SPL (which is
diff --git a/arch/Kconfig b/arch/Kconfig
index c43787c..92d4b97 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1,6 +1,9 @@
 config CREATE_ARCH_SYMLINK
 	bool
 
+config HAVE_ARCH_IOREMAP
+	bool
+
 choice
 	prompt "Architecture select"
 	default SANDBOX
@@ -33,6 +36,7 @@
 
 config MIPS
 	bool "MIPS architecture"
+	select HAVE_ARCH_IOREMAP
 	select HAVE_PRIVATE_LIBGCC
 	select SUPPORT_OF_CONTROL
 
diff --git a/arch/arm/cpu/arm11/cpu.c b/arch/arm/cpu/arm11/cpu.c
index 1e4c214..7244c2e 100644
--- a/arch/arm/cpu/arm11/cpu.c
+++ b/arch/arm/cpu/arm11/cpu.c
@@ -69,23 +69,6 @@
 	asm volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
 }
 
-static int check_cache_range(unsigned long start, unsigned long stop)
-{
-	int ok = 1;
-
-	if (start & (CONFIG_SYS_CACHELINE_SIZE - 1))
-		ok = 0;
-
-	if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1))
-		ok = 0;
-
-	if (!ok)
-		debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n",
-			start, stop);
-
-	return ok;
-}
-
 void invalidate_dcache_range(unsigned long start, unsigned long stop)
 {
 	if (!check_cache_range(start, stop))
diff --git a/arch/arm/cpu/arm926ejs/cache.c b/arch/arm/cpu/arm926ejs/cache.c
index 2839c86..2119382 100644
--- a/arch/arm/cpu/arm926ejs/cache.c
+++ b/arch/arm/cpu/arm926ejs/cache.c
@@ -29,23 +29,6 @@
 	);
 }
 
-static int check_cache_range(unsigned long start, unsigned long stop)
-{
-	int ok = 1;
-
-	if (start & (CONFIG_SYS_CACHELINE_SIZE - 1))
-		ok = 0;
-
-	if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1))
-		ok = 0;
-
-	if (!ok)
-		debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n",
-			start, stop);
-
-	return ok;
-}
-
 void invalidate_dcache_range(unsigned long start, unsigned long stop)
 {
 	if (!check_cache_range(start, stop))
diff --git a/arch/arm/cpu/armv7/am33xx/config.mk b/arch/arm/cpu/armv7/am33xx/config.mk
index 6d95d32..ab94708 100644
--- a/arch/arm/cpu/armv7/am33xx/config.mk
+++ b/arch/arm/cpu/armv7/am33xx/config.mk
@@ -26,6 +26,7 @@
 else
 ifeq ($(CONFIG_TI_SECURE_DEVICE),y)
 ALL-$(CONFIG_QSPI_BOOT) += u-boot_HS_XIP_X-LOADER
+ALL-y	+= u-boot_HS.img
 endif
 ALL-y	+= u-boot.img
 endif
diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c
index dc309da..52f1856 100644
--- a/arch/arm/cpu/armv7/cache_v7.c
+++ b/arch/arm/cpu/armv7/cache_v7.c
@@ -19,23 +19,6 @@
 void v7_flush_dcache_all(void);
 void v7_invalidate_dcache_all(void);
 
-static int check_cache_range(unsigned long start, unsigned long stop)
-{
-	int ok = 1;
-
-	if (start & (CONFIG_SYS_CACHELINE_SIZE - 1))
-		ok = 0;
-
-	if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1))
-		ok = 0;
-
-	if (!ok)
-		debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n",
-			start, stop);
-
-	return ok;
-}
-
 static u32 get_ccsidr(void)
 {
 	u32 ccsidr;
@@ -61,27 +44,8 @@
 {
 	u32 mva;
 
-	/*
-	 * If start address is not aligned to cache-line do not
-	 * invalidate the first cache-line
-	 */
-	if (start & (line_len - 1)) {
-		printf("ERROR: %s - start address is not aligned - 0x%08x\n",
-			__func__, start);
-		/* move to next cache line */
-		start = (start + line_len - 1) & ~(line_len - 1);
-	}
-
-	/*
-	 * If stop address is not aligned to cache-line do not
-	 * invalidate the last cache-line
-	 */
-	if (stop & (line_len - 1)) {
-		printf("ERROR: %s - stop address is not aligned - 0x%08x\n",
-			__func__, stop);
-		/* align to the beginning of this cache line */
-		stop &= ~(line_len - 1);
-	}
+	if (!check_cache_range(start, stop))
+		return;
 
 	for (mva = start; mva < stop; mva = mva + line_len) {
 		/* DCIMVAC - Invalidate data cache by MVA to PoC */
@@ -195,6 +159,14 @@
 {
 }
 
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
 void arm_init_before_mmu(void)
 {
 }
diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile
index 87a7ac0..3172bae 100644
--- a/arch/arm/cpu/armv7/omap-common/Makefile
+++ b/arch/arm/cpu/armv7/omap-common/Makefile
@@ -36,3 +36,5 @@
 obj-y	+= lowlevel_init.o
 
 obj-y	+= mem-common.o
+
+obj-$(CONFIG_TI_SECURE_DEVICE) += sec-common.o
diff --git a/arch/arm/cpu/armv7/omap-common/config_secure.mk b/arch/arm/cpu/armv7/omap-common/config_secure.mk
index c7bb101..1122439 100644
--- a/arch/arm/cpu/armv7/omap-common/config_secure.mk
+++ b/arch/arm/cpu/armv7/omap-common/config_secure.mk
@@ -12,8 +12,8 @@
 	$(if $(KBUILD_VERBOSE:1=), >/dev/null)
 else
 cmd_mkomapsecimg = $(TI_SECURE_DEV_PKG)/scripts/create-boot-image.sh \
-    $(patsubst u-boot_HS_%,%,$(@F)) $< $@ $(CONFIG_ISW_ENTRY_ADDR) \
-    $(if $(KBUILD_VERBOSE:1=), >/dev/null)
+	$(patsubst u-boot_HS_%,%,$(@F)) $< $@ $(CONFIG_ISW_ENTRY_ADDR) \
+	$(if $(KBUILD_VERBOSE:1=), >/dev/null)
 endif
 else
 cmd_mkomapsecimg = echo "WARNING:" \
@@ -25,14 +25,33 @@
 	"variable must be defined for TI secure devices. $@ was NOT created!"
 endif
 
+ifdef CONFIG_SPL_LOAD_FIT
+quiet_cmd_omapsecureimg = SECURE  $@
+ifneq ($(TI_SECURE_DEV_PKG),)
+ifneq ($(wildcard $(TI_SECURE_DEV_PKG)/scripts/secure-binary-image.sh),)
+cmd_omapsecureimg = $(TI_SECURE_DEV_PKG)/scripts/secure-binary-image.sh \
+	$< $@ \
+	$(if $(KBUILD_VERBOSE:1=), >/dev/null)
+else
+cmd_omapsecureimg = echo "WARNING:" \
+	"$(TI_SECURE_DEV_PKG)/scripts/secure-binary-image.sh not found." \
+	"$@ was NOT created!"; cp $< $@
+endif
+else
+cmd_omapsecureimg = echo "WARNING: TI_SECURE_DEV_PKG environment" \
+	"variable must be defined for TI secure devices." \
+	"$@ was NOT created!"; cp $< $@
+endif
+endif
+
+
 # Standard X-LOADER target (QPSI, NOR flash)
 u-boot-spl_HS_X-LOADER: $(obj)/u-boot-spl.bin
 	$(call if_changed,mkomapsecimg)
 
-# For MLO targets (SD card boot) the final file name
-# that is copied to the SD card fAT partition must
-# be MLO, so we make a copy of the output file to a
-# new file with that name
+# For MLO targets (SD card boot) the final file name that is copied to the SD
+# card FAT partition must be MLO, so we make a copy of the output file to a new
+# file with that name
 u-boot-spl_HS_MLO: $(obj)/u-boot-spl.bin
 	$(call if_changed,mkomapsecimg)
 	@if [ -f $@ ]; then \
@@ -51,16 +70,44 @@
 u-boot-spl_HS_ISSW: $(obj)/u-boot-spl.bin
 	$(call if_changed,mkomapsecimg)
 
-# For SPI flash on AM335x and AM43xx, these
-# require special byte swap handling so we use
-# the SPI_X-LOADER target instead of X-LOADER
-# and let the create-boot-image.sh script handle
-# that
+# For SPI flash on AM335x and AM43xx, these require special byte swap handling
+# so we use the SPI_X-LOADER target instead of X-LOADER and let the
+# create-boot-image.sh script handle that
 u-boot-spl_HS_SPI_X-LOADER: $(obj)/u-boot-spl.bin
 	$(call if_changed,mkomapsecimg)
 
-# For supporting single stage XiP QSPI on AM43xx, the
-# image is a full u-boot file, not an SPL. In this case
-# the mkomapsecimg command looks for a u-boot-HS_* prefix
+# For supporting single stage XiP QSPI on AM43xx, the image is a full u-boot
+# file, not an SPL. In this case the mkomapsecimg command looks for a
+# u-boot-HS_* prefix
 u-boot_HS_XIP_X-LOADER: $(obj)/u-boot.bin
 	$(call if_changed,mkomapsecimg)
+
+# For supporting the SPL loading and interpreting of FIT images whose
+# components are pre-processed before being integrated into the FIT image in
+# order to secure them in some way
+ifdef CONFIG_SPL_LOAD_FIT
+
+MKIMAGEFLAGS_u-boot_HS.img = -f auto -A $(ARCH) -T firmware -C none -O u-boot \
+	-a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_UBOOT_START) \
+	-n "U-Boot $(UBOOTRELEASE) for $(BOARD) board" -E \
+	$(patsubst %,-b arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST)))
+
+OF_LIST_TARGETS = $(patsubst %,arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST)))
+$(OF_LIST_TARGETS): dtbs
+
+%_HS.dtb: %.dtb
+	$(call if_changed,omapsecureimg)
+	$(Q)if [ -f $@ ]; then \
+		cp -f $@ $<; \
+	fi
+
+u-boot-nodtb_HS.bin: u-boot-nodtb.bin
+	$(call if_changed,omapsecureimg)
+
+u-boot_HS.img: u-boot-nodtb_HS.bin u-boot.img $(patsubst %.dtb,%_HS.dtb,$(OF_LIST_TARGETS))
+	$(call if_changed,mkimage)
+	$(Q)if [ -f $@ ]; then \
+		cp -f $@ u-boot.img; \
+	fi
+
+endif
diff --git a/arch/arm/cpu/armv7/omap-common/emif-common.c b/arch/arm/cpu/armv7/omap-common/emif-common.c
index 9a9c764..2b79010 100644
--- a/arch/arm/cpu/armv7/omap-common/emif-common.c
+++ b/arch/arm/cpu/armv7/omap-common/emif-common.c
@@ -37,7 +37,8 @@
 void force_emif_self_refresh()
 {
 	set_lpmode_selfrefresh(EMIF1_BASE);
-	set_lpmode_selfrefresh(EMIF2_BASE);
+	if (!is_dra72x())
+		set_lpmode_selfrefresh(EMIF2_BASE);
 }
 
 inline u32 emif_num(u32 base)
diff --git a/arch/arm/cpu/armv7/omap-common/hwinit-common.c b/arch/arm/cpu/armv7/omap-common/hwinit-common.c
index 2f9693f..f317293 100644
--- a/arch/arm/cpu/armv7/omap-common/hwinit-common.c
+++ b/arch/arm/cpu/armv7/omap-common/hwinit-common.c
@@ -147,8 +147,7 @@
 	hw_data_init();
 
 #ifdef CONFIG_SPL_BUILD
-	if (warm_reset() &&
-	    (is_omap44xx() || (omap_revision() == OMAP5430_ES1_0)))
+	if (warm_reset())
 		force_emif_self_refresh();
 #endif
 	watchdog_init();
diff --git a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
index 5283135..66a3b3d 100644
--- a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
+++ b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
@@ -16,9 +16,10 @@
 #include <asm/arch/spl.h>
 #include <linux/linkage.h>
 
+.arch_extension sec
+
 #ifdef CONFIG_SPL
 ENTRY(save_boot_params)
-
 	ldr	r1, =OMAP_SRAM_SCRATCH_BOOT_PARAMS
 	str	r0, [r1]
 	b	save_boot_params_ret
@@ -26,14 +27,40 @@
 #endif
 
 ENTRY(omap_smc1)
-	PUSH	{r4-r12, lr}	@ save registers - ROM code may pollute
+	push	{r4-r12, lr}	@ save registers - ROM code may pollute
 				@ our registers
-	MOV	r12, r0		@ Service
-	MOV	r0, r1		@ Argument
-	DSB
-	DMB
-	.word	0xe1600070	@ SMC #0 - hand assembled for GCC versions
-				@ call ROM Code API for the service requested
+	mov	r12, r0		@ Service
+	mov	r0, r1		@ Argument
 
-	POP	{r4-r12, pc}
+	dsb
+	dmb
+	smc	0		@ SMC #0 to enter monitor mode
+				@ call ROM Code API for the service requested
+	pop	{r4-r12, pc}
 ENDPROC(omap_smc1)
+
+ENTRY(omap_smc_sec)
+	push	{r4-r12, lr}	@ save registers - ROM code may pollute
+				@ our registers
+	mov	r6, #0xFF	@ Indicate new Task call
+	mov	r12, #0x00	@ Secure Service ID in R12
+
+	dsb
+	dmb
+	smc	0		@ SMC #0 to enter monitor mode
+
+	b	omap_smc_sec_end @ exit at end of the service execution
+	nop
+
+	@ In case of IRQ happening in Secure, then ARM will branch here.
+	@ At that moment, IRQ will be pending and ARM will jump to Non Secure
+	@ IRQ handler
+	mov	r12, #0xFE
+
+	dsb
+	dmb
+	smc	0		@ SMC #0 to enter monitor mode
+
+omap_smc_sec_end:
+	pop	{r4-r12, pc}
+ENDPROC(omap_smc_sec)
diff --git a/arch/arm/cpu/armv7/omap-common/sec-common.c b/arch/arm/cpu/armv7/omap-common/sec-common.c
new file mode 100644
index 0000000..246a239
--- /dev/null
+++ b/arch/arm/cpu/armv7/omap-common/sec-common.c
@@ -0,0 +1,139 @@
+/*
+ *
+ * Common security related functions for OMAP devices
+ *
+ * (C) Copyright 2016
+ * Texas Instruments, <www.ti.com>
+ *
+ * Daniel Allred <d-allred@ti.com>
+ * Andreas Dannenberg <dannenberg@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <stdarg.h>
+
+#include <asm/arch/sys_proto.h>
+#include <asm/omap_common.h>
+#include <asm/omap_sec_common.h>
+#include <asm/spl.h>
+#include <spl.h>
+
+/* Index for signature verify ROM API */
+#define API_HAL_KM_VERIFYCERTIFICATESIGNATURE_INDEX	(0x0000000E)
+
+static uint32_t secure_rom_call_args[5] __aligned(ARCH_DMA_MINALIGN);
+
+u32 secure_rom_call(u32 service, u32 proc_id, u32 flag, ...)
+{
+	int i;
+	u32 num_args;
+	va_list ap;
+
+	va_start(ap, flag);
+
+	num_args = va_arg(ap, u32);
+
+	if (num_args > 4)
+		return 1;
+
+	/* Copy args to aligned args structure */
+	for (i = 0; i < num_args; i++)
+		secure_rom_call_args[i + 1] = va_arg(ap, u32);
+
+	secure_rom_call_args[0] = num_args;
+
+	va_end(ap);
+
+	/* if data cache is enabled, flush the aligned args structure */
+	flush_dcache_range(
+		(unsigned int)&secure_rom_call_args[0],
+		(unsigned int)&secure_rom_call_args[0] +
+		roundup(sizeof(secure_rom_call_args), ARCH_DMA_MINALIGN));
+
+	return omap_smc_sec(service, proc_id, flag, secure_rom_call_args);
+}
+
+static u32 find_sig_start(char *image, size_t size)
+{
+	char *image_end = image + size;
+	char *sig_start_magic = "CERT_";
+	int magic_str_len = strlen(sig_start_magic);
+	char *ch;
+
+	while (--image_end > image) {
+		if (*image_end == '_') {
+			ch = image_end - magic_str_len + 1;
+			if (!strncmp(ch, sig_start_magic, magic_str_len))
+				return (u32)ch;
+		}
+	}
+	return 0;
+}
+
+int secure_boot_verify_image(void **image, size_t *size)
+{
+	int result = 1;
+	u32 cert_addr, sig_addr;
+	size_t cert_size;
+
+	/* Perform cache writeback on input buffer */
+	flush_dcache_range(
+		(u32)*image,
+		(u32)*image + roundup(*size, ARCH_DMA_MINALIGN));
+
+	cert_addr = (uint32_t)*image;
+	sig_addr = find_sig_start((char *)*image, *size);
+
+	if (sig_addr == 0) {
+		printf("No signature found in image!\n");
+		result = 1;
+		goto auth_exit;
+	}
+
+	*size = sig_addr - cert_addr;	/* Subtract out the signature size */
+	cert_size = *size;
+
+	/* Check if image load address is 32-bit aligned */
+	if (!IS_ALIGNED(cert_addr, 4)) {
+		printf("Image is not 4-byte aligned!\n");
+		result = 1;
+		goto auth_exit;
+	}
+
+	/* Image size also should be multiple of 4 */
+	if (!IS_ALIGNED(cert_size, 4)) {
+		printf("Image size is not 4-byte aligned!\n");
+		result = 1;
+		goto auth_exit;
+	}
+
+	/* Call ROM HAL API to verify certificate signature */
+	debug("%s: load_addr = %x, size = %x, sig_addr = %x\n", __func__,
+	      cert_addr, cert_size, sig_addr);
+
+	result = secure_rom_call(
+		API_HAL_KM_VERIFYCERTIFICATESIGNATURE_INDEX, 0, 0,
+		4, cert_addr, cert_size, sig_addr, 0xFFFFFFFF);
+auth_exit:
+	if (result != 0) {
+		printf("Authentication failed!\n");
+		printf("Return Value = %08X\n", result);
+		hang();
+	}
+
+	/*
+	 * Output notification of successful authentication as well the name of
+	 * the signing certificate used to re-assure the user that the secure
+	 * code is being processed as expected. However suppress any such log
+	 * output in case of building for SPL and booting via YMODEM. This is
+	 * done to avoid disturbing the YMODEM serial protocol transactions.
+	 */
+	if (!(IS_ENABLED(CONFIG_SPL_BUILD) &&
+	      IS_ENABLED(CONFIG_SPL_YMODEM_SUPPORT) &&
+	      spl_boot_device() == BOOT_DEVICE_UART))
+		printf("Authentication passed: %s\n", (char *)sig_addr);
+
+	return result;
+}
diff --git a/arch/arm/cpu/armv7/omap5/config.mk b/arch/arm/cpu/armv7/omap5/config.mk
index a7e55a5..d245572 100644
--- a/arch/arm/cpu/armv7/omap5/config.mk
+++ b/arch/arm/cpu/armv7/omap5/config.mk
@@ -15,5 +15,8 @@
 ALL-y	+= MLO
 endif
 else
+ifeq ($(CONFIG_TI_SECURE_DEVICE),y)
+ALL-y   += u-boot_HS.img
+endif
 ALL-y	+= u-boot.img
 endif
diff --git a/arch/arm/cpu/armv7m/config.mk b/arch/arm/cpu/armv7m/config.mk
index 4a53006..db4660e 100644
--- a/arch/arm/cpu/armv7m/config.mk
+++ b/arch/arm/cpu/armv7m/config.mk
@@ -5,4 +5,4 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-PLATFORM_CPPFLAGS += -march=armv7-m -mthumb
+PLATFORM_CPPFLAGS += -march=armv7-m -mthumb -mno-unaligned-access
diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig
index 3d19bbf..acf2460 100644
--- a/arch/arm/cpu/armv8/Kconfig
+++ b/arch/arm/cpu/armv8/Kconfig
@@ -3,4 +3,22 @@
 config ARMV8_MULTIENTRY
         boolean "Enable multiple CPUs to enter into U-Boot"
 
+config ARMV8_SPIN_TABLE
+	bool "Support spin-table enable method"
+	depends on ARMV8_MULTIENTRY && OF_LIBFDT
+	help
+	  Say Y here to support "spin-table" enable method for booting Linux.
+
+	  To use this feature, you must do:
+	    - Specify enable-method = "spin-table" in each CPU node in the
+	      Device Tree you are using to boot the kernel
+	    - Let secondary CPUs in U-Boot (in a board specific manner)
+	      before the master CPU jumps to the kernel
+
+	  U-Boot automatically does:
+	    - Set "cpu-release-addr" property of each CPU node
+	      (overwrites it if already exists).
+	    - Reserve the code for the spin-table and the release address
+	      via a /memreserve/ region in the Device Tree.
+
 endif
diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile
index bf8644c..f6eb9f4 100644
--- a/arch/arm/cpu/armv8/Makefile
+++ b/arch/arm/cpu/armv8/Makefile
@@ -15,6 +15,9 @@
 obj-y	+= tlb.o
 obj-y	+= transition.o
 obj-y	+= fwcall.o
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o
+endif
 
 obj-$(CONFIG_FSL_LAYERSCAPE) += fsl-layerscape/
 obj-$(CONFIG_S32V234) += s32v234/
diff --git a/arch/arm/cpu/armv8/spin_table.c b/arch/arm/cpu/armv8/spin_table.c
new file mode 100644
index 0000000..ec1c9b8
--- /dev/null
+++ b/arch/arm/cpu/armv8/spin_table.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <asm/spin_table.h>
+
+int spin_table_update_dt(void *fdt)
+{
+	int cpus_offset, offset;
+	const char *prop;
+	int ret;
+	unsigned long rsv_addr = (unsigned long)&spin_table_reserve_begin;
+	unsigned long rsv_size = &spin_table_reserve_end -
+						&spin_table_reserve_begin;
+
+	cpus_offset = fdt_path_offset(fdt, "/cpus");
+	if (cpus_offset < 0)
+		return -ENODEV;
+
+	for (offset = fdt_first_subnode(fdt, cpus_offset);
+	     offset >= 0;
+	     offset = fdt_next_subnode(fdt, offset)) {
+		prop = fdt_getprop(fdt, offset, "device_type", NULL);
+		if (!prop || strcmp(prop, "cpu"))
+			continue;
+
+		/*
+		 * In the first loop, we check if every CPU node specifies
+		 * spin-table.  Otherwise, just return successfully to not
+		 * disturb other methods, like psci.
+		 */
+		prop = fdt_getprop(fdt, offset, "enable-method", NULL);
+		if (!prop || strcmp(prop, "spin-table"))
+			return 0;
+	}
+
+	for (offset = fdt_first_subnode(fdt, cpus_offset);
+	     offset >= 0;
+	     offset = fdt_next_subnode(fdt, offset)) {
+		prop = fdt_getprop(fdt, offset, "device_type", NULL);
+		if (!prop || strcmp(prop, "cpu"))
+			continue;
+
+		ret = fdt_setprop_u64(fdt, offset, "cpu-release-addr",
+				(unsigned long)&spin_table_cpu_release_addr);
+		if (ret)
+			return -ENOSPC;
+	}
+
+	ret = fdt_add_mem_rsv(fdt, rsv_addr, rsv_size);
+	if (ret)
+		return -ENOSPC;
+
+	printf("   Reserved memory region for spin-table: addr=%lx size=%lx\n",
+	       rsv_addr, rsv_size);
+
+	return 0;
+}
diff --git a/arch/arm/cpu/armv8/spin_table_v8.S b/arch/arm/cpu/armv8/spin_table_v8.S
new file mode 100644
index 0000000..d7f78a6
--- /dev/null
+++ b/arch/arm/cpu/armv8/spin_table_v8.S
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <linux/linkage.h>
+
+ENTRY(spin_table_secondary_jump)
+.globl spin_table_reserve_begin
+spin_table_reserve_begin:
+0:	wfe
+	ldr	x0, spin_table_cpu_release_addr
+	cbz	x0, 0b
+	br	x0
+.globl spin_table_cpu_release_addr
+	.align	3
+spin_table_cpu_release_addr:
+	.quad	0
+.globl spin_table_reserve_end
+spin_table_reserve_end:
+ENDPROC(spin_table_secondary_jump)
diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
index 670e323..67edf94 100644
--- a/arch/arm/cpu/armv8/start.S
+++ b/arch/arm/cpu/armv8/start.S
@@ -94,7 +94,11 @@
 	/* Processor specific initialization */
 	bl	lowlevel_init
 
-#ifdef CONFIG_ARMV8_MULTIENTRY
+#if CONFIG_IS_ENABLED(ARMV8_SPIN_TABLE)
+	branch_if_master x0, x1, master_cpu
+	b	spin_table_secondary_jump
+	/* never return */
+#elif defined(CONFIG_ARMV8_MULTIENTRY)
 	branch_if_master x0, x1, master_cpu
 
 	/*
@@ -106,10 +110,8 @@
 	ldr	x0, [x1]
 	cbz	x0, slave_cpu
 	br	x0			/* branch to the given address */
-master_cpu:
-	/* On the master CPU */
 #endif /* CONFIG_ARMV8_MULTIENTRY */
-
+master_cpu:
 	bl	_main
 
 #ifdef CONFIG_SYS_RESET_SCTRL
diff --git a/arch/arm/dts/exynos4210-origen.dts b/arch/arm/dts/exynos4210-origen.dts
index 3f87761..26c4d7f 100644
--- a/arch/arm/dts/exynos4210-origen.dts
+++ b/arch/arm/dts/exynos4210-origen.dts
@@ -22,7 +22,7 @@
 	aliases {
 		serial0 = "/serial@13800000";
 		console = "/serial@13820000";
-		mmc2 = "sdhci@12530000";
+		mmc2 = "/sdhci@12530000";
 	};
 
 	sdhci@12510000 {
diff --git a/arch/arm/dts/exynos4210-trats.dts b/arch/arm/dts/exynos4210-trats.dts
index f3fac80..2ed38f3 100644
--- a/arch/arm/dts/exynos4210-trats.dts
+++ b/arch/arm/dts/exynos4210-trats.dts
@@ -29,8 +29,8 @@
 		i2c7 = "/i2c@138d0000";
 		serial0 = "/serial@13800000";
 		console = "/serial@13820000";
-		mmc0 = "sdhci@12510000";
-		mmc2 = "sdhci@12530000";
+		mmc0 = "/sdhci@12510000";
+		mmc2 = "/sdhci@12530000";
 	};
 
 	fimd@11c00000 {
diff --git a/arch/arm/dts/exynos4210-universal_c210.dts b/arch/arm/dts/exynos4210-universal_c210.dts
index ad3527e..8cac7dd 100644
--- a/arch/arm/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/dts/exynos4210-universal_c210.dts
@@ -17,8 +17,8 @@
 	aliases {
 		serial0 = "/serial@13800000";
 		console = "/serial@13820000";
-		mmc0 = "sdhci@12510000";
-		mmc2 = "sdhci@12530000";
+		mmc0 = "/sdhci@12510000";
+		mmc2 = "/sdhci@12530000";
 	};
 
 	sdhci@12510000 {
diff --git a/arch/arm/dts/exynos4412-odroid.dts b/arch/arm/dts/exynos4412-odroid.dts
index a63e8ab..188cb93 100644
--- a/arch/arm/dts/exynos4412-odroid.dts
+++ b/arch/arm/dts/exynos4412-odroid.dts
@@ -25,8 +25,8 @@
 		i2c7 = "/i2c@138d0000";
 		serial0 = "/serial@13800000";
 		console = "/serial@13810000";
-		mmc2 = "sdhci@12530000";
-		mmc4 = "dwmmc@12550000";
+		mmc2 = "/sdhci@12530000";
+		mmc4 = "/dwmmc@12550000";
 	};
 
 	i2c@13860000 {
diff --git a/arch/arm/dts/exynos4412-trats2.dts b/arch/arm/dts/exynos4412-trats2.dts
index 2d4e522..1fbcf89 100644
--- a/arch/arm/dts/exynos4412-trats2.dts
+++ b/arch/arm/dts/exynos4412-trats2.dts
@@ -29,9 +29,9 @@
 		i2c7 = "/i2c@138d0000";
 		serial0 = "/serial@13800000";
 		console = "/serial@13820000";
-		mmc0 = "sdhci@12510000";
-		mmc2 = "sdhci@12530000";
-		mmc4 = "dwmmc@12550000";
+		mmc0 = "/sdhci@12510000";
+		mmc2 = "/sdhci@12530000";
+		mshc0 = "/dwmmc@12550000";
 	};
 
 	i2c@138d0000 {
diff --git a/arch/arm/dts/rk3288-firefly.dts b/arch/arm/dts/rk3288-firefly.dts
index aed8d3a..3176d50 100644
--- a/arch/arm/dts/rk3288-firefly.dts
+++ b/arch/arm/dts/rk3288-firefly.dts
@@ -30,7 +30,8 @@
 		0x5 0x0>;
 	rockchip,phy-timing = <0x48f9aab4 0xea0910 0x1002c200
 		0xa60 0x40 0x10 0x0>;
-	rockchip,sdram-channel = /bits/ 8 <0x1 0xa 0x3 0x2 0x1 0x0 0xf 0xf>;
+	/* Add a dummy value to cause of-platdata think this is bytes */
+	rockchip,sdram-channel = /bits/ 8 <0x1 0xa 0x3 0x2 0x1 0x0 0xf 0xf 0xff>;
 	rockchip,sdram-params = <0x30B25564 0x627 3 666000000 3 9 1>;
 };
 
diff --git a/arch/arm/include/asm/arch-rockchip/sdram.h b/arch/arm/include/asm/arch-rockchip/sdram.h
index d3de42d..e08e28f 100644
--- a/arch/arm/include/asm/arch-rockchip/sdram.h
+++ b/arch/arm/include/asm/arch-rockchip/sdram.h
@@ -24,6 +24,12 @@
 	u8 row_3_4;
 	u8 cs0_row;
 	u8 cs1_row;
+	/*
+	 * For of-platdata, which would otherwise convert this into two
+	 * byte-swapped integers. With a size of 9 bytes, this struct will
+	 * appear in of-platdata as a byte array.
+	 */
+	u8 dummy;
 };
 
 struct rk3288_sdram_pctl_timing {
@@ -81,12 +87,4 @@
 	u32 odt;
 };
 
-struct rk3288_sdram_params {
-	struct rk3288_sdram_channel ch[2];
-	struct rk3288_sdram_pctl_timing pctl_timing;
-	struct rk3288_sdram_phy_timing phy_timing;
-	struct rk3288_base_params base;
-	int num_channels;
-};
-
 #endif
diff --git a/arch/arm/include/asm/arch-stm32f7/fmc.h b/arch/arm/include/asm/arch-stm32f7/fmc.h
new file mode 100644
index 0000000..7dd5077
--- /dev/null
+++ b/arch/arm/include/asm/arch-stm32f7/fmc.h
@@ -0,0 +1,75 @@
+/*
+ * (C) Copyright 2013
+ * Pavel Boldin, Emcraft Systems, paboldin@emcraft.com
+ *
+ * (C) Copyright 2015
+ * Kamil Lulko, <kamil.lulko@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _MACH_FMC_H_
+#define _MACH_FMC_H_
+
+struct stm32_fmc_regs {
+	u32 sdcr1;	/* Control register 1 */
+	u32 sdcr2;	/* Control register 2 */
+	u32 sdtr1;	/* Timing register 1 */
+	u32 sdtr2;	/* Timing register 2 */
+	u32 sdcmr;	/* Mode register */
+	u32 sdrtr;	/* Refresh timing register */
+	u32 sdsr;	/* Status register */
+};
+
+/*
+ * FMC registers base
+ */
+#define STM32_SDRAM_FMC_BASE	0xA0000140
+#define STM32_SDRAM_FMC		((struct stm32_fmc_regs *)STM32_SDRAM_FMC_BASE)
+
+/* Control register SDCR */
+#define FMC_SDCR_RPIPE_SHIFT	13	/* RPIPE bit shift */
+#define FMC_SDCR_RBURST_SHIFT	12	/* RBURST bit shift */
+#define FMC_SDCR_SDCLK_SHIFT	10	/* SDRAM clock divisor shift */
+#define FMC_SDCR_WP_SHIFT	9	/* Write protection shift */
+#define FMC_SDCR_CAS_SHIFT	7	/* CAS latency shift */
+#define FMC_SDCR_NB_SHIFT	6	/* Number of banks shift */
+#define FMC_SDCR_MWID_SHIFT	4	/* Memory width shift */
+#define FMC_SDCR_NR_SHIFT	2	/* Number of row address bits shift */
+#define FMC_SDCR_NC_SHIFT	0	/* Number of col address bits shift */
+
+/* Timings register SDTR */
+#define FMC_SDTR_TMRD_SHIFT	0	/* Load mode register to active */
+#define FMC_SDTR_TXSR_SHIFT	4	/* Exit self-refresh time */
+#define FMC_SDTR_TRAS_SHIFT	8	/* Self-refresh time */
+#define FMC_SDTR_TRC_SHIFT	12	/* Row cycle delay */
+#define FMC_SDTR_TWR_SHIFT	16	/* Recovery delay */
+#define FMC_SDTR_TRP_SHIFT	20	/* Row precharge delay */
+#define FMC_SDTR_TRCD_SHIFT	24	/* Row-to-column delay */
+
+
+#define FMC_SDCMR_NRFS_SHIFT	5
+
+#define FMC_SDCMR_MODE_NORMAL		0
+#define FMC_SDCMR_MODE_START_CLOCK	1
+#define FMC_SDCMR_MODE_PRECHARGE	2
+#define FMC_SDCMR_MODE_AUTOREFRESH	3
+#define FMC_SDCMR_MODE_WRITE_MODE	4
+#define FMC_SDCMR_MODE_SELFREFRESH	5
+#define FMC_SDCMR_MODE_POWERDOWN	6
+
+#define FMC_SDCMR_BANK_1		(1 << 4)
+#define FMC_SDCMR_BANK_2		(1 << 3)
+
+#define FMC_SDCMR_MODE_REGISTER_SHIFT	9
+
+#define FMC_SDSR_BUSY			(1 << 5)
+
+#define FMC_BUSY_WAIT()		do { \
+		__asm__ __volatile__ ("dsb" : : : "memory"); \
+		while (STM32_SDRAM_FMC->sdsr & FMC_SDSR_BUSY) \
+			; \
+	} while (0)
+
+
+#endif /* _MACH_FMC_H_ */
diff --git a/arch/arm/include/asm/arch-stm32f7/stm32.h b/arch/arm/include/asm/arch-stm32f7/stm32.h
index 68bdab0..de55ae5 100644
--- a/arch/arm/include/asm/arch-stm32f7/stm32.h
+++ b/arch/arm/include/asm/arch-stm32f7/stm32.h
@@ -64,6 +64,52 @@
 };
 #define STM32_BUS_MASK          0xFFFF0000
 
+struct stm32_rcc_regs {
+	u32 cr;		/* RCC clock control */
+	u32 pllcfgr;	/* RCC PLL configuration */
+	u32 cfgr;	/* RCC clock configuration */
+	u32 cir;	/* RCC clock interrupt */
+	u32 ahb1rstr;	/* RCC AHB1 peripheral reset */
+	u32 ahb2rstr;	/* RCC AHB2 peripheral reset */
+	u32 ahb3rstr;	/* RCC AHB3 peripheral reset */
+	u32 rsv0;
+	u32 apb1rstr;	/* RCC APB1 peripheral reset */
+	u32 apb2rstr;	/* RCC APB2 peripheral reset */
+	u32 rsv1[2];
+	u32 ahb1enr;	/* RCC AHB1 peripheral clock enable */
+	u32 ahb2enr;	/* RCC AHB2 peripheral clock enable */
+	u32 ahb3enr;	/* RCC AHB3 peripheral clock enable */
+	u32 rsv2;
+	u32 apb1enr;	/* RCC APB1 peripheral clock enable */
+	u32 apb2enr;	/* RCC APB2 peripheral clock enable */
+	u32 rsv3[2];
+	u32 ahb1lpenr;	/* RCC AHB1 periph clk enable in low pwr mode */
+	u32 ahb2lpenr;	/* RCC AHB2 periph clk enable in low pwr mode */
+	u32 ahb3lpenr;	/* RCC AHB3 periph clk enable in low pwr mode */
+	u32 rsv4;
+	u32 apb1lpenr;	/* RCC APB1 periph clk enable in low pwr mode */
+	u32 apb2lpenr;	/* RCC APB2 periph clk enable in low pwr mode */
+	u32 rsv5[2];
+	u32 bdcr;	/* RCC Backup domain control */
+	u32 csr;	/* RCC clock control & status */
+	u32 rsv6[2];
+	u32 sscgr;	/* RCC spread spectrum clock generation */
+	u32 plli2scfgr;	/* RCC PLLI2S configuration */
+	u32 pllsaicfgr;
+	u32 dckcfgr;
+};
+#define STM32_RCC		((struct stm32_rcc_regs *)RCC_BASE)
+
+struct stm32_pwr_regs {
+	u32 cr1;   /* power control register 1 */
+	u32 csr1;  /* power control/status register 2 */
+	u32 cr2;   /* power control register 2 */
+	u32 csr2;  /* power control/status register 2 */
+};
+#define STM32_PWR		((struct stm32_pwr_regs *)PWR_BASE)
+
 int configure_clocks(void);
+unsigned long clock_get(enum clock clck);
+void stm32_flash_latency_cfg(int latency);
 
 #endif /* _ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/include/asm/arch-stm32f7/stm32_periph.h b/arch/arm/include/asm/arch-stm32f7/stm32_periph.h
index 38adc4e..0bd4695 100644
--- a/arch/arm/include/asm/arch-stm32f7/stm32_periph.h
+++ b/arch/arm/include/asm/arch-stm32f7/stm32_periph.h
@@ -17,11 +17,13 @@
 enum periph_id {
 	UART1_GPIOA_9_10 = 0,
 	UART2_GPIOD_5_6,
+	UART6_GPIOC_6_7,
 };
 
 enum periph_clock {
 	USART1_CLOCK_CFG = 0,
 	USART2_CLOCK_CFG,
+	USART6_CLOCK_CFG,
 	GPIO_A_CLOCK_CFG,
 	GPIO_B_CLOCK_CFG,
 	GPIO_C_CLOCK_CFG,
diff --git a/arch/arm/include/asm/armv7m.h b/arch/arm/include/asm/armv7m.h
index 200444d..54d8a2b 100644
--- a/arch/arm/include/asm/armv7m.h
+++ b/arch/arm/include/asm/armv7m.h
@@ -51,10 +51,21 @@
 #define V7M_MPU_CTRL_ENABLE		(1 << 0)
 #define V7M_MPU_CTRL_HFNMIENA		(1 << 1)
 
+#define V7M_MPU_CTRL_ENABLE		(1 << 0)
+#define V7M_MPU_CTRL_DISABLE		(0 << 0)
+#define V7M_MPU_CTRL_HFNMIENA		(1 << 1)
+
 #define V7M_MPU_RASR_EN			(1 << 0)
 #define V7M_MPU_RASR_SIZE_BITS		1
 #define V7M_MPU_RASR_SIZE_4GB		(31 << V7M_MPU_RASR_SIZE_BITS)
+#define V7M_MPU_RASR_SIZE_8MB		(24 << V7M_MPU_RASR_SIZE_BITS)
+#define V7M_MPU_RASR_TEX_SHIFT	19
+#define V7M_MPU_RASR_S_SHIFT		18
+#define V7M_MPU_RASR_C_SHIFT		17
+#define V7M_MPU_RASR_B_SHIFT		16
 #define V7M_MPU_RASR_AP_RW_RW		(3 << 24)
+#define V7M_MPU_RASR_XN_ENABLE	(0 << 28)
+#define V7M_MPU_RASR_XN_DISABLE (1 << 28)
 
 #endif /* !defined(__ASSEMBLY__) */
 #endif /* ARMV7M_H */
diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
index 1f63127..16e65c3 100644
--- a/arch/arm/include/asm/cache.h
+++ b/arch/arm/include/asm/cache.h
@@ -29,6 +29,8 @@
 }
 #endif
 
+int check_cache_range(unsigned long start, unsigned long stop);
+
 void l2_cache_enable(void);
 void l2_cache_disable(void);
 void set_section_dcache(int section, enum dcache_option option);
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 9d185a6..6121f1d 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -292,40 +292,6 @@
 #define readsb(a, d, s)		__raw_readsb((unsigned long)a, d, s)
 
 /*
- * ioremap and friends.
- *
- * ioremap takes a PCI memory address, as specified in
- * linux/Documentation/IO-mapping.txt.  If you want a
- * physical address, use __ioremap instead.
- */
-extern void * __ioremap(unsigned long offset, size_t size, unsigned long flags);
-extern void __iounmap(void *addr);
-
-/*
- * Generic ioremap support.
- *
- * Define:
- *  iomem_valid_addr(off,size)
- *  iomem_to_phys(off)
- */
-#ifdef iomem_valid_addr
-#define __arch_ioremap(off,sz,nocache)					\
- ({									\
-	unsigned long _off = (off), _size = (sz);			\
-	void *_ret = (void *)0;						\
-	if (iomem_valid_addr(_off, _size))				\
-		_ret = __ioremap(iomem_to_phys(_off),_size,nocache);	\
-	_ret;								\
- })
-
-#define __arch_iounmap __iounmap
-#endif
-
-#define ioremap(off,sz)			__arch_ioremap((off),(sz),0)
-#define ioremap_nocache(off,sz)		__arch_ioremap((off),(sz),1)
-#define iounmap(_addr)			__arch_iounmap(_addr)
-
-/*
  * DMA-consistent mapping functions.  These allocate/free a region of
  * uncached, unwrite-buffered mapped memory space for use with DMA
  * devices.  This is the "generic" version.  The PCI specific version
diff --git a/arch/arm/include/asm/omap_common.h b/arch/arm/include/asm/omap_common.h
index 07f3848..605c549 100644
--- a/arch/arm/include/asm/omap_common.h
+++ b/arch/arm/include/asm/omap_common.h
@@ -627,6 +627,12 @@
 
 void omap_smc1(u32 service, u32 val);
 
+/*
+ * Low-level helper function used when performing secure ROM calls on high-
+ * security (HS) device variants by doing a specially-formed smc entry.
+ */
+u32 omap_smc_sec(u32 service, u32 proc_id, u32 flag, u32 *params);
+
 void enable_edma3_clocks(void);
 void disable_edma3_clocks(void);
 
diff --git a/arch/arm/include/asm/omap_sec_common.h b/arch/arm/include/asm/omap_sec_common.h
new file mode 100644
index 0000000..842f2af
--- /dev/null
+++ b/arch/arm/include/asm/omap_sec_common.h
@@ -0,0 +1,30 @@
+/*
+ * (C) Copyright 2016
+ * Texas Instruments, <www.ti.com>
+ *
+ * Andreas Dannenberg <dannenberg@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef	_OMAP_SEC_COMMON_H_
+#define	_OMAP_SEC_COMMON_H_
+
+#include <common.h>
+
+/*
+ * Invoke secure ROM API on high-security (HS) device variants. It formats
+ * the variable argument list into the format expected by the ROM code before
+ * triggering the actual low-level smc entry.
+ */
+u32 secure_rom_call(u32 service, u32 proc_id, u32 flag, ...);
+
+/*
+ * Invoke a secure ROM API on high-secure (HS) device variants that can be used
+ * to verify a secure blob by authenticating and optionally decrypting it. The
+ * exact operation performed depends on how the certificate that was embedded
+ * into the blob during the signing/encryption step when the secure blob was
+ * first created.
+ */
+int secure_boot_verify_image(void **p_image, size_t *p_size);
+
+#endif /* _OMAP_SEC_COMMON_H_ */
diff --git a/arch/arm/include/asm/spin_table.h b/arch/arm/include/asm/spin_table.h
new file mode 100644
index 0000000..8b57539
--- /dev/null
+++ b/arch/arm/include/asm/spin_table.h
@@ -0,0 +1,14 @@
+/*
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __ASM_SPIN_TABLE_H__
+#define __ASM_SPIN_TABLE_H__
+
+extern u64 spin_table_cpu_release_addr;
+extern char spin_table_reserve_begin;
+extern char spin_table_reserve_end;
+
+int spin_table_update_dt(void *fdt);
+
+#endif /* __ASM_SPIN_TABLE_H__ */
diff --git a/arch/arm/include/asm/types.h b/arch/arm/include/asm/types.h
index d108915..9af7353 100644
--- a/arch/arm/include/asm/types.h
+++ b/arch/arm/include/asm/types.h
@@ -71,5 +71,4 @@
 
 #endif /* __KERNEL__ */
 
-typedef unsigned long resource_size_t;
 #endif
diff --git a/arch/arm/lib/bootm-fdt.c b/arch/arm/lib/bootm-fdt.c
index 76b75d8..2c0b56a 100644
--- a/arch/arm/lib/bootm-fdt.c
+++ b/arch/arm/lib/bootm-fdt.c
@@ -21,6 +21,7 @@
 #include <asm/armv7.h>
 #endif
 #include <asm/psci.h>
+#include <asm/spin_table.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -45,6 +46,12 @@
 	if (ret)
 		return ret;
 
+#ifdef CONFIG_ARMV8_SPIN_TABLE
+	ret = spin_table_update_dt(blob);
+	if (ret)
+		return ret;
+#endif
+
 #ifdef CONFIG_ARMV7_NONSEC
 	ret = psci_update_dt(blob);
 	if (ret)
diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
index 3bd8710..d330b09 100644
--- a/arch/arm/lib/cache.c
+++ b/arch/arm/lib/cache.c
@@ -10,6 +10,10 @@
 #include <common.h>
 #include <malloc.h>
 
+#ifndef CONFIG_SYS_CACHELINE_SIZE
+#define CONFIG_SYS_CACHELINE_SIZE 32
+#endif
+
 /*
  * Flush range from all levels of d-cache/unified-cache.
  * Affects the range [start, start + size - 1].
@@ -46,6 +50,24 @@
 	/* An empty stub, real implementation should be in platform code */
 }
 
+int check_cache_range(unsigned long start, unsigned long stop)
+{
+	int ok = 1;
+
+	if (start & (CONFIG_SYS_CACHELINE_SIZE - 1))
+		ok = 0;
+
+	if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1))
+		ok = 0;
+
+	if (!ok) {
+		warn_non_spl("CACHE: Misaligned operation at range [%08lx, %08lx]\n",
+			     start, stop);
+	}
+
+	return ok;
+}
+
 #ifdef CONFIG_SYS_NONCACHED_MEMORY
 /*
  * Reserve one MMU section worth of address space below the malloc() area that
diff --git a/arch/arm/mach-exynos/include/mach/dwmmc.h b/arch/arm/mach-exynos/include/mach/dwmmc.h
index bd997ad..ab8361f 100644
--- a/arch/arm/mach-exynos/include/mach/dwmmc.h
+++ b/arch/arm/mach-exynos/include/mach/dwmmc.h
@@ -28,4 +28,3 @@
 #define DWMCI_DIVRATIO_MASK		0x7
 
 int exynos_dwmmc_init(const void *blob);
-int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel);
diff --git a/arch/arm/mach-rockchip/rk3288-board-spl.c b/arch/arm/mach-rockchip/rk3288-board-spl.c
index 15f1266..123f58b 100644
--- a/arch/arm/mach-rockchip/rk3288-board-spl.c
+++ b/arch/arm/mach-rockchip/rk3288-board-spl.c
@@ -29,6 +29,7 @@
 
 u32 spl_boot_device(void)
 {
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
 	const void *blob = gd->fdt_blob;
 	struct udevice *dev;
 	const char *bootdev;
@@ -63,6 +64,7 @@
 	}
 
 fallback:
+#endif
 	return BOOT_DEVICE_MMC1;
 }
 
@@ -114,7 +116,6 @@
 #ifdef CONFIG_SPL_MMC_SUPPORT
 static int configure_emmc(struct udevice *pinctrl)
 {
-#if !defined(CONFIG_TARGET_ROCK2) && !defined(CONFIG_TARGET_FIREFLY_RK3288)
 	struct gpio_desc desc;
 	int ret;
 
@@ -144,7 +145,6 @@
 		debug("gpio value ret=%d\n", ret);
 		return ret;
 	}
-#endif
 
 	return 0;
 }
@@ -247,15 +247,18 @@
 		goto err;
 	}
 #ifdef CONFIG_SPL_MMC_SUPPORT
-	ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD);
-	if (ret) {
-		debug("%s: Failed to set up SD card\n", __func__);
-		goto err;
-	}
-	ret = configure_emmc(pinctrl);
-	if (ret) {
-		debug("%s: Failed to set up eMMC\n", __func__);
-		goto err;
+	if (!IS_ENABLED(CONFIG_TARGET_ROCK2) &&
+	    !IS_ENABLED(CONFIG_TARGET_FIREFLY_RK3288)) {
+		ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD);
+		if (ret) {
+			debug("%s: Failed to set up SD card\n", __func__);
+			goto err;
+		}
+		ret = configure_emmc(pinctrl);
+		if (ret) {
+			debug("%s: Failed to set up eMMC\n", __func__);
+			goto err;
+		}
 	}
 #endif
 
diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
index 55ac73e..b36b6af 100644
--- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
+++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
@@ -10,6 +10,7 @@
 #include <common.h>
 #include <clk.h>
 #include <dm.h>
+#include <dt-structs.h>
 #include <errno.h>
 #include <ram.h>
 #include <regmap.h>
@@ -41,6 +42,19 @@
 	struct rk3288_grf *grf;
 	struct rk3288_sgrf *sgrf;
 	struct rk3288_pmu *pmu;
+	bool is_veyron;
+};
+
+struct rk3288_sdram_params {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_rockchip_rk3288_dmc of_plat;
+#endif
+	struct rk3288_sdram_channel ch[2];
+	struct rk3288_sdram_pctl_timing pctl_timing;
+	struct rk3288_sdram_phy_timing phy_timing;
+	struct rk3288_base_params base;
+	int num_channels;
+	struct regmap *map;
 };
 
 #ifdef CONFIG_SPL_BUILD
@@ -703,7 +717,7 @@
 
 	return 0;
 }
-#endif
+#endif /* CONFIG_SPL_BUILD */
 
 size_t sdram_size_mb(struct rk3288_pmu *pmu)
 {
@@ -779,18 +793,36 @@
 static int setup_sdram(struct udevice *dev)
 {
 	struct dram_info *priv = dev_get_priv(dev);
-	struct rk3288_sdram_params params;
+	struct rk3288_sdram_params *params = dev_get_platdata(dev);
+
+# ifdef CONFIG_ROCKCHIP_FAST_SPL
+	if (priv->is_veyron) {
+		int ret;
+
+		ret = veyron_init(priv);
+		if (ret)
+			return ret;
+	}
+# endif
+
+	return sdram_init(priv, params);
+}
+
+static int rk3288_dmc_ofdata_to_platdata(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct rk3288_sdram_params *params = dev_get_platdata(dev);
 	const void *blob = gd->fdt_blob;
 	int node = dev->of_offset;
 	int i, ret;
 
-	params.num_channels = fdtdec_get_int(blob, node,
-					     "rockchip,num-channels", 1);
-	for (i = 0; i < params.num_channels; i++) {
+	params->num_channels = fdtdec_get_int(blob, node,
+					      "rockchip,num-channels", 1);
+	for (i = 0; i < params->num_channels; i++) {
 		ret = fdtdec_get_byte_array(blob, node,
 					    "rockchip,sdram-channel",
-					    (u8 *)&params.ch[i],
-					    sizeof(params.ch[i]));
+					    (u8 *)&params->ch[i],
+					    sizeof(params->ch[i]));
 		if (ret) {
 			debug("%s: Cannot read rockchip,sdram-channel\n",
 			      __func__);
@@ -798,46 +830,82 @@
 		}
 	}
 	ret = fdtdec_get_int_array(blob, node, "rockchip,pctl-timing",
-				   (u32 *)&params.pctl_timing,
-				   sizeof(params.pctl_timing) / sizeof(u32));
+				   (u32 *)&params->pctl_timing,
+				   sizeof(params->pctl_timing) / sizeof(u32));
 	if (ret) {
 		debug("%s: Cannot read rockchip,pctl-timing\n", __func__);
 		return -EINVAL;
 	}
 	ret = fdtdec_get_int_array(blob, node, "rockchip,phy-timing",
-				   (u32 *)&params.phy_timing,
-				   sizeof(params.phy_timing) / sizeof(u32));
+				   (u32 *)&params->phy_timing,
+				   sizeof(params->phy_timing) / sizeof(u32));
 	if (ret) {
 		debug("%s: Cannot read rockchip,phy-timing\n", __func__);
 		return -EINVAL;
 	}
 	ret = fdtdec_get_int_array(blob, node, "rockchip,sdram-params",
-				   (u32 *)&params.base,
-				   sizeof(params.base) / sizeof(u32));
+				   (u32 *)&params->base,
+				   sizeof(params->base) / sizeof(u32));
 	if (ret) {
 		debug("%s: Cannot read rockchip,sdram-params\n", __func__);
 		return -EINVAL;
 	}
+#ifdef CONFIG_ROCKCHIP_FAST_SPL
+	struct dram_info *priv = dev_get_priv(dev);
 
-# ifdef CONFIG_ROCKCHIP_FAST_SPL
-	if (!fdt_node_check_compatible(blob, 0, "google,veyron")) {
-		ret = veyron_init(priv);
-		if (ret)
-			return ret;
+	priv->is_veyron = !fdt_node_check_compatible(blob, 0, "google,veyron");
+#endif
+	ret = regmap_init_mem(dev, &params->map);
+	if (ret)
+		return ret;
+#endif
+
+	return 0;
+}
+#endif /* CONFIG_SPL_BUILD */
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+static int conv_of_platdata(struct udevice *dev)
+{
+	struct rk3288_sdram_params *plat = dev_get_platdata(dev);
+	struct dtd_rockchip_rk3288_dmc *of_plat = &plat->of_plat;
+	int i, ret;
+
+	for (i = 0; i < 2; i++) {
+		memcpy(&plat->ch[i], of_plat->rockchip_sdram_channel,
+		       sizeof(plat->ch[i]));
 	}
-# endif
+	memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing,
+	       sizeof(plat->pctl_timing));
+	memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing,
+	       sizeof(plat->phy_timing));
+	memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base));
+	plat->num_channels = of_plat->rockchip_num_channels;
+	ret = regmap_init_mem_platdata(dev, of_plat->reg,
+				       ARRAY_SIZE(of_plat->reg) / 2,
+				       &plat->map);
+	if (ret)
+		return ret;
 
-	return sdram_init(priv, &params);
+	return 0;
 }
 #endif
 
 static int rk3288_dmc_probe(struct udevice *dev)
 {
+#ifdef CONFIG_SPL_BUILD
+	struct rk3288_sdram_params *plat = dev_get_platdata(dev);
+#endif
 	struct dram_info *priv = dev_get_priv(dev);
 	struct regmap *map;
 	int ret;
 	struct udevice *dev_clk;
 
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	ret = conv_of_platdata(dev);
+	if (ret)
+		return ret;
+#endif
 	map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC);
 	if (IS_ERR(map))
 		return PTR_ERR(map);
@@ -849,14 +917,12 @@
 	priv->sgrf = syscon_get_first_range(ROCKCHIP_SYSCON_SGRF);
 	priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU);
 
-	ret = regmap_init_mem(dev, &map);
-	if (ret)
-		return ret;
-	priv->chan[0].pctl = regmap_get_range(map, 0);
-	priv->chan[0].publ = regmap_get_range(map, 1);
-	priv->chan[1].pctl = regmap_get_range(map, 2);
-	priv->chan[1].publ = regmap_get_range(map, 3);
-
+#ifdef CONFIG_SPL_BUILD
+	priv->chan[0].pctl = regmap_get_range(plat->map, 0);
+	priv->chan[0].publ = regmap_get_range(plat->map, 1);
+	priv->chan[1].pctl = regmap_get_range(plat->map, 2);
+	priv->chan[1].publ = regmap_get_range(plat->map, 3);
+#endif
 	ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk);
 	if (ret)
 		return ret;
@@ -898,10 +964,16 @@
 };
 
 U_BOOT_DRIVER(dmc_rk3288) = {
-	.name = "rk3288_dmc",
+	.name = "rockchip_rk3288_dmc",
 	.id = UCLASS_RAM,
 	.of_match = rk3288_dmc_ids,
 	.ops = &rk3288_dmc_ops,
+#ifdef CONFIG_SPL_BUILD
+	.ofdata_to_platdata = rk3288_dmc_ofdata_to_platdata,
+#endif
 	.probe = rk3288_dmc_probe,
 	.priv_auto_alloc_size = sizeof(struct dram_info),
+#ifdef CONFIG_SPL_BUILD
+	.platdata_auto_alloc_size = sizeof(struct rk3288_sdram_params),
+#endif
 };
diff --git a/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c b/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c
index c9f7c4e..be4b2b0 100644
--- a/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c
+++ b/arch/arm/mach-rockchip/rk3288/syscon_rk3288.c
@@ -23,3 +23,41 @@
 	.id = UCLASS_SYSCON,
 	.of_match = rk3288_syscon_ids,
 };
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+static int rk3288_syscon_bind_of_platdata(struct udevice *dev)
+{
+	dev->driver_data = dev->driver->of_match->data;
+	debug("syscon: %s %d\n", dev->name, (uint)dev->driver_data);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(rockchip_rk3288_noc) = {
+	.name = "rockchip_rk3288_noc",
+	.id = UCLASS_SYSCON,
+	.of_match = rk3288_syscon_ids,
+	.bind = rk3288_syscon_bind_of_platdata,
+};
+
+U_BOOT_DRIVER(rockchip_rk3288_grf) = {
+	.name = "rockchip_rk3288_grf",
+	.id = UCLASS_SYSCON,
+	.of_match = rk3288_syscon_ids + 1,
+	.bind = rk3288_syscon_bind_of_platdata,
+};
+
+U_BOOT_DRIVER(rockchip_rk3288_sgrf) = {
+	.name = "rockchip_rk3288_sgrf",
+	.id = UCLASS_SYSCON,
+	.of_match = rk3288_syscon_ids + 2,
+	.bind = rk3288_syscon_bind_of_platdata,
+};
+
+U_BOOT_DRIVER(rockchip_rk3288_pmu) = {
+	.name = "rockchip_rk3288_pmu",
+	.id = UCLASS_SYSCON,
+	.of_match = rk3288_syscon_ids + 3,
+	.bind = rk3288_syscon_bind_of_platdata,
+};
+#endif
diff --git a/arch/arm/mach-stm32/stm32f7/Makefile b/arch/arm/mach-stm32/stm32f7/Makefile
index 40f1ad3..643d4d9 100644
--- a/arch/arm/mach-stm32/stm32f7/Makefile
+++ b/arch/arm/mach-stm32/stm32f7/Makefile
@@ -5,4 +5,4 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-obj-y += timer.o clock.o
+obj-y += timer.o clock.o soc.o
diff --git a/arch/arm/mach-stm32/stm32f7/clock.c b/arch/arm/mach-stm32/stm32f7/clock.c
index 17a715b..ac47850 100644
--- a/arch/arm/mach-stm32/stm32f7/clock.c
+++ b/arch/arm/mach-stm32/stm32f7/clock.c
@@ -11,12 +11,243 @@
 #include <asm/arch/stm32.h>
 #include <asm/arch/stm32_periph.h>
 
+#define RCC_CR_HSION		(1 << 0)
+#define RCC_CR_HSEON		(1 << 16)
+#define RCC_CR_HSERDY		(1 << 17)
+#define RCC_CR_HSEBYP		(1 << 18)
+#define RCC_CR_CSSON		(1 << 19)
+#define RCC_CR_PLLON		(1 << 24)
+#define RCC_CR_PLLRDY		(1 << 25)
+
+#define RCC_PLLCFGR_PLLM_MASK	0x3F
+#define RCC_PLLCFGR_PLLN_MASK	0x7FC0
+#define RCC_PLLCFGR_PLLP_MASK	0x30000
+#define RCC_PLLCFGR_PLLQ_MASK	0xF000000
+#define RCC_PLLCFGR_PLLSRC	(1 << 22)
+#define RCC_PLLCFGR_PLLM_SHIFT	0
+#define RCC_PLLCFGR_PLLN_SHIFT	6
+#define RCC_PLLCFGR_PLLP_SHIFT	16
+#define RCC_PLLCFGR_PLLQ_SHIFT	24
+
+#define RCC_CFGR_AHB_PSC_MASK	0xF0
+#define RCC_CFGR_APB1_PSC_MASK	0x1C00
+#define RCC_CFGR_APB2_PSC_MASK	0xE000
+#define RCC_CFGR_SW0		(1 << 0)
+#define RCC_CFGR_SW1		(1 << 1)
+#define RCC_CFGR_SW_MASK	0x3
+#define RCC_CFGR_SW_HSI		0
+#define RCC_CFGR_SW_HSE		RCC_CFGR_SW0
+#define RCC_CFGR_SW_PLL		RCC_CFGR_SW1
+#define RCC_CFGR_SWS0		(1 << 2)
+#define RCC_CFGR_SWS1		(1 << 3)
+#define RCC_CFGR_SWS_MASK	0xC
+#define RCC_CFGR_SWS_HSI	0
+#define RCC_CFGR_SWS_HSE	RCC_CFGR_SWS0
+#define RCC_CFGR_SWS_PLL	RCC_CFGR_SWS1
+#define RCC_CFGR_HPRE_SHIFT	4
+#define RCC_CFGR_PPRE1_SHIFT	10
+#define RCC_CFGR_PPRE2_SHIFT	13
+
+#define RCC_APB1ENR_PWREN	(1 << 28)
+
+/*
+ * RCC USART specific definitions
+ */
+#define RCC_ENR_USART1EN		(1 << 4)
+#define RCC_ENR_USART2EN		(1 << 17)
+#define RCC_ENR_USART3EN		(1 << 18)
+#define RCC_ENR_USART6EN		(1 <<  5)
+
+/*
+ * Offsets of some PWR registers
+ */
+#define PWR_CR1_ODEN		(1 << 16)
+#define PWR_CR1_ODSWEN		(1 << 17)
+#define PWR_CSR1_ODRDY		(1 << 16)
+#define PWR_CSR1_ODSWRDY	(1 << 17)
+
+
+/*
+ * RCC GPIO specific definitions
+ */
+#define RCC_ENR_GPIO_A_EN	(1 << 0)
+#define RCC_ENR_GPIO_B_EN	(1 << 1)
+#define RCC_ENR_GPIO_C_EN	(1 << 2)
+#define RCC_ENR_GPIO_D_EN	(1 << 3)
+#define RCC_ENR_GPIO_E_EN	(1 << 4)
+#define RCC_ENR_GPIO_F_EN	(1 << 5)
+#define RCC_ENR_GPIO_G_EN	(1 << 6)
+#define RCC_ENR_GPIO_H_EN	(1 << 7)
+#define RCC_ENR_GPIO_I_EN	(1 << 8)
+#define RCC_ENR_GPIO_J_EN	(1 << 9)
+#define RCC_ENR_GPIO_K_EN	(1 << 10)
+
+struct pll_psc {
+	u8	pll_m;
+	u16	pll_n;
+	u8	pll_p;
+	u8	pll_q;
+	u8	ahb_psc;
+	u8	apb1_psc;
+	u8	apb2_psc;
+};
+
+#define AHB_PSC_1		0
+#define AHB_PSC_2		0x8
+#define AHB_PSC_4		0x9
+#define AHB_PSC_8		0xA
+#define AHB_PSC_16		0xB
+#define AHB_PSC_64		0xC
+#define AHB_PSC_128		0xD
+#define AHB_PSC_256		0xE
+#define AHB_PSC_512		0xF
+
+#define APB_PSC_1		0
+#define APB_PSC_2		0x4
+#define APB_PSC_4		0x5
+#define APB_PSC_8		0x6
+#define APB_PSC_16		0x7
+
+#if !defined(CONFIG_STM32_HSE_HZ)
+#error "CONFIG_STM32_HSE_HZ not defined!"
+#else
+#if (CONFIG_STM32_HSE_HZ == 25000000)
+#if (CONFIG_SYS_CLK_FREQ == 200000000)
+/* 200 MHz */
+struct pll_psc sys_pll_psc = {
+	.pll_m = 25,
+	.pll_n = 400,
+	.pll_p = 2,
+	.pll_q = 8,
+	.ahb_psc = AHB_PSC_1,
+	.apb1_psc = APB_PSC_4,
+	.apb2_psc = APB_PSC_2
+};
+#endif
+#else
+#error "No PLL/Prescaler configuration for given CONFIG_STM32_HSE_HZ exists"
+#endif
+#endif
+
+int configure_clocks(void)
+{
+	/* Reset RCC configuration */
+	setbits_le32(&STM32_RCC->cr, RCC_CR_HSION);
+	writel(0, &STM32_RCC->cfgr); /* Reset CFGR */
+	clrbits_le32(&STM32_RCC->cr, (RCC_CR_HSEON | RCC_CR_CSSON
+		| RCC_CR_PLLON));
+	writel(0x24003010, &STM32_RCC->pllcfgr); /* Reset value from RM */
+	clrbits_le32(&STM32_RCC->cr, RCC_CR_HSEBYP);
+	writel(0, &STM32_RCC->cir); /* Disable all interrupts */
+
+	/* Configure for HSE+PLL operation */
+	setbits_le32(&STM32_RCC->cr, RCC_CR_HSEON);
+	while (!(readl(&STM32_RCC->cr) & RCC_CR_HSERDY))
+		;
+
+	setbits_le32(&STM32_RCC->cfgr, ((
+		sys_pll_psc.ahb_psc << RCC_CFGR_HPRE_SHIFT)
+		| (sys_pll_psc.apb1_psc << RCC_CFGR_PPRE1_SHIFT)
+		| (sys_pll_psc.apb2_psc << RCC_CFGR_PPRE2_SHIFT)));
+
+	/* Configure the main PLL */
+	uint32_t pllcfgr = 0;
+	pllcfgr = RCC_PLLCFGR_PLLSRC; /* pll source HSE */
+	pllcfgr |= sys_pll_psc.pll_m << RCC_PLLCFGR_PLLM_SHIFT;
+	pllcfgr |= sys_pll_psc.pll_n << RCC_PLLCFGR_PLLN_SHIFT;
+	pllcfgr |= ((sys_pll_psc.pll_p >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT;
+	pllcfgr |= sys_pll_psc.pll_q << RCC_PLLCFGR_PLLQ_SHIFT;
+	writel(pllcfgr, &STM32_RCC->pllcfgr);
+
+	/* Enable the main PLL */
+	setbits_le32(&STM32_RCC->cr, RCC_CR_PLLON);
+	while (!(readl(&STM32_RCC->cr) & RCC_CR_PLLRDY))
+		;
+
+	/* Enable high performance mode, System frequency up to 200 MHz */
+	setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_PWREN);
+	setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODEN);
+	/* Infinite wait! */
+	while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODRDY))
+		;
+	/* Enable the Over-drive switch */
+	setbits_le32(&STM32_PWR->cr1, PWR_CR1_ODSWEN);
+	/* Infinite wait! */
+	while (!(readl(&STM32_PWR->csr1) & PWR_CSR1_ODSWRDY))
+		;
+
+	stm32_flash_latency_cfg(5);
+	clrbits_le32(&STM32_RCC->cfgr, (RCC_CFGR_SW0 | RCC_CFGR_SW1));
+	setbits_le32(&STM32_RCC->cfgr, RCC_CFGR_SW_PLL);
+
+	while ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) !=
+			RCC_CFGR_SWS_PLL)
+		;
+
+	return 0;
+}
+
+unsigned long clock_get(enum clock clck)
+{
+	u32 sysclk = 0;
+	u32 shift = 0;
+	/* Prescaler table lookups for clock computation */
+	u8 ahb_psc_table[16] = {
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9
+	};
+	u8 apb_psc_table[8] = {
+		0, 0, 0, 0, 1, 2, 3, 4
+	};
+
+	if ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) ==
+			RCC_CFGR_SWS_PLL) {
+		u16 pllm, plln, pllp;
+		pllm = (readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
+		plln = ((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLN_MASK)
+			>> RCC_PLLCFGR_PLLN_SHIFT);
+		pllp = ((((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLP_MASK)
+			>> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1);
+		sysclk = ((CONFIG_STM32_HSE_HZ / pllm) * plln) / pllp;
+	}
+
+	switch (clck) {
+	case CLOCK_CORE:
+		return sysclk;
+		break;
+	case CLOCK_AHB:
+		shift = ahb_psc_table[(
+			(readl(&STM32_RCC->cfgr) & RCC_CFGR_AHB_PSC_MASK)
+			>> RCC_CFGR_HPRE_SHIFT)];
+		return sysclk >>= shift;
+		break;
+	case CLOCK_APB1:
+		shift = apb_psc_table[(
+			(readl(&STM32_RCC->cfgr) & RCC_CFGR_APB1_PSC_MASK)
+			>> RCC_CFGR_PPRE1_SHIFT)];
+		return sysclk >>= shift;
+		break;
+	case CLOCK_APB2:
+		shift = apb_psc_table[(
+			(readl(&STM32_RCC->cfgr) & RCC_CFGR_APB2_PSC_MASK)
+			>> RCC_CFGR_PPRE2_SHIFT)];
+		return sysclk >>= shift;
+		break;
+	default:
+		return 0;
+		break;
+	}
+}
+
+
 void clock_setup(int peripheral)
 {
 	switch (peripheral) {
 	case USART1_CLOCK_CFG:
 		setbits_le32(RCC_BASE + RCC_APB2ENR, RCC_ENR_USART1EN);
 		break;
+	case USART6_CLOCK_CFG:
+		setbits_le32(RCC_BASE + RCC_APB2ENR, RCC_ENR_USART6EN);
+		break;
 	case GPIO_A_CLOCK_CFG:
 		setbits_le32(RCC_BASE + RCC_AHB1ENR, RCC_ENR_GPIO_A_EN);
 		break;
diff --git a/arch/arm/mach-stm32/stm32f7/soc.c b/arch/arm/mach-stm32/stm32f7/soc.c
new file mode 100644
index 0000000..8baee99
--- /dev/null
+++ b/arch/arm/mach-stm32/stm32f7/soc.c
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2015
+ * Kamil Lulko, <kamil.lulko@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/armv7m.h>
+#include <asm/arch/stm32.h>
+
+u32 get_cpu_rev(void)
+{
+	return 0;
+}
+
+int arch_cpu_init(void)
+{
+	configure_clocks();
+
+	/*
+		* Configure the memory protection unit (MPU)
+		* 0x00000000 - 0xffffffff: Strong-order, Shareable
+		* 0xC0000000 - 0xC0800000: Normal, Outer and inner Non-cacheable
+	 */
+
+	 /* Disable MPU */
+	 writel(0, &V7M_MPU->ctrl);
+
+	 writel(
+		 0x00000000 /* address */
+		 | 1 << 4	/* VALID */
+		 | 0 << 0	/* REGION */
+		 , &V7M_MPU->rbar
+	 );
+
+	 /* Strong-order, Shareable */
+	 /* TEX=000, S=1, C=0, B=0*/
+	 writel(
+		 (V7M_MPU_RASR_XN_ENABLE
+			 | V7M_MPU_RASR_AP_RW_RW
+			 | 0x01 << V7M_MPU_RASR_S_SHIFT
+			 | 0x00 << V7M_MPU_RASR_TEX_SHIFT
+			 | V7M_MPU_RASR_SIZE_4GB
+			 | V7M_MPU_RASR_EN)
+		 , &V7M_MPU->rasr
+	 );
+
+	 writel(
+		 0xC0000000 /* address */
+		 | 1 << 4	/* VALID */
+		 | 1 << 0	/* REGION */
+		 , &V7M_MPU->rbar
+	 );
+
+	 /* Normal, Outer and inner Non-cacheable */
+	 /* TEX=001, S=0, C=0, B=0*/
+	 writel(
+		 (V7M_MPU_RASR_XN_ENABLE
+			 | V7M_MPU_RASR_AP_RW_RW
+			 | 0x01 << V7M_MPU_RASR_TEX_SHIFT
+			 | V7M_MPU_RASR_SIZE_8MB
+			 | V7M_MPU_RASR_EN)
+			 , &V7M_MPU->rasr
+	 );
+
+	 /* Enable MPU */
+	 writel(V7M_MPU_CTRL_ENABLE | V7M_MPU_CTRL_HFNMIENA, &V7M_MPU->ctrl);
+
+	return 0;
+}
+
+void s_init(void)
+{
+}
diff --git a/arch/nds32/include/asm/io.h b/arch/nds32/include/asm/io.h
index 04708e9..b2c4d0e 100644
--- a/arch/nds32/include/asm/io.h
+++ b/arch/nds32/include/asm/io.h
@@ -344,40 +344,6 @@
 #define insl_p(port, to, len)		insl(port, to, len)
 
 /*
- * ioremap and friends.
- *
- * ioremap takes a PCI memory address, as specified in
- * linux/Documentation/IO-mapping.txt.  If you want a
- * physical address, use __ioremap instead.
- */
-extern void *__ioremap(unsigned long offset, size_t size, unsigned long flags);
-extern void __iounmap(void *addr);
-
-/*
- * Generic ioremap support.
- *
- * Define:
- *  iomem_valid_addr(off,size)
- *  iomem_to_phys(off)
- */
-#ifdef iomem_valid_addr
-#define __arch_ioremap(off, sz, nocache)				\
-({									\
-	unsigned long _off = (off), _size = (sz);			\
-	void *_ret = (void *)0;						\
-	if (iomem_valid_addr(_off, _size))				\
-		_ret = __ioremap(iomem_to_phys(_off), _size, 0);	\
-	_ret;								\
-})
-
-#define __arch_iounmap __iounmap
-#endif
-
-#define ioremap(off, sz)		__arch_ioremap((off), (sz), 0)
-#define ioremap_nocache(off, sz)	__arch_ioremap((off), (sz), 1)
-#define iounmap(_addr)			__arch_iounmap(_addr)
-
-/*
  * DMA-consistent mapping functions.  These allocate/free a region of
  * uncached, unwrite-buffered mapped memory space for use with DMA
  * devices.  This is the "generic" version.  The PCI specific version
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index a8a90cb..d4c1ee0 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -10,8 +10,13 @@
 config SYS_CPU
 	default "sandbox"
 
+config SANDBOX_SPL
+	bool "Enable SPL for sandbox"
+	select SUPPORT_SPL
+
 config SYS_CONFIG_NAME
-	default "sandbox"
+	default "sandbox_spl" if SANDBOX_SPL
+	default "sandbox" if !SANDBOX_SPL
 
 config PCI
 	bool "PCI support"
diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk
index 16fd6d50..6d62abb 100644
--- a/arch/sandbox/config.mk
+++ b/arch/sandbox/config.mk
@@ -20,4 +20,9 @@
 	-Wl,--start-group $(u-boot-main) -Wl,--end-group \
 	$(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map
 
+cmd_u-boot-spl = (cd $(obj) && $(CC) -o $(SPL_BIN) -Wl,-T u-boot-spl.lds \
+	-Wl,--start-group $(patsubst $(obj)/%,%,$(u-boot-spl-main)) \
+	$(patsubst $(obj)/%,%,$(u-boot-spl-platdata)) -Wl,--end-group \
+	$(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot-spl.map -Wl,--gc-sections)
+
 CONFIG_ARCH_DEVICE_TREE := sandbox
diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile
index 1b42fee..db43633 100644
--- a/arch/sandbox/cpu/Makefile
+++ b/arch/sandbox/cpu/Makefile
@@ -8,6 +8,7 @@
 #
 
 obj-y	:= cpu.o os.o start.o state.o
+obj-$(CONFIG_SPL_BUILD)	+= spl.o
 obj-$(CONFIG_ETH_SANDBOX_RAW)	+= eth-raw-os.o
 obj-$(CONFIG_SANDBOX_SDL)	+= sdl.o
 
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index 196f3e1..2def722 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -4,10 +4,12 @@
  */
 #define DEBUG
 #include <common.h>
-#include <dm/root.h>
+#include <errno.h>
+#include <libfdt.h>
 #include <os.h>
 #include <asm/io.h>
 #include <asm/state.h>
+#include <dm/root.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -55,7 +57,7 @@
 
 void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
 {
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && !defined(CONFIG_SPL_BUILD)
 	unsigned long plen = len;
 	void *ptr;
 
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 8a4d719..2d63dd8 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -541,6 +541,57 @@
 	return unlink(fname);
 }
 
+int os_find_u_boot(char *fname, int maxlen)
+{
+	struct sandbox_state *state = state_get_current();
+	const char *progname = state->argv[0];
+	int len = strlen(progname);
+	char *p;
+	int fd;
+
+	if (len >= maxlen || len < 4)
+		return -ENOSPC;
+
+	/* Look for 'u-boot' in the same directory as 'u-boot-spl' */
+	strcpy(fname, progname);
+	if (!strcmp(fname + len - 4, "-spl")) {
+		fname[len - 4] = '\0';
+		fd = os_open(fname, O_RDONLY);
+		if (fd >= 0) {
+			close(fd);
+			return 0;
+		}
+	}
+
+	/* Look for 'u-boot' in the parent directory of spl/ */
+	p = strstr(fname, "/spl/");
+	if (p) {
+		strcpy(p, p + 4);
+		fd = os_open(fname, O_RDONLY);
+		if (fd >= 0) {
+			close(fd);
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+int os_spl_to_uboot(const char *fname)
+{
+	struct sandbox_state *state = state_get_current();
+	char *argv[state->argc + 1];
+	int ret;
+
+	memcpy(argv, state->argv, sizeof(char *) * (state->argc + 1));
+	argv[0] = (char *)fname;
+	ret = execv(fname, argv);
+	if (ret)
+		return ret;
+
+	return unlink(fname);
+}
+
 void os_localtime(struct rtc_time *rt)
 {
 	time_t t = time(NULL);
diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c
new file mode 100644
index 0000000..e8349c0
--- /dev/null
+++ b/arch/sandbox/cpu/spl.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <os.h>
+#include <spl.h>
+#include <asm/spl.h>
+#include <asm/state.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void board_init_f(ulong flag)
+{
+	struct sandbox_state *state = state_get_current();
+
+	gd->arch.ram_buf = state->ram_buf;
+	gd->ram_size = state->ram_size;
+}
+
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_BOARD;
+}
+
+void spl_board_announce_boot_device(void)
+{
+	char fname[256];
+	int ret;
+
+	ret = os_find_u_boot(fname, sizeof(fname));
+	if (ret) {
+		printf("(%s not found, error %d)\n", fname, ret);
+		return;
+	}
+	printf("%s\n", fname);
+}
+
+int spl_board_load_image(void)
+{
+	char fname[256];
+	int ret;
+
+	ret = os_find_u_boot(fname, sizeof(fname));
+	if (ret)
+		return ret;
+
+	/* Hopefully this will not return */
+	return os_spl_to_uboot(fname);
+}
+
+void spl_board_init(void)
+{
+	struct udevice *dev;
+
+	preloader_console_init();
+
+	/*
+	* Scan all the devices so that we can output their platform data. See
+	* sandbox_spl_probe().
+	*/
+	for (uclass_first_device(UCLASS_MISC, &dev);
+	dev;
+	uclass_next_device(&dev))
+		;
+}
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c
index 969618e..6e4ec01 100644
--- a/arch/sandbox/cpu/start.c
+++ b/arch/sandbox/cpu/start.c
@@ -73,6 +73,7 @@
 }
 SANDBOX_CMDLINE_OPT_SHORT(help, 'h', 0, "Display help");
 
+#ifndef CONFIG_SPL_BUILD
 int sandbox_main_loop_init(void)
 {
 	struct sandbox_state *state = state_get_current();
@@ -97,6 +98,7 @@
 
 	return 0;
 }
+#endif
 
 static int sandbox_cmdline_cb_boot(struct sandbox_state *state,
 				      const char *arg)
diff --git a/arch/sandbox/cpu/u-boot-spl.lds b/arch/sandbox/cpu/u-boot-spl.lds
new file mode 100644
index 0000000..7e92b4a
--- /dev/null
+++ b/arch/sandbox/cpu/u-boot-spl.lds
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2011-2012 The Chromium OS Authors.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+SECTIONS
+{
+
+	. = ALIGN(4);
+	.u_boot_list : {
+		KEEP(*(SORT(.u_boot_list*)));
+	}
+
+	__u_boot_sandbox_option_start = .;
+	_u_boot_sandbox_getopt : { *(.u_boot_sandbox_getopt) }
+	__u_boot_sandbox_option_end = .;
+
+	__bss_start = .;
+}
+
+INSERT BEFORE .data;
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 2ae4014..e6d336f 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -172,6 +172,37 @@
 		};
 	};
 
+	spl-test {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		boolval;
+		intval = <1>;
+		intarray = <2 3 4>;
+		byteval = [05];
+		bytearray = [06];
+		longbytearray = [09 0a 0b 0c 0d 0e 0f 10 11];
+		stringval = "message";
+		stringarray = "multi-word", "message";
+	};
+
+	spl-test2 {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		intval = <3>;
+		intarray = <5>;
+		byteval = [08];
+		bytearray = [01 23 34];
+		longbytearray = [09 0a 0b 0c];
+		stringval = "message2";
+		stringarray = "another", "multi-word", "message";
+	};
+
+	spl-test3 {
+		u-boot,dm-pre-reloc;
+		compatible = "sandbox,spl-test";
+		stringarray = "one";
+	};
+
 	square {
 		compatible = "demo-shape";
 		colour = "blue";
diff --git a/arch/sandbox/include/asm/spl.h b/arch/sandbox/include/asm/spl.h
new file mode 100644
index 0000000..59f2401
--- /dev/null
+++ b/arch/sandbox/include/asm/spl.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __asm_spl_h
+#define __asm_spl_h
+
+#define CONFIG_SPL_BOARD_LOAD_IMAGE
+
+/**
+ * Board-specific load method for boards that have a special way of loading
+ * U-Boot, which does not fit with the existing SPL code.
+ *
+ * @return 0 on success, negative errno value on failure.
+ */
+int spl_board_load_image(void);
+
+enum {
+	BOOT_DEVICE_BOARD,
+};
+
+#endif
diff --git a/arch/sandbox/lib/Makefile b/arch/sandbox/lib/Makefile
index 96761e2..7820c55 100644
--- a/arch/sandbox/lib/Makefile
+++ b/arch/sandbox/lib/Makefile
@@ -8,5 +8,7 @@
 #
 
 obj-y	+= interrupts.o
+ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_PCI)	+= pci_io.o
+endif
 obj-$(CONFIG_CMD_BOOTM) += bootm.o
diff --git a/arch/sandbox/lib/bootm.c b/arch/sandbox/lib/bootm.c
index d49c927..0c9a797 100644
--- a/arch/sandbox/lib/bootm.c
+++ b/arch/sandbox/lib/bootm.c
@@ -56,7 +56,7 @@
 		bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 		printf("## Transferring control to Linux (at address %08lx)...\n",
 		       images->ep);
-		reset_cpu(0);
+		printf("sandbox: continuing, as we cannot run Linux\n");
 	}
 
 	return 0;
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index 0a00db3..5dc27be 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -128,39 +128,6 @@
 #define in_8(port)			inb(port)
 #define in_le16(port)		inw(port)
 #define in_le32(port)		inl(port)
-/*
- * ioremap and friends.
- *
- * ioremap takes a PCI memory address, as specified in
- * linux/Documentation/IO-mapping.txt.  If you want a
- * physical address, use __ioremap instead.
- */
-extern void *__ioremap(unsigned long offset, size_t size, unsigned long flags);
-extern void __iounmap(void *addr);
-
-/*
- * Generic ioremap support.
- *
- * Define:
- *  iomem_valid_addr(off,size)
- *  iomem_to_phys(off)
- */
-#ifdef iomem_valid_addr
-#define __arch_ioremap(off, sz, nocache)				\
-({								\
-	unsigned long _off = (off), _size = (sz);		\
-	void *_ret = (void *)0;					\
-	if (iomem_valid_addr(_off, _size))			\
-		_ret = __ioremap(iomem_to_phys(_off), _size, 0);	\
-	_ret;							\
-})
-
-#define __arch_iounmap __iounmap
-#endif
-
-#define ioremap(off, sz)			__arch_ioremap((off), (sz), 0)
-#define ioremap_nocache(off, sz)		__arch_ioremap((off), (sz), 1)
-#define iounmap(_addr)			__arch_iounmap(_addr)
 
 /*
  * DMA-consistent mapping functions.  These allocate/free a region of
diff --git a/board/sandbox/MAINTAINERS b/board/sandbox/MAINTAINERS
index f5db773..4dcbf4b 100644
--- a/board/sandbox/MAINTAINERS
+++ b/board/sandbox/MAINTAINERS
@@ -11,3 +11,10 @@
 F:	board/sandbox/
 F:	include/configs/sandbox.h
 F:	configs/sandbox_noblk_defconfig
+
+SANDBOX SPL BOARD
+M:	Simon Glass <sjg@chromium.org>
+S:	Maintained
+F:	board/sandbox/
+F:	include/configs/sandbox_spl.h
+F:	configs/sandbox_spl_defconfig
diff --git a/board/st/stm32f746-disco/stm32f746-disco.c b/board/st/stm32f746-disco/stm32f746-disco.c
index 0e04d14..47aa058 100644
--- a/board/st/stm32f746-disco/stm32f746-disco.c
+++ b/board/st/stm32f746-disco/stm32f746-disco.c
@@ -10,6 +10,8 @@
 #include <asm/armv7m.h>
 #include <asm/arch/stm32.h>
 #include <asm/arch/gpio.h>
+#include <asm/arch/rcc.h>
+#include <asm/arch/fmc.h>
 #include <dm/platdata.h>
 #include <dm/platform_data/serial_stm32x7.h>
 #include <asm/arch/stm32_periph.h>
@@ -30,12 +32,227 @@
 	.otype = STM32_GPIO_OTYPE_PP,
 	.speed = STM32_GPIO_SPEED_50M,
 	.pupd = STM32_GPIO_PUPD_UP,
-	.af = STM32_GPIO_AF7
+	.af = STM32_GPIO_AF8
 };
 
+const struct stm32_gpio_ctl gpio_ctl_fmc = {
+	.mode = STM32_GPIO_MODE_AF,
+	.otype = STM32_GPIO_OTYPE_PP,
+	.speed = STM32_GPIO_SPEED_100M,
+	.pupd = STM32_GPIO_PUPD_NO,
+	.af = STM32_GPIO_AF12
+};
+
+static const struct stm32_gpio_dsc ext_ram_fmc_gpio[] = {
+	/* Chip is LQFP144, see DM00077036.pdf for details */
+	{STM32_GPIO_PORT_D, STM32_GPIO_PIN_10},	/* 79, FMC_D15 */
+	{STM32_GPIO_PORT_D, STM32_GPIO_PIN_9},	/* 78, FMC_D14 */
+	{STM32_GPIO_PORT_D, STM32_GPIO_PIN_8},	/* 77, FMC_D13 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_15},	/* 68, FMC_D12 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_14},	/* 67, FMC_D11 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_13},	/* 66, FMC_D10 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_12},	/* 65, FMC_D9 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_11},	/* 64, FMC_D8 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_10},	/* 63, FMC_D7 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_9},	/* 60, FMC_D6 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_8},	/* 59, FMC_D5 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_7},	/* 58, FMC_D4 */
+	{STM32_GPIO_PORT_D, STM32_GPIO_PIN_1},	/* 115, FMC_D3 */
+	{STM32_GPIO_PORT_D, STM32_GPIO_PIN_0},	/* 114, FMC_D2 */
+	{STM32_GPIO_PORT_D, STM32_GPIO_PIN_15},	/* 86, FMC_D1 */
+	{STM32_GPIO_PORT_D, STM32_GPIO_PIN_14},	/* 85, FMC_D0 */
+
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_1},	/* 142, FMC_NBL1 */
+	{STM32_GPIO_PORT_E, STM32_GPIO_PIN_0},	/* 141, FMC_NBL0 */
+
+	{STM32_GPIO_PORT_G, STM32_GPIO_PIN_5},	/* 90, FMC_A15, BA1 */
+	{STM32_GPIO_PORT_G, STM32_GPIO_PIN_4},	/* 89, FMC_A14, BA0 */
+
+	{STM32_GPIO_PORT_G, STM32_GPIO_PIN_1},	/* 57, FMC_A11 */
+	{STM32_GPIO_PORT_G, STM32_GPIO_PIN_0},	/* 56, FMC_A10 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_15},	/* 55, FMC_A9 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_14},	/* 54, FMC_A8 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_13},	/* 53, FMC_A7 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_12},	/* 50, FMC_A6 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_5},	/* 15, FMC_A5 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_4},	/* 14, FMC_A4 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_3},	/* 13, FMC_A3 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_2},	/* 12, FMC_A2 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_1},	/* 11, FMC_A1 */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_0},	/* 10, FMC_A0 */
+
+	{STM32_GPIO_PORT_H, STM32_GPIO_PIN_3},	/* 136, SDRAM_NE */
+	{STM32_GPIO_PORT_F, STM32_GPIO_PIN_11},	/* 49, SDRAM_NRAS */
+	{STM32_GPIO_PORT_G, STM32_GPIO_PIN_15},	/* 132, SDRAM_NCAS */
+	{STM32_GPIO_PORT_H, STM32_GPIO_PIN_5},	/* 26, SDRAM_NWE */
+	{STM32_GPIO_PORT_C, STM32_GPIO_PIN_3},	/* 135, SDRAM_CKE */
+
+	{STM32_GPIO_PORT_G, STM32_GPIO_PIN_8},	/* 93, SDRAM_CLK */
+};
+
+static int fmc_setup_gpio(void)
+{
+	int rv = 0;
+	int i;
+
+	clock_setup(GPIO_B_CLOCK_CFG);
+	clock_setup(GPIO_C_CLOCK_CFG);
+	clock_setup(GPIO_D_CLOCK_CFG);
+	clock_setup(GPIO_E_CLOCK_CFG);
+	clock_setup(GPIO_F_CLOCK_CFG);
+	clock_setup(GPIO_G_CLOCK_CFG);
+	clock_setup(GPIO_H_CLOCK_CFG);
+
+	for (i = 0; i < ARRAY_SIZE(ext_ram_fmc_gpio); i++) {
+		rv = stm32_gpio_config(&ext_ram_fmc_gpio[i],
+				&gpio_ctl_fmc);
+		if (rv)
+			goto out;
+	}
+
+out:
+	return rv;
+}
+
+/*
+ * STM32 RCC FMC specific definitions
+ */
+#define RCC_ENR_FMC	(1 << 0)	/* FMC module clock  */
+
+static inline u32 _ns2clk(u32 ns, u32 freq)
+{
+	u32 tmp = freq/1000000;
+	return (tmp * ns) / 1000;
+}
+
+#define NS2CLK(ns) (_ns2clk(ns, freq))
+
+/*
+ * Following are timings for IS42S16400J, from corresponding datasheet
+ */
+#define SDRAM_CAS	3	/* 3 cycles */
+#define SDRAM_NB	1	/* Number of banks */
+#define SDRAM_MWID	1	/* 16 bit memory */
+
+#define SDRAM_NR	0x1	/* 12-bit row */
+#define SDRAM_NC	0x0	/* 8-bit col */
+#define SDRAM_RBURST	0x1	/* Single read requests always as bursts */
+#define SDRAM_RPIPE	0x0	/* No HCLK clock cycle delay */
+
+#define SDRAM_TRRD	NS2CLK(12)
+#define SDRAM_TRCD	NS2CLK(18)
+#define SDRAM_TRP	NS2CLK(18)
+#define SDRAM_TRAS	NS2CLK(42)
+#define SDRAM_TRC	NS2CLK(60)
+#define SDRAM_TRFC	NS2CLK(60)
+#define SDRAM_TCDL	(1 - 1)
+#define SDRAM_TRDL	NS2CLK(12)
+#define SDRAM_TBDL	(1 - 1)
+#define SDRAM_TREF	(NS2CLK(64000000 / 8192) - 20)
+#define SDRAM_TCCD	(1 - 1)
+
+#define SDRAM_TXSR	SDRAM_TRFC	/* Row cycle time after precharge */
+#define SDRAM_TMRD	1		/* Page 10, Mode Register Set */
+
+
+/* Last data in to row precharge, need also comply ineq on page 1648 */
+#define SDRAM_TWR	max(\
+	(int)max((int)SDRAM_TRDL, (int)(SDRAM_TRAS - SDRAM_TRCD)), \
+	(int)(SDRAM_TRC - SDRAM_TRCD - SDRAM_TRP)\
+)
+
+
+#define SDRAM_MODE_BL_SHIFT	0
+#define SDRAM_MODE_CAS_SHIFT	4
+#define SDRAM_MODE_BL		0
+#define SDRAM_MODE_CAS		SDRAM_CAS
+
+int dram_init(void)
+{
+	u32 freq;
+	int rv;
+
+	rv = fmc_setup_gpio();
+	if (rv)
+		return rv;
+
+	setbits_le32(RCC_BASE + RCC_AHB3ENR, RCC_ENR_FMC);
+
+	/*
+	 * Get frequency for NS2CLK calculation.
+	 */
+	freq = clock_get(CLOCK_AHB) / CONFIG_SYS_RAM_FREQ_DIV;
+
+	writel(
+		CONFIG_SYS_RAM_FREQ_DIV << FMC_SDCR_SDCLK_SHIFT
+		| SDRAM_CAS << FMC_SDCR_CAS_SHIFT
+		| SDRAM_NB << FMC_SDCR_NB_SHIFT
+		| SDRAM_MWID << FMC_SDCR_MWID_SHIFT
+		| SDRAM_NR << FMC_SDCR_NR_SHIFT
+		| SDRAM_NC << FMC_SDCR_NC_SHIFT
+		| SDRAM_RPIPE << FMC_SDCR_RPIPE_SHIFT
+		| SDRAM_RBURST << FMC_SDCR_RBURST_SHIFT,
+		&STM32_SDRAM_FMC->sdcr1);
+
+	writel(
+		SDRAM_TRCD << FMC_SDTR_TRCD_SHIFT
+		| SDRAM_TRP << FMC_SDTR_TRP_SHIFT
+		| SDRAM_TWR << FMC_SDTR_TWR_SHIFT
+		| SDRAM_TRC << FMC_SDTR_TRC_SHIFT
+		| SDRAM_TRAS << FMC_SDTR_TRAS_SHIFT
+		| SDRAM_TXSR << FMC_SDTR_TXSR_SHIFT
+		| SDRAM_TMRD << FMC_SDTR_TMRD_SHIFT,
+		&STM32_SDRAM_FMC->sdtr1);
+
+	writel(FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_START_CLOCK,
+	       &STM32_SDRAM_FMC->sdcmr);
+
+	udelay(200);	/* 200 us delay, page 10, "Power-Up" */
+	FMC_BUSY_WAIT();
+
+	writel(FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_PRECHARGE,
+	       &STM32_SDRAM_FMC->sdcmr);
+
+	udelay(100);
+	FMC_BUSY_WAIT();
+
+	writel((FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_AUTOREFRESH
+		| 7 << FMC_SDCMR_NRFS_SHIFT), &STM32_SDRAM_FMC->sdcmr);
+
+	udelay(100);
+	FMC_BUSY_WAIT();
+
+	writel(FMC_SDCMR_BANK_1 | (SDRAM_MODE_BL << SDRAM_MODE_BL_SHIFT
+		| SDRAM_MODE_CAS << SDRAM_MODE_CAS_SHIFT)
+		<< FMC_SDCMR_MODE_REGISTER_SHIFT | FMC_SDCMR_MODE_WRITE_MODE,
+		&STM32_SDRAM_FMC->sdcmr);
+
+	udelay(100);
+
+	FMC_BUSY_WAIT();
+
+	writel(FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_NORMAL,
+	       &STM32_SDRAM_FMC->sdcmr);
+
+	FMC_BUSY_WAIT();
+
+	/* Refresh timer */
+	writel(SDRAM_TREF, &STM32_SDRAM_FMC->sdrtr);
+
+	/*
+	 * Fill in global info with description of SRAM configuration
+	 */
+	gd->bd->bi_dram[0].start = CONFIG_SYS_RAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_RAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_RAM_SIZE;
+
+	return rv;
+}
+
 static const struct stm32_gpio_dsc usart_gpio[] = {
-	{STM32_GPIO_PORT_A, STM32_GPIO_PIN_9},	/* TX */
-	{STM32_GPIO_PORT_B, STM32_GPIO_PIN_7},	/* RX */
+	{STM32_GPIO_PORT_C, STM32_GPIO_PIN_6},	/* TX */
+	{STM32_GPIO_PORT_C, STM32_GPIO_PIN_7},	/* RX */
 };
 
 int uart_setup_gpio(void)
@@ -43,8 +260,7 @@
 	int i;
 	int rv = 0;
 
-	clock_setup(GPIO_A_CLOCK_CFG);
-	clock_setup(GPIO_B_CLOCK_CFG);
+	clock_setup(GPIO_C_CLOCK_CFG);
 	for (i = 0; i < ARRAY_SIZE(usart_gpio); i++) {
 		rv = stm32_gpio_config(&usart_gpio[i], &gpio_ctl_usart);
 		if (rv)
@@ -56,7 +272,7 @@
 }
 
 static const struct stm32x7_serial_platdata serial_platdata = {
-	.base = (struct stm32_usart *)USART1_BASE,
+	.base = (struct stm32_usart *)USART6_BASE,
 	.clock = CONFIG_SYS_CLK_FREQ,
 };
 
@@ -75,7 +291,7 @@
 	int res;
 
 	res = uart_setup_gpio();
-	clock_setup(USART1_CLOCK_CFG);
+	clock_setup(USART6_CLOCK_CFG);
 	if (res)
 		return res;
 
@@ -88,12 +304,3 @@
 
 	return 0;
 }
-
-int dram_init(void)
-{
-	gd->bd->bi_dram[0].start = CONFIG_SYS_RAM_BASE;
-	gd->bd->bi_dram[0].size  = CONFIG_SYS_RAM_SIZE;
-
-	gd->ram_size = CONFIG_SYS_RAM_SIZE;
-	return 0;
-}
diff --git a/board/ti/am43xx/board.c b/board/ti/am43xx/board.c
index f005762..27c311e 100644
--- a/board/ti/am43xx/board.c
+++ b/board/ti/am43xx/board.c
@@ -13,6 +13,7 @@
 #include <asm/errno.h>
 #include <spl.h>
 #include <usb.h>
+#include <asm/omap_sec_common.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/arch/mux.h>
@@ -862,3 +863,10 @@
 		return -1;
 }
 #endif
+
+#ifdef CONFIG_TI_SECURE_DEVICE
+void board_fit_image_post_process(void **p_image, size_t *p_size)
+{
+	secure_boot_verify_image(p_image, p_size);
+}
+#endif
diff --git a/board/ti/am57xx/board.c b/board/ti/am57xx/board.c
index 08cf14d..927d136 100644
--- a/board/ti/am57xx/board.c
+++ b/board/ti/am57xx/board.c
@@ -13,6 +13,7 @@
 #include <sata.h>
 #include <usb.h>
 #include <asm/omap_common.h>
+#include <asm/omap_sec_common.h>
 #include <asm/emif.h>
 #include <asm/gpio.h>
 #include <asm/arch/gpio.h>
@@ -750,3 +751,10 @@
 		return -1;
 }
 #endif
+
+#ifdef CONFIG_TI_SECURE_DEVICE
+void board_fit_image_post_process(void **p_image, size_t *p_size)
+{
+	secure_boot_verify_image(p_image, p_size);
+}
+#endif
diff --git a/board/ti/dra7xx/evm.c b/board/ti/dra7xx/evm.c
index 6a4d027..99e8254 100644
--- a/board/ti/dra7xx/evm.c
+++ b/board/ti/dra7xx/evm.c
@@ -17,6 +17,8 @@
 #include <asm/gpio.h>
 #include <usb.h>
 #include <linux/usb/gadget.h>
+#include <asm/omap_common.h>
+#include <asm/omap_sec_common.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/dra7xx_iodelay.h>
 #include <asm/emif.h>
@@ -834,3 +836,10 @@
 		return -1;
 }
 #endif
+
+#ifdef CONFIG_TI_SECURE_DEVICE
+void board_fit_image_post_process(void **p_image, size_t *p_size)
+{
+	secure_boot_verify_image(p_image, p_size);
+}
+#endif
diff --git a/common/board_f.c b/common/board_f.c
index d405b5b..8d936cc 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -117,10 +117,11 @@
 # if defined(CONFIG_HW_WATCHDOG) && (defined(CONFIG_BLACKFIN) || \
 	defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \
 	defined(CONFIG_SH) || defined(CONFIG_AT91SAM9_WATCHDOG) || \
+	defined(CONFIG_DESIGNWARE_WATCHDOG) || \
 	defined(CONFIG_IMX_WATCHDOG))
 	hw_watchdog_init();
-# endif
 	puts("       Watchdog enabled\n");
+# endif
 	WATCHDOG_RESET();
 
 	return 0;
diff --git a/common/bootm.c b/common/bootm.c
index 2431019..9ed6428 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -635,10 +635,6 @@
 			goto err;
 		else if (ret == BOOTM_ERR_OVERLAP)
 			ret = 0;
-#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
-		if (images->os.os == IH_OS_LINUX)
-			fixup_silent_linux();
-#endif
 	}
 
 	/* Relocate the ramdisk */
@@ -678,13 +674,19 @@
 		return 1;
 	}
 
+
 	/* Call various other states that are not generally used */
 	if (!ret && (states & BOOTM_STATE_OS_CMDLINE))
 		ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);
 	if (!ret && (states & BOOTM_STATE_OS_BD_T))
 		ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
-	if (!ret && (states & BOOTM_STATE_OS_PREP))
+	if (!ret && (states & BOOTM_STATE_OS_PREP)) {
+#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
+		if (images->os.os == IH_OS_LINUX)
+			fixup_silent_linux();
+#endif
 		ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
+	}
 
 #ifdef CONFIG_TRACE
 	/* Pretend to run the OS, then run a user command */
diff --git a/common/bootm_os.c b/common/bootm_os.c
index 9ec84bd..e3f5a46 100644
--- a/common/bootm_os.c
+++ b/common/bootm_os.c
@@ -481,6 +481,7 @@
 
 	/* Stand-alone may return when 'autostart' is 'no' */
 	if (images->os.type == IH_TYPE_STANDALONE ||
+	    IS_ENABLED(CONFIG_SANDBOX) ||
 	    state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
 		return 0;
 	bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
diff --git a/common/image.c b/common/image.c
index 0be09e5..af155b2 100644
--- a/common/image.c
+++ b/common/image.c
@@ -69,7 +69,7 @@
 #endif
 
 static const table_entry_t uimage_arch[] = {
-	{	IH_ARCH_INVALID,	NULL,		"Invalid ARCH",	},
+	{	IH_ARCH_INVALID,	"invalid",	"Invalid ARCH",	},
 	{	IH_ARCH_ALPHA,		"alpha",	"Alpha",	},
 	{	IH_ARCH_ARM,		"arm",		"ARM",		},
 	{	IH_ARCH_I386,		"x86",		"Intel x86",	},
@@ -97,7 +97,7 @@
 };
 
 static const table_entry_t uimage_os[] = {
-	{	IH_OS_INVALID,	NULL,		"Invalid OS",		},
+	{	IH_OS_INVALID,	"invalid",	"Invalid OS",		},
 	{	IH_OS_LINUX,	"linux",	"Linux",		},
 #if defined(CONFIG_LYNXKDI) || defined(USE_HOSTCC)
 	{	IH_OS_LYNXOS,	"lynxos",	"LynxOS",		},
@@ -144,7 +144,7 @@
 	{	IH_TYPE_KERNEL_NOLOAD, "kernel_noload",  "Kernel Image (no loading done)", },
 	{	IH_TYPE_KWBIMAGE,   "kwbimage",   "Kirkwood Boot Image",},
 	{	IH_TYPE_IMXIMAGE,   "imximage",   "Freescale i.MX Boot Image",},
-	{	IH_TYPE_INVALID,    NULL,	  "Invalid Image",	},
+	{	IH_TYPE_INVALID,    "invalid",	  "Invalid Image",	},
 	{	IH_TYPE_MULTI,	    "multi",	  "Multi-File Image",	},
 	{	IH_TYPE_OMAPIMAGE,  "omapimage",  "TI OMAP SPL With GP CH",},
 	{	IH_TYPE_PBLIMAGE,   "pblimage",   "Freescale PBL Boot Image",},
@@ -176,6 +176,19 @@
 	{	-1,		"",		"",			},
 };
 
+struct table_info {
+	const char *desc;
+	int count;
+	const table_entry_t *table;
+};
+
+static const struct table_info table_info[IH_COUNT] = {
+	{ "architecture", IH_ARCH_COUNT, uimage_arch },
+	{ "compression", IH_COMP_COUNT, uimage_comp },
+	{ "operating system", IH_OS_COUNT, uimage_os },
+	{ "image type", IH_TYPE_COUNT, uimage_type },
+};
+
 /*****************************************************************************/
 /* Legacy format routines */
 /*****************************************************************************/
@@ -570,6 +583,74 @@
 	return NULL;
 }
 
+static const char *unknown_msg(enum ih_category category)
+{
+	static char msg[30];
+
+	strcpy(msg, "Unknown ");
+	strcat(msg, table_info[category].desc);
+
+	return msg;
+}
+
+/**
+ * get_cat_table_entry_name - translate entry id to long name
+ * @category: category to look up (enum ih_category)
+ * @id: entry id to be translated
+ *
+ * This will scan the translation table trying to find the entry that matches
+ * the given id.
+ *
+ * @retur long entry name if translation succeeds; error string on failure
+ */
+const char *genimg_get_cat_name(enum ih_category category, uint id)
+{
+	const table_entry_t *entry;
+
+	entry = get_table_entry(table_info[category].table, id);
+	if (!entry)
+		return unknown_msg(category);
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+	return entry->lname;
+#else
+	return entry->lname + gd->reloc_off;
+#endif
+}
+
+/**
+ * get_cat_table_entry_short_name - translate entry id to short name
+ * @category: category to look up (enum ih_category)
+ * @id: entry id to be translated
+ *
+ * This will scan the translation table trying to find the entry that matches
+ * the given id.
+ *
+ * @retur short entry name if translation succeeds; error string on failure
+ */
+const char *genimg_get_cat_short_name(enum ih_category category, uint id)
+{
+	const table_entry_t *entry;
+
+	entry = get_table_entry(table_info[category].table, id);
+	if (!entry)
+		return unknown_msg(category);
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+	return entry->sname;
+#else
+	return entry->sname + gd->reloc_off;
+#endif
+}
+
+int genimg_get_cat_count(enum ih_category category)
+{
+	return table_info[category].count;
+}
+
+const char *genimg_get_cat_desc(enum ih_category category)
+{
+	return table_info[category].desc;
+}
+
 /**
  * get_table_entry_name - translate entry id to long name
  * @table: pointer to a translation table for entries of a specific type
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 0039716..14320fe 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -13,7 +13,6 @@
 #include <nand.h>
 #include <fat.h>
 #include <version.h>
-#include <i2c.h>
 #include <image.h>
 #include <malloc.h>
 #include <dm/root.h>
@@ -203,7 +202,7 @@
 	gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;
 	gd->malloc_ptr = 0;
 #endif
-	if (CONFIG_IS_ENABLED(OF_CONTROL)) {
+	if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
 		ret = fdtdec_setup();
 		if (ret) {
 			debug("fdtdec_setup() returned error %d\n", ret);
@@ -211,7 +210,8 @@
 		}
 	}
 	if (IS_ENABLED(CONFIG_SPL_DM)) {
-		ret = dm_init_and_scan(true);
+		/* With CONFIG_OF_PLATDATA, bring in all devices */
+		ret = dm_init_and_scan(!CONFIG_IS_ENABLED(OF_PLATDATA));
 		if (ret) {
 			debug("dm_init_and_scan() returned error %d\n", ret);
 			return ret;
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 9874708..069e94d 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -132,7 +132,7 @@
 	int data_offset, data_size;
 	int base_offset, align_len = ARCH_DMA_MINALIGN - 1;
 	int src_sector;
-	void *dst;
+	void *dst, *src;
 
 	/*
 	 * Figure out where the external images start. This is the base for the
@@ -206,8 +206,13 @@
 		return -EIO;
 	debug("image: dst=%p, data_offset=%x, size=%x\n", dst, data_offset,
 	      data_size);
-	memcpy(dst, dst + get_aligned_image_overhead(info, data_offset),
-	       data_size);
+	src = dst + get_aligned_image_overhead(info, data_offset);
+
+#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
+	board_fit_image_post_process((void **)&src, (size_t *)&data_size);
+#endif
+
+	memcpy(dst, src, data_size);
 
 	/* Figure out which device tree the board wants to use */
 	fdt_len = spl_fit_select_fdt(fit, images, &fdt_offset);
@@ -236,8 +241,14 @@
 	 */
 	debug("fdt: dst=%p, data_offset=%x, size=%x\n", dst, fdt_offset,
 	      fdt_len);
-	memcpy(load_ptr + data_size,
-	       dst + get_aligned_image_overhead(info, fdt_offset), fdt_len);
+	src = dst + get_aligned_image_overhead(info, fdt_offset);
+	dst = load_ptr + data_size;
+
+#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
+	board_fit_image_post_process((void **)&src, (size_t *)&fdt_len);
+#endif
+
+	memcpy(dst, src, fdt_len);
 
 	return 0;
 }
diff --git a/configs/am43xx_hs_evm_defconfig b/configs/am43xx_hs_evm_defconfig
index 4856a19..68dfb6c 100644
--- a/configs/am43xx_hs_evm_defconfig
+++ b/configs/am43xx_hs_evm_defconfig
@@ -13,6 +13,7 @@
 CONFIG_FIT=y
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=1, NAND"
 CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
 # CONFIG_CMD_IMLS is not set
diff --git a/configs/am57xx_hs_evm_defconfig b/configs/am57xx_hs_evm_defconfig
index e01e504..01a4701 100644
--- a/configs/am57xx_hs_evm_defconfig
+++ b/configs/am57xx_hs_evm_defconfig
@@ -40,4 +40,5 @@
 CONFIG_FIT=y
 CONFIG_SPL_OF_LIBFDT=y
 CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
 CONFIG_OF_LIST="am57xx-beagle-x15"
diff --git a/configs/da850evm_defconfig b/configs/da850evm_defconfig
index 0e281a5..40ab975 100644
--- a/configs/da850evm_defconfig
+++ b/configs/da850evm_defconfig
@@ -5,6 +5,7 @@
 CONFIG_SYS_EXTRA_OPTIONS="MAC_ADDR_IN_SPIFLASH"
 CONFIG_BOOTDELAY=3
 CONFIG_HUSH_PARSER=y
+CONFIG_CMD_BOOTZ=y
 CONFIG_SYS_PROMPT="U-Boot > "
 # CONFIG_CMD_IMLS is not set
 CONFIG_CMD_ASKENV=y
diff --git a/configs/dra7xx_hs_evm_defconfig b/configs/dra7xx_hs_evm_defconfig
index 6933ab5..eb01f41 100644
--- a/configs/dra7xx_hs_evm_defconfig
+++ b/configs/dra7xx_hs_evm_defconfig
@@ -58,4 +58,5 @@
 CONFIG_FIT=y
 CONFIG_SPL_OF_LIBFDT=y
 CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
 CONFIG_OF_LIST="dra7-evm dra72-evm"
diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig
index 4af9120..bdafc71 100644
--- a/configs/firefly-rk3288_defconfig
+++ b/configs/firefly-rk3288_defconfig
@@ -69,3 +69,6 @@
 CONFIG_USE_TINY_PRINTF=y
 CONFIG_CMD_DHRYSTONE=y
 CONFIG_ERRNO_STR=y
+CONFIG_SPL_OF_PLATDATA=y
+# CONFIG_SPL_OF_LIBFDT is not set
+CONFIG_ROCKCHIP_SERIAL=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
new file mode 100644
index 0000000..0f6dda8
--- /dev/null
+++ b/configs/sandbox_spl_defconfig
@@ -0,0 +1,183 @@
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_MMC=y
+CONFIG_SANDBOX_SPL=y
+CONFIG_PCI=y
+CONFIG_DEFAULT_DEVICE_TREE="sandbox"
+CONFIG_I8042_KEYB=y
+CONFIG_SPL=y
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_SPL_LOAD_FIT=y
+CONFIG_BOOTSTAGE=y
+CONFIG_BOOTSTAGE_REPORT=y
+CONFIG_BOOTSTAGE_USER_COUNT=0x20
+CONFIG_BOOTSTAGE_FDT=y
+CONFIG_BOOTSTAGE_STASH=y
+CONFIG_BOOTSTAGE_STASH_ADDR=0x0
+CONFIG_BOOTSTAGE_STASH_SIZE=0x4096
+CONFIG_CONSOLE_RECORD=y
+CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_CPU=y
+CONFIG_CMD_LICENSE=y
+CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMLS is not set
+CONFIG_CMD_ASKENV=y
+CONFIG_CMD_GREPENV=y
+CONFIG_LOOPW=y
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_MX_CYCLIC=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_DEMO=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_REMOTEPROC=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_TFTPPUT=y
+CONFIG_CMD_TFTPSRV=y
+CONFIG_CMD_RARP=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_CDP=y
+CONFIG_CMD_SNTP=y
+CONFIG_CMD_DNS=y
+CONFIG_CMD_LINK_LOCAL=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_TIMER=y
+CONFIG_CMD_SOUND=y
+CONFIG_CMD_QFW=y
+CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
+CONFIG_CMD_EXT2=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_EXT4_WRITE=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_OF_CONTROL=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_OF_HOSTFILE=y
+CONFIG_SPL_OF_PLATDATA=y
+CONFIG_NETCONSOLE=y
+CONFIG_SPL_DM=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+CONFIG_DEVRES=y
+CONFIG_DEBUG_DEVRES=y
+# CONFIG_SPL_SIMPLE_BUS is not set
+CONFIG_ADC=y
+CONFIG_ADC_SANDBOX=y
+CONFIG_BLK=y
+CONFIG_CLK=y
+CONFIG_CPU=y
+CONFIG_DM_DEMO=y
+CONFIG_DM_DEMO_SIMPLE=y
+CONFIG_DM_DEMO_SHAPE=y
+CONFIG_PM8916_GPIO=y
+CONFIG_SANDBOX_GPIO=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_I2C_CROS_EC_TUNNEL=y
+CONFIG_I2C_CROS_EC_LDO=y
+CONFIG_DM_I2C_GPIO=y
+CONFIG_SYS_I2C_SANDBOX=y
+CONFIG_I2C_MUX=y
+CONFIG_SPL_I2C_MUX=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=y
+CONFIG_CROS_EC_KEYB=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_DM_MAILBOX=y
+CONFIG_SANDBOX_MBOX=y
+CONFIG_MISC=y
+CONFIG_CMD_CROS_EC=y
+CONFIG_CROS_EC=y
+CONFIG_CROS_EC_I2C=y
+CONFIG_CROS_EC_LPC=y
+CONFIG_CROS_EC_SANDBOX=y
+CONFIG_CROS_EC_SPI=y
+CONFIG_PWRSEQ=y
+CONFIG_SPL_PWRSEQ=y
+CONFIG_SYSRESET=y
+CONFIG_DM_MMC_OPS=y
+CONFIG_SANDBOX_MMC=y
+CONFIG_SPI_FLASH_SANDBOX=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_DM_ETH=y
+CONFIG_DM_PCI=y
+CONFIG_DM_PCI_COMPAT=y
+CONFIG_PCI_SANDBOX=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_ROCKCHIP_PINCTRL=y
+CONFIG_ROCKCHIP_3036_PINCTRL=y
+CONFIG_PINCTRL_SANDBOX=y
+CONFIG_DM_PMIC=y
+CONFIG_PMIC_ACT8846=y
+CONFIG_DM_PMIC_PFUZE100=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_RK808=y
+CONFIG_PMIC_S2MPS11=y
+CONFIG_DM_PMIC_SANDBOX=y
+CONFIG_PMIC_S5M8767=y
+CONFIG_PMIC_TPS65090=y
+CONFIG_DM_REGULATOR=y
+CONFIG_REGULATOR_ACT8846=y
+CONFIG_DM_REGULATOR_PFUZE100=y
+CONFIG_DM_REGULATOR_MAX77686=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_REGULATOR_RK808=y
+CONFIG_REGULATOR_S5M8767=y
+CONFIG_DM_REGULATOR_SANDBOX=y
+CONFIG_REGULATOR_TPS65090=y
+CONFIG_RAM=y
+CONFIG_REMOTEPROC_SANDBOX=y
+CONFIG_DM_RESET=y
+CONFIG_SANDBOX_RESET=y
+CONFIG_DM_RTC=y
+CONFIG_SANDBOX_SERIAL=y
+CONFIG_SOUND=y
+CONFIG_SOUND_SANDBOX=y
+CONFIG_SANDBOX_SPI=y
+CONFIG_SPMI=y
+CONFIG_SPMI_SANDBOX=y
+CONFIG_TIMER=y
+CONFIG_TIMER_EARLY=y
+CONFIG_SANDBOX_TIMER=y
+CONFIG_TPM_TIS_SANDBOX=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EMUL=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_SYS_USB_EVENT_POLL=y
+CONFIG_DM_VIDEO=y
+CONFIG_CONSOLE_ROTATION=y
+CONFIG_CONSOLE_TRUETYPE=y
+CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
+CONFIG_VIDEO_SANDBOX_SDL=y
+CONFIG_CMD_DHRYSTONE=y
+CONFIG_TPM=y
+CONFIG_LZ4=y
+CONFIG_ERRNO_STR=y
+CONFIG_UNIT_TEST=y
+CONFIG_UT_TIME=y
+CONFIG_UT_DM=y
+CONFIG_UT_ENV=y
diff --git a/doc/README.ti-secure b/doc/README.ti-secure
index 7fc9b9b..54c996d 100644
--- a/doc/README.ti-secure
+++ b/doc/README.ti-secure
@@ -19,69 +19,80 @@
 package is viewable and downloadable. Contact TI, either online or by way
 of a local TI representative, to request access.
 
-When CONFIG_TI_SECURE_DEVICE is set, the U-Boot SPL build process requires
-the presence and use of these tools in order to create a viable boot image.
-The build process will look for the environment variable TI_SECURE_DEV_PKG,
-which should be the path of the installed SECDEV package. If the
-TI_SECURE_DEV_PKG variable is not defined or if it is defined but doesn't
-point to a valid SECDEV package, a warning is issued during the build to
-indicate that a final secure bootable image was not created.
+Booting of U-Boot SPL
+=====================
 
-Within the SECDEV package exists an image creation script:
+	When CONFIG_TI_SECURE_DEVICE is set, the U-Boot SPL build process
+	requires the presence and use of these tools in order to create a
+	viable boot image. The build process will look for the environment
+	variable TI_SECURE_DEV_PKG, which should be the path of the installed
+	SECDEV package. If the TI_SECURE_DEV_PKG variable is not defined or
+	if it is defined but doesn't point to a valid SECDEV package, a
+	warning is issued during the build to indicate that a final secure
+	bootable image was not created.
 
-${TI_SECURE_DEV_PKG}/scripts/create-boot-image.sh
+	Within the SECDEV package exists an image creation script:
 
-This is called as part of the SPL/u-boot build process. As the secure boot
-image formats and requirements differ between secure SOC from TI, the
-purpose of this script is to abstract these details as much as possible.
+	${TI_SECURE_DEV_PKG}/scripts/create-boot-image.sh
 
-The script is basically the only required interface to the TI SECDEV package
-for secure TI devices.
+	This is called as part of the SPL/u-boot build process. As the secure
+	boot image formats and requirements differ between secure SOC from TI,
+	the purpose of this script is to abstract these details as much as
+	possible.
 
-Invoking the script for AM43xx Secure Devices
-=============================================
+	The script is basically the only required interface to the TI SECDEV
+	package for creating a bootable SPL image for secure TI devices.
 
-create-boot-image.sh <IMAGE_FLAG> <INPUT_FILE> <OUTPUT_FILE> <SPL_LOAD_ADDR>
+	Invoking the script for AM43xx Secure Devices
+	=============================================
 
-<IMAGE_FLAG> is a value that specifies the type of the image to generate OR
-the action the image generation tool will take. Valid values are:
-	SPI_X-LOADER - Generates an image for SPI flash (byte swapped)
-	XIP_X-LOADER - Generates a single stage u-boot for NOR/QSPI XiP
-	ISSW - Generates an image for all other boot modes
+	create-boot-image.sh \
+		<IMAGE_FLAG> <INPUT_FILE> <OUTPUT_FILE> <SPL_LOAD_ADDR>
 
-<INPUT_FILE> is the full path and filename of the public world boot loader
-binary file (depending on the boot media, this is usually either
-u-boot-spl.bin or u-boot.bin).
+	<IMAGE_FLAG> is a value that specifies the type of the image to
+	generate OR the action the image generation tool will take. Valid
+	values are:
+		SPI_X-LOADER - Generates an image for SPI flash (byte
+			swapped)
+		XIP_X-LOADER - Generates a single stage u-boot for
+			NOR/QSPI XiP
+		ISSW - Generates an image for all other boot modes
 
-<OUTPUT_FILE> is the full path and filename of the final secure image. The
-output binary images should be used in place of the standard non-secure
-binary images (see the platform-specific user's guides and releases notes
-for how the non-secure images are typically used)
+	<INPUT_FILE> is the full path and filename of the public world boot
+	loaderbinary file (depending on the boot media, this is usually
+	either u-boot-spl.bin or u-boot.bin).
+
+	<OUTPUT_FILE> is the full path and filename of the final secure
+	image. The output binary images should be used in place of the standard
+	non-secure binary images (see the platform-specific user's guides and
+	releases notes for how the non-secure images are typically used)
 	u-boot-spl_HS_SPI_X-LOADER - byte swapped boot image for SPI flash
 	u-boot_HS_XIP_X-LOADER - boot image for NOR or QSPI flash
 	u-boot-spl_HS_ISSW - boot image for all other boot media
 
-<SPL_LOAD_ADDR> is the address at which SOC ROM should load the <INPUT_FILE>
+	<SPL_LOAD_ADDR> is the address at which SOC ROM should load the
+	<INPUT_FILE>
 
-Invoking the script for DRA7xx/AM57xx Secure Devices
-====================================================
+	Invoking the script for DRA7xx/AM57xx Secure Devices
+	====================================================
 
-create-boot-image.sh <IMAGE_TYPE> <INPUT_FILE> <OUTPUT_FILE>
+	create-boot-image.sh <IMAGE_TYPE> <INPUT_FILE> <OUTPUT_FILE>
 
-<IMAGE_TYPE> is a value that specifies the type of the image to generate OR
-the action the image generation tool will take. Valid values are:
-	X-LOADER - Generates an image for NOR or QSPI boot modes
-	MLO - Generates an image for SD/MMC/eMMC boot modes
-	ULO - Generates an image for USB/UART peripheral boot modes
-	Note: ULO is not yet used by the u-boot build process
+	<IMAGE_TYPE> is a value that specifies the type of the image to
+	generate OR the action the image generation tool will take. Valid
+	values are:
+		X-LOADER - Generates an image for NOR or QSPI boot modes
+		MLO - Generates an image for SD/MMC/eMMC boot modes
+		ULO - Generates an image for USB/UART peripheral boot modes
+		Note: ULO is not yet used by the u-boot build process
 
-<INPUT_FILE> is the full path and filename of the public world boot loader
-binary file (for this platform, this is always u-boot-spl.bin).
+	<INPUT_FILE> is the full path and filename of the public world boot
+	loader binary file (for this platform, this is always u-boot-spl.bin).
 
-<OUTPUT_FILE> is the full path and filename of the final secure image. The
-output binary images should be used in place of the standard non-secure
-binary images (see the platform-specific user's guides and releases notes
-for how the non-secure images are typically used)
+	<OUTPUT_FILE> is the full path and filename of the final secure image.
+	The output binary images should be used in place of the standard
+	non-secure binary images (see the platform-specific user's guides
+	and releases notes for how the non-secure images are typically used)
 	u-boot-spl_HS_MLO - boot image for SD/MMC/eMMC. This image is
 		copied to a file named MLO, which is the name that
 		the device ROM bootloader requires for loading from
@@ -89,3 +100,61 @@
 		non-secure devices)
 	u-boot-spl_HS_X-LOADER - boot image for all other flash memories
 		including QSPI and NOR flash
+
+Booting of Primary U-Boot (u-boot.img)
+======================================
+
+	The SPL image is responsible for loading the next stage boot loader,
+	which is the main u-boot image. For secure TI devices, the SPL will
+	be authenticated, as described above, as part of the particular
+	device's ROM boot process. In order to continue the secure boot
+	process, the authenticated SPL must authenticate the main u-boot
+	image that it loads.
+
+	The configurations for secure TI platforms are written to make the boot
+	process use the FIT image format for the u-boot.img (CONFIG_SPL_FRAMEWORK
+	and CONFIG_SPL_LOAD_FIT). With these configurations the binary
+	components that the SPL loads include a specific DTB image and u-boot
+	image. These DTB image may be one of many available to the boot
+	process. In order to secure these components so that they can be
+	authenticated by the SPL as they are loaded from the FIT image,	the
+	build procedure for secure TI devices will secure these images before
+	they are integrated into the FIT image. When those images are extracted
+	from the FIT image at boot time, they are post-processed to verify that
+	they are still secure. The outlined security-related SPL post-processing
+	is enabled through the CONFIG_SPL_FIT_IMAGE_POST_PROCESS option which
+	must be enabled for the secure boot scheme to work. In order to allow
+	verifying proper operation of the secure boot chain in case of successful
+	authentication messages like "Authentication passed: CERT_U-BOOT-NOD" are
+	output by the SPL to the console for each blob that got extracted from the
+	FIT image. Note that the last part of this log message is the (truncated)
+	name of the signing certificate embedded into the blob that got processed.
+
+	The exact details of the how the images are secured is handled by the
+	SECDEV package. Within the SECDEV package exists a script to process
+	an input binary image:
+
+	${TI_SECURE_DEV_PKG}/scripts/secure-binary-image.sh
+
+	This is called as part of the u-boot build process. As the secure
+	image formats and requirements can differ between the various secure
+	SOCs from TI, this script in the SECDEV package abstracts these
+	details. This script is essentially the only required interface to the
+	TI SECDEV package for creating a u-boot.img image for secure TI
+	devices.
+
+	The SPL/u-boot code contains calls to dedicated secure ROM functions
+	to perform the validation on the secured images. The details of the
+	interface to those functions is shown in the code. The summary
+	is that they are accessed by invoking an ARM secure monitor call to
+	the device's secure ROM (fixed read-only-memory that is secure and
+	only accessible when the ARM core is operating in the secure mode).
+
+	Invoking the secure-binary-image script for Secure Devices
+	==========================================================
+
+	secure-binary-image.sh <INPUT_FILE> <OUTPUT_FILE>
+
+	<INPUT_FILE> is the full path and filename of the input binary image
+
+	<OUTPUT_FILE> is the full path and filename of the output secure image.
diff --git a/doc/driver-model/of-plat.txt b/doc/driver-model/of-plat.txt
new file mode 100644
index 0000000..86e5e25
--- /dev/null
+++ b/doc/driver-model/of-plat.txt
@@ -0,0 +1,310 @@
+Driver Model Compiled-in Device Tree / Platform Data
+====================================================
+
+
+Introduction
+------------
+
+Device tree is the standard configuration method in U-Boot. It is used to
+define what devices are in the system and provide configuration information
+to these devices.
+
+The overhead of adding device tree access to U-Boot is fairly modest,
+approximately 3KB on Thumb 2 (plus the size of the DT itself). This means
+that in most cases it is best to use device tree for configuration.
+
+However there are some very constrained environments where U-Boot needs to
+work. These include SPL with severe memory limitations. For example, some
+SoCs require a 16KB SPL image which must include a full MMC stack. In this
+case the overhead of device tree access may be too great.
+
+It is possible to create platform data manually by defining C structures
+for it, and reference that data in a U_BOOT_DEVICE() declaration. This
+bypasses the use of device tree completely, effectively creating a parallel
+configuration mechanism. But it is an available option for SPL.
+
+As an alternative, a new 'of-platdata' feature is provided. This converts the
+device tree contents into C code which can be compiled into the SPL binary.
+This saves the 3KB of code overhead and perhaps a few hundred more bytes due
+to more efficient storage of the data.
+
+Note: Quite a bit of thought has gone into the design of this feature.
+However it still has many rough edges and comments and suggestions are
+strongly encouraged! Quite possibly there is a much better approach.
+
+
+Caveats
+-------
+
+There are many problems with this features. It should only be used when
+strictly necessary. Notable problems include:
+
+   - Device tree does not describe data types. But the C code must define a
+        type for each property. These are guessed using heuristics which
+        are wrong in several fairly common cases. For example an 8-byte value
+        is considered to be a 2-item integer array, and is byte-swapped. A
+        boolean value that is not present means 'false', but cannot be
+        included in the structures since there is generally no mention of it
+        in the device tree file.
+
+   - Naming of nodes and properties is automatic. This means that they follow
+        the naming in the device tree, which may result in C identifiers that
+        look a bit strange.
+
+   - It is not possible to find a value given a property name. Code must use
+        the associated C member variable directly in the code. This makes
+        the code less robust in the face of device-tree changes. It also
+        makes it very unlikely that your driver code will be useful for more
+        than one SoC. Even if the code is common, each SoC will end up with
+        a different C struct name, and a likely a different format for the
+        platform data.
+
+   - The platform data is provided to drivers as a C structure. The driver
+        must use the same structure to access the data. Since a driver
+        normally also supports device tree it must use #ifdef to separate
+        out this code, since the structures are only available in SPL.
+
+
+How it works
+------------
+
+The feature is enabled by CONFIG SPL_OF_PLATDATA. This is only available
+in SPL and should be tested with:
+
+        #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA)
+
+A new tool called 'dtoc' converts a device tree file either into a set of
+struct declarations, one for each compatible node, or a set of
+U_BOOT_DEVICE() declarations along with the actual platform data for each
+device. As an example, consider this MMC node:
+
+        sdmmc: dwmmc@ff0c0000 {
+                compatible = "rockchip,rk3288-dw-mshc";
+                clock-freq-min-max = <400000 150000000>;
+                clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
+                         <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
+                clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+                fifo-depth = <0x100>;
+                interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                reg = <0xff0c0000 0x4000>;
+                bus-width = <4>;
+                cap-mmc-highspeed;
+                cap-sd-highspeed;
+                card-detect-delay = <200>;
+                disable-wp;
+                num-slots = <1>;
+                pinctrl-names = "default";
+                pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
+                vmmc-supply = <&vcc_sd>;
+                status = "okay";
+                u-boot,dm-pre-reloc;
+        };
+
+
+Some of these properties are dropped by U-Boot under control of the
+CONFIG_OF_SPL_REMOVE_PROPS option. The rest are processed. This will produce
+the following C struct declaration:
+
+struct dtd_rockchip_rk3288_dw_mshc {
+        fdt32_t         bus_width;
+        bool            cap_mmc_highspeed;
+        bool            cap_sd_highspeed;
+        fdt32_t         card_detect_delay;
+        fdt32_t         clock_freq_min_max[2];
+        struct phandle_2_cell clocks[4];
+        bool            disable_wp;
+        fdt32_t         fifo_depth;
+        fdt32_t         interrupts[3];
+        fdt32_t         num_slots;
+        fdt32_t         reg[2];
+        fdt32_t         vmmc_supply;
+};
+
+and the following device declaration:
+
+static struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = {
+        .fifo_depth             = 0x100,
+        .cap_sd_highspeed       = true,
+        .interrupts             = {0x0, 0x20, 0x4},
+        .clock_freq_min_max     = {0x61a80, 0x8f0d180},
+        .vmmc_supply            = 0xb,
+        .num_slots              = 0x1,
+        .clocks                 = {{&dtv_clock_controller_at_ff760000, 456},
+                                   {&dtv_clock_controller_at_ff760000, 68},
+                                   {&dtv_clock_controller_at_ff760000, 114},
+                                   {&dtv_clock_controller_at_ff760000, 118}},
+        .cap_mmc_highspeed      = true,
+        .disable_wp             = true,
+        .bus_width              = 0x4,
+        .u_boot_dm_pre_reloc    = true,
+        .reg                    = {0xff0c0000, 0x4000},
+        .card_detect_delay      = 0xc8,
+};
+U_BOOT_DEVICE(dwmmc_at_ff0c0000) = {
+        .name           = "rockchip_rk3288_dw_mshc",
+        .platdata       = &dtv_dwmmc_at_ff0c0000,
+        .platdata_size  = sizeof(dtv_dwmmc_at_ff0c0000),
+};
+
+The device is then instantiated at run-time and the platform data can be
+accessed using:
+
+        struct udevice *dev;
+        struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_platdata(dev);
+
+This avoids the code overhead of converting the device tree data to
+platform data in the driver. The ofdata_to_platdata() method should
+therefore do nothing in such a driver.
+
+
+Converting of-platdata to a useful form
+---------------------------------------
+
+Of course it would be possible use the of-platdata directly in your driver
+whenever configuration information is required. However this meands that the
+driver will not be able to support device tree, since the of-platdata
+structure is not available when device tree is used. It would make no sense
+to use this structure if device tree were available, since the structure has
+all the limitations metioned in caveats above.
+
+Therefore it is recommended that the of-platdata structure should be used
+only in the probe() method of your driver. It cannot be used in the
+ofdata_to_platdata() method since this is not called when platform data is
+already present.
+
+
+How to structure your driver
+----------------------------
+
+Drivers should always support device tree as an option. The of-platdata
+feature is intended as a add-on to existing drivers.
+
+Your driver should convert the platdata struct in its probe() method. The
+existing device tree decoding logic should be kept in the
+ofdata_to_platdata() method and wrapped with #if.
+
+For example:
+
+    #include <dt-structs.h>
+
+    struct mmc_platdata {
+    #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA)
+            /* Put this first since driver model will copy the data here */
+            struct dtd_mmc dtplat;
+    #endif
+            /*
+             * Other fields can go here, to be filled in by decoding from
+             * the device tree (or the C structures when of-platdata is used).
+             */
+            int fifo_depth;
+    };
+
+    static int mmc_ofdata_to_platdata(struct udevice *dev)
+    {
+    #if !CONFIG_IS_ENABLED(SPL_OF_PLATDATA)
+            /* Decode the device tree data */
+            struct mmc_platdata *plat = dev_get_platdata(dev);
+            const void *blob = gd->fdt_blob;
+            int node = dev->of_offset;
+
+            plat->fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0);
+    #endif
+
+            return 0;
+    }
+
+    static int mmc_probe(struct udevice *dev)
+    {
+            struct mmc_platdata *plat = dev_get_platdata(dev);
+
+    #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA)
+            /* Decode the of-platdata from the C structures */
+            struct dtd_mmc *dtplat = &plat->dtplat;
+
+            plat->fifo_depth = dtplat->fifo_depth;
+    #endif
+            /* Set up the device from the plat data */
+            writel(plat->fifo_depth, ...)
+    }
+
+    static const struct udevice_id mmc_ids[] = {
+            { .compatible = "vendor,mmc" },
+            { }
+    };
+
+    U_BOOT_DRIVER(mmc_drv) = {
+            .name           = "mmc",
+            .id             = UCLASS_MMC,
+            .of_match       = mmc_ids,
+            .ofdata_to_platdata = mmc_ofdata_to_platdata,
+            .probe          = mmc_probe,
+            .priv_auto_alloc_size = sizeof(struct mmc_priv),
+            .platdata_auto_alloc_size = sizeof(struct mmc_platdata),
+    };
+
+
+In the case where SPL_OF_PLATDATA is enabled, platdata_auto_alloc_size is
+still used to allocate space for the platform data. This is different from
+the normal behaviour and is triggered by the use of of-platdata (strictly
+speaking it is a non-zero platdata_size which triggers this).
+
+The of-platdata struct contents is copied from the C structure data to the
+start of the newly allocated area. In the case where device tree is used,
+the platform data is allocated, and starts zeroed. In this case the
+ofdata_to_platdata() method should still set up the platform data (and the
+of-platdata struct will not be present).
+
+SPL must use either of-platdata or device tree. Drivers cannot use both at
+the same time, but they must support device tree. Supporting of-platdata is
+optional.
+
+The device tree becomes in accessible when CONFIG_SPL_OF_PLATDATA is enabled,
+since the device-tree access code is not compiled in. A corollary is that
+a board can only move to using of-platdata if all the drivers it uses support
+it. There would be little point in having some drivers require the device
+tree data, since then libfdt would still be needed for those drivers and
+there would be no code-size benefit.
+
+Internals
+---------
+
+The dt-structs.h file includes the generated file
+(include/generated//dt-structs.h) if CONFIG_SPL_OF_PLATDATA is enabled.
+Otherwise (such as in U-Boot proper) these structs are not available. This
+prevents them being used inadvertently. All usage must be bracketed with
+#if CONFIG_IS_ENABLED(SPL_OF_PLATDATA).
+
+The dt-platdata.c file contains the device declarations and is is built in
+spl/dt-platdata.c.
+
+Some phandles (thsoe that are recognised as such) are converted into
+points to platform data. This pointer can potentially be used to access the
+referenced device (by searching for the pointer value). This feature is not
+yet implemented, however.
+
+The beginnings of a libfdt Python module are provided. So far this only
+implements a subset of the features.
+
+The 'swig' tool is needed to build the libfdt Python module. If this is not
+found then the Python model is not used and a fallback is used instead, which
+makes use of fdtget.
+
+
+Credits
+-------
+
+This is an implementation of an idea by Tom Rini <trini@konsulko.com>.
+
+
+Future work
+-----------
+- Consider programmatically reading binding files instead of device tree
+     contents
+- Complete the phandle feature
+- Move to using a full Python libfdt module
+
+--
+Simon Glass <sjg@chromium.org>
+Google, Inc
+6/6/16
+Updated Independence Day 2016
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 6e4d672..e0f8567 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -10,6 +10,7 @@
 #include <clk.h>
 #include <clk-uclass.h>
 #include <dm.h>
+#include <dt-structs.h>
 #include <errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -21,6 +22,22 @@
 
 #if CONFIG_IS_ENABLED(OF_CONTROL)
 #ifdef CONFIG_SPL_BUILD
+# if CONFIG_IS_ENABLED(OF_PLATDATA)
+int clk_get_by_index_platdata(struct udevice *dev, int index,
+			      struct phandle_2_cell *cells, struct clk *clk)
+{
+	int ret;
+
+	if (index != 0)
+		return -ENOSYS;
+	ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
+	if (ret)
+		return ret;
+	clk->id = cells[0].id;
+
+	return 0;
+}
+# else
 int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
 {
 	int ret;
@@ -39,6 +56,7 @@
 	clk->id = cell[1];
 	return 0;
 }
+# endif /* OF_PLATDATA */
 
 int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
 {
@@ -117,8 +135,8 @@
 
 	return clk_get_by_index(dev, index, clk);
 }
-#endif
-#endif
+#endif /* CONFIG_SPL_BUILD */
+#endif /* OF_CONTROL */
 
 int clk_request(struct udevice *dev, struct clk *clk)
 {
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c
index 797e537..9c4d2b3 100644
--- a/drivers/clk/clk_fixed_rate.c
+++ b/drivers/clk/clk_fixed_rate.c
@@ -30,9 +30,11 @@
 
 static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev)
 {
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
 	to_clk_fixed_rate(dev)->fixed_rate =
 				fdtdec_get_int(gd->fdt_blob, dev->of_offset,
 					       "clock-frequency", 0);
+#endif
 
 	return 0;
 }
diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c
index 2285453..679f010 100644
--- a/drivers/clk/clk_rk3288.c
+++ b/drivers/clk/clk_rk3288.c
@@ -7,7 +7,9 @@
 #include <common.h>
 #include <clk-uclass.h>
 #include <dm.h>
+#include <dt-structs.h>
 #include <errno.h>
+#include <mapmem.h>
 #include <syscon.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
@@ -21,6 +23,12 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+struct rk3288_clk_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_rockchip_rk3288_cru dtd;
+#endif
+};
+
 struct rk3288_clk_priv {
 	struct rk3288_grf *grf;
 	struct rk3288_cru *cru;
@@ -783,13 +791,30 @@
 	.set_rate	= rk3288_clk_set_rate,
 };
 
+static int rk3288_clk_ofdata_to_platdata(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct rk3288_clk_priv *priv = dev_get_priv(dev);
+
+	priv->cru = (struct rk3288_cru *)dev_get_addr(dev);
+#endif
+
+	return 0;
+}
+
 static int rk3288_clk_probe(struct udevice *dev)
 {
 	struct rk3288_clk_priv *priv = dev_get_priv(dev);
 
-	priv->cru = (struct rk3288_cru *)dev_get_addr(dev);
 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+	if (IS_ERR(priv->grf))
+		return PTR_ERR(priv->grf);
 #ifdef CONFIG_SPL_BUILD
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct rk3288_clk_plat *plat = dev_get_platdata(dev);
+
+	priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
+#endif
 	rkclk_init(priv->cru, priv->grf);
 #endif
 
@@ -813,12 +838,14 @@
 	{ }
 };
 
-U_BOOT_DRIVER(clk_rk3288) = {
-	.name		= "clk_rk3288",
+U_BOOT_DRIVER(rockchip_rk3288_cru) = {
+	.name		= "rockchip_rk3288_cru",
 	.id		= UCLASS_CLK,
 	.of_match	= rk3288_clk_ids,
 	.priv_auto_alloc_size = sizeof(struct rk3288_clk_priv),
+	.platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat),
 	.ops		= &rk3288_clk_ops,
 	.bind		= rk3288_clk_bind,
+	.ofdata_to_platdata	= rk3288_clk_ofdata_to_platdata,
 	.probe		= rk3288_clk_probe,
 };
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 0e56b23..a7f77b4 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -112,7 +112,7 @@
 
 	devres_release_all(dev);
 
-	if (dev->flags & DM_NAME_ALLOCED)
+	if (dev->flags & DM_FLAG_NAME_ALLOCED)
 		free((char *)dev->name);
 	free(dev);
 
diff --git a/drivers/core/device.c b/drivers/core/device.c
index f7fb0cc..5bb1d77 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -30,7 +30,7 @@
 static int device_bind_common(struct udevice *parent, const struct driver *drv,
 			      const char *name, void *platdata,
 			      ulong driver_data, int of_offset,
-			      struct udevice **devp)
+			      uint of_platdata_size, struct udevice **devp)
 {
 	struct udevice *dev;
 	struct uclass *uc;
@@ -84,12 +84,29 @@
 		}
 	}
 
-	if (!dev->platdata && drv->platdata_auto_alloc_size) {
-		dev->flags |= DM_FLAG_ALLOC_PDATA;
-		dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
-		if (!dev->platdata) {
-			ret = -ENOMEM;
-			goto fail_alloc1;
+	if (drv->platdata_auto_alloc_size) {
+		bool alloc = !platdata;
+
+		if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
+			if (of_platdata_size) {
+				dev->flags |= DM_FLAG_OF_PLATDATA;
+				if (of_platdata_size <
+						drv->platdata_auto_alloc_size)
+					alloc = true;
+			}
+		}
+		if (alloc) {
+			dev->flags |= DM_FLAG_ALLOC_PDATA;
+			dev->platdata = calloc(1,
+					       drv->platdata_auto_alloc_size);
+			if (!dev->platdata) {
+				ret = -ENOMEM;
+				goto fail_alloc1;
+			}
+			if (CONFIG_IS_ENABLED(OF_PLATDATA) && platdata) {
+				memcpy(dev->platdata, platdata,
+				       of_platdata_size);
+			}
 		}
 	}
 
@@ -202,14 +219,14 @@
 				 struct udevice **devp)
 {
 	return device_bind_common(parent, drv, name, NULL, driver_data,
-				  of_offset, devp);
+				  of_offset, 0, devp);
 }
 
 int device_bind(struct udevice *parent, const struct driver *drv,
 		const char *name, void *platdata, int of_offset,
 		struct udevice **devp)
 {
-	return device_bind_common(parent, drv, name, platdata, 0, of_offset,
+	return device_bind_common(parent, drv, name, platdata, 0, of_offset, 0,
 				  devp);
 }
 
@@ -217,6 +234,7 @@
 			const struct driver_info *info, struct udevice **devp)
 {
 	struct driver *drv;
+	uint platdata_size = 0;
 
 	drv = lists_driver_lookup_name(info->name);
 	if (!drv)
@@ -224,8 +242,11 @@
 	if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
 		return -EPERM;
 
-	return device_bind(parent, drv, info->name, (void *)info->platdata,
-			   -1, devp);
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	platdata_size = info->platdata_size;
+#endif
+	return device_bind_common(parent, drv, info->name,
+			(void *)info->platdata, 0, -1, platdata_size, devp);
 }
 
 static void *alloc_priv(int size, uint flags)
@@ -608,7 +629,7 @@
 
 fdt_addr_t dev_get_addr_index(struct udevice *dev, int index)
 {
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 	fdt_addr_t addr;
 
 	if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
@@ -738,7 +759,7 @@
 
 void device_set_name_alloced(struct udevice *dev)
 {
-	dev->flags |= DM_NAME_ALLOCED;
+	dev->flags |= DM_FLAG_NAME_ALLOCED;
 }
 
 int device_set_name(struct udevice *dev, const char *name)
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 0c27717..6a634e6 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -99,7 +99,7 @@
 	return 0;
 }
 
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 /**
  * driver_check_compatible() - Check if a driver is compatible with this node
  *
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index 519832f..0299ff0 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -15,6 +15,49 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static struct regmap *regmap_alloc_count(int count)
+{
+	struct regmap *map;
+
+	map = malloc(sizeof(struct regmap));
+	if (!map)
+		return NULL;
+	if (count <= 1) {
+		map->range = &map->base_range;
+	} else {
+		map->range = malloc(count * sizeof(struct regmap_range));
+		if (!map->range) {
+			free(map);
+			return NULL;
+		}
+	}
+	map->range_count = count;
+
+	return map;
+}
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
+			     struct regmap **mapp)
+{
+	struct regmap_range *range;
+	struct regmap *map;
+
+	map = regmap_alloc_count(count);
+	if (!map)
+		return -ENOMEM;
+
+	map->base = *reg;
+	for (range = map->range; count > 0; reg += 2, range++, count--) {
+		range->start = *reg;
+		range->size = reg[1];
+	}
+
+	*mapp = map;
+
+	return 0;
+}
+#else
 int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
 {
 	const void *blob = gd->fdt_blob;
@@ -37,22 +80,11 @@
 	if (!cell || !count)
 		return -EINVAL;
 
-	map = malloc(sizeof(struct regmap));
+	map = regmap_alloc_count(count);
 	if (!map)
 		return -ENOMEM;
 
-	if (count <= 1) {
-		map->range = &map->base_range;
-	} else {
-		map->range = malloc(count * sizeof(struct regmap_range));
-		if (!map->range) {
-			free(map);
-			return -ENOMEM;
-		}
-	}
-
 	map->base = fdtdec_get_number(cell, addr_len);
-	map->range_count = count;
 
 	for (range = map->range; count > 0;
 	     count--, cell += both_len, range++) {
@@ -64,6 +96,7 @@
 
 	return 0;
 }
+#endif
 
 void *regmap_get_range(struct regmap *map, unsigned int range_num)
 {
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 95886ad..1587024 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -188,7 +188,7 @@
 	return ret;
 }
 
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
 		     bool pre_reloc_only)
 {
@@ -244,7 +244,7 @@
 		return ret;
 	}
 
-	if (CONFIG_IS_ENABLED(OF_CONTROL)) {
+	if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
 		ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
 		if (ret) {
 			debug("dm_scan_fdt() failed: %d\n", ret);
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
index e03f46a..01bd968 100644
--- a/drivers/core/syscon-uclass.c
+++ b/drivers/core/syscon-uclass.c
@@ -29,7 +29,20 @@
 {
 	struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
 
+	/*
+	 * With OF_PLATDATA we really have no way of knowing the format of
+	 * the device-specific platform data. So we assume that it starts with
+	 * a 'reg' member, and this holds a single address and size. Drivers
+	 * using OF_PLATDATA will need to ensure that this is true.
+	 */
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct syscon_base_platdata *plat = dev_get_platdata(dev);
+
+	return regmap_init_mem_platdata(dev, plat->reg, ARRAY_SIZE(plat->reg),
+					&priv->regmap);
+#else
 	return regmap_init_mem(dev, &priv->regmap);
+#endif
 }
 
 int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp)
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 066639b..fff6f0c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -29,12 +29,19 @@
 obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
 obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
 ifdef CONFIG_DM_I2C
+ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
 endif
+endif
 obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
 obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
 obj-$(CONFIG_STATUS_LED) += status_led.o
 obj-$(CONFIG_SANDBOX) += swap_case.o
+ifdef CONFIG_SPL_OF_PLATDATA
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SANDBOX) += spltest_sandbox.o
+endif
+endif
 obj-$(CONFIG_SANDBOX) += syscon_sandbox.o
 obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
 obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
diff --git a/drivers/misc/spltest_sandbox.c b/drivers/misc/spltest_sandbox.c
new file mode 100644
index 0000000..1fef825
--- /dev/null
+++ b/drivers/misc/spltest_sandbox.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_spl_probe(struct udevice *dev)
+{
+	struct dtd_sandbox_spl_test *plat = dev_get_platdata(dev);
+	int i;
+
+	printf("of-platdata probe:\n");
+	printf("bool %d\n", plat->boolval);
+
+	printf("byte %02x\n", plat->byteval);
+	printf("bytearray");
+	for (i = 0; i < sizeof(plat->bytearray); i++)
+		printf(" %02x", plat->bytearray[i]);
+	printf("\n");
+
+	printf("int %d\n", plat->intval);
+	printf("intarray");
+	for (i = 0; i < ARRAY_SIZE(plat->intarray); i++)
+		printf(" %d", plat->intarray[i]);
+	printf("\n");
+
+	printf("longbytearray");
+	for (i = 0; i < sizeof(plat->longbytearray); i++)
+		printf(" %02x", plat->longbytearray[i]);
+	printf("\n");
+
+	printf("string %s\n", plat->stringval);
+	printf("stringarray");
+	for (i = 0; i < ARRAY_SIZE(plat->stringarray); i++)
+		printf(" \"%s\"", plat->stringarray[i]);
+	printf("\n");
+
+	return 0;
+}
+
+U_BOOT_DRIVER(sandbox_spl_test) = {
+	.name	= "sandbox_spl_test",
+	.id	= UCLASS_MISC,
+	.flags	= DM_FLAG_PRE_RELOC,
+	.probe	= sandbox_spl_probe,
+};
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 863bbb3..283befc 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -23,8 +23,21 @@
 #define	DWMMC_MMC0_SDR_TIMING_VAL	0x03030001
 #define	DWMMC_MMC2_SDR_TIMING_VAL	0x03020001
 
+#ifdef CONFIG_DM_MMC
+#include <dm.h>
+DECLARE_GLOBAL_DATA_PTR;
+
+struct exynos_mmc_plat {
+	struct mmc_config cfg;
+	struct mmc mmc;
+};
+#endif
+
 /* Exynos implmentation specific drver private data */
 struct dwmci_exynos_priv_data {
+#ifdef CONFIG_DM_MMC
+	struct dwmci_host host;
+#endif
 	u32 sdr_timing;
 };
 
@@ -80,11 +93,10 @@
 		exynos_dwmci_clksel(host);
 }
 
-static int exynos_dwmci_core_init(struct dwmci_host *host, int index)
+static int exynos_dwmci_core_init(struct dwmci_host *host)
 {
 	unsigned int div;
 	unsigned long freq, sclk;
-	struct dwmci_exynos_priv_data *priv = host->priv;
 
 	if (host->bus_hz)
 		freq = host->bus_hz;
@@ -92,10 +104,10 @@
 		freq = DWMMC_MAX_FREQ;
 
 	/* request mmc clock vlaue of 52MHz.  */
-	sclk = get_mmc_clk(index);
+	sclk = get_mmc_clk(host->dev_index);
 	div = DIV_ROUND_UP(sclk, freq);
 	/* set the clock divisor for mmc */
-	set_mmc_clk(index, div);
+	set_mmc_clk(host->dev_index, div);
 
 	host->name = "EXYNOS DWMMC";
 #ifdef CONFIG_EXYNOS5420
@@ -103,78 +115,35 @@
 #endif
 	host->board_init = exynos_dwmci_board_init;
 
-	if (!priv->sdr_timing) {
-		if (index == 0)
-			priv->sdr_timing = DWMMC_MMC0_SDR_TIMING_VAL;
-		else if (index == 2)
-			priv->sdr_timing = DWMMC_MMC2_SDR_TIMING_VAL;
-	}
-
 	host->caps = MMC_MODE_DDR_52MHz;
 	host->clksel = exynos_dwmci_clksel;
-	host->dev_index = index;
 	host->get_mmc_clk = exynos_dwmci_get_clk;
+
+#ifndef CONFIG_DM_MMC
 	/* Add the mmc channel to be registered with mmc core */
 	if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) {
-		printf("DWMMC%d registration failed\n", index);
+		printf("DWMMC%d registration failed\n", host->dev_index);
 		return -1;
 	}
+#endif
+
 	return 0;
 }
 
-/*
- * This function adds the mmc channel to be registered with mmc core.
- * index -	mmc channel number.
- * regbase -	register base address of mmc channel specified in 'index'.
- * bus_width -	operating bus width of mmc channel specified in 'index'.
- * clksel -	value to be written into CLKSEL register in case of FDT.
- *		NULL in case od non-FDT.
- */
-int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)
-{
-	struct dwmci_host *host = NULL;
-	struct dwmci_exynos_priv_data *priv;
-
-	host = malloc(sizeof(struct dwmci_host));
-	if (!host) {
-		error("dwmci_host malloc fail!\n");
-		return -ENOMEM;
-	}
-
-	priv = malloc(sizeof(struct dwmci_exynos_priv_data));
-	if (!priv) {
-		error("dwmci_exynos_priv_data malloc fail!\n");
-		return -ENOMEM;
-	}
-
-	host->ioaddr = (void *)regbase;
-	host->buswidth = bus_width;
-
-	if (clksel)
-		priv->sdr_timing = clksel;
-
-	host->priv = priv;
-
-	return exynos_dwmci_core_init(host, index);
-}
-
-#if CONFIG_IS_ENABLED(OF_CONTROL)
 static struct dwmci_host dwmci_host[DWMMC_MAX_CH_NUM];
 
 static int do_dwmci_init(struct dwmci_host *host)
 {
-	int index, flag, err;
-
-	index = host->dev_index;
+	int flag, err;
 
 	flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
 	err = exynos_pinmux_config(host->dev_id, flag);
 	if (err) {
-		printf("DWMMC%d not configure\n", index);
+		printf("DWMMC%d not configure\n", host->dev_index);
 		return err;
 	}
 
-	return exynos_dwmci_core_init(host, index);
+	return exynos_dwmci_core_init(host);
 }
 
 static int exynos_dwmci_get_config(const void *blob, int node,
@@ -197,13 +166,14 @@
 	if (host->dev_index == host->dev_id)
 		host->dev_index = host->dev_id - PERIPH_ID_SDMMC0;
 
-	/* Get the bus width from the device node */
-	host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
-	if (host->buswidth <= 0) {
-		printf("DWMMC%d: Can't get bus-width\n", host->dev_index);
+	if (host->dev_index > 4) {
+		printf("DWMMC%d: Can't get the dev index\n", host->dev_index);
 		return -EINVAL;
 	}
 
+	/* Get the bus width from the device node (Default is 4bit buswidth) */
+	host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 4);
+
 	/* Set the base address from the device node */
 	base = fdtdec_get_addr(blob, node, "reg");
 	if (!base) {
@@ -265,15 +235,13 @@
 
 int exynos_dwmmc_init(const void *blob)
 {
-	int compat_id;
 	int node_list[DWMMC_MAX_CH_NUM];
 	int boot_dev_node;
 	int err = 0, count;
 
-	compat_id = COMPAT_SAMSUNG_EXYNOS_DWMMC;
-
 	count = fdtdec_find_aliases_for_id(blob, "mmc",
-				compat_id, node_list, DWMMC_MAX_CH_NUM);
+			COMPAT_SAMSUNG_EXYNOS_DWMMC, node_list,
+			DWMMC_MAX_CH_NUM);
 
 	/* For DWMMC always set boot device as mmc 0 */
 	if (count >= 3 && get_boot_mode() == BOOT_MODE_SD) {
@@ -286,4 +254,58 @@
 
 	return err;
 }
+
+#ifdef CONFIG_DM_MMC
+static int exynos_dwmmc_probe(struct udevice *dev)
+{
+	struct exynos_mmc_plat *plat = dev_get_platdata(dev);
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct dwmci_exynos_priv_data *priv = dev_get_priv(dev);
+	struct dwmci_host *host = &priv->host;
+	int err;
+
+	err = exynos_dwmci_get_config(gd->fdt_blob, dev->of_offset, host);
+	if (err)
+		return err;
+	err = do_dwmci_init(host);
+	if (err)
+		return err;
+
+	dwmci_setup_cfg(&plat->cfg, host->name, host->buswidth, host->caps,
+			DWMMC_MAX_FREQ, DWMMC_MIN_FREQ);
+	host->mmc = &plat->mmc;
+	host->mmc->priv = &priv->host;
+	host->priv = dev;
+	upriv->mmc = host->mmc;
+
+	return dwmci_probe(dev);
+}
+
+static int exynos_dwmmc_bind(struct udevice *dev)
+{
+	struct exynos_mmc_plat *plat = dev_get_platdata(dev);
+	int ret;
+
+	ret = dwmci_bind(dev, &plat->mmc, &plat->cfg);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct udevice_id exynos_dwmmc_ids[] = {
+	{ .compatible = "samsung,exynos4412-dw-mshc" },
+	{ }
+};
+
+U_BOOT_DRIVER(exynos_dwmmc_drv) = {
+	.name		= "exynos_dwmmc",
+	.id		= UCLASS_MMC,
+	.of_match	= exynos_dwmmc_ids,
+	.bind		= exynos_dwmmc_bind,
+	.ops		= &dm_dwmci_ops,
+	.probe		= exynos_dwmmc_probe,
+	.priv_auto_alloc_size	= sizeof(struct dwmci_exynos_priv_data),
+	.platdata_auto_alloc_size = sizeof(struct exynos_mmc_plat),
+};
 #endif
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index 691a515..020a59b 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -7,8 +7,10 @@
 #include <common.h>
 #include <clk.h>
 #include <dm.h>
+#include <dt-structs.h>
 #include <dwmmc.h>
 #include <errno.h>
+#include <mapmem.h>
 #include <pwrseq.h>
 #include <syscon.h>
 #include <asm/gpio.h>
@@ -19,6 +21,9 @@
 DECLARE_GLOBAL_DATA_PTR;
 
 struct rockchip_mmc_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_rockchip_rk3288_dw_mshc dtplat;
+#endif
 	struct mmc_config cfg;
 	struct mmc mmc;
 };
@@ -26,6 +31,9 @@
 struct rockchip_dwmmc_priv {
 	struct clk clk;
 	struct dwmci_host host;
+	int fifo_depth;
+	bool fifo_mode;
+	u32 minmax[2];
 };
 
 static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
@@ -45,6 +53,7 @@
 
 static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
 {
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
 	struct dwmci_host *host = &priv->host;
 
@@ -61,6 +70,16 @@
 	else
 		host->dev_index = 1;
 
+	priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+				    "fifo-depth", 0);
+	if (priv->fifo_depth < 0)
+		return -EINVAL;
+	priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev->of_offset,
+					  "fifo-mode");
+	if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
+				 "clock-freq-min-max", priv->minmax, 2))
+		return -EINVAL;
+#endif
 	return 0;
 }
 
@@ -71,28 +90,34 @@
 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
 	struct dwmci_host *host = &priv->host;
 	struct udevice *pwr_dev __maybe_unused;
-	u32 minmax[2];
 	int ret;
-	int fifo_depth;
 
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_rockchip_rk3288_dw_mshc *dtplat = &plat->dtplat;
+
+	host->name = dev->name;
+	host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
+	host->buswidth = dtplat->bus_width;
+	host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk;
+	host->priv = dev;
+	host->dev_index = 0;
+	priv->fifo_depth = dtplat->fifo_depth;
+	priv->fifo_mode = 0;
+	memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax));
+
+	ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
+	if (ret < 0)
+		return ret;
+#else
 	ret = clk_get_by_index(dev, 0, &priv->clk);
 	if (ret < 0)
 		return ret;
-
-	if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
-				 "clock-freq-min-max", minmax, 2))
-		return -EINVAL;
-
-	fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
-				    "fifo-depth", 0);
-	if (fifo_depth < 0)
-		return -EINVAL;
-
+#endif
 	host->fifoth_val = MSIZE(0x2) |
-		RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2);
+		RX_WMARK(priv->fifo_depth / 2 - 1) |
+		TX_WMARK(priv->fifo_depth / 2);
 
-	if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "fifo-mode"))
-		host->fifo_mode = true;
+	host->fifo_mode = priv->fifo_mode;
 
 #ifdef CONFIG_PWRSEQ
 	/* Enable power if needed */
@@ -105,7 +130,7 @@
 	}
 #endif
 	dwmci_setup_cfg(&plat->cfg, dev->name, host->buswidth, host->caps,
-			minmax[1], minmax[0]);
+			priv->minmax[1], priv->minmax[0]);
 	host->mmc = &plat->mmc;
 	host->mmc->priv = &priv->host;
 	host->mmc->dev = dev;
@@ -132,7 +157,7 @@
 };
 
 U_BOOT_DRIVER(rockchip_dwmmc_drv) = {
-	.name		= "rockchip_dwmmc",
+	.name		= "rockchip_rk3288_dw_mshc",
 	.id		= UCLASS_MMC,
 	.of_match	= rockchip_dwmmc_ids,
 	.ofdata_to_platdata = rockchip_dwmmc_ofdata_to_platdata,
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c
index 1fa1daa..8cb3b82 100644
--- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c
+++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c
@@ -476,6 +476,7 @@
 static int rk3288_pinctrl_get_periph_id(struct udevice *dev,
 					struct udevice *periph)
 {
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
 	u32 cell[3];
 	int ret;
 
@@ -506,6 +507,7 @@
 	case 103:
 		return PERIPH_ID_HDMI;
 	}
+#endif
 
 	return -ENOENT;
 }
@@ -664,8 +666,12 @@
 
 static int rk3288_pinctrl_bind(struct udevice *dev)
 {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	return 0;
+#else
 	/* scan child GPIO banks */
 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+#endif
 }
 
 #ifndef CONFIG_SPL_BUILD
@@ -719,7 +725,7 @@
 };
 
 U_BOOT_DRIVER(pinctrl_rk3288) = {
-	.name		= "pinctrl_rk3288",
+	.name		= "rockchip_rk3288_pinctrl",
 	.id		= UCLASS_PINCTRL,
 	.of_match	= rk3288_pinctrl_ids,
 	.priv_auto_alloc_size = sizeof(struct rk3288_pinctrl_priv),
diff --git a/drivers/rtc/date.c b/drivers/rtc/date.c
index 8c643a0..bfa2e13 100644
--- a/drivers/rtc/date.c
+++ b/drivers/rtc/date.c
@@ -5,10 +5,6 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
-/*
- * Date & Time support for Philips PCF8563 RTC
- */
-
 #include <common.h>
 #include <command.h>
 #include <errno.h>
@@ -28,53 +24,52 @@
 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 };
 
+static int month_offset[] = {
+	0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+};
+
 /*
  * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
  */
 int rtc_calc_weekday(struct rtc_time *tm)
 {
-	int leapsToDate;
-	int lastYear;
+	int leaps_to_date;
+	int last_year;
 	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;
+		return -1;
+	last_year = tm->tm_year - 1;
 
-	/*
-	 * Number of leap corrections to apply up to end of last year
-	 */
-	leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
+	/* Number of leap corrections to apply up to end of last year */
+	leaps_to_date = last_year / 4 - last_year / 100 + last_year / 400;
 
 	/*
 	 * This year is a leap year if it is divisible by 4 except when it is
 	 * divisible by 100 unless it is divisible by 400
 	 *
-	 * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
+	 * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 is.
 	 */
-	if((tm->tm_year%4==0) &&
-	   ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
-	   (tm->tm_mon>2)) {
-		/*
-		 * We are past Feb. 29 in a leap year
-		 */
-		day=1;
+	if (tm->tm_year % 4 == 0 &&
+	    ((tm->tm_year % 100 != 0) || (tm->tm_year % 400 == 0)) &&
+	    tm->tm_mon > 2) {
+		/* We are past Feb. 29 in a leap year */
+		day = 1;
 	} else {
-		day=0;
+		day = 0;
 	}
 
-	day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday;
-
-	tm->tm_wday=day%7;
+	day += last_year * 365 + leaps_to_date + month_offset[tm->tm_mon - 1] +
+			tm->tm_mday;
+	tm->tm_wday = day % 7;
 
 	return 0;
 }
 
 int rtc_to_tm(int tim, struct rtc_time *tm)
 {
-	register int    i;
-	register long   hms, day;
+	register int i;
+	register long hms, day;
 
 	day = tim / SECDAY;
 	hms = tim % SECDAY;
@@ -85,22 +80,19 @@
 	tm->tm_sec = (hms % 3600) % 60;
 
 	/* Number of years in days */
-	for (i = STARTOFTIME; day >= days_in_year(i); i++) {
+	for (i = STARTOFTIME; day >= days_in_year(i); i++)
 		day -= days_in_year(i);
-	}
 	tm->tm_year = i;
 
 	/* Number of months in days left */
-	if (leapyear(tm->tm_year)) {
+	if (leapyear(tm->tm_year))
 		days_in_month(FEBRUARY) = 29;
-	}
-	for (i = 1; day >= days_in_month(i); i++) {
+	for (i = 1; day >= days_in_month(i); i++)
 		day -= days_in_month(i);
-	}
 	days_in_month(FEBRUARY) = 28;
 	tm->tm_mon = i;
 
-	/* Days are what is left over (+1) from all that. */
+	/* Days are what is left over (+1) from all that */
 	tm->tm_mday = day + 1;
 
 	/* Zero unused fields */
@@ -113,19 +105,20 @@
 	return rtc_calc_weekday(tm);
 }
 
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+/*
+ * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
  * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
  *
  * [For the Julian calendar (which was used in Russia before 1917,
  * Britain & colonies before 1752, anywhere else before 1582,
  * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
+ * -year / 100 + year / 400 terms, and add 10.]
  *
  * This algorithm was first published by Gauss (I think).
  *
  * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
+ * machines where 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 rtc_mktime(const struct rtc_time *tm)
@@ -135,8 +128,8 @@
 	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 */
+	if (0 >= (int)mon) {	/* 1..12 -> 11, 12, 1..10 */
+		mon += 12;	/* Puts Feb last since it has leap day */
 		year -= 1;
 	}
 
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 0e38903..9ff7234 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -312,6 +312,15 @@
 	  be used. It can be a constant or a function to get clock, eg,
 	  get_serial_clock().
 
+config ROCKCHIP_SERIAL
+	bool "Rockchip on-chip UART support"
+	depends on DM_SERIAL && SPL_OF_PLATDATA
+	help
+	  Select this to enable a debug UART for Rockchip devices when using
+	  CONFIG_OF_PLATDATA (i.e. a compiled-in device tree replacemenmt).
+	  This uses the ns16550 driver, converting the platdata from of-platdata
+	  to the ns16550 format.
+
 config SANDBOX_SERIAL
 	bool "Sandbox UART support"
 	depends on SANDBOX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 92cbea5..6986d65 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -28,6 +28,9 @@
 obj-$(CONFIG_MXC_UART) += serial_mxc.o
 obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o
 obj-$(CONFIG_MESON_SERIAL) += serial_meson.o
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_ROCKCHIP_SERIAL) += serial_rockchip.o
+endif
 obj-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o
 obj-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o
 obj-$(CONFIG_SANDBOX_SERIAL) += sandbox.o
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index c6cb3eb..88fca15 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -347,7 +347,7 @@
 	return 0;
 }
 
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
 {
 	struct ns16550_platdata *plat = dev->platdata;
@@ -416,6 +416,7 @@
 	.setbrg = ns16550_serial_setbrg,
 };
 
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
 #if CONFIG_IS_ENABLED(OF_CONTROL)
 /*
  * Please consider existing compatible strings before adding a new
@@ -452,4 +453,5 @@
 	.flags	= DM_FLAG_PRE_RELOC,
 };
 #endif
+#endif /* !OF_PLATDATA */
 #endif /* CONFIG_DM_SERIAL */
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c
index 58f882b..bcc3465 100644
--- a/drivers/serial/sandbox.c
+++ b/drivers/serial/sandbox.c
@@ -115,7 +115,9 @@
 		return 0;
 
 	os_usleep(100);
+#ifndef CONFIG_SPL_BUILD
 	video_sync_all();
+#endif
 	if (next_index == serial_buf_read)
 		return 1;	/* buffer full */
 
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 0ce5c44..19f38e1 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -33,7 +33,13 @@
 	struct udevice *dev;
 	int node;
 
-	if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) {
+	if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
+		uclass_first_device(UCLASS_SERIAL, &dev);
+		if (dev) {
+			gd->cur_serial_dev = dev;
+			return;
+		}
+	} else if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) {
 		/* Check for a chosen console */
 		node = fdtdec_get_chosen_node(blob, "stdout-path");
 		if (node < 0) {
diff --git a/drivers/serial/serial_rockchip.c b/drivers/serial/serial_rockchip.c
new file mode 100644
index 0000000..6bac95a
--- /dev/null
+++ b/drivers/serial/serial_rockchip.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <ns16550.h>
+#include <serial.h>
+#include <asm/arch/clock.h>
+
+struct rockchip_uart_platdata {
+	struct dtd_rockchip_rk3288_uart dtplat;
+	struct ns16550_platdata plat;
+};
+
+struct dtd_rockchip_rk3288_uart *dtplat, s_dtplat;
+
+static int rockchip_serial_probe(struct udevice *dev)
+{
+	struct rockchip_uart_platdata *plat = dev_get_platdata(dev);
+
+	/* Create some new platform data for the standard driver */
+	plat->plat.base = plat->dtplat.reg[0];
+	plat->plat.reg_shift = plat->dtplat.reg_shift;
+	plat->plat.clock = plat->dtplat.clock_frequency;
+	dev->platdata = &plat->plat;
+
+	return ns16550_serial_probe(dev);
+}
+
+U_BOOT_DRIVER(rockchip_rk3288_uart) = {
+	.name	= "rockchip_rk3288_uart",
+	.id	= UCLASS_SERIAL,
+	.priv_auto_alloc_size = sizeof(struct NS16550),
+	.platdata_auto_alloc_size = sizeof(struct rockchip_uart_platdata),
+	.probe	= rockchip_serial_probe,
+	.ops	= &ns16550_serial_ops,
+	.flags	= DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c
index cfbfab7..592c0bd 100644
--- a/drivers/serial/serial_stm32x7.c
+++ b/drivers/serial/serial_stm32x7.c
@@ -9,6 +9,7 @@
 #include <dm.h>
 #include <asm/io.h>
 #include <serial.h>
+#include <asm/arch/stm32.h>
 #include <dm/platform_data/serial_stm32x7.h>
 #include "serial_stm32x7.h"
 
@@ -18,7 +19,20 @@
 {
 	struct stm32x7_serial_platdata *plat = dev->platdata;
 	struct stm32_usart *const usart = plat->base;
-	writel(plat->clock/baudrate, &usart->brr);
+	u32  clock, int_div, frac_div, tmp;
+
+	if (((u32)usart & STM32_BUS_MASK) == APB1_PERIPH_BASE)
+		clock = clock_get(CLOCK_APB1);
+	else if (((u32)usart & STM32_BUS_MASK) == APB2_PERIPH_BASE)
+		clock = clock_get(CLOCK_APB2);
+	else
+		return -EINVAL;
+
+	int_div = (25 * clock) / (4 * baudrate);
+	tmp = ((int_div / 100) << USART_BRR_M_SHIFT) & USART_BRR_M_MASK;
+	frac_div = int_div - (100 * (tmp >> USART_BRR_M_SHIFT));
+	tmp |= (((frac_div * 16) + 50) / 100) & USART_BRR_F_MASK;
+	writel(tmp, &usart->brr);
 
 	return 0;
 }
diff --git a/dts/Kconfig b/dts/Kconfig
index c56c129..4b7d8b1 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -85,4 +85,25 @@
 	  can be discarded. This option defines the list of properties to
 	  discard.
 
+config SPL_OF_PLATDATA
+	bool "Generate platform data for use in SPL"
+	depends on SPL_OF_CONTROL
+	help
+	  For very constrained SPL environments the overhead of decoding
+	  device tree nodes and converting their contents into platform data
+	  is too large. This overhead includes libfdt code as well as the
+	  device tree contents itself. The latter is fairly compact, but the
+	  former can add 3KB or more to a Thumb 2 Image.
+
+	  This option enables generation of platform data from the device
+	  tree as C code. This code creates devices using U_BOOT_DEVICE()
+	  declarations. The benefit is that it allows driver code to access
+	  the platform data directly in C structures, avoidin the libfdt
+	  overhead.
+
+	  This option works by generating C structure declarations for each
+	  compatible string, then adding platform data and U_BOOT_DEVICE
+	  declarations for each node. See README.platdata for more
+	  information.
+
 endmenu
diff --git a/include/clk.h b/include/clk.h
index 2f31cf7..161bc28 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -60,6 +60,10 @@
 };
 
 #if CONFIG_IS_ENABLED(OF_CONTROL)
+struct phandle_2_cell;
+int clk_get_by_index_platdata(struct udevice *dev, int index,
+			      struct phandle_2_cell *cells, struct clk *clk);
+
 /**
  * clock_get_by_index - Get/request a clock by integer index.
  *
diff --git a/include/common.h b/include/common.h
index 3feaae6..e9f0dea 100644
--- a/include/common.h
+++ b/include/common.h
@@ -101,6 +101,13 @@
 #define _DEBUG	0
 #endif
 
+#ifdef CONFIG_SPL_BUILD
+#define _SPL_BUILD	1
+#else
+#define _SPL_BUILD	0
+#endif
+
+/* Define this at the top of a file to add a prefix to debug messages */
 #ifndef pr_fmt
 #define pr_fmt(fmt) fmt
 #endif
@@ -116,9 +123,14 @@
 			printf(pr_fmt(fmt), ##args);	\
 	} while (0)
 
+/* Show a message if DEBUG is defined in a file */
 #define debug(fmt, args...)			\
 	debug_cond(_DEBUG, fmt, ##args)
 
+/* Show a message if not in SPL */
+#define warn_non_spl(fmt, args...)			\
+	debug_cond(!_SPL_BUILD, fmt, ##args)
+
 /*
  * An assertion is run-time check done in debug mode only. If DEBUG is not
  * defined then it is skipped. If DEBUG is defined and the assertion fails,
diff --git a/include/configs/dragonboard410c.h b/include/configs/dragonboard410c.h
index 4b00922..1dbe219 100644
--- a/include/configs/dragonboard410c.h
+++ b/include/configs/dragonboard410c.h
@@ -84,8 +84,8 @@
 
 #define BOOT_TARGET_DEVICES(func) \
 	func(USB, usb, 0) \
-	func(MMC, mmc, 0) \
 	func(MMC, mmc, 1) \
+	func(MMC, mmc, 0) \
 	func(DHCP, dhcp, na)
 
 #include <config_distro_bootcmd.h>
@@ -126,6 +126,8 @@
 	"fdtfile=apq8016-sbc.dtb\0" \
 	"fdt_addr_r=0x83000000\0"\
 	"ramdisk_addr_r=0x84000000\0"\
+	"scriptaddr=0x90000000\0"\
+	"pxefile_addr_r=0x90100000\0"\
 	BOOTENV
 
 #define CONFIG_ENV_IS_NOWHERE
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 23a0c40..4de89f8 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -16,8 +16,10 @@
 
 #endif
 
+#ifndef CONFIG_SPL_BUILD
 #define CONFIG_IO_TRACE
 #define CONFIG_CMD_IOTRACE
+#endif
 
 #ifndef CONFIG_TIMER
 #define CONFIG_SYS_TIMER_RATE		1000000
@@ -192,6 +194,7 @@
 #define CONFIG_CMD_LZMADEC
 #define CONFIG_CMD_DATE
 
+#ifndef CONFIG_SPL_BUILD
 #define CONFIG_CMD_IDE
 #define CONFIG_SYS_IDE_MAXBUS		1
 #define CONFIG_SYS_ATA_IDE0_OFFSET	0
@@ -201,6 +204,7 @@
 #define CONFIG_SYS_ATA_REG_OFFSET	1
 #define CONFIG_SYS_ATA_ALT_OFFSET	2
 #define CONFIG_SYS_ATA_STRIDE		4
+#endif
 
 #define CONFIG_SCSI
 #define CONFIG_SCSI_AHCI_PLAT
diff --git a/include/configs/sandbox_spl.h b/include/configs/sandbox_spl.h
new file mode 100644
index 0000000..ffc3098
--- /dev/null
+++ b/include/configs/sandbox_spl.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __SANDBOX_SPL_CONFIG_H
+#define __SANDBOX_SPL_CONFIG_H
+
+#include <configs/sandbox.h>
+
+#define CONFIG_SPL_BOARD_INIT
+
+#define CONFIG_SPL_DRIVERS_MISC_SUPPORT
+#define CONFIG_SPL_ENV_SUPPORT
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
+
+#endif
diff --git a/include/configs/stm32f746-disco.h b/include/configs/stm32f746-disco.h
index e544a21..4391bff 100644
--- a/include/configs/stm32f746-disco.h
+++ b/include/configs/stm32f746-disco.h
@@ -24,13 +24,13 @@
  * Configuration of the external SDRAM memory
  */
 #define CONFIG_NR_DRAM_BANKS		1
-#define CONFIG_SYS_RAM_SIZE		((64 + 192) << 10)
+#define CONFIG_SYS_RAM_SIZE		(8 * 1024 * 1024)
 #define CONFIG_SYS_RAM_CS		1
 #define CONFIG_SYS_RAM_FREQ_DIV		2
-#define CONFIG_SYS_RAM_BASE		0x20000000
+#define CONFIG_SYS_RAM_BASE		0xC0000000
 #define CONFIG_SYS_SDRAM_BASE		CONFIG_SYS_RAM_BASE
-#define CONFIG_SYS_LOAD_ADDR		0x20000000
-#define CONFIG_LOADADDR			0x20000000
+#define CONFIG_SYS_LOAD_ADDR		0xC0400000
+#define CONFIG_LOADADDR			0xC0400000
 
 #define CONFIG_SYS_MAX_FLASH_SECT	8
 #define CONFIG_SYS_MAX_FLASH_BANKS	1
@@ -42,7 +42,8 @@
 #define CONFIG_STM32_FLASH
 #define CONFIG_STM32X7_SERIAL
 
-#define CONFIG_SYS_CLK_FREQ		16*1000*1000 /* 180 MHz */
+#define CONFIG_STM32_HSE_HZ		25000000
+#define CONFIG_SYS_CLK_FREQ		200000000 /* 200 MHz */
 #define CONFIG_SYS_HZ_CLOCK		1000000	/* Timer is clocked at 1MHz */
 
 #define CONFIG_CMDLINE_TAG
diff --git a/include/dm/device.h b/include/dm/device.h
index 1bfcf3b..c825d47 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -42,7 +42,9 @@
 #define DM_FLAG_BOUND			(1 << 6)
 
 /* Device name is allocated and should be freed on unbind() */
-#define DM_NAME_ALLOCED			(1 << 7)
+#define DM_FLAG_NAME_ALLOCED		(1 << 7)
+
+#define DM_FLAG_OF_PLATDATA		(1 << 8)
 
 /**
  * struct udevice - An instance of a driver
@@ -553,7 +555,7 @@
 /**
  * device_set_name_alloced() - note that a device name is allocated
  *
- * This sets the DM_NAME_ALLOCED flag for the device, so that when it is
+ * This sets the DM_FLAG_NAME_ALLOCED flag for the device, so that when it is
  * unbound the name will be freed. This avoids memory leaks.
  *
  * @dev:	Device to update
diff --git a/include/dm/platdata.h b/include/dm/platdata.h
index 6f4f001..488b2ab 100644
--- a/include/dm/platdata.h
+++ b/include/dm/platdata.h
@@ -22,10 +22,15 @@
  *
  * @name:	Driver name
  * @platdata:	Driver-specific platform data
+ * @platdata_size: Size of platform data structure
+ * @flags:	Platform data flags (DM_FLAG_...)
  */
 struct driver_info {
 	const char *name;
 	const void *platdata;
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	uint platdata_size;
+#endif
 };
 
 /**
diff --git a/include/dt-structs.h b/include/dt-structs.h
new file mode 100644
index 0000000..e13afa6
--- /dev/null
+++ b/include/dt-structs.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_STTUCTS
+#define __DT_STTUCTS
+
+/* These structures may only be used in SPL */
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+struct phandle_2_cell {
+	const void *node;
+	int id;
+};
+#include <generated/dt-structs.h>
+#endif
+
+#endif
diff --git a/include/image.h b/include/image.h
index d788c26..2a5b560 100644
--- a/include/image.h
+++ b/include/image.h
@@ -123,62 +123,79 @@
 # define IMAGE_OF_SYSTEM_SETUP	0
 #endif
 
+enum ih_category {
+	IH_ARCH,
+	IH_COMP,
+	IH_OS,
+	IH_TYPE,
+
+	IH_COUNT,
+};
+
 /*
  * Operating System Codes
  */
-#define IH_OS_INVALID		0	/* Invalid OS	*/
-#define IH_OS_OPENBSD		1	/* OpenBSD	*/
-#define IH_OS_NETBSD		2	/* NetBSD	*/
-#define IH_OS_FREEBSD		3	/* FreeBSD	*/
-#define IH_OS_4_4BSD		4	/* 4.4BSD	*/
-#define IH_OS_LINUX		5	/* Linux	*/
-#define IH_OS_SVR4		6	/* SVR4		*/
-#define IH_OS_ESIX		7	/* Esix		*/
-#define IH_OS_SOLARIS		8	/* Solaris	*/
-#define IH_OS_IRIX		9	/* Irix		*/
-#define IH_OS_SCO		10	/* SCO		*/
-#define IH_OS_DELL		11	/* Dell		*/
-#define IH_OS_NCR		12	/* NCR		*/
-#define IH_OS_LYNXOS		13	/* LynxOS	*/
-#define IH_OS_VXWORKS		14	/* VxWorks	*/
-#define IH_OS_PSOS		15	/* pSOS		*/
-#define IH_OS_QNX		16	/* QNX		*/
-#define IH_OS_U_BOOT		17	/* Firmware	*/
-#define IH_OS_RTEMS		18	/* RTEMS	*/
-#define IH_OS_ARTOS		19	/* ARTOS	*/
-#define IH_OS_UNITY		20	/* Unity OS	*/
-#define IH_OS_INTEGRITY		21	/* INTEGRITY	*/
-#define IH_OS_OSE		22	/* OSE		*/
-#define IH_OS_PLAN9		23	/* Plan 9	*/
-#define IH_OS_OPENRTOS		24	/* OpenRTOS	*/
+enum {
+	IH_OS_INVALID		= 0,	/* Invalid OS	*/
+	IH_OS_OPENBSD,			/* OpenBSD	*/
+	IH_OS_NETBSD,			/* NetBSD	*/
+	IH_OS_FREEBSD,			/* FreeBSD	*/
+	IH_OS_4_4BSD,			/* 4.4BSD	*/
+	IH_OS_LINUX,			/* Linux	*/
+	IH_OS_SVR4,			/* SVR4		*/
+	IH_OS_ESIX,			/* Esix		*/
+	IH_OS_SOLARIS,			/* Solaris	*/
+	IH_OS_IRIX,			/* Irix		*/
+	IH_OS_SCO,			/* SCO		*/
+	IH_OS_DELL,			/* Dell		*/
+	IH_OS_NCR,			/* NCR		*/
+	IH_OS_LYNXOS,			/* LynxOS	*/
+	IH_OS_VXWORKS,			/* VxWorks	*/
+	IH_OS_PSOS,			/* pSOS		*/
+	IH_OS_QNX,			/* QNX		*/
+	IH_OS_U_BOOT,			/* Firmware	*/
+	IH_OS_RTEMS,			/* RTEMS	*/
+	IH_OS_ARTOS,			/* ARTOS	*/
+	IH_OS_UNITY,			/* Unity OS	*/
+	IH_OS_INTEGRITY,		/* INTEGRITY	*/
+	IH_OS_OSE,			/* OSE		*/
+	IH_OS_PLAN9,			/* Plan 9	*/
+	IH_OS_OPENRTOS,		/* OpenRTOS	*/
+
+	IH_OS_COUNT,
+};
 
 /*
  * CPU Architecture Codes (supported by Linux)
  */
-#define IH_ARCH_INVALID		0	/* Invalid CPU	*/
-#define IH_ARCH_ALPHA		1	/* Alpha	*/
-#define IH_ARCH_ARM		2	/* ARM		*/
-#define IH_ARCH_I386		3	/* Intel x86	*/
-#define IH_ARCH_IA64		4	/* IA64		*/
-#define IH_ARCH_MIPS		5	/* MIPS		*/
-#define IH_ARCH_MIPS64		6	/* MIPS	 64 Bit */
-#define IH_ARCH_PPC		7	/* PowerPC	*/
-#define IH_ARCH_S390		8	/* IBM S390	*/
-#define IH_ARCH_SH		9	/* SuperH	*/
-#define IH_ARCH_SPARC		10	/* Sparc	*/
-#define IH_ARCH_SPARC64		11	/* Sparc 64 Bit */
-#define IH_ARCH_M68K		12	/* M68K		*/
-#define IH_ARCH_MICROBLAZE	14	/* MicroBlaze   */
-#define IH_ARCH_NIOS2		15	/* Nios-II	*/
-#define IH_ARCH_BLACKFIN	16	/* Blackfin	*/
-#define IH_ARCH_AVR32		17	/* AVR32	*/
-#define IH_ARCH_ST200	        18	/* STMicroelectronics ST200  */
-#define IH_ARCH_SANDBOX		19	/* Sandbox architecture (test only) */
-#define IH_ARCH_NDS32	        20	/* ANDES Technology - NDS32  */
-#define IH_ARCH_OPENRISC        21	/* OpenRISC 1000  */
-#define IH_ARCH_ARM64		22	/* ARM64	*/
-#define IH_ARCH_ARC		23	/* Synopsys DesignWare ARC */
-#define IH_ARCH_X86_64		24	/* AMD x86_64, Intel and Via */
+enum {
+	IH_ARCH_INVALID		= 0,	/* Invalid CPU	*/
+	IH_ARCH_ALPHA,			/* Alpha	*/
+	IH_ARCH_ARM,			/* ARM		*/
+	IH_ARCH_I386,			/* Intel x86	*/
+	IH_ARCH_IA64,			/* IA64		*/
+	IH_ARCH_MIPS,			/* MIPS		*/
+	IH_ARCH_MIPS64,			/* MIPS	 64 Bit */
+	IH_ARCH_PPC,			/* PowerPC	*/
+	IH_ARCH_S390,			/* IBM S390	*/
+	IH_ARCH_SH,			/* SuperH	*/
+	IH_ARCH_SPARC,			/* Sparc	*/
+	IH_ARCH_SPARC64,		/* Sparc 64 Bit */
+	IH_ARCH_M68K,			/* M68K		*/
+	IH_ARCH_MICROBLAZE,		/* MicroBlaze   */
+	IH_ARCH_NIOS2,			/* Nios-II	*/
+	IH_ARCH_BLACKFIN,		/* Blackfin	*/
+	IH_ARCH_AVR32,			/* AVR32	*/
+	IH_ARCH_ST200,			/* STMicroelectronics ST200  */
+	IH_ARCH_SANDBOX,		/* Sandbox architecture (test only) */
+	IH_ARCH_NDS32,			/* ANDES Technology - NDS32  */
+	IH_ARCH_OPENRISC,		/* OpenRISC 1000  */
+	IH_ARCH_ARM64,			/* ARM64	*/
+	IH_ARCH_ARC,			/* Synopsys DesignWare ARC */
+	IH_ARCH_X86_64,			/* AMD x86_64, Intel and Via */
+
+	IH_ARCH_COUNT,
+};
 
 /*
  * Image Types
@@ -219,47 +236,54 @@
  *	as command interpreter (=> Shell Scripts).
  */
 
-#define IH_TYPE_INVALID		0	/* Invalid Image		*/
-#define IH_TYPE_STANDALONE	1	/* Standalone Program		*/
-#define IH_TYPE_KERNEL		2	/* OS Kernel Image		*/
-#define IH_TYPE_RAMDISK		3	/* RAMDisk Image		*/
-#define IH_TYPE_MULTI		4	/* Multi-File Image		*/
-#define IH_TYPE_FIRMWARE	5	/* Firmware Image		*/
-#define IH_TYPE_SCRIPT		6	/* Script file			*/
-#define IH_TYPE_FILESYSTEM	7	/* Filesystem Image (any type)	*/
-#define IH_TYPE_FLATDT		8	/* Binary Flat Device Tree Blob	*/
-#define IH_TYPE_KWBIMAGE	9	/* Kirkwood Boot Image		*/
-#define IH_TYPE_IMXIMAGE	10	/* Freescale IMXBoot Image	*/
-#define IH_TYPE_UBLIMAGE	11	/* Davinci UBL Image		*/
-#define IH_TYPE_OMAPIMAGE	12	/* TI OMAP Config Header Image	*/
-#define IH_TYPE_AISIMAGE	13	/* TI Davinci AIS Image		*/
-#define IH_TYPE_KERNEL_NOLOAD	14	/* OS Kernel Image, can run from any load address */
-#define IH_TYPE_PBLIMAGE	15	/* Freescale PBL Boot Image	*/
-#define IH_TYPE_MXSIMAGE	16	/* Freescale MXSBoot Image	*/
-#define IH_TYPE_GPIMAGE		17	/* TI Keystone GPHeader Image	*/
-#define IH_TYPE_ATMELIMAGE	18	/* ATMEL ROM bootable Image	*/
-#define IH_TYPE_SOCFPGAIMAGE	19	/* Altera SOCFPGA Preloader	*/
-#define IH_TYPE_X86_SETUP	20	/* x86 setup.bin Image		*/
-#define IH_TYPE_LPC32XXIMAGE	21	/* x86 setup.bin Image		*/
-#define IH_TYPE_LOADABLE	22	/* A list of typeless images	*/
-#define IH_TYPE_RKIMAGE		23	/* Rockchip Boot Image		*/
-#define IH_TYPE_RKSD		24	/* Rockchip SD card		*/
-#define IH_TYPE_RKSPI		25	/* Rockchip SPI image		*/
-#define IH_TYPE_ZYNQIMAGE	26	/* Xilinx Zynq Boot Image */
-#define IH_TYPE_ZYNQMPIMAGE	27	/* Xilinx ZynqMP Boot Image */
-#define IH_TYPE_FPGA		28	/* FPGA Image */
+enum {
+	IH_TYPE_INVALID		= 0,	/* Invalid Image		*/
+	IH_TYPE_STANDALONE,		/* Standalone Program		*/
+	IH_TYPE_KERNEL,			/* OS Kernel Image		*/
+	IH_TYPE_RAMDISK,		/* RAMDisk Image		*/
+	IH_TYPE_MULTI,			/* Multi-File Image		*/
+	IH_TYPE_FIRMWARE,		/* Firmware Image		*/
+	IH_TYPE_SCRIPT,			/* Script file			*/
+	IH_TYPE_FILESYSTEM,		/* Filesystem Image (any type)	*/
+	IH_TYPE_FLATDT,			/* Binary Flat Device Tree Blob	*/
+	IH_TYPE_KWBIMAGE,		/* Kirkwood Boot Image		*/
+	IH_TYPE_IMXIMAGE,		/* Freescale IMXBoot Image	*/
+	IH_TYPE_UBLIMAGE,		/* Davinci UBL Image		*/
+	IH_TYPE_OMAPIMAGE,		/* TI OMAP Config Header Image	*/
+	IH_TYPE_AISIMAGE,		/* TI Davinci AIS Image		*/
+	/* OS Kernel Image, can run from any load address */
+	IH_TYPE_KERNEL_NOLOAD,
+	IH_TYPE_PBLIMAGE,		/* Freescale PBL Boot Image	*/
+	IH_TYPE_MXSIMAGE,		/* Freescale MXSBoot Image	*/
+	IH_TYPE_GPIMAGE,		/* TI Keystone GPHeader Image	*/
+	IH_TYPE_ATMELIMAGE,		/* ATMEL ROM bootable Image	*/
+	IH_TYPE_SOCFPGAIMAGE,		/* Altera SOCFPGA Preloader	*/
+	IH_TYPE_X86_SETUP,		/* x86 setup.bin Image		*/
+	IH_TYPE_LPC32XXIMAGE,		/* x86 setup.bin Image		*/
+	IH_TYPE_LOADABLE,		/* A list of typeless images	*/
+	IH_TYPE_RKIMAGE,		/* Rockchip Boot Image		*/
+	IH_TYPE_RKSD,			/* Rockchip SD card		*/
+	IH_TYPE_RKSPI,			/* Rockchip SPI image		*/
+	IH_TYPE_ZYNQIMAGE,		/* Xilinx Zynq Boot Image */
+	IH_TYPE_ZYNQMPIMAGE,		/* Xilinx ZynqMP Boot Image */
+	IH_TYPE_FPGA,			/* FPGA Image */
 
-#define IH_TYPE_COUNT		29	/* Number of image types */
+	IH_TYPE_COUNT,			/* Number of image types */
+};
 
 /*
  * Compression Types
  */
-#define IH_COMP_NONE		0	/*  No	 Compression Used	*/
-#define IH_COMP_GZIP		1	/* gzip	 Compression Used	*/
-#define IH_COMP_BZIP2		2	/* bzip2 Compression Used	*/
-#define IH_COMP_LZMA		3	/* lzma  Compression Used	*/
-#define IH_COMP_LZO		4	/* lzo   Compression Used	*/
-#define IH_COMP_LZ4		5	/* lz4   Compression Used	*/
+enum {
+	IH_COMP_NONE		= 0,	/*  No	 Compression Used	*/
+	IH_COMP_GZIP,			/* gzip	 Compression Used	*/
+	IH_COMP_BZIP2,			/* bzip2 Compression Used	*/
+	IH_COMP_LZMA,			/* lzma  Compression Used	*/
+	IH_COMP_LZO,			/* lzo   Compression Used	*/
+	IH_COMP_LZ4,			/* lz4   Compression Used	*/
+
+	IH_COMP_COUNT,
+};
 
 #define IH_MAGIC	0x27051956	/* Image Magic Number		*/
 #define IH_NMLEN		32	/* Image Name Length		*/
@@ -454,6 +478,40 @@
  */
 const char *genimg_get_comp_short_name(uint8_t comp);
 
+/**
+ * genimg_get_cat_name() - Get the name of an item in a category
+ *
+ * @category:	Category of item
+ * @id:		Item ID
+ * @return name of item, or "Unknown ..." if unknown
+ */
+const char *genimg_get_cat_name(enum ih_category category, uint id);
+
+/**
+ * genimg_get_cat_short_name() - Get the short name of an item in a category
+ *
+ * @category:	Category of item
+ * @id:		Item ID
+ * @return short name of item, or "Unknown ..." if unknown
+ */
+const char *genimg_get_cat_short_name(enum ih_category category, uint id);
+
+/**
+ * genimg_get_cat_count() - Get the number of items in a category
+ *
+ * @category:	Category to check
+ * @return the number of items in the category (IH_xxx_COUNT)
+ */
+int genimg_get_cat_count(enum ih_category category);
+
+/**
+ * genimg_get_cat_desc() - Get the description of a category
+ *
+ * @return the description of a category, e.g. "architecture". This
+ * effectively converts the enum to a string.
+ */
+const char *genimg_get_cat_desc(enum ih_category category);
+
 int genimg_get_os_id(const char *name);
 int genimg_get_arch_id(const char *name);
 int genimg_get_type_id(const char *name);
@@ -1173,4 +1231,21 @@
  */
 int board_fit_config_name_match(const char *name);
 
+#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
+/**
+ * board_fit_image_post_process() - Do any post-process on FIT binary data
+ *
+ * This is used to do any sort of image manipulation, verification, decryption
+ * etc. in a platform or board specific way. Obviously, anything done here would
+ * need to be comprehended in how the images were prepared before being injected
+ * into the FIT creation (i.e. the binary blobs would have been pre-processed
+ * before being added to the FIT image).
+ *
+ * @image: pointer to the image start pointer
+ * @size: pointer to the image size
+ * @return no return value (failure should be handled internally)
+ */
+void board_fit_image_post_process(void **p_image, size_t *p_size);
+#endif /* CONFIG_SPL_FIT_IMAGE_POST_PROCESS */
+
 #endif	/* __IMAGE_H__ */
diff --git a/include/linux/io.h b/include/linux/io.h
index 1b36a22..a104b7e 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -5,6 +5,22 @@
 #ifndef _LINUX_IO_H
 #define _LINUX_IO_H
 
+#include <linux/compiler.h>
+#include <linux/types.h>
 #include <asm/io.h>
 
+#ifndef CONFIG_HAVE_ARCH_IOREMAP
+static inline void __iomem *ioremap(resource_size_t offset,
+				    resource_size_t size)
+{
+	return (void __iomem *)(unsigned long)offset;
+}
+
+static inline void iounmap(void __iomem *addr)
+{
+}
+
+#define devm_ioremap(dev, offset, size)		ioremap(offset, size)
+#endif
+
 #endif /* _LINUX_IO_H */
diff --git a/include/linux/types.h b/include/linux/types.h
index 6f75be4..416fa66 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -124,6 +124,10 @@
 typedef		__INT64_TYPE__		int64_t;
 #endif
 
+#ifdef __KERNEL__
+typedef phys_addr_t resource_size_t;
+#endif
+
 /*
  * Below are truly Linux-specific types that should never collide with
  * any application/library that wants linux/types.h.
diff --git a/include/os.h b/include/os.h
index 954a48c..1782e50 100644
--- a/include/os.h
+++ b/include/os.h
@@ -287,6 +287,31 @@
 int os_jump_to_image(const void *dest, int size);
 
 /**
+ * os_find_u_boot() - Determine the path to U-Boot proper
+ *
+ * This function is intended to be called from within sandbox SPL. It uses
+ * a few heuristics to find U-Boot proper. Normally it is either in the same
+ * directory, or the directory above (since u-boot-spl is normally in an
+ * spl/ subdirectory when built).
+ *
+ * @fname:	Place to put full path to U-Boot
+ * @maxlen:	Maximum size of @fname
+ * @return 0 if OK, -NOSPC if the filename is too large, -ENOENT if not found
+ */
+int os_find_u_boot(char *fname, int maxlen);
+
+/**
+ * os_spl_to_uboot() - Run U-Boot proper
+ *
+ * When called from SPL, this runs U-Boot proper. The filename is obtained by
+ * calling os_find_u_boot().
+ *
+ * @fname:	Full pathname to U-Boot executable
+ * @return 0 if OK, -ve on error
+ */
+int os_spl_to_uboot(const char *fname);
+
+/**
  * Read the current system time
  *
  * This reads the current Local Time and places it into the provided
diff --git a/include/regmap.h b/include/regmap.h
index eccf770..1eed94e 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -57,6 +57,22 @@
 int regmap_init_mem(struct udevice *dev, struct regmap **mapp);
 
 /**
+ * regmap_init_mem_platdata() - Set up a new memory register map for of-platdata
+ *
+ * This creates a new regmap with a list of regions passed in, rather than
+ * using the device tree. It only supports 32-bit machines.
+ *
+ * Use regmap_uninit() to free it.
+ *
+ * @dev:	Device that uses this map
+ * @reg:	List of address, size pairs
+ * @count:	Number of pairs (e.g. 1 if the regmap has a single entry)
+ * @mapp:	Returns allocated map
+ */
+int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
+			     struct regmap **mapp);
+
+/**
  * regmap_get_range() - Obtain the base memory address of a regmap range
  *
  * @map:	Regmap to query
diff --git a/include/syscon.h b/include/syscon.h
index 4593b6e..34842aa 100644
--- a/include/syscon.h
+++ b/include/syscon.h
@@ -23,6 +23,17 @@
 
 #define syscon_get_ops(dev)        ((struct syscon_ops *)(dev)->driver->ops)
 
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+/*
+ * We don't support 64-bit machines. If they are so resource-contrained that
+ * they need to use OF_PLATDATA, something is horribly wrong with the
+ * education of our hardware engineers.
+ */
+struct syscon_base_platdata {
+	u32 reg[2];
+};
+#endif
+
 /**
  * syscon_get_regmap() - Get access to a register map
  *
diff --git a/lib/Makefile b/lib/Makefile
index f48d901..f6a8ba1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -48,11 +48,10 @@
 obj-$(CONFIG_$(SPL_)SHA256) += sha256.o
 
 obj-$(CONFIG_$(SPL_)OF_LIBFDT) += libfdt/
-ifdef CONFIG_SPL_OF_CONTROL
-obj-$(CONFIG_OF_LIBFDT) += libfdt/
-endif
+ifneq ($(CONFIG_SPL_BUILD)$(CONFIG_SPL_OF_PLATDATA),yy)
 obj-$(CONFIG_$(SPL_)OF_CONTROL) += fdtdec_common.o
 obj-$(CONFIG_$(SPL_)OF_CONTROL) += fdtdec.o
+endif
 
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o
diff --git a/lib/libfdt/libfdt.swig b/lib/libfdt/libfdt.swig
new file mode 100644
index 0000000..14f583d
--- /dev/null
+++ b/lib/libfdt/libfdt.swig
@@ -0,0 +1,89 @@
+/* File: libfdt.i */
+%module libfdt
+
+%{
+#define SWIG_FILE_WITH_INIT
+#include "libfdt.h"
+%}
+
+%pythoncode %{
+def Raise(errnum):
+    raise ValueError('Error %s' % fdt_strerror(errnum))
+
+def Name(fdt, offset):
+    name, len = fdt_get_name(fdt, offset)
+    return name
+
+def String(fdt, offset):
+    offset = fdt32_to_cpu(offset)
+    name = fdt_string(fdt, offset)
+    return name
+
+def swap32(x):
+    return (((x << 24) & 0xFF000000) |
+            ((x <<  8) & 0x00FF0000) |
+            ((x >>  8) & 0x0000FF00) |
+            ((x >> 24) & 0x000000FF))
+
+def fdt32_to_cpu(x):
+    return swap32(x)
+
+def Data(prop):
+    set_prop(prop)
+    return get_prop_data()
+%}
+
+%include "typemaps.i"
+%include "cstring.i"
+
+%typemap(in) void* = char*;
+
+typedef int fdt32_t;
+
+struct fdt_property {
+        fdt32_t tag;
+        fdt32_t len;
+        fdt32_t nameoff;
+        char data[0];
+};
+
+/*
+ * This is a work-around since I'm not sure of a better way to copy out the
+ * contents of a string. This is used in dtoc/GetProps(). The intent is to
+ * pass in a pointer to a property and access the data field at the end of
+ * it. Ideally the Data() function above would be able to do this directly,
+ * but I'm not sure how to do that.
+ */
+#pragma SWIG nowarn=454
+%inline %{
+    static struct fdt_property *cur_prop;
+
+    void set_prop(struct fdt_property *prop) {
+        cur_prop = prop;
+    }
+%}
+
+%cstring_output_allocate_size(char **s, int *sz, free(*$1));
+%inline %{
+    void get_prop_data(char **s, int *sz) {
+        *sz = fdt32_to_cpu(cur_prop->len);
+        *s = (char *)malloc(*sz);
+        if (!*s)
+            *sz = 0;
+        else
+            memcpy(*s, cur_prop + 1, *sz);
+    }
+%}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+int fdt_path_offset(const void *fdt, const char *path);
+int fdt_first_property_offset(const void *fdt, int nodeoffset);
+int fdt_next_property_offset(const void *fdt, int offset);
+const char *fdt_strerror(int errval);
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+                                                      int offset,
+                                                      int *OUTPUT);
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *OUTPUT);
+const char *fdt_string(const void *fdt, int stroffset);
+int fdt_first_subnode(const void *fdt, int offset);
+int fdt_next_subnode(const void *fdt, int offset);
diff --git a/lib/libfdt/setup.py b/lib/libfdt/setup.py
new file mode 100644
index 0000000..62e7bcc
--- /dev/null
+++ b/lib/libfdt/setup.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+"""
+setup.py file for SWIG libfdt
+"""
+
+from distutils.core import setup, Extension
+import os
+import sys
+
+# Don't cross-compile - always use the host compiler.
+del os.environ['CROSS_COMPILE']
+del os.environ['CC']
+
+progname = sys.argv[0]
+cflags = sys.argv[1]
+files = sys.argv[2:]
+
+if cflags:
+    cflags = [flag for flag in cflags.split(' ') if flag]
+else:
+    cflags = None
+
+libfdt_module = Extension(
+    '_libfdt',
+    sources = files,
+    extra_compile_args =  cflags
+)
+
+sys.argv = [progname, '--quiet', 'build_ext', '--inplace']
+
+setup (name = 'libfdt',
+       version = '0.1',
+       author      = "SWIG Docs",
+       description = """Simple swig libfdt from docs""",
+       ext_modules = [libfdt_module],
+       py_modules = ["libfdt"],
+       )
diff --git a/lib/libfdt/test_libfdt.py b/lib/libfdt/test_libfdt.py
new file mode 100644
index 0000000..14d0da4
--- /dev/null
+++ b/lib/libfdt/test_libfdt.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+
+import os
+import sys
+
+our_path = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(our_path, '../../b/sandbox_spl/tools'))
+
+import libfdt
+
+with open('b/sandbox_spl/u-boot.dtb') as fd:
+    fdt = fd.read()
+
+print libfdt.fdt_path_offset(fdt, "/aliases")
diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c
index b334f05..1aa43ab 100644
--- a/lib/tiny-printf.c
+++ b/lib/tiny-printf.c
@@ -185,3 +185,12 @@
 
 	return ret;
 }
+
+void __assert_fail(const char *assertion, const char *file, unsigned line,
+		   const char *function)
+{
+	/* This will not return */
+	printf("%s:%u: %s: Assertion `%s' failed.", file, line, function,
+	       assertion);
+	hang();
+}
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index bff8b5b..763a699 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -28,12 +28,16 @@
 # C code
 # Executables compiled from a single .c file
 host-csingle	:= $(foreach m,$(__hostprogs), \
-			$(if $($(m)-objs)$($(m)-cxxobjs),,$(m)))
+			$(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-sharedobjs),,$(m)))
 
 # C executables linked based on several .o files
 host-cmulti	:= $(foreach m,$(__hostprogs),\
 		   $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
 
+# Shared object libraries
+host-shared	:= $(foreach m,$(__hostprogs),\
+		   $(if $($(m)-sharedobjs),$(m))))
+
 # Object (.o) files compiled from .c files
 host-cobjs	:= $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
 
@@ -59,6 +63,7 @@
 host-cobjs	:= $(addprefix $(obj)/,$(host-cobjs))
 host-cxxmulti	:= $(addprefix $(obj)/,$(host-cxxmulti))
 host-cxxobjs	:= $(addprefix $(obj)/,$(host-cxxobjs))
+host-shared	:= $(addprefix $(obj)/,$(host-shared))
 host-objdirs    := $(addprefix $(obj)/,$(host-objdirs))
 
 obj-dirs += $(host-objdirs)
@@ -128,4 +133,4 @@
 	$(call if_changed_dep,host-cxxobjs)
 
 targets += $(host-csingle)  $(host-cmulti) $(host-cobjs)\
-	   $(host-cxxmulti) $(host-cxxobjs)
+	   $(host-cxxmulti) $(host-cxxobjs) $(host-shared)
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 0997fd9..3ba9742 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -45,6 +45,7 @@
 # FIX ME
 cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) \
 							$(NOSTDINC_FLAGS)
+c_flags := $(KBUILD_CFLAGS) $(cpp_flags)
 
 HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(srctree)/board/$(VENDOR)/common/Makefile),y,n)
 
@@ -76,6 +77,9 @@
 
 u-boot-spl-init := $(head-y)
 u-boot-spl-main := $(libs-y)
+ifdef CONFIG_SPL_OF_PLATDATA
+u-boot-spl-platdata := $(obj)/dts/dt-platdata.o
+endif
 
 # Linker Script
 ifdef CONFIG_SPL_LDSCRIPT
@@ -169,7 +173,7 @@
 quiet_cmd_copy = COPY    $@
       cmd_copy = cp $< $@
 
-ifeq ($(CONFIG_SPL_OF_CONTROL)$(CONFIG_OF_SEPARATE),yy)
+ifeq ($(CONFIG_SPL_OF_CONTROL)$(CONFIG_OF_SEPARATE)$(CONFIG_SPL_OF_PLATDATA),yy)
 $(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin $(obj)/$(SPL_BIN)-pad.bin \
 		$(obj)/$(SPL_BIN).dtb FORCE
 	$(call if_changed,cat)
@@ -207,6 +211,32 @@
 $(obj)/$(SPL_BIN).cfg:	include/config.h FORCE
 	$(call if_changed,cpp_cfg)
 
+pythonpath = PYTHONPATH=tools
+
+quiet_cmd_dtocc = DTOC C  $@
+cmd_dtocc = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o $@ platdata
+
+quiet_cmd_dtoch = DTOC H  $@
+cmd_dtoch = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o $@ struct
+
+quiet_cmd_plat = PLAT    $@
+cmd_plat = $(CC) $(c_flags) -c $< -o $@
+
+$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c include/generated/dt-structs.h
+	$(call if_changed,plat)
+
+PHONY += dts_dir
+dts_dir:
+	$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
+
+include/generated/dt-structs.h: $(obj)/$(SPL_BIN).dtb dts_dir dtoc
+	$(call if_changed,dtoch)
+
+$(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir dtoc
+	$(call if_changed,dtocc)
+
+dtoc: #$(objtree)/tools/_libfdt.so
+
 ifdef CONFIG_SAMSUNG
 ifdef CONFIG_VAR_SIZE_SPL
 VAR_SIZE_PARAM = --vs
@@ -241,19 +271,24 @@
 $(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE
 	$(call if_changed,mksunxiboot)
 
-quiet_cmd_u-boot-spl = LD      $@
-      cmd_u-boot-spl = (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
+# Rule to link u-boot-spl
+# May be overridden by arch/$(ARCH)/config.mk
+quiet_cmd_u-boot-spl ?= LD      $@
+      cmd_u-boot-spl ?= (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
 		       $(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \
-		       $(patsubst $(obj)/%,%,$(u-boot-spl-main)) --end-group \
+		       $(patsubst $(obj)/%,%,$(u-boot-spl-main))  \
+		       $(patsubst $(obj)/%,%,$(u-boot-spl-platdata)) \
+		       --end-group \
 		       $(PLATFORM_LIBS) -Map $(SPL_BIN).map -o $(SPL_BIN))
 
-$(obj)/$(SPL_BIN): $(u-boot-spl-init) $(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE
+$(obj)/$(SPL_BIN): $(u-boot-spl-platdata) $(u-boot-spl-init) \
+		$(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE
 	$(call if_changed,u-boot-spl)
 
 $(sort $(u-boot-spl-init) $(u-boot-spl-main)): $(u-boot-spl-dirs) ;
 
 PHONY += $(u-boot-spl-dirs)
-$(u-boot-spl-dirs):
+$(u-boot-spl-dirs): $(u-boot-spl-platdata)
 	$(Q)$(MAKE) $(build)=$@
 
 quiet_cmd_cpp_lds = LDS     $@
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..ee55972
--- /dev/null
+++ b/test/README
@@ -0,0 +1,92 @@
+Testing in U-Boot
+=================
+
+U-Boot has a large amount of code. This file describes how this code is
+tested and what tests you should write when adding a new feature.
+
+
+Running tests
+-------------
+
+To run most tests on sandbox, type this:
+
+    test/run
+
+in the U-Boot directory. Note that only the pytest suite is run using this
+comment.
+
+
+Sandbox
+-------
+U-Boot can be built as a user-space application (e.g. for Linux). This
+allows test to be executed without needing target hardware. The 'sandbox'
+target provides this feature and it is widely used in tests.
+
+
+Pytest Suite
+------------
+
+Many tests are available using the pytest suite, in test/py. This can run
+either on sandbox or on real hardware. It relies on the U-Boot console to
+inject test commands and check the result. It is slower to run than C code,
+but provides the ability to unify lots of test and summarise their results.
+
+You can run the tests on sandbox with:
+
+	./test/py/test.py --bd sandbox --build
+
+This will produce HTML output in build-sandbox/test-log.html
+
+See test/py/README.md for more information about the pytest suite.
+
+
+tbot
+----
+
+Tbot provides a way to execute tests on target hardware. It is intended for
+trying out both U-Boot and Linux (and potentially other software) on a
+number of boards automatically. It can be used to create a continuous test
+environment. See tools/tbot/README for more information.
+
+
+Ad-hoc tests
+------------
+
+There are several ad-hoc tests which run outside the pytest environment:
+
+   test/fs	- File system test (shell script)
+   test/image	- FIT and lagacy image tests (shell script and Python)
+   test/stdint	- A test that stdint.h can be used in U-Boot (shell script)
+   trace	- Test for the tracing feature (shell script)
+
+The above should be converted to run as part of the pytest suite.
+
+
+When to write tests
+-------------------
+
+If you add code to U-Boot without a test you are taking a risk. Even if you
+perform thorough manual testing at the time of submission, it may break when
+future changes are made to U-Boot. It may even break when applied to mainline,
+if other changes interact with it. A good mindset is that untested code
+probably doesn't work and should be deleted.
+
+You can assume that the Pytest suite will be run before patches are accepted
+to mainline, so this provides protection against future breakage.
+
+On the other hand there is quite a bit of code that is not covered with tests,
+or is covered sparingly. So here are some suggestions:
+
+- If you are adding a new uclass, add a sandbox driver and a test that uses it
+- If you are modifying code covered by an existing test, add a new test case
+  to cover your changes
+- If the code you are modifying has not tests, consider writing one. Even a
+  very basic test is useful, and may be picked up and enhanced by others. It
+  is much easier to add onto a test - writing a new large test can seem
+  daunting to most contributors.
+
+
+Future work
+-----------
+
+Converting existing shell scripts into pytest tests.
diff --git a/test/py/conftest.py b/test/py/conftest.py
index 449f98b..5b3a923 100644
--- a/test/py/conftest.py
+++ b/test/py/conftest.py
@@ -179,6 +179,7 @@
     ubconfig.board_type = board_type
     ubconfig.board_identity = board_identity
     ubconfig.gdbserver = gdbserver
+    ubconfig.dtb = build_dir + '/arch/sandbox/dts/test.dtb'
 
     env_vars = (
         'board_type',
@@ -192,7 +193,7 @@
     for v in env_vars:
         os.environ['U_BOOT_' + v.upper()] = getattr(ubconfig, v)
 
-    if board_type == 'sandbox':
+    if board_type.startswith('sandbox'):
         import u_boot_console_sandbox
         console = u_boot_console_sandbox.ConsoleSandbox(log, ubconfig)
     else:
diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py
index 68917eb..35a32fb 100644
--- a/test/py/multiplexed_log.py
+++ b/test/py/multiplexed_log.py
@@ -101,6 +101,7 @@
         self.logfile = logfile
         self.name = name
         self.chained_file = chained_file
+        self.output = None
 
     def close(self):
         """Clean up any resources managed by this object."""
@@ -109,6 +110,9 @@
     def run(self, cmd, cwd=None, ignore_errors=False):
         """Run a command as a sub-process, and log the results.
 
+        The output is available at self.output which can be useful if there is
+        an exception.
+
         Args:
             cmd: The command to execute.
             cwd: The directory to run the command in. Can be None to use the
@@ -119,7 +123,7 @@
                 raised if such problems occur.
 
         Returns:
-            Nothing.
+            The output as a string.
         """
 
         msg = '+' + ' '.join(cmd) + '\n'
@@ -159,8 +163,12 @@
         self.logfile.write(self, output)
         if self.chained_file:
             self.chained_file.write(output)
+
+        # Store the output so it can be accessed if we raise an exception.
+        self.output = output
         if exception:
             raise exception
+        return output
 
 class SectionCtxMgr(object):
     """A context manager for Python's "with" statement, which allows a certain
diff --git a/test/py/tests/test_ofplatdata.py b/test/py/tests/test_ofplatdata.py
new file mode 100644
index 0000000..c8b309e
--- /dev/null
+++ b/test/py/tests/test_ofplatdata.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2016 Google, Inc
+#
+# SPDX-License-Identifier: GPL-2.0+
+
+import pytest
+
+OF_PLATDATA_OUTPUT = '''
+of-platdata probe:
+bool 1
+byte 05
+bytearray 06 00 00
+int 1
+intarray 2 3 4 0
+longbytearray 09 0a 0b 0c 0d 0e 0f 10 11
+string message
+stringarray "multi-word" "message" ""
+of-platdata probe:
+bool 0
+byte 08
+bytearray 01 23 34
+int 3
+intarray 5 0 0 0
+longbytearray 09 00 00 00 00 00 00 00 00
+string message2
+stringarray "another" "multi-word" "message"
+of-platdata probe:
+bool 0
+byte 00
+bytearray 00 00 00
+int 0
+intarray 0 0 0 0
+longbytearray 00 00 00 00 00 00 00 00 00
+string <NULL>
+stringarray "one" "" ""
+'''
+
+@pytest.mark.buildconfigspec('spl')
+def test_ofplatdata(u_boot_console):
+    """Test that of-platdata can be generated and used in sandbox"""
+    cons = u_boot_console
+    output = cons.get_spawn_output().replace('\r', '')
+    assert OF_PLATDATA_OUTPUT in output
diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py
new file mode 100644
index 0000000..c779895
--- /dev/null
+++ b/test/py/tests/test_vboot.py
@@ -0,0 +1,185 @@
+# Copyright (c) 2013, Google Inc.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+# U-Boot Verified Boot Test
+
+"""
+This tests verified boot in the following ways:
+
+For image verification:
+- Create FIT (unsigned) with mkimage
+- Check that verification shows that no keys are verified
+- Sign image
+- Check that verification shows that a key is now verified
+
+For configuration verification:
+- Corrupt signature and check for failure
+- Create FIT (with unsigned configuration) with mkimage
+- Check that image veriication works
+- Sign the FIT and mark the key as 'required' for verification
+- Check that image verification works
+- Corrupt the signature
+- Check that image verification no-longer works
+
+Tests run with both SHA1 and SHA256 hashing.
+"""
+
+import pytest
+import sys
+import u_boot_utils as util
+
+@pytest.mark.buildconfigspec('fit_signature')
+def test_vboot(u_boot_console):
+    """Test verified boot signing with mkimage and verification with 'bootm'.
+
+    This works using sandbox only as it needs to update the device tree used
+    by U-Boot to hold public keys from the signing process.
+
+    The SHA1 and SHA256 tests are combined into a single test since the
+    key-generation process is quite slow and we want to avoid doing it twice.
+    """
+    def dtc(dts):
+        """Run the device-tree compiler to compile a .dts file
+
+        The output file will be the same as the input file but with a .dtb
+        extension.
+
+        Args:
+            dts: Device tree file to compile.
+        """
+        dtb = dts.replace('.dts', '.dtb')
+        util.cmd(cons, 'dtc %s %s%s -O dtb '
+                       '-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb))
+
+    def run_bootm(test_type, expect_string):
+        """Run a 'bootm' command U-Boot.
+
+        This always starts a fresh U-Boot instance since the device tree may
+        contain a new public key.
+
+        Args:
+            test_type: A string identifying the test type
+            expect_string: A string which is expected in the output
+        """
+        cons.cleanup_spawn()
+        cons.ensure_spawned()
+        cons.log.action('%s: Test Verified Boot Run: %s' % (algo, test_type))
+        output = cons.run_command_list(
+            ['sb load hostfs - 100 %stest.fit' % tmpdir,
+             'fdt addr 100',
+             'bootm 100'])
+        assert(expect_string in output)
+
+    def make_fit(its):
+        """Make a new FIT from the .its source file
+
+        This runs 'mkimage -f' to create a new FIT.
+
+        Args:
+            its: Filename containing .its source
+        """
+        util.run_and_log(cons, [mkimage, '-D', dtc_args, '-f',
+                                '%s%s' % (datadir, its), fit])
+
+    def sign_fit():
+        """Sign the FIT
+
+        Signs the FIT and writes the signature into it. It also writes the
+        public key into the dtb.
+        """
+        cons.log.action('%s: Sign images' % algo)
+        util.run_and_log(cons, [mkimage, '-F', '-k', tmpdir, '-K', dtb,
+                                '-r', fit])
+
+    def test_with_algo(sha):
+        """Test verified boot with the given hash algorithm
+
+        This is the main part of the test code. The same procedure is followed
+        for both hashing algorithms.
+
+        Args:
+            sha: Either 'sha1' or 'sha256', to select the algorithm to use
+        """
+        global algo
+
+        algo = sha
+
+        # Compile our device tree files for kernel and U-Boot
+        dtc('sandbox-kernel.dts')
+        dtc('sandbox-u-boot.dts')
+
+        # Build the FIT, but don't sign anything yet
+        cons.log.action('%s: Test FIT with signed images' % algo)
+        make_fit('sign-images-%s.its' % algo)
+        run_bootm('unsigned images', 'dev-')
+
+        # Sign images with our dev keys
+        sign_fit()
+        run_bootm('signed images', 'dev+')
+
+        # Create a fresh .dtb without the public keys
+        dtc('sandbox-u-boot.dts')
+
+        cons.log.action('%s: Test FIT with signed configuration' % algo)
+        make_fit('sign-configs-%s.its' % algo)
+        run_bootm('unsigned config', '%s+ OK' % algo)
+
+        # Sign images with our dev keys
+        sign_fit()
+        run_bootm('signed config', 'dev+')
+
+        cons.log.action('%s: Check signed config on the host' % algo)
+
+        util.run_and_log(cons, [fit_check_sign, '-f', fit, '-k', tmpdir,
+                                '-k', dtb])
+
+        # Increment the first byte of the signature, which should cause failure
+        sig = util.cmd(cons, 'fdtget -t bx %s %s value' % (fit, sig_node))
+        byte_list = sig.split()
+        byte = int(byte_list[0], 16)
+        byte_list = ['%x' % (byte + 1)] + byte_list[1:]
+        sig = ' '.join(byte_list)
+        util.cmd(cons, 'fdtput -t bx %s %s value %s' % (fit, sig_node, sig))
+
+        run_bootm('Signed config with bad hash', 'Bad Data Hash')
+
+        cons.log.action('%s: Check bad config on the host' % algo)
+        util.run_and_log_expect_exception(cons, [fit_check_sign, '-f', fit,
+                '-k', dtb], 1, 'Failed to verify required signature')
+
+    cons = u_boot_console
+    tmpdir = cons.config.result_dir + '/'
+    tmp = tmpdir + 'vboot.tmp'
+    datadir = 'test/py/tests/vboot/'
+    fit = '%stest.fit' % tmpdir
+    mkimage = cons.config.build_dir + '/tools/mkimage'
+    fit_check_sign = cons.config.build_dir + '/tools/fit_check_sign'
+    dtc_args = '-I dts -O dtb -i %s' % tmpdir
+    dtb = '%ssandbox-u-boot.dtb' % tmpdir
+    sig_node = '/configurations/conf@1/signature@1'
+
+    # Create an RSA key pair
+    public_exponent = 65537
+    util.cmd(cons, 'openssl genpkey -algorithm RSA -out %sdev.key '
+                   '-pkeyopt rsa_keygen_bits:2048 '
+                   '-pkeyopt rsa_keygen_pubexp:%d '
+                   '2>/dev/null'  % (tmpdir, public_exponent))
+
+    # Create a certificate containing the public key
+    util.cmd(cons, 'openssl req -batch -new -x509 -key %sdev.key -out '
+                   '%sdev.crt' % (tmpdir, tmpdir))
+
+    # Create a number kernel image with zeroes
+    with open('%stest-kernel.bin' % tmpdir, 'w') as fd:
+        fd.write(5000 * chr(0))
+
+    try:
+        # We need to use our own device tree file. Remember to restore it
+        # afterwards.
+        old_dtb = cons.config.dtb
+        cons.config.dtb = dtb
+        test_with_algo('sha1')
+        test_with_algo('sha256')
+    finally:
+        cons.config.dtb = old_dtb
diff --git a/test/vboot/sandbox-kernel.dts b/test/py/tests/vboot/sandbox-kernel.dts
similarity index 100%
rename from test/vboot/sandbox-kernel.dts
rename to test/py/tests/vboot/sandbox-kernel.dts
diff --git a/test/vboot/sandbox-u-boot.dts b/test/py/tests/vboot/sandbox-u-boot.dts
similarity index 100%
rename from test/vboot/sandbox-u-boot.dts
rename to test/py/tests/vboot/sandbox-u-boot.dts
diff --git a/test/vboot/sign-configs-sha1.its b/test/py/tests/vboot/sign-configs-sha1.its
similarity index 100%
rename from test/vboot/sign-configs-sha1.its
rename to test/py/tests/vboot/sign-configs-sha1.its
diff --git a/test/vboot/sign-configs-sha256.its b/test/py/tests/vboot/sign-configs-sha256.its
similarity index 100%
rename from test/vboot/sign-configs-sha256.its
rename to test/py/tests/vboot/sign-configs-sha256.its
diff --git a/test/vboot/sign-images-sha1.its b/test/py/tests/vboot/sign-images-sha1.its
similarity index 100%
rename from test/vboot/sign-images-sha1.its
rename to test/py/tests/vboot/sign-images-sha1.its
diff --git a/test/vboot/sign-images-sha256.its b/test/py/tests/vboot/sign-images-sha256.its
similarity index 100%
rename from test/vboot/sign-images-sha256.its
rename to test/py/tests/vboot/sign-images-sha256.its
diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py
index 815fa64..4606ad4 100644
--- a/test/py/u_boot_console_base.py
+++ b/test/py/u_boot_console_base.py
@@ -216,6 +216,22 @@
             self.cleanup_spawn()
             raise
 
+    def run_command_list(self, cmds):
+        """Run a list of commands.
+
+        This is a helper function to call run_command() with default arguments
+        for each command in a list.
+
+        Args:
+            cmd: List of commands (each a string)
+        Returns:
+            Combined output of all commands, as a string
+        """
+        output = ''
+        for cmd in cmds:
+            output += self.run_command(cmd)
+        return output
+
     def ctrlc(self):
         """Send a CTRL-C character to U-Boot.
 
@@ -329,7 +345,7 @@
                 m = self.p.expect([pattern_u_boot_spl_signon] +
                                   self.bad_patterns)
                 if m != 0:
-                    raise Exception('Bad pattern found on console: ' +
+                    raise Exception('Bad pattern found on SPL console: ' +
                                     self.bad_pattern_ids[m - 1])
             m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns)
             if m != 0:
@@ -377,6 +393,16 @@
             pass
         self.p = None
 
+    def get_spawn_output(self):
+        """Return the start-up output from U-Boot
+
+        Returns:
+            The output produced by ensure_spawed(), as a string.
+        """
+        if self.p:
+            return self.p.get_expect_output()
+        return None
+
     def validate_version_string_in_text(self, text):
         """Assert that a command's output includes the U-Boot signon message.
 
diff --git a/test/py/u_boot_console_sandbox.py b/test/py/u_boot_console_sandbox.py
index 04654ae..647e1f8 100644
--- a/test/py/u_boot_console_sandbox.py
+++ b/test/py/u_boot_console_sandbox.py
@@ -39,14 +39,18 @@
             A u_boot_spawn.Spawn object that is attached to U-Boot.
         """
 
+        bcfg = self.config.buildconfig
+        config_spl = bcfg.get('config_spl', 'n') == 'y'
+        fname = '/spl/u-boot-spl' if config_spl else '/u-boot'
+        print fname
         cmd = []
         if self.config.gdbserver:
             cmd += ['gdbserver', self.config.gdbserver]
         cmd += [
-            self.config.build_dir + '/u-boot',
+            self.config.build_dir + fname,
             '-v',
             '-d',
-            self.config.build_dir + '/arch/sandbox/dts/test.dtb'
+            self.config.dtb
         ]
         return Spawn(cmd, cwd=self.config.source_dir)
 
diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py
index d155173..3a0fbfa 100644
--- a/test/py/u_boot_spawn.py
+++ b/test/py/u_boot_spawn.py
@@ -18,6 +18,9 @@
 class Spawn(object):
     """Represents the stdio of a freshly created sub-process. Commands may be
     sent to the process, and responses waited for.
+
+    Members:
+        output: accumulated output from expect()
     """
 
     def __init__(self, args, cwd=None):
@@ -34,6 +37,7 @@
 
         self.waited = False
         self.buf = ''
+        self.output = ''
         self.logfile_read = None
         self.before = ''
         self.after = ''
@@ -154,6 +158,7 @@
                     posafter = earliest_m.end()
                     self.before = self.buf[:pos]
                     self.after = self.buf[pos:posafter]
+                    self.output += self.buf[:posafter]
                     self.buf = self.buf[posafter:]
                     return earliest_pi
                 tnow_s = time.time()
@@ -198,3 +203,11 @@
             if not self.isalive():
                 break
             time.sleep(0.1)
+
+    def get_expect_output(self):
+        """Return the output read by expect()
+
+        Returns:
+            The output processed by expect(), as a string.
+        """
+        return self.output
diff --git a/test/py/u_boot_utils.py b/test/py/u_boot_utils.py
index e4765e3..e358c58 100644
--- a/test/py/u_boot_utils.py
+++ b/test/py/u_boot_utils.py
@@ -165,12 +165,47 @@
             problems occur.
 
     Returns:
-        Nothing.
+        The output as a string.
     """
 
     runner = u_boot_console.log.get_runner(cmd[0], sys.stdout)
-    runner.run(cmd, ignore_errors=ignore_errors)
+    output = runner.run(cmd, ignore_errors=ignore_errors)
     runner.close()
+    return output
+
+def cmd(u_boot_console, cmd_str):
+    """Run a single command string and log its output.
+
+    Args:
+        u_boot_console: A console connection to U-Boot.
+        cmd: The command to run, as a string.
+
+    Returns:
+        The output as a string.
+    """
+    return run_and_log(u_boot_console, cmd_str.split())
+
+def run_and_log_expect_exception(u_boot_console, cmd, retcode, msg):
+    """Run a command which is expected to fail.
+
+    This runs a command and checks that it fails with the expected return code
+    and exception method. If not, an exception is raised.
+
+    Args:
+        u_boot_console: A console connection to U-Boot.
+        cmd: The command to run, as an array of argv[].
+        retcode: Expected non-zero return code from the command.
+        msg: String which should be contained within the command's output.
+    """
+    try:
+        runner = u_boot_console.log.get_runner(cmd[0], sys.stdout)
+        runner.run(cmd)
+    except Exception as e:
+        assert(msg in runner.output)
+    else:
+        raise Exception('Expected exception, but not raised')
+    finally:
+        runner.close()
 
 ram_base = None
 def find_ram_base(u_boot_console):
diff --git a/test/run b/test/run
new file mode 100755
index 0000000..a6dcf8f
--- /dev/null
+++ b/test/run
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# Run all tests
+./test/py/test.py --bd sandbox --build
diff --git a/test/vboot/.gitignore b/test/vboot/.gitignore
deleted file mode 100644
index 4631242..0000000
--- a/test/vboot/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/*.dtb
-/test.fit
-/dev-keys
diff --git a/test/vboot/vboot_test.sh b/test/vboot/vboot_test.sh
deleted file mode 100755
index 6d7abb8..0000000
--- a/test/vboot/vboot_test.sh
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2013, Google Inc.
-#
-# Simple Verified Boot Test Script
-#
-# SPDX-License-Identifier:	GPL-2.0+
-
-set -e
-
-# Run U-Boot and report the result
-# Args:
-#	$1:	Test message
-run_uboot() {
-	echo -n "Test Verified Boot Run: $1: "
-	${uboot} -d sandbox-u-boot.dtb >${tmp} -c '
-sb load hostfs - 100 test.fit;
-fdt addr 100;
-bootm 100;
-reset'
-	if ! grep -q "$2" ${tmp}; then
-		echo
-		echo "Verified boot key check failed, output follows:"
-		cat ${tmp}
-		false
-	else
-		echo "OK"
-	fi
-}
-
-echo "Simple Verified Boot Test"
-echo "========================="
-echo
-echo "Please see doc/uImage.FIT/verified-boot.txt for more information"
-echo
-
-err=0
-tmp=/tmp/vboot_test.$$
-
-dir=$(dirname $0)
-
-if [ -z ${O} ]; then
-	O=.
-fi
-O=$(readlink -f ${O})
-
-dtc="-I dts -O dtb -p 2000"
-uboot="${O}/u-boot"
-mkimage="${O}/tools/mkimage"
-fit_check_sign="${O}/tools/fit_check_sign"
-keys="${dir}/dev-keys"
-echo ${mkimage} -D "${dtc}"
-
-echo "Build keys"
-mkdir -p ${keys}
-
-PUBLIC_EXPONENT=${1}
-
-if [ -z "${PUBLIC_EXPONENT}" ]; then
-	PUBLIC_EXPONENT=65537
-fi
-
-# Create an RSA key pair
-openssl genpkey -algorithm RSA -out ${keys}/dev.key \
-    -pkeyopt rsa_keygen_bits:2048 \
-    -pkeyopt rsa_keygen_pubexp:${PUBLIC_EXPONENT} 2>/dev/null
-
-# Create a certificate containing the public key
-openssl req -batch -new -x509 -key ${keys}/dev.key -out ${keys}/dev.crt
-
-pushd ${dir} >/dev/null
-
-function do_test {
-	echo do $sha test
-	# Compile our device tree files for kernel and U-Boot
-	dtc -p 0x1000 sandbox-kernel.dts -O dtb -o sandbox-kernel.dtb
-	dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb
-
-	# Create a number kernel image with zeroes
-	head -c 5000 /dev/zero >test-kernel.bin
-
-	# Build the FIT, but don't sign anything yet
-	echo Build FIT with signed images
-	${mkimage} -D "${dtc}" -f sign-images-$sha.its test.fit >${tmp}
-
-	run_uboot "unsigned signatures:" "dev-"
-
-	# Sign images with our dev keys
-	echo Sign images
-	${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb \
-		-r test.fit >${tmp}
-
-	run_uboot "signed images" "dev+"
-
-
-	# Create a fresh .dtb without the public keys
-	dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb
-
-	echo Build FIT with signed configuration
-	${mkimage} -D "${dtc}" -f sign-configs-$sha.its test.fit >${tmp}
-
-	run_uboot "unsigned config" $sha"+ OK"
-
-	# Sign images with our dev keys
-	echo Sign images
-	${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb \
-		-r test.fit >${tmp}
-
-	run_uboot "signed config" "dev+"
-
-	echo check signed config on the host
-	if ! ${fit_check_sign} -f test.fit -k sandbox-u-boot.dtb >${tmp}; then
-		echo
-		echo "Verified boot key check on host failed, output follows:"
-		cat ${tmp}
-		false
-	else
-		if ! grep -q "dev+" ${tmp}; then
-			echo
-			echo "Verified boot key check failed, output follows:"
-			cat ${tmp}
-			false
-		else
-			echo "OK"
-		fi
-	fi
-
-	run_uboot "signed config" "dev+"
-
-	# Increment the first byte of the signature, which should cause failure
-	sig=$(fdtget -t bx test.fit /configurations/conf@1/signature@1 value)
-	newbyte=$(printf %x $((0x${sig:0:2} + 1)))
-	sig="${newbyte} ${sig:2}"
-	fdtput -t bx test.fit /configurations/conf@1/signature@1 value ${sig}
-
-	run_uboot "signed config with bad hash" "Bad Data Hash"
-}
-
-sha=sha1
-do_test
-sha=sha256
-do_test
-
-popd >/dev/null
-
-echo
-if ${ok}; then
-	echo "Test passed"
-else
-	echo "Test failed"
-fi
diff --git a/tools/Makefile b/tools/Makefile
index f72294a..421414b 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -107,6 +107,20 @@
 fit_info-objs   := $(dumpimage-mkimage-objs) fit_info.o
 fit_check_sign-objs   := $(dumpimage-mkimage-objs) fit_check_sign.o
 
+# Build a libfdt Python module if swig is available
+# Use 'sudo apt-get install swig libpython-dev' to enable this
+hostprogs-$(CONFIG_SPL_OF_PLATDATA) += \
+	$(if $(shell which swig),_libfdt.so)
+_libfdt.so-sharedobjs += $(LIBFDT_OBJS)
+libfdt:
+
+tools/_libfdt.so: $(patsubst %.o,%.c,$(LIBFDT_OBJS)) tools/libfdt_wrap.c
+	python $(srctree)/lib/libfdt/setup.py "$(_hostc_flags)" $^
+	mv _libfdt.so $@
+
+tools/libfdt_wrap.c: $(srctree)/lib/libfdt/libfdt.swig
+	swig -python -o $@ $<
+
 # TODO(sjg@chromium.org): Is this correct on Mac OS?
 
 ifneq ($(CONFIG_MX23)$(CONFIG_MX28),)
diff --git a/tools/dtoc/.gitignore b/tools/dtoc/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/tools/dtoc/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/tools/dtoc/dtoc b/tools/dtoc/dtoc
new file mode 120000
index 0000000..896ca44
--- /dev/null
+++ b/tools/dtoc/dtoc
@@ -0,0 +1 @@
+dtoc.py
\ No newline at end of file
diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/dtoc.py
new file mode 100755
index 0000000..ec80abe
--- /dev/null
+++ b/tools/dtoc/dtoc.py
@@ -0,0 +1,394 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import copy
+from optparse import OptionError, OptionParser
+import os
+import sys
+
+import fdt_util
+
+# Bring in the patman libraries
+our_path = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(our_path, '../patman'))
+
+# Bring in either the normal fdt library (which relies on libfdt) or the
+# fallback one (which uses fdtget and is slower). Both provide the same
+# interfface for this file to use.
+try:
+    from fdt import Fdt
+    import fdt
+    have_libfdt = True
+except ImportError:
+    have_libfdt = False
+    from fdt_fallback import Fdt
+    import fdt_fallback as fdt
+
+import struct
+
+# When we see these properties we ignore them - i.e. do not create a structure member
+PROP_IGNORE_LIST = [
+    '#address-cells',
+    '#gpio-cells',
+    '#size-cells',
+    'compatible',
+    'linux,phandle',
+    "status",
+    'phandle',
+    'u-boot,dm-pre-reloc',
+]
+
+# C type declarations for the tyues we support
+TYPE_NAMES = {
+    fdt_util.TYPE_INT: 'fdt32_t',
+    fdt_util.TYPE_BYTE: 'unsigned char',
+    fdt_util.TYPE_STRING: 'const char *',
+    fdt_util.TYPE_BOOL: 'bool',
+};
+
+STRUCT_PREFIX = 'dtd_'
+VAL_PREFIX = 'dtv_'
+
+def Conv_name_to_c(name):
+    """Convert a device-tree name to a C identifier
+
+    Args:
+        name:   Name to convert
+    Return:
+        String containing the C version of this name
+    """
+    str = name.replace('@', '_at_')
+    str = str.replace('-', '_')
+    str = str.replace(',', '_')
+    str = str.replace('/', '__')
+    return str
+
+def TabTo(num_tabs, str):
+    if len(str) >= num_tabs * 8:
+        return str + ' '
+    return str + '\t' * (num_tabs - len(str) / 8)
+
+class DtbPlatdata:
+    """Provide a means to convert device tree binary data to platform data
+
+    The output of this process is C structures which can be used in space-
+    constrained encvironments where the ~3KB code overhead of device tree
+    code is not affordable.
+
+    Properties:
+        fdt: Fdt object, referencing the device tree
+        _dtb_fname: Filename of the input device tree binary file
+        _valid_nodes: A list of Node object with compatible strings
+        _options: Command-line options
+        _phandle_node: A dict of nodes indexed by phandle number (1, 2...)
+        _outfile: The current output file (sys.stdout or a real file)
+        _lines: Stashed list of output lines for outputting in the future
+        _phandle_node: A dict of Nodes indexed by phandle (an integer)
+    """
+    def __init__(self, dtb_fname, options):
+        self._dtb_fname = dtb_fname
+        self._valid_nodes = None
+        self._options = options
+        self._phandle_node = {}
+        self._outfile = None
+        self._lines = []
+
+    def SetupOutput(self, fname):
+        """Set up the output destination
+
+        Once this is done, future calls to self.Out() will output to this
+        file.
+
+        Args:
+            fname: Filename to send output to, or '-' for stdout
+        """
+        if fname == '-':
+            self._outfile = sys.stdout
+        else:
+            self._outfile = open(fname, 'w')
+
+    def Out(self, str):
+        """Output a string to the output file
+
+        Args:
+            str: String to output
+        """
+        self._outfile.write(str)
+
+    def Buf(self, str):
+        """Buffer up a string to send later
+
+        Args:
+            str: String to add to our 'buffer' list
+        """
+        self._lines.append(str)
+
+    def GetBuf(self):
+        """Get the contents of the output buffer, and clear it
+
+        Returns:
+            The output buffer, which is then cleared for future use
+        """
+        lines = self._lines
+        self._lines = []
+        return lines
+
+    def GetValue(self, type, value):
+        """Get a value as a C expression
+
+        For integers this returns a byte-swapped (little-endian) hex string
+        For bytes this returns a hex string, e.g. 0x12
+        For strings this returns a literal string enclosed in quotes
+        For booleans this return 'true'
+
+        Args:
+            type: Data type (fdt_util)
+            value: Data value, as a string of bytes
+        """
+        if type == fdt_util.TYPE_INT:
+            return '%#x' % fdt_util.fdt32_to_cpu(value)
+        elif type == fdt_util.TYPE_BYTE:
+            return '%#x' % ord(value[0])
+        elif type == fdt_util.TYPE_STRING:
+            return '"%s"' % value
+        elif type == fdt_util.TYPE_BOOL:
+            return 'true'
+
+    def GetCompatName(self, node):
+        """Get a node's first compatible string as a C identifier
+
+        Args:
+            node: Node object to check
+        Return:
+            C identifier for the first compatible string
+        """
+        compat = node.props['compatible'].value
+        if type(compat) == list:
+            compat = compat[0]
+        return Conv_name_to_c(compat)
+
+    def ScanDtb(self):
+        """Scan the device tree to obtain a tree of notes and properties
+
+        Once this is done, self.fdt.GetRoot() can be called to obtain the
+        device tree root node, and progress from there.
+        """
+        self.fdt = Fdt(self._dtb_fname)
+        self.fdt.Scan()
+
+    def ScanTree(self):
+        """Scan the device tree for useful information
+
+        This fills in the following properties:
+            _phandle_node: A dict of Nodes indexed by phandle (an integer)
+            _valid_nodes: A list of nodes we wish to consider include in the
+                platform data
+        """
+        node_list = []
+        self._phandle_node = {}
+        for node in self.fdt.GetRoot().subnodes:
+            if 'compatible' in node.props:
+                status = node.props.get('status')
+                if (not options.include_disabled and not status or
+                    status.value != 'disabled'):
+                    node_list.append(node)
+                    phandle_prop = node.props.get('phandle')
+                    if phandle_prop:
+                        phandle = phandle_prop.GetPhandle()
+                        self._phandle_node[phandle] = node
+
+        self._valid_nodes = node_list
+
+    def IsPhandle(self, prop):
+        """Check if a node contains phandles
+
+        We have no reliable way of detecting whether a node uses a phandle
+        or not. As an interim measure, use a list of known property names.
+
+        Args:
+            prop: Prop object to check
+        Return:
+            True if the object value contains phandles, else False
+        """
+        if prop.name in ['clocks']:
+            return True
+        return False
+
+    def ScanStructs(self):
+        """Scan the device tree building up the C structures we will use.
+
+        Build a dict keyed by C struct name containing a dict of Prop
+        object for each struct field (keyed by property name). Where the
+        same struct appears multiple times, try to use the 'widest'
+        property, i.e. the one with a type which can express all others.
+
+        Once the widest property is determined, all other properties are
+        updated to match that width.
+        """
+        structs = {}
+        for node in self._valid_nodes:
+            node_name = self.GetCompatName(node)
+            fields = {}
+
+            # Get a list of all the valid properties in this node.
+            for name, prop in node.props.iteritems():
+                if name not in PROP_IGNORE_LIST and name[0] != '#':
+                    fields[name] = copy.deepcopy(prop)
+
+            # If we've seen this node_name before, update the existing struct.
+            if node_name in structs:
+                struct = structs[node_name]
+                for name, prop in fields.iteritems():
+                    oldprop = struct.get(name)
+                    if oldprop:
+                        oldprop.Widen(prop)
+                    else:
+                        struct[name] = prop
+
+            # Otherwise store this as a new struct.
+            else:
+                structs[node_name] = fields
+
+        upto = 0
+        for node in self._valid_nodes:
+            node_name = self.GetCompatName(node)
+            struct = structs[node_name]
+            for name, prop in node.props.iteritems():
+                if name not in PROP_IGNORE_LIST and name[0] != '#':
+                    prop.Widen(struct[name])
+            upto += 1
+        return structs
+
+    def GenerateStructs(self, structs):
+        """Generate struct defintions for the platform data
+
+        This writes out the body of a header file consisting of structure
+        definitions for node in self._valid_nodes. See the documentation in
+        README.of-plat for more information.
+        """
+        self.Out('#include <stdbool.h>\n')
+        self.Out('#include <libfdt.h>\n')
+
+        # Output the struct definition
+        for name in sorted(structs):
+            self.Out('struct %s%s {\n' % (STRUCT_PREFIX, name));
+            for pname in sorted(structs[name]):
+                prop = structs[name][pname]
+                if self.IsPhandle(prop):
+                    # For phandles, include a reference to the target
+                    self.Out('\t%s%s[%d]' % (TabTo(2, 'struct phandle_2_cell'),
+                                             Conv_name_to_c(prop.name),
+                                             len(prop.value) / 2))
+                else:
+                    ptype = TYPE_NAMES[prop.type]
+                    self.Out('\t%s%s' % (TabTo(2, ptype),
+                                         Conv_name_to_c(prop.name)))
+                    if type(prop.value) == list:
+                        self.Out('[%d]' % len(prop.value))
+                self.Out(';\n')
+            self.Out('};\n')
+
+    def GenerateTables(self):
+        """Generate device defintions for the platform data
+
+        This writes out C platform data initialisation data and
+        U_BOOT_DEVICE() declarations for each valid node. See the
+        documentation in README.of-plat for more information.
+        """
+        self.Out('#include <common.h>\n')
+        self.Out('#include <dm.h>\n')
+        self.Out('#include <dt-structs.h>\n')
+        self.Out('\n')
+        node_txt_list = []
+        for node in self._valid_nodes:
+            struct_name = self.GetCompatName(node)
+            var_name = Conv_name_to_c(node.name)
+            self.Buf('static struct %s%s %s%s = {\n' %
+                (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
+            for pname, prop in node.props.iteritems():
+                if pname in PROP_IGNORE_LIST or pname[0] == '#':
+                    continue
+                ptype = TYPE_NAMES[prop.type]
+                member_name = Conv_name_to_c(prop.name)
+                self.Buf('\t%s= ' % TabTo(3, '.' + member_name))
+
+                # Special handling for lists
+                if type(prop.value) == list:
+                    self.Buf('{')
+                    vals = []
+                    # For phandles, output a reference to the platform data
+                    # of the target node.
+                    if self.IsPhandle(prop):
+                        # Process the list as pairs of (phandle, id)
+                        it = iter(prop.value)
+                        for phandle_cell, id_cell in zip(it, it):
+                            phandle = fdt_util.fdt32_to_cpu(phandle_cell)
+                            id = fdt_util.fdt32_to_cpu(id_cell)
+                            target_node = self._phandle_node[phandle]
+                            name = Conv_name_to_c(target_node.name)
+                            vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id))
+                    else:
+                        for val in prop.value:
+                            vals.append(self.GetValue(prop.type, val))
+                    self.Buf(', '.join(vals))
+                    self.Buf('}')
+                else:
+                    self.Buf(self.GetValue(prop.type, prop.value))
+                self.Buf(',\n')
+            self.Buf('};\n')
+
+            # Add a device declaration
+            self.Buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
+            self.Buf('\t.name\t\t= "%s",\n' % struct_name)
+            self.Buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
+            self.Buf('\t.platdata_size\t= sizeof(%s%s),\n' %
+                     (VAL_PREFIX, var_name))
+            self.Buf('};\n')
+            self.Buf('\n')
+
+            # Output phandle target nodes first, since they may be referenced
+            # by others
+            if 'phandle' in node.props:
+                self.Out(''.join(self.GetBuf()))
+            else:
+                node_txt_list.append(self.GetBuf())
+
+        # Output all the nodes which are not phandle targets themselves, but
+        # may reference them. This avoids the need for forward declarations.
+        for node_txt in node_txt_list:
+            self.Out(''.join(node_txt))
+
+
+if __name__ != "__main__":
+    pass
+
+parser = OptionParser()
+parser.add_option('-d', '--dtb-file', action='store',
+                  help='Specify the .dtb input file')
+parser.add_option('--include-disabled', action='store_true',
+                  help='Include disabled nodes')
+parser.add_option('-o', '--output', action='store', default='-',
+                  help='Select output filename')
+(options, args) = parser.parse_args()
+
+if not args:
+    raise ValueError('Please specify a command: struct, platdata')
+
+plat = DtbPlatdata(options.dtb_file, options)
+plat.ScanDtb()
+plat.ScanTree()
+plat.SetupOutput(options.output)
+structs = plat.ScanStructs()
+
+for cmd in args[0].split(','):
+    if cmd == 'struct':
+        plat.GenerateStructs(structs)
+    elif cmd == 'platdata':
+        plat.GenerateTables()
+    else:
+        raise ValueError("Unknown command '%s': (use: struct, platdata)" % cmd)
diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py
new file mode 100644
index 0000000..1d913a9
--- /dev/null
+++ b/tools/dtoc/fdt.py
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+import fdt_util
+import libfdt
+import sys
+
+# This deals with a device tree, presenting it as a list of Node and Prop
+# objects, representing nodes and properties, respectively.
+#
+# This implementation uses a libfdt Python library to access the device tree,
+# so it is fairly efficient.
+
+class Prop:
+    """A device tree property
+
+    Properties:
+        name: Property name (as per the device tree)
+        value: Property value as a string of bytes, or a list of strings of
+            bytes
+        type: Value type
+    """
+    def __init__(self, name, bytes):
+        self.name = name
+        self.value = None
+        if not bytes:
+            self.type = fdt_util.TYPE_BOOL
+            self.value = True
+            return
+        self.type, self.value = fdt_util.BytesToValue(bytes)
+
+    def GetPhandle(self):
+        """Get a (single) phandle value from a property
+
+        Gets the phandle valuie from a property and returns it as an integer
+        """
+        return fdt_util.fdt32_to_cpu(self.value[:4])
+
+    def Widen(self, newprop):
+        """Figure out which property type is more general
+
+        Given a current property and a new property, this function returns the
+        one that is less specific as to type. The less specific property will
+        be ble to represent the data in the more specific property. This is
+        used for things like:
+
+            node1 {
+                compatible = "fred";
+                value = <1>;
+            };
+            node1 {
+                compatible = "fred";
+                value = <1 2>;
+            };
+
+        He we want to use an int array for 'value'. The first property
+        suggests that a single int is enough, but the second one shows that
+        it is not. Calling this function with these two propertes would
+        update the current property to be like the second, since it is less
+        specific.
+        """
+        if newprop.type < self.type:
+            self.type = newprop.type
+
+        if type(newprop.value) == list and type(self.value) != list:
+            self.value = [self.value]
+
+        if type(self.value) == list and len(newprop.value) > len(self.value):
+            val = fdt_util.GetEmpty(self.type)
+            while len(self.value) < len(newprop.value):
+                self.value.append(val)
+
+
+class Node:
+    """A device tree node
+
+    Properties:
+        offset: Integer offset in the device tree
+        name: Device tree node tname
+        path: Full path to node, along with the node name itself
+        _fdt: Device tree object
+        subnodes: A list of subnodes for this node, each a Node object
+        props: A dict of properties for this node, each a Prop object.
+            Keyed by property name
+    """
+    def __init__(self, fdt, offset, name, path):
+        self.offset = offset
+        self.name = name
+        self.path = path
+        self._fdt = fdt
+        self.subnodes = []
+        self.props = {}
+
+    def Scan(self):
+        """Scan a node's properties and subnodes
+
+        This fills in the props and subnodes properties, recursively
+        searching into subnodes so that the entire tree is built.
+        """
+        self.props = self._fdt.GetProps(self.path)
+
+        offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.offset)
+        while offset >= 0:
+            sep = '' if self.path[-1] == '/' else '/'
+            name = libfdt.Name(self._fdt.GetFdt(), offset)
+            path = self.path + sep + name
+            node = Node(self._fdt, offset, name, path)
+            self.subnodes.append(node)
+
+            node.Scan()
+            offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
+
+
+class Fdt:
+    """Provides simple access to a flat device tree blob.
+
+    Properties:
+      fname: Filename of fdt
+      _root: Root of device tree (a Node object)
+    """
+
+    def __init__(self, fname):
+        self.fname = fname
+        with open(fname) as fd:
+            self._fdt = fd.read()
+
+    def GetFdt(self):
+        """Get the contents of the FDT
+
+        Returns:
+            The FDT contents as a string of bytes
+        """
+        return self._fdt
+
+    def Scan(self):
+        """Scan a device tree, building up a tree of Node objects
+
+        This fills in the self._root property
+        """
+        self._root = Node(self, 0, '/', '/')
+        self._root.Scan()
+
+    def GetRoot(self):
+        """Get the root Node of the device tree
+
+        Returns:
+            The root Node object
+        """
+        return self._root
+
+    def GetProps(self, node):
+        """Get all properties from a node.
+
+        Args:
+            node: Full path to node name to look in.
+
+        Returns:
+            A dictionary containing all the properties, indexed by node name.
+            The entries are Prop objects.
+
+        Raises:
+            ValueError: if the node does not exist.
+        """
+        offset = libfdt.fdt_path_offset(self._fdt, node)
+        if offset < 0:
+            libfdt.Raise(offset)
+        props_dict = {}
+        poffset = libfdt.fdt_first_property_offset(self._fdt, offset)
+        while poffset >= 0:
+            dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
+            prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop))
+            props_dict[prop.name] = prop
+
+            poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
+        return props_dict
diff --git a/tools/dtoc/fdt_fallback.py b/tools/dtoc/fdt_fallback.py
new file mode 100644
index 0000000..14decf3
--- /dev/null
+++ b/tools/dtoc/fdt_fallback.py
@@ -0,0 +1,207 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+import command
+import fdt_util
+import sys
+
+# This deals with a device tree, presenting it as a list of Node and Prop
+# objects, representing nodes and properties, respectively.
+#
+# This implementation uses the fdtget tool to access the device tree, so it
+# is not very efficient for larger trees. The tool is called once for each
+# node and property in the tree.
+
+class Prop:
+    """A device tree property
+
+    Properties:
+        name: Property name (as per the device tree)
+        value: Property value as a string of bytes, or a list of strings of
+            bytes
+        type: Value type
+    """
+    def __init__(self, name, byte_list_str):
+        self.name = name
+        self.value = None
+        if not byte_list_str.strip():
+            self.type = fdt_util.TYPE_BOOL
+            return
+        bytes = [chr(int(byte, 16)) for byte in byte_list_str.strip().split(' ')]
+        self.type, self.value = fdt_util.BytesToValue(''.join(bytes))
+
+    def GetPhandle(self):
+        """Get a (single) phandle value from a property
+
+        Gets the phandle valuie from a property and returns it as an integer
+        """
+        return fdt_util.fdt32_to_cpu(self.value[:4])
+
+    def Widen(self, newprop):
+        """Figure out which property type is more general
+
+        Given a current property and a new property, this function returns the
+        one that is less specific as to type. The less specific property will
+        be ble to represent the data in the more specific property. This is
+        used for things like:
+
+            node1 {
+                compatible = "fred";
+                value = <1>;
+            };
+            node1 {
+                compatible = "fred";
+                value = <1 2>;
+            };
+
+        He we want to use an int array for 'value'. The first property
+        suggests that a single int is enough, but the second one shows that
+        it is not. Calling this function with these two propertes would
+        update the current property to be like the second, since it is less
+        specific.
+        """
+        if newprop.type < self.type:
+            self.type = newprop.type
+
+        if type(newprop.value) == list and type(self.value) != list:
+            self.value = newprop.value
+
+class Node:
+    """A device tree node
+
+    Properties:
+        name: Device tree node tname
+        path: Full path to node, along with the node name itself
+        _fdt: Device tree object
+        subnodes: A list of subnodes for this node, each a Node object
+        props: A dict of properties for this node, each a Prop object.
+            Keyed by property name
+    """
+    def __init__(self, fdt, name, path):
+        self.name = name
+        self.path = path
+        self._fdt = fdt
+        self.subnodes = []
+        self.props = {}
+
+    def Scan(self):
+        """Scan a node's properties and subnodes
+
+        This fills in the props and subnodes properties, recursively
+        searching into subnodes so that the entire tree is built.
+        """
+        for name, byte_list_str in self._fdt.GetProps(self.path).iteritems():
+            prop = Prop(name, byte_list_str)
+            self.props[name] = prop
+
+        for name in self._fdt.GetSubNodes(self.path):
+            sep = '' if self.path[-1] == '/' else '/'
+            path = self.path + sep + name
+            node = Node(self._fdt, name, path)
+            self.subnodes.append(node)
+
+            node.Scan()
+
+
+class Fdt:
+    """Provides simple access to a flat device tree blob.
+
+    Properties:
+      fname: Filename of fdt
+      _root: Root of device tree (a Node object)
+    """
+
+    def __init__(self, fname):
+        self.fname = fname
+
+    def Scan(self):
+        """Scan a device tree, building up a tree of Node objects
+
+        This fills in the self._root property
+        """
+        self._root = Node(self, '/', '/')
+        self._root.Scan()
+
+    def GetRoot(self):
+        """Get the root Node of the device tree
+
+        Returns:
+            The root Node object
+        """
+        return self._root
+
+    def GetSubNodes(self, node):
+        """Returns a list of sub-nodes of a given node
+
+        Args:
+            node: Node name to return children from
+
+        Returns:
+            List of children in the node (each a string node name)
+
+        Raises:
+            CmdError: if the node does not exist.
+        """
+        out = command.Output('fdtget', self.fname, '-l', node)
+        return out.strip().splitlines()
+
+    def GetProps(self, node, convert_dashes=False):
+        """Get all properties from a node
+
+        Args:
+            node: full path to node name to look in
+            convert_dashes: True to convert - to _ in node names
+
+        Returns:
+            A dictionary containing all the properties, indexed by node name.
+            The entries are simply strings - no decoding of lists or numbers
+            is done.
+
+        Raises:
+            CmdError: if the node does not exist.
+        """
+        out = command.Output('fdtget', self.fname, node, '-p')
+        props = out.strip().splitlines()
+        props_dict = {}
+        for prop in props:
+            name = prop
+            if convert_dashes:
+                prop = re.sub('-', '_', prop)
+            props_dict[prop] = self.GetProp(node, name)
+        return props_dict
+
+    def GetProp(self, node, prop, default=None, typespec=None):
+        """Get a property from a device tree.
+
+        This looks up the given node and property, and returns the value as a
+        string,
+
+        If the node or property does not exist, this will return the default
+        value.
+
+        Args:
+            node: Full path to node to look up.
+            prop: Property name to look up.
+            default: Default value to return if nothing is present in the fdt,
+                or None to raise in this case. This will be converted to a
+                string.
+            typespec: Type character to use (None for default, 's' for string)
+
+        Returns:
+            string containing the property value.
+
+        Raises:
+            CmdError: if the property does not exist and no default is provided.
+        """
+        args = [self.fname, node, prop, '-t', 'bx']
+        if default is not None:
+          args += ['-d', str(default)]
+        if typespec is not None:
+          args += ['-t%s' % typespec]
+        out = command.Output('fdtget', *args)
+        return out.strip()
diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py
new file mode 100644
index 0000000..929b524
--- /dev/null
+++ b/tools/dtoc/fdt_util.py
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+import struct
+
+# A list of types we support
+(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
+
+def BytesToValue(bytes):
+    """Converts a string of bytes into a type and value
+
+    Args:
+        A string containing bytes
+
+    Return:
+        A tuple:
+            Type of data
+            Data, either a single element or a list of elements. Each element
+            is one of:
+                TYPE_STRING: string value from the property
+                TYPE_INT: a byte-swapped integer stored as a 4-byte string
+                TYPE_BYTE: a byte stored as a single-byte string
+    """
+    size = len(bytes)
+    strings = bytes.split('\0')
+    is_string = True
+    count = len(strings) - 1
+    if count > 0 and not strings[-1]:
+        for string in strings[:-1]:
+            if not string:
+                is_string = False
+                break
+            for ch in string:
+                if ch < ' ' or ch > '~':
+                    is_string = False
+                    break
+    else:
+        is_string = False
+    if is_string:
+        if count == 1:
+            return TYPE_STRING, strings[0]
+        else:
+            return TYPE_STRING, strings[:-1]
+    if size % 4:
+        if size == 1:
+            return TYPE_BYTE, bytes[0]
+        else:
+            return TYPE_BYTE, list(bytes)
+    val = []
+    for i in range(0, size, 4):
+        val.append(bytes[i:i + 4])
+    if size == 4:
+        return TYPE_INT, val[0]
+    else:
+        return TYPE_INT, val
+
+def GetEmpty(type):
+    """Get an empty / zero value of the given type
+
+    Returns:
+        A single value of the given type
+    """
+    if type == TYPE_BYTE:
+        return chr(0)
+    elif type == TYPE_INT:
+        return struct.pack('<I', 0);
+    elif type == TYPE_STRING:
+        return ''
+    else:
+        return True
+
+def fdt32_to_cpu(val):
+    """Convert a device tree cell to an integer
+
+    Args:
+        Value to convert (4-character string representing the cell value)
+
+    Return:
+        A native-endian integer value
+    """
+    return struct.unpack(">I", val)[0]
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 58aa8e2..10fd6d4 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -195,7 +195,8 @@
 	fdt_begin_node(fdt, str);
 	fdt_property_string(fdt, "description", params->imagename);
 	fdt_property_string(fdt, "type", typename);
-	fdt_property_string(fdt, "arch", genimg_get_arch_name(params->arch));
+	fdt_property_string(fdt, "arch",
+			    genimg_get_arch_short_name(params->arch));
 	fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os));
 	fdt_property_string(fdt, "compression",
 			    genimg_get_comp_short_name(params->comp));
@@ -650,8 +651,8 @@
 	}
 
 	if (ret) {
-		fprintf(stderr, "%s Can't add hashes to FIT blob\n",
-			params->cmdname);
+		fprintf(stderr, "%s Can't add hashes to FIT blob: %d\n",
+			params->cmdname, ret);
 		goto err_system;
 	}
 
diff --git a/tools/image-host.c b/tools/image-host.c
index 7effb6c..3e14fdc 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -38,7 +38,7 @@
 		printf("Can't set hash '%s' property for '%s' node(%s)\n",
 		       FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
 		       fdt_strerror(ret));
-		return -1;
+		return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
 	}
 
 	return 0;
@@ -64,25 +64,27 @@
 	const char *node_name;
 	int value_len;
 	char *algo;
+	int ret;
 
 	node_name = fit_get_name(fit, noffset, NULL);
 
 	if (fit_image_hash_get_algo(fit, noffset, &algo)) {
 		printf("Can't get hash algo property for '%s' hash node in '%s' image node\n",
 		       node_name, image_name);
-		return -1;
+		return -ENOENT;
 	}
 
 	if (calculate_hash(data, size, algo, value, &value_len)) {
 		printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n",
 		       algo, node_name, image_name);
-		return -1;
+		return -EPROTONOSUPPORT;
 	}
 
-	if (fit_set_hash_value(fit, noffset, value, value_len)) {
+	ret = fit_set_hash_value(fit, noffset, value, value_len);
+	if (ret) {
 		printf("Can't set hash value for '%s' hash node in '%s' image node\n",
 		       node_name, image_name);
-		return -1;
+		return ret;
 	}
 
 	return 0;
@@ -322,7 +324,7 @@
 				comment, require_keys);
 		}
 		if (ret)
-			return -1;
+			return ret;
 	}
 
 	return 0;
diff --git a/tools/mkimage.c b/tools/mkimage.c
index ff3024a..d993958 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -25,45 +25,47 @@
 	.imagename2 = "",
 };
 
-static int h_compare_image_name(const void *vtype1, const void *vtype2)
+static enum ih_category cur_category;
+
+static int h_compare_category_name(const void *vtype1, const void *vtype2)
 {
 	const int *type1 = vtype1;
 	const int *type2 = vtype2;
-	const char *name1 = genimg_get_type_short_name(*type1);
-	const char *name2 = genimg_get_type_short_name(*type2);
+	const char *name1 = genimg_get_cat_short_name(cur_category, *type1);
+	const char *name2 = genimg_get_cat_short_name(cur_category, *type2);
 
 	return strcmp(name1, name2);
 }
 
-/* Show all image types supported by mkimage */
-static void show_image_types(void)
+static int show_valid_options(enum ih_category category)
 {
-	struct image_type_params *tparams;
-	int order[IH_TYPE_COUNT];
+	int *order;
 	int count;
-	int type;
+	int item;
 	int i;
 
-	/* Sort the names in order of short name for easier reading */
-	memset(order, '\0', sizeof(order));
-	for (count = 0, type = 0; type < IH_TYPE_COUNT; type++) {
-		tparams = imagetool_get_type(type);
-		if (tparams)
-			order[count++] = type;
-	}
-	qsort(order, count, sizeof(int), h_compare_image_name);
+	count = genimg_get_cat_count(category);
+	order = calloc(count, sizeof(*order));
+	if (!order)
+		return -ENOMEM;
 
-	fprintf(stderr, "\nInvalid image type. Supported image types:\n");
+	/* Sort the names in order of short name for easier reading */
+	for (item = 0; item < count; item++)
+		order[item] = item;
+	cur_category = category;
+	qsort(order, count, sizeof(int), h_compare_category_name);
+
+	fprintf(stderr, "\nInvalid %s, supported are:\n",
+		genimg_get_cat_desc(category));
 	for (i = 0; i < count; i++) {
-		type = order[i];
-		tparams = imagetool_get_type(type);
-		if (tparams) {
-			fprintf(stderr, "\t%-15s  %s\n",
-				genimg_get_type_short_name(type),
-				genimg_get_type_name(type));
-		}
+		item = order[i];
+		fprintf(stderr, "\t%-15s  %s\n",
+			genimg_get_cat_short_name(category, item),
+			genimg_get_cat_name(category, item));
 	}
 	fprintf(stderr, "\n");
+
+	return 0;
 }
 
 static void usage(const char *msg)
@@ -150,8 +152,10 @@
 			break;
 		case 'A':
 			params.arch = genimg_get_arch_id(optarg);
-			if (params.arch < 0)
+			if (params.arch < 0) {
+				show_valid_options(IH_ARCH);
 				usage("Invalid architecture");
+			}
 			break;
 		case 'b':
 			if (add_content(IH_TYPE_FLATDT, optarg)) {
@@ -166,8 +170,10 @@
 			break;
 		case 'C':
 			params.comp = genimg_get_comp_id(optarg);
-			if (params.comp < 0)
+			if (params.comp < 0) {
+				show_valid_options(IH_COMP);
 				usage("Invalid compression type");
+			}
 			break;
 		case 'd':
 			params.datafile = optarg;
@@ -197,7 +203,6 @@
 			 * The flattened image tree (FIT) format
 			 * requires a flattened device tree image type
 			 */
-			params.fit_image_type = params.type;
 			params.type = IH_TYPE_FLATDT;
 			params.fflag = 1;
 			break;
@@ -215,8 +220,10 @@
 			break;
 		case 'O':
 			params.os = genimg_get_os_id(optarg);
-			if (params.os < 0)
+			if (params.os < 0) {
+				show_valid_options(IH_OS);
 				usage("Invalid operating system");
+			}
 			break;
 		case 'p':
 			params.external_offset = strtoull(optarg, &ptr, 16);
@@ -225,6 +232,7 @@
 					params.cmdname, optarg);
 				exit(EXIT_FAILURE);
 			}
+			break;
 		case 'q':
 			params.quiet = 1;
 			break;
@@ -244,7 +252,7 @@
 		case 'T':
 			type = genimg_get_type_id(optarg);
 			if (type < 0) {
-				show_image_types();
+				show_valid_options(IH_TYPE);
 				usage("Invalid image type");
 			}
 			break;
@@ -272,9 +280,12 @@
 	 * will always be IH_TYPE_FLATDT in this case).
 	 */
 	if (params.type == IH_TYPE_FLATDT) {
-		params.fit_image_type = type;
+		params.fit_image_type = type ? type : IH_TYPE_KERNEL;
+		/* For auto_its, datafile is always 'auto' */
 		if (!params.auto_its)
 			params.datafile = datafile;
+		else if (!params.datafile)
+			usage("Missing data file for auto-FIT (use -d)");
 	} else if (type != IH_TYPE_INVALID) {
 		params.type = type;
 	}
@@ -283,7 +294,6 @@
 		usage("Missing output filename");
 }
 
-
 int main(int argc, char **argv)
 {
 	int ifd = -1;