Merge tag 'v2021.04-rc4' into next

Prepare v2021.04-rc4
diff --git a/Makefile b/Makefile
index 3ebb38b..36b867a 100644
--- a/Makefile
+++ b/Makefile
@@ -1326,6 +1326,7 @@
 # binman
 # ---------------------------------------------------------------------------
 # Use 'make BINMAN_DEBUG=1' to enable debugging
+# Use 'make BINMAN_VERBOSE=3' to set vebosity level
 default_dt := $(if $(DEVICE_TREE),$(DEVICE_TREE),$(CONFIG_DEFAULT_DEVICE_TREE))
 quiet_cmd_binman = BINMAN  $@
 cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
diff --git a/arch/Kconfig b/arch/Kconfig
index 27843cd..7023223 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -142,6 +142,8 @@
 	imply AVB_VERIFY
 	imply LIBAVB
 	imply CMD_AVB
+	imply SCP03
+	imply CMD_SCP03
 	imply UDP_FUNCTION_FASTBOOT
 	imply VIRTIO_MMIO
 	imply VIRTIO_PCI
diff --git a/arch/arc/lib/reset.c b/arch/arc/lib/reset.c
index fbb56ec..b8589d0 100644
--- a/arch/arc/lib/reset.c
+++ b/arch/arc/lib/reset.c
@@ -7,7 +7,7 @@
 #include <common.h>
 #include <cpu_func.h>
 
-__weak void reset_cpu(ulong addr)
+__weak void reset_cpu(void)
 {
 	/* Stop debug session here */
 	__builtin_arc_brk();
@@ -17,7 +17,7 @@
 {
 	printf("Resetting the board...\n");
 
-	reset_cpu(0);
+	reset_cpu();
 
 	return 0;
 }
diff --git a/arch/arm/cpu/arm920t/ep93xx/cpu.c b/arch/arm/cpu/arm920t/ep93xx/cpu.c
index c9ea4e4..3435bdc 100644
--- a/arch/arm/cpu/arm920t/ep93xx/cpu.c
+++ b/arch/arm/cpu/arm920t/ep93xx/cpu.c
@@ -14,7 +14,7 @@
 #include <asm/io.h>
 
 /* We reset the CPU by generating a 1-->0 transition on DeviceCfg bit 31. */
-extern void reset_cpu(ulong addr)
+extern void reset_cpu(void)
 {
 	struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
 	uint32_t value;
diff --git a/arch/arm/cpu/arm920t/imx/timer.c b/arch/arm/cpu/arm920t/imx/timer.c
index e9d5577..0cd3a03 100644
--- a/arch/arm/cpu/arm920t/imx/timer.c
+++ b/arch/arm/cpu/arm920t/imx/timer.c
@@ -81,7 +81,7 @@
 /*
  * Reset the cpu by setting up the watchdog timer and let him time out
  */
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	/* Disable watchdog and set Time-Out field to 0 */
 	WCR = 0x00000000;
diff --git a/arch/arm/cpu/arm926ejs/armada100/timer.c b/arch/arm/cpu/arm926ejs/armada100/timer.c
index ec73393..6d77ad3 100644
--- a/arch/arm/cpu/arm926ejs/armada100/timer.c
+++ b/arch/arm/cpu/arm926ejs/armada100/timer.c
@@ -142,7 +142,7 @@
  * 2. Write key value to TMP_WSAR reg.
  * 3. Perform write operation.
  */
-void reset_cpu(unsigned long ignored)
+void reset_cpu(void)
 {
 	struct armd1mpmu_registers *mpmu =
 		(struct armd1mpmu_registers *) ARMD1_MPMU_BASE;
diff --git a/arch/arm/cpu/arm926ejs/mx25/reset.c b/arch/arm/cpu/arm926ejs/mx25/reset.c
index 38df1c9..7844a99 100644
--- a/arch/arm/cpu/arm926ejs/mx25/reset.c
+++ b/arch/arm/cpu/arm926ejs/mx25/reset.c
@@ -23,7 +23,7 @@
 /*
  * Reset the cpu by setting up the watchdog timer and let it time out
  */
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	struct wdog_regs *regs = (struct wdog_regs *)IMX_WDT_BASE;
 	/* Disable watchdog and set Time-Out field to 0 */
diff --git a/arch/arm/cpu/arm926ejs/mx27/reset.c b/arch/arm/cpu/arm926ejs/mx27/reset.c
index 320b0a6..496fb30 100644
--- a/arch/arm/cpu/arm926ejs/mx27/reset.c
+++ b/arch/arm/cpu/arm926ejs/mx27/reset.c
@@ -23,7 +23,7 @@
 /*
  * Reset the cpu by setting up the watchdog timer and let it time out
  */
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	struct wdog_regs *regs = (struct wdog_regs *)IMX_WDT_BASE;
 	/* Disable watchdog and set Time-Out field to 0 */
diff --git a/arch/arm/cpu/arm926ejs/mxs/mxs.c b/arch/arm/cpu/arm926ejs/mxs/mxs.c
index c936213..344b9b4 100644
--- a/arch/arm/cpu/arm926ejs/mxs/mxs.c
+++ b/arch/arm/cpu/arm926ejs/mxs/mxs.c
@@ -32,9 +32,9 @@
 /* Lowlevel init isn't used on i.MX28, so just have a dummy here */
 __weak void lowlevel_init(void) {}
 
-void reset_cpu(ulong ignored) __attribute__((noreturn));
+void reset_cpu(void) __attribute__((noreturn));
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	struct mxs_rtc_regs *rtc_regs =
 		(struct mxs_rtc_regs *)MXS_RTC_BASE;
diff --git a/arch/arm/cpu/arm926ejs/spear/reset.c b/arch/arm/cpu/arm926ejs/spear/reset.c
index a316540..97a624e 100644
--- a/arch/arm/cpu/arm926ejs/spear/reset.c
+++ b/arch/arm/cpu/arm926ejs/spear/reset.c
@@ -11,7 +11,7 @@
 #include <asm/arch/spr_syscntl.h>
 #include <linux/delay.h>
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	struct syscntl_regs *syscntl_regs_p =
 	    (struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE;
diff --git a/arch/arm/cpu/arm946es/cpu.c b/arch/arm/cpu/arm946es/cpu.c
index fb0ea5e..334bb54 100644
--- a/arch/arm/cpu/arm946es/cpu.c
+++ b/arch/arm/cpu/arm946es/cpu.c
@@ -56,7 +56,7 @@
 
 #ifndef CONFIG_ARCH_INTEGRATOR
 
-__attribute__((noreturn)) void reset_cpu(ulong addr __attribute__((unused)))
+__attribute__((noreturn)) void reset_cpu(void)
 {
 	writew(0x0, 0xfffece10);
 	writew(0x8, 0xfffece10);
diff --git a/arch/arm/cpu/armv7/bcm281xx/reset.c b/arch/arm/cpu/armv7/bcm281xx/reset.c
index fda5a95..1491e5c 100644
--- a/arch/arm/cpu/armv7/bcm281xx/reset.c
+++ b/arch/arm/cpu/armv7/bcm281xx/reset.c
@@ -13,7 +13,7 @@
 #define CLKS_SHIFT	20		/* Clock period shift */
 #define LD_SHIFT	0		/* Reload value shift */
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	/*
 	 * Set WD enable, RST enable,
diff --git a/arch/arm/cpu/armv7/bcmcygnus/reset.c b/arch/arm/cpu/armv7/bcmcygnus/reset.c
index 3bfed34..63992fd 100644
--- a/arch/arm/cpu/armv7/bcmcygnus/reset.c
+++ b/arch/arm/cpu/armv7/bcmcygnus/reset.c
@@ -10,7 +10,7 @@
 #define CRMU_MAIL_BOX1		0x03024028
 #define CRMU_SOFT_RESET_CMD	0xFFFFFFFF
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	/* Send soft reset command via Mailbox. */
 	writel(CRMU_SOFT_RESET_CMD, CRMU_MAIL_BOX1);
diff --git a/arch/arm/cpu/armv7/bcmnsp/reset.c b/arch/arm/cpu/armv7/bcmnsp/reset.c
index 675f99f..a313775 100644
--- a/arch/arm/cpu/armv7/bcmnsp/reset.c
+++ b/arch/arm/cpu/armv7/bcmnsp/reset.c
@@ -9,7 +9,7 @@
 
 #define CRU_RESET_OFFSET	0x1803F184
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	/* Reset the cpu by setting software reset request bit */
 	writel(0x1, CRU_RESET_OFFSET);
diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c
index 146cf52..19ff432 100644
--- a/arch/arm/cpu/armv7/cache_v7.c
+++ b/arch/arm/cpu/armv7/cache_v7.c
@@ -176,9 +176,6 @@
 {
 }
 
-void arm_init_domains(void)
-{
-}
 #endif /* #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */
 
 #if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
diff --git a/arch/arm/cpu/armv7/ls102xa/cpu.c b/arch/arm/cpu/armv7/ls102xa/cpu.c
index f26a5b2..d863c96 100644
--- a/arch/arm/cpu/armv7/ls102xa/cpu.c
+++ b/arch/arm/cpu/armv7/ls102xa/cpu.c
@@ -375,7 +375,7 @@
 }
 #endif
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 
diff --git a/arch/arm/cpu/armv7/s5p4418/cpu.c b/arch/arm/cpu/armv7/s5p4418/cpu.c
index 3c71a37..3baa761 100644
--- a/arch/arm/cpu/armv7/s5p4418/cpu.c
+++ b/arch/arm/cpu/armv7/s5p4418/cpu.c
@@ -88,7 +88,7 @@
 }
 #endif
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	void *clkpwr_reg = (void *)PHY_BASEADDR_CLKPWR;
 	const u32 sw_rst_enb_bitpos = 3;
diff --git a/arch/arm/cpu/armv7/stv0991/reset.c b/arch/arm/cpu/armv7/stv0991/reset.c
index fb67de1..77d4477 100644
--- a/arch/arm/cpu/armv7/stv0991/reset.c
+++ b/arch/arm/cpu/armv7/stv0991/reset.c
@@ -9,7 +9,7 @@
 #include <asm/io.h>
 #include <asm/arch/stv0991_wdru.h>
 #include <linux/delay.h>
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	puts("System is going to reboot ...\n");
 	/*
diff --git a/arch/arm/cpu/armv7m/cpu.c b/arch/arm/cpu/armv7m/cpu.c
index 7f827da..6372101 100644
--- a/arch/arm/cpu/armv7m/cpu.c
+++ b/arch/arm/cpu/armv7m/cpu.c
@@ -47,7 +47,7 @@
 /*
  * Perform the low-level reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/*
 	 * Perform reset but keep priority group unchanged.
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
index 3a5bf77..270a72e 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
@@ -1231,7 +1231,7 @@
 
 __efi_runtime_data u32 __iomem *rstcr = (u32 *)CONFIG_SYS_FSL_RST_ADDR;
 
-void __efi_runtime reset_cpu(ulong addr)
+void __efi_runtime reset_cpu(void)
 {
 #if defined(CONFIG_ARCH_LX2160A) || defined(CONFIG_ARCH_LX2162A)
 	/* clear the RST_REQ_MSK and SW_RST_REQ */
@@ -1260,7 +1260,7 @@
 	case EFI_RESET_COLD:
 	case EFI_RESET_WARM:
 	case EFI_RESET_PLATFORM_SPECIFIC:
-		reset_cpu(0);
+		reset_cpu();
 		break;
 	case EFI_RESET_SHUTDOWN:
 		/* Nothing we can do */
diff --git a/arch/arm/cpu/armv8/s32v234/generic.c b/arch/arm/cpu/armv8/s32v234/generic.c
index 0fc9885..d1ae10b 100644
--- a/arch/arm/cpu/armv8/s32v234/generic.c
+++ b/arch/arm/cpu/armv8/s32v234/generic.c
@@ -319,7 +319,7 @@
 
 #define SRC_SCR_SW_RST					(1<<12)
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	printf("Feature not supported.\n");
 };
diff --git a/arch/arm/cpu/pxa/pxa2xx.c b/arch/arm/cpu/pxa/pxa2xx.c
index ea91d8a..c7efb67 100644
--- a/arch/arm/cpu/pxa/pxa2xx.c
+++ b/arch/arm/cpu/pxa/pxa2xx.c
@@ -267,9 +267,9 @@
 	writel(readl(CKEN) | CKEN14_I2C, CKEN);
 }
 
-void __attribute__((weak)) reset_cpu(ulong ignored) __attribute__((noreturn));
+void __attribute__((weak)) reset_cpu(void) __attribute__((noreturn));
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	uint32_t tmp;
 
diff --git a/arch/arm/cpu/sa1100/cpu.c b/arch/arm/cpu/sa1100/cpu.c
index 91e100a..6f67f7f 100644
--- a/arch/arm/cpu/sa1100/cpu.c
+++ b/arch/arm/cpu/sa1100/cpu.c
@@ -55,7 +55,7 @@
 #define RSRR	0x00
 #define RCSR	0x04
 
-__attribute__((noreturn)) void reset_cpu(ulong addr __attribute__((unused)))
+__attribute__((noreturn)) void reset_cpu(void)
 {
 	/* repeat endlessly */
 	while (1) {
diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
index c20e05e..b10edf8 100644
--- a/arch/arm/include/asm/cache.h
+++ b/arch/arm/include/asm/cache.h
@@ -35,7 +35,6 @@
 void set_section_dcache(int section, enum dcache_option option);
 
 void arm_init_before_mmu(void);
-void arm_init_domains(void);
 void cpu_cache_initialization(void);
 void dram_bank_mmu_setup(int bank);
 
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 5fe8369..11fceec 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -397,20 +397,6 @@
 	isb();
 }
 
-static inline unsigned int get_dacr(void)
-{
-	unsigned int val;
-	asm("mrc p15, 0, %0, c3, c0, 0	@ get DACR" : "=r" (val) : : "cc");
-	return val;
-}
-
-static inline void set_dacr(unsigned int val)
-{
-	asm volatile("mcr p15, 0, %0, c3, c0, 0	@ set DACR"
-	  : : "r" (val) : "cc");
-	isb();
-}
-
 #ifdef CONFIG_ARMV7_LPAE
 /* Long-Descriptor Translation Table Level 1/2 Bits */
 #define TTB_SECT_XN_MASK	(1ULL << 54)
@@ -475,7 +461,7 @@
 #define TTB_SECT_XN_MASK	(1 << 4)
 #define TTB_SECT_C_MASK		(1 << 3)
 #define TTB_SECT_B_MASK		(1 << 2)
-#define TTB_SECT			(2 << 0)
+#define TTB_SECT		(2 << 0)
 
 /*
  * Short-descriptor format memory region attributes, without TEX remap
@@ -489,7 +475,7 @@
  */
 enum dcache_option {
 	DCACHE_OFF = TTB_SECT_DOMAIN(0) | TTB_SECT_XN_MASK | TTB_SECT,
-	DCACHE_WRITETHROUGH = DCACHE_OFF | TTB_SECT_C_MASK,
+	DCACHE_WRITETHROUGH = TTB_SECT_DOMAIN(0) | TTB_SECT | TTB_SECT_C_MASK,
 	DCACHE_WRITEBACK = DCACHE_WRITETHROUGH | TTB_SECT_B_MASK,
 	DCACHE_WRITEALLOC = DCACHE_WRITEBACK | TTB_SECT_TEX(1),
 };
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 24050e5..aab1bf4 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -22,10 +22,6 @@
 {
 }
 
-__weak void arm_init_domains(void)
-{
-}
-
 static void set_section_phys(int section, phys_addr_t phys,
 			     enum dcache_option option)
 {
@@ -203,11 +199,12 @@
 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
 		     : : "r" (gd->arch.tlb_addr) : "memory");
 #endif
-	/* Set the access control to all-supervisor */
+	/*
+	 * initial value of Domain Access Control Register (DACR)
+	 * Set the access control to client (1U) for each of the 16 domains
+	 */
 	asm volatile("mcr p15, 0, %0, c3, c0, 0"
-		     : : "r" (~0));
-
-	arm_init_domains();
+		     : : "r" (0x55555555));
 
 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c
index 05bb1a3..6dc27d1 100644
--- a/arch/arm/lib/interrupts.c
+++ b/arch/arm/lib/interrupts.c
@@ -53,7 +53,7 @@
 void bad_mode (void)
 {
 	panic ("Resetting CPU ...\n");
-	reset_cpu(0);
+	reset_cpu();
 }
 
 static void show_efi_loaded_images(struct pt_regs *regs)
diff --git a/arch/arm/lib/interrupts_m.c b/arch/arm/lib/interrupts_m.c
index 2ae1c5b..277854a 100644
--- a/arch/arm/lib/interrupts_m.c
+++ b/arch/arm/lib/interrupts_m.c
@@ -59,7 +59,7 @@
 void bad_mode(void)
 {
 	panic("Resetting CPU ...\n");
-	reset_cpu(0);
+	reset_cpu();
 }
 
 void do_hard_fault(struct autosave_regs *autosave_regs)
diff --git a/arch/arm/lib/reset.c b/arch/arm/lib/reset.c
index 4f1a768..95169ba 100644
--- a/arch/arm/lib/reset.c
+++ b/arch/arm/lib/reset.c
@@ -39,7 +39,7 @@
 	disable_interrupts();
 
 	reset_misc();
-	reset_cpu(0);
+	reset_cpu();
 
 	/*NOTREACHED*/
 	return 0;
diff --git a/arch/arm/mach-at91/arm920t/reset.c b/arch/arm/mach-at91/arm920t/reset.c
index d92bc57..91e3751 100644
--- a/arch/arm/mach-at91/arm920t/reset.c
+++ b/arch/arm/mach-at91/arm920t/reset.c
@@ -24,7 +24,7 @@
 	/* true empty function for defining weak symbol */
 }
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	at91_st_t *st = (at91_st_t *) ATMEL_BASE_ST;
 
diff --git a/arch/arm/mach-at91/arm926ejs/reset.c b/arch/arm/mach-at91/arm926ejs/reset.c
index 56fbbd9..6acbfa3 100644
--- a/arch/arm/mach-at91/arm926ejs/reset.c
+++ b/arch/arm/mach-at91/arm926ejs/reset.c
@@ -12,7 +12,7 @@
 #include <asm/arch/at91_rstc.h>
 
 /* Reset the cpu by telling the reset controller to do so */
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	at91_rstc_t *rstc = (at91_rstc_t *) ATMEL_BASE_RSTC;
 
diff --git a/arch/arm/mach-at91/armv7/reset.c b/arch/arm/mach-at91/armv7/reset.c
index 8f4c81d..1ea415e 100644
--- a/arch/arm/mach-at91/armv7/reset.c
+++ b/arch/arm/mach-at91/armv7/reset.c
@@ -15,7 +15,7 @@
 #include <asm/arch/at91_rstc.h>
 
 /* Reset the cpu by telling the reset controller to do so */
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	at91_rstc_t *rstc = (at91_rstc_t *)ATMEL_BASE_RSTC;
 
diff --git a/arch/arm/mach-bcm283x/reset.c b/arch/arm/mach-bcm283x/reset.c
index 2b4ccd4..f13ac0c 100644
--- a/arch/arm/mach-bcm283x/reset.c
+++ b/arch/arm/mach-bcm283x/reset.c
@@ -48,7 +48,7 @@
 	writel(BCM2835_WDOG_PASSWORD | rstc, &wdog_regs->rstc);
 }
 
-void reset_cpu(ulong ticks)
+void reset_cpu(void)
 {
 	struct bcm2835_wdog_regs *regs =
 		(struct bcm2835_wdog_regs *)BCM2835_WDOG_PHYSADDR;
diff --git a/arch/arm/mach-davinci/reset.c b/arch/arm/mach-davinci/reset.c
index 4e6031a..0d59eb6 100644
--- a/arch/arm/mach-davinci/reset.c
+++ b/arch/arm/mach-davinci/reset.c
@@ -12,7 +12,7 @@
 #include <asm/arch/timer_defs.h>
 #include <asm/arch/hardware.h>
 
-void reset_cpu(unsigned long a)
+void reset_cpu(void)
 {
 	struct davinci_timer *const wdttimer =
 		(struct davinci_timer *)DAVINCI_WDOG_BASE;
diff --git a/arch/arm/mach-exynos/soc.c b/arch/arm/mach-exynos/soc.c
index 810fa34..a07c87a 100644
--- a/arch/arm/mach-exynos/soc.c
+++ b/arch/arm/mach-exynos/soc.c
@@ -20,7 +20,7 @@
 void *secondary_boot_addr = (void *)_main;
 #endif /* CONFIG_TARGET_ESPRESSO7420 */
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 #ifdef CONFIG_CPU_V7A
 	writel(0x1, samsung_get_base_swreset());
diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c
index 5f37282..e6bc977 100644
--- a/arch/arm/mach-imx/imx8m/soc.c
+++ b/arch/arm/mach-imx/imx8m/soc.c
@@ -923,7 +923,7 @@
 #endif
 
 #if !CONFIG_IS_ENABLED(SYSRESET)
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 
diff --git a/arch/arm/mach-imx/mx7ulp/soc.c b/arch/arm/mach-imx/mx7ulp/soc.c
index 8dd6b4d..320f24d 100644
--- a/arch/arm/mach-imx/mx7ulp/soc.c
+++ b/arch/arm/mach-imx/mx7ulp/soc.c
@@ -197,7 +197,7 @@
 #endif
 
 #ifndef CONFIG_ULP_WATCHDOG
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	setbits_le32(SIM0_RBASE, SIM_SOPT1_A7_SW_RESET);
 	while (1)
diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 4fbf148..9191f68 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -320,7 +320,7 @@
 #endif
 
 #ifndef CONFIG_SYSRESET
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 }
 #endif
diff --git a/arch/arm/mach-keystone/ddr3.c b/arch/arm/mach-keystone/ddr3.c
index 7dea600..9ee3284 100644
--- a/arch/arm/mach-keystone/ddr3.c
+++ b/arch/arm/mach-keystone/ddr3.c
@@ -345,7 +345,7 @@
 
 		if (!ecc_test) {
 			puts("Reseting the device ...\n");
-			reset_cpu(0);
+			reset_cpu();
 		}
 	}
 
@@ -445,7 +445,7 @@
 		tmp &= ~KS2_RSTYPE_PLL_SOFT;
 		__raw_writel(tmp, KS2_RSTCTRL_RSCFG);
 
-		reset_cpu(0);
+		reset_cpu();
 	}
 }
 #endif
diff --git a/arch/arm/mach-keystone/init.c b/arch/arm/mach-keystone/init.c
index 4950f14..5b95f60 100644
--- a/arch/arm/mach-keystone/init.c
+++ b/arch/arm/mach-keystone/init.c
@@ -192,7 +192,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	volatile u32 *rstctrl = (volatile u32 *)(KS2_RSTCTRL);
 	u32 tmp;
diff --git a/arch/arm/mach-kirkwood/cpu.c b/arch/arm/mach-kirkwood/cpu.c
index 551c22a..9c818fa 100644
--- a/arch/arm/mach-kirkwood/cpu.c
+++ b/arch/arm/mach-kirkwood/cpu.c
@@ -19,7 +19,7 @@
 #include <asm/arch/soc.h>
 #include <mvebu_mmc.h>
 
-void reset_cpu(unsigned long ignored)
+void reset_cpu(void)
 {
 	struct kwcpu_registers *cpureg =
 	    (struct kwcpu_registers *)KW_CPU_REG_BASE;
diff --git a/arch/arm/mach-lpc32xx/cpu.c b/arch/arm/mach-lpc32xx/cpu.c
index 32af620..c2586d0 100644
--- a/arch/arm/mach-lpc32xx/cpu.c
+++ b/arch/arm/mach-lpc32xx/cpu.c
@@ -17,28 +17,17 @@
 static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
 static struct wdt_regs  *wdt = (struct wdt_regs *)WDT_BASE;
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/* Enable watchdog clock */
 	setbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG);
 
-	/* To be compatible with the original U-Boot code:
-	 * addr: - 0: perform hard reset.
-	 *       - !=0: perform a soft reset; i.e. "RESOUT_N" not asserted). */
-	if (addr == 0) {
-		/* Reset pulse length is 13005 peripheral clock frames */
-		writel(13000, &wdt->pulse);
+	/* Reset pulse length is 13005 peripheral clock frames */
+	writel(13000, &wdt->pulse);
 
-		/* Force WDOG_RESET2 and RESOUT_N signal active */
-		writel(WDTIM_MCTRL_RESFRC2 | WDTIM_MCTRL_RESFRC1
-		       | WDTIM_MCTRL_M_RES2, &wdt->mctrl);
-	} else {
-		/* Force match output active */
-		writel(0x01, &wdt->emr);
-
-		/* Internal reset on match output (no pulse on "RESOUT_N") */
-		writel(WDTIM_MCTRL_M_RES1, &wdt->mctrl);
-	}
+	/* Force WDOG_RESET2 and RESOUT_N signal active */
+	writel(WDTIM_MCTRL_RESFRC2 | WDTIM_MCTRL_RESFRC1 | WDTIM_MCTRL_M_RES2,
+	       &wdt->mctrl);
 
 	while (1)
 		/* NOP */;
diff --git a/arch/arm/mach-mediatek/mt7622/init.c b/arch/arm/mach-mediatek/mt7622/init.c
index 7f6ce80..e501907 100644
--- a/arch/arm/mach-mediatek/mt7622/init.c
+++ b/arch/arm/mach-mediatek/mt7622/init.c
@@ -27,7 +27,7 @@
 
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/arch/arm/mach-mediatek/mt8512/init.c b/arch/arm/mach-mediatek/mt8512/init.c
index c14e7d2..b7050df 100644
--- a/arch/arm/mach-mediatek/mt8512/init.c
+++ b/arch/arm/mach-mediatek/mt8512/init.c
@@ -43,7 +43,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct udevice *watchdog_dev = NULL;
 
diff --git a/arch/arm/mach-mediatek/mt8516/init.c b/arch/arm/mach-mediatek/mt8516/init.c
index 3771152..3460dcc 100644
--- a/arch/arm/mach-mediatek/mt8516/init.c
+++ b/arch/arm/mach-mediatek/mt8516/init.c
@@ -85,7 +85,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/arch/arm/mach-mediatek/mt8518/init.c b/arch/arm/mach-mediatek/mt8518/init.c
index 28b00c3..f7e03de 100644
--- a/arch/arm/mach-mediatek/mt8518/init.c
+++ b/arch/arm/mach-mediatek/mt8518/init.c
@@ -42,7 +42,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/arch/arm/mach-meson/board-common.c b/arch/arm/mach-meson/board-common.c
index 34b3c8f..1690b6b 100644
--- a/arch/arm/mach-meson/board-common.c
+++ b/arch/arm/mach-meson/board-common.c
@@ -167,7 +167,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct pt_regs regs;
 
@@ -182,7 +182,7 @@
 		;
 }
 #else
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/arch/arm/mach-mvebu/armada3700/cpu.c b/arch/arm/mach-mvebu/armada3700/cpu.c
index 70f76c7..0cf60d7 100644
--- a/arch/arm/mach-mvebu/armada3700/cpu.c
+++ b/arch/arm/mach-mvebu/armada3700/cpu.c
@@ -314,7 +314,7 @@
 	return fdt_setprop_inplace(blob, node, "ranges", new_ranges, len);
 }
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	/*
 	 * Write magic number of 0x1d1e to North Bridge Warm Reset register
diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c
index 529dac9..474327a 100644
--- a/arch/arm/mach-mvebu/armada8k/cpu.c
+++ b/arch/arm/mach-mvebu/armada8k/cpu.c
@@ -104,7 +104,7 @@
 	dcache_enable();
 }
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	u32 reg;
 
diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c
index 7dce11e..0b935c4 100644
--- a/arch/arm/mach-mvebu/cpu.c
+++ b/arch/arm/mach-mvebu/cpu.c
@@ -42,7 +42,7 @@
 	 */
 }
 
-void reset_cpu(unsigned long ignored)
+void reset_cpu(void)
 {
 	struct mvebu_system_registers *reg =
 		(struct mvebu_system_registers *)MVEBU_SYSTEM_REG_BASE;
diff --git a/arch/arm/mach-nexell/Makefile b/arch/arm/mach-nexell/Makefile
index 10b3963..dda16db 100644
--- a/arch/arm/mach-nexell/Makefile
+++ b/arch/arm/mach-nexell/Makefile
@@ -10,4 +10,3 @@
 obj-y				+= tieoff.o
 obj-$(CONFIG_ARCH_S5P4418)	+= reg-call.o
 obj-$(CONFIG_ARCH_S5P4418)	+= nx_sec_reg.o
-obj-$(CONFIG_CMD_BOOTL)		+= cmd_boot_linux.o
diff --git a/arch/arm/mach-nexell/cmd_boot_linux.c b/arch/arm/mach-nexell/cmd_boot_linux.c
deleted file mode 100644
index 9b38d38..0000000
--- a/arch/arm/mach-nexell/cmd_boot_linux.c
+++ /dev/null
@@ -1,145 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2016 nexell
- * jhkim <jhkim@nexell.co.kr>
- */
-
-#include <common.h>
-#include <bootm.h>
-#include <command.h>
-#include <environment.h>
-#include <errno.h>
-#include <image.h>
-#include <fdt_support.h>
-#include <asm/global_data.h>
-
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_CLI_FRAMEWORK)
-
-DECLARE_GLOBAL_DATA_PTR;
-
-static bootm_headers_t linux_images;
-
-static void boot_go_set_os(cmd_tbl_t *cmdtp, int flag, int argc,
-			   char * const argv[],
-			   bootm_headers_t *images)
-{
-	char * const img_addr = argv[0];
-
-	images->os.type = IH_TYPE_KERNEL;
-	images->os.comp = IH_COMP_NONE;
-	images->os.os = IH_OS_LINUX;
-	images->os.load = simple_strtoul(img_addr, NULL, 16);
-	images->ep = images->os.load;
-#if defined(CONFIG_ARM)
-	images->os.arch = IH_ARCH_ARM;
-#elif defined(CONFIG_ARM64)
-	images->os.arch = IH_ARCH_ARM64;
-#else
-	#error "Not support architecture ..."
-#endif
-	if (!IS_ENABLED(CONFIG_OF_LIBFDT) && !IS_ENABLED(CONFIG_SPL_BUILD)) {
-		/* set DTB address for linux kernel */
-		if (argc > 2) {
-			unsigned long ft_addr;
-
-			ft_addr = simple_strtol(argv[2], NULL, 16);
-			images->ft_addr = (char *)ft_addr;
-
-			/*
-			 * if not defined IMAGE_ENABLE_OF_LIBFDT,
-			 * must be set to fdt address
-			 */
-			if (!IMAGE_ENABLE_OF_LIBFDT)
-				gd->bd->bi_boot_params = ft_addr;
-
-			debug("## set ft:%08lx and boot params:%08lx [control of:%s]"
-			      "...\n", ft_addr, gd->bd->bi_boot_params,
-			      IMAGE_ENABLE_OF_LIBFDT ? "on" : "off");
-		}
-	}
-}
-
-#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)
-static void boot_start_lmb(bootm_headers_t *images)
-{
-	ulong		mem_start;
-	phys_size_t	mem_size;
-
-	lmb_init(&images->lmb);
-
-	mem_start = getenv_bootm_low();
-	mem_size = getenv_bootm_size();
-
-	lmb_add(&images->lmb, (phys_addr_t)mem_start, mem_size);
-
-	arch_lmb_reserve(&images->lmb);
-	board_lmb_reserve(&images->lmb);
-}
-#else
-#define lmb_reserve(lmb, base, size)
-static inline void boot_start_lmb(bootm_headers_t *images) { }
-#endif
-
-int do_boot_linux(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-	boot_os_fn *boot_fn;
-	bootm_headers_t *images = &linux_images;
-	int flags;
-	int ret;
-
-	boot_start_lmb(images);
-
-	flags  = BOOTM_STATE_START;
-
-	argc--; argv++;
-	boot_go_set_os(cmdtp, flag, argc, argv, images);
-
-	if (IS_ENABLED(CONFIG_OF_LIBFDT)) {
-		/* find flattened device tree */
-		ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, images,
-				   &images->ft_addr, &images->ft_len);
-		if (ret) {
-			puts("Could not find a valid device tree\n");
-			return 1;
-		}
-		set_working_fdt_addr((ulong)images->ft_addr);
-	}
-
-	if (!IS_ENABLED(CONFIG_OF_LIBFDT))
-		flags |= BOOTM_STATE_OS_GO;
-
-	boot_fn = do_bootm_linux;
-	ret = boot_fn(flags, argc, argv, images);
-
-	if (ret == BOOTM_ERR_UNIMPLEMENTED)
-		show_boot_progress(BOOTSTAGE_ID_DECOMP_UNIMPL);
-	else if (ret == BOOTM_ERR_RESET)
-		do_reset(cmdtp, flag, argc, argv);
-
-	return ret;
-}
-
-U_BOOT_CMD(bootl, CONFIG_SYS_MAXARGS, 1, do_boot_linux,
-	   "boot linux image from memory",
-	   "[addr [arg ...]]\n    - boot linux image stored in memory\n"
-	   "\tuse a '-' for the DTB address\n"
-);
-#endif
-
-#if defined(CONFIG_CMD_BOOTD) && !defined(CONFIG_CMD_BOOTM)
-int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-	return run_command(env_get("bootcmd"), flag);
-}
-
-U_BOOT_CMD(boot, 1, 1, do_bootd,
-	   "boot default, i.e., run 'bootcmd'",
-	   ""
-);
-
-/* keep old command name "bootd" for backward compatibility */
-U_BOOT_CMD(bootd, 1,	1,	do_bootd,
-	   "boot default, i.e., run 'bootcmd'",
-	   ""
-);
-#endif
diff --git a/arch/arm/mach-octeontx/cpu.c b/arch/arm/mach-octeontx/cpu.c
index ce5f2b4..7bd74fe 100644
--- a/arch/arm/mach-octeontx/cpu.c
+++ b/arch/arm/mach-octeontx/cpu.c
@@ -72,6 +72,6 @@
 	return 0x80000;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/arch/arm/mach-octeontx2/cpu.c b/arch/arm/mach-octeontx2/cpu.c
index 8786815..afa458c 100644
--- a/arch/arm/mach-octeontx2/cpu.c
+++ b/arch/arm/mach-octeontx2/cpu.c
@@ -68,6 +68,6 @@
 	return 0x80000;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/arch/arm/mach-omap2/omap-cache.c b/arch/arm/mach-omap2/omap-cache.c
index 1b246f8..36db588 100644
--- a/arch/arm/mach-omap2/omap-cache.c
+++ b/arch/arm/mach-omap2/omap-cache.c
@@ -41,9 +41,6 @@
 #define ARMV7_DCACHE_POLICY	DCACHE_WRITEBACK & ~TTB_SECT_XN_MASK
 #endif
 
-#define ARMV7_DOMAIN_CLIENT	1
-#define ARMV7_DOMAIN_MASK	(0x3 << 0)
-
 void enable_caches(void)
 {
 
@@ -67,17 +64,3 @@
 	for (i = start; i < end; i++)
 		set_section_dcache(i, ARMV7_DCACHE_POLICY);
 }
-
-void arm_init_domains(void)
-{
-	u32 reg;
-
-	reg = get_dacr();
-	/*
-	* Set DOMAIN to client access so that all permissions
-	* set in pagetables are validated by the mmu.
-	*/
-	reg &= ~ARMV7_DOMAIN_MASK;
-	reg |= ARMV7_DOMAIN_CLIENT;
-	set_dacr(reg);
-}
diff --git a/arch/arm/mach-omap2/omap5/hwinit.c b/arch/arm/mach-omap2/omap5/hwinit.c
index 47ac865..edab9a9 100644
--- a/arch/arm/mach-omap2/omap5/hwinit.c
+++ b/arch/arm/mach-omap2/omap5/hwinit.c
@@ -417,7 +417,7 @@
 	die_id[3] = readl((*ctrl)->control_std_fuse_die_id_3);
 }
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 	u32 omap_rev = omap_revision();
 
diff --git a/arch/arm/mach-omap2/reset.c b/arch/arm/mach-omap2/reset.c
index 2bbd5fc..1fd79c2 100644
--- a/arch/arm/mach-omap2/reset.c
+++ b/arch/arm/mach-omap2/reset.c
@@ -14,7 +14,7 @@
 #include <asm/arch/cpu.h>
 #include <linux/compiler.h>
 
-void __weak reset_cpu(unsigned long ignored)
+void __weak reset_cpu(void)
 {
 	writel(PRM_RSTCTRL_RESET, PRM_RSTCTRL);
 }
diff --git a/arch/arm/mach-orion5x/cpu.c b/arch/arm/mach-orion5x/cpu.c
index beae7b8..ffae9a0 100644
--- a/arch/arm/mach-orion5x/cpu.c
+++ b/arch/arm/mach-orion5x/cpu.c
@@ -20,7 +20,7 @@
 
 #define BUFLEN	16
 
-void reset_cpu(unsigned long ignored)
+void reset_cpu(void)
 {
 	struct orion5x_cpu_registers *cpureg =
 	    (struct orion5x_cpu_registers *)ORION5X_CPU_REG_BASE;
diff --git a/arch/arm/mach-owl/soc.c b/arch/arm/mach-owl/soc.c
index 4d2b9d0..4baef2e 100644
--- a/arch/arm/mach-owl/soc.c
+++ b/arch/arm/mach-owl/soc.c
@@ -74,7 +74,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/arch/arm/mach-socfpga/include/mach/reset_manager.h b/arch/arm/mach-socfpga/include/mach/reset_manager.h
index 8c25325..1d68034 100644
--- a/arch/arm/mach-socfpga/include/mach/reset_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/reset_manager.h
@@ -8,7 +8,7 @@
 
 phys_addr_t socfpga_get_rstmgr_addr(void);
 
-void reset_cpu(ulong addr);
+void reset_cpu(void);
 
 void socfpga_per_reset(u32 reset, int set);
 void socfpga_per_reset_all(void);
diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c
index bc2db53..897ec13 100644
--- a/arch/arm/mach-stm32mp/cpu.c
+++ b/arch/arm/mach-stm32mp/cpu.c
@@ -212,6 +212,35 @@
 }
 
 /*
+ * weak function overidde: set the DDR/SYSRAM executable before to enable the
+ * MMU and configure DACR, for early early_enable_caches (SPL or pre-reloc)
+ */
+void dram_bank_mmu_setup(int bank)
+{
+	struct bd_info *bd = gd->bd;
+	int	i;
+	phys_addr_t start;
+	phys_size_t size;
+
+	if (IS_ENABLED(CONFIG_SPL_BUILD)) {
+		start = ALIGN_DOWN(STM32_SYSRAM_BASE, MMU_SECTION_SIZE);
+		size = ALIGN(STM32_SYSRAM_SIZE, MMU_SECTION_SIZE);
+	} else if (gd->flags & GD_FLG_RELOC) {
+		/* bd->bi_dram is available only after relocation */
+		start = bd->bi_dram[bank].start;
+		size =  bd->bi_dram[bank].size;
+	} else {
+		/* mark cacheable and executable the beggining of the DDR */
+		start = STM32_DDR_BASE;
+		size = CONFIG_DDR_CACHEABLE_SIZE;
+	}
+
+	for (i = start >> MMU_SECTION_SHIFT;
+	     i < (start >> MMU_SECTION_SHIFT) + (size >> MMU_SECTION_SHIFT);
+	     i++)
+		set_section_dcache(i, DCACHE_DEFAULT_OPTION);
+}
+/*
  * initialize the MMU and activate cache in SPL or in U-Boot pre-reloc stage
  * MMU/TLB is updated in enable_caches() for U-Boot after relocation
  * or is deactivated in U-Boot entry function start.S::cpu_init_cp15
@@ -228,17 +257,8 @@
 		gd->arch.tlb_addr = (unsigned long)&early_tlb;
 	}
 
+	/* enable MMU (default configuration) */
 	dcache_enable();
-
-	if (IS_ENABLED(CONFIG_SPL_BUILD))
-		mmu_set_region_dcache_behaviour(
-			ALIGN_DOWN(STM32_SYSRAM_BASE, MMU_SECTION_SIZE),
-			ALIGN(STM32_SYSRAM_SIZE, MMU_SECTION_SIZE),
-			DCACHE_DEFAULT_OPTION);
-	else
-		mmu_set_region_dcache_behaviour(STM32_DDR_BASE,
-						CONFIG_DDR_CACHEABLE_SIZE,
-						DCACHE_DEFAULT_OPTION);
 }
 
 /*
diff --git a/arch/arm/mach-stm32mp/dram_init.c b/arch/arm/mach-stm32mp/dram_init.c
index ad6977f..66e81ba 100644
--- a/arch/arm/mach-stm32mp/dram_init.c
+++ b/arch/arm/mach-stm32mp/dram_init.c
@@ -13,6 +13,7 @@
 #include <log.h>
 #include <ram.h>
 #include <asm/global_data.h>
+#include <asm/system.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -41,6 +42,7 @@
 
 ulong board_get_usable_ram_top(ulong total_size)
 {
+	phys_size_t size;
 	phys_addr_t reg;
 	struct lmb lmb;
 
@@ -48,10 +50,13 @@
 	lmb_init(&lmb);
 	lmb_add(&lmb, gd->ram_base, gd->ram_size);
 	boot_fdt_add_mem_rsv_regions(&lmb, (void *)gd->fdt_blob);
-	reg = lmb_alloc(&lmb, CONFIG_SYS_MALLOC_LEN + total_size, SZ_4K);
+	size = ALIGN(CONFIG_SYS_MALLOC_LEN + total_size, MMU_SECTION_SIZE),
+	reg = lmb_alloc(&lmb, size, MMU_SECTION_SIZE);
 
-	if (reg)
-		return ALIGN(reg + CONFIG_SYS_MALLOC_LEN + total_size, SZ_4K);
+	if (!reg)
+		reg = gd->ram_top - size;
 
-	return gd->ram_top;
+	mmu_set_region_dcache_behaviour(reg, size, DCACHE_DEFAULT_OPTION);
+
+	return reg + size;
 }
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 0135575..a29d115 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -816,13 +816,14 @@
 	depends on !MACH_SUN9I
 	depends on !MACH_SUN50I
 	depends on !SUN50I_GEN_H6
-	select VIDEO
+	select DM_VIDEO
+	select DISPLAY
 	imply VIDEO_DT_SIMPLEFB
 	default y
 	---help---
-	Say Y here to add support for using a cfb console on the HDMI, LCD
-	or VGA output found on most sunxi devices. See doc/README.video for
-	info on how to select the video output and mode.
+	Say Y here to add support for using a graphical console on the HDMI,
+	LCD or VGA output found on older sunxi devices. This will also provide
+	a simple_framebuffer device for Linux.
 
 config VIDEO_HDMI
 	bool "HDMI output support"
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index fa2b6fc..503538e 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -338,7 +338,7 @@
 }
 #endif
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 #if defined(CONFIG_SUNXI_GEN_SUN4I) || defined(CONFIG_MACH_SUN8I_R40)
 	static const struct sunxi_wdog *wdog =
diff --git a/arch/arm/mach-tegra/cmd_enterrcm.c b/arch/arm/mach-tegra/cmd_enterrcm.c
index 25df31a..92ff6cb 100644
--- a/arch/arm/mach-tegra/cmd_enterrcm.c
+++ b/arch/arm/mach-tegra/cmd_enterrcm.c
@@ -40,7 +40,7 @@
 
 	tegra_pmc_writel(2, PMC_SCRATCH0);
 	disable_interrupts();
-	reset_cpu(0);
+	reset_cpu();
 
 	return 0;
 }
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
index 93db63e..8d617be 100644
--- a/arch/arm/mach-tegra/pmc.c
+++ b/arch/arm/mach-tegra/pmc.c
@@ -85,7 +85,7 @@
 	writel(value, NV_PA_PMC_BASE + offset);
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	u32 value;
 
diff --git a/arch/arm/mach-uniphier/arm32/psci.c b/arch/arm/mach-uniphier/arm32/psci.c
index a4d260a..fbb6ebc 100644
--- a/arch/arm/mach-uniphier/arm32/psci.c
+++ b/arch/arm/mach-uniphier/arm32/psci.c
@@ -158,5 +158,5 @@
 
 void __secure psci_system_reset(void)
 {
-	reset_cpu(0);
+	reset_cpu();
 }
diff --git a/arch/arm/mach-uniphier/reset.c b/arch/arm/mach-uniphier/reset.c
index 5fffd23..dddb48e 100644
--- a/arch/arm/mach-uniphier/reset.c
+++ b/arch/arm/mach-uniphier/reset.c
@@ -18,7 +18,7 @@
 #define __SECURE
 #endif
 
-void __SECURE reset_cpu(unsigned long ignored)
+void __SECURE reset_cpu(void)
 {
 	u32 tmp;
 
diff --git a/arch/arm/mach-zynq/cpu.c b/arch/arm/mach-zynq/cpu.c
index 3befc12..69b818f 100644
--- a/arch/arm/mach-zynq/cpu.c
+++ b/arch/arm/mach-zynq/cpu.c
@@ -78,7 +78,7 @@
 						>> ZYNQ_SILICON_VER_SHIFT;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	zynq_slcr_cpu_reset();
 	while (1)
diff --git a/arch/arm/mach-zynqmp-r5/cpu.c b/arch/arm/mach-zynqmp-r5/cpu.c
index d841c3a..0d36844 100644
--- a/arch/arm/mach-zynqmp-r5/cpu.c
+++ b/arch/arm/mach-zynqmp-r5/cpu.c
@@ -30,7 +30,7 @@
 /*
  * Perform the low-level reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	while (1)
 		;
diff --git a/arch/nds32/cpu/n1213/ag101/cpu.c b/arch/nds32/cpu/n1213/ag101/cpu.c
index 9d99c83..91c3574 100644
--- a/arch/nds32/cpu/n1213/ag101/cpu.c
+++ b/arch/nds32/cpu/n1213/ag101/cpu.c
@@ -46,7 +46,7 @@
 	/*
 	 * reset to the base addr of andesboot.
 	 * currently no ROM loader at addr 0.
-	 * do not use reset_cpu(0);
+	 * do not use reset_cpu();
 	 */
 #ifdef CONFIG_FTWDT010_WATCHDOG
 	/*
diff --git a/arch/nds32/cpu/n1213/start.S b/arch/nds32/cpu/n1213/start.S
index 386c199..3395721 100644
--- a/arch/nds32/cpu/n1213/start.S
+++ b/arch/nds32/cpu/n1213/start.S
@@ -500,25 +500,3 @@
 	bal	do_interruption
 
 	.align	5
-
-/*
- * void reset_cpu(ulong addr);
- * $r0: input address to jump to
- */
-.globl reset_cpu
-reset_cpu:
-/* No need to disable MMU because we never enable it */
-
-	bal	invalidate_icac
-	bal	invalidate_dcac
-	mfsr	$p0, $MMU_CFG
-	andi	$p0, $p0, 0x3			! MMPS
-	li	$p1, 0x2			! TLB MMU
-	bne	$p0, $p1, 1f
-	tlbop	flushall			! Flush TLB
-1:
-	mfsr	$p0, MR_CAC_CTL			! Get the $CACHE_CTL reg
-	li	$p1, DIS_DCAC
-	and	$p0, $p0, $p1			! Clear the DC_EN bit
-	mtsr	$p0, MR_CAC_CTL			! Write back the $CACHE_CTL reg
-	br	$r0				! Jump to the input address
diff --git a/arch/nds32/lib/interrupts.c b/arch/nds32/lib/interrupts.c
index 1481e05..0ec72d1 100644
--- a/arch/nds32/lib/interrupts.c
+++ b/arch/nds32/lib/interrupts.c
@@ -66,7 +66,7 @@
 void bad_mode(void)
 {
 	panic("Resetting CPU ...\n");
-	reset_cpu(0);
+	reset_cpu();
 }
 
 void show_regs(struct pt_regs *regs)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 3d8af0a..2d9583c 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -153,7 +153,7 @@
 		printf("Cannot seek to start of file '%s'\n", fname);
 		goto err;
 	}
-	*bufp = malloc(size);
+	*bufp = os_malloc(size);
 	if (!*bufp) {
 		printf("Not enough memory to read file '%s'\n", fname);
 		ret = -ENOMEM;
@@ -267,11 +267,18 @@
 	signal(SIGINT, os_sigint_handler);
 }
 
+/*
+ * Provide our own malloc so we don't use space in the sandbox ram_buf for
+ * allocations that are internal to sandbox, or need to be done before U-Boot's
+ * malloc() is ready.
+ */
 void *os_malloc(size_t length)
 {
 	int page_size = getpagesize();
 	struct os_mem_hdr *hdr;
 
+	if (!length)
+		return NULL;
 	/*
 	 * Use an address that is hopefully available to us so that pointers
 	 * to this memory are fairly obvious. If we end up with a different
@@ -298,6 +305,47 @@
 	}
 }
 
+/* These macros are from kernel.h but not accessible in this file */
+#define ALIGN(x, a)		__ALIGN_MASK((x), (typeof(x))(a) - 1)
+#define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
+
+/*
+ * Provide our own malloc so we don't use space in the sandbox ram_buf for
+ * allocations that are internal to sandbox, or need to be done before U-Boot's
+ * malloc() is ready.
+ */
+void *os_realloc(void *ptr, size_t length)
+{
+	int page_size = getpagesize();
+	struct os_mem_hdr *hdr;
+	void *new_ptr;
+
+	/* Reallocating a NULL pointer is just an alloc */
+	if (!ptr)
+		return os_malloc(length);
+
+	/* Changing a length to 0 is just a free */
+	if (length) {
+		os_free(ptr);
+		return NULL;
+	}
+
+	/*
+	 * If the new size is the same number of pages as the old, nothing to
+	 * do. There isn't much point in shrinking things
+	 */
+	hdr = ptr - page_size;
+	if (ALIGN(length, page_size) <= ALIGN(hdr->length, page_size))
+		return ptr;
+
+	/* We have to grow it, so allocate something new */
+	new_ptr = os_malloc(length);
+	memcpy(new_ptr, ptr, hdr->length);
+	os_free(ptr);
+
+	return new_ptr;
+}
+
 void os_usleep(unsigned long usec)
 {
 	usleep(usec);
@@ -343,8 +391,8 @@
 	state->argv = argv;
 
 	/* dynamically construct the arguments to the system getopt_long */
-	short_opts = malloc(sizeof(*short_opts) * num_options * 2 + 1);
-	long_opts = malloc(sizeof(*long_opts) * (num_options + 1));
+	short_opts = os_malloc(sizeof(*short_opts) * num_options * 2 + 1);
+	long_opts = os_malloc(sizeof(*long_opts) * (num_options + 1));
 	if (!short_opts || !long_opts)
 		return 1;
 
@@ -423,7 +471,7 @@
 
 	while (node) {
 		next = node->next;
-		free(node);
+		os_free(node);
 		node = next;
 	}
 }
@@ -448,7 +496,7 @@
 	/* Create a buffer upfront, with typically sufficient size */
 	dirlen = strlen(dirname) + 2;
 	len = dirlen + 256;
-	fname = malloc(len);
+	fname = os_malloc(len);
 	if (!fname) {
 		ret = -ENOMEM;
 		goto done;
@@ -461,7 +509,7 @@
 			ret = errno;
 			break;
 		}
-		next = malloc(sizeof(*node) + strlen(entry->d_name) + 1);
+		next = os_malloc(sizeof(*node) + strlen(entry->d_name) + 1);
 		if (!next) {
 			os_dirent_free(head);
 			ret = -ENOMEM;
@@ -470,10 +518,10 @@
 		if (dirlen + strlen(entry->d_name) > len) {
 			len = dirlen + strlen(entry->d_name);
 			old_fname = fname;
-			fname = realloc(fname, len);
+			fname = os_realloc(fname, len);
 			if (!fname) {
-				free(old_fname);
-				free(next);
+				os_free(old_fname);
+				os_free(next);
 				os_dirent_free(head);
 				ret = -ENOMEM;
 				goto done;
@@ -507,7 +555,7 @@
 
 done:
 	closedir(dir);
-	free(fname);
+	os_free(fname);
 	return ret;
 }
 
@@ -624,7 +672,7 @@
 	for (argc = 0; (*argvp)[argc]; argc++)
 		;
 
-	argv = malloc((argc + count + 1) * sizeof(char *));
+	argv = os_malloc((argc + count + 1) * sizeof(char *));
 	if (!argv) {
 		printf("Out of memory for %d argv\n", count);
 		return -ENOMEM;
@@ -707,7 +755,7 @@
 		os_exit(2);
 
 	err = execv(fname, argv);
-	free(argv);
+	os_free(argv);
 	if (err) {
 		perror("Unable to run image");
 		printf("Image filename '%s'\n", fname);
@@ -729,7 +777,7 @@
 	return os_jump_to_file(fname);
 }
 
-int os_find_u_boot(char *fname, int maxlen)
+int os_find_u_boot(char *fname, int maxlen, bool use_img)
 {
 	struct sandbox_state *state = state_get_current();
 	const char *progname = state->argv[0];
@@ -753,8 +801,8 @@
 			return 0;
 		}
 
-		/* Look for 'u-boot-tpl' in the tpl/ directory */
-		p = strstr(fname, "/tpl/");
+		/* Look for 'u-boot-spl' in the spl/ directory */
+		p = strstr(fname, "/spl/");
 		if (p) {
 			p[1] = 's';
 			fd = os_open(fname, O_RDONLY);
@@ -781,6 +829,8 @@
 	if (p) {
 		/* Remove the "spl" characters */
 		memmove(p, p + 4, strlen(p + 4) + 1);
+		if (use_img)
+			strcat(p, ".img");
 		fd = os_open(fname, O_RDONLY);
 		if (fd >= 0) {
 			close(fd);
diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c
index d4dab36..8102649 100644
--- a/arch/sandbox/cpu/sdl.c
+++ b/arch/sandbox/cpu/sdl.c
@@ -69,14 +69,14 @@
 	 * We don't want to include common.h in this file since it uses
 	 * system headers. So add a declation here.
 	 */
-	extern void reset_cpu(unsigned long addr);
+	extern void reset_cpu(void);
 	SDL_Event event;
 
 	while (SDL_PollEvent(&event)) {
 		switch (event.type) {
 		case SDL_QUIT:
 			puts("LCD window closed - quitting\n");
-			reset_cpu(1);
+			reset_cpu();
 			break;
 		}
 	}
diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c
index e7b4b50..f82b0d3 100644
--- a/arch/sandbox/cpu/spl.c
+++ b/arch/sandbox/cpu/spl.c
@@ -13,7 +13,7 @@
 #include <asm/global_data.h>
 #include <asm/spl.h>
 #include <asm/state.h>
-#include <test/test.h>
+#include <test/ut.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -37,16 +37,20 @@
 	char fname[256];
 	int ret;
 
-	ret = os_find_u_boot(fname, sizeof(fname));
+	ret = os_find_u_boot(fname, sizeof(fname), false);
 	if (ret) {
 		printf("(%s not found, error %d)\n", fname, ret);
 		return ret;
 	}
 
-	/* Set up spl_image to boot from jump_to_image_no_args() */
-	spl_image->arg = strdup(fname);
+	/*
+	 * Set up spl_image to boot from jump_to_image_no_args(). Allocate this
+	 * outsdide the RAM buffer (i.e. don't use strdup()).
+	 */
+	spl_image->arg = os_malloc(strlen(fname) + 1);
 	if (!spl_image->arg)
-		return log_msg_ret("Setup exec filename", -ENOMEM);
+		return log_msg_ret("exec", -ENOMEM);
+	strcpy(spl_image->arg, fname);
 
 	return 0;
 }
@@ -59,9 +63,12 @@
 	preloader_console_init();
 
 	if (state->run_unittests) {
+		struct unit_test *tests = UNIT_TEST_ALL_START();
+		const int count = UNIT_TEST_ALL_COUNT();
 		int ret;
 
-		ret = dm_test_main(state->select_unittests);
+		ret = ut_run_list("spl", NULL, tests, count,
+				  state->select_unittests);
 		/* continue execution into U-Boot */
 	}
 }
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c
index 483a264..e87365e 100644
--- a/arch/sandbox/cpu/start.c
+++ b/arch/sandbox/cpu/start.c
@@ -88,7 +88,7 @@
 
 	/* Sort the options */
 	size = sizeof(*sorted_opt) * num_options;
-	sorted_opt = malloc(size);
+	sorted_opt = os_malloc(size);
 	if (!sorted_opt) {
 		printf("No memory to sort options\n");
 		os_exit(1);
@@ -188,7 +188,7 @@
 	int len;
 
 	len = strlen(state->argv[0]) + strlen(fmt) + 1;
-	fname = malloc(len);
+	fname = os_malloc(len);
 	if (!fname)
 		return -ENOMEM;
 	snprintf(fname, len, fmt, state->argv[0]);
@@ -208,7 +208,7 @@
 	int len;
 
 	len = strlen(state->argv[0]) + strlen(fmt) + 1;
-	fname = malloc(len);
+	fname = os_malloc(len);
 	if (!fname)
 		return -ENOMEM;
 	strcpy(fname, state->argv[0]);
@@ -436,16 +436,18 @@
 {
 	struct sandbox_state *state;
 	gd_t data;
+	int size;
 	int ret;
 
 	/*
 	 * Copy argv[] so that we can pass the arguments in the original
 	 * sequence when resetting the sandbox.
 	 */
-	os_argv = calloc(argc + 1, sizeof(char *));
+	size = sizeof(char *) * (argc + 1);
+	os_argv = os_malloc(size);
 	if (!os_argv)
 		os_exit(1);
-	memcpy(os_argv, argv, sizeof(char *) * (argc + 1));
+	memcpy(os_argv, argv, size);
 
 	memset(&data, '\0', sizeof(data));
 	gd = &data;
@@ -489,7 +491,6 @@
 	gd->reloc_off = (ulong)gd->arch.text_base;
 
 	/* sandbox test: log functions called before log_init in board_init_f */
-	log_info("sandbox: starting...\n");
 	log_debug("debug: %s\n", __func__);
 
 	/* Do pre- and post-relocation init */
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index b2901b7..f63cfd3 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <bloblist.h>
 #include <errno.h>
 #include <fdtdec.h>
 #include <log.h>
@@ -29,17 +30,17 @@
 		return 0;
 
 	size = used + extra_size;
-	buf = malloc(size);
+	buf = os_malloc(size);
 	if (!buf)
 		return -ENOMEM;
 
 	ret = fdt_open_into(blob, buf, size);
 	if (ret) {
-		free(buf);
+		os_free(buf);
 		return -EIO;
 	}
 
-	free(blob);
+	os_free(blob);
 	state->state_fdt = buf;
 	return 0;
 }
@@ -55,7 +56,7 @@
 		printf("Cannot find sandbox state file '%s'\n", fname);
 		return -ENOENT;
 	}
-	state->state_fdt = malloc(size);
+	state->state_fdt = os_malloc(size);
 	if (!state->state_fdt) {
 		puts("No memory to read sandbox state\n");
 		return -ENOMEM;
@@ -77,7 +78,7 @@
 err_read:
 	os_close(fd);
 err_open:
-	free(state->state_fdt);
+	os_free(state->state_fdt);
 	state->state_fdt = NULL;
 
 	return ret;
@@ -244,7 +245,7 @@
 	/* Create a state FDT if we don't have one */
 	if (!state->state_fdt) {
 		size = 0x4000;
-		state->state_fdt = malloc(size);
+		state->state_fdt = os_malloc(size);
 		if (!state->state_fdt) {
 			puts("No memory to create FDT\n");
 			return -ENOMEM;
@@ -302,7 +303,7 @@
 err_write:
 	os_close(fd);
 err_create:
-	free(state->state_fdt);
+	os_free(state->state_fdt);
 
 	return ret;
 }
@@ -398,8 +399,12 @@
 {
 	int err;
 
+	log_info("Writing sandbox state\n");
 	state = &main_state;
 
+	/* Finish the bloblist, so that it is correct before writing memory */
+	bloblist_finish();
+
 	if (state->write_ram_buf) {
 		err = os_write_ram_buf(state->ram_buf_fname);
 		if (err) {
@@ -419,8 +424,8 @@
 	if (state->jumped_fname)
 		os_unlink(state->jumped_fname);
 
-	if (state->state_fdt)
-		free(state->state_fdt);
+	os_free(state->state_fdt);
+	os_free(state->ram_buf);
 	memset(state, '\0', sizeof(*state));
 
 	return 0;
diff --git a/arch/sandbox/include/asm/gpio.h b/arch/sandbox/include/asm/gpio.h
index df4ba4f..9e10052 100644
--- a/arch/sandbox/include/asm/gpio.h
+++ b/arch/sandbox/include/asm/gpio.h
@@ -23,6 +23,15 @@
  */
 #include <asm-generic/gpio.h>
 
+/* Our own private GPIO flags, which musn't conflict with GPIOD_... */
+#define GPIOD_EXT_HIGH		BIT(31)	/* external source is high (else low) */
+#define GPIOD_EXT_DRIVEN	BIT(30)	/* external source is driven */
+#define GPIOD_EXT_PULL_UP	BIT(29)	/* GPIO has external pull-up */
+#define GPIOD_EXT_PULL_DOWN	BIT(28)	/* GPIO has external pull-down */
+
+#define GPIOD_EXT_PULL		(BIT(28) | BIT(29))
+#define GPIOD_SANDBOX_MASK	GENMASK(31, 28)
+
 /**
  * Return the simulated value of a GPIO (used only in sandbox test code)
  *
@@ -69,17 +78,17 @@
  * @param offset	GPIO offset within bank
  * @return dir_flags: bitfield accesses by GPIOD_ defines
  */
-ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset);
+ulong sandbox_gpio_get_flags(struct udevice *dev, unsigned int offset);
 
 /**
  * Set the simulated flags of a GPIO (used only in sandbox test code)
  *
  * @param dev		device to use
  * @param offset	GPIO offset within bank
- * @param flags		dir_flags: bitfield accesses by GPIOD_ defines
+ * @param flags		bitfield accesses by GPIOD_ defines
  * @return -1 on error, 0 if ok
  */
-int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
-			       ulong flags);
+int sandbox_gpio_set_flags(struct udevice *dev, unsigned int offset,
+			   ulong flags);
 
 #endif
diff --git a/arch/sh/cpu/sh4/cpu.c b/arch/sh/cpu/sh4/cpu.c
index 801102f..1b2f50d 100644
--- a/arch/sh/cpu/sh4/cpu.c
+++ b/arch/sh/cpu/sh4/cpu.c
@@ -32,7 +32,7 @@
 int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
 	disable_interrupts();
-	reset_cpu(0);
+	reset_cpu();
 	return 0;
 }
 
diff --git a/arch/sh/cpu/sh4/watchdog.c b/arch/sh/cpu/sh4/watchdog.c
index 1de32cd..bf403d3 100644
--- a/arch/sh/cpu/sh4/watchdog.c
+++ b/arch/sh/cpu/sh4/watchdog.c
@@ -51,7 +51,7 @@
 }
 #endif
 
-void reset_cpu(unsigned long ignored)
+void reset_cpu(void)
 {
 	/* Address error with SR.BL=1 first. */
 	trigger_address_error();
diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c
index bddba3e..a02f4f9 100644
--- a/arch/x86/cpu/ivybridge/cpu.c
+++ b/arch/x86/cpu/ivybridge/cpu.c
@@ -143,7 +143,7 @@
 
 		/* System is not happy after keyboard reset... */
 		debug("Issuing CF9 warm reset\n");
-		reset_cpu(0);
+		reset_cpu();
 	}
 
 	ret = cpu_common_init();
diff --git a/arch/x86/include/asm/intel_pinctrl_defs.h b/arch/x86/include/asm/intel_pinctrl_defs.h
index 1ea141f..5d83d24 100644
--- a/arch/x86/include/asm/intel_pinctrl_defs.h
+++ b/arch/x86/include/asm/intel_pinctrl_defs.h
@@ -11,6 +11,11 @@
 
 /* This file is included by device trees, so avoid BIT() macros */
 
+#define GPIO_DW_SIZE(x)			(sizeof(u32) * (x))
+#define PAD_CFG_OFFSET(x, dw_num)	((x) + GPIO_DW_SIZE(dw_num))
+#define PAD_CFG0_OFFSET(x)		PAD_CFG_OFFSET(x, 0)
+#define PAD_CFG1_OFFSET(x)		PAD_CFG_OFFSET(x, 1)
+
 #define PAD_CFG0_TX_STATE_BIT		0
 #define PAD_CFG0_TX_STATE		(1 << PAD_CFG0_TX_STATE_BIT)
 #define PAD_CFG0_RX_STATE_BIT		1
diff --git a/board/BuR/brppt2/board.c b/board/BuR/brppt2/board.c
index e6eb403..ee006f0 100644
--- a/board/BuR/brppt2/board.c
+++ b/board/BuR/brppt2/board.c
@@ -540,7 +540,7 @@
 	spl_dram_init();
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 #endif /* CONFIG_SPL_BUILD */
diff --git a/board/abilis/tb100/tb100.c b/board/abilis/tb100/tb100.c
index 52dc5b8..89e7322 100644
--- a/board/abilis/tb100/tb100.c
+++ b/board/abilis/tb100/tb100.c
@@ -9,7 +9,7 @@
 #include <netdev.h>
 #include <asm/io.h>
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 #define CRM_SWRESET	0xff101044
 	writel(0x1, (void *)CRM_SWRESET);
diff --git a/board/advantech/imx8qm_rom7720_a1/imx8qm_rom7720_a1.c b/board/advantech/imx8qm_rom7720_a1/imx8qm_rom7720_a1.c
index 8492e76..ace18b2 100644
--- a/board/advantech/imx8qm_rom7720_a1/imx8qm_rom7720_a1.c
+++ b/board/advantech/imx8qm_rom7720_a1/imx8qm_rom7720_a1.c
@@ -115,7 +115,7 @@
 /*
  * Board specific reset that is system reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/* TODO */
 }
diff --git a/board/armltd/total_compute/total_compute.c b/board/armltd/total_compute/total_compute.c
index 01c65e4..b7eaab0 100644
--- a/board/armltd/total_compute/total_compute.c
+++ b/board/armltd/total_compute/total_compute.c
@@ -63,6 +63,6 @@
 }
 
 /* Nothing to be done here as handled by PSCI interface */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/armltd/vexpress/vexpress_common.c b/board/armltd/vexpress/vexpress_common.c
index df4cbd3..ba3278a 100644
--- a/board/armltd/vexpress/vexpress_common.c
+++ b/board/armltd/vexpress/vexpress_common.c
@@ -174,7 +174,7 @@
 }
 
 /* Use the ARM Watchdog System to cause reset */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	if (v2m_cfg_write(SYS_CFG_REBOOT | SYS_CFG_SITE_MB, 0))
 		printf("Unable to reboot\n");
diff --git a/board/armltd/vexpress64/vexpress64.c b/board/armltd/vexpress64/vexpress64.c
index 9d29490..2e42602 100644
--- a/board/armltd/vexpress64/vexpress64.c
+++ b/board/armltd/vexpress64/vexpress64.c
@@ -143,7 +143,7 @@
 #endif
 
 /* Actual reset is done via PSCI. */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/atmark-techno/armadillo-800eva/armadillo-800eva.c b/board/atmark-techno/armadillo-800eva/armadillo-800eva.c
index 1bae283..c1c3dfd 100644
--- a/board/atmark-techno/armadillo-800eva/armadillo-800eva.c
+++ b/board/atmark-techno/armadillo-800eva/armadillo-800eva.c
@@ -322,6 +322,6 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/beacon/beacon-rzg2m/beacon-rzg2m.c b/board/beacon/beacon-rzg2m/beacon-rzg2m.c
index c343de5..0c7f8e5 100644
--- a/board/beacon/beacon-rzg2m/beacon-rzg2m.c
+++ b/board/beacon/beacon-rzg2m/beacon-rzg2m.c
@@ -47,7 +47,7 @@
 #define RST_CA57RESCNT	(RST_BASE + 0x40)
 #define RST_CODE	0xA5A5000F
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	writel(RST_CODE, RST_CA57RESCNT);
 }
diff --git a/board/bosch/shc/board.c b/board/bosch/shc/board.c
index bfce291..e893781 100644
--- a/board/bosch/shc/board.c
+++ b/board/bosch/shc/board.c
@@ -486,7 +486,7 @@
 		printf("Resetting ...\n");
 		writel(RESET_MASK, GPIO1_BASE + OMAP_GPIO_IRQSTATUS_SET_0);
 		disable_interrupts();
-		reset_cpu(0);
+		reset_cpu();
 		/*NOTREACHED*/
 	}
 }
diff --git a/board/broadcom/bcmns2/northstar2.c b/board/broadcom/bcmns2/northstar2.c
index 494e457..ee586d5 100644
--- a/board/broadcom/bcmns2/northstar2.c
+++ b/board/broadcom/bcmns2/northstar2.c
@@ -57,7 +57,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/board/broadcom/bcmns3/ns3.c b/board/broadcom/bcmns3/ns3.c
index 9d2df92..758a358 100644
--- a/board/broadcom/bcmns3/ns3.c
+++ b/board/broadcom/bcmns3/ns3.c
@@ -15,9 +15,6 @@
 #include <dt-bindings/memory/bcm-ns3-mc.h>
 #include <broadcom/chimp.h>
 
-/* Default reset-level = 3 and strap-val = 0 */
-#define L3_RESET	30
-
 #define BANK_OFFSET(bank)      ((u64)BCM_NS3_DDR_INFO_BASE + 8 + ((bank) * 16))
 
 /*
@@ -188,25 +185,10 @@
 	return BCM_NS3_MEM_END;
 }
 
-void reset_cpu(ulong level)
+void reset_cpu(void)
 {
-	u32 reset_level, strap_val;
-
-	/* Default reset type is L3 reset */
-	if (!level) {
-		/*
-		 * Encoding: U-Boot reset command expects decimal argument,
-		 * Boot strap val: Bits[3:0]
-		 * reset level: Bits[7:4]
-		 */
-		strap_val = L3_RESET % 10;
-		level = L3_RESET / 10;
-		reset_level = level % 10;
-		psci_system_reset2(reset_level, strap_val);
-	} else {
-		/* U-Boot cmd "reset" with any arg will trigger L1 reset */
-		psci_system_reset();
-	}
+	/* Perform a level 3 reset */
+	psci_system_reset2(3, 0);
 }
 
 #ifdef CONFIG_OF_BOARD_SETUP
diff --git a/board/broadcom/bcmstb/bcmstb.c b/board/broadcom/bcmstb/bcmstb.c
index f6bdf1f..ee0a341 100644
--- a/board/broadcom/bcmstb/bcmstb.c
+++ b/board/broadcom/bcmstb/bcmstb.c
@@ -43,7 +43,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong ignored)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/cavium/thunderx/thunderx.c b/board/cavium/thunderx/thunderx.c
index b09f72c..a7dc5c6 100644
--- a/board/cavium/thunderx/thunderx.c
+++ b/board/cavium/thunderx/thunderx.c
@@ -110,7 +110,7 @@
 /*
  * Board specific reset that is system reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/compulab/cm_t335/spl.c b/board/compulab/cm_t335/spl.c
index 8662632..33264df 100644
--- a/board/compulab/cm_t335/spl.c
+++ b/board/compulab/cm_t335/spl.c
@@ -96,7 +96,7 @@
 		break;
 	default:
 		puts("Failed configuring DRAM, resetting...\n\n");
-		reset_cpu(0);
+		reset_cpu();
 	}
 	debug("%s: setting DRAM size to %ldM\n", __func__, size >> 20);
 	config_ddr(303, &ioregs, &ddr3_data,
diff --git a/board/cortina/presidio-asic/presidio.c b/board/cortina/presidio-asic/presidio.c
index 5c73522..f344622 100644
--- a/board/cortina/presidio-asic/presidio.c
+++ b/board/cortina/presidio-asic/presidio.c
@@ -115,7 +115,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	invoke_psci_fn_smc(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
 }
diff --git a/board/freescale/imx8qm_mek/imx8qm_mek.c b/board/freescale/imx8qm_mek/imx8qm_mek.c
index c677220..682099a 100644
--- a/board/freescale/imx8qm_mek/imx8qm_mek.c
+++ b/board/freescale/imx8qm_mek/imx8qm_mek.c
@@ -105,7 +105,7 @@
 /*
  * Board specific reset that is system reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/* TODO */
 }
diff --git a/board/freescale/imx8qxp_mek/imx8qxp_mek.c b/board/freescale/imx8qxp_mek/imx8qxp_mek.c
index 7179823..21cfa14 100644
--- a/board/freescale/imx8qxp_mek/imx8qxp_mek.c
+++ b/board/freescale/imx8qxp_mek/imx8qxp_mek.c
@@ -129,7 +129,7 @@
 /*
  * Board specific reset that is system reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/* TODO */
 }
diff --git a/board/freescale/mx6memcal/spl.c b/board/freescale/mx6memcal/spl.c
index c82b532..61d0ca3 100644
--- a/board/freescale/mx6memcal/spl.c
+++ b/board/freescale/mx6memcal/spl.c
@@ -425,7 +425,7 @@
 		    is_cpu_type(MXC_CPU_MX6SL)) {
 			printf("cpu type 0x%x doesn't support 64-bit bus\n",
 			       get_cpu_type());
-			reset_cpu(0);
+			reset_cpu();
 		}
 	}
 #ifdef CONFIG_MX6SL
diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c
index 4f1dc3b..dc424f2 100644
--- a/board/gdsys/a38x/controlcenterdc.c
+++ b/board/gdsys/a38x/controlcenterdc.c
@@ -288,8 +288,8 @@
 	ccdc_eth_init();
 #endif
 	ret = get_tpm(&tpm);
-	if (ret || tpm_init(tpm) || tpm_startup(tpm, TPM_ST_CLEAR) ||
-	    tpm_continue_self_test(tpm)) {
+	if (ret || tpm_init(tpm) || tpm1_startup(tpm, TPM_ST_CLEAR) ||
+	    tpm1_continue_self_test(tpm)) {
 		return 1;
 	}
 
diff --git a/board/gdsys/a38x/hre.c b/board/gdsys/a38x/hre.c
index 699241b..de5411a 100644
--- a/board/gdsys/a38x/hre.c
+++ b/board/gdsys/a38x/hre.c
@@ -107,8 +107,8 @@
 	uint8_t *ptr;
 	uint16_t v16;
 
-	err = tpm_get_capability(tpm, TPM_CAP_NV_INDEX, index,
-				 info, sizeof(info));
+	err = tpm1_get_capability(tpm, TPM_CAP_NV_INDEX, index, info,
+				  sizeof(info));
 	if (err) {
 		printf("tpm_get_capability(CAP_NV_INDEX, %08x) failed: %u\n",
 		       index, err);
@@ -150,8 +150,8 @@
 	unsigned int i;
 
 	/* fetch list of already loaded keys in the TPM */
-	err = tpm_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
-				 sizeof(buf));
+	err = tpm1_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
+				  sizeof(buf));
 	if (err)
 		return -1;
 	key_count = get_unaligned_be16(buf);
@@ -162,8 +162,8 @@
 	/* now search a(/ the) key which we can access with the given auth */
 	for (i = 0; i < key_count; ++i) {
 		buf_len = sizeof(buf);
-		err = tpm_get_pub_key_oiap(tpm, key_handles[i], auth, buf,
-					   &buf_len);
+		err = tpm1_get_pub_key_oiap(tpm, key_handles[i], auth, buf,
+					    &buf_len);
 		if (err && err != TPM_AUTHFAIL)
 			return -1;
 		if (err)
@@ -192,8 +192,8 @@
 	if (get_tpm_nv_size(tpm, NV_COMMON_DATA_INDEX, &size) ||
 	    size < NV_COMMON_DATA_MIN_SIZE)
 		return 1;
-	err = tpm_nv_read_value(tpm, NV_COMMON_DATA_INDEX,
-				buf, min(sizeof(buf), size));
+	err = tpm1_nv_read_value(tpm, NV_COMMON_DATA_INDEX, buf,
+				 min(sizeof(buf), size));
 	if (err) {
 		printf("tpm_nv_read_value() failed: %u\n", err);
 		return 1;
@@ -270,8 +270,8 @@
 	if (mode & HREG_RD) {
 		if (!result->valid) {
 			if (IS_PCR_HREG(spec)) {
-				hre_tpm_err = tpm_pcr_read(tpm, HREG_IDX(spec),
-					result->digest, 20);
+				hre_tpm_err = tpm1_pcr_read(tpm, HREG_IDX(spec),
+							    result->digest, 20);
 				result->valid = (hre_tpm_err == TPM_SUCCESS);
 			} else if (IS_FIX_HREG(spec)) {
 				switch (HREG_IDX(spec)) {
@@ -357,8 +357,8 @@
 		return -1;
 	if (find_key(tpm, src_reg->digest, dst_reg->digest, &parent_handle))
 		return -1;
-	hre_tpm_err = tpm_load_key2_oiap(tpm, parent_handle, key, key_size,
-					 src_reg->digest, &key_handle);
+	hre_tpm_err = tpm1_load_key2_oiap(tpm, parent_handle, key, key_size,
+					  src_reg->digest, &key_handle);
 	if (hre_tpm_err) {
 		hre_err = HRE_E_TPM_FAILURE;
 		return -1;
@@ -474,8 +474,8 @@
 	}
 
 	if (dst_reg && dst_modified && IS_PCR_HREG(dst_spec)) {
-		hre_tpm_err = tpm_extend(tpm, HREG_IDX(dst_spec),
-					 dst_reg->digest, dst_reg->digest);
+		hre_tpm_err = tpm1_extend(tpm, HREG_IDX(dst_spec),
+					  dst_reg->digest, dst_reg->digest);
 		if (hre_tpm_err) {
 			hre_err = HRE_E_TPM_FAILURE;
 			return NULL;
diff --git a/board/gdsys/a38x/keyprogram.c b/board/gdsys/a38x/keyprogram.c
index 853981a..7020fae 100644
--- a/board/gdsys/a38x/keyprogram.c
+++ b/board/gdsys/a38x/keyprogram.c
@@ -23,15 +23,15 @@
 	uint i;
 
 	/* fetch list of already loaded keys in the TPM */
-	err = tpm_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
-				 sizeof(buf));
+	err = tpm1_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
+				  sizeof(buf));
 	if (err)
 		return -1;
 	key_count = get_unaligned_be16(buf);
 	ptr = buf + 2;
 	for (i = 0; i < key_count; ++i, ptr += 4) {
-		err = tpm_flush_specific(tpm, get_unaligned_be32(ptr),
-					 TPM_RT_KEY);
+		err = tpm1_flush_specific(tpm, get_unaligned_be32(ptr),
+					  TPM_RT_KEY);
 		if (err && err != TPM_KEY_OWNER_CONTROL)
 			return err;
 	}
diff --git a/board/gdsys/mpc8308/gazerbeam.c b/board/gdsys/mpc8308/gazerbeam.c
index 4e974c5..3d4a7e5 100644
--- a/board/gdsys/mpc8308/gazerbeam.c
+++ b/board/gdsys/mpc8308/gazerbeam.c
@@ -145,8 +145,8 @@
 	env_set_ulong("fpga_hw_rev", fpga_hw_rev);
 
 	ret = get_tpm(&tpm);
-	if (ret || tpm_init(tpm) || tpm_startup(tpm, TPM_ST_CLEAR) ||
-	    tpm_continue_self_test(tpm)) {
+	if (ret || tpm_init(tpm) || tpm1_startup(tpm, TPM_ST_CLEAR) ||
+	    tpm1_continue_self_test(tpm)) {
 		printf("TPM init failed\n");
 	}
 
diff --git a/board/gdsys/p1022/controlcenterd-id.c b/board/gdsys/p1022/controlcenterd-id.c
index 1b5aa90..87b346a 100644
--- a/board/gdsys/p1022/controlcenterd-id.c
+++ b/board/gdsys/p1022/controlcenterd-id.c
@@ -273,8 +273,8 @@
 	uint8_t *ptr;
 	uint16_t v16;
 
-	err = tpm_get_capability(tpm, TPM_CAP_NV_INDEX, index,
-				 info, sizeof(info));
+	err = tpm1_get_capability(tpm, TPM_CAP_NV_INDEX, index, info,
+				  sizeof(info));
 	if (err) {
 		printf("tpm_get_capability(CAP_NV_INDEX, %08x) failed: %u\n",
 		       index, err);
@@ -315,8 +315,8 @@
 	unsigned int i;
 
 	/* fetch list of already loaded keys in the TPM */
-	err = tpm_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
-				 sizeof(buf));
+	err = tpm1_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
+				  sizeof(buf));
 	if (err)
 		return -1;
 	key_count = get_unaligned_be16(buf);
@@ -327,8 +327,8 @@
 	/* now search a(/ the) key which we can access with the given auth */
 	for (i = 0; i < key_count; ++i) {
 		buf_len = sizeof(buf);
-		err = tpm_get_pub_key_oiap(tpm, key_handles[i], auth, buf,
-					   &buf_len);
+		err = tpm1_get_pub_key_oiap(tpm, key_handles[i], auth, buf,
+					    &buf_len);
 		if (err && err != TPM_AUTHFAIL)
 			return -1;
 		if (err)
@@ -356,8 +356,8 @@
 	if (get_tpm_nv_size(tpm, NV_COMMON_DATA_INDEX, &size) ||
 	    size < NV_COMMON_DATA_MIN_SIZE)
 		return 1;
-	err = tpm_nv_read_value(tpm, NV_COMMON_DATA_INDEX,
-				buf, min(sizeof(buf), size));
+	err = tpm1_nv_read_value(tpm, NV_COMMON_DATA_INDEX, buf,
+				 min(sizeof(buf), size));
 	if (err) {
 		printf("tpm_nv_read_value() failed: %u\n", err);
 		return 1;
@@ -508,8 +508,8 @@
 	if (mode & HREG_RD) {
 		if (!result->valid) {
 			if (IS_PCR_HREG(spec)) {
-				hre_tpm_err = tpm_pcr_read(tpm, HREG_IDX(spec),
-					result->digest, 20);
+				hre_tpm_err = tpm1_pcr_read(tpm, HREG_IDX(spec),
+							    result->digest, 20);
 				result->valid = (hre_tpm_err == TPM_SUCCESS);
 			} else if (IS_FIX_HREG(spec)) {
 				switch (HREG_IDX(spec)) {
@@ -601,8 +601,8 @@
 		return -1;
 	if (find_key(tpm, src_reg->digest, dst_reg->digest, &parent_handle))
 		return -1;
-	hre_tpm_err = tpm_load_key2_oiap(tpm, parent_handle, key, key_size,
-					 src_reg->digest, &key_handle);
+	hre_tpm_err = tpm1_load_key2_oiap(tpm, parent_handle, key, key_size,
+					  src_reg->digest, &key_handle);
 	if (hre_tpm_err) {
 		hre_err = HRE_E_TPM_FAILURE;
 		return -1;
@@ -718,8 +718,8 @@
 	}
 
 	if (dst_reg && dst_modified && IS_PCR_HREG(dst_spec)) {
-		hre_tpm_err = tpm_extend(tpm, HREG_IDX(dst_spec),
-					 dst_reg->digest, dst_reg->digest);
+		hre_tpm_err = tpm1_extend(tpm, HREG_IDX(dst_spec),
+					  dst_reg->digest, dst_reg->digest);
 		if (hre_tpm_err) {
 			hre_err = HRE_E_TPM_FAILURE;
 			return NULL;
@@ -964,10 +964,10 @@
 
 	puts("CCDM S1: start actions\n");
 #ifndef CCDM_SECOND_STAGE
-	if (tpm_continue_self_test(tpm))
+	if (tpm1_continue_self_test(tpm))
 		goto failure;
 #else
-	tpm_continue_self_test(tpm);
+	tpm1_continue_self_test(tpm);
 #endif
 	mdelay(37);
 
@@ -1003,7 +1003,7 @@
 
 	puts("CCDM S1\n");
 	ret = get_tpm(&tpm);
-	if (ret || tpm_init(tpm) || tpm_startup(tpm, TPM_ST_CLEAR))
+	if (ret || tpm_init(tpm) || tpm1_startup(tpm, TPM_ST_CLEAR))
 		return 1;
 	ret = first_stage_actions(tpm);
 #ifndef CCDM_SECOND_STAGE
@@ -1061,7 +1061,7 @@
 	ret = get_tpm(&tpm);
 	if (ret || tpm_init(tpm))
 		return 1;
-	err = tpm_startup(tpm, TPM_ST_CLEAR);
+	err = tpm1_startup(tpm, TPM_ST_CLEAR);
 	if (err != TPM_INVALID_POSTINIT)
 		did_first_stage_run = false;
 
diff --git a/board/ge/b1x5v2/spl.c b/board/ge/b1x5v2/spl.c
index 2e6f905..52c80f7 100644
--- a/board/ge/b1x5v2/spl.c
+++ b/board/ge/b1x5v2/spl.c
@@ -436,7 +436,7 @@
 	return 1024;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/highbank/highbank.c b/board/highbank/highbank.c
index a790d45..906bd9b 100644
--- a/board/highbank/highbank.c
+++ b/board/highbank/highbank.c
@@ -128,7 +128,7 @@
 	return (midr & 0xfff0) == 0xc090;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	writel(HB_PWR_HARD_RESET, HB_SREG_A9_PWR_REQ);
 	if (is_highbank())
diff --git a/board/hisilicon/hikey/hikey.c b/board/hisilicon/hikey/hikey.c
index afe324c..c9a2d60 100644
--- a/board/hisilicon/hikey/hikey.c
+++ b/board/hisilicon/hikey/hikey.c
@@ -486,7 +486,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	writel(0x48698284, &ao_sc->stat0);
 	wfi();
diff --git a/board/hisilicon/hikey960/hikey960.c b/board/hisilicon/hikey960/hikey960.c
index 62073aa..f41fabb 100644
--- a/board/hisilicon/hikey960/hikey960.c
+++ b/board/hisilicon/hikey960/hikey960.c
@@ -185,7 +185,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/board/hisilicon/poplar/poplar.c b/board/hisilicon/poplar/poplar.c
index fda9a34..6cc79d9 100644
--- a/board/hisilicon/poplar/poplar.c
+++ b/board/hisilicon/poplar/poplar.c
@@ -60,7 +60,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/board/kmc/kzm9g/kzm9g.c b/board/kmc/kzm9g/kzm9g.c
index 02c87a0..dccf469 100644
--- a/board/kmc/kzm9g/kzm9g.c
+++ b/board/kmc/kzm9g/kzm9g.c
@@ -366,7 +366,7 @@
 	return ret;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/* Soft Power On Reset */
 	writel((1 << 31), RESCNT2);
diff --git a/board/liebherr/display5/spl.c b/board/liebherr/display5/spl.c
index b8658c8..39f70f5 100644
--- a/board/liebherr/display5/spl.c
+++ b/board/liebherr/display5/spl.c
@@ -376,7 +376,7 @@
 #endif
 }
 
-void reset_cpu(ulong addr) {}
+void reset_cpu(void) {}
 
 #ifdef CONFIG_SPL_LOAD_FIT
 int board_fit_config_name_match(const char *name)
diff --git a/board/phytium/durian/durian.c b/board/phytium/durian/durian.c
index 8a82a45..ef13f7c 100644
--- a/board/phytium/durian/durian.c
+++ b/board/phytium/durian/durian.c
@@ -42,7 +42,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct arm_smccc_res res;
 
diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.c b/board/qualcomm/dragonboard410c/dragonboard410c.c
index 646013c..0d282de 100644
--- a/board/qualcomm/dragonboard410c/dragonboard410c.c
+++ b/board/qualcomm/dragonboard410c/dragonboard410c.c
@@ -203,7 +203,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/board/qualcomm/dragonboard820c/dragonboard820c.c b/board/qualcomm/dragonboard820c/dragonboard820c.c
index 877e34c..4ccb1a0 100644
--- a/board/qualcomm/dragonboard820c/dragonboard820c.c
+++ b/board/qualcomm/dragonboard820c/dragonboard820c.c
@@ -127,7 +127,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	psci_system_reset();
 }
diff --git a/board/renesas/alt/alt.c b/board/renesas/alt/alt.c
index 854c476..3b60afc 100644
--- a/board/renesas/alt/alt.c
+++ b/board/renesas/alt/alt.c
@@ -111,7 +111,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct udevice *dev;
 	const u8 pmic_bus = 7;
diff --git a/board/renesas/alt/alt_spl.c b/board/renesas/alt/alt_spl.c
index 2de236f..cdaa04e 100644
--- a/board/renesas/alt/alt_spl.c
+++ b/board/renesas/alt/alt_spl.c
@@ -408,6 +408,6 @@
 	spl_boot_list[2] = BOOT_DEVICE_NONE;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/renesas/blanche/blanche.c b/board/renesas/blanche/blanche.c
index 9671382..a365269 100644
--- a/board/renesas/blanche/blanche.c
+++ b/board/renesas/blanche/blanche.c
@@ -360,7 +360,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct udevice *dev;
 	const u8 pmic_bus = 6;
diff --git a/board/renesas/condor/condor.c b/board/renesas/condor/condor.c
index 4454061..e930de3 100644
--- a/board/renesas/condor/condor.c
+++ b/board/renesas/condor/condor.c
@@ -34,7 +34,7 @@
 #define RST_CA57_CODE	0xA5A5000F
 #define RST_CA53_CODE	0x5A5A000F
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	unsigned long midr, cputype;
 
diff --git a/board/renesas/draak/draak.c b/board/renesas/draak/draak.c
index ffd52eb..1d76f95 100644
--- a/board/renesas/draak/draak.c
+++ b/board/renesas/draak/draak.c
@@ -75,7 +75,7 @@
 #define RST_CA53RESCNT	(RST_BASE + 0x44)
 #define RST_CA53_CODE	0x5A5A000F
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	writel(RST_CA53_CODE, RST_CA53RESCNT);
 }
diff --git a/board/renesas/eagle/eagle.c b/board/renesas/eagle/eagle.c
index f9e553f..bb32e3d 100644
--- a/board/renesas/eagle/eagle.c
+++ b/board/renesas/eagle/eagle.c
@@ -78,7 +78,7 @@
 #define RST_CA57_CODE	0xA5A5000F
 #define RST_CA53_CODE	0x5A5A000F
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	unsigned long midr, cputype;
 
diff --git a/board/renesas/ebisu/ebisu.c b/board/renesas/ebisu/ebisu.c
index 82cd2a5..9d4af8d 100644
--- a/board/renesas/ebisu/ebisu.c
+++ b/board/renesas/ebisu/ebisu.c
@@ -42,7 +42,7 @@
 #define RST_CA53RESCNT	(RST_BASE + 0x44)
 #define RST_CA53_CODE	0x5A5A000F
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	writel(RST_CA53_CODE, RST_CA53RESCNT);
 }
diff --git a/board/renesas/gose/gose.c b/board/renesas/gose/gose.c
index 56cdc73..51768c3 100644
--- a/board/renesas/gose/gose.c
+++ b/board/renesas/gose/gose.c
@@ -117,7 +117,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct udevice *dev;
 	const u8 pmic_bus = 6;
diff --git a/board/renesas/gose/gose_spl.c b/board/renesas/gose/gose_spl.c
index 624ba5d..c0bf720 100644
--- a/board/renesas/gose/gose_spl.c
+++ b/board/renesas/gose/gose_spl.c
@@ -405,6 +405,6 @@
 	spl_boot_list[2] = BOOT_DEVICE_NONE;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/renesas/grpeach/grpeach.c b/board/renesas/grpeach/grpeach.c
index ac989eb..199ec4a 100644
--- a/board/renesas/grpeach/grpeach.c
+++ b/board/renesas/grpeach/grpeach.c
@@ -40,7 +40,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/* Dummy read (must read WRCSR:WOVF at least once before clearing) */
 	readb(RZA1_WDT_BASE + WRCSR);
diff --git a/board/renesas/koelsch/koelsch.c b/board/renesas/koelsch/koelsch.c
index b0a66ea..7e94bd8 100644
--- a/board/renesas/koelsch/koelsch.c
+++ b/board/renesas/koelsch/koelsch.c
@@ -119,7 +119,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct udevice *dev;
 	const u8 pmic_bus = 6;
diff --git a/board/renesas/koelsch/koelsch_spl.c b/board/renesas/koelsch/koelsch_spl.c
index 449bbfa..b377f70 100644
--- a/board/renesas/koelsch/koelsch_spl.c
+++ b/board/renesas/koelsch/koelsch_spl.c
@@ -407,6 +407,6 @@
 	spl_boot_list[2] = BOOT_DEVICE_NONE;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/renesas/lager/lager.c b/board/renesas/lager/lager.c
index add4eef..87c5e01 100644
--- a/board/renesas/lager/lager.c
+++ b/board/renesas/lager/lager.c
@@ -128,7 +128,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct udevice *dev;
 	const u8 pmic_bus = 2;
diff --git a/board/renesas/lager/lager_spl.c b/board/renesas/lager/lager_spl.c
index 1ca857c..d3d397e 100644
--- a/board/renesas/lager/lager_spl.c
+++ b/board/renesas/lager/lager_spl.c
@@ -393,6 +393,6 @@
 	spl_boot_list[2] = BOOT_DEVICE_NONE;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/renesas/porter/porter.c b/board/renesas/porter/porter.c
index b3e4c08..b0f8505 100644
--- a/board/renesas/porter/porter.c
+++ b/board/renesas/porter/porter.c
@@ -117,7 +117,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct udevice *dev;
 	const u8 pmic_bus = 6;
diff --git a/board/renesas/porter/porter_spl.c b/board/renesas/porter/porter_spl.c
index f10c6cf..8595770 100644
--- a/board/renesas/porter/porter_spl.c
+++ b/board/renesas/porter/porter_spl.c
@@ -488,6 +488,6 @@
 	spl_boot_list[2] = BOOT_DEVICE_NONE;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/renesas/rcar-common/gen3-spl.c b/board/renesas/rcar-common/gen3-spl.c
index fd6e505..b02a946 100644
--- a/board/renesas/rcar-common/gen3-spl.c
+++ b/board/renesas/rcar-common/gen3-spl.c
@@ -55,6 +55,6 @@
 {
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/renesas/salvator-x/salvator-x.c b/board/renesas/salvator-x/salvator-x.c
index 08ed725..071076a 100644
--- a/board/renesas/salvator-x/salvator-x.c
+++ b/board/renesas/salvator-x/salvator-x.c
@@ -76,7 +76,7 @@
 #define RST_RSTOUTCR	(RST_BASE + 0x58)
 #define RST_CODE	0xA5A5000F
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 #if defined(CONFIG_SYS_I2C) && defined(CONFIG_SYS_I2C_SH)
 	i2c_reg_write(CONFIG_SYS_I2C_POWERIC_ADDR, 0x20, 0x80);
diff --git a/board/renesas/silk/silk.c b/board/renesas/silk/silk.c
index 05af5f4..4558070 100644
--- a/board/renesas/silk/silk.c
+++ b/board/renesas/silk/silk.c
@@ -112,7 +112,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct udevice *dev;
 	const u8 pmic_bus = 1;
diff --git a/board/renesas/silk/silk_spl.c b/board/renesas/silk/silk_spl.c
index f10f84a..afb9f85 100644
--- a/board/renesas/silk/silk_spl.c
+++ b/board/renesas/silk/silk_spl.c
@@ -422,6 +422,6 @@
 	spl_boot_list[2] = BOOT_DEVICE_NONE;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/renesas/stout/cpld.c b/board/renesas/stout/cpld.c
index b56ed17..ac8048c 100644
--- a/board/renesas/stout/cpld.c
+++ b/board/renesas/stout/cpld.c
@@ -163,7 +163,7 @@
 	"cpld write addr val\n"
 );
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	cpld_write(CPLD_ADDR_RESET, 1);
 }
diff --git a/board/renesas/stout/stout_spl.c b/board/renesas/stout/stout_spl.c
index 57c1fab..c37c055 100644
--- a/board/renesas/stout/stout_spl.c
+++ b/board/renesas/stout/stout_spl.c
@@ -474,6 +474,6 @@
 	spl_boot_list[2] = BOOT_DEVICE_NONE;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/siemens/capricorn/board.c b/board/siemens/capricorn/board.c
index 56973a1..dcbab8e 100644
--- a/board/siemens/capricorn/board.c
+++ b/board/siemens/capricorn/board.c
@@ -232,7 +232,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/synopsys/emsdp/emsdp.c b/board/synopsys/emsdp/emsdp.c
index 997120e..a3cee23 100644
--- a/board/synopsys/emsdp/emsdp.c
+++ b/board/synopsys/emsdp/emsdp.c
@@ -98,7 +98,7 @@
 /* Bits in CREG_BOOT register */
 #define CREG_BOOT_WP_BIT	BIT(8)
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	writel(1, CREG_IP_SW_RESET);
 	while (1)
diff --git a/board/synopsys/iot_devkit/iot_devkit.c b/board/synopsys/iot_devkit/iot_devkit.c
index c605136..650958f 100644
--- a/board/synopsys/iot_devkit/iot_devkit.c
+++ b/board/synopsys/iot_devkit/iot_devkit.c
@@ -151,7 +151,7 @@
 
 #define IOTDK_RESET_SEQ		0x55AA6699
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	writel(IOTDK_RESET_SEQ, RESET_REG);
 }
diff --git a/board/technexion/pico-imx6ul/spl.c b/board/technexion/pico-imx6ul/spl.c
index 3807779..251f5a1 100644
--- a/board/technexion/pico-imx6ul/spl.c
+++ b/board/technexion/pico-imx6ul/spl.c
@@ -147,7 +147,7 @@
 	board_init_r(NULL, 0);
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/technexion/pico-imx7d/spl.c b/board/technexion/pico-imx7d/spl.c
index bed0f21..df5f058 100644
--- a/board/technexion/pico-imx7d/spl.c
+++ b/board/technexion/pico-imx7d/spl.c
@@ -127,7 +127,7 @@
 	board_init_r(NULL, 0);
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/toradex/apalis-imx8/apalis-imx8.c b/board/toradex/apalis-imx8/apalis-imx8.c
index 76faa6e..04877fc 100644
--- a/board/toradex/apalis-imx8/apalis-imx8.c
+++ b/board/toradex/apalis-imx8/apalis-imx8.c
@@ -117,7 +117,7 @@
 /*
  * Board specific reset that is system reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/* TODO */
 }
diff --git a/board/toradex/apalis-imx8x/apalis-imx8x.c b/board/toradex/apalis-imx8x/apalis-imx8x.c
index b6f3bdd..ac3bac6 100644
--- a/board/toradex/apalis-imx8x/apalis-imx8x.c
+++ b/board/toradex/apalis-imx8x/apalis-imx8x.c
@@ -127,7 +127,7 @@
 /*
  * Board specific reset that is system reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/* TODO */
 }
diff --git a/board/toradex/apalis_imx6/apalis_imx6.c b/board/toradex/apalis_imx6/apalis_imx6.c
index 0c857b5..74060da 100644
--- a/board/toradex/apalis_imx6/apalis_imx6.c
+++ b/board/toradex/apalis_imx6/apalis_imx6.c
@@ -1139,7 +1139,7 @@
 }
 #endif
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/toradex/colibri-imx8x/colibri-imx8x.c b/board/toradex/colibri-imx8x/colibri-imx8x.c
index 562199a..169d4d0 100644
--- a/board/toradex/colibri-imx8x/colibri-imx8x.c
+++ b/board/toradex/colibri-imx8x/colibri-imx8x.c
@@ -129,7 +129,7 @@
 /*
  * Board specific reset that is system reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	/* TODO */
 }
diff --git a/board/toradex/colibri_imx6/colibri_imx6.c b/board/toradex/colibri_imx6/colibri_imx6.c
index 74d59e5..c0e7754 100644
--- a/board/toradex/colibri_imx6/colibri_imx6.c
+++ b/board/toradex/colibri_imx6/colibri_imx6.c
@@ -1081,7 +1081,7 @@
 	board_init_r(NULL, 0);
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/toradex/colibri_imx7/colibri_imx7.c b/board/toradex/colibri_imx7/colibri_imx7.c
index 8f7ef99..301b07d 100644
--- a/board/toradex/colibri_imx7/colibri_imx7.c
+++ b/board/toradex/colibri_imx7/colibri_imx7.c
@@ -237,7 +237,7 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct udevice *dev;
 
diff --git a/board/xen/xenguest_arm64/xenguest_arm64.c b/board/xen/xenguest_arm64/xenguest_arm64.c
index 7d0d782..21363d8 100644
--- a/board/xen/xenguest_arm64/xenguest_arm64.c
+++ b/board/xen/xenguest_arm64/xenguest_arm64.c
@@ -171,7 +171,7 @@
 /*
  * Board specific reset that is system reset.
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c
index c644fe8..e2f9d13 100644
--- a/board/xilinx/versal/board.c
+++ b/board/xilinx/versal/board.c
@@ -242,6 +242,6 @@
 	return 0;
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c
index 4466717..23c12f4 100644
--- a/board/xilinx/zynqmp/zynqmp.c
+++ b/board/xilinx/zynqmp/zynqmp.c
@@ -436,7 +436,7 @@
 }
 #endif
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 }
 
diff --git a/cmd/Kconfig b/cmd/Kconfig
index eff238c..e4bb1d4 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -2030,12 +2030,19 @@
 	help
 	  Add -v option to verify data against a hash.
 
+config CMD_SCP03
+	bool "scp03 - SCP03 enable and rotate/provision operations"
+	depends on SCP03
+	help
+	  This command provides access to a Trusted Application
+	  running in a TEE to request Secure Channel Protocol 03
+	  (SCP03) enablement and/or rotation of its SCP03 keys.
+
 config CMD_TPM_V1
 	bool
 
 config CMD_TPM_V2
 	bool
-	select CMD_LOG
 
 config CMD_TPM
 	bool "Enable the 'tpm' command"
diff --git a/cmd/Makefile b/cmd/Makefile
index 567e2b7..e606ac4 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -194,6 +194,9 @@
 # Android Verified Boot 2.0
 obj-$(CONFIG_CMD_AVB) += avb.o
 
+# Foundries.IO SCP03
+obj-$(CONFIG_CMD_SCP03) += scp03.o
+
 obj-$(CONFIG_ARM) += arm/
 obj-$(CONFIG_RISCV) += riscv/
 obj-$(CONFIG_SANDBOX) += sandbox/
diff --git a/cmd/scp03.c b/cmd/scp03.c
new file mode 100644
index 0000000..655e0bb
--- /dev/null
+++ b/cmd/scp03.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2021, Foundries.IO
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <env.h>
+#include <scp03.h>
+
+int do_scp03_enable(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[])
+{
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	if (tee_enable_scp03()) {
+		printf("TEE failed to enable SCP03\n");
+		return CMD_RET_FAILURE;
+	}
+
+	printf("SCP03 is enabled\n");
+
+	return CMD_RET_SUCCESS;
+}
+
+int do_scp03_provision(struct cmd_tbl *cmdtp, int flag, int argc,
+		       char *const argv[])
+{
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	if (tee_provision_scp03()) {
+		printf("TEE failed to provision SCP03 keys\n");
+		return CMD_RET_FAILURE;
+	}
+
+	printf("SCP03 is provisioned\n");
+
+	return CMD_RET_SUCCESS;
+}
+
+static char text[] =
+	"provides a command to enable SCP03 and provision the SCP03 keys\n"
+	" enable    - enable SCP03 on the TEE\n"
+	" provision - provision SCP03 on the TEE\n";
+
+U_BOOT_CMD_WITH_SUBCMDS(scp03, "Secure Channel Protocol 03 control", text,
+	U_BOOT_SUBCMD_MKENT(enable, 1, 1, do_scp03_enable),
+	U_BOOT_SUBCMD_MKENT(provision, 1, 1, do_scp03_provision));
+
diff --git a/cmd/tpm-v1.c b/cmd/tpm-v1.c
index 0e2168a..3a7e35d 100644
--- a/cmd/tpm-v1.c
+++ b/cmd/tpm-v1.c
@@ -11,6 +11,7 @@
 #include <tpm-common.h>
 #include <tpm-v1.h>
 #include "tpm-user-utils.h"
+#include <tpm_api.h>
 
 static int do_tpm_startup(struct cmd_tbl *cmdtp, int flag, int argc,
 			  char *const argv[])
@@ -55,7 +56,7 @@
 	perm = simple_strtoul(argv[2], NULL, 0);
 	size = simple_strtoul(argv[3], NULL, 0);
 
-	return report_return_code(tpm_nv_define_space(dev, index, perm, size));
+	return report_return_code(tpm1_nv_define_space(dev, index, perm, size));
 }
 
 static int do_tpm_nv_read_value(struct cmd_tbl *cmdtp, int flag, int argc,
@@ -130,7 +131,7 @@
 		return CMD_RET_FAILURE;
 	}
 
-	rc = tpm_extend(dev, index, in_digest, out_digest);
+	rc = tpm_pcr_extend(dev, index, in_digest, out_digest);
 	if (!rc) {
 		puts("PCR value after execution of the command:\n");
 		print_byte_string(out_digest, sizeof(out_digest));
@@ -304,7 +305,7 @@
 	index = simple_strtoul(argv[2], NULL, 0);
 	perm = simple_strtoul(argv[3], NULL, 0);
 
-	return report_return_code(tpm_nv_define_space(dev, index, perm, size));
+	return report_return_code(tpm1_nv_define_space(dev, index, perm, size));
 }
 
 static int do_tpm_nv_read(struct cmd_tbl *cmdtp, int flag, int argc,
@@ -389,7 +390,7 @@
 	if (rc)
 		return rc;
 
-	err = tpm_oiap(dev, &auth_handle);
+	err = tpm1_oiap(dev, &auth_handle);
 
 	return report_return_code(err);
 }
@@ -461,8 +462,8 @@
 		return CMD_RET_FAILURE;
 	parse_byte_string(argv[4], usage_auth, NULL);
 
-	err = tpm_load_key2_oiap(dev, parent_handle, key, key_len, usage_auth,
-				 &key_handle);
+	err = tpm1_load_key2_oiap(dev, parent_handle, key, key_len, usage_auth,
+				  &key_handle);
 	if (!err)
 		printf("Key handle is 0x%x\n", key_handle);
 
@@ -491,8 +492,8 @@
 		return CMD_RET_FAILURE;
 	parse_byte_string(argv[2], usage_auth, NULL);
 
-	err = tpm_get_pub_key_oiap(dev, key_handle, usage_auth, pub_key_buffer,
-				   &pub_key_len);
+	err = tpm1_get_pub_key_oiap(dev, key_handle, usage_auth, pub_key_buffer,
+				    &pub_key_len);
 	if (!err) {
 		printf("dump of received pub key structure:\n");
 		print_byte_string(pub_key_buffer, pub_key_len);
@@ -500,7 +501,7 @@
 	return report_return_code(err);
 }
 
-TPM_COMMAND_NO_ARG(tpm_end_oiap)
+TPM_COMMAND_NO_ARG(tpm1_end_oiap)
 
 #endif /* CONFIG_TPM_AUTH_SESSIONS */
 
@@ -562,7 +563,7 @@
 		res_count = get_unaligned_be16(buf);
 		ptr = buf + 2;
 		for (i = 0; i < res_count; ++i, ptr += 4)
-			tpm_flush_specific(dev, get_unaligned_be32(ptr), type);
+			tpm1_flush_specific(dev, get_unaligned_be32(ptr), type);
 	} else {
 		u32 handle = simple_strtoul(argv[2], NULL, 0);
 
@@ -570,7 +571,7 @@
 			printf("Illegal resource handle %s\n", argv[2]);
 			return -1;
 		}
-		tpm_flush_specific(dev, cpu_to_be32(handle), type);
+		tpm1_flush_specific(dev, cpu_to_be32(handle), type);
 	}
 
 	return 0;
@@ -691,7 +692,7 @@
 	U_BOOT_CMD_MKENT(oiap, 0, 1,
 			 do_tpm_oiap, "", ""),
 	U_BOOT_CMD_MKENT(end_oiap, 0, 1,
-			 do_tpm_end_oiap, "", ""),
+			 do_tpm1_end_oiap, "", ""),
 	U_BOOT_CMD_MKENT(load_key2_oiap, 0, 1,
 			 do_tpm_load_key2_oiap, "", ""),
 #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c
index ebfb25c..a3ccb12 100644
--- a/cmd/tpm_test.c
+++ b/cmd/tpm_test.c
@@ -9,6 +9,7 @@
 #include <log.h>
 #include <tpm-v1.h>
 #include "tpm-user-utils.h"
+#include <tpm_api.h>
 
 /* Prints error and returns on failure */
 #define TPM_CHECK(tpm_command) do { \
@@ -49,7 +50,7 @@
 	struct tpm_permanent_flags pflags;
 	uint32_t result;
 
-	result = tpm_get_permanent_flags(dev, &pflags);
+	result = tpm1_get_permanent_flags(dev, &pflags);
 	if (result)
 		return result;
 	if (disable)
@@ -90,7 +91,7 @@
 	tpm_init(dev);
 	TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR));
 	TPM_CHECK(tpm_continue_self_test(dev));
-	TPM_CHECK(tpm_extend(dev, 1, value_in, value_out));
+	TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, value_out));
 	printf("done\n");
 	return 0;
 }
@@ -146,7 +147,7 @@
 
 #define reboot() do { \
 	printf("\trebooting...\n"); \
-	reset_cpu(0); \
+	reset_cpu(); \
 } while (0)
 
 static int test_fast_enable(struct udevice *dev)
@@ -238,18 +239,18 @@
 	uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE;
 
 	printf("\tInitialising spaces\n");
-	tpm_nv_set_locked(dev);  /* useful only the first time */
-	tpm_nv_define_space(dev, INDEX0, perm, 4);
+	tpm1_nv_set_locked(dev);  /* useful only the first time */
+	tpm1_nv_define_space(dev, INDEX0, perm, 4);
 	tpm_nv_write_value(dev, INDEX0, (uint8_t *)&zero, 4);
-	tpm_nv_define_space(dev, INDEX1, perm, 4);
+	tpm1_nv_define_space(dev, INDEX1, perm, 4);
 	tpm_nv_write_value(dev, INDEX1, (uint8_t *)&zero, 4);
-	tpm_nv_define_space(dev, INDEX2, perm, 4);
+	tpm1_nv_define_space(dev, INDEX2, perm, 4);
 	tpm_nv_write_value(dev, INDEX2, (uint8_t *)&zero, 4);
-	tpm_nv_define_space(dev, INDEX3, perm, 4);
+	tpm1_nv_define_space(dev, INDEX3, perm, 4);
 	tpm_nv_write_value(dev, INDEX3, (uint8_t *)&zero, 4);
 	perm = TPM_NV_PER_READ_STCLEAR | TPM_NV_PER_WRITE_STCLEAR |
 		TPM_NV_PER_PPWRITE;
-	tpm_nv_define_space(dev, INDEX_INITIALISED, perm, 1);
+	tpm1_nv_define_space(dev, INDEX_INITIALISED, perm, 1);
 }
 
 static int test_readonly(struct udevice *dev)
@@ -325,30 +326,33 @@
 
 	/* Redefines spaces a couple of times. */
 	perm = TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK;
-	TPM_CHECK(tpm_nv_define_space(dev, INDEX0, perm, 2 * sizeof(uint32_t)));
-	TPM_CHECK(tpm_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t)));
+	TPM_CHECK(tpm1_nv_define_space(dev, INDEX0, perm,
+				       2 * sizeof(uint32_t)));
+	TPM_CHECK(tpm1_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t)));
 	perm = TPM_NV_PER_PPWRITE;
-	TPM_CHECK(tpm_nv_define_space(dev, INDEX1, perm, 2 * sizeof(uint32_t)));
-	TPM_CHECK(tpm_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t)));
+	TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm,
+				       2 * sizeof(uint32_t)));
+	TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t)));
 
 	/* Sets the global lock */
 	tpm_set_global_lock(dev);
 
 	/* Verifies that index0 cannot be redefined */
-	result = tpm_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t));
+	result = tpm1_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t));
 	assert(result == TPM_AREA_LOCKED);
 
 	/* Checks that index1 can */
-	TPM_CHECK(tpm_nv_define_space(dev, INDEX1, perm, 2 * sizeof(uint32_t)));
-	TPM_CHECK(tpm_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t)));
+	TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm,
+				       2 * sizeof(uint32_t)));
+	TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t)));
 
 	/* Turns off PP */
 	tpm_tsc_physical_presence(dev, PHYS_PRESENCE);
 
 	/* Verifies that neither index0 nor index1 can be redefined */
-	result = tpm_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t));
+	result = tpm1_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t));
 	assert(result == TPM_BAD_PRESENCE);
-	result = tpm_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t));
+	result = tpm1_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t));
 	assert(result == TPM_BAD_PRESENCE);
 
 	printf("done\n");
@@ -434,7 +438,7 @@
 		   100);
 	TTPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)),
 		   100);
-	TTPM_CHECK(tpm_extend(dev, 0, in, out), 200);
+	TTPM_CHECK(tpm_pcr_extend(dev, 0, in, out), 200);
 	TTPM_CHECK(tpm_set_global_lock(dev), 50);
 	TTPM_CHECK(tpm_tsc_physical_presence(dev, PHYS_PRESENCE), 100);
 	printf("done\n");
diff --git a/common/Kconfig b/common/Kconfig
index 2bb3798..482f123 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -588,6 +588,14 @@
 
 endif # AVB_VERIFY
 
+config SCP03
+	bool "Build SCP03 - Secure Channel Protocol O3 - controls"
+	depends on OPTEE || SANDBOX
+	depends on TEE
+	help
+	  This option allows U-Boot to enable and or provision SCP03 on an OPTEE
+	  controlled Secured Element.
+
 config SPL_HASH
 	bool # "Support hashing API (SHA1, SHA256, etc.)"
 	help
diff --git a/common/Makefile b/common/Makefile
index daeea67..215b8b2 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -137,3 +137,4 @@
 obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o
 
 obj-$(CONFIG_AVB_VERIFY) += avb_verify.o
+obj-$(CONFIG_SCP03) += scp03.o
diff --git a/common/bootm.c b/common/bootm.c
index defaed8..dab7c36 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -586,7 +586,7 @@
 	if (IS_ENABLED(CONFIG_BOOTARGS_SUBST) && (flags & BOOTM_CL_SUBST)) {
 		ret = process_subst(buf, maxlen);
 		if (ret)
-			return log_msg_ret("silent", ret);
+			return log_msg_ret("subst", ret);
 	}
 
 	return 0;
diff --git a/common/log.c b/common/log.c
index 6b0034c..ea407c6 100644
--- a/common/log.c
+++ b/common/log.c
@@ -153,7 +153,7 @@
 {
 	struct log_filter *filt;
 
-	if (rec->force_debug)
+	if (rec->flags & LOGRECF_FORCE_DEBUG)
 		return true;
 
 	/* If there are no filters, filter on the default log level */
@@ -218,8 +218,11 @@
 		if ((ldev->flags & LOGDF_ENABLE) &&
 		    log_passes_filters(ldev, rec)) {
 			if (!rec->msg) {
-				vsnprintf(buf, sizeof(buf), fmt, args);
+				int len;
+
+				len = vsnprintf(buf, sizeof(buf), fmt, args);
 				rec->msg = buf;
+				gd->log_cont = len && buf[len - 1] != '\n';
 			}
 			ldev->drv->emit(ldev, rec);
 		}
@@ -245,7 +248,11 @@
 
 	rec.cat = cat;
 	rec.level = level & LOGL_LEVEL_MASK;
-	rec.force_debug = level & LOGL_FORCE_DEBUG;
+	rec.flags = 0;
+	if (level & LOGL_FORCE_DEBUG)
+		rec.flags |= LOGRECF_FORCE_DEBUG;
+	if (gd->log_cont)
+		rec.flags |= LOGRECF_CONT;
 	rec.file = file;
 	rec.line = line;
 	rec.func = func;
@@ -255,7 +262,8 @@
 		gd->log_drop_count++;
 
 		/* display dropped traces with console puts and DEBUG_UART */
-		if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL || rec.force_debug) {
+		if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL ||
+		    rec.flags & LOGRECF_FORCE_DEBUG) {
 			char buf[CONFIG_SYS_CBSIZE];
 
 			va_start(args, fmt);
diff --git a/common/log_console.c b/common/log_console.c
index 6abb13c..3f61774 100644
--- a/common/log_console.c
+++ b/common/log_console.c
@@ -15,6 +15,7 @@
 static int log_console_emit(struct log_device *ldev, struct log_rec *rec)
 {
 	int fmt = gd->log_fmt;
+	bool add_space = false;
 
 	/*
 	 * The output format is designed to give someone a fighting chance of
@@ -26,18 +27,21 @@
 	 *    - function is an identifier and ends with ()
 	 *    - message has a space before it unless it is on its own
 	 */
-	if (fmt & BIT(LOGF_LEVEL))
-		printf("%s.", log_get_level_name(rec->level));
-	if (fmt & BIT(LOGF_CAT))
-		printf("%s,", log_get_cat_name(rec->cat));
-	if (fmt & BIT(LOGF_FILE))
-		printf("%s:", rec->file);
-	if (fmt & BIT(LOGF_LINE))
-		printf("%d-", rec->line);
-	if (fmt & BIT(LOGF_FUNC))
-		printf("%s()", rec->func);
+	if (!(rec->flags & LOGRECF_CONT) && fmt != BIT(LOGF_MSG)) {
+		add_space = true;
+		if (fmt & BIT(LOGF_LEVEL))
+			printf("%s.", log_get_level_name(rec->level));
+		if (fmt & BIT(LOGF_CAT))
+			printf("%s,", log_get_cat_name(rec->cat));
+		if (fmt & BIT(LOGF_FILE))
+			printf("%s:", rec->file);
+		if (fmt & BIT(LOGF_LINE))
+			printf("%d-", rec->line);
+		if (fmt & BIT(LOGF_FUNC))
+			printf("%s()", rec->func);
+	}
 	if (fmt & BIT(LOGF_MSG))
-		printf("%s%s", fmt != BIT(LOGF_MSG) ? " " : "", rec->msg);
+		printf("%s%s", add_space ? " " : "", rec->msg);
 
 	return 0;
 }
diff --git a/common/scp03.c b/common/scp03.c
new file mode 100644
index 0000000..09ef7b5
--- /dev/null
+++ b/common/scp03.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2021, Foundries.IO
+ *
+ */
+
+#include <common.h>
+#include <scp03.h>
+#include <tee.h>
+#include <tee/optee_ta_scp03.h>
+
+static int scp03_enable(bool provision)
+{
+	const struct tee_optee_ta_uuid uuid = PTA_SCP03_UUID;
+	struct tee_open_session_arg session;
+	struct tee_invoke_arg invoke;
+	struct tee_param param;
+	struct udevice *tee = NULL;
+
+	tee = tee_find_device(tee, NULL, NULL, NULL);
+	if (!tee)
+		return -ENODEV;
+
+	memset(&session, 0, sizeof(session));
+	tee_optee_ta_uuid_to_octets(session.uuid, &uuid);
+	if (tee_open_session(tee, &session, 0, NULL))
+		return -ENXIO;
+
+	memset(&param, 0, sizeof(param));
+	param.attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
+	param.u.value.a = provision;
+
+	memset(&invoke, 0, sizeof(invoke));
+	invoke.func = PTA_CMD_ENABLE_SCP03;
+	invoke.session = session.session;
+
+	if (tee_invoke_func(tee, &invoke, 1, &param))
+		return -EIO;
+
+	tee_close_session(tee, session.session);
+
+	return 0;
+}
+
+int tee_enable_scp03(void)
+{
+	return scp03_enable(false);
+}
+
+int tee_provision_scp03(void)
+{
+	return scp03_enable(true);
+}
diff --git a/common/spl/spl.c b/common/spl/spl.c
index e3d8408..5f51098 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -16,6 +16,7 @@
 #include <init.h>
 #include <irq_func.h>
 #include <log.h>
+#include <mapmem.h>
 #include <serial.h>
 #include <spl.h>
 #include <asm/global_data.h>
@@ -168,7 +169,7 @@
 
 __weak struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
 {
-	return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset);
+	return map_sysmem(CONFIG_SYS_TEXT_BASE + offset, 0);
 }
 
 void spl_set_header_raw_uboot(struct spl_image_info *spl_image)
@@ -694,7 +695,7 @@
 #endif
 	switch (spl_image.os) {
 	case IH_OS_U_BOOT:
-		debug("Jumping to U-Boot\n");
+		debug("Jumping to %s...\n", spl_phase_name(spl_next_phase()));
 		break;
 #if CONFIG_IS_ENABLED(ATF)
 	case IH_OS_ARM_TRUSTED_FIRMWARE:
@@ -741,7 +742,6 @@
 		debug("Failed to stash bootstage: err=%d\n", ret);
 #endif
 
-	debug("loaded - jumping to %s...\n", spl_phase_name(spl_next_phase()));
 	spl_board_prepare_for_boot();
 	jump_to_image_no_args(&spl_image);
 }
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 75c8ff0..49508fc 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -11,6 +11,7 @@
 #include <image.h>
 #include <log.h>
 #include <malloc.h>
+#include <mapmem.h>
 #include <spl.h>
 #include <sysinfo.h>
 #include <asm/cache.h>
@@ -235,11 +236,11 @@
 	size_t length;
 	int len;
 	ulong size;
-	ulong load_addr, load_ptr;
+	ulong load_addr;
+	void *load_ptr;
 	void *src;
 	ulong overhead;
 	int nr_sectors;
-	int align_len = ARCH_DMA_MINALIGN - 1;
 	uint8_t image_comp = -1, type = -1;
 	const void *data;
 	const void *fit = ctx->fit;
@@ -269,11 +270,13 @@
 	}
 
 	if (external_data) {
+		void *src_ptr;
+
 		/* External data */
 		if (fit_image_get_data_size(fit, node, &len))
 			return -ENOENT;
 
-		load_ptr = (load_addr + align_len) & ~align_len;
+		src_ptr = map_sysmem(ALIGN(load_addr, ARCH_DMA_MINALIGN), len);
 		length = len;
 
 		overhead = get_aligned_image_overhead(info, offset);
@@ -281,12 +284,12 @@
 
 		if (info->read(info,
 			       sector + get_aligned_image_offset(info, offset),
-			       nr_sectors, (void *)load_ptr) != nr_sectors)
+			       nr_sectors, src_ptr) != nr_sectors)
 			return -EIO;
 
-		debug("External data: dst=%lx, offset=%x, size=%lx\n",
-		      load_ptr, offset, (unsigned long)length);
-		src = (void *)load_ptr + overhead;
+		debug("External data: dst=%p, offset=%x, size=%lx\n",
+		      src_ptr, offset, (unsigned long)length);
+		src = src_ptr + overhead;
 	} else {
 		/* Embedded data */
 		if (fit_image_get_data(fit, node, &data, &length)) {
@@ -295,7 +298,7 @@
 		}
 		debug("Embedded data: dst=%lx, size=%lx\n", load_addr,
 		      (unsigned long)length);
-		src = (void *)data;
+		src = (void *)data;	/* cast away const */
 	}
 
 	if (CONFIG_IS_ENABLED(FIT_SIGNATURE)) {
@@ -309,16 +312,16 @@
 	if (CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS))
 		board_fit_image_post_process(&src, &length);
 
+	load_ptr = map_sysmem(load_addr, length);
 	if (IS_ENABLED(CONFIG_SPL_GZIP) && image_comp == IH_COMP_GZIP) {
 		size = length;
-		if (gunzip((void *)load_addr, CONFIG_SYS_BOOTM_LEN,
-			   src, &size)) {
+		if (gunzip(load_ptr, CONFIG_SYS_BOOTM_LEN, src, &size)) {
 			puts("Uncompressing error\n");
 			return -EIO;
 		}
 		length = size;
 	} else {
-		memcpy((void *)load_addr, src, length);
+		memcpy(load_ptr, src, length);
 	}
 
 	if (image_info) {
@@ -383,7 +386,7 @@
 	}
 
 	/* Make the load-address of the FDT available for the SPL framework */
-	spl_image->fdt_addr = (void *)image_info.load_addr;
+	spl_image->fdt_addr = map_sysmem(image_info.load_addr, 0);
 	if (CONFIG_IS_ENABLED(FIT_IMAGE_TINY))
 		return 0;
 
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index c011870..2696d0b 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -1,4 +1,4 @@
-CONFIG_SYS_TEXT_BASE=0
+CONFIG_SYS_TEXT_BASE=0x200000
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
 CONFIG_NR_DRAM_BANKS=1
diff --git a/doc/Makefile b/doc/Makefile
index a686d47..683e4b5 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -56,7 +56,6 @@
 	PYTHONDONTWRITEBYTECODE=1 \
 	BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \
 	$(SPHINXBUILD) \
-	-W \
 	-b $2 \
 	-c $(abspath $(srctree)/$(src)) \
 	-d $(abspath $(BUILDDIR)/.doctrees/$3) \
diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst
index 60ee1e0..8b18a22 100644
--- a/doc/arch/sandbox.rst
+++ b/doc/arch/sandbox.rst
@@ -17,6 +17,12 @@
 all the generic code, not specific to any one architecture. The idea is to
 create unit tests which we can run to test this upper level code.
 
+Sandbox allows development of many types of new features in a traditional way,
+rather than needing to test each iteration on real hardware. Many U-Boot
+features were developed on sandbox, including the core driver model, most
+uclasses, verified boot, bloblist, logging and dozens of others. Sandbox has
+enabled many large-scale code refactors as well.
+
 CONFIG_SANDBOX is defined when building a native board.
 
 The board name is 'sandbox' but the vendor name is unset, so there is a
@@ -76,7 +82,7 @@
 You can issue commands as your would normally. If the command you want is
 not supported you can add it to include/configs/sandbox.h.
 
-To exit, type 'reset' or press Ctrl-C.
+To exit, type 'poweroff' or press Ctrl-C.
 
 
 Console / LCD support
@@ -486,42 +492,10 @@
 -------
 
 U-Boot sandbox can be used to run various tests, mostly in the test/
-directory. These include:
+directory.
 
-command_ut:
-  Unit tests for command parsing and handling
-compression:
-  Unit tests for U-Boot's compression algorithms, useful for
-  security checking. It supports gzip, bzip2, lzma and lzo.
-driver model:
-  Run this pytest::
-
-   ./test/py/test.py --bd sandbox --build -k ut_dm -v
-
-image:
-  Unit tests for images:
-  test/image/test-imagetools.sh - multi-file images
-  test/image/test-fit.py        - FIT images
-tracing:
-  test/trace/test-trace.sh tests the tracing system (see README.trace)
-verified boot:
-  See test/vboot/vboot_test.sh for this
-
-If you change or enhance any of the above subsystems, you shold write or
-expand a test and include it with your patch series submission. Test
-coverage in U-Boot is limited, as we need to work to improve it.
-
-Note that many of these tests are implemented as commands which you can
-run natively on your board if desired (and enabled).
-
-To run all tests use "make check".
-
-To run a single test in an existing sandbox build, you can use -T to use the
-test device tree, and -c to select the test:
-
-  /tmp/b/sandbox/u-boot -T -c "ut dm pci_busdev"
-
-This runs dm_test_pci_busdev() which is in test/dm/pci.c
+See :doc:`../develop/tests_sandbox` for more information and
+:doc:`../develop/testing` for information about testing generally.
 
 
 Memory Map
@@ -537,5 +511,7 @@
    e000   CONFIG_BLOBLIST_ADDR       Blob list
   10000   CONFIG_MALLOC_F_ADDR       Early memory allocation
   f0000   CONFIG_PRE_CON_BUF_ADDR    Pre-console buffer
- 100000   CONFIG_TRACE_EARLY_ADDR    Early trace buffer (if enabled)
+ 100000   CONFIG_TRACE_EARLY_ADDR    Early trace buffer (if enabled). Also used
+                                     as the SPL load buffer in spl_test_load().
+ 200000   CONFIG_SYS_TEXT_BASE       Load buffer for U-Boot (sandbox_spl only)
 =======   ========================   ===============================
diff --git a/doc/develop/index.rst b/doc/develop/index.rst
index ac57fdb..41c0ba1 100644
--- a/doc/develop/index.rst
+++ b/doc/develop/index.rst
@@ -33,3 +33,5 @@
    coccinelle
    testing
    py_testing
+   tests_writing
+   tests_sandbox
diff --git a/doc/develop/logging.rst b/doc/develop/logging.rst
index 60c18c5..f4e9250 100644
--- a/doc/develop/logging.rst
+++ b/doc/develop/logging.rst
@@ -96,16 +96,45 @@
 as the category, so you should #define this right at the top of the source
 file to ensure the category is correct.
 
+Generally each log format_string ends with a newline. If it does not, then the
+next log statement will have the LOGRECF_CONT flag set. This can be used to
+continue the statement on the same line as the previous one without emitting
+new header information (such as category/level). This behaviour is implemented
+with log_console. Here is an example that prints a list all on one line with
+the tags at the start:
+
+.. code-block:: c
+
+   log_debug("Here is a list:");
+   for (i = 0; i < count; i++)
+      log_debug(" item %d", i);
+   log_debug("\n");
+
+Also see the special category LOGL_CONT and level LOGC_CONT.
+
 You can also define CONFIG_LOG_ERROR_RETURN to enable the log_ret() macro. This
 can be used whenever your function returns an error value:
 
 .. code-block:: c
 
-   return log_ret(uclass_first_device(UCLASS_MMC, &dev));
+   return log_ret(uclass_first_device_err(UCLASS_MMC, &dev));
 
 This will write a log record when an error code is detected (a value < 0). This
 can make it easier to trace errors that are generated deep in the call stack.
 
+The log_msg_ret() variant will print a short string if CONFIG_LOG_ERROR_RETURN
+is enabled. So long as the string is unique within the function you can normally
+determine exactly which call failed:
+
+.. code-block:: c
+
+   ret = gpio_request_by_name(dev, "cd-gpios", 0, &desc, GPIOD_IS_IN);
+   if (ret)
+      return log_msg_ret("gpio", ret);
+
+Some functions return 0 for success and any other value is an error. For these,
+log_retz() and log_msg_retz() are available.
+
 Convenience functions
 ~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/doc/develop/py_testing.rst b/doc/develop/py_testing.rst
index 7f01858..c4cecc0 100644
--- a/doc/develop/py_testing.rst
+++ b/doc/develop/py_testing.rst
@@ -13,7 +13,8 @@
   U-Boot; there can be no disconnect.
 - There is no need to write or embed test-related code into U-Boot itself.
   It is asserted that writing test-related code in Python is simpler and more
-  flexible than writing it all in C.
+  flexible than writing it all in C. But see :doc:`tests_writing` for caveats
+  and more discussion / analysis.
 - It is reasonably simple to interact with U-Boot in this way.
 
 Requirements
diff --git a/doc/develop/testing.rst b/doc/develop/testing.rst
index 4bc9ca3..ced13ac 100644
--- a/doc/develop/testing.rst
+++ b/doc/develop/testing.rst
@@ -8,17 +8,27 @@
 Running tests
 -------------
 
-To run most tests on sandbox, type this:
+To run most tests on sandbox, type this::
 
     make check
 
 in the U-Boot directory. Note that only the pytest suite is run using this
 command.
 
-Some tests take ages to run. To run just the quick ones, type this:
+Some tests take ages to run and are marked with @pytest.mark.slow. To run just
+the quick ones, type this::
 
     make qcheck
 
+It is also possible to run just the tests for tools (patman, binman, etc.).
+Such tests are included with those tools, i.e. no actual U-Boot unit tests are
+run. Type this::
+
+    make tcheck
+
+All of the above use the test/run script with a paremeter to select which tests
+are run.
+
 
 Sandbox
 -------
@@ -26,6 +36,7 @@
 allows test to be executed without needing target hardware. The 'sandbox'
 target provides this feature and it is widely used in tests.
 
+See :doc:`tests_sandbox` for more information.
 
 Pytest Suite
 ------------
@@ -35,14 +46,27 @@
 inject test commands and check the result. It is slower to run than C code,
 but provides the ability to unify lots of tests and summarise their results.
 
-You can run the tests on sandbox with:
+You can run the tests on sandbox with::
 
-	./test/py/test.py --bd sandbox --build
+   ./test/py/test.py --bd sandbox --build
 
 This will produce HTML output in build-sandbox/test-log.html
 
+Some tests run with other versions of sandbox. For example sandbox_flattree
+runs the tests with livetree (the hierachical devicetree) disabled. You can
+also select particular tests with -k::
+
+   ./test/py/test.py --bd sandbox_flattree --build -k hello
+
+There are some special tests that run in SPL. For this you need the sandbox_spl
+build::
+
+   ./test/py/test.py --bd sandbox_spl --build -k test_spl
+
 See test/py/README.md for more information about the pytest suite.
 
+See :doc:`tests_sandbox` for how to run tests directly (not through pytest).
+
 
 tbot
 ----
@@ -58,10 +82,14 @@
 
 There are several ad-hoc tests which run outside the pytest environment:
 
-   test/fs	- File system test (shell script)
-   test/image	- FIT and legacy 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)
+test/fs
+   File system test (shell script)
+test/image
+   FIT and legacy 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)
 
 TODO: Move these into pytest.
 
@@ -89,6 +117,8 @@
   is much easier to add onto a test - writing a new large test can seem
   daunting to most contributors.
 
+See doc:`tests_writing` for how to write tests.
+
 
 Future work
 -----------
diff --git a/doc/develop/tests_sandbox.rst b/doc/develop/tests_sandbox.rst
new file mode 100644
index 0000000..84608dc
--- /dev/null
+++ b/doc/develop/tests_sandbox.rst
@@ -0,0 +1,209 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Sandbox tests
+=============
+
+Test Design
+-----------
+
+Most uclasses and many functions of U-Boot have sandbox tests. This allows much
+of the code to be checked in an developer-friendly environment.
+
+Sandbox provides a way to write and run unit tests. The traditional approach to
+unit tests is to build lots of little executables, one for each test or
+category of tests. With sandbox, so far as possible, all the tests share a
+small number of executables (e.g. 'u-boot' for sandbox, 'u-boot-spl' and
+'u-boot' for sandbox_spl) and can be run very quickly. The vast majority of
+tests can run on the 'sandbox' build,
+
+Available tests
+---------------
+
+Some of the available tests are:
+
+  - command_ut: Unit tests for command parsing and handling
+  - compression: Unit tests for U-Boot's compression algorithms, useful for
+      security checking. It supports gzip, bzip2, lzma and lzo.
+  - image: Unit tests for images:
+
+     - test/image/test-imagetools.sh - multi-file images
+     - test/py/tests/test-fit.py     - FIT images
+  - tracing: test/trace/test-trace.sh tests the tracing system (see
+      README.trace)
+  - verified boot: test/py/tests/test_vboot.py
+
+If you change or enhance any U-Boot subsystem, you should write or expand a
+test and include it with your patch series submission. Test coverage in some
+older areas of U-Boot is still somewhat limited and we need to work to improve
+it.
+
+Note that many of these tests are implemented as commands which you can
+run natively on your board if desired (and enabled).
+
+To run all tests, use 'make check'.
+
+
+Running sandbox tests directly
+------------------------------
+
+Typically tests are run using the pytest suite. Running pytests on sandbox is
+easy and always gets things right. For example some tests require files to be
+set up before they can work.
+
+But it is also possible to run some sandbox tests directly. For example, this
+runs the dm_test_gpio() test which you can find in test/dm/gpio.c::
+
+   $ ./u-boot -T -c "ut dm gpio"
+
+
+   U-Boot 2021.01
+
+   Model: sandbox
+   DRAM:  128 MiB
+   WDT:   Started with servicing (60s timeout)
+   MMC:   mmc2: 2 (SD), mmc1: 1 (SD), mmc0: 0 (SD)
+   In:    serial
+   Out:   vidconsole
+   Err:   vidconsole
+   Model: sandbox
+   SCSI:
+   Net:   eth0: eth@10002000, eth5: eth@10003000, eth3: sbe5, eth6: eth@10004000
+   Test: dm_test_gpio: gpio.c
+   Test: dm_test_gpio: gpio.c (flat tree)
+   Failures: 0
+
+The -T option tells the U-Boot sandbox to run with the 'test' devicetree
+(test.dts) instead of -D which selects the normal sandbox.dts - this is
+necessary because many tests rely on nodes or properties in the test devicetree.
+If you try running tests without -T then you may see failures, like::
+
+   $ ./u-boot -c "ut dm gpio"
+
+
+   U-Boot 2021.01
+
+   DRAM:  128 MiB
+   WDT:   Not found!
+   MMC:
+   In:    serial
+   Out:   serial
+   Err:   serial
+   SCSI:
+   Net:   No ethernet found.
+   Please run with test device tree:
+       ./u-boot -d arch/sandbox/dts/test.dtb
+   Test: dm_test_gpio: gpio.c
+   test/dm/gpio.c:37, dm_test_gpio(): 0 == gpio_lookup_name("b4", &dev, &offset, &gpio): Expected 0x0 (0), got 0xffffffea (-22)
+   Test: dm_test_gpio: gpio.c (flat tree)
+   test/dm/gpio.c:37, dm_test_gpio(): 0 == gpio_lookup_name("b4", &dev, &offset, &gpio): Expected 0x0 (0), got 0xffffffea (-22)
+   Failures: 2
+
+The message above should provide a hint if you forget to use the -T flag. Even
+running with -D will produce different results.
+
+You can easily use gdb on these tests, without needing --gdbserver::
+
+   $ gdb u-boot --args -T -c "ut dm gpio"
+   ...
+   (gdb) break dm_test_gpio
+   Breakpoint 1 at 0x1415bd: file test/dm/gpio.c, line 37.
+   (gdb) run -T -c "ut dm gpio"
+   Starting program: u-boot -T -c "ut dm gpio"
+   Test: dm_test_gpio: gpio.c
+
+   Breakpoint 1, dm_test_gpio (uts=0x5555558029a0 <global_dm_test_state>)
+       at files/test/dm/gpio.c:37
+   37		ut_assertok(gpio_lookup_name("b4", &dev, &offset, &gpio));
+   (gdb)
+
+You can then single-step and look at variables as needed.
+
+
+Running sandbox_spl tests directly
+----------------------------------
+
+SPL is the phase before U-Boot proper. It is present in the sandbox_spl build,
+so you can run SPL like this::
+
+   ./spl/u-boot-spl
+
+SPL tests are special in that they run (only in the SPL phase, of course) if the
+-u flag is given::
+
+   ./spl/u-boot-spl -u
+
+   U-Boot SPL 2021.01-00723-g43c77b51be5-dirty (Jan 24 2021 - 16:38:24 -0700)
+   Running 5 driver model tests
+   Test: dm_test_of_plat_base: of_platdata.c (flat tree)
+   Test: dm_test_of_plat_dev: of_platdata.c (flat tree)
+   Test: dm_test_of_plat_parent: of_platdata.c (flat tree)
+   Test: dm_test_of_plat_phandle: of_platdata.c (flat tree)
+   Test: dm_test_of_plat_props: of_platdata.c (flat tree)
+   Failures: 0
+
+
+   U-Boot 2021.01-00723-g43c77b51be5-dirty (Jan 24 2021 - 16:38:24 -0700)
+
+   DRAM:  128 MiB
+   ...
+
+It is not possible to run SPL tests in U-Boot proper, firstly because they are
+not built into U-Boot proper and secondly because the environment is very
+different, e.g. some SPL tests rely on of-platdata which is only available in
+SPL.
+
+Note that after running, SPL continues to boot into U-Boot proper. You can add
+'-c exit' to make U-Boot quit without doing anything further. It is not
+currently possible to run SPL tests and then stop, since the pytests require
+that U-Boot produces the expected banner.
+
+You can use the -k flag to select which tests run::
+
+   ./spl/u-boot-spl -u -k dm_test_of_plat_parent
+
+Of course you can use gdb with sandbox_spl, just as with sandbox.
+
+
+Running all tests directly
+--------------------------
+
+A fast way to run all sandbox tests is::
+
+   ./u-boot -T -c "ut all"
+
+It typically runs single-thread in 6 seconds on 2021 hardware, with 2s of that
+to the delays in the time test.
+
+This should not be considered a substitute for 'make check', but can be helpful
+for git bisect, etc.
+
+
+What tests are built in?
+------------------------
+
+Whatever sandbox build is used, which tests are present is determined by which
+source files are built. For sandbox_spl, the of_platdata tests are built
+because of the build rule in test/dm/Makefile::
+
+   ifeq ($(CONFIG_SPL_BUILD),y)
+   obj-$(CONFIG_SPL_OF_PLATDATA) += of_platdata.o
+   else
+   ...other tests for non-spl
+   endif
+
+You can get a list of tests in a U-Boot ELF file by looking for the
+linker_list::
+
+   $ nm /tmp/b/sandbox_spl/spl/u-boot-spl |grep 2_dm_test
+   000000000001f200 D _u_boot_list_2_dm_test_2_dm_test_of_plat_base
+   000000000001f220 D _u_boot_list_2_dm_test_2_dm_test_of_plat_dev
+   000000000001f240 D _u_boot_list_2_dm_test_2_dm_test_of_plat_parent
+   000000000001f260 D _u_boot_list_2_dm_test_2_dm_test_of_plat_phandle
+   000000000001f280 D _u_boot_list_2_dm_test_2_dm_test_of_plat_props
+
+
+Writing tests
+-------------
+
+See :doc:`tests_writing` for how to write new tests.
+
diff --git a/doc/develop/tests_writing.rst b/doc/develop/tests_writing.rst
new file mode 100644
index 0000000..1ddf7a3
--- /dev/null
+++ b/doc/develop/tests_writing.rst
@@ -0,0 +1,346 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright 2021 Google LLC
+.. sectionauthor:: Simon Glass <sjg@chromium.org>
+
+Writing Tests
+=============
+
+This describes how to write tests in U-Boot and describes the possible options.
+
+Test types
+----------
+
+There are two basic types of test in U-Boot:
+
+  - Python tests, in test/py/tests
+  - C tests, in test/ and its subdirectories
+
+(there are also UEFI tests in lib/efi_selftest/ not considered here.)
+
+Python tests talk to U-Boot via the command line. They support both sandbox and
+real hardware. They typically do not require building test code into U-Boot
+itself. They are fairly slow to run, due to the command-line interface and there
+being two separate processes. Python tests are fairly easy to write. They can
+be a little tricky to debug sometimes due to the voluminous output of pytest.
+
+C tests are written directly in U-Boot. While they can be used on boards, they
+are more commonly used with sandbox, as they obviously add to U-Boot code size.
+C tests are easy to write so long as the required facilities exist. Where they
+do not it can involve refactoring or adding new features to sandbox. They are
+fast to run and easy to debug.
+
+Regardless of which test type is used, all tests are collected and run by the
+pytest framework, so there is typically no need to run them separately. This
+means that C tests can be used when it makes sense, and Python tests when it
+doesn't.
+
+
+This table shows how to decide whether to write a C or Python test:
+
+=====================  ===========================  =============================
+Attribute              C test                       Python test
+=====================  ===========================  =============================
+Fast to run?           Yes                          No (two separate processes)
+Easy to write?         Yes, if required test        Yes
+                       features exist in sandbox
+                       or the target system
+Needs code in U-Boot?  Yes                          No, provided the test can be
+                                                    executed and the result
+                                                    determined using the command
+                                                    line
+Easy to debug?         Yes                          No, since access to the U-Boot
+                                                    state is not available and the
+                                                    amount of output can
+                                                    sometimes require a bit of
+                                                    digging
+Can use gdb?           Yes, directly                Yes, with --gdbserver
+Can run on boards?     Some can, but only if        Some
+                       compiled in and not
+                       dependent on sandboxau
+=====================  ===========================  =============================
+
+
+Python or C
+-----------
+
+Typically in U-Boot we encourage C test using sandbox for all features. This
+allows fast testing, easy development and allows contributors to make changes
+without needing dozens of boards to test with.
+
+When a test requires setup or interaction with the running host (such as to
+generate images and then running U-Boot to check that they can be loaded), or
+cannot be run on sandbox, Python tests should be used. These should typically
+NOT rely on running with sandbox, but instead should function correctly on any
+board supported by U-Boot.
+
+
+How slow are Python tests?
+--------------------------
+
+Under the hood, when running on sandbox, Python tests work by starting a sandbox
+test and connecting to it via a pipe. Each interaction with the U-Boot process
+requires at least a context switch to handle the pipe interaction. The test
+sends a command to U-Boot, which then reacts and shows some output, then the
+test sees that and continues. Of course on real hardware, communications delays
+(e.g. with a serial console) make this slower.
+
+For comparison, consider a test that checks the 'md' (memory dump). All times
+below are approximate, as measured on an AMD 2950X system. Here is is the test
+in Python::
+
+   @pytest.mark.buildconfigspec('cmd_memory')
+   def test_md(u_boot_console):
+       """Test that md reads memory as expected, and that memory can be modified
+       using the mw command."""
+
+       ram_base = u_boot_utils.find_ram_base(u_boot_console)
+       addr = '%08x' % ram_base
+       val = 'a5f09876'
+       expected_response = addr + ': ' + val
+       u_boot_console.run_command('mw ' + addr + ' 0 10')
+       response = u_boot_console.run_command('md ' + addr + ' 10')
+       assert(not (expected_response in response))
+       u_boot_console.run_command('mw ' + addr + ' ' + val)
+       response = u_boot_console.run_command('md ' + addr + ' 10')
+       assert(expected_response in response)
+
+This runs a few commands and checks the output. Note that it runs a command,
+waits for the response and then checks it agains what is expected. If run by
+itself it takes around 800ms, including test collection. For 1000 runs it takes
+19 seconds, or 19ms per run. Of course 1000 runs it not that useful since we
+only want to run it once.
+
+There is no exactly equivalent C test, but here is a similar one that tests 'ms'
+(memory search)::
+
+   /* Test 'ms' command with bytes */
+   static int mem_test_ms_b(struct unit_test_state *uts)
+   {
+      u8 *buf;
+
+      buf = map_sysmem(0, BUF_SIZE + 1);
+      memset(buf, '\0', BUF_SIZE);
+      buf[0x0] = 0x12;
+      buf[0x31] = 0x12;
+      buf[0xff] = 0x12;
+      buf[0x100] = 0x12;
+      ut_assertok(console_record_reset_enable());
+      run_command("ms.b 1 ff 12", 0);
+      ut_assert_nextline("00000030: 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................");
+      ut_assert_nextline("--");
+      ut_assert_nextline("000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12    ................");
+      ut_assert_nextline("2 matches");
+      ut_assert_console_end();
+
+      ut_asserteq(2, env_get_hex("memmatches", 0));
+      ut_asserteq(0xff, env_get_hex("memaddr", 0));
+      ut_asserteq(0xfe, env_get_hex("mempos", 0));
+
+      unmap_sysmem(buf);
+
+      return 0;
+   }
+   MEM_TEST(mem_test_ms_b, UT_TESTF_CONSOLE_REC);
+
+This runs the command directly in U-Boot, then checks the console output, also
+directly in U-Boot. If run by itself this takes 100ms. For 1000 runs it takes
+660ms, or 0.66ms per run.
+
+So overall running a C test is perhaps 8 times faster individually and the
+interactions are perhaps 25 times faster.
+
+It should also be noted that the C test is fairly easy to debug. You can set a
+breakpoint on do_mem_search(), which is what implements the 'ms' command,
+single step to see what might be wrong, etc. That is also possible with the
+pytest, but requires two terminals and --gdbserver.
+
+
+Why does speed matter?
+----------------------
+
+Many development activities rely on running tests:
+
+  - 'git bisect run make qcheck' can be used to find a failing commit
+  - test-driven development relies on quick iteration of build/test
+  - U-Boot's continuous integration (CI) systems make use of tests. Running
+      all sandbox tests typically takes 90 seconds and running each qemu test
+      takes about 30 seconds. This is currently dwarfed by the time taken to
+      build all boards
+
+As U-Boot continues to grow its feature set, fast and reliable tests are a
+critical factor factor in developer productivity and happiness.
+
+
+Writing C tests
+---------------
+
+C tests are arranged into suites which are typically executed by the 'ut'
+command. Each suite is in its own file. This section describes how to accomplish
+some common test tasks.
+
+(there are also UEFI C tests in lib/efi_selftest/ not considered here.)
+
+Add a new driver model test
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Use this when adding a test for a new or existing uclass, adding new operations
+or features to a uclass, adding new ofnode or dev_read_() functions, or anything
+else related to driver model.
+
+Find a suitable place for your test, perhaps near other test functions in
+existing code, or in a new file. Each uclass should have its own test file.
+
+Declare the test with::
+
+   /* Test that ... */
+   static int dm_test_uclassname_what(struct unit_test_state *uts)
+   {
+      /* test code here */
+
+      return 0;
+   }
+   DM_TEST(dm_test_uclassname_what, UT_TESTF_SCAN_FDT);
+
+Replace 'uclassname' with the name of your uclass, if applicable. Replace 'what'
+with what you are testing.
+
+The flags for DM_TEST() are defined in test/test.h and you typically want
+UT_TESTF_SCAN_FDT so that the devicetree is scanned and all devices are bound
+and ready for use. The DM_TEST macro adds UT_TESTF_DM automatically so that
+the test runner knows it is a driver model test.
+
+Driver model tests are special in that the entire driver model state is
+recreated anew for each test. This ensures that if a previous test deletes a
+device, for example, it does not affect subsequent tests. Driver model tests
+also run both with livetree and flattree, to ensure that both devicetree
+implementations work as expected.
+
+Example commit: c48cb7ebfb4 ("sandbox: add ADC unit tests") [1]
+
+[1] https://gitlab.denx.de/u-boot/u-boot/-/commit/c48cb7ebfb4
+
+
+Add a C test to an existing suite
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Use this when you are adding to or modifying an existing feature outside driver
+model. An example is bloblist.
+
+Add a new function in the same file as the rest of the suite and register it
+with the suite. For example, to add a new mem_search test::
+
+   /* Test 'ms' command with 32-bit values */
+   static int mem_test_ms_new_thing(struct unit_test_state *uts)
+   {
+         /* test code here*/
+
+         return 0;
+   }
+   MEM_TEST(mem_test_ms_new_thing, UT_TESTF_CONSOLE_REC);
+
+Note that the MEM_TEST() macros is defined at the top of the file.
+
+Example commit: 9fe064646d2 ("bloblist: Support relocating to a larger space") [1]
+
+[1] https://gitlab.denx.de/u-boot/u-boot/-/commit/9fe064646d2
+
+
+Add a new test suite
+~~~~~~~~~~~~~~~~~~~~
+
+Each suite should focus on one feature or subsystem, so if you are writing a
+new one of those, you should add a new suite.
+
+Create a new file in test/ or a subdirectory and define a macro to register the
+suite. For example::
+
+   #include <common.h>
+   #include <console.h>
+   #include <mapmem.h>
+   #include <dm/test.h>
+   #include <test/ut.h>
+
+   /* Declare a new wibble test */
+   #define WIBBLE_TEST(_name, _flags)   UNIT_TEST(_name, _flags, wibble_test)
+
+   /* Tetss go here */
+
+   /* At the bottom of the file: */
+
+   int do_ut_wibble(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+   {
+     struct unit_test *tests = UNIT_TEST_SUITE_START(wibble_test);
+     const int n_ents = UNIT_TEST_SUITE_COUNT(wibble_test);
+
+     return cmd_ut_category("cmd_wibble", "wibble_test_", tests, n_ents, argc, argv);
+   }
+
+Then add new tests to it as above.
+
+Register this new suite in test/cmd_ut.c by adding to cmd_ut_sub[]::
+
+  /* Within cmd_ut_sub[]... */
+
+  U_BOOT_CMD_MKENT(wibble, CONFIG_SYS_MAXARGS, 1, do_ut_wibble, "", ""),
+
+and adding new help to ut_help_text[]::
+
+  "ut wibble - Test the wibble feature\n"
+
+If your feature is conditional on a particular Kconfig, then you can use #ifdef
+to control that.
+
+Finally, add the test to the build by adding to the Makefile in the same
+directory::
+
+  obj-$(CONFIG_$(SPL_)CMDLINE) += wibble.o
+
+Note that CMDLINE is never enabled in SPL, so this test will only be present in
+U-Boot proper. See below for how to do SPL tests.
+
+As before, you can add an extra Kconfig check if needed::
+
+  ifneq ($(CONFIG_$(SPL_)WIBBLE),)
+  obj-$(CONFIG_$(SPL_)CMDLINE) += wibble.o
+  endif
+
+
+Example commit: 919e7a8fb64 ("test: Add a simple test for bloblist") [1]
+
+[1] https://gitlab.denx.de/u-boot/u-boot/-/commit/919e7a8fb64
+
+
+Making the test run from pytest
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All C tests must run from pytest. Typically this is automatic, since pytest
+scans the U-Boot executable for available tests to run. So long as you have a
+'ut' subcommand for your test suite, it will run. The same applies for driver
+model tests since they use the 'ut dm' subcommand.
+
+See test/py/tests/test_ut.py for how unit tests are run.
+
+
+Add a C test for SPL
+~~~~~~~~~~~~~~~~~~~~
+
+Note: C tests are only available for sandbox_spl at present. There is currently
+no mechanism in other boards to existing SPL tests even if they are built into
+the image.
+
+SPL tests cannot be run from the 'ut' command since there are no commands
+available in SPL. Instead, sandbox (only) calls ut_run_list() on start-up, when
+the -u flag is given. This runs the available unit tests, no matter what suite
+they are in.
+
+To create a new SPL test, follow the same rules as above, either adding to an
+existing suite or creating a new one.
+
+An example SPL test is spl_test_load().
+
+
+Writing Python tests
+--------------------
+
+See :doc:`py_testing` for brief notes how to write Python tests. You
+should be able to use the existing tests in test/py/tests as examples.
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 9169fff..637b73c 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -29,7 +29,9 @@
    load
    loady
    mbr
+   md
    pstore
    qfw
    sbi
    true
+   scp03
diff --git a/doc/usage/md.rst b/doc/usage/md.rst
new file mode 100644
index 0000000..4c1073e
--- /dev/null
+++ b/doc/usage/md.rst
@@ -0,0 +1,106 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+md command
+==========
+
+Synopis
+-------
+
+::
+
+    md <address>[<data_size>] [<length>]
+
+Description
+-----------
+
+The md command is used to dump the contents of memory. It uses a standard
+format that includes the address, hex data and ASCII display. It supports
+various data sizes and uses the endianness of the target.
+
+The specified data_size and length become the defaults for future memory
+commands commands.
+
+address
+    start address to display
+
+data_size
+    size of each value to display (defaults to .l):
+
+    =========  ===================
+    data_size  Output size
+    =========  ===================
+    .b         byte
+    .w         word (16 bits)
+    .l         long (32 bits)
+    .q         quadword (64 bits)
+    =========  ===================
+
+length
+    number of values to dump. Defaults to 40 (0d64). Note that this is not
+    the same as the number of bytes, unless .b is used.
+
+Note that the format of 'md.b' can be emulated from linux with::
+
+    # This works but requires using sed to get the extra spaces
+    # <addr> is the address, <f> is the filename
+    xxd -o <addr> -g1 <f> |sed 's/  /    /' >bad
+
+    # This uses a single tool but the offset always starts at 0
+    # <f> is the filename
+    hexdump -v -e '"%08.8_ax: " 16/1 "%02x " "    "' -e '16/1 "%_p" "\n" ' <f>
+
+
+Example
+-------
+
+::
+
+    => md 10000
+    00010000: 00010000 00000000 f0f30f00 00005596    .............U..
+    00010010: 10011010 00000000 10011010 00000000    ................
+    00010020: 10011050 00000000 b96d4cd8 00007fff    P........Lm.....
+    00010030: 00000000 00000000 f0f30f18 00005596    .............U..
+    00010040: 10011040 00000000 10011040 00000000    @.......@.......
+    00010050: b96d4cd8 00007fff 10011020 00000000    .Lm..... .......
+    00010060: 00000003 000000c3 00000000 00000000    ................
+    00010070: 00000000 00000000 f0e892f3 00005596    .............U..
+    00010080: 00000000 000000a1 00000000 00000000    ................
+    00010090: 00000000 00000000 f0e38aa6 00005596    .............U..
+    000100a0: 00000000 000000a6 00000022 00000000    ........".......
+    000100b0: 00000001 00000000 f0e38aa1 00005596    .............U..
+    000100c0: 00000000 000000be 00000000 00000000    ................
+    000100d0: 00000000 00000000 00000000 00000000    ................
+    000100e0: 00000000 00000000 00000000 00000000    ................
+    000100f0: 00000000 00000000 00000000 00000000    ................
+    => md.b 10000
+    00010000: 00 00 01 00 00 00 00 00 00 0f f3 f0 96 55 00 00    .............U..
+    00010010: 10 10 01 10 00 00 00 00 10 10 01 10 00 00 00 00    ................
+    00010020: 50 10 01 10 00 00 00 00 d8 4c 6d b9 ff 7f 00 00    P........Lm.....
+    00010030: 00 00 00 00 00 00 00 00 18 0f f3 f0 96 55 00 00    .............U..
+    => md.b 10000 10
+    00010000: 00 00 01 00 00 00 00 00 00 0f f3 f0 96 55 00 00    .............U..
+    =>
+    00010010: 10 10 01 10 00 00 00 00 10 10 01 10 00 00 00 00    ................
+    =>
+    00010020: 50 10 01 10 00 00 00 00 d8 4c 6d b9 ff 7f 00 00    P........Lm.....
+    =>
+    => md.q 10000
+    00010000: 0000000000010000 00005596f0f30f00    .............U..
+    00010010: 0000000010011010 0000000010011010    ................
+    00010020: 0000000010011050 00007fffb96d4cd8    P........Lm.....
+    00010030: 0000000000000000 00005596f0f30f18    .............U..
+    00010040: 0000000010011040 0000000010011040    @.......@.......
+    00010050: 00007fffb96d4cd8 0000000010011020    .Lm..... .......
+    00010060: 000000c300000003 0000000000000000    ................
+    00010070: 0000000000000000 00005596f0e892f3    .............U..
+
+The empty commands cause a 'repeat', so that md shows the next available data
+in the same format as before.
+
+
+Return value
+------------
+
+The return value $? is always 0 (true).
+
+
diff --git a/doc/usage/scp03.rst b/doc/usage/scp03.rst
new file mode 100644
index 0000000..7ff87ed
--- /dev/null
+++ b/doc/usage/scp03.rst
@@ -0,0 +1,33 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+scp03 command
+=============
+
+Synopsis
+--------
+
+::
+
+    scp03 enable
+    scp03 provision
+
+Description
+-----------
+
+The *scp03* command calls into a Trusted Application executing in a
+Trusted Execution Environment to enable (if present) the Secure
+Channel Protocol 03 stablished between the processor and the secure
+element.
+
+This protocol encrypts all the communication between the processor and
+the secure element using a set of pre-defined keys. These keys can be
+rotated (provisioned) using the *provision* request.
+
+See also
+--------
+
+For some information on the internals implemented in the TEE, please
+check the GlobalPlatform documentation on `Secure Channel Protocol '03'`_
+
+.. _Secure Channel Protocol '03':
+   https://globalplatform.org/wp-content/uploads/2014/07/GPC_2.3_D_SCP03_v1.1.2_PublicRelease.pdf
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 4a9b74e..f24db87 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -3,6 +3,8 @@
  * Copyright (c) 2013 Google, Inc
  */
 
+#define LOG_CATEGORY	UCLASS_GPIO
+
 #include <common.h>
 #include <dm.h>
 #include <log.h>
@@ -21,6 +23,7 @@
 #include <dm/device_compat.h>
 #include <linux/bug.h>
 #include <linux/ctype.h>
+#include <linux/delay.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -220,7 +223,7 @@
 static int gpio_find_and_xlate(struct gpio_desc *desc,
 			       struct ofnode_phandle_args *args)
 {
-	struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
+	const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
 
 	if (ops->xlate)
 		return ops->xlate(desc->dev, desc, args);
@@ -353,6 +356,7 @@
 
 int dm_gpio_request(struct gpio_desc *desc, const char *label)
 {
+	const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
 	struct udevice *dev = desc->dev;
 	struct gpio_dev_priv *uc_priv;
 	char *str;
@@ -364,8 +368,8 @@
 	str = strdup(label);
 	if (!str)
 		return -ENOMEM;
-	if (gpio_get_ops(dev)->request) {
-		ret = gpio_get_ops(dev)->request(dev, desc->offset, label);
+	if (ops->request) {
+		ret = ops->request(dev, desc->offset, label);
 		if (ret) {
 			free(str);
 			return ret;
@@ -442,14 +446,15 @@
 
 int _dm_gpio_free(struct udevice *dev, uint offset)
 {
+	const struct dm_gpio_ops *ops = gpio_get_ops(dev);
 	struct gpio_dev_priv *uc_priv;
 	int ret;
 
 	uc_priv = dev_get_uclass_priv(dev);
 	if (!uc_priv->name[offset])
 		return -ENXIO;
-	if (gpio_get_ops(dev)->rfree) {
-		ret = gpio_get_ops(dev)->rfree(dev, offset);
+	if (ops->rfree) {
+		ret = ops->rfree(dev, offset);
 		if (ret)
 			return ret;
 	}
@@ -515,11 +520,8 @@
 	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
-	ret = check_reserved(&desc, "dir_input");
-	if (ret)
-		return ret;
 
-	return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset);
+	return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_IN);
 }
 
 /**
@@ -534,24 +536,25 @@
 int gpio_direction_output(unsigned gpio, int value)
 {
 	struct gpio_desc desc;
+	ulong flags;
 	int ret;
 
 	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
-	ret = check_reserved(&desc, "dir_output");
-	if (ret)
-		return ret;
 
-	return gpio_get_ops(desc.dev)->direction_output(desc.dev,
-							desc.offset, value);
+	flags = GPIOD_IS_OUT;
+	if (value)
+		flags |= GPIOD_IS_OUT_ACTIVE;
+	return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, flags);
 }
 
 static int _gpio_get_value(const struct gpio_desc *desc)
 {
+	const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
 	int value;
 
-	value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
+	value = ops->get_value(desc->dev, desc->offset);
 
 	return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
 }
@@ -569,6 +572,7 @@
 
 int dm_gpio_set_value(const struct gpio_desc *desc, int value)
 {
+	const struct dm_gpio_ops *ops;
 	int ret;
 
 	ret = check_reserved(desc, "set_value");
@@ -578,21 +582,33 @@
 	if (desc->flags & GPIOD_ACTIVE_LOW)
 		value = !value;
 
+	/* GPIOD_ are directly managed by driver in set_flags */
+	ops = gpio_get_ops(desc->dev);
+	if (ops->set_flags) {
+		ulong flags = desc->flags;
+
+		if (value)
+			flags |= GPIOD_IS_OUT_ACTIVE;
+		else
+			flags &= ~GPIOD_IS_OUT_ACTIVE;
+		return ops->set_flags(desc->dev, desc->offset, flags);
+	}
+
 	/*
 	 * Emulate open drain by not actively driving the line high or
 	 * Emulate open source by not actively driving the line low
 	 */
 	if ((desc->flags & GPIOD_OPEN_DRAIN && value) ||
 	    (desc->flags & GPIOD_OPEN_SOURCE && !value))
-		return gpio_get_ops(desc->dev)->direction_input(desc->dev,
-								desc->offset);
+		return ops->direction_input(desc->dev, desc->offset);
 	else if (desc->flags & GPIOD_OPEN_DRAIN ||
 		 desc->flags & GPIOD_OPEN_SOURCE)
-		return gpio_get_ops(desc->dev)->direction_output(desc->dev,
-								desc->offset,
-								value);
+		return ops->direction_output(desc->dev, desc->offset, value);
 
-	gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
+	ret = ops->set_value(desc->dev, desc->offset, value);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
@@ -620,10 +636,21 @@
 	return 0;
 }
 
-static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+/**
+ * _dm_gpio_set_flags() - Send flags to the driver
+ *
+ * This uses the best available method to send the given flags to the driver.
+ * Note that if flags & GPIOD_ACTIVE_LOW, the driver sees the opposite value
+ * of GPIOD_IS_OUT_ACTIVE.
+ *
+ * @desc:	GPIO description
+ * @flags:	flags value to set
+ * @return 0 if OK, -ve on error
+ */
+static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong flags)
 {
 	struct udevice *dev = desc->dev;
-	struct dm_gpio_ops *ops = gpio_get_ops(dev);
+	const struct dm_gpio_ops *ops = gpio_get_ops(dev);
 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 	int ret = 0;
 
@@ -638,38 +665,52 @@
 		return ret;
 	}
 
-	/* GPIOD_ are directly managed by driver in set_dir_flags*/
-	if (ops->set_dir_flags) {
-		ret = ops->set_dir_flags(dev, desc->offset, flags);
+	/* If active low, invert the output state */
+	if ((flags & (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)) ==
+		(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW))
+		flags ^= GPIOD_IS_OUT_ACTIVE;
+
+	/* GPIOD_ are directly managed by driver in set_flags */
+	if (ops->set_flags) {
+		ret = ops->set_flags(dev, desc->offset, flags);
 	} else {
 		if (flags & GPIOD_IS_OUT) {
-			ret = ops->direction_output(dev, desc->offset,
-						    GPIOD_FLAGS_OUTPUT(flags));
+			bool value = flags & GPIOD_IS_OUT_ACTIVE;
+
+			ret = ops->direction_output(dev, desc->offset, value);
 		} else if (flags & GPIOD_IS_IN) {
 			ret = ops->direction_input(dev, desc->offset);
 		}
 	}
 
-	/* save the flags also in descriptor */
-	if (!ret)
-		desc->flags = flags;
-
 	return ret;
 }
 
-int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set)
 {
+	ulong flags;
 	int ret;
 
 	ret = check_reserved(desc, "set_dir_flags");
 	if (ret)
 		return ret;
 
-	/* combine the requested flags (for IN/OUT) and the descriptor flags */
-	flags |= desc->flags;
-	ret = _dm_gpio_set_dir_flags(desc, flags);
+	flags = (desc->flags & ~clr) | set;
 
-	return ret;
+	ret = _dm_gpio_set_flags(desc, flags);
+	if (ret)
+		return ret;
+
+	/* save the flags also in descriptor */
+	desc->flags = flags;
+
+	return 0;
+}
+
+int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+{
+	/* combine the requested flags (for IN/OUT) and the descriptor flags */
+	return dm_gpio_clrset_flags(desc, GPIOD_MASK_DIR, flags);
 }
 
 int dm_gpio_set_dir(struct gpio_desc *desc)
@@ -680,42 +721,57 @@
 	if (ret)
 		return ret;
 
-	return _dm_gpio_set_dir_flags(desc, desc->flags);
+	return _dm_gpio_set_flags(desc, desc->flags);
 }
 
-int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags)
+int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr,
+			  ulong set)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		ret = dm_gpio_clrset_flags(&desc[i], clr, set);
+		if (ret)
+			return log_ret(ret);
+	}
+
+	return 0;
+}
+
+int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flagsp)
 {
 	struct udevice *dev = desc->dev;
 	int ret, value;
-	struct dm_gpio_ops *ops = gpio_get_ops(dev);
-	ulong dir_flags;
+	const struct dm_gpio_ops *ops = gpio_get_ops(dev);
+	ulong flags;
 
-	ret = check_reserved(desc, "get_dir_flags");
+	ret = check_reserved(desc, "get_flags");
 	if (ret)
 		return ret;
 
 	/* GPIOD_ are directly provided by driver except GPIOD_ACTIVE_LOW */
-	if (ops->get_dir_flags) {
-		ret = ops->get_dir_flags(dev, desc->offset, &dir_flags);
+	if (ops->get_flags) {
+		ret = ops->get_flags(dev, desc->offset, &flags);
 		if (ret)
 			return ret;
 
 		/* GPIOD_ACTIVE_LOW is saved in desc->flags */
-		value = dir_flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
+		value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
 		if (desc->flags & GPIOD_ACTIVE_LOW)
 			value = !value;
-		dir_flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE);
-		dir_flags |= (desc->flags & GPIOD_ACTIVE_LOW);
+		flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE);
+		flags |= (desc->flags & GPIOD_ACTIVE_LOW);
 		if (value)
-			dir_flags |= GPIOD_IS_OUT_ACTIVE;
+			flags |= GPIOD_IS_OUT_ACTIVE;
 	} else {
-		dir_flags = desc->flags;
+		flags = desc->flags;
 		/* only GPIOD_IS_OUT_ACTIVE is provided by uclass */
-		dir_flags &= ~GPIOD_IS_OUT_ACTIVE;
+		flags &= ~GPIOD_IS_OUT_ACTIVE;
 		if ((desc->flags & GPIOD_IS_OUT) && _gpio_get_value(desc))
-			dir_flags |= GPIOD_IS_OUT_ACTIVE;
+			flags |= GPIOD_IS_OUT_ACTIVE;
 	}
-	*flags = dir_flags;
+	*flagsp = flags;
 
 	return 0;
 }
@@ -785,7 +841,7 @@
 			const char **namep)
 {
 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
-	struct dm_gpio_ops *ops = gpio_get_ops(dev);
+	const struct dm_gpio_ops *ops = gpio_get_ops(dev);
 
 	BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
 	if (!device_active(dev))
@@ -822,7 +878,7 @@
 
 int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
 {
-	struct dm_gpio_ops *ops = gpio_get_ops(dev);
+	const struct dm_gpio_ops *ops = gpio_get_ops(dev);
 	struct gpio_dev_priv *priv;
 	char *str = buf;
 	int func;
@@ -862,7 +918,7 @@
 #if CONFIG_IS_ENABLED(ACPIGEN)
 int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio)
 {
-	struct dm_gpio_ops *ops;
+	const struct dm_gpio_ops *ops;
 
 	memset(gpio, '\0', sizeof(*gpio));
 	if (!dm_gpio_is_valid(desc)) {
@@ -949,6 +1005,71 @@
 	return vector;
 }
 
+int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list,
+				    int count)
+{
+	static const char tristate[] = "01z";
+	enum {
+		PULLUP,
+		PULLDOWN,
+
+		NUM_OPTIONS,
+	};
+	int vals[NUM_OPTIONS];
+	uint mask;
+	uint vector = 0;
+	int ret, i;
+
+	/*
+	 * Limit to 19 digits which should be plenty. This avoids overflow of a
+	 * 32-bit int
+	 */
+	assert(count < 20);
+
+	for (i = 0; i < NUM_OPTIONS; i++) {
+		uint flags = GPIOD_IS_IN;
+
+		flags |= (i == PULLDOWN) ? GPIOD_PULL_DOWN : GPIOD_PULL_UP;
+		ret = dm_gpios_clrset_flags(desc_list, count, GPIOD_MASK_PULL,
+					    flags);
+		if (ret)
+			return log_msg_ret("pu", ret);
+
+		/* Give the lines time to settle */
+		udelay(10);
+
+		ret = dm_gpio_get_values_as_int(desc_list, count);
+		if (ret < 0)
+			return log_msg_ret("get1", ret);
+		vals[i] = ret;
+	}
+
+	log_debug("values: %x %x, count = %d\n", vals[0], vals[1], count);
+	for (i = count - 1, mask = 1 << i; i >= 0; i--, mask >>= 1) {
+		uint pd = vals[PULLDOWN] & mask ? 1 : 0;
+		uint pu = vals[PULLUP] & mask ? 1 : 0;
+		uint digit;
+
+		/*
+		 * Get value with internal pulldown active. If this is 1 then
+		 * there is a stronger external pullup, which we call 1. If not
+		 * then call it 0.
+		 *
+		 * If the values differ then the pin is floating so we call
+		 * this a 2.
+		 */
+		if (pu == pd)
+			digit = pd;
+		else
+			digit = 2;
+		log_debug("%c ", tristate[digit]);
+		vector = 3 * vector + digit;
+	}
+	log_debug("vector=%d\n", vector);
+
+	return vector;
+}
+
 /**
  * gpio_request_tail: common work for requesting a gpio.
  *
@@ -1011,7 +1132,10 @@
 		debug("%s: dm_gpio_requestf failed\n", __func__);
 		goto err;
 	}
-	ret = dm_gpio_set_dir_flags(desc, flags);
+
+	/* Keep any direction flags provided by the devicetree */
+	ret = dm_gpio_set_dir_flags(desc,
+				    flags | (desc->flags & GPIOD_MASK_DIR));
 	if (ret) {
 		debug("%s: dm_gpio_set_dir failed\n", __func__);
 		goto err;
@@ -1024,6 +1148,7 @@
 	return ret;
 }
 
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
 static int _gpio_request_by_name_nodev(ofnode node, const char *list_name,
 				       int index, struct gpio_desc *desc,
 				       int flags, bool add_index)
@@ -1110,6 +1235,7 @@
 
 	return ret;
 }
+#endif /* OF_PLATDATA */
 
 int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
 {
@@ -1306,10 +1432,10 @@
 			ops->get_function += gd->reloc_off;
 		if (ops->xlate)
 			ops->xlate += gd->reloc_off;
-		if (ops->set_dir_flags)
-			ops->set_dir_flags += gd->reloc_off;
-		if (ops->get_dir_flags)
-			ops->get_dir_flags += gd->reloc_off;
+		if (ops->set_flags)
+			ops->set_flags += gd->reloc_off;
+		if (ops->get_flags)
+			ops->get_flags += gd->reloc_off;
 
 		reloc_done++;
 	}
diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c
index eda9548..ab46a94 100644
--- a/drivers/gpio/intel_gpio.c
+++ b/drivers/gpio/intel_gpio.c
@@ -3,6 +3,8 @@
  * Copyright 2019 Google LLC
  */
 
+#define LOG_CATEGORY	UCLASS_GPIO
+
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
@@ -23,38 +25,6 @@
 #include <dm/acpi.h>
 #include <dt-bindings/gpio/x86-gpio.h>
 
-static int intel_gpio_direction_input(struct udevice *dev, uint offset)
-{
-	struct udevice *pinctrl = dev_get_parent(dev);
-	uint config_offset;
-
-	config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
-
-	pcr_clrsetbits32(pinctrl, config_offset,
-			 PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
-				  PAD_CFG0_RX_DISABLE,
-			 PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE);
-
-	return 0;
-}
-
-static int intel_gpio_direction_output(struct udevice *dev, uint offset,
-				       int value)
-{
-	struct udevice *pinctrl = dev_get_parent(dev);
-	uint config_offset;
-
-	config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
-
-	pcr_clrsetbits32(pinctrl, config_offset,
-			 PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
-				  PAD_CFG0_TX_DISABLE | PAD_CFG0_TX_STATE,
-			 PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE |
-				  (value ? PAD_CFG0_TX_STATE : 0));
-
-	return 0;
-}
-
 static int intel_gpio_get_value(struct udevice *dev, uint offset)
 {
 	struct udevice *pinctrl = dev_get_parent(dev);
@@ -130,6 +100,41 @@
 	return 0;
 }
 
+static int intel_gpio_set_flags(struct udevice *dev, unsigned int offset,
+				ulong flags)
+{
+	struct udevice *pinctrl = dev_get_parent(dev);
+	u32 bic0 = 0, bic1 = 0;
+	u32 or0, or1;
+	uint config_offset;
+
+	config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
+
+	if (flags & GPIOD_IS_OUT) {
+		bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
+			PAD_CFG0_TX_DISABLE;
+		or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE;
+	} else if (flags & GPIOD_IS_IN) {
+		bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
+			PAD_CFG0_RX_DISABLE;
+		or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE;
+	}
+	if (flags & GPIOD_PULL_UP) {
+		bic1 |= PAD_CFG1_PULL_MASK;
+		or1 |= PAD_CFG1_PULL_UP_20K;
+	} else if (flags & GPIOD_PULL_DOWN) {
+		bic1 |= PAD_CFG1_PULL_MASK;
+		or1 |= PAD_CFG1_PULL_DN_20K;
+	}
+
+	pcr_clrsetbits32(pinctrl, PAD_CFG0_OFFSET(config_offset), bic0, or0);
+	pcr_clrsetbits32(pinctrl, PAD_CFG1_OFFSET(config_offset), bic1, or1);
+	log_debug("%s: flags=%lx, offset=%x, config_offset=%x, %x/%x %x/%x\n",
+		  dev->name, flags, offset, config_offset, bic0, or0, bic1, or1);
+
+	return 0;
+}
+
 #if CONFIG_IS_ENABLED(ACPIGEN)
 static int intel_gpio_get_acpi(const struct gpio_desc *desc,
 			       struct acpi_gpio *gpio)
@@ -177,12 +182,11 @@
 }
 
 static const struct dm_gpio_ops gpio_intel_ops = {
-	.direction_input	= intel_gpio_direction_input,
-	.direction_output	= intel_gpio_direction_output,
 	.get_value		= intel_gpio_get_value,
 	.set_value		= intel_gpio_set_value,
 	.get_function		= intel_gpio_get_function,
 	.xlate			= intel_gpio_xlate,
+	.set_flags		= intel_gpio_set_flags,
 #if CONFIG_IS_ENABLED(ACPIGEN)
 	.get_acpi		= intel_gpio_get_acpi,
 #endif
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index dc8d506..d008fdd 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -19,42 +19,51 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/gpio/sandbox-gpio.h>
 
-
 struct gpio_state {
 	const char *label;	/* label given by requester */
-	ulong dir_flags;	/* dir_flags (GPIOD_...) */
+	ulong flags;		/* flags (GPIOD_...) */
 };
 
-/* Access routines for GPIO dir flags */
-static ulong *get_gpio_dir_flags(struct udevice *dev, unsigned int offset)
+/* Access routines for GPIO info */
+static struct gpio_state *get_gpio_state(struct udevice *dev, uint offset)
 {
 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 	struct gpio_state *state = dev_get_priv(dev);
 
 	if (offset >= uc_priv->gpio_count) {
-		static ulong invalid_dir_flags;
 		printf("sandbox_gpio: error: invalid gpio %u\n", offset);
-		return &invalid_dir_flags;
+		return NULL;
 	}
 
-	return &state[offset].dir_flags;
+	return &state[offset];
+}
+
+/* Access routines for GPIO flags */
+static ulong *get_gpio_flags(struct udevice *dev, unsigned int offset)
+{
+	struct gpio_state *state = get_gpio_state(dev, offset);
+
+	if (!state)
+		return NULL;
+
+	return &state->flags;
 
 }
 
 static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
 {
-	return (*get_gpio_dir_flags(dev, offset) & flag) != 0;
+	return (*get_gpio_flags(dev, offset) & flag) != 0;
 }
 
 static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
 			 int value)
 {
-	ulong *gpio = get_gpio_dir_flags(dev, offset);
+	struct gpio_state *state = get_gpio_state(dev, offset);
 
 	if (value)
-		*gpio |= flag;
+		state->flags |= flag;
 	else
-		*gpio &= ~flag;
+		state->flags &= ~flag;
 
 	return 0;
 }
@@ -65,14 +74,31 @@
 
 int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
 {
+	struct gpio_state *state = get_gpio_state(dev, offset);
+	bool val;
+
 	if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
 		debug("sandbox_gpio: get_value on output gpio %u\n", offset);
-	return get_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE);
+
+	if (state->flags & GPIOD_EXT_DRIVEN) {
+		val = state->flags & GPIOD_EXT_HIGH;
+	} else {
+		if (state->flags & GPIOD_EXT_PULL_UP)
+			val = true;
+		else if (state->flags & GPIOD_EXT_PULL_DOWN)
+			val = false;
+		else
+			val = state->flags & GPIOD_PULL_UP;
+	}
+
+	return val;
 }
 
 int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
 {
-	return set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE, value);
+	set_gpio_flag(dev, offset, GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+
+	return 0;
 }
 
 int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
@@ -83,20 +109,23 @@
 int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
 {
 	set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
-	set_gpio_flag(dev, offset, GPIOD_IS_IN, !(output));
+	set_gpio_flag(dev, offset, GPIOD_IS_IN, !output);
 
 	return 0;
 }
 
-ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset)
+ulong sandbox_gpio_get_flags(struct udevice *dev, uint offset)
 {
-	return *get_gpio_dir_flags(dev, offset);
+	ulong flags = *get_gpio_flags(dev, offset);
+
+	return flags & ~GPIOD_SANDBOX_MASK;
 }
 
-int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
-			       ulong flags)
+int sandbox_gpio_set_flags(struct udevice *dev, uint offset, ulong flags)
 {
-	*get_gpio_dir_flags(dev, offset) = flags;
+	struct gpio_state *state = get_gpio_state(dev, offset);
+
+	state->flags = flags;
 
 	return 0;
 }
@@ -117,10 +146,19 @@
 static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
 				    int value)
 {
+	int ret;
+
 	debug("%s: offset:%u, value = %d\n", __func__, offset, value);
 
-	return sandbox_gpio_set_direction(dev, offset, 1) |
-		sandbox_gpio_set_value(dev, offset, value);
+	ret = sandbox_gpio_set_direction(dev, offset, 1);
+	if (ret)
+		return ret;
+	ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
+			    GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
 /* read GPIO IN value of port 'offset' */
@@ -134,6 +172,8 @@
 /* write GPIO OUT value to port 'offset' */
 static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
 {
+	int ret;
+
 	debug("%s: offset:%u, value = %d\n", __func__, offset, value);
 
 	if (!sandbox_gpio_get_direction(dev, offset)) {
@@ -142,7 +182,12 @@
 		return -1;
 	}
 
-	return sandbox_gpio_set_value(dev, offset, value);
+	ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
+			    GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
 static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
@@ -177,33 +222,30 @@
 	return 0;
 }
 
-static int sb_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
-				 ulong flags)
+static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset,
+			     ulong flags)
 {
-	ulong *dir_flags;
+	debug("%s: offset:%u, flags = %lx\n", __func__, offset, flags);
+	struct gpio_state *state = get_gpio_state(dev, offset);
 
-	debug("%s: offset:%u, dir_flags = %lx\n", __func__, offset, flags);
-
-	dir_flags = get_gpio_dir_flags(dev, offset);
-
-	/*
-	 * For testing purposes keep the output value when switching to input.
-	 * This allows us to manipulate the input value via the gpio command.
-	 */
-	if (flags & GPIOD_IS_IN)
-		*dir_flags = (flags & ~GPIOD_IS_OUT_ACTIVE) |
-			     (*dir_flags & GPIOD_IS_OUT_ACTIVE);
-	else
-		*dir_flags = flags;
+	if (flags & GPIOD_IS_OUT) {
+		flags |= GPIOD_EXT_DRIVEN;
+		if (flags & GPIOD_IS_OUT_ACTIVE)
+			flags |= GPIOD_EXT_HIGH;
+		else
+			flags &= ~GPIOD_EXT_HIGH;
+	} else {
+		flags |= state->flags & GPIOD_SANDBOX_MASK;
+	}
+	state->flags = flags;
 
 	return 0;
 }
 
-static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
-				 ulong *flags)
+static int sb_gpio_get_flags(struct udevice *dev, uint offset, ulong *flagsp)
 {
 	debug("%s: offset:%u\n", __func__, offset);
-	*flags = *get_gpio_dir_flags(dev, offset);
+	*flagsp = *get_gpio_flags(dev, offset) & ~GPIOD_SANDBOX_MASK;
 
 	return 0;
 }
@@ -272,8 +314,8 @@
 	.set_value		= sb_gpio_set_value,
 	.get_function		= sb_gpio_get_function,
 	.xlate			= sb_gpio_xlate,
-	.set_dir_flags		= sb_gpio_set_dir_flags,
-	.get_dir_flags		= sb_gpio_get_dir_flags,
+	.set_flags		= sb_gpio_set_flags,
+	.get_flags		= sb_gpio_get_flags,
 #if CONFIG_IS_ENABLED(ACPIGEN)
 	.get_acpi		= sb_gpio_get_acpi,
 #endif
@@ -456,7 +498,7 @@
 	return pin_name;
 }
 
-static char *get_dir_flags_string(ulong flags)
+static char *get_flags_string(ulong flags)
 {
 	if (flags & GPIOD_OPEN_DRAIN)
 		return "drive-open-drain";
@@ -475,7 +517,7 @@
 {
 	struct udevice *gpio_dev;
 	unsigned int gpio_idx;
-	ulong dir_flags;
+	ulong flags;
 	int function;
 
 	/* look up for the bank which owns the requested pin */
@@ -484,11 +526,11 @@
 		snprintf(buf, size, "Error");
 	} else {
 		function = sb_gpio_get_function(gpio_dev, gpio_idx);
-		dir_flags = *get_gpio_dir_flags(gpio_dev, gpio_idx);
+		flags = *get_gpio_flags(gpio_dev, gpio_idx);
 
 		snprintf(buf, size, "gpio %s %s",
 			 function == GPIOF_OUTPUT ? "output" : "input",
-			 get_dir_flags_string(dir_flags));
+			 get_flags_string(flags));
 	}
 
 	return 0;
diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c
index 7184db3..125c237 100644
--- a/drivers/gpio/stm32_gpio.c
+++ b/drivers/gpio/stm32_gpio.c
@@ -191,8 +191,8 @@
 	return GPIOF_FUNC;
 }
 
-static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
-				    ulong flags)
+static int stm32_gpio_set_flags(struct udevice *dev, unsigned int offset,
+				ulong flags)
 {
 	struct stm32_gpio_priv *priv = dev_get_priv(dev);
 	struct stm32_gpio_regs *regs = priv->regs;
@@ -203,12 +203,13 @@
 		return idx;
 
 	if (flags & GPIOD_IS_OUT) {
-		int value = GPIOD_FLAGS_OUTPUT(flags);
+		bool value = flags & GPIOD_IS_OUT_ACTIVE;
 
 		if (flags & GPIOD_OPEN_DRAIN)
 			stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_OD);
 		else
 			stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_PP);
+
 		stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT);
 		writel(BSRR_BIT(idx, value), &regs->bsrr);
 
@@ -223,8 +224,8 @@
 	return 0;
 }
 
-static int stm32_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
-				    ulong *flags)
+static int stm32_gpio_get_flags(struct udevice *dev, unsigned int offset,
+				ulong *flagsp)
 {
 	struct stm32_gpio_priv *priv = dev_get_priv(dev);
 	struct stm32_gpio_regs *regs = priv->regs;
@@ -259,7 +260,7 @@
 	default:
 		break;
 	}
-	*flags = dir_flags;
+	*flagsp = dir_flags;
 
 	return 0;
 }
@@ -270,8 +271,8 @@
 	.get_value		= stm32_gpio_get_value,
 	.set_value		= stm32_gpio_set_value,
 	.get_function		= stm32_gpio_get_function,
-	.set_dir_flags		= stm32_gpio_set_dir_flags,
-	.get_dir_flags		= stm32_gpio_get_dir_flags,
+	.set_flags		= stm32_gpio_set_flags,
+	.get_flags		= stm32_gpio_get_flags,
 };
 
 static int gpio_stm32_probe(struct udevice *dev)
diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c
index 1a8d0a3..fe7a59d 100644
--- a/drivers/pinctrl/pinctrl-stmfx.c
+++ b/drivers/pinctrl/pinctrl-stmfx.c
@@ -163,12 +163,14 @@
 	return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 1);
 }
 
-static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
-				    ulong flags)
+static int stmfx_gpio_set_flags(struct udevice *dev, unsigned int offset,
+				ulong flags)
 {
 	int ret = -ENOTSUPP;
 
 	if (flags & GPIOD_IS_OUT) {
+		bool value = flags & GPIOD_IS_OUT_ACTIVE;
+
 		if (flags & GPIOD_OPEN_SOURCE)
 			return -ENOTSUPP;
 		if (flags & GPIOD_OPEN_DRAIN)
@@ -177,8 +179,7 @@
 			ret = stmfx_conf_set_type(dev, offset, 1);
 		if (ret)
 			return ret;
-		ret = stmfx_gpio_direction_output(dev, offset,
-						  GPIOD_FLAGS_OUTPUT(flags));
+		ret = stmfx_gpio_direction_output(dev, offset, value);
 	} else if (flags & GPIOD_IS_IN) {
 		ret = stmfx_gpio_direction_input(dev, offset);
 		if (ret)
@@ -199,8 +200,8 @@
 	return ret;
 }
 
-static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
-				    ulong *flags)
+static int stmfx_gpio_get_flags(struct udevice *dev, unsigned int offset,
+				ulong *flagsp)
 {
 	ulong dir_flags = 0;
 	int ret;
@@ -233,7 +234,7 @@
 				dir_flags |= GPIOD_PULL_DOWN;
 		}
 	}
-	*flags = dir_flags;
+	*flagsp = dir_flags;
 
 	return 0;
 }
@@ -266,8 +267,8 @@
 	.get_function = stmfx_gpio_get_function,
 	.direction_input = stmfx_gpio_direction_input,
 	.direction_output = stmfx_gpio_direction_output,
-	.set_dir_flags = stmfx_gpio_set_dir_flags,
-	.get_dir_flags = stmfx_gpio_get_dir_flags,
+	.set_flags = stmfx_gpio_set_flags,
+	.get_flags = stmfx_gpio_get_flags,
 };
 
 U_BOOT_DRIVER(stmfx_gpio) = {
diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c
index 6c9dc7a..9512f68 100644
--- a/drivers/sysreset/sysreset-uclass.c
+++ b/drivers/sysreset/sysreset-uclass.c
@@ -113,7 +113,7 @@
 /**
  * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
  */
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	sysreset_walk_halt(SYSRESET_WARM);
 }
diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig
index 65622f3..d030280 100644
--- a/drivers/tee/optee/Kconfig
+++ b/drivers/tee/optee/Kconfig
@@ -31,6 +31,12 @@
 	  permits to test reverse RPC calls to TEE supplicant. Should
 	  be used only in sandbox env.
 
+config OPTEE_TA_SCP03
+	bool "Support SCP03 TA"
+	default y
+	help
+	  Enables support for controlling (enabling, provisioning) the
+	  Secure Channel Protocol 03 operation in the OP-TEE SCP03 TA.
 endmenu
 
 endif
diff --git a/drivers/tee/sandbox.c b/drivers/tee/sandbox.c
index 3a1d34d..35e8542 100644
--- a/drivers/tee/sandbox.c
+++ b/drivers/tee/sandbox.c
@@ -8,6 +8,7 @@
 #include <tee.h>
 #include <tee/optee_ta_avb.h>
 #include <tee/optee_ta_rpc_test.h>
+#include <tee/optee_ta_scp03.h>
 
 #include "optee/optee_msg.h"
 #include "optee/optee_private.h"
@@ -68,6 +69,7 @@
 	return NULL;
 }
 
+#if defined(CONFIG_OPTEE_TA_SCP03) || defined(CONFIG_OPTEE_TA_AVB)
 static u32 get_attr(uint n, uint num_params, struct tee_param *params)
 {
 	if (n >= num_params)
@@ -79,7 +81,7 @@
 static u32 check_params(u8 p0, u8 p1, u8 p2, u8 p3, uint num_params,
 			struct tee_param *params)
 {
-	u8 p[] = { p0, p1, p2, p3};
+	u8 p[] = { p0, p1, p2, p3 };
 	uint n;
 
 	for (n = 0; n < ARRAY_SIZE(p); n++)
@@ -97,6 +99,50 @@
 
 	return TEE_ERROR_BAD_PARAMETERS;
 }
+#endif
+
+#ifdef CONFIG_OPTEE_TA_SCP03
+static u32 pta_scp03_open_session(struct udevice *dev, uint num_params,
+				  struct tee_param *params)
+{
+	/*
+	 * We don't expect additional parameters when opening a session to
+	 * this TA.
+	 */
+	return check_params(TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
+			    TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
+			    num_params, params);
+}
+
+static u32 pta_scp03_invoke_func(struct udevice *dev, u32 func, uint num_params,
+				 struct tee_param *params)
+{
+	u32 res;
+	static bool enabled;
+
+	switch (func) {
+	case PTA_CMD_ENABLE_SCP03:
+		res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_INPUT,
+				   TEE_PARAM_ATTR_TYPE_NONE,
+				   TEE_PARAM_ATTR_TYPE_NONE,
+				   TEE_PARAM_ATTR_TYPE_NONE,
+				   num_params, params);
+		if (res)
+			return res;
+
+		if (!enabled) {
+			enabled = true;
+		} else {
+		}
+
+		if (params[0].u.value.a)
+
+		return TEE_SUCCESS;
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+}
+#endif
 
 #ifdef CONFIG_OPTEE_TA_AVB
 static u32 ta_avb_open_session(struct udevice *dev, uint num_params,
@@ -357,6 +403,12 @@
 	  .invoke_func = ta_rpc_test_invoke_func,
 	},
 #endif
+#ifdef CONFIG_OPTEE_TA_SCP03
+	{ .uuid = PTA_SCP03_UUID,
+	  .open_session = pta_scp03_open_session,
+	  .invoke_func = pta_scp03_invoke_func,
+	},
+#endif
 };
 
 static void sandbox_tee_get_version(struct udevice *dev,
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index 8f075b9..f64d200 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -10,7 +10,7 @@
 obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o
 obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o
 
-obj-$(CONFIG_TPM2_CR50_I2C) += cr50_i2c.o
+obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o
 obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o
 obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_spi.o
 obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o
diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index b103a6f..76432bd 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -309,7 +309,7 @@
 	int status;
 	int ret;
 
-	log_debug("%s: len=%x\n", __func__, buf_len);
+	log_debug("%s: buf_len=%x\n", __func__, buf_len);
 	if (buf_len < TPM_HEADER_SIZE)
 		return -E2BIG;
 
@@ -386,7 +386,7 @@
 	ulong timeout;
 	int ret;
 
-	log_debug("%s: len=%x\n", __func__, len);
+	log_debug("len=%x\n", len);
 	timeout = timer_get_us() + TIMEOUT_LONG_US;
 	do {
 		ret = cr50_i2c_status(dev);
diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c
index beb0fa3..35774a6 100644
--- a/drivers/tpm/tpm-uclass.c
+++ b/drivers/tpm/tpm-uclass.c
@@ -4,6 +4,8 @@
  * Written by Simon Glass <sjg@chromium.org>
  */
 
+#define LOG_CATEGORY UCLASS_TPM
+
 #include <common.h>
 #include <dm.h>
 #include <log.h>
@@ -87,15 +89,15 @@
 	ordinal = get_unaligned_be32(sendbuf + TPM_CMD_ORDINAL_BYTE);
 
 	if (count == 0) {
-		debug("no data\n");
+		log_debug("no data\n");
 		return -ENODATA;
 	}
 	if (count > send_size) {
-		debug("invalid count value %x %zx\n", count, send_size);
+		log_debug("invalid count value %x %zx\n", count, send_size);
 		return -E2BIG;
 	}
 
-	debug("%s: Calling send\n", __func__);
+	log_debug("%s: Calling send\n", __func__);
 	ret = ops->send(dev, sendbuf, send_size);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index c74bacf..24c804a 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -285,7 +285,7 @@
 	length = get_unaligned_be32(sent);
 	sent += sizeof(length);
 	if (length != send_size) {
-		printf("TPM2: Unmatching length, received: %ld, expected: %d\n",
+		printf("TPM2: Unmatching length, received: %zd, expected: %d\n",
 		       send_size, length);
 		rc = TPM2_RC_SIZE;
 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index f52aba4..4361a58 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -7,6 +7,8 @@
  */
 
 #include <common.h>
+#include <display.h>
+#include <dm.h>
 #include <cpu_func.h>
 #include <efi_loader.h>
 #include <init.h>
@@ -28,7 +30,9 @@
 #include <fdt_support.h>
 #include <i2c.h>
 #include <malloc.h>
+#include <video.h>
 #include <video_fb.h>
+#include <dm/uclass-internal.h>
 #include "../videomodes.h"
 #include "../anx9804.h"
 #include "../hitachi_tx18d42vm_lcd.h"
@@ -45,6 +49,11 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/* Maximum LCD size we support */
+#define LCD_MAX_WIDTH		3840
+#define LCD_MAX_HEIGHT		2160
+#define LCD_MAX_LOG2_BPP	VIDEO_BPP32
+
 enum sunxi_monitor {
 	sunxi_monitor_none,
 	sunxi_monitor_dvi,
@@ -58,13 +67,12 @@
 };
 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
 
-struct sunxi_display {
-	GraphicDevice graphic_device;
+struct sunxi_display_priv {
 	enum sunxi_monitor monitor;
 	unsigned int depth;
 	unsigned int fb_addr;
 	unsigned int fb_size;
-} sunxi_display;
+};
 
 const struct ctfb_res_modes composite_video_modes[2] = {
 	/*  x     y  hz  pixclk ps/kHz   le   ri  up  lo   hs vs  s  vmode */
@@ -214,7 +222,8 @@
 	return r;
 }
 
-static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
+static int sunxi_hdmi_edid_get_mode(struct sunxi_display_priv *sunxi_display,
+				    struct ctfb_res_modes *mode,
 				    bool verbose_mode)
 {
 	struct edid1_info edid1;
@@ -291,14 +300,14 @@
 	}
 
 	/* Check for basic audio support, if found enable hdmi output */
-	sunxi_display.monitor = sunxi_monitor_dvi;
+	sunxi_display->monitor = sunxi_monitor_dvi;
 	for (i = 0; i < ext_blocks; i++) {
 		if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
 		    cea681[i].revision < 2)
 			continue;
 
 		if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
-			sunxi_display.monitor = sunxi_monitor_hdmi;
+			sunxi_display->monitor = sunxi_monitor_hdmi;
 	}
 
 	return 0;
@@ -414,9 +423,9 @@
 static void sunxi_frontend_enable(void) {}
 #endif
 
-static bool sunxi_is_composite(void)
+static bool sunxi_is_composite(enum sunxi_monitor monitor)
 {
-	switch (sunxi_display.monitor) {
+	switch (monitor) {
 	case sunxi_monitor_none:
 	case sunxi_monitor_dvi:
 	case sunxi_monitor_hdmi:
@@ -473,7 +482,8 @@
 };
 
 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
-				    unsigned int address)
+				    unsigned int address,
+				    enum sunxi_monitor monitor)
 {
 	struct sunxi_de_be_reg * const de_be =
 		(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
@@ -502,7 +512,7 @@
 #endif
 			     SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
 
-	if (sunxi_is_composite()) {
+	if (sunxi_is_composite(monitor)) {
 		writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
 		       &de_be->output_color_ctrl);
 		for (i = 0; i < 12; i++)
@@ -616,7 +626,8 @@
 		gpio_direction_output(pin, PWM_ON);
 }
 
-static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
+static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display_priv *sunxi_display,
+				      const struct ctfb_res_modes *mode,
 				      bool for_ext_vga_dac)
 {
 	struct sunxi_lcdc_reg * const lcdc =
@@ -643,17 +654,18 @@
 	}
 
 	lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
-		     sunxi_is_composite());
+		     sunxi_is_composite(sunxi_display->monitor));
 
 	video_ctfb_mode_to_display_timing(mode, &timing);
 	lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
-			    sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
+			    sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
 }
 
 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
 				      int *clk_div, int *clk_double,
-				      bool use_portd_hvsync)
+				      bool use_portd_hvsync,
+				      enum sunxi_monitor monitor)
 {
 	struct sunxi_lcdc_reg * const lcdc =
 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
@@ -663,7 +675,7 @@
 
 	video_ctfb_mode_to_display_timing(mode, &timing);
 	lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
-			    sunxi_is_composite());
+			    sunxi_is_composite(monitor));
 
 	if (use_portd_hvsync) {
 		sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
@@ -671,7 +683,7 @@
 	}
 
 	lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
-		     sunxi_is_composite());
+		     sunxi_is_composite(monitor));
 }
 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
 
@@ -725,7 +737,8 @@
 }
 
 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
-				int clk_div, int clk_double)
+				int clk_div, int clk_double,
+				enum sunxi_monitor monitor)
 {
 	struct sunxi_hdmi_reg * const hdmi =
 		(struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
@@ -734,7 +747,7 @@
 	/* Write clear interrupt status bits */
 	writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
 
-	if (sunxi_display.monitor == sunxi_monitor_hdmi)
+	if (monitor == sunxi_monitor_hdmi)
 		sunxi_hdmi_setup_info_frames(mode);
 
 	/* Set input sync enable */
@@ -789,7 +802,7 @@
 
 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
 
-static void sunxi_tvencoder_mode_set(void)
+static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor)
 {
 	struct sunxi_ccm_reg * const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
@@ -801,7 +814,7 @@
 	/* Clock on */
 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
 
-	switch (sunxi_display.monitor) {
+	switch (monitor) {
 	case sunxi_monitor_vga:
 		tvencoder_mode_set(tve, tve_mode_vga);
 		break;
@@ -896,26 +909,28 @@
 	sunxi_drc_init();
 }
 
-static void sunxi_mode_set(const struct ctfb_res_modes *mode,
+static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display,
+			   const struct ctfb_res_modes *mode,
 			   unsigned int address)
 {
+	enum sunxi_monitor monitor = sunxi_display->monitor;
 	int __maybe_unused clk_div, clk_double;
 	struct sunxi_lcdc_reg * const lcdc =
 		(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
 	struct sunxi_tve_reg * __maybe_unused const tve =
 		(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
 
-	switch (sunxi_display.monitor) {
+	switch (sunxi_display->monitor) {
 	case sunxi_monitor_none:
 		break;
 	case sunxi_monitor_dvi:
 	case sunxi_monitor_hdmi:
 #ifdef CONFIG_VIDEO_HDMI
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
-		sunxi_hdmi_mode_set(mode, clk_div, clk_double);
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
+		sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 		sunxi_hdmi_enable();
 #endif
 		break;
@@ -930,7 +945,7 @@
 			axp_set_eldo(3, 1800);
 			anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
 				     ANX9804_DATA_RATE_1620M,
-				     sunxi_display.depth);
+				     sunxi_display->depth);
 		}
 		if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
 			mdelay(50); /* Wait for lcd controller power on */
@@ -942,10 +957,10 @@
 			i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
 			i2c_set_bus_num(orig_i2c_bus);
 		}
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon0_mode_set(mode, false);
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 #ifdef CONFIG_VIDEO_LCD_SSD2828
 		sunxi_ssd2828_init(mode);
 #endif
@@ -953,17 +968,17 @@
 		break;
 	case sunxi_monitor_vga:
 #ifdef CONFIG_VIDEO_VGA
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
-		sunxi_tvencoder_mode_set();
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor);
+		sunxi_tvencoder_mode_set(monitor);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 		tvencoder_enable(tve);
 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon0_mode_set(mode, true);
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 		sunxi_vga_external_dac_enable();
 #endif
 		break;
@@ -972,11 +987,11 @@
 	case sunxi_monitor_composite_pal_m:
 	case sunxi_monitor_composite_pal_nc:
 #ifdef CONFIG_VIDEO_COMPOSITE
-		sunxi_composer_mode_set(mode, address);
-		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
-		sunxi_tvencoder_mode_set();
+		sunxi_composer_mode_set(mode, address, monitor);
+		sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
+		sunxi_tvencoder_mode_set(monitor);
 		sunxi_composer_enable();
-		lcdc_enable(lcdc, sunxi_display.depth);
+		lcdc_enable(lcdc, sunxi_display->depth);
 		tvencoder_enable(tve);
 #endif
 		break;
@@ -999,11 +1014,6 @@
 	}
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
-{
-	return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
-}
-
 static bool sunxi_has_hdmi(void)
 {
 #ifdef CONFIG_VIDEO_HDMI
@@ -1052,9 +1062,11 @@
 		return sunxi_monitor_none;
 }
 
-void *video_hw_init(void)
+static int sunxi_de_probe(struct udevice *dev)
 {
-	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+	struct sunxi_display_priv *sunxi_display = dev_get_priv(dev);
 	const struct ctfb_res_modes *mode;
 	struct ctfb_res_modes custom;
 	const char *options;
@@ -1067,10 +1079,8 @@
 	char mon[16];
 	char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
 
-	memset(&sunxi_display, 0, sizeof(struct sunxi_display));
-
 	video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
-				 &sunxi_display.depth, &options);
+				 &sunxi_display->depth, &options);
 #ifdef CONFIG_VIDEO_HDMI
 	hpd = video_get_option_int(options, "hpd", 1);
 	hpd_delay = video_get_option_int(options, "hpd_delay", 500);
@@ -1078,35 +1088,35 @@
 #endif
 	overscan_x = video_get_option_int(options, "overscan_x", -1);
 	overscan_y = video_get_option_int(options, "overscan_y", -1);
-	sunxi_display.monitor = sunxi_get_default_mon(true);
+	sunxi_display->monitor = sunxi_get_default_mon(true);
 	video_get_option_string(options, "monitor", mon, sizeof(mon),
-				sunxi_get_mon_desc(sunxi_display.monitor));
+				sunxi_get_mon_desc(sunxi_display->monitor));
 	for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
 		if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
-			sunxi_display.monitor = i;
+			sunxi_display->monitor = i;
 			break;
 		}
 	}
 	if (i > SUNXI_MONITOR_LAST)
 		printf("Unknown monitor: '%s', falling back to '%s'\n",
-		       mon, sunxi_get_mon_desc(sunxi_display.monitor));
+		       mon, sunxi_get_mon_desc(sunxi_display->monitor));
 
 #ifdef CONFIG_VIDEO_HDMI
 	/* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
-	if (sunxi_display.monitor == sunxi_monitor_dvi ||
-	    sunxi_display.monitor == sunxi_monitor_hdmi) {
+	if (sunxi_display->monitor == sunxi_monitor_dvi ||
+	    sunxi_display->monitor == sunxi_monitor_hdmi) {
 		/* Always call hdp_detect, as it also enables clocks, etc. */
 		hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
 		if (hdmi_present && edid) {
 			printf("HDMI connected: ");
-			if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
+			if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0)
 				mode = &custom;
 			else
 				hdmi_present = false;
 		}
 		/* Fall back to EDID in case HPD failed */
 		if (edid && !hdmi_present) {
-			if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
+			if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) {
 				mode = &custom;
 				hdmi_present = true;
 			}
@@ -1114,38 +1124,39 @@
 		/* Shut down when display was not found */
 		if ((hpd || edid) && !hdmi_present) {
 			sunxi_hdmi_shutdown();
-			sunxi_display.monitor = sunxi_get_default_mon(false);
+			sunxi_display->monitor = sunxi_get_default_mon(false);
 		} /* else continue with hdmi/dvi without a cable connected */
 	}
 #endif
 
-	switch (sunxi_display.monitor) {
+	switch (sunxi_display->monitor) {
 	case sunxi_monitor_none:
-		return NULL;
+		printf("Unknown monitor\n");
+		return -EINVAL;
 	case sunxi_monitor_dvi:
 	case sunxi_monitor_hdmi:
 		if (!sunxi_has_hdmi()) {
 			printf("HDMI/DVI not supported on this board\n");
-			sunxi_display.monitor = sunxi_monitor_none;
-			return NULL;
+			sunxi_display->monitor = sunxi_monitor_none;
+			return -EINVAL;
 		}
 		break;
 	case sunxi_monitor_lcd:
 		if (!sunxi_has_lcd()) {
 			printf("LCD not supported on this board\n");
-			sunxi_display.monitor = sunxi_monitor_none;
-			return NULL;
+			sunxi_display->monitor = sunxi_monitor_none;
+			return -EINVAL;
 		}
-		sunxi_display.depth = video_get_params(&custom, lcd_mode);
+		sunxi_display->depth = video_get_params(&custom, lcd_mode);
 		mode = &custom;
 		break;
 	case sunxi_monitor_vga:
 		if (!sunxi_has_vga()) {
 			printf("VGA not supported on this board\n");
-			sunxi_display.monitor = sunxi_monitor_none;
-			return NULL;
+			sunxi_display->monitor = sunxi_monitor_none;
+			return -EINVAL;
 		}
-		sunxi_display.depth = 18;
+		sunxi_display->depth = 18;
 		break;
 	case sunxi_monitor_composite_pal:
 	case sunxi_monitor_composite_ntsc:
@@ -1153,85 +1164,99 @@
 	case sunxi_monitor_composite_pal_nc:
 		if (!sunxi_has_composite()) {
 			printf("Composite video not supported on this board\n");
-			sunxi_display.monitor = sunxi_monitor_none;
-			return NULL;
+			sunxi_display->monitor = sunxi_monitor_none;
+			return -EINVAL;
 		}
-		if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
-		    sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
+		if (sunxi_display->monitor == sunxi_monitor_composite_pal ||
+		    sunxi_display->monitor == sunxi_monitor_composite_pal_nc)
 			mode = &composite_video_modes[0];
 		else
 			mode = &composite_video_modes[1];
-		sunxi_display.depth = 24;
+		sunxi_display->depth = 24;
 		break;
 	}
 
 	/* Yes these defaults are quite high, overscan on composite sucks... */
 	if (overscan_x == -1)
-		overscan_x = sunxi_is_composite() ? 32 : 0;
+		overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0;
 	if (overscan_y == -1)
-		overscan_y = sunxi_is_composite() ? 20 : 0;
+		overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0;
 
-	sunxi_display.fb_size =
-		(mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
+	sunxi_display->fb_size = plat->size;
 	overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
 	/* We want to keep the fb_base for simplefb page aligned, where as
 	 * the sunxi dma engines will happily accept an unaligned address. */
 	if (overscan_offset)
-		sunxi_display.fb_size += 0x1000;
-
-	if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
-		printf("Error need %dkB for fb, but only %dkB is reserved\n",
-		       sunxi_display.fb_size >> 10,
-		       CONFIG_SUNXI_MAX_FB_SIZE >> 10);
-		return NULL;
-	}
+		sunxi_display->fb_size += 0x1000;
 
 	printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
 	       mode->xres, mode->yres,
 	       (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
-	       sunxi_get_mon_desc(sunxi_display.monitor),
+	       sunxi_get_mon_desc(sunxi_display->monitor),
 	       overscan_x, overscan_y);
 
-	gd->fb_base = gd->bd->bi_dram[0].start +
-		      gd->bd->bi_dram[0].size - sunxi_display.fb_size;
+	sunxi_display->fb_addr = plat->base;
 	sunxi_engines_init();
 
 #ifdef CONFIG_EFI_LOADER
-	efi_add_memory_map(gd->fb_base, sunxi_display.fb_size,
+	efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size,
 			   EFI_RESERVED_MEMORY_TYPE);
 #endif
 
-	fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
-	sunxi_display.fb_addr = gd->fb_base;
+	fb_dma_addr = sunxi_display->fb_addr - CONFIG_SYS_SDRAM_BASE;
 	if (overscan_offset) {
 		fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
-		sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
-		memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
-		flush_cache(gd->fb_base, sunxi_display.fb_size);
+		sunxi_display->fb_addr += ALIGN(overscan_offset, 0x1000);
+		memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size);
+		flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size);
 	}
-	sunxi_mode_set(mode, fb_dma_addr);
+	sunxi_mode_set(sunxi_display, mode, fb_dma_addr);
 
-	/*
-	 * These are the only members of this structure that are used. All the
-	 * others are driver specific. The pitch is stored in plnSizeX.
-	 */
-	graphic_device->frameAdrs = sunxi_display.fb_addr;
-	graphic_device->gdfIndex = GDF_32BIT_X888RGB;
-	graphic_device->gdfBytesPP = 4;
-	graphic_device->winSizeX = mode->xres - 2 * overscan_x;
-	graphic_device->winSizeY = mode->yres - 2 * overscan_y;
-	graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
+	/* The members of struct video_priv to be set by the driver. */
+	uc_priv->bpix = VIDEO_BPP32;
+	uc_priv->xsize = mode->xres;
+	uc_priv->ysize = mode->yres;
 
-	return graphic_device;
+	video_set_flush_dcache(dev, true);
+
+	return 0;
 }
 
+static int sunxi_de_bind(struct udevice *dev)
+{
+	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+	plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * VNBYTES(LCD_MAX_LOG2_BPP);
+
+	return 0;
+}
+
+static const struct video_ops sunxi_de_ops = {
+};
+
+U_BOOT_DRIVER(sunxi_de) = {
+	.name	= "sunxi_de",
+	.id	= UCLASS_VIDEO,
+	.ops	= &sunxi_de_ops,
+	.bind	= sunxi_de_bind,
+	.probe	= sunxi_de_probe,
+	.priv_auto = sizeof(struct sunxi_display_priv),
+	.flags	= DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRVINFO(sunxi_de) = {
+	.name = "sunxi_de"
+};
+
 /*
  * Simplefb support.
  */
 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
 int sunxi_simplefb_setup(void *blob)
 {
-	static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+	struct sunxi_display_priv *sunxi_display;
+	struct video_priv *uc_priv;
+	struct udevice *de;
 	int offset, ret;
 	u64 start, size;
 	const char *pipeline = NULL;
@@ -1242,7 +1267,19 @@
 #define PIPELINE_PREFIX
 #endif
 
-	switch (sunxi_display.monitor) {
+	ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de);
+	if (ret) {
+		printf("DE not present\n");
+		return 0;
+	} else if (!device_active(de)) {
+		printf("DE is present but not probed\n");
+		return 0;
+	}
+
+	uc_priv = dev_get_uclass_priv(de);
+	sunxi_display = dev_get_priv(de);
+
+	switch (sunxi_display->monitor) {
 	case sunxi_monitor_none:
 		return 0;
 	case sunxi_monitor_dvi:
@@ -1280,16 +1317,17 @@
 	 * linux/arch/arm/mm/ioremap.c around line 301.
 	 */
 	start = gd->bd->bi_dram[0].start;
-	size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
+	size = sunxi_display->fb_addr - start;
 	ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
 	if (ret) {
 		eprintf("Cannot setup simplefb: Error reserving memory\n");
 		return ret;
 	}
 
-	ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
-			graphic_device->winSizeX, graphic_device->winSizeY,
-			graphic_device->plnSizeX, "x8r8g8b8");
+	ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr,
+				      uc_priv->xsize, uc_priv->ysize,
+				      VNBYTES(uc_priv->bpix) * uc_priv->xsize,
+				      "x8r8g8b8");
 	if (ret)
 		eprintf("Cannot setup simplefb: Error setting properties\n");
 
diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c
index 5e0a096..3586246 100644
--- a/drivers/watchdog/imx_watchdog.c
+++ b/drivers/watchdog/imx_watchdog.c
@@ -44,7 +44,7 @@
 
 #if !defined(CONFIG_IMX_WATCHDOG) || \
     (defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT))
-void __attribute__((weak)) reset_cpu(ulong addr)
+void __attribute__((weak)) reset_cpu(void)
 {
 	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 
diff --git a/drivers/watchdog/ulp_wdog.c b/drivers/watchdog/ulp_wdog.c
index 7533fc6..6f63b11 100644
--- a/drivers/watchdog/ulp_wdog.c
+++ b/drivers/watchdog/ulp_wdog.c
@@ -77,7 +77,7 @@
 	hw_watchdog_reset();
 }
 
-void reset_cpu(ulong addr)
+void reset_cpu(void)
 {
 	struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
 
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index b6a9991..c24f5e0 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -410,6 +410,12 @@
 	 * This value is used as logging level for continuation messages.
 	 */
 	int logl_prev;
+	/**
+	 * @log_cont: Previous log line did not finished wtih \n
+	 *
+	 * This allows for chained log messages on the same line
+	 */
+	bool log_cont;
 #endif
 #if CONFIG_IS_ENABLED(BLOBLIST)
 	/**
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 82294cb..2cb0500 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -128,6 +128,12 @@
 #define GPIOD_PULL_UP		BIT(7)	/* GPIO has pull-up enabled */
 #define GPIOD_PULL_DOWN		BIT(8)	/* GPIO has pull-down enabled */
 
+/* Flags for updating the above */
+#define GPIOD_MASK_DIR		(GPIOD_IS_OUT | GPIOD_IS_IN | \
+					GPIOD_IS_OUT_ACTIVE)
+#define GPIOD_MASK_DSTYPE	(GPIOD_OPEN_DRAIN | GPIOD_OPEN_SOURCE)
+#define GPIOD_MASK_PULL		(GPIOD_PULL_UP | GPIOD_PULL_DOWN)
+
 	uint offset;		/* GPIO offset within the device */
 	/*
 	 * We could consider adding the GPIO label in here. Possibly we could
@@ -135,12 +141,6 @@
 	 */
 };
 
-/* helper to compute the value of the gpio output */
-#define GPIOD_FLAGS_OUTPUT_MASK (GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE)
-#define GPIOD_FLAGS_OUTPUT(flags) \
-	(((((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_IS_OUT_ACTIVE) || \
-	  (((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_ACTIVE_LOW)))
-
 /**
  * dm_gpio_is_valid() - Check if a GPIO is valid
  *
@@ -260,10 +260,32 @@
 struct dm_gpio_ops {
 	int (*request)(struct udevice *dev, unsigned offset, const char *label);
 	int (*rfree)(struct udevice *dev, unsigned int offset);
+
+	/**
+	 * direction_input() - deprecated
+	 *
+	 * Equivalent to set_flags(...GPIOD_IS_IN)
+	 */
 	int (*direction_input)(struct udevice *dev, unsigned offset);
+
+	/**
+	 * direction_output() - deprecated
+	 *
+	 * Equivalent to set_flags(...GPIOD_IS_OUT) with GPIOD_IS_OUT_ACTIVE
+	 * also set if @value
+	 */
 	int (*direction_output)(struct udevice *dev, unsigned offset,
 				int value);
+
 	int (*get_value)(struct udevice *dev, unsigned offset);
+
+	/**
+	 * set_value() - Sets the GPIO value of an output
+	 *
+	 * If the driver provides an @set_flags() method then that is used
+	 * in preference to this, with GPIOD_IS_OUT_ACTIVE set according to
+	 * @value.
+	 */
 	int (*set_value)(struct udevice *dev, unsigned offset, int value);
 	/**
 	 * get_function() Get the GPIO function
@@ -301,35 +323,54 @@
 		     struct ofnode_phandle_args *args);
 
 	/**
-	 * set_dir_flags() - Set GPIO dir flags
+	 * set_flags() - Adjust GPIO flags
 	 *
 	 * This function should set up the GPIO configuration according to the
-	 * information provide by the direction flags bitfield.
+	 * information provided by @flags.
 	 *
-	 * This method is optional.
+	 * If any flags cannot be set (e.g. the driver or hardware does not
+	 * support them or this particular GPIO does not have the requested
+	 * feature), the driver should return -EINVAL.
+	 *
+	 * The uclass checks that flags do not obviously conflict (e.g. input
+	 * and output). If the driver finds other conflicts it should return
+	 * -ERECALLCONFLICT
+	 *
+	 * Note that GPIOD_ACTIVE_LOW should be ignored, since the uclass
+	 * adjusts for it automatically. For example, for an output GPIO,
+	 * GPIOD_ACTIVE_LOW causes GPIOD_IS_OUT_ACTIVE to be inverted by the
+	 * uclass, so the driver always sees the value that should be set at the
+	 * pin (1=high, 0=low).
+	 *
+	 * This method is required and should be implemented by new drivers. At
+	 * some point, it will supersede direction_input() and
+	 * direction_output(), which wil be removed.
 	 *
 	 * @dev:	GPIO device
 	 * @offset:	GPIO offset within that device
-	 * @flags:	GPIO configuration to use
-	 * @return 0 if OK, -ve on error
+	 * @flags:	New flags value (GPIOD_...)
+	 *
+	 * @return 0 if OK, -EINVAL if unsupported, -ERECALLCONFLICT if flags
+	 *	conflict in some *	non-obvious way and were not applied,
+	 *	other -ve on error
 	 */
-	int (*set_dir_flags)(struct udevice *dev, unsigned int offset,
-			     ulong flags);
+	int (*set_flags)(struct udevice *dev, unsigned int offset, ulong flags);
 
 	/**
-	 * get_dir_flags() - Get GPIO dir flags
+	 * get_flags() - Get GPIO flags
 	 *
-	 * This function return the GPIO direction flags used.
+	 * This function return the GPIO flags used. It should read this from
+	 * the hardware directly.
 	 *
 	 * This method is optional.
 	 *
 	 * @dev:	GPIO device
 	 * @offset:	GPIO offset within that device
-	 * @flags:	place to put the used direction flags by GPIO
+	 * @flagsp:	place to put the current flags value
 	 * @return 0 if OK, -ve on error
 	 */
-	int (*get_dir_flags)(struct udevice *dev, unsigned int offset,
-			     ulong *flags);
+	int (*get_flags)(struct udevice *dev, unsigned int offset,
+			 ulong *flagsp);
 
 #if CONFIG_IS_ENABLED(ACPIGEN)
 	/**
@@ -457,6 +498,31 @@
 int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count);
 
 /**
+ * dm_gpio_get_values_as_int_base3() - Create a base-3 int from a list of GPIOs
+ *
+ * This uses pull-ups/pull-downs to figure out whether a GPIO line is externally
+ * pulled down, pulled up or floating. This allows three different strap values
+ * for each pin:
+ *    0 : external pull-down
+ *    1 : external pull-up
+ *    2 : floating
+ *
+ * With this it is possible to obtain more combinations from the same number of
+ * strapping pins, when compared to dm_gpio_get_values_as_int(). The external
+ * pull resistors should be made stronger that the internal SoC pull resistors,
+ * for this to work.
+ *
+ * With 2 pins, 6 combinations are possible, compared with 4
+ * With 3 pins, 27 are possible, compared with 8
+ *
+ * @desc_list: List of GPIOs to collect
+ * @count: Number of GPIOs
+ * @return resulting integer value, or -ve on error
+ */
+int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list,
+				    int count);
+
+/**
  * gpio_claim_vector() - claim a number of GPIOs for input
  *
  * @gpio_num_array:	array of gpios to claim, terminated by -1
@@ -652,6 +718,25 @@
 int dm_gpio_set_dir(struct gpio_desc *desc);
 
 /**
+ * dm_gpio_clrset_flags() - Update flags
+ *
+ * This updates the flags as directled. Note that desc->flags is updated by this
+ * function on success. If any changes cannot be made, best efforts are made.
+ *
+ * By use of @clr and @set any of flags can be individually updated, or left
+ * alone
+ *
+ * @desc:	GPIO description containing device, offset and flags,
+ *		previously returned by gpio_request_by_name()
+ * @clr:	Flags to clear (GPIOD_...)
+ * @set:	Flags to set (GPIOD_...)
+ * @return 0 if OK, -EINVAL if the flags had obvious conflicts,
+ * -ERECALLCONFLICT if there was a non-obvious hardware conflict when attempting
+ * to set the flags
+ */
+int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set);
+
+/**
  * dm_gpio_set_dir_flags() - Set direction using description and added flags
  *
  * This sets up the direction according to the provided flags and the GPIO
@@ -666,16 +751,31 @@
 int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags);
 
 /**
- * dm_gpio_get_dir_flags() - Get direction flags
+ * dm_gpios_clrset_flags() - Sets flags for a set of GPIOs
  *
- * read the current direction flags
+ * This clears and sets flags individually for each GPIO.
+ *
+ * @desc:	List of GPIOs to update
+ * @count:	Number of GPIOs in the list
+ * @clr:	Flags to clear (GPIOD_...), e.g. GPIOD_MASK_DIR if you are
+ *		changing the direction
+ * @set:	Flags to set (GPIOD_...)
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr,
+			  ulong set);
+
+/**
+ * dm_gpio_get_flags() - Get flags
+ *
+ * Read the current flags
  *
  * @desc:	GPIO description containing device, offset and flags,
  *		previously returned by gpio_request_by_name()
  * @flags:	place to put the used flags
  * @return 0 if OK, -ve on error, in which case desc->flags is not updated
  */
-int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags);
+int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flags);
 
 /**
  * gpio_get_number() - Get the global GPIO number of a GPIO
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 7b602dd..33a4d7b 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -223,23 +223,6 @@
 #define CONFIG_VIDEO_LCD_I2C_BUS	-1 /* NA, but necessary to compile */
 #endif
 
-#ifdef CONFIG_VIDEO_SUNXI
-/*
- * The amount of RAM to keep free at the top of RAM when relocating u-boot,
- * to use as framebuffer. This must be a multiple of 4096.
- */
-#define CONFIG_SUNXI_MAX_FB_SIZE (16 << 20)
-
-#define CONFIG_VIDEO_LOGO
-#define CONFIG_VIDEO_STD_TIMINGS
-#define CONFIG_I2C_EDID
-#define VIDEO_LINE_LEN (pGD->plnSizeX)
-
-/* allow both serial and cfb console. */
-/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */
-
-#endif /* CONFIG_VIDEO_SUNXI */
-
 /* Ethernet support */
 
 #ifdef CONFIG_USB_EHCI_HCD
@@ -401,11 +384,7 @@
 	"stdin=serial\0"
 #endif
 
-#ifdef CONFIG_VIDEO
-#define CONSOLE_STDOUT_SETTINGS \
-	"stdout=serial,vga\0" \
-	"stderr=serial,vga\0"
-#elif CONFIG_DM_VIDEO
+#ifdef CONFIG_DM_VIDEO
 #define CONSOLE_STDOUT_SETTINGS \
 	"stdout=serial,vidconsole\0" \
 	"stderr=serial,vidconsole\0"
diff --git a/include/cpu_func.h b/include/cpu_func.h
index 8aa825d..c3a66f0 100644
--- a/include/cpu_func.h
+++ b/include/cpu_func.h
@@ -84,6 +84,6 @@
  */
 int cleanup_before_linux_select(int flags);
 
-void reset_cpu(ulong addr);
-;
+void reset_cpu(void);
+
 #endif
diff --git a/include/dm/test.h b/include/dm/test.h
index 6ac6672..fe1cc2e 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -125,25 +125,9 @@
 
 extern struct unit_test_state global_dm_test_state;
 
-/*
- * struct dm_test_state - Entire state of dm test system
- *
- * This is often abreviated to dms.
- *
- * @root: Root device
- * @testdev: Test device
- * @force_fail_alloc: Force all memory allocs to fail
- * @skip_post_probe: Skip uclass post-probe processing
- */
-struct dm_test_state {
-	struct udevice *root;
-	struct udevice *testdev;
-	int force_fail_alloc;
-	int skip_post_probe;
-};
-
 /* Declare a new driver model test */
-#define DM_TEST(_name, _flags)	UNIT_TEST(_name, _flags, dm_test)
+#define DM_TEST(_name, _flags) \
+	UNIT_TEST(_name, UT_TESTF_DM | UT_TESTF_CONSOLE_REC | (_flags), dm_test)
 
 /*
  * struct sandbox_sdl_plat - Platform data for the SDL video driver
diff --git a/include/log.h b/include/log.h
index 2d27f9f..6ef891d 100644
--- a/include/log.h
+++ b/include/log.h
@@ -316,12 +316,40 @@
 		    __ret); \
 	__ret; \
 	})
+
+/*
+ * Similar to the above, but any non-zero value is consider an error, not just
+ * values less than 0.
+ */
+#define log_retz(_ret) ({ \
+	int __ret = (_ret); \
+	if (__ret) \
+		log(LOG_CATEGORY, LOGL_ERR, "returning err=%d\n", __ret); \
+	__ret; \
+	})
+#define log_msg_retz(_msg, _ret) ({ \
+	int __ret = (_ret); \
+	if (__ret) \
+		log(LOG_CATEGORY, LOGL_ERR, "%s: returning err=%d\n", _msg, \
+		    __ret); \
+	__ret; \
+	})
 #else
 /* Non-logging versions of the above which just return the error code */
 #define log_ret(_ret) (_ret)
 #define log_msg_ret(_msg, _ret) ((void)(_msg), _ret)
+#define log_retz(_ret) (_ret)
+#define log_msg_retz(_msg, _ret) ((void)(_msg), _ret)
 #endif
 
+/** * enum log_rec_flags - Flags for a log record */
+enum log_rec_flags {
+	/** @LOGRECF_FORCE_DEBUG: Force output of debug record */
+	LOGRECF_FORCE_DEBUG	= BIT(0),
+	/** @LOGRECF_CONT: Continuation of previous log record */
+	LOGRECF_CONT		= BIT(1),
+};
+
 /**
  * struct log_rec - a single log record
  *
@@ -337,18 +365,18 @@
  *
  * @cat: Category, representing a uclass or part of U-Boot
  * @level: Severity level, less severe is higher
- * @force_debug: Force output of debug
- * @file: Name of file where the log record was generated (not allocated)
  * @line: Line number where the log record was generated
+ * @flags: Flags for log record (enum log_rec_flags)
+ * @file: Name of file where the log record was generated (not allocated)
  * @func: Function where the log record was generated (not allocated)
  * @msg: Log message (allocated)
  */
 struct log_rec {
 	enum log_category_t cat;
 	enum log_level_t level;
-	bool force_debug;
+	u16 line;
+	u8 flags;
 	const char *file;
-	int line;
 	const char *func;
 	const char *msg;
 };
diff --git a/include/os.h b/include/os.h
index 65bcb23..77d8bd8 100644
--- a/include/os.h
+++ b/include/os.h
@@ -114,7 +114,7 @@
  * os_malloc() - aquires some memory from the underlying os.
  *
  * @length:	Number of bytes to be allocated
- * Return:	Pointer to length bytes or NULL on error
+ * Return:	Pointer to length bytes or NULL if @length is 0 or on error
  */
 void *os_malloc(size_t length);
 
@@ -123,11 +123,22 @@
  *
  * This returns the memory to the OS.
  *
- * @ptr:	Pointer to memory block to free
+ * @ptr:	Pointer to memory block to free. If this is NULL then this
+ *		function does nothing
  */
 void os_free(void *ptr);
 
 /**
+ * os_realloc() - reallocate memory
+ *
+ * This follows the semantics of realloc(), so can perform an os_malloc() or
+ * os_free() depending on @ptr and @length.
+ *
+ * Return:	Pointer to reallocated memory or NULL if @length is 0
+ */
+void *os_realloc(void *ptr, size_t length);
+
+/**
  * os_usleep() - access to the usleep function of the os
  *
  * @usec:	time to sleep in micro seconds
@@ -313,9 +324,10 @@
  *
  * @fname:	place to put full path to U-Boot
  * @maxlen:	maximum size of @fname
+ * @use_img:	select the 'u-boot.img' file instead of the 'u-boot' ELF file
  * Return:	0 if OK, -NOSPC if the filename is too large, -ENOENT if not found
  */
-int os_find_u_boot(char *fname, int maxlen);
+int os_find_u_boot(char *fname, int maxlen, bool use_img);
 
 /**
  * os_spl_to_uboot() - Run U-Boot proper
diff --git a/include/scp03.h b/include/scp03.h
new file mode 100644
index 0000000..729667c
--- /dev/null
+++ b/include/scp03.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2021, Foundries.IO
+ *
+ */
+
+#ifndef _SCP03_H
+#define _SCP03_H
+
+/*
+ * Requests to OPTEE to enable or provision the Secure Channel Protocol on its
+ * Secure Element
+ *
+ *  If key provisioning is requested, OPTEE shall generate new SCP03 keys and
+ *  write them to the Secure Element.
+ *
+ *  Both functions return < 0 on error else 0.
+ */
+int tee_enable_scp03(void);
+int tee_provision_scp03(void);
+#endif /* _SCP03_H */
diff --git a/include/spl.h b/include/spl.h
index 0d13458..4f6e0e5 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -222,6 +222,15 @@
 	void *priv;
 	int bl_len;
 	const char *filename;
+	/**
+	 * read() - Read from device
+	 *
+	 * @load: Information about the load state
+	 * @sector: Sector number to read from (each @load->bl_len bytes)
+	 * @count: Number of sectors to read
+	 * @buf: Buffer to read into
+	 * @return number of sectors read, 0 on error
+	 */
 	ulong (*read)(struct spl_load_info *load, ulong sector, ulong count,
 		      void *buf);
 };
diff --git a/include/sysreset.h b/include/sysreset.h
index 8bb094d..701e4f5 100644
--- a/include/sysreset.h
+++ b/include/sysreset.h
@@ -116,6 +116,6 @@
 /**
  * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
  */
-void reset_cpu(ulong addr);
+void reset_cpu(void);
 
 #endif
diff --git a/include/tee/optee_ta_scp03.h b/include/tee/optee_ta_scp03.h
new file mode 100644
index 0000000..13f9956
--- /dev/null
+++ b/include/tee/optee_ta_scp03.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * (C) Copyright 2021, Foundries.IO
+ *
+ */
+#ifndef __TA_SCP03_H
+#define __TA_SCP03_H
+
+#define PTA_SCP03_UUID { 0xbe0e5821, 0xe718, 0x4f77, \
+			{ 0xab, 0x3e, 0x8e, 0x6c, 0x73, 0xa9, 0xc7, 0x35 } }
+
+/*
+ * Enable Secure Channel Protocol functionality (SCP03) on the Secure Element.
+ *   Setting the operation value to something different than NULL will trigger
+ *   the SCP03 provisioning request.
+ *
+ *   in	params[0].a = operation
+ */
+#define PTA_CMD_ENABLE_SCP03	0
+
+#endif /*__TA_SCP03_H*/
diff --git a/include/test/test.h b/include/test/test.h
index 3fdaa2b..0b124ed 100644
--- a/include/test/test.h
+++ b/include/test/test.h
@@ -14,16 +14,24 @@
  *
  * @fail_count: Number of tests that failed
  * @start: Store the starting mallinfo when doing leak test
- * @priv: A pointer to some other info some suites want to track
+ * @of_live: true to use livetree if available, false to use flattree
  * @of_root: Record of the livetree root node (used for setting up tests)
+ * @root: Root device
+ * @testdev: Test device
+ * @force_fail_alloc: Force all memory allocs to fail
+ * @skip_post_probe: Skip uclass post-probe processing
  * @expect_str: Temporary string used to hold expected string value
  * @actual_str: Temporary string used to hold actual string value
  */
 struct unit_test_state {
 	int fail_count;
 	struct mallinfo start;
-	void *priv;
 	struct device_node *of_root;
+	bool of_live;
+	struct udevice *root;
+	struct udevice *testdev;
+	int force_fail_alloc;
+	int skip_post_probe;
 	char expect_str[256];
 	char actual_str[256];
 };
@@ -36,6 +44,8 @@
 	UT_TESTF_FLAT_TREE	= BIT(3),	/* test needs flat DT */
 	UT_TESTF_LIVE_TREE	= BIT(4),	/* needs live device tree */
 	UT_TESTF_CONSOLE_REC	= BIT(5),	/* needs console recording */
+	/* do extra driver model init and uninit */
+	UT_TESTF_DM		= BIT(6),
 };
 
 /**
@@ -76,13 +86,24 @@
  * @_suite:	name of the test suite concatenated with "_test"
  */
 #define UNIT_TEST(_name, _flags, _suite)				\
-	ll_entry_declare(struct unit_test, _name, _suite) = {		\
+	ll_entry_declare(struct unit_test, _name, ut_ ## _suite) = {	\
 		.file = __FILE__,					\
 		.name = #_name,						\
 		.flags = _flags,					\
 		.func = _name,						\
 	}
 
+/* Get the start of a list of unit tests for a particular suite */
+#define UNIT_TEST_SUITE_START(_suite) \
+	ll_entry_start(struct unit_test, ut_ ## _suite)
+#define UNIT_TEST_SUITE_COUNT(_suite) \
+	ll_entry_count(struct unit_test, ut_ ## _suite)
+
+/* Use ! and ~ so that all tests will be sorted between these two values */
+#define UNIT_TEST_ALL_START()	ll_entry_start(struct unit_test, ut_!)
+#define UNIT_TEST_ALL_END()	ll_entry_start(struct unit_test, ut_~)
+#define UNIT_TEST_ALL_COUNT()	(UNIT_TEST_ALL_END() - UNIT_TEST_ALL_START())
+
 /* Sizes for devres tests */
 enum {
 	TEST_DEVRES_SIZE	= 100,
@@ -103,15 +124,4 @@
  */
 struct udevice *testbus_get_clear_removed(void);
 
-/**
- * dm_test_main() - Run driver model tests
- *
- * Run all the available driver model tests, or a selection
- *
- * @test_name: Name of single test to run (e.g. "dm_test_fdt_pre_reloc" or just
- *	"fdt_pre_reloc"), or NULL to run all
- * @return 0 if all tests passed, 1 if not
- */
-int dm_test_main(const char *test_name);
-
 #endif /* __TEST_TEST_H */
diff --git a/include/test/ut.h b/include/test/ut.h
index 17400c7..fbbba28 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -356,4 +356,49 @@
  */
 void ut_unsilence_console(struct unit_test_state *uts);
 
+/**
+ * ut_set_skip_delays() - Sets whether delays should be skipped
+ *
+ * Normally functions like mdelay() cause U-Boot to wait for a while. This
+ * allows all such delays to be skipped on sandbox, to speed up tests
+ *
+ * @uts: Test state (in case in future we want to keep state here)
+ * @skip_delays: true to skip delays, false to process them normally
+ */
+void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays);
+
+/**
+ * test_get_state() - Get the active test state
+ *
+ * @return the currently active test state, or NULL if none
+ */
+struct unit_test_state *test_get_state(void);
+
+/**
+ * test_set_state() - Set the active test state
+ *
+ * @uts: Test state to use as currently active test state, or NULL if none
+ */
+void test_set_state(struct unit_test_state *uts);
+
+/**
+ * ut_run_tests() - Run a set of tests
+ *
+ * This runs the test, handling any preparation and clean-up needed. It prints
+ * the name of each test before running it.
+ *
+ * @category: Category of these tests. This is a string printed at the start to
+ *	announce the the number of tests
+ * @prefix: String prefix for the tests. Any tests that have this prefix will be
+ *	printed without the prefix, so that it is easier to see the unique part
+ *	of the test name. If NULL, no prefix processing is done
+ * @tests: List of tests to run
+ * @count: Number of tests to run
+ * @select_name: Name of a single test to run (from the list provided). If NULL
+ *	then all tests are run
+ * @return 0 if all tests passed, -1 if any failed
+ */
+int ut_run_list(const char *name, const char *prefix, struct unit_test *tests,
+		int count, const char *select_name);
+
 #endif
diff --git a/include/tpm-common.h b/include/tpm-common.h
index c1309a2..998b4fb 100644
--- a/include/tpm-common.h
+++ b/include/tpm-common.h
@@ -55,6 +55,8 @@
  * @buf:		Buffer used during the exchanges with the chip
  * @pcr_count:		Number of PCR per bank
  * @pcr_select_min:	Minimum size in bytes of the pcrSelect array
+ * @plat_hier_disabled:	Platform hierarchy has been disabled (TPM is locked
+ *			down until next reboot)
  */
 struct tpm_chip_priv {
 	enum tpm_version version;
@@ -66,6 +68,7 @@
 	/* TPM v2 specific data */
 	uint pcr_count;
 	uint pcr_select_min;
+	bool plat_hier_disabled;
 };
 
 /**
diff --git a/include/tpm-v1.h b/include/tpm-v1.h
index 8f6cc28..fcfe1f0 100644
--- a/include/tpm-v1.h
+++ b/include/tpm-v1.h
@@ -289,7 +289,7 @@
  * @param mode		TPM startup mode
  * @return return code of the operation
  */
-u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode);
+u32 tpm1_startup(struct udevice *dev, enum tpm_startup_type mode);
 
 /**
  * Issue a TPM_SelfTestFull command.
@@ -297,7 +297,7 @@
  * @param dev		TPM device
  * @return return code of the operation
  */
-u32 tpm_self_test_full(struct udevice *dev);
+u32 tpm1_self_test_full(struct udevice *dev);
 
 /**
  * Issue a TPM_ContinueSelfTest command.
@@ -305,7 +305,7 @@
  * @param dev		TPM device
  * @return return code of the operation
  */
-u32 tpm_continue_self_test(struct udevice *dev);
+u32 tpm1_continue_self_test(struct udevice *dev);
 
 /**
  * Issue a TPM_NV_DefineSpace command.  The implementation is limited
@@ -318,7 +318,7 @@
  * @param size		size of the area
  * @return return code of the operation
  */
-u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size);
+u32 tpm1_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size);
 
 /**
  * Issue a TPM_NV_ReadValue command.  This implementation is limited
@@ -331,7 +331,7 @@
  * @param count		size of output buffer
  * @return return code of the operation
  */
-u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count);
+u32 tpm1_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count);
 
 /**
  * Issue a TPM_NV_WriteValue command.  This implementation is limited
@@ -344,8 +344,8 @@
  * @param length	length of data bytes of input buffer
  * @return return code of the operation
  */
-u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
-		       u32 length);
+u32 tpm1_nv_write_value(struct udevice *dev, u32 index, const void *data,
+			u32 length);
 
 /**
  * Issue a TPM_Extend command.
@@ -358,8 +358,8 @@
  *			command
  * @return return code of the operation
  */
-u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest,
-	       void *out_digest);
+u32 tpm1_extend(struct udevice *dev, u32 index, const void *in_digest,
+		void *out_digest);
 
 /**
  * Issue a TPM_PCRRead command.
@@ -370,7 +370,7 @@
  * @param count		size of output buffer
  * @return return code of the operation
  */
-u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count);
+u32 tpm1_pcr_read(struct udevice *dev, u32 index, void *data, size_t count);
 
 /**
  * Issue a TSC_PhysicalPresence command.  TPM physical presence flag
@@ -380,7 +380,7 @@
  * @param presence	TPM physical presence flag
  * @return return code of the operation
  */
-u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence);
+u32 tpm1_tsc_physical_presence(struct udevice *dev, u16 presence);
 
 /**
  * Issue a TPM_ReadPubek command.
@@ -390,7 +390,7 @@
  * @param count		size of output buffer
  * @return return code of the operation
  */
-u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count);
+u32 tpm1_read_pubek(struct udevice *dev, void *data, size_t count);
 
 /**
  * Issue a TPM_ForceClear command.
@@ -398,7 +398,7 @@
  * @param dev		TPM device
  * @return return code of the operation
  */
-u32 tpm_force_clear(struct udevice *dev);
+u32 tpm1_force_clear(struct udevice *dev);
 
 /**
  * Issue a TPM_PhysicalEnable command.
@@ -406,7 +406,7 @@
  * @param dev		TPM device
  * @return return code of the operation
  */
-u32 tpm_physical_enable(struct udevice *dev);
+u32 tpm1_physical_enable(struct udevice *dev);
 
 /**
  * Issue a TPM_PhysicalDisable command.
@@ -414,7 +414,7 @@
  * @param dev		TPM device
  * @return return code of the operation
  */
-u32 tpm_physical_disable(struct udevice *dev);
+u32 tpm1_physical_disable(struct udevice *dev);
 
 /**
  * Issue a TPM_PhysicalSetDeactivated command.
@@ -423,7 +423,7 @@
  * @param state		boolean state of the deactivated flag
  * @return return code of the operation
  */
-u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state);
+u32 tpm1_physical_set_deactivated(struct udevice *dev, u8 state);
 
 /**
  * Issue a TPM_GetCapability command.  This implementation is limited
@@ -437,8 +437,8 @@
  * @param count		size of output buffer
  * @return return code of the operation
  */
-u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
-		       void *cap, size_t count);
+u32 tpm1_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
+			void *cap, size_t count);
 
 /**
  * Issue a TPM_FlushSpecific command for a AUTH resource.
@@ -447,7 +447,7 @@
  * @param auth_handle	handle of the auth session
  * @return return code of the operation
  */
-u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle);
+u32 tpm1_terminate_auth_session(struct udevice *dev, u32 auth_handle);
 
 /**
  * Issue a TPM_OIAP command to setup an object independent authorization
@@ -460,7 +460,7 @@
  * @param auth_handle	pointer to the (new) auth handle or NULL.
  * @return return code of the operation
  */
-u32 tpm_oiap(struct udevice *dev, u32 *auth_handle);
+u32 tpm1_oiap(struct udevice *dev, u32 *auth_handle);
 
 /**
  * Ends an active OIAP session.
@@ -468,7 +468,7 @@
  * @param dev		TPM device
  * @return return code of the operation
  */
-u32 tpm_end_oiap(struct udevice *dev);
+u32 tpm1_end_oiap(struct udevice *dev);
 
 /**
  * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating
@@ -482,9 +482,9 @@
  * @param key_handle	pointer to the key handle
  * @return return code of the operation
  */
-u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
-		       size_t key_length, const void *parent_key_usage_auth,
-		       u32 *key_handle);
+u32 tpm1_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
+			size_t key_length, const void *parent_key_usage_auth,
+			u32 *key_handle);
 
 /**
  * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for
@@ -500,9 +500,9 @@
  *			of the stored TPM_PUBKEY structure (iff pubkey != NULL).
  * @return return code of the operation
  */
-u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
-			 const void *usage_auth, void *pubkey,
-			 size_t *pubkey_len);
+u32 tpm1_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
+			  const void *usage_auth, void *pubkey,
+			  size_t *pubkey_len);
 
 /**
  * Get the TPM permanent flags value
@@ -511,8 +511,8 @@
  * @param pflags	Place to put permanent flags
  * @return return code of the operation
  */
-u32 tpm_get_permanent_flags(struct udevice *dev,
-			    struct tpm_permanent_flags *pflags);
+u32 tpm1_get_permanent_flags(struct udevice *dev,
+			     struct tpm_permanent_flags *pflags);
 
 /**
  * Get the TPM permissions
@@ -521,7 +521,7 @@
  * @param perm		Returns permissions value
  * @return return code of the operation
  */
-u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm);
+u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm);
 
 /**
  * Flush a resource with a given handle and type from the TPM
@@ -531,7 +531,7 @@
  * @param resource_type                type of the resource
  * @return return code of the operation
  */
-u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type);
+u32 tpm1_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type);
 
 #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
 /**
@@ -543,8 +543,8 @@
  * @param[out] handle	The handle of the key (Non-null iff found)
  * @return 0 if key was found in TPM; != 0 if not.
  */
-u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20],
-		      const u8 pubkey_digest[20], u32 *handle);
+u32 tpm1_find_key_sha1(struct udevice *dev, const u8 auth[20],
+		       const u8 pubkey_digest[20], u32 *handle);
 #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
 
 /**
@@ -557,7 +557,7 @@
  * @param count		size of output buffer
  * @return return code of the operation
  */
-u32 tpm_get_random(struct udevice *dev, void *data, u32 count);
+u32 tpm1_get_random(struct udevice *dev, void *data, u32 count);
 
 /**
  * tpm_finalise_physical_presence() - Finalise physical presence
@@ -565,15 +565,15 @@
  * @param dev		TPM device
  * @return return code of the operation (0 = success)
  */
-u32 tpm_finalise_physical_presence(struct udevice *dev);
+u32 tpm1_finalise_physical_presence(struct udevice *dev);
 
 /**
- * tpm_nv_set_locked() - lock the non-volatile space
+ * tpm_nv_enable_locking() - lock the non-volatile space
  *
  * @param dev		TPM device
  * @return return code of the operation (0 = success)
  */
-u32 tpm_nv_set_locked(struct udevice *dev);
+u32 tpm1_nv_set_locked(struct udevice *dev);
 
 /**
  * tpm_set_global_lock() - set the global lock
@@ -589,6 +589,6 @@
  * @param dev		TPM device
  * @return return code of the operation (0 = success)
  */
-u32 tpm_resume(struct udevice *dev);
+u32 tpm1_resume(struct udevice *dev);
 
 #endif /* __TPM_V1_H */
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index 56eaa65..df67a19 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -237,10 +237,14 @@
 enum tpm2_command_codes {
 	TPM2_CC_STARTUP		= 0x0144,
 	TPM2_CC_SELF_TEST	= 0x0143,
+	TPM2_CC_HIER_CONTROL	= 0x0121,
 	TPM2_CC_CLEAR		= 0x0126,
 	TPM2_CC_CLEARCONTROL	= 0x0127,
 	TPM2_CC_HIERCHANGEAUTH	= 0x0129,
+	TPM2_CC_NV_DEFINE_SPACE	= 0x012a,
 	TPM2_CC_PCR_SETAUTHPOL	= 0x012C,
+	TPM2_CC_NV_WRITE	= 0x0137,
+	TPM2_CC_NV_WRITELOCK	= 0x0138,
 	TPM2_CC_DAM_RESET	= 0x0139,
 	TPM2_CC_DAM_PARAMETERS	= 0x013A,
 	TPM2_CC_NV_READ         = 0x014E,
@@ -271,6 +275,7 @@
 	TPM2_RC_COMMAND_CODE	= TPM2_RC_VER1 + 0x0043,
 	TPM2_RC_AUTHSIZE	= TPM2_RC_VER1 + 0x0044,
 	TPM2_RC_AUTH_CONTEXT	= TPM2_RC_VER1 + 0x0045,
+	TPM2_RC_NV_DEFINED	= TPM2_RC_VER1 + 0x004c,
 	TPM2_RC_NEEDS_TEST	= TPM2_RC_VER1 + 0x0053,
 	TPM2_RC_WARN		= 0x0900,
 	TPM2_RC_TESTING		= TPM2_RC_WARN + 0x000A,
@@ -355,6 +360,20 @@
 	TPM_MAX_BUF_SIZE	= 1260,
 };
 
+enum {
+	/* Secure storage for firmware settings */
+	TPM_HT_PCR = 0,
+	TPM_HT_NV_INDEX,
+	TPM_HT_HMAC_SESSION,
+	TPM_HT_POLICY_SESSION,
+
+	HR_SHIFT		= 24,
+	HR_PCR			= TPM_HT_PCR << HR_SHIFT,
+	HR_HMAC_SESSION		= TPM_HT_HMAC_SESSION << HR_SHIFT,
+	HR_POLICY_SESSION	= TPM_HT_POLICY_SESSION << HR_SHIFT,
+	HR_NV_INDEX		= TPM_HT_NV_INDEX << HR_SHIFT,
+};
+
 /**
  * Issue a TPM2_Startup command.
  *
@@ -389,6 +408,23 @@
 	       const ssize_t pw_sz);
 
 /**
+ * Issue a TPM_NV_DefineSpace command
+ *
+ * This allows a space to be defined with given attributes and policy
+ *
+ * @dev			TPM device
+ * @space_index		index of the area
+ * @space_size		size of area in bytes
+ * @nv_attributes	TPM_NV_ATTRIBUTES of the area
+ * @nv_policy		policy to use
+ * @nv_policy_size	size of the policy
+ * @return return code of the operation
+ */
+u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
+			 size_t space_size, u32 nv_attributes,
+			 const u8 *nv_policy, size_t nv_policy_size);
+
+/**
  * Issue a TPM2_PCR_Extend command.
  *
  * @dev		TPM device
@@ -403,6 +439,29 @@
 		    const u8 *digest, u32 digest_len);
 
 /**
+ * Read data from the secure storage
+ *
+ * @dev		TPM device
+ * @index	Index of data to read
+ * @data	Place to put data
+ * @count	Number of bytes of data
+ * @return code of the operation
+ */
+u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count);
+
+/**
+ * Write data to the secure storage
+ *
+ * @dev		TPM device
+ * @index	Index of data to write
+ * @data	Data to write
+ * @count	Number of bytes of data
+ * @return code of the operation
+ */
+u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
+			u32 count);
+
+/**
  * Issue a TPM2_PCR_Read command.
  *
  * @dev		TPM device
@@ -516,4 +575,26 @@
  */
 u32 tpm2_get_random(struct udevice *dev, void *data, u32 count);
 
+/**
+ * Lock data in the TPM
+ *
+ * Once locked the data cannot be written until after a reboot
+ *
+ * @dev		TPM device
+ * @index	Index of data to lock
+ * @return code of the operation
+ */
+u32 tpm2_write_lock(struct udevice *dev, u32 index);
+
+/**
+ * Disable access to any platform data
+ *
+ * This can be called to close off access to the firmware data in the data,
+ * before calling the kernel.
+ *
+ * @dev		TPM device
+ * @return code of the operation
+ */
+u32 tpm2_disable_platform_hierarchy(struct udevice *dev);
+
 #endif /* __TPM_V2_H */
diff --git a/include/tpm_api.h b/include/tpm_api.h
new file mode 100644
index 0000000..f13d98c
--- /dev/null
+++ b/include/tpm_api.h
@@ -0,0 +1,322 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2013 The Chromium OS Authors.
+ * Coypright (c) 2013 Guntermann & Drunck GmbH
+ */
+
+#ifndef __TPM_API_H
+#define __TPM_API_H
+
+#include <tpm-common.h>
+#include <tpm-v1.h>
+#include <tpm-v2.h>
+
+/**
+ * Issue a TPM_Startup command.
+ *
+ * @param dev		TPM device
+ * @param mode		TPM startup mode
+ * @return return code of the operation
+ */
+u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode);
+
+/**
+ * Issue a TPM_SelfTestFull command.
+ *
+ * @param dev		TPM device
+ * @return return code of the operation
+ */
+u32 tpm_self_test_full(struct udevice *dev);
+
+/**
+ * Issue a TPM_ContinueSelfTest command.
+ *
+ * @param dev		TPM device
+ * @return return code of the operation
+ */
+u32 tpm_continue_self_test(struct udevice *dev);
+
+/**
+ * Issue a TPM_NV_DefineSpace command.  The implementation is limited
+ * to specify TPM_NV_ATTRIBUTES and size of the area.  The area index
+ * could be one of the special value listed in enum tpm_nv_index.
+ *
+ * @param dev		TPM device
+ * @param index		index of the area
+ * @param perm		TPM_NV_ATTRIBUTES of the area
+ * @param size		size of the area
+ * @return return code of the operation
+ */
+u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size);
+
+/**
+ * Issue a TPM_NV_ReadValue command.  This implementation is limited
+ * to read the area from offset 0.  The area index could be one of
+ * the special value listed in enum tpm_nv_index.
+ *
+ * @param dev		TPM device
+ * @param index		index of the area
+ * @param data		output buffer of the area contents
+ * @param count		size of output buffer
+ * @return return code of the operation
+ */
+u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count);
+
+/**
+ * Issue a TPM_NV_WriteValue command.  This implementation is limited
+ * to write the area from offset 0.  The area index could be one of
+ * the special value listed in enum tpm_nv_index.
+ *
+ * @param dev		TPM device
+ * @param index		index of the area
+ * @param data		input buffer to be wrote to the area
+ * @param length	length of data bytes of input buffer
+ * @return return code of the operation
+ */
+u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
+		       u32 length);
+
+/**
+ * Issue a TPM_Extend command.
+ *
+ * @param dev		TPM device
+ * @param index		index of the PCR
+ * @param in_digest	160-bit value representing the event to be
+ *			recorded
+ * @param out_digest	160-bit PCR value after execution of the
+ *			command
+ * @return return code of the operation
+ */
+u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest,
+		   void *out_digest);
+
+/**
+ * Issue a TPM_PCRRead command.
+ *
+ * @param dev		TPM device
+ * @param index		index of the PCR
+ * @param data		output buffer for contents of the named PCR
+ * @param count		size of output buffer
+ * @return return code of the operation
+ */
+u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count);
+
+/**
+ * Issue a TSC_PhysicalPresence command.  TPM physical presence flag
+ * is bit-wise OR'ed of flags listed in enum tpm_physical_presence.
+ *
+ * @param dev		TPM device
+ * @param presence	TPM physical presence flag
+ * @return return code of the operation
+ */
+u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence);
+
+/**
+ * Issue a TPM_ReadPubek command.
+ *
+ * @param dev		TPM device
+ * @param data		output buffer for the public endorsement key
+ * @param count		size of output buffer
+ * @return return code of the operation
+ */
+u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count);
+
+/**
+ * Issue a TPM_ForceClear command.
+ *
+ * @param dev		TPM device
+ * @return return code of the operation
+ */
+u32 tpm_force_clear(struct udevice *dev);
+
+/**
+ * Issue a TPM_PhysicalEnable command.
+ *
+ * @param dev		TPM device
+ * @return return code of the operation
+ */
+u32 tpm_physical_enable(struct udevice *dev);
+
+/**
+ * Issue a TPM_PhysicalDisable command.
+ *
+ * @param dev		TPM device
+ * @return return code of the operation
+ */
+u32 tpm_physical_disable(struct udevice *dev);
+
+/**
+ * Issue a TPM_PhysicalSetDeactivated command.
+ *
+ * @param dev		TPM device
+ * @param state		boolean state of the deactivated flag
+ * @return return code of the operation
+ */
+u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state);
+
+/**
+ * Issue a TPM_GetCapability command.  This implementation is limited
+ * to query sub_cap index that is 4-byte wide.
+ *
+ * @param dev		TPM device
+ * @param cap_area	partition of capabilities
+ * @param sub_cap	further definition of capability, which is
+ *			limited to be 4-byte wide
+ * @param cap		output buffer for capability information
+ * @param count		size of output buffer
+ * @return return code of the operation
+ */
+u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
+		       void *cap, size_t count);
+
+/**
+ * Issue a TPM_FlushSpecific command for a AUTH resource.
+ *
+ * @param dev		TPM device
+ * @param auth_handle	handle of the auth session
+ * @return return code of the operation
+ */
+u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle);
+
+/**
+ * Issue a TPM_OIAP command to setup an object independent authorization
+ * session.
+ * Information about the session is stored internally.
+ * If there was already an OIAP session active it is terminated and a new
+ * session is set up.
+ *
+ * @param dev		TPM device
+ * @param auth_handle	pointer to the (new) auth handle or NULL.
+ * @return return code of the operation
+ */
+u32 tpm_oiap(struct udevice *dev, u32 *auth_handle);
+
+/**
+ * Ends an active OIAP session.
+ *
+ * @param dev		TPM device
+ * @return return code of the operation
+ */
+u32 tpm_end_oiap(struct udevice *dev);
+
+/**
+ * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating
+ * the usage of the parent key.
+ *
+ * @param dev		TPM device
+ * @param parent_handle	handle of the parent key.
+ * @param key		pointer to the key structure (TPM_KEY or TPM_KEY12).
+ * @param key_length	size of the key structure
+ * @param parent_key_usage_auth	usage auth for the parent key
+ * @param key_handle	pointer to the key handle
+ * @return return code of the operation
+ */
+u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
+		       size_t key_length, const void *parent_key_usage_auth,
+		       u32 *key_handle);
+
+/**
+ * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for
+ * authenticating the usage of the key.
+ *
+ * @param dev		TPM device
+ * @param key_handle	handle of the key
+ * @param usage_auth	usage auth for the key
+ * @param pubkey	pointer to the pub key buffer; may be NULL if the pubkey
+ *			should not be stored.
+ * @param pubkey_len	pointer to the pub key buffer len. On entry: the size of
+ *			the provided pubkey buffer. On successful exit: the size
+ *			of the stored TPM_PUBKEY structure (iff pubkey != NULL).
+ * @return return code of the operation
+ */
+u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
+			 const void *usage_auth, void *pubkey,
+			 size_t *pubkey_len);
+
+/**
+ * Get the TPM permissions
+ *
+ * @param dev		TPM device
+ * @param perm		Returns permissions value
+ * @return return code of the operation
+ */
+u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm);
+
+/**
+ * Flush a resource with a given handle and type from the TPM
+ *
+ * @param dev		TPM device
+ * @param key_handle           handle of the resource
+ * @param resource_type                type of the resource
+ * @return return code of the operation
+ */
+u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type);
+
+#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
+/**
+ * Search for a key by usage AuthData and the hash of the parent's pub key.
+ *
+ * @param dev		TPM device
+ * @param auth	        Usage auth of the key to search for
+ * @param pubkey_digest	SHA1 hash of the pub key structure of the key
+ * @param[out] handle	The handle of the key (Non-null iff found)
+ * @return 0 if key was found in TPM; != 0 if not.
+ */
+u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20],
+		      const u8 pubkey_digest[20], u32 *handle);
+#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
+
+/**
+ * Read random bytes from the TPM RNG. The implementation deals with the fact
+ * that the TPM may legally return fewer bytes than requested by retrying
+ * until @p count bytes have been received.
+ *
+ * @param dev		TPM device
+ * @param data		output buffer for the random bytes
+ * @param count		size of output buffer
+ * @return return code of the operation
+ */
+u32 tpm_get_random(struct udevice *dev, void *data, u32 count);
+
+/**
+ * tpm_finalise_physical_presence() - Finalise physical presence
+ *
+ * @param dev		TPM device
+ * @return return code of the operation (0 = success)
+ */
+u32 tpm_finalise_physical_presence(struct udevice *dev);
+
+/**
+ * tpm_nv_enable_locking() - lock the non-volatile space
+ *
+ * @param dev		TPM device
+ * @return return code of the operation (0 = success)
+ */
+u32 tpm_nv_enable_locking(struct udevice *dev);
+
+/**
+ * tpm_set_global_lock() - set the global lock
+ *
+ * @param dev		TPM device
+ * @return return code of the operation (0 = success)
+ */
+u32 tpm_set_global_lock(struct udevice *dev);
+
+/**
+ * tpm_write_lock() - lock the non-volatile space
+ *
+ * @param dev		TPM device
+ * @param index		Index of space to lock
+ * @return return code of the operation (0 = success)
+ */
+u32 tpm_write_lock(struct udevice *dev, u32 index);
+
+/**
+ * tpm_resume() - start up the TPM from resume (after suspend)
+ *
+ * @param dev		TPM device
+ * @return return code of the operation (0 = success)
+ */
+u32 tpm_resume(struct udevice *dev);
+
+#endif /* __TPM_API_H */
diff --git a/lib/Makefile b/lib/Makefile
index edc1c3d..c42d4e1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -53,6 +53,7 @@
 obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-common.o
 ifeq ($(CONFIG_$(SPL_TPL_)TPM),y)
 obj-y += crc8.o
+obj-$(CONFIG_TPM) += tpm_api.o
 obj-$(CONFIG_TPM_V1) += tpm-v1.o
 obj-$(CONFIG_TPM_V2) += tpm-v2.o
 endif
diff --git a/lib/tpm-common.c b/lib/tpm-common.c
index e4af87f..4277846 100644
--- a/lib/tpm-common.c
+++ b/lib/tpm-common.c
@@ -166,6 +166,7 @@
 	u8 response_buffer[COMMAND_BUFFER_SIZE];
 	size_t response_length;
 	int i;
+	uint size;
 
 	if (response) {
 		response_length = *size_ptr;
@@ -174,8 +175,13 @@
 		response_length = sizeof(response_buffer);
 	}
 
-	err = tpm_xfer(dev, command, tpm_command_size(command),
-		       response, &response_length);
+	size = tpm_command_size(command);
+	log_debug("TPM request [size:%d]: ", size);
+	for (i = 0; i < size; i++)
+		log_debug("%02x ", ((u8 *)command)[i]);
+	log_debug("\n");
+
+	err = tpm_xfer(dev, command, size, response, &response_length);
 
 	if (err < 0)
 		return err;
diff --git a/lib/tpm-v1.c b/lib/tpm-v1.c
index a846fe0..8dc1440 100644
--- a/lib/tpm-v1.c
+++ b/lib/tpm-v1.c
@@ -32,7 +32,7 @@
 
 #endif /* CONFIG_TPM_AUTH_SESSIONS */
 
-u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode)
+u32 tpm1_startup(struct udevice *dev, enum tpm_startup_type mode)
 {
 	const u8 command[12] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
@@ -48,12 +48,12 @@
 	return tpm_sendrecv_command(dev, buf, NULL, NULL);
 }
 
-u32 tpm_resume(struct udevice *dev)
+u32 tpm1_resume(struct udevice *dev)
 {
-	return tpm_startup(dev, TPM_ST_STATE);
+	return tpm1_startup(dev, TPM_ST_STATE);
 }
 
-u32 tpm_self_test_full(struct udevice *dev)
+u32 tpm1_self_test_full(struct udevice *dev)
 {
 	const u8 command[10] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
@@ -61,7 +61,7 @@
 	return tpm_sendrecv_command(dev, command, NULL, NULL);
 }
 
-u32 tpm_continue_self_test(struct udevice *dev)
+u32 tpm1_continue_self_test(struct udevice *dev)
 {
 	const u8 command[10] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
@@ -69,35 +69,33 @@
 	return tpm_sendrecv_command(dev, command, NULL, NULL);
 }
 
-u32 tpm_clear_and_reenable(struct udevice *dev)
+u32 tpm1_clear_and_reenable(struct udevice *dev)
 {
 	u32 ret;
 
 	log_info("TPM: Clear and re-enable\n");
-	ret = tpm_force_clear(dev);
+	ret = tpm1_force_clear(dev);
 	if (ret != TPM_SUCCESS) {
 		log_err("Can't initiate a force clear\n");
 		return ret;
 	}
 
-	if (tpm_get_version(dev) == TPM_V1) {
-		ret = tpm_physical_enable(dev);
-		if (ret != TPM_SUCCESS) {
-			log_err("TPM: Can't set enabled state\n");
-			return ret;
-		}
+	ret = tpm1_physical_enable(dev);
+	if (ret != TPM_SUCCESS) {
+		log_err("TPM: Can't set enabled state\n");
+		return ret;
+	}
 
-		ret = tpm_physical_set_deactivated(dev, 0);
-		if (ret != TPM_SUCCESS) {
-			log_err("TPM: Can't set deactivated state\n");
-			return ret;
-		}
+	ret = tpm1_physical_set_deactivated(dev, 0);
+	if (ret != TPM_SUCCESS) {
+		log_err("TPM: Can't set deactivated state\n");
+		return ret;
 	}
 
 	return TPM_SUCCESS;
 }
 
-u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size)
+u32 tpm1_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size)
 {
 	const u8 command[101] = {
 		0x0, 0xc1,		/* TPM_TAG */
@@ -140,12 +138,12 @@
 	return tpm_sendrecv_command(dev, buf, NULL, NULL);
 }
 
-u32 tpm_nv_set_locked(struct udevice *dev)
+u32 tpm1_nv_set_locked(struct udevice *dev)
 {
-	return tpm_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
+	return tpm1_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
 }
 
-u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
+u32 tpm1_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
 {
 	const u8 command[22] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
@@ -179,8 +177,8 @@
 	return 0;
 }
 
-u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
-		       u32 length)
+u32 tpm1_nv_write_value(struct udevice *dev, u32 index, const void *data,
+			u32 length)
 {
 	const u8 command[256] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
@@ -210,13 +208,8 @@
 	return 0;
 }
 
-uint32_t tpm_set_global_lock(struct udevice *dev)
-{
-	return tpm_nv_write_value(dev, TPM_NV_INDEX_0, NULL, 0);
-}
-
-u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest,
-	       void *out_digest)
+u32 tpm1_extend(struct udevice *dev, u32 index, const void *in_digest,
+		void *out_digest)
 {
 	const u8 command[34] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
@@ -247,7 +240,7 @@
 	return 0;
 }
 
-u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
+u32 tpm1_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
 {
 	const u8 command[14] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
@@ -275,7 +268,7 @@
 	return 0;
 }
 
-u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence)
+u32 tpm1_tsc_physical_presence(struct udevice *dev, u16 presence)
 {
 	const u8 command[12] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
@@ -291,7 +284,7 @@
 	return tpm_sendrecv_command(dev, buf, NULL, NULL);
 }
 
-u32 tpm_finalise_physical_presence(struct udevice *dev)
+u32 tpm1_finalise_physical_presence(struct udevice *dev)
 {
 	const u8 command[12] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
@@ -300,7 +293,7 @@
 	return tpm_sendrecv_command(dev, command, NULL, NULL);
 }
 
-u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count)
+u32 tpm1_read_pubek(struct udevice *dev, void *data, size_t count)
 {
 	const u8 command[30] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
@@ -331,7 +324,7 @@
 	return 0;
 }
 
-u32 tpm_force_clear(struct udevice *dev)
+u32 tpm1_force_clear(struct udevice *dev)
 {
 	const u8 command[10] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
@@ -340,7 +333,7 @@
 	return tpm_sendrecv_command(dev, command, NULL, NULL);
 }
 
-u32 tpm_physical_enable(struct udevice *dev)
+u32 tpm1_physical_enable(struct udevice *dev)
 {
 	const u8 command[10] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
@@ -349,7 +342,7 @@
 	return tpm_sendrecv_command(dev, command, NULL, NULL);
 }
 
-u32 tpm_physical_disable(struct udevice *dev)
+u32 tpm1_physical_disable(struct udevice *dev)
 {
 	const u8 command[10] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
@@ -358,7 +351,7 @@
 	return tpm_sendrecv_command(dev, command, NULL, NULL);
 }
 
-u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state)
+u32 tpm1_physical_set_deactivated(struct udevice *dev, u8 state)
 {
 	const u8 command[11] = {
 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
@@ -374,8 +367,8 @@
 	return tpm_sendrecv_command(dev, buf, NULL, NULL);
 }
 
-u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
-		       void *cap, size_t count)
+u32 tpm1_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
+			void *cap, size_t count)
 {
 	const u8 command[22] = {
 		0x0, 0xc1,		/* TPM_TAG */
@@ -414,8 +407,8 @@
 	return 0;
 }
 
-u32 tpm_get_permanent_flags(struct udevice *dev,
-			    struct tpm_permanent_flags *pflags)
+u32 tpm1_get_permanent_flags(struct udevice *dev,
+			     struct tpm_permanent_flags *pflags)
 {
 	const u8 command[22] = {
 		0x0, 0xc1,		/* TPM_TAG */
@@ -453,7 +446,7 @@
 	return 0;
 }
 
-u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm)
+u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm)
 {
 	const u8 command[22] = {
 		0x0, 0xc1,		/* TPM_TAG */
@@ -482,7 +475,7 @@
 }
 
 #ifdef CONFIG_TPM_FLUSH_RESOURCES
-u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
+u32 tpm1_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
 {
 	const u8 command[18] = {
 		0x00, 0xc1,             /* TPM_TAG */
@@ -641,7 +634,7 @@
 	return TPM_SUCCESS;
 }
 
-u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle)
+u32 tpm1_terminate_auth_session(struct udevice *dev, u32 auth_handle)
 {
 	const u8 command[18] = {
 		0x00, 0xc1,		/* TPM_TAG */
@@ -663,16 +656,16 @@
 	return tpm_sendrecv_command(dev, request, NULL, NULL);
 }
 
-u32 tpm_end_oiap(struct udevice *dev)
+u32 tpm1_end_oiap(struct udevice *dev)
 {
 	u32 err = TPM_SUCCESS;
 
 	if (oiap_session.valid)
-		err = tpm_terminate_auth_session(dev, oiap_session.handle);
+		err = tpm1_terminate_auth_session(dev, oiap_session.handle);
 	return err;
 }
 
-u32 tpm_oiap(struct udevice *dev, u32 *auth_handle)
+u32 tpm1_oiap(struct udevice *dev, u32 *auth_handle)
 {
 	const u8 command[10] = {
 		0x00, 0xc1,		/* TPM_TAG */
@@ -686,7 +679,7 @@
 	u32 err;
 
 	if (oiap_session.valid)
-		tpm_terminate_auth_session(dev, oiap_session.handle);
+		tpm1_terminate_auth_session(dev, oiap_session.handle);
 
 	err = tpm_sendrecv_command(dev, command, response, &response_length);
 	if (err)
@@ -702,9 +695,9 @@
 	return 0;
 }
 
-u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
-		       size_t key_length, const void *parent_key_usage_auth,
-		       u32 *key_handle)
+u32 tpm1_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
+			size_t key_length, const void *parent_key_usage_auth,
+			u32 *key_handle)
 {
 	const u8 command[14] = {
 		0x00, 0xc2,		/* TPM_TAG */
@@ -723,7 +716,7 @@
 	u32 err;
 
 	if (!oiap_session.valid) {
-		err = tpm_oiap(dev, NULL);
+		err = tpm1_oiap(dev, NULL);
 		if (err)
 			return err;
 	}
@@ -768,9 +761,9 @@
 	return 0;
 }
 
-u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
-			 const void *usage_auth, void *pubkey,
-			 size_t *pubkey_len)
+u32 tpm1_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
+			  const void *usage_auth, void *pubkey,
+			  size_t *pubkey_len)
 {
 	const u8 command[14] = {
 		0x00, 0xc2,		/* TPM_TAG */
@@ -788,7 +781,7 @@
 	u32 err;
 
 	if (!oiap_session.valid) {
-		err = tpm_oiap(dev, NULL);
+		err = tpm1_oiap(dev, NULL);
 		if (err)
 			return err;
 	}
@@ -834,8 +827,8 @@
 }
 
 #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
-u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20],
-		      const u8 pubkey_digest[20], u32 *handle)
+u32 tpm1_find_key_sha1(struct udevice *dev, const u8 auth[20],
+		       const u8 pubkey_digest[20], u32 *handle)
 {
 	u16 key_count;
 	u32 key_handles[10];
@@ -876,7 +869,7 @@
 
 #endif /* CONFIG_TPM_AUTH_SESSIONS */
 
-u32 tpm_get_random(struct udevice *dev, void *data, u32 count)
+u32 tpm1_get_random(struct udevice *dev, void *data, u32 count)
 {
 	const u8 command[14] = {
 		0x0, 0xc1,		/* TPM_TAG */
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 1f3deb0..235f8c2 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -47,9 +47,11 @@
 u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
 	       const ssize_t pw_sz)
 {
+	/* Length of the message header, up to start of password */
+	uint offset = 27;
 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
-		tpm_u32(27 + pw_sz),		/* Length */
+		tpm_u32(offset + pw_sz),	/* Length */
 		tpm_u32(TPM2_CC_CLEAR),		/* Command code */
 
 		/* HANDLE */
@@ -64,7 +66,6 @@
 		tpm_u16(pw_sz),			/* Size of <hmac/password> */
 		/* STRING(pw)			   <hmac/password> (if any) */
 	};
-	unsigned int offset = 27;
 	int ret;
 
 	/*
@@ -80,12 +81,61 @@
 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
 }
 
+u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
+			 size_t space_size, u32 nv_attributes,
+			 const u8 *nv_policy, size_t nv_policy_size)
+{
+	/*
+	 * Calculate the offset of the nv_policy piece by adding each of the
+	 * chunks below.
+	 */
+	uint offset = 10 + 8 + 13 + 14;
+	u8 command_v2[COMMAND_BUFFER_SIZE] = {
+		/* header 10 bytes */
+		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
+		tpm_u32(offset + nv_policy_size),/* Length */
+		tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
+
+		/* handles 8 bytes */
+		tpm_u32(TPM2_RH_PLATFORM),	/* Primary platform seed */
+
+		/* session header 13 bytes */
+		tpm_u32(9),			/* Header size */
+		tpm_u32(TPM2_RS_PW),		/* Password authorisation */
+		tpm_u16(0),			/* nonce_size */
+		0,				/* session_attrs */
+		tpm_u16(0),			/* auth_size */
+
+		/* message 14 bytes + policy */
+		tpm_u16(12 + nv_policy_size),	/* size */
+		tpm_u32(space_index),
+		tpm_u16(TPM2_ALG_SHA256),
+		tpm_u32(nv_attributes),
+		tpm_u16(nv_policy_size),
+		/* nv_policy */
+	};
+	int ret;
+
+	/*
+	 * Fill the command structure starting from the first buffer:
+	 *     - the password (if any)
+	 */
+	ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
+			       offset, nv_policy, nv_policy_size);
+	if (ret)
+		return TPM_LIB_ERROR;
+
+	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+}
+
 u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
 		    const u8 *digest, u32 digest_len)
 {
+	/* Length of the message header, up to start of digest */
+	uint offset = 33;
 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
-		tpm_u32(33 + digest_len),	/* Length */
+		tpm_u32(offset + digest_len),	/* Length */
 		tpm_u32(TPM2_CC_PCR_EXTEND),	/* Command code */
 
 		/* HANDLE */
@@ -99,11 +149,12 @@
 		0,				/* Attributes: Cont/Excl/Rst */
 		tpm_u16(0),			/* Size of <hmac/password> */
 						/* <hmac/password> (if any) */
+
+		/* hashes */
 		tpm_u32(1),			/* Count (number of hashes) */
 		tpm_u16(algorithm),	/* Algorithm of the hash */
 		/* STRING(digest)		   Digest */
 	};
-	unsigned int offset = 33;
 	int ret;
 
 	/*
@@ -112,13 +163,96 @@
 	 */
 	ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
 			       offset, digest, digest_len);
-	offset += digest_len;
 	if (ret)
 		return TPM_LIB_ERROR;
 
 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
 }
 
+u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
+{
+	u8 command_v2[COMMAND_BUFFER_SIZE] = {
+		/* header 10 bytes */
+		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
+		tpm_u32(10 + 8 + 4 + 9 + 4),	/* Length */
+		tpm_u32(TPM2_CC_NV_READ),	/* Command code */
+
+		/* handles 8 bytes */
+		tpm_u32(TPM2_RH_PLATFORM),	/* Primary platform seed */
+		tpm_u32(HR_NV_INDEX + index),	/* Password authorisation */
+
+		/* AUTH_SESSION */
+		tpm_u32(9),			/* Authorization size */
+		tpm_u32(TPM2_RS_PW),		/* Session handle */
+		tpm_u16(0),			/* Size of <nonce> */
+						/* <nonce> (if any) */
+		0,				/* Attributes: Cont/Excl/Rst */
+		tpm_u16(0),			/* Size of <hmac/password> */
+						/* <hmac/password> (if any) */
+
+		tpm_u16(count),			/* Number of bytes */
+		tpm_u16(0),			/* Offset */
+	};
+	size_t response_len = COMMAND_BUFFER_SIZE;
+	u8 response[COMMAND_BUFFER_SIZE];
+	int ret;
+	u16 tag;
+	u32 size, code;
+
+	ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
+	if (ret)
+		return log_msg_ret("read", ret);
+	if (unpack_byte_string(response, response_len, "wdds",
+			       0, &tag, 2, &size, 6, &code,
+			       16, data, count))
+		return TPM_LIB_ERROR;
+
+	return 0;
+}
+
+u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
+			u32 count)
+{
+	struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+	uint offset = 10 + 8 + 4 + 9 + 2;
+	uint len = offset + count + 2;
+	/* Use empty password auth if platform hierarchy is disabled */
+	u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
+		TPM2_RH_PLATFORM;
+	u8 command_v2[COMMAND_BUFFER_SIZE] = {
+		/* header 10 bytes */
+		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
+		tpm_u32(len),			/* Length */
+		tpm_u32(TPM2_CC_NV_WRITE),	/* Command code */
+
+		/* handles 8 bytes */
+		tpm_u32(auth),			/* Primary platform seed */
+		tpm_u32(HR_NV_INDEX + index),	/* Password authorisation */
+
+		/* AUTH_SESSION */
+		tpm_u32(9),			/* Authorization size */
+		tpm_u32(TPM2_RS_PW),		/* Session handle */
+		tpm_u16(0),			/* Size of <nonce> */
+						/* <nonce> (if any) */
+		0,				/* Attributes: Cont/Excl/Rst */
+		tpm_u16(0),			/* Size of <hmac/password> */
+						/* <hmac/password> (if any) */
+
+		tpm_u16(count),
+	};
+	size_t response_len = COMMAND_BUFFER_SIZE;
+	u8 response[COMMAND_BUFFER_SIZE];
+	int ret;
+
+	ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
+			       offset, data, count,
+			       offset + count, 0);
+	if (ret)
+		return TPM_LIB_ERROR;
+
+	return tpm_sendrecv_command(dev, command_v2, response, &response_len);
+}
+
 u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
 		  void *data, unsigned int *updates)
 {
@@ -467,3 +601,61 @@
 
 	return 0;
 }
+
+u32 tpm2_write_lock(struct udevice *dev, u32 index)
+{
+	u8 command_v2[COMMAND_BUFFER_SIZE] = {
+		/* header 10 bytes */
+		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
+		tpm_u32(10 + 8 + 13), /* Length */
+		tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
+
+		/* handles 8 bytes */
+		tpm_u32(TPM2_RH_PLATFORM),	/* Primary platform seed */
+		tpm_u32(HR_NV_INDEX + index),	/* Password authorisation */
+
+		/* session header 9 bytes */
+		tpm_u32(9),			/* Header size */
+		tpm_u32(TPM2_RS_PW),		/* Password authorisation */
+		tpm_u16(0),			/* nonce_size */
+		0,				/* session_attrs */
+		tpm_u16(0),			/* auth_size */
+	};
+
+	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+}
+
+u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
+{
+	struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+	u8 command_v2[COMMAND_BUFFER_SIZE] = {
+		/* header 10 bytes */
+		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
+		tpm_u32(10 + 4 + 13 + 5),	/* Length */
+		tpm_u32(TPM2_CC_HIER_CONTROL),	/* Command code */
+
+		/* 4 bytes */
+		tpm_u32(TPM2_RH_PLATFORM),	/* Primary platform seed */
+
+		/* session header 9 bytes */
+		tpm_u32(9),			/* Header size */
+		tpm_u32(TPM2_RS_PW),		/* Password authorisation */
+		tpm_u16(0),			/* nonce_size */
+		0,				/* session_attrs */
+		tpm_u16(0),			/* auth_size */
+
+		/* payload 5 bytes */
+		tpm_u32(TPM2_RH_PLATFORM),	/* Hierarchy to disable */
+		0,				/* 0=disable */
+	};
+	int ret;
+
+	ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+	log_info("ret=%s, %x\n", dev->name, ret);
+	if (ret)
+		return ret;
+
+	priv->plat_hier_disabled = true;
+
+	return 0;
+}
diff --git a/lib/tpm_api.c b/lib/tpm_api.c
new file mode 100644
index 0000000..4c66264
--- /dev/null
+++ b/lib/tpm_api.c
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <tpm_api.h>
+#include <tpm-v1.h>
+#include <tpm-v2.h>
+#include <tpm_api.h>
+
+static bool is_tpm1(struct udevice *dev)
+{
+	return IS_ENABLED(CONFIG_TPM_V1) && tpm_get_version(dev) == TPM_V1;
+}
+
+static bool is_tpm2(struct udevice *dev)
+{
+	return IS_ENABLED(CONFIG_TPM_V2) && tpm_get_version(dev) == TPM_V2;
+}
+
+u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode)
+{
+	if (is_tpm1(dev)) {
+		return tpm1_startup(dev, mode);
+	} else if (is_tpm2(dev)) {
+		enum tpm2_startup_types type;
+
+		switch (mode) {
+		case TPM_ST_CLEAR:
+			type = TPM2_SU_CLEAR;
+			break;
+		case TPM_ST_STATE:
+			type = TPM2_SU_STATE;
+			break;
+		default:
+		case TPM_ST_DEACTIVATED:
+			return -EINVAL;
+		}
+		return tpm2_startup(dev, type);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+u32 tpm_resume(struct udevice *dev)
+{
+	if (is_tpm1(dev))
+		return tpm1_startup(dev, TPM_ST_STATE);
+	else if (is_tpm2(dev))
+		return tpm2_startup(dev, TPM2_SU_STATE);
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_self_test_full(struct udevice *dev)
+{
+	if (is_tpm1(dev))
+		return tpm1_self_test_full(dev);
+	else if (is_tpm2(dev))
+		return tpm2_self_test(dev, TPMI_YES);
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_continue_self_test(struct udevice *dev)
+{
+	if (is_tpm1(dev))
+		return tpm1_continue_self_test(dev);
+	else if (is_tpm2(dev))
+		return tpm2_self_test(dev, TPMI_NO);
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_clear_and_reenable(struct udevice *dev)
+{
+	u32 ret;
+
+	log_info("TPM: Clear and re-enable\n");
+	ret = tpm_force_clear(dev);
+	if (ret != TPM_SUCCESS) {
+		log_err("Can't initiate a force clear\n");
+		return ret;
+	}
+
+	if (is_tpm1(dev)) {
+		ret = tpm1_physical_enable(dev);
+		if (ret != TPM_SUCCESS) {
+			log_err("TPM: Can't set enabled state\n");
+			return ret;
+		}
+
+		ret = tpm1_physical_set_deactivated(dev, 0);
+		if (ret != TPM_SUCCESS) {
+			log_err("TPM: Can't set deactivated state\n");
+			return ret;
+		}
+	}
+
+	return TPM_SUCCESS;
+}
+
+u32 tpm_nv_enable_locking(struct udevice *dev)
+{
+	if (is_tpm1(dev))
+		return tpm1_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
+	else if (is_tpm2(dev))
+		return -ENOSYS;
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
+{
+	if (is_tpm1(dev))
+		return tpm1_nv_read_value(dev, index, data, count);
+	else if (is_tpm2(dev))
+		return tpm2_nv_read_value(dev, index, data, count);
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
+		       u32 count)
+{
+	if (is_tpm1(dev))
+		return tpm1_nv_write_value(dev, index, data, count);
+	else if (is_tpm2(dev))
+		return tpm2_nv_write_value(dev, index, data, count);
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_set_global_lock(struct udevice *dev)
+{
+	return tpm_nv_write_value(dev, TPM_NV_INDEX_0, NULL, 0);
+}
+
+u32 tpm_write_lock(struct udevice *dev, u32 index)
+{
+	if (is_tpm1(dev))
+		return -ENOSYS;
+	else if (is_tpm2(dev))
+		return tpm2_write_lock(dev, index);
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest,
+		   void *out_digest)
+{
+	if (is_tpm1(dev))
+		return tpm1_extend(dev, index, in_digest, out_digest);
+	else if (is_tpm2(dev))
+		return tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, in_digest,
+				       TPM2_DIGEST_LEN);
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
+{
+	if (is_tpm1(dev))
+		return tpm1_pcr_read(dev, index, data, count);
+	else if (is_tpm2(dev))
+		return -ENOSYS;
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence)
+{
+	if (is_tpm1(dev))
+		return tpm1_tsc_physical_presence(dev, presence);
+
+	/*
+	 * Nothing to do on TPM2 for this; use platform hierarchy availability
+	 * instead.
+	 */
+	else if (is_tpm2(dev))
+		return 0;
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_finalise_physical_presence(struct udevice *dev)
+{
+	if (is_tpm1(dev))
+		return tpm1_finalise_physical_presence(dev);
+
+	/* Nothing needs to be done with tpm2 */
+	else if (is_tpm2(dev))
+		return 0;
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count)
+{
+	if (is_tpm1(dev))
+		return tpm1_read_pubek(dev, data, count);
+	else if (is_tpm2(dev))
+		return -ENOSYS; /* not implemented yet */
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_force_clear(struct udevice *dev)
+{
+	if (is_tpm1(dev))
+		return tpm1_force_clear(dev);
+	else if (is_tpm2(dev))
+		return tpm2_clear(dev, TPM2_RH_PLATFORM, NULL, 0);
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_physical_enable(struct udevice *dev)
+{
+	if (is_tpm1(dev))
+		return tpm1_physical_enable(dev);
+
+	/* Nothing needs to be done with tpm2 */
+	else if (is_tpm2(dev))
+		return 0;
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_physical_disable(struct udevice *dev)
+{
+	if (is_tpm1(dev))
+		return tpm1_physical_disable(dev);
+
+	/* Nothing needs to be done with tpm2 */
+	else if (is_tpm2(dev))
+		return 0;
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state)
+{
+	if (is_tpm1(dev))
+		return tpm1_physical_set_deactivated(dev, state);
+	/* Nothing needs to be done with tpm2 */
+	else if (is_tpm2(dev))
+		return 0;
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
+		       void *cap, size_t count)
+{
+	if (is_tpm1(dev))
+		return tpm1_get_capability(dev, cap_area, sub_cap, cap, count);
+	else if (is_tpm2(dev))
+		return tpm2_get_capability(dev, cap_area, sub_cap, cap, count);
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm)
+{
+	if (is_tpm1(dev))
+		return tpm1_get_permissions(dev, index, perm);
+	else if (is_tpm2(dev))
+		return -ENOSYS; /* not implemented yet */
+	else
+		return -ENOSYS;
+}
+
+u32 tpm_get_random(struct udevice *dev, void *data, u32 count)
+{
+	if (is_tpm1(dev))
+		return tpm1_get_random(dev, data, count);
+	else if (is_tpm2(dev))
+		return -ENOSYS; /* not implemented yet */
+	else
+		return -ENOSYS;
+}
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index 43295ee..85857a7 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -1629,7 +1629,6 @@
 CONFIG_STV0991_HZ
 CONFIG_STV0991_HZ_CLOCK
 CONFIG_ST_SMI
-CONFIG_SUNXI_MAX_FB_SIZE
 CONFIG_SXNI855T
 CONFIG_SYSFLAGS_ADDR
 CONFIG_SYSFS
diff --git a/test/Makefile b/test/Makefile
index 932e517..a26e915 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -2,6 +2,9 @@
 #
 # (C) Copyright 2012 The Chromium Authors
 
+obj-y += test-main.o
+obj-$(CONFIG_SANDBOX) += image/
+
 ifneq ($(CONFIG_$(SPL_)BLOBLIST),)
 obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o
 obj-$(CONFIG_$(SPL_)CMDLINE) += bootm.o
diff --git a/test/bloblist.c b/test/bloblist.c
index 6953d30..d876b63 100644
--- a/test/bloblist.c
+++ b/test/bloblist.c
@@ -387,9 +387,8 @@
 int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
 		   char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test,
-						 bloblist_test);
-	const int n_ents = ll_entry_count(struct unit_test, bloblist_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(bloblist_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(bloblist_test);
 
 	return cmd_ut_category("bloblist", "bloblist_test_",
 			       tests, n_ents, argc, argv);
diff --git a/test/bootm.c b/test/bootm.c
index 563d6eb..8528982 100644
--- a/test/bootm.c
+++ b/test/bootm.c
@@ -240,8 +240,8 @@
 
 int do_ut_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test, bootm_test);
-	const int n_ents = ll_entry_count(struct unit_test, bootm_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(bootm_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(bootm_test);
 
 	return cmd_ut_category("bootm", "bootm_test_", tests, n_ents,
 			       argc, argv);
diff --git a/test/cmd/mem.c b/test/cmd/mem.c
index fbaa8a4..d76f47c 100644
--- a/test/cmd/mem.c
+++ b/test/cmd/mem.c
@@ -12,8 +12,8 @@
 
 int do_ut_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test, mem_test);
-	const int n_ents = ll_entry_count(struct unit_test, mem_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(mem_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(mem_test);
 
 	return cmd_ut_category("cmd_mem", "mem_test_", tests, n_ents, argc,
 			       argv);
diff --git a/test/cmd/setexpr.c b/test/cmd/setexpr.c
index fd6d869..27113c0 100644
--- a/test/cmd/setexpr.c
+++ b/test/cmd/setexpr.c
@@ -306,8 +306,8 @@
 	ut_asserteq(1, run_command("setexpr.s fred 0", 0));
 	ut_assertok(ut_check_delta(start_mem));
 
-	start_mem = ut_check_free();
 	ut_assertok(env_set("fred", "12345"));
+	start_mem = ut_check_free();
 	ut_assertok(run_command("setexpr.s fred *0", 0));
 	ut_asserteq_str("hello", env_get("fred"));
 	ut_assertok(ut_check_delta(start_mem));
@@ -345,7 +345,22 @@
 	start_mem = ut_check_free();
 	ut_assertok(run_command("setexpr.s fred *0 + *10", 0));
 	ut_asserteq_str("hello there", env_get("fred"));
-	ut_assertok(ut_check_delta(start_mem));
+
+	/*
+	 * This check does not work with sandbox_flattree, apparently due to
+	 * memory allocations in env_set().
+	 *
+	 * The truetype console produces lots of memory allocations even though
+	 * the LCD display is not visible. But even without these, it does not
+	 * work.
+	 *
+	 * A better test would be for dlmalloc to record the allocs and frees
+	 * for a particular caller, but that is not supported.
+	 *
+	 * For now, drop this test.
+	 *
+	 * ut_assertok(ut_check_delta(start_mem));
+	 */
 
 	unmap_sysmem(buf);
 
@@ -375,10 +390,9 @@
 
 int do_ut_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test,
-						 setexpr_test);
-	const int n_ents = ll_entry_count(struct unit_test, setexpr_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(setexpr_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(setexpr_test);
 
-	return cmd_ut_category("cmd_setexpr", "cmd_mem_", tests, n_ents, argc,
-			       argv);
+	return cmd_ut_category("cmd_setexpr", "setexpr_test_", tests, n_ents,
+			       argc, argv);
 }
diff --git a/test/cmd_ut.c b/test/cmd_ut.c
index 8728cc8..b9c1660 100644
--- a/test/cmd_ut.c
+++ b/test/cmd_ut.c
@@ -9,6 +9,7 @@
 #include <console.h>
 #include <test/suites.h>
 #include <test/test.h>
+#include <test/ut.h>
 
 static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc,
 		     char *const argv[]);
@@ -17,41 +18,12 @@
 		    struct unit_test *tests, int n_ents,
 		    int argc, char *const argv[])
 {
-	struct unit_test_state uts = { .fail_count = 0 };
-	struct unit_test *test;
-	int prefix_len = prefix ? strlen(prefix) : 0;
+	int ret;
 
-	if (argc == 1)
-		printf("Running %d %s tests\n", n_ents, name);
+	ret = ut_run_list(name, prefix, tests, n_ents,
+			  argc > 1 ? argv[1] : NULL);
 
-	for (test = tests; test < tests + n_ents; test++) {
-		const char *test_name = test->name;
-
-		/* Remove the prefix */
-		if (prefix && !strncmp(test_name, prefix, prefix_len))
-			test_name += prefix_len;
-
-		if (argc > 1 && strcmp(argv[1], test_name))
-			continue;
-		printf("Test: %s\n", test->name);
-
-		if (test->flags & UT_TESTF_CONSOLE_REC) {
-			int ret = console_record_reset_enable();
-
-			if (ret) {
-				printf("Skipping: Console recording disabled\n");
-				continue;
-			}
-		}
-
-		uts.start = mallinfo();
-
-		test->func(&uts);
-	}
-
-	printf("Failures: %d\n", uts.fail_count);
-
-	return uts.fail_count ? CMD_RET_FAILURE : 0;
+	return ret ? CMD_RET_FAILURE : 0;
 }
 
 static struct cmd_tbl cmd_ut_sub[] = {
diff --git a/test/compression.c b/test/compression.c
index a2a4b9f..4cd1be5 100644
--- a/test/compression.c
+++ b/test/compression.c
@@ -539,9 +539,8 @@
 int do_ut_compression(struct cmd_tbl *cmdtp, int flag, int argc,
 		      char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test,
-						 compression_test);
-	const int n_ents = ll_entry_count(struct unit_test, compression_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(compression_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(compression_test);
 
 	return cmd_ut_category("compression", "compression_test_",
 			       tests, n_ents, argc, argv);
diff --git a/test/dm/Makefile b/test/dm/Makefile
index fd14551..f5cc554 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -2,7 +2,7 @@
 #
 # Copyright (c) 2013 Google, Inc
 
-obj-$(CONFIG_UT_DM) += test-main.o
+obj-$(CONFIG_UT_DM) += test-dm.o
 
 # Tests for particular subsystems - when enabling driver model for a new
 # subsystem you must add sandbox tests here.
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index 240187c..2edab7be 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -360,24 +360,24 @@
 	run_command("acpi list", 0);
 	addr = (ulong)map_to_sysmem(buf);
 	ut_assert_nextline("ACPI tables start at %lx", addr);
-	ut_assert_nextline("RSDP %08lx %06lx (v02 U-BOOT)", addr,
+	ut_assert_nextline("RSDP %08lx %06zx (v02 U-BOOT)", addr,
 			   sizeof(struct acpi_rsdp));
 	addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16);
-	ut_assert_nextline("RSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
+	ut_assert_nextline("RSDT %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
 			   addr, sizeof(struct acpi_table_header) +
 			   3 * sizeof(u32), U_BOOT_BUILD_DATE);
 	addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16);
-	ut_assert_nextline("XSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
+	ut_assert_nextline("XSDT %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
 			   addr, sizeof(struct acpi_table_header) +
 			   3 * sizeof(u64), U_BOOT_BUILD_DATE);
 	addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64);
-	ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
+	ut_assert_nextline("DMAR %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
 			   addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
 	addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
-	ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
+	ut_assert_nextline("DMAR %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
 			   addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
 	addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
-	ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
+	ut_assert_nextline("DMAR %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
 			   addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
 	ut_assert_console_end();
 
diff --git a/test/dm/core.c b/test/dm/core.c
index 35ca689..2210345 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -117,14 +117,13 @@
 /* Test that binding with plat occurs correctly */
 static int dm_test_autobind(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	struct udevice *dev;
 
 	/*
 	 * We should have a single class (UCLASS_ROOT) and a single root
 	 * device with no children.
 	 */
-	ut_assert(dms->root);
+	ut_assert(uts->root);
 	ut_asserteq(1, list_count_items(gd->uclass_root));
 	ut_asserteq(0, list_count_items(&gd->dm_root->child_head));
 	ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]);
@@ -207,7 +206,6 @@
 /* Test that autoprobe finds all the expected devices */
 static int dm_test_autoprobe(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	int expected_base_add;
 	struct udevice *dev;
 	struct uclass *uc;
@@ -221,7 +219,7 @@
 	ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]);
 
 	/* The root device should not be activated until needed */
-	ut_assert(dev_get_flags(dms->root) & DM_FLAG_ACTIVATED);
+	ut_assert(dev_get_flags(uts->root) & DM_FLAG_ACTIVATED);
 
 	/*
 	 * We should be able to find the three test devices, and they should
@@ -241,7 +239,7 @@
 
 		/* Activating a device should activate the root device */
 		if (!i)
-			ut_assert(dev_get_flags(dms->root) & DM_FLAG_ACTIVATED);
+			ut_assert(dev_get_flags(uts->root) & DM_FLAG_ACTIVATED);
 	}
 
 	/*
@@ -293,7 +291,6 @@
 /* Test that we can bind, probe, remove, unbind a driver */
 static int dm_test_lifecycle(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	int op_count[DM_TEST_OP_COUNT];
 	struct udevice *dev, *test_dev;
 	int pingret;
@@ -301,7 +298,7 @@
 
 	memcpy(op_count, dm_testdrv_op_count, sizeof(op_count));
 
-	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
+	ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
 					&dev));
 	ut_assert(dev);
 	ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND]
@@ -309,7 +306,7 @@
 	ut_assert(!dev_get_priv(dev));
 
 	/* Probe the device - it should fail allocating private data */
-	dms->force_fail_alloc = 1;
+	uts->force_fail_alloc = 1;
 	ret = device_probe(dev);
 	ut_assert(ret == -ENOMEM);
 	ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE]
@@ -317,7 +314,7 @@
 	ut_assert(!dev_get_priv(dev));
 
 	/* Try again without the alloc failure */
-	dms->force_fail_alloc = 0;
+	uts->force_fail_alloc = 0;
 	ut_assertok(device_probe(dev));
 	ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE]
 			== op_count[DM_TEST_OP_PROBE] + 2);
@@ -349,19 +346,18 @@
 /* Test that we can bind/unbind and the lists update correctly */
 static int dm_test_ordering(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	struct udevice *dev, *dev_penultimate, *dev_last, *test_dev;
 	int pingret;
 
-	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
+	ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
 					&dev));
 	ut_assert(dev);
 
 	/* Bind two new devices (numbers 4 and 5) */
-	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
+	ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
 					&dev_penultimate));
 	ut_assert(dev_penultimate);
-	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
+	ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
 					&dev_last));
 	ut_assert(dev_last);
 
@@ -376,7 +372,7 @@
 	ut_assert(dev_last == test_dev);
 
 	/* Add back the original device 3, now in position 5 */
-	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
+	ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
 					&dev));
 	ut_assert(dev);
 
@@ -568,7 +564,6 @@
 
 static int dm_test_children(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	struct udevice *top[NODE_COUNT];
 	struct udevice *child[NODE_COUNT];
 	struct udevice *grandchild[NODE_COUNT];
@@ -578,12 +573,12 @@
 	int i;
 
 	/* We don't care about the numbering for this test */
-	dms->skip_post_probe = 1;
+	uts->skip_post_probe = 1;
 
 	ut_assert(NODE_COUNT > 5);
 
 	/* First create 10 top-level children */
-	ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top));
+	ut_assertok(create_children(uts, uts->root, NODE_COUNT, 0, top));
 
 	/* Now a few have their own children */
 	ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL));
@@ -654,7 +649,6 @@
 
 static int dm_test_device_reparent(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	struct udevice *top[NODE_COUNT];
 	struct udevice *child[NODE_COUNT];
 	struct udevice *grandchild[NODE_COUNT];
@@ -664,12 +658,12 @@
 	int i;
 
 	/* We don't care about the numbering for this test */
-	dms->skip_post_probe = 1;
+	uts->skip_post_probe = 1;
 
 	ut_assert(NODE_COUNT > 5);
 
 	/* First create 10 top-level children */
-	ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top));
+	ut_assertok(create_children(uts, uts->root, NODE_COUNT, 0, top));
 
 	/* Now a few have their own children */
 	ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL));
@@ -815,15 +809,14 @@
 /* Test that pre-relocation devices work as expected */
 static int dm_test_pre_reloc(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	struct udevice *dev;
 
 	/* The normal driver should refuse to bind before relocation */
-	ut_asserteq(-EPERM, device_bind_by_name(dms->root, true,
+	ut_asserteq(-EPERM, device_bind_by_name(uts->root, true,
 						&driver_info_manual, &dev));
 
 	/* But this one is marked pre-reloc */
-	ut_assertok(device_bind_by_name(dms->root, true,
+	ut_assertok(device_bind_by_name(uts->root, true,
 					&driver_info_pre_reloc, &dev));
 
 	return 0;
@@ -836,10 +829,9 @@
  */
 static int dm_test_remove_active_dma(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	struct udevice *dev;
 
-	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_act_dma,
+	ut_assertok(device_bind_by_name(uts->root, false, &driver_info_act_dma,
 					&dev));
 	ut_assert(dev);
 
@@ -872,7 +864,7 @@
 	 * the active DMA remove call
 	 */
 	ut_assertok(device_unbind(dev));
-	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
+	ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
 					&dev));
 	ut_assert(dev);
 
@@ -895,25 +887,24 @@
 /* Test removal of 'vital' devices */
 static int dm_test_remove_vital(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	struct udevice *normal, *dma, *vital, *dma_vital;
 
 	/* Skip the behaviour in test_post_probe() */
-	dms->skip_post_probe = 1;
+	uts->skip_post_probe = 1;
 
-	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
+	ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
 					&normal));
 	ut_assertnonnull(normal);
 
-	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_act_dma,
+	ut_assertok(device_bind_by_name(uts->root, false, &driver_info_act_dma,
 					&dma));
 	ut_assertnonnull(dma);
 
-	ut_assertok(device_bind_by_name(dms->root, false,
+	ut_assertok(device_bind_by_name(uts->root, false,
 					&driver_info_vital_clk, &vital));
 	ut_assertnonnull(vital);
 
-	ut_assertok(device_bind_by_name(dms->root, false,
+	ut_assertok(device_bind_by_name(uts->root, false,
 					&driver_info_act_dma_vital_clk,
 					&dma_vital));
 	ut_assertnonnull(dma_vital);
@@ -1133,11 +1124,10 @@
 
 static int dm_test_inactive_child(struct unit_test_state *uts)
 {
-	struct dm_test_state *dms = uts->priv;
 	struct udevice *parent, *dev1, *dev2;
 
 	/* Skip the behaviour in test_post_probe() */
-	dms->skip_post_probe = 1;
+	uts->skip_post_probe = 1;
 
 	ut_assertok(uclass_first_device_err(UCLASS_TEST, &parent));
 
diff --git a/test/dm/gpio.c b/test/dm/gpio.c
index d7b85e7..33ae987 100644
--- a/test/dm/gpio.c
+++ b/test/dm/gpio.c
@@ -80,15 +80,15 @@
 
 	/* Make it an open drain output, and reset it */
 	ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE,
-		    sandbox_gpio_get_dir_flags(dev, offset));
-	ut_assertok(ops->set_dir_flags(dev, offset,
-				       GPIOD_IS_OUT | GPIOD_OPEN_DRAIN));
+		    sandbox_gpio_get_flags(dev, offset));
+	ut_assertok(ops->set_flags(dev, offset,
+				   GPIOD_IS_OUT | GPIOD_OPEN_DRAIN));
 	ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
-		    sandbox_gpio_get_dir_flags(dev, offset));
-	ut_assertok(ops->set_dir_flags(dev, offset,
-				       GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE));
+		    sandbox_gpio_get_flags(dev, offset));
+	ut_assertok(ops->set_flags(dev, offset,
+				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE));
 	ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE,
-		    sandbox_gpio_get_dir_flags(dev, offset));
+		    sandbox_gpio_get_flags(dev, offset));
 
 	/* Make it an input */
 	ut_assertok(ops->direction_input(dev, offset));
@@ -176,54 +176,64 @@
 
 	/* GPIO 0 is (GPIO_OUT|GPIO_OPEN_DRAIN) */
 	ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
-		    sandbox_gpio_get_dir_flags(gpio_c, 0));
+		    sandbox_gpio_get_flags(gpio_c, 0));
 
-	/* Set it as output high, should become an input */
+	/* Set it as output high */
 	ut_assertok(dm_gpio_set_value(&desc_list[0], 1));
-	ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf)));
-	ut_asserteq_str("c0: input: 0 [x] a-test.test3-gpios0", buf);
+	ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN | GPIOD_IS_OUT_ACTIVE,
+		    sandbox_gpio_get_flags(gpio_c, 0));
 
-	/* Set it as output low, should become output low */
+	/* Set it as output low */
 	ut_assertok(dm_gpio_set_value(&desc_list[0], 0));
-	ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf)));
-	ut_asserteq_str("c0: output: 0 [x] a-test.test3-gpios0", buf);
+	ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
+		    sandbox_gpio_get_flags(gpio_c, 0));
 
 	/* GPIO 1 is (GPIO_OUT|GPIO_OPEN_SOURCE) */
 	ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
-		    sandbox_gpio_get_dir_flags(gpio_c, 1));
+		    sandbox_gpio_get_flags(gpio_c, 1));
 
 	/* Set it as output high, should become output high */
 	ut_assertok(dm_gpio_set_value(&desc_list[1], 1));
 	ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf)));
 	ut_asserteq_str("c1: output: 1 [x] a-test.test3-gpios1", buf);
 
-	/* Set it as output low, should become an input */
+	/* Set it as output low */
 	ut_assertok(dm_gpio_set_value(&desc_list[1], 0));
-	ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf)));
-	ut_asserteq_str("c1: input: 1 [x] a-test.test3-gpios1", buf);
+	ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
+		    sandbox_gpio_get_flags(gpio_c, 1));
 
-	/* GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN) */
-	ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
-		    sandbox_gpio_get_dir_flags(gpio_c, 6));
+	ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf)));
+	ut_asserteq_str("c1: output: 0 [x] a-test.test3-gpios1", buf);
+
+	/*
+	 * GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN). Looking at it
+	 * directlt from the driver, we get GPIOD_IS_OUT_ACTIVE also, since it
+	 * is active low
+	 */
+	ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN |
+		    GPIOD_IS_OUT_ACTIVE,
+		    sandbox_gpio_get_flags(gpio_c, 6));
 
 	/* Set it as output high, should become output low */
 	ut_assertok(dm_gpio_set_value(&desc_list[6], 1));
 	ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf)));
 	ut_asserteq_str("c6: output: 0 [x] a-test.test3-gpios6", buf);
 
-	/* Set it as output low, should become an input */
+	/* Set it as output low */
 	ut_assertok(dm_gpio_set_value(&desc_list[6], 0));
-	ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf)));
-	ut_asserteq_str("c6: input: 0 [x] a-test.test3-gpios6", buf);
+	ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN |
+		    GPIOD_IS_OUT_ACTIVE,
+		    sandbox_gpio_get_flags(gpio_c, 6));
 
 	/* GPIO 7 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_SOURCE) */
-	ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
-		    sandbox_gpio_get_dir_flags(gpio_c, 7));
+	ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE |
+		    GPIOD_IS_OUT_ACTIVE,
+		    sandbox_gpio_get_flags(gpio_c, 7));
 
-	/* Set it as output high, should become an input */
+	/* Set it as output high */
 	ut_assertok(dm_gpio_set_value(&desc_list[7], 1));
-	ut_assertok(gpio_get_status(gpio_c, 7, buf, sizeof(buf)));
-	ut_asserteq_str("c7: input: 0 [x] a-test.test3-gpios7", buf);
+	ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
+		    sandbox_gpio_get_flags(gpio_c, 7));
 
 	/* Set it as output low, should become output high */
 	ut_assertok(dm_gpio_set_value(&desc_list[7], 0));
@@ -363,12 +373,12 @@
 	ut_assertok(gpio_free_list(dev, desc_list, 3));
 
 	ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE,
-		    sandbox_gpio_get_dir_flags(gpio_a, 1));
+		    sandbox_gpio_get_flags(gpio_a, 1));
 	ut_asserteq(6, gpio_request_list_by_name(dev, "test2-gpios", desc_list,
 						 ARRAY_SIZE(desc_list), 0));
 
 	/* This was set to output previously but flags resetted to 0 = INPUT */
-	ut_asserteq(0, sandbox_gpio_get_dir_flags(gpio_a, 1));
+	ut_asserteq(0, sandbox_gpio_get_flags(gpio_a, 1));
 	ut_asserteq(GPIOF_INPUT, gpio_get_function(gpio_a, 1, NULL));
 
 	/* Active low should invert the input value */
@@ -397,22 +407,22 @@
 	ut_asserteq(6, gpio_request_list_by_name(dev, "test3-gpios", desc_list,
 						 ARRAY_SIZE(desc_list), 0));
 
-	ut_assertok(dm_gpio_get_dir_flags(&desc_list[0], &flags));
+	ut_assertok(dm_gpio_get_flags(&desc_list[0], &flags));
 	ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, flags);
 
-	ut_assertok(dm_gpio_get_dir_flags(&desc_list[1], &flags));
+	ut_assertok(dm_gpio_get_flags(&desc_list[1], &flags));
 	ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, flags);
 
-	ut_assertok(dm_gpio_get_dir_flags(&desc_list[2], &flags));
+	ut_assertok(dm_gpio_get_flags(&desc_list[2], &flags));
 	ut_asserteq(GPIOD_IS_OUT, flags);
 
-	ut_assertok(dm_gpio_get_dir_flags(&desc_list[3], &flags));
+	ut_assertok(dm_gpio_get_flags(&desc_list[3], &flags));
 	ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, flags);
 
-	ut_assertok(dm_gpio_get_dir_flags(&desc_list[4], &flags));
+	ut_assertok(dm_gpio_get_flags(&desc_list[4], &flags));
 	ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_DOWN, flags);
 
-	ut_assertok(dm_gpio_get_dir_flags(&desc_list[5], &flags));
+	ut_assertok(dm_gpio_get_flags(&desc_list[5], &flags));
 	ut_asserteq(GPIOD_IS_IN, flags);
 
 	ut_assertok(gpio_free_list(dev, desc_list, 6));
@@ -582,3 +592,189 @@
 	return 0;
 }
 DM_TEST(dm_test_gpio_devm, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int dm_test_clrset_flags(struct unit_test_state *uts)
+{
+	struct gpio_desc desc;
+	struct udevice *dev;
+	ulong flags;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc, 0));
+
+	ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_OUT));
+	ut_assertok(dm_gpio_get_flags(&desc, &flags));
+	ut_asserteq(GPIOD_IS_OUT, flags);
+	ut_asserteq(GPIOD_IS_OUT, desc.flags);
+	ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset));
+
+	ut_assertok(dm_gpio_clrset_flags(&desc, 0, GPIOD_IS_OUT_ACTIVE));
+	ut_assertok(dm_gpio_get_flags(&desc, &flags));
+	ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, flags);
+	ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, desc.flags);
+	ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset));
+	ut_asserteq(1, dm_gpio_get_value(&desc));
+
+	ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_IN));
+	ut_assertok(dm_gpio_get_flags(&desc, &flags));
+	ut_asserteq(GPIOD_IS_IN, flags & GPIOD_MASK_DIR);
+	ut_asserteq(GPIOD_IS_IN, desc.flags & GPIOD_MASK_DIR);
+
+	ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_PULL,
+					 GPIOD_PULL_UP));
+	ut_assertok(dm_gpio_get_flags(&desc, &flags));
+	ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, flags);
+	ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, desc.flags);
+
+	/* Check we cannot set both PULL_UP and PULL_DOWN */
+	ut_asserteq(-EINVAL, dm_gpio_clrset_flags(&desc, 0, GPIOD_PULL_DOWN));
+
+	return 0;
+}
+DM_TEST(dm_test_clrset_flags, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* Check that an active-low GPIO works as expected */
+static int dm_test_clrset_flags_invert(struct unit_test_state *uts)
+{
+	struct gpio_desc desc;
+	struct udevice *dev;
+	ulong flags;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc,
+					 GPIOD_IS_OUT | GPIOD_ACTIVE_LOW));
+
+	/*
+	 * From this size we see it as 0 (active low), but the sandbox driver
+	 * sees the pin value high
+	 */
+	ut_asserteq(0, dm_gpio_get_value(&desc));
+	ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset));
+
+	ut_assertok(dm_gpio_set_value(&desc, 1));
+	ut_asserteq(1, dm_gpio_get_value(&desc));
+	ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset));
+
+	/* Do the same with dm_gpio_clrset_flags() */
+	ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_IS_OUT_ACTIVE, 0));
+	ut_asserteq(0, dm_gpio_get_value(&desc));
+	ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset));
+
+	ut_assertok(dm_gpio_clrset_flags(&desc, 0, GPIOD_IS_OUT_ACTIVE));
+	ut_asserteq(1, dm_gpio_get_value(&desc));
+	ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset));
+
+	ut_assertok(dm_gpio_get_flags(&desc, &flags));
+	ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE,
+		    flags);
+	ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE,
+		    desc.flags);
+
+	ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_IS_OUT_ACTIVE, 0));
+	ut_assertok(dm_gpio_get_flags(&desc, &flags));
+	ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW, flags);
+	ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW, desc.flags);
+
+	return 0;
+}
+DM_TEST(dm_test_clrset_flags_invert, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int set_gpios(struct unit_test_state *uts, struct gpio_desc *desc,
+		     int count, uint value)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		const uint mask = 1 << i;
+
+		ut_assertok(sandbox_gpio_set_value(desc[i].dev, desc[i].offset,
+						   value & mask));
+	}
+
+	return 0;
+}
+
+/* Check that an active-low GPIO works as expected */
+static int dm_test_gpio_get_values_as_int(struct unit_test_state *uts)
+{
+	const int gpio_count = 3;
+	struct gpio_desc desc[gpio_count];
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc,
+						 gpio_count, GPIOD_IS_IN));
+	ut_assertok(set_gpios(uts, desc, gpio_count, 0));
+	ut_asserteq(0, dm_gpio_get_values_as_int(desc, gpio_count));
+
+	ut_assertok(set_gpios(uts, desc, gpio_count, 5));
+	ut_asserteq(5, dm_gpio_get_values_as_int(desc, gpio_count));
+
+	ut_assertok(set_gpios(uts, desc, gpio_count, 7));
+	ut_asserteq(7, dm_gpio_get_values_as_int(desc, gpio_count));
+
+	return 0;
+}
+DM_TEST(dm_test_gpio_get_values_as_int,
+	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* Check that an active-low GPIO works as expected */
+static int dm_test_gpio_get_values_as_int_base3(struct unit_test_state *uts)
+{
+	const int gpio_count = 3;
+	struct gpio_desc desc[gpio_count];
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc,
+						 gpio_count, GPIOD_IS_IN));
+
+	/*
+	 * First test the sandbox GPIO driver works as expected. The external
+	 * pull resistor should be stronger than the internal one.
+	 */
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset,
+			       GPIOD_IS_IN | GPIOD_EXT_PULL_UP | GPIOD_PULL_UP);
+	ut_asserteq(1, dm_gpio_get_value(desc));
+
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_IS_IN |
+			       GPIOD_EXT_PULL_DOWN | GPIOD_PULL_UP);
+	ut_asserteq(0, dm_gpio_get_value(desc));
+
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset,
+			       GPIOD_IS_IN | GPIOD_PULL_UP);
+	ut_asserteq(1, dm_gpio_get_value(desc));
+
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_PULL_DOWN);
+	ut_asserteq(0, dm_gpio_get_value(desc));
+
+	/*
+	 * Set up pins: pull-up (1), pull-down (0) and floating (2). This should
+	 * result in digits 2 0 1, i.e. 2 * 9 + 1 * 3 = 19
+	 */
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_EXT_PULL_UP);
+	sandbox_gpio_set_flags(desc[1].dev, desc[1].offset,
+			       GPIOD_EXT_PULL_DOWN);
+	sandbox_gpio_set_flags(desc[2].dev, desc[2].offset, 0);
+	ut_asserteq(19, dm_gpio_get_values_as_int_base3(desc, gpio_count));
+
+	/*
+	 * Set up pins: floating (2), pull-up (1) and pull-down (0). This should
+	 * result in digits 0 1 2, i.e. 1 * 3 + 2 = 5
+	 */
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, 0);
+	sandbox_gpio_set_flags(desc[1].dev, desc[1].offset, GPIOD_EXT_PULL_UP);
+	sandbox_gpio_set_flags(desc[2].dev, desc[2].offset,
+			       GPIOD_EXT_PULL_DOWN);
+	ut_asserteq(5, dm_gpio_get_values_as_int_base3(desc, gpio_count));
+
+	return 0;
+}
+DM_TEST(dm_test_gpio_get_values_as_int_base3,
+	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c
new file mode 100644
index 0000000..9ba2ba2
--- /dev/null
+++ b/test/dm/test-dm.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013 Google, Inc
+ */
+
+#include <common.h>
+#include <command.h>
+#include <console.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <asm/state.h>
+#include <dm/root.h>
+#include <dm/uclass-internal.h>
+#include <test/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * dm_test_run() - Run driver model tests
+ *
+ * Run all the available driver model tests, or a selection
+ *
+ * @test_name: Name of single test to run (e.g. "dm_test_fdt_pre_reloc" or just
+ *	"fdt_pre_reloc"), or NULL to run all
+ * @return 0 if all tests passed, 1 if not
+ */
+static int dm_test_run(const char *test_name)
+{
+	struct unit_test *tests = UNIT_TEST_SUITE_START(dm_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(dm_test);
+	int ret;
+
+	ret = ut_run_list("driver model", "dm_test_", tests, n_ents, test_name);
+
+	return ret ? CMD_RET_FAILURE : 0;
+}
+
+int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	const char *test_name = NULL;
+
+	if (argc > 1)
+		test_name = argv[1];
+
+	return dm_test_run(test_name);
+}
diff --git a/test/dm/test-driver.c b/test/dm/test-driver.c
index ca7626a..02cb974 100644
--- a/test/dm/test-driver.c
+++ b/test/dm/test-driver.c
@@ -18,7 +18,6 @@
 #include <test/ut.h>
 
 int dm_testdrv_op_count[DM_TEST_OP_COUNT];
-static struct unit_test_state *uts = &global_dm_test_state;
 
 static int testdrv_ping(struct udevice *dev, int pingval, int *pingret)
 {
@@ -37,6 +36,8 @@
 
 static int test_bind(struct udevice *dev)
 {
+	struct unit_test_state *uts = test_get_state();
+
 	/* Private data should not be allocated */
 	ut_assert(!dev_get_priv(dev));
 
@@ -46,6 +47,7 @@
 
 static int test_probe(struct udevice *dev)
 {
+	struct unit_test_state *uts = test_get_state();
 	struct dm_test_priv *priv = dev_get_priv(dev);
 
 	/* Private data should be allocated */
@@ -58,6 +60,8 @@
 
 static int test_remove(struct udevice *dev)
 {
+	struct unit_test_state *uts = test_get_state();
+
 	/* Private data should still be allocated */
 	ut_assert(dev_get_priv(dev));
 
@@ -67,6 +71,8 @@
 
 static int test_unbind(struct udevice *dev)
 {
+	struct unit_test_state *uts = test_get_state();
+
 	/* Private data should not be allocated */
 	ut_assert(!dev_get_priv(dev));
 
@@ -116,10 +122,10 @@
 
 static int test_manual_probe(struct udevice *dev)
 {
-	struct dm_test_state *dms = uts->priv;
+	struct unit_test_state *uts = test_get_state();
 
 	dm_testdrv_op_count[DM_TEST_OP_PROBE]++;
-	if (!dms->force_fail_alloc)
+	if (!uts->force_fail_alloc)
 		dev_set_priv(dev, calloc(1, sizeof(struct dm_test_priv)));
 	if (!dev_get_priv(dev))
 		return -ENOMEM;
diff --git a/test/dm/test-main.c b/test/dm/test-main.c
deleted file mode 100644
index 560f8d6..0000000
--- a/test/dm/test-main.c
+++ /dev/null
@@ -1,230 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2013 Google, Inc
- */
-
-#include <common.h>
-#include <command.h>
-#include <console.h>
-#include <dm.h>
-#include <errno.h>
-#include <log.h>
-#include <malloc.h>
-#include <asm/global_data.h>
-#include <asm/state.h>
-#include <dm/test.h>
-#include <dm/root.h>
-#include <dm/uclass-internal.h>
-#include <test/test.h>
-#include <test/test.h>
-#include <test/ut.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-struct unit_test_state global_dm_test_state;
-static struct dm_test_state _global_priv_dm_test_state;
-
-/* Get ready for testing */
-static int dm_test_init(struct unit_test_state *uts, bool of_live)
-{
-	struct dm_test_state *dms = uts->priv;
-
-	memset(dms, '\0', sizeof(*dms));
-	gd->dm_root = NULL;
-	if (!CONFIG_IS_ENABLED(OF_PLATDATA))
-		memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count));
-	state_reset_for_test(state_get_current());
-
-	/* Determine whether to make the live tree available */
-	gd_set_of_root(of_live ? uts->of_root : NULL);
-	ut_assertok(dm_init(of_live));
-	dms->root = dm_root();
-
-	return 0;
-}
-
-/* Ensure all the test devices are probed */
-static int do_autoprobe(struct unit_test_state *uts)
-{
-	struct udevice *dev;
-	int ret;
-
-	/* Scanning the uclass is enough to probe all the devices */
-	for (ret = uclass_first_device(UCLASS_TEST, &dev);
-	     dev;
-	     ret = uclass_next_device(&dev))
-		;
-
-	return ret;
-}
-
-static int dm_test_destroy(struct unit_test_state *uts)
-{
-	int id;
-
-	for (id = 0; id < UCLASS_COUNT; id++) {
-		struct uclass *uc;
-
-		/*
-		 * If the uclass doesn't exist we don't want to create it. So
-		 * check that here before we call uclass_find_device().
-		 */
-		uc = uclass_find(id);
-		if (!uc)
-			continue;
-		ut_assertok(uclass_destroy(uc));
-	}
-
-	return 0;
-}
-
-static int dm_do_test(struct unit_test_state *uts, struct unit_test *test,
-		      bool of_live)
-{
-	struct sandbox_state *state = state_get_current();
-	const char *fname = strrchr(test->file, '/') + 1;
-
-	printf("Test: %s: %s%s\n", test->name, fname,
-	       !of_live ? " (flat tree)" : "");
-	ut_assertok(dm_test_init(uts, of_live));
-
-	uts->start = mallinfo();
-	if (test->flags & UT_TESTF_SCAN_PDATA)
-		ut_assertok(dm_scan_plat(false));
-	if (test->flags & UT_TESTF_PROBE_TEST)
-		ut_assertok(do_autoprobe(uts));
-	if (!CONFIG_IS_ENABLED(OF_PLATDATA) &&
-	    (test->flags & UT_TESTF_SCAN_FDT))
-		ut_assertok(dm_extended_scan(false));
-
-	/*
-	 * Silence the console and rely on console recording to get
-	 * our output.
-	 */
-	console_record_reset_enable();
-	if (!state->show_test_output)
-		gd->flags |= GD_FLG_SILENT;
-	test->func(uts);
-	gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
-	state_set_skip_delays(false);
-
-	ut_assertok(dm_test_destroy(uts));
-
-	return 0;
-}
-
-/**
- * dm_test_run_on_flattree() - Check if we should run a test with flat DT
- *
- * This skips long/slow tests where there is not much value in running a flat
- * DT test in addition to a live DT test.
- *
- * @return true to run the given test on the flat device tree
- */
-static bool dm_test_run_on_flattree(struct unit_test *test)
-{
-	const char *fname = strrchr(test->file, '/') + 1;
-
-	return !strstr(fname, "video") || strstr(test->name, "video_base");
-}
-
-static bool test_matches(const char *test_name, const char *find_name)
-{
-	if (!find_name)
-		return true;
-
-	if (!strcmp(test_name, find_name))
-		return true;
-
-	/* All tests have this prefix */
-	if (!strncmp(test_name, "dm_test_", 8))
-		test_name += 8;
-
-	if (!strcmp(test_name, find_name))
-		return true;
-
-	return false;
-}
-
-int dm_test_main(const char *test_name)
-{
-	struct unit_test *tests = ll_entry_start(struct unit_test, dm_test);
-	const int n_ents = ll_entry_count(struct unit_test, dm_test);
-	struct unit_test_state *uts = &global_dm_test_state;
-	struct unit_test *test;
-	int found;
-
-	uts->priv = &_global_priv_dm_test_state;
-	uts->fail_count = 0;
-
-	if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
-		/*
-		 * If we have no device tree, or it only has a root node, then
-		 * these * tests clearly aren't going to work...
-		 */
-		if (!gd->fdt_blob || fdt_next_node(gd->fdt_blob, 0, NULL) < 0) {
-			puts("Please run with test device tree:\n"
-			     "    ./u-boot -d arch/sandbox/dts/test.dtb\n");
-			ut_assert(gd->fdt_blob);
-		}
-	}
-
-	if (!test_name)
-		printf("Running %d driver model tests\n", n_ents);
-	else
-
-	found = 0;
-	uts->of_root = gd_of_root();
-	for (test = tests; test < tests + n_ents; test++) {
-		const char *name = test->name;
-		int runs;
-
-		if (!test_matches(name, test_name))
-			continue;
-
-		/* Run with the live tree if possible */
-		runs = 0;
-		if (CONFIG_IS_ENABLED(OF_LIVE)) {
-			if (!(test->flags & UT_TESTF_FLAT_TREE)) {
-				ut_assertok(dm_do_test(uts, test, true));
-				runs++;
-			}
-		}
-
-		/*
-		 * Run with the flat tree if we couldn't run it with live tree,
-		 * or it is a core test.
-		 */
-		if (!(test->flags & UT_TESTF_LIVE_TREE) &&
-		    (!runs || dm_test_run_on_flattree(test))) {
-			ut_assertok(dm_do_test(uts, test, false));
-			runs++;
-		}
-		found++;
-	}
-
-	if (test_name && !found)
-		printf("Test '%s' not found\n", test_name);
-	else
-		printf("Failures: %d\n", uts->fail_count);
-
-	/* Put everything back to normal so that sandbox works as expected */
-	gd_set_of_root(uts->of_root);
-	gd->dm_root = NULL;
-	ut_assertok(dm_init(CONFIG_IS_ENABLED(OF_LIVE)));
-	dm_scan_plat(false);
-	if (!CONFIG_IS_ENABLED(OF_PLATDATA))
-		dm_scan_fdt(false);
-
-	return uts->fail_count ? CMD_RET_FAILURE : 0;
-}
-
-int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
-{
-	const char *test_name = NULL;
-
-	if (argc > 1)
-		test_name = argv[1];
-
-	return dm_test_main(test_name);
-}
diff --git a/test/dm/test-uclass.c b/test/dm/test-uclass.c
index f1b7aaa..0677017 100644
--- a/test/dm/test-uclass.c
+++ b/test/dm/test-uclass.c
@@ -17,8 +17,6 @@
 #include <test/test.h>
 #include <test/ut.h>
 
-static struct unit_test_state *uts = &global_dm_test_state;
-
 int test_ping(struct udevice *dev, int pingval, int *pingret)
 {
 	const struct test_ops *ops = device_get_ops(dev);
@@ -31,6 +29,7 @@
 
 static int test_post_bind(struct udevice *dev)
 {
+	struct unit_test_state *uts = test_get_state();
 	struct dm_test_perdev_uc_pdata *uc_pdata;
 
 	dm_testdrv_op_count[DM_TEST_OP_POST_BIND]++;
@@ -56,6 +55,7 @@
 static int test_pre_probe(struct udevice *dev)
 {
 	struct dm_test_uclass_perdev_priv *priv = dev_get_uclass_priv(dev);
+	struct unit_test_state *uts = test_get_state();
 
 	dm_testdrv_op_count[DM_TEST_OP_PRE_PROBE]++;
 	ut_assert(priv);
@@ -66,18 +66,18 @@
 
 static int test_post_probe(struct udevice *dev)
 {
+	struct unit_test_state *uts = test_get_state();
 	struct udevice *prev = list_entry(dev->uclass_node.prev,
 					    struct udevice, uclass_node);
 
 	struct dm_test_uclass_perdev_priv *priv = dev_get_uclass_priv(dev);
 	struct uclass *uc = dev->uclass;
-	struct dm_test_state *dms = uts->priv;
 
 	dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]++;
 	ut_assert(priv);
 	ut_assert(device_active(dev));
 	priv->base_add = 0;
-	if (dms->skip_post_probe)
+	if (uts->skip_post_probe)
 		return 0;
 	if (&prev->uclass_node != &uc->dev_head) {
 		struct dm_test_uclass_perdev_priv *prev_uc_priv
@@ -101,6 +101,8 @@
 
 static int test_init(struct uclass *uc)
 {
+	struct unit_test_state *uts = test_get_state();
+
 	dm_testdrv_op_count[DM_TEST_OP_INIT]++;
 	ut_assert(uclass_get_priv(uc));
 
diff --git a/test/env/cmd_ut_env.c b/test/env/cmd_ut_env.c
index a440b1b..d65a321 100644
--- a/test/env/cmd_ut_env.c
+++ b/test/env/cmd_ut_env.c
@@ -12,8 +12,8 @@
 
 int do_ut_env(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test, env_test);
-	const int n_ents = ll_entry_count(struct unit_test, env_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(env_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(env_test);
 
 	return cmd_ut_category("environment", "env_test_",
 			       tests, n_ents, argc, argv);
diff --git a/test/image/Makefile b/test/image/Makefile
new file mode 100644
index 0000000..c4039df
--- /dev/null
+++ b/test/image/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2021 Google LLC
+
+obj-$(CONFIG_SPL_BUILD) += spl_load.o
diff --git a/test/image/spl_load.c b/test/image/spl_load.c
new file mode 100644
index 0000000..851603d
--- /dev/null
+++ b/test/image/spl_load.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <image.h>
+#include <mapmem.h>
+#include <os.h>
+#include <spl.h>
+#include <test/ut.h>
+
+/* Declare a new SPL test */
+#define SPL_TEST(_name, _flags)		UNIT_TEST(_name, _flags, spl_test)
+
+/* Context used for this test */
+struct text_ctx {
+	int fd;
+};
+
+static ulong read_fit_image(struct spl_load_info *load, ulong sector,
+			    ulong count, void *buf)
+{
+	struct text_ctx *text_ctx = load->priv;
+	off_t offset, ret;
+	ssize_t res;
+
+	offset = sector * load->bl_len;
+	ret = os_lseek(text_ctx->fd, offset, OS_SEEK_SET);
+	if (ret != offset) {
+		printf("Failed to seek to %zx, got %zx (errno=%d)\n", offset,
+		       ret, errno);
+		return 0;
+	}
+
+	res = os_read(text_ctx->fd, buf, count * load->bl_len);
+	if (res == -1) {
+		printf("Failed to read %lx bytes, got %ld (errno=%d)\n",
+		       count * load->bl_len, res, errno);
+		return 0;
+	}
+
+	return count;
+}
+
+int board_fit_config_name_match(const char *name)
+{
+	return 0;
+}
+
+struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+{
+	return map_sysmem(0x100000, 0);
+}
+
+static int spl_test_load(struct unit_test_state *uts)
+{
+	struct spl_image_info image;
+	struct image_header *header;
+	struct text_ctx text_ctx;
+	struct spl_load_info load;
+	char fname[256];
+	int ret;
+	int fd;
+
+	memset(&load, '\0', sizeof(load));
+	load.bl_len = 512;
+	load.read = read_fit_image;
+
+	ret = os_find_u_boot(fname, sizeof(fname), true);
+	if (ret) {
+		printf("(%s not found, error %d)\n", fname, ret);
+		return ret;
+	}
+	load.filename = fname;
+
+	header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));
+
+	fd = os_open(fname, OS_O_RDONLY);
+	ut_assert(fd >= 0);
+	ut_asserteq(512, os_read(fd, header, 512));
+	text_ctx.fd = fd;
+
+	load.priv = &text_ctx;
+
+	ut_assertok(spl_load_simple_fit(&image, &load, 0, header));
+
+	return 0;
+}
+SPL_TEST(spl_test_load, 0);
diff --git a/test/lib/cmd_ut_lib.c b/test/lib/cmd_ut_lib.c
index f5c7bf3..f1ac015 100644
--- a/test/lib/cmd_ut_lib.c
+++ b/test/lib/cmd_ut_lib.c
@@ -13,8 +13,8 @@
 
 int do_ut_lib(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test, lib_test);
-	const int n_ents = ll_entry_count(struct unit_test, lib_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(lib_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(lib_test);
 
 	return cmd_ut_category("lib", "lib_test_", tests, n_ents, argc, argv);
 }
diff --git a/test/log/Makefile b/test/log/Makefile
index 3f09deb..a3dedac 100644
--- a/test/log/Makefile
+++ b/test/log/Makefile
@@ -7,7 +7,7 @@
 
 ifdef CONFIG_UT_LOG
 
-obj-y += test-main.o
+obj-y += log_ut.o
 
 ifdef CONFIG_SANDBOX
 obj-$(CONFIG_LOG_SYSLOG) += syslog_test.o
diff --git a/test/log/cont_test.c b/test/log/cont_test.c
index 16379a7..de7b7f0 100644
--- a/test/log/cont_test.c
+++ b/test/log/cont_test.c
@@ -15,8 +15,6 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define BUFFSIZE 64
-
 static int log_test_cont(struct unit_test_state *uts)
 {
 	int log_fmt;
@@ -29,12 +27,13 @@
 	gd->log_fmt = (1 << LOGF_CAT) | (1 << LOGF_LEVEL) | (1 << LOGF_MSG);
 	gd->default_log_level = LOGL_INFO;
 	console_record_reset_enable();
-	log(LOGC_ARCH, LOGL_ERR, "ea%d ", 1);
+	log(LOGC_ARCH, LOGL_ERR, "ea%d\n", 1);
 	log(LOGC_CONT, LOGL_CONT, "cc%d\n", 2);
 	gd->default_log_level = log_level;
 	gd->log_fmt = log_fmt;
 	gd->flags &= ~GD_FLG_RECORD;
-	ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1 ERR.arch, cc2"));
+	ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1"));
+	ut_assertok(ut_check_console_line(uts, "ERR.arch, cc2"));
 	ut_assertok(ut_check_console_end(uts));
 
 	/* Write a third message which is not a continuation */
@@ -48,6 +47,18 @@
 	ut_assertok(ut_check_console_line(uts, "INFO.efi, ie3"));
 	ut_assertok(ut_check_console_end(uts));
 
+	/* Write two messages without a newline between them */
+	gd->log_fmt = (1 << LOGF_CAT) | (1 << LOGF_LEVEL) | (1 << LOGF_MSG);
+	gd->default_log_level = LOGL_INFO;
+	console_record_reset_enable();
+	log(LOGC_ARCH, LOGL_ERR, "ea%d ", 1);
+	log(LOGC_CONT, LOGL_CONT, "cc%d\n", 2);
+	gd->default_log_level = log_level;
+	gd->log_fmt = log_fmt;
+	gd->flags &= ~GD_FLG_RECORD;
+	ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1 cc2"));
+	ut_assertok(ut_check_console_end(uts));
+
 	return 0;
 }
 LOG_TEST(log_test_cont);
diff --git a/test/log/test-main.c b/test/log/log_ut.c
similarity index 75%
rename from test/log/test-main.c
rename to test/log/log_ut.c
index c534add..5aa3a18 100644
--- a/test/log/test-main.c
+++ b/test/log/log_ut.c
@@ -13,8 +13,8 @@
 
 int do_ut_log(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test, log_test);
-	const int n_ents = ll_entry_count(struct unit_test, log_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(log_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(log_test);
 
 	return cmd_ut_category("log", "log_test_",
 			       tests, n_ents, argc, argv);
diff --git a/test/optee/cmd_ut_optee.c b/test/optee/cmd_ut_optee.c
index 9fa4c91..c3887ab 100644
--- a/test/optee/cmd_ut_optee.c
+++ b/test/optee/cmd_ut_optee.c
@@ -94,9 +94,8 @@
 
 int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test,
-						 optee_test);
-	const int n_ents = ll_entry_count(struct unit_test, optee_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(optee_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(optee_test);
 	struct unit_test_state *uts;
 	void *fdt_optee = &__dtb_test_optee_optee_begin;
 	void *fdt_no_optee = &__dtb_test_optee_no_optee_begin;
diff --git a/test/overlay/cmd_ut_overlay.c b/test/overlay/cmd_ut_overlay.c
index c001fb1..56a3df1 100644
--- a/test/overlay/cmd_ut_overlay.c
+++ b/test/overlay/cmd_ut_overlay.c
@@ -213,9 +213,8 @@
 
 int do_ut_overlay(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test,
-						 overlay_test);
-	const int n_ents = ll_entry_count(struct unit_test, overlay_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(overlay_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(overlay_test);
 	struct unit_test_state *uts;
 	void *fdt_base = &__dtb_test_fdt_base_begin;
 	void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
diff --git a/test/py/conftest.py b/test/py/conftest.py
index 9bfd926..1b909cd 100644
--- a/test/py/conftest.py
+++ b/test/py/conftest.py
@@ -226,7 +226,7 @@
         import u_boot_console_exec_attach
         console = u_boot_console_exec_attach.ConsoleExecAttach(log, ubconfig)
 
-re_ut_test_list = re.compile(r'_u_boot_list_2_(.*)_test_2_\1_test_(.*)\s*$')
+re_ut_test_list = re.compile(r'_u_boot_list_2_ut_(.*)_test_2_\1_test_(.*)\s*$')
 def generate_ut_subtest(metafunc, fixture_name, sym_path):
     """Provide parametrization for a ut_subtest fixture.
 
diff --git a/test/py/tests/test_log.py b/test/py/tests/test_log.py
index f889120..140dcb9 100644
--- a/test/py/tests/test_log.py
+++ b/test/py/tests/test_log.py
@@ -45,5 +45,4 @@
     cons = u_boot_console
     cons.restart_uboot()
     output = cons.get_spawn_output().replace('\r', '')
-    assert 'sandbox: starting...' in output
     assert (not 'debug: main' in output)
diff --git a/test/py/tests/test_ofplatdata.py b/test/py/tests/test_ofplatdata.py
index 92d09b7..e9cce4d 100644
--- a/test/py/tests/test_ofplatdata.py
+++ b/test/py/tests/test_ofplatdata.py
@@ -4,7 +4,7 @@
 import pytest
 import u_boot_utils as util
 
-@pytest.mark.boardspec('sandbox')
+@pytest.mark.boardspec('sandbox_spl')
 @pytest.mark.buildconfigspec('spl_of_platdata')
 def test_spl_devicetree(u_boot_console):
     """Test content of spl device-tree"""
diff --git a/test/py/tests/test_scp03.py b/test/py/tests/test_scp03.py
new file mode 100644
index 0000000..1f68925
--- /dev/null
+++ b/test/py/tests/test_scp03.py
@@ -0,0 +1,27 @@
+# Copyright (c) 2021 Foundries.io Ltd
+#
+# SPDX-License-Identifier:  GPL-2.0+
+#
+# SCP03 command test
+
+"""
+This tests SCP03 command in U-boot.
+
+For additional details check doc/usage/scp03.rst
+"""
+
+import pytest
+import u_boot_utils as util
+
+@pytest.mark.buildconfigspec('cmd_scp03')
+def test_scp03(u_boot_console):
+    """Enable and provision keys with SCP03
+    """
+
+    success_str1 = "SCP03 is enabled"
+    success_str2 = "SCP03 is provisioned"
+
+    response = u_boot_console.run_command('scp03 enable')
+    assert success_str1 in response
+    response = u_boot_console.run_command('scp03 provision')
+    assert success_str2 in response
diff --git a/test/str_ut.c b/test/str_ut.c
index cd50455..359d7d4 100644
--- a/test/str_ut.c
+++ b/test/str_ut.c
@@ -107,9 +107,8 @@
 
 int do_ut_str(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test,
-						 str_test);
-	const int n_ents = ll_entry_count(struct unit_test, str_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(str_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(str_test);
 
 	return cmd_ut_category("str", "str_", tests, n_ents, argc, argv);
 }
diff --git a/test/test-main.c b/test/test-main.c
new file mode 100644
index 0000000..e1b49e0
--- /dev/null
+++ b/test/test-main.c
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <console.h>
+#include <dm.h>
+#include <asm/state.h>
+#include <dm/root.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* This is valid when a test is running, NULL otherwise */
+static struct unit_test_state *cur_test_state;
+
+struct unit_test_state *test_get_state(void)
+{
+	return cur_test_state;
+}
+
+void test_set_state(struct unit_test_state *uts)
+{
+	cur_test_state = uts;
+}
+
+/**
+ * dm_test_pre_run() - Get ready to run a driver model test
+ *
+ * This clears out the driver model data structures. For sandbox it resets the
+ * state structure
+ *
+ * @uts: Test state
+ */
+static int dm_test_pre_run(struct unit_test_state *uts)
+{
+	bool of_live = uts->of_live;
+
+	uts->root = NULL;
+	uts->testdev = NULL;
+	uts->force_fail_alloc = false;
+	uts->skip_post_probe = false;
+	gd->dm_root = NULL;
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA))
+		memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count));
+	state_reset_for_test(state_get_current());
+
+	/* Determine whether to make the live tree available */
+	gd_set_of_root(of_live ? uts->of_root : NULL);
+	ut_assertok(dm_init(of_live));
+	uts->root = dm_root();
+
+	return 0;
+}
+
+static int dm_test_post_run(struct unit_test_state *uts)
+{
+	int id;
+
+	for (id = 0; id < UCLASS_COUNT; id++) {
+		struct uclass *uc;
+
+		/*
+		 * If the uclass doesn't exist we don't want to create it. So
+		 * check that here before we call uclass_find_device().
+		 */
+		uc = uclass_find(id);
+		if (!uc)
+			continue;
+		ut_assertok(uclass_destroy(uc));
+	}
+
+	return 0;
+}
+
+/* Ensure all the test devices are probed */
+static int do_autoprobe(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	int ret;
+
+	/* Scanning the uclass is enough to probe all the devices */
+	for (ret = uclass_first_device(UCLASS_TEST, &dev);
+	     dev;
+	     ret = uclass_next_device(&dev))
+		;
+
+	return ret;
+}
+
+/*
+ * ut_test_run_on_flattree() - Check if we should run a test with flat DT
+ *
+ * This skips long/slow tests where there is not much value in running a flat
+ * DT test in addition to a live DT test.
+ *
+ * @return true to run the given test on the flat device tree
+ */
+static bool ut_test_run_on_flattree(struct unit_test *test)
+{
+	const char *fname = strrchr(test->file, '/') + 1;
+
+	if (!(test->flags & UT_TESTF_DM))
+		return false;
+
+	return !strstr(fname, "video") || strstr(test->name, "video_base");
+}
+
+/**
+ * test_matches() - Check if a test should be run
+ *
+ * This checks if the a test should be run. In the normal case of running all
+ * tests, @select_name is NULL.
+ *
+ * @prefix: String prefix for the tests. Any tests that have this prefix will be
+ *	printed without the prefix, so that it is easier to see the unique part
+ *	of the test name. If NULL, any suite name (xxx_test) is considered to be
+ *	a prefix.
+ * @test_name: Name of current test
+ * @select_name: Name of test to run (or NULL for all)
+ * @return true to run this test, false to skip it
+ */
+static bool test_matches(const char *prefix, const char *test_name,
+			 const char *select_name)
+{
+	if (!select_name)
+		return true;
+
+	if (!strcmp(test_name, select_name))
+		return true;
+
+	if (!prefix) {
+		const char *p = strstr(test_name, "_test_");
+
+		/* convert xxx_test_yyy to yyy, i.e. remove the suite name */
+		if (p)
+			test_name = p + 6;
+	} else {
+		/* All tests have this prefix */
+		if (!strncmp(test_name, prefix, strlen(prefix)))
+			test_name += strlen(prefix);
+	}
+
+	if (!strcmp(test_name, select_name))
+		return true;
+
+	return false;
+}
+
+/**
+ * ut_list_has_dm_tests() - Check if a list of tests has driver model ones
+ *
+ * @tests: List of tests to run
+ * @count: Number of tests to ru
+ * @return true if any of the tests have the UT_TESTF_DM flag
+ */
+static bool ut_list_has_dm_tests(struct unit_test *tests, int count)
+{
+	struct unit_test *test;
+
+	for (test = tests; test < tests + count; test++) {
+		if (test->flags & UT_TESTF_DM)
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ * dm_test_restore() Put things back to normal so sandbox works as expected
+ *
+ * @of_root: Value to set for of_root
+ * @return 0 if OK, -ve on error
+ */
+static int dm_test_restore(struct device_node *of_root)
+{
+	int ret;
+
+	gd_set_of_root(of_root);
+	gd->dm_root = NULL;
+	ret = dm_init(CONFIG_IS_ENABLED(OF_LIVE));
+	if (ret)
+		return ret;
+	dm_scan_plat(false);
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA))
+		dm_scan_fdt(false);
+
+	return 0;
+}
+
+/**
+ * test_pre_run() - Handle any preparation needed to run a test
+ *
+ * @uts: Test state
+ * @test: Test to prepare for
+ * @return 0 if OK, -EAGAIN to skip this test since some required feature is not
+ *	available, other -ve on error (meaning that testing cannot likely
+ *	continue)
+ */
+static int test_pre_run(struct unit_test_state *uts, struct unit_test *test)
+{
+	if (test->flags & UT_TESTF_DM)
+		ut_assertok(dm_test_pre_run(uts));
+
+	ut_set_skip_delays(uts, false);
+
+	uts->start = mallinfo();
+
+	if (test->flags & UT_TESTF_SCAN_PDATA)
+		ut_assertok(dm_scan_plat(false));
+
+	if (test->flags & UT_TESTF_PROBE_TEST)
+		ut_assertok(do_autoprobe(uts));
+
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA) &&
+	    (test->flags & UT_TESTF_SCAN_FDT))
+		ut_assertok(dm_extended_scan(false));
+
+	if (test->flags & UT_TESTF_CONSOLE_REC) {
+		int ret = console_record_reset_enable();
+
+		if (ret) {
+			printf("Skipping: Console recording disabled\n");
+			return -EAGAIN;
+		}
+	}
+	ut_silence_console(uts);
+
+	return 0;
+}
+
+/**
+ * test_post_run() - Handle cleaning up after a test
+ *
+ * @uts: Test state
+ * @test: Test to clean up after
+ * @return 0 if OK, -ve on error (meaning that testing cannot likely continue)
+ */
+static int test_post_run(struct unit_test_state *uts, struct unit_test *test)
+{
+	ut_unsilence_console(uts);
+	if (test->flags & UT_TESTF_DM)
+		ut_assertok(dm_test_post_run(uts));
+
+	return 0;
+}
+
+/**
+ * ut_run_test() - Run a single test
+ *
+ * This runs the test, handling any preparation and clean-up needed. It prints
+ * the name of each test before running it.
+ *
+ * @uts: Test state to update. The caller should ensure that this is zeroed for
+ *	the first call to this function. On exit, @uts->fail_count is
+ *	incremented by the number of failures (0, one hopes)
+ * @test_name: Test to run
+ * @name: Name of test, possibly skipping a prefix that should not be displayed
+ * @return 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if
+ *	any failed
+ */
+static int ut_run_test(struct unit_test_state *uts, struct unit_test *test,
+		       const char *test_name)
+{
+	const char *fname = strrchr(test->file, '/') + 1;
+	const char *note = "";
+	int ret;
+
+	if ((test->flags & UT_TESTF_DM) && !uts->of_live)
+		note = " (flat tree)";
+	printf("Test: %s: %s%s\n", test_name, fname, note);
+
+	/* Allow access to test state from drivers */
+	test_set_state(uts);
+
+	ret = test_pre_run(uts, test);
+	if (ret == -EAGAIN)
+		return -EAGAIN;
+	if (ret)
+		return ret;
+
+	test->func(uts);
+
+	ret = test_post_run(uts, test);
+	if (ret)
+		return ret;
+
+	test_set_state( NULL);
+
+	return 0;
+}
+
+/**
+ * ut_run_test_live_flat() - Run a test with both live and flat tree
+ *
+ * This calls ut_run_test() with livetree enabled, which is the standard setup
+ * for runnig tests. Then, for driver model test, it calls it again with
+ * livetree disabled. This allows checking of flattree being used when OF_LIVE
+ * is enabled, as is the case in U-Boot proper before relocation, as well as in
+ * SPL.
+ *
+ * @uts: Test state to update. The caller should ensure that this is zeroed for
+ *	the first call to this function. On exit, @uts->fail_count is
+ *	incremented by the number of failures (0, one hopes)
+ * @test: Test to run
+ * @name: Name of test, possibly skipping a prefix that should not be displayed
+ * @return 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if
+ *	any failed
+ */
+static int ut_run_test_live_flat(struct unit_test_state *uts,
+				 struct unit_test *test, const char *name)
+{
+	int runs;
+
+	/* Run with the live tree if possible */
+	runs = 0;
+	if (CONFIG_IS_ENABLED(OF_LIVE)) {
+		if (!(test->flags & UT_TESTF_FLAT_TREE)) {
+			uts->of_live = true;
+			ut_assertok(ut_run_test(uts, test, test->name));
+			runs++;
+		}
+	}
+
+	/*
+	 * Run with the flat tree if we couldn't run it with live tree,
+	 * or it is a core test.
+	 */
+	if (!(test->flags & UT_TESTF_LIVE_TREE) &&
+	    (!runs || ut_test_run_on_flattree(test))) {
+		uts->of_live = false;
+		ut_assertok(ut_run_test(uts, test, test->name));
+		runs++;
+	}
+
+	return 0;
+}
+
+/**
+ * ut_run_tests() - Run a set of tests
+ *
+ * This runs the tests, handling any preparation and clean-up needed. It prints
+ * the name of each test before running it.
+ *
+ * @uts: Test state to update. The caller should ensure that this is zeroed for
+ *	the first call to this function. On exit, @uts->fail_count is
+ *	incremented by the number of failures (0, one hopes)
+ * @prefix: String prefix for the tests. Any tests that have this prefix will be
+ *	printed without the prefix, so that it is easier to see the unique part
+ *	of the test name. If NULL, no prefix processing is done
+ * @tests: List of tests to run
+ * @count: Number of tests to run
+ * @select_name: Name of a single test to run (from the list provided). If NULL
+ *	then all tests are run
+ * @return 0 if all tests passed, -ENOENT if test @select_name was not found,
+ *	-EBADF if any failed
+ */
+static int ut_run_tests(struct unit_test_state *uts, const char *prefix,
+			struct unit_test *tests, int count,
+			const char *select_name)
+{
+	struct unit_test *test;
+	int found = 0;
+
+	for (test = tests; test < tests + count; test++) {
+		const char *test_name = test->name;
+		int ret;
+
+		if (!test_matches(prefix, test_name, select_name))
+			continue;
+		ret = ut_run_test_live_flat(uts, test, select_name);
+		found++;
+		if (ret == -EAGAIN)
+			continue;
+		if (ret)
+			return ret;
+	}
+	if (select_name && !found)
+		return -ENOENT;
+
+	return uts->fail_count ? -EBADF : 0;
+}
+
+int ut_run_list(const char *category, const char *prefix,
+		struct unit_test *tests, int count, const char *select_name)
+{
+	struct unit_test_state uts = { .fail_count = 0 };
+	bool has_dm_tests = false;
+	int ret;
+
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA) &&
+	    ut_list_has_dm_tests(tests, count)) {
+		has_dm_tests = true;
+		/*
+		 * If we have no device tree, or it only has a root node, then
+		 * these * tests clearly aren't going to work...
+		 */
+		if (!gd->fdt_blob || fdt_next_node(gd->fdt_blob, 0, NULL) < 0) {
+			puts("Please run with test device tree:\n"
+			     "    ./u-boot -d arch/sandbox/dts/test.dtb\n");
+			return CMD_RET_FAILURE;
+		}
+	}
+
+	if (!select_name)
+		printf("Running %d %s tests\n", count, category);
+
+	uts.of_root = gd_of_root();
+	ret = ut_run_tests(&uts, prefix, tests, count, select_name);
+
+	if (ret == -ENOENT)
+		printf("Test '%s' not found\n", select_name);
+	else
+		printf("Failures: %d\n", uts.fail_count);
+
+	/* Best efforts only...ignore errors */
+	if (has_dm_tests)
+		dm_test_restore(uts.of_root);
+
+	return ret;
+}
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
index 6f6aea5..617eed8 100644
--- a/test/unicode_ut.c
+++ b/test/unicode_ut.c
@@ -729,8 +729,8 @@
 
 int do_ut_unicode(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-	struct unit_test *tests = ll_entry_start(struct unit_test, unicode_test);
-	const int n_ents = ll_entry_count(struct unit_test, unicode_test);
+	struct unit_test *tests = UNIT_TEST_SUITE_START(unicode_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(unicode_test);
 
 	return cmd_ut_category("Unicode", "unicode_test_",
 			       tests, n_ents, argc, argv);
diff --git a/test/ut.c b/test/ut.c
index 7328338..ea0af15 100644
--- a/test/ut.c
+++ b/test/ut.c
@@ -133,3 +133,10 @@
 {
 	gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
 }
+
+void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays)
+{
+#ifdef CONFIG_SANDBOX
+	state_set_skip_delays(skip_delays);
+#endif
+}
diff --git a/tools/binman/README b/tools/binman/README
index a00c902..45f0a0c 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -637,7 +637,8 @@
 
 Binman normally operates silently unless there is an error, in which case it
 just displays the error. The -D/--debug option can be used to create a full
-backtrace when errors occur.
+backtrace when errors occur. You can use BINMAN_DEBUG=1 when building to select
+this.
 
 Internally binman logs some output while it is running. This can be displayed
 by increasing the -v/--verbosity from the default of 1:
@@ -649,6 +650,7 @@
    4: detailed information about each operation
    5: debug (all output)
 
+You can use BINMAN_VERBOSE=5 (for example) when building to select this.
 
 Hashing Entries
 ---------------