Merge branch '2022-09-29-dm-core-support-multiple-device-trees-in-ofnode' into next

To quote the author:
At present the ofnode interface is somewhat limited, in that it cannot
access the device tree provided by the OS, only the one used by U-Boot
itself (assuming these are separate). This prevents using ofnode functions
to handle device tree fixups, i.e. ft_board_setup() and the like.

The ofnode interface was introduced to allow a consistent API to access
the device tree, whether a flat tree or a live tree (OF_LIVE) is in use.

With the flat tree, adding nodes and properties at the start of the tree
(as often happens when writing to the /chosen node) requires copying a
lot of data for each operation. With live tree, such operations are
quite a bit faster, since there is no memory copying required. This has to
be weighed against the required memory allocation with OF_LIVE, as well
as the cost of unflattening and flattening the device tree which U-Boot
is running.

This series enables support for access to multiple device trees with the
ofnode interface. This is already available to some extent with OF_LIVE,
but some of the ofnode functions need changes to allow the tree to be
specified.

The mechanism works by using the top 1-4 bits of the device tree offset.
The sign bit is not affected, since negative values must be supported.

With this implemented, it becomes possible to use the ofnode interface
to do device tree fixups. The only current user is the EVT_FT_FIXUP
event.

This has two main benefits:

- ofnode can now be used everywhere, in preference to the libfdt calls
- live tree can eventually be used everywhere, with potential speed
  improvements when larger number of fixups are used

This series is only a step along the way. Firstly, while it is possible
to access the 'fix-up' tree using OF_LIVE, most of the fixup functions use
flat tree directly, rather than the ofnode interface. These need to be
updated. Also the tree must be flattened again before it is passed to the
OS. This is not currently implemented.

With OFNODE_MULTI_TREE disabled this has almost no effect on code size:
around 4 bytes if EVENT is enabled, 0 if not. With the feature enabled,
the increase is around 700 bytes, e.g. on venice2:

$ buildman -b ofn2a venice2 -sS --step 0
Summary of 2 commits for 1 boards (1 thread, 64 jobs per thread)
01: image: Drop some other #ifdefs in image-board.c
       arm:  w+   venice2
48: wip
       arm: (for 1/1 boards) all +668.0 text +668.0

This size increase is not too bad, considering the extra functionality,
but is too large to enable everywhere. So for now this features needs to
be opt-in only, based on EVENT.
diff --git a/arch/arc/lib/bootm.c b/arch/arc/lib/bootm.c
index 628addd..07b2c15 100644
--- a/arch/arc/lib/bootm.c
+++ b/arch/arc/lib/bootm.c
@@ -22,10 +22,10 @@
 	return 0;
 }
 
-__weak int board_prep_linux(bootm_headers_t *images) { return 0; }
+__weak int board_prep_linux(struct bootm_headers *images) { return 0; }
 
 /* Subcommand: PREP */
-static int boot_prep_linux(bootm_headers_t *images)
+static int boot_prep_linux(struct bootm_headers *images)
 {
 	int ret;
 
@@ -49,7 +49,7 @@
 }
 
 /* Subcommand: GO */
-static void boot_jump_linux(bootm_headers_t *images, int flag)
+static void boot_jump_linux(struct bootm_headers *images, int flag)
 {
 	ulong kernel_entry;
 	unsigned int r0, r2;
@@ -79,7 +79,7 @@
 		board_jump_and_run(kernel_entry, r0, 0, r2);
 }
 
-int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
+int do_bootm_linux(int flag, int argc, char *argv[], struct bootm_headers *images)
 {
 	/* No need for those on ARC */
 	if ((flag & BOOTM_STATE_OS_BD_T) || (flag & BOOTM_STATE_OS_CMDLINE))
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 9f086f3..e414ef8 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -192,10 +192,10 @@
 }
 #endif
 
-__weak void board_prep_linux(bootm_headers_t *images) { }
+__weak void board_prep_linux(struct bootm_headers *images) { }
 
 /* Subcommand: PREP */
-static void boot_prep_linux(bootm_headers_t *images)
+static void boot_prep_linux(struct bootm_headers *images)
 {
 	char *commandline = env_get("bootargs");
 
@@ -288,7 +288,7 @@
 #endif
 
 /* Subcommand: GO */
-static void boot_jump_linux(bootm_headers_t *images, int flag)
+static void boot_jump_linux(struct bootm_headers *images, int flag)
 {
 #ifdef CONFIG_ARM64
 	void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,
@@ -379,7 +379,7 @@
  * they are called if subcommand is equal 0.
  */
 int do_bootm_linux(int flag, int argc, char *const argv[],
-		   bootm_headers_t *images)
+		   struct bootm_headers *images)
 {
 	/* No need for those on ARM */
 	if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
@@ -401,7 +401,7 @@
 }
 
 #if defined(CONFIG_BOOTM_VXWORKS)
-void boot_prep_vxworks(bootm_headers_t *images)
+void boot_prep_vxworks(struct bootm_headers *images)
 {
 #if defined(CONFIG_OF_LIBFDT)
 	int off;
@@ -416,7 +416,8 @@
 #endif
 	cleanup_before_linux();
 }
-void boot_jump_vxworks(bootm_headers_t *images)
+
+void boot_jump_vxworks(struct bootm_headers *images)
 {
 #if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
 	armv8_setup_psci();
diff --git a/arch/arm/mach-aspeed/ast2600/spl.c b/arch/arm/mach-aspeed/ast2600/spl.c
index 53c8a15..0952e73 100644
--- a/arch/arm/mach-aspeed/ast2600/spl.c
+++ b/arch/arm/mach-aspeed/ast2600/spl.c
@@ -56,9 +56,9 @@
 	return BOOT_DEVICE_RAM;
 }
 
-struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size)
 {
-	return (struct image_header *)(CONFIG_SYS_LOAD_ADDR);
+	return (struct legacy_img_hdr *)(CONFIG_SYS_LOAD_ADDR);
 }
 
 #ifdef CONFIG_SPL_OS_BOOT
diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c
index 0d1a776..c6747b2 100644
--- a/arch/arm/mach-imx/hab.c
+++ b/arch/arm/mach-imx/hab.c
@@ -589,7 +589,7 @@
 	switch (genimg_get_format(buf)) {
 #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
 	case IMAGE_FORMAT_LEGACY:
-		return (image_get_image_size((image_header_t *)img_addr)
+		return (image_get_image_size((struct legacy_img_hdr *)img_addr)
 			+ 0x1000 - 1)  & ~(0x1000 - 1);
 #endif
 #if CONFIG_IS_ENABLED(FIT)
diff --git a/arch/arm/mach-imx/spl_imx_romapi.c b/arch/arm/mach-imx/spl_imx_romapi.c
index 07bf07b..aa5d23a 100644
--- a/arch/arm/mach-imx/spl_imx_romapi.c
+++ b/arch/arm/mach-imx/spl_imx_romapi.c
@@ -72,7 +72,7 @@
 	int ret;
 	u32 offset;
 	u32 pagesize, size;
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	u32 image_offset;
 
 	ret = rom_api_query_boot_infor(QUERY_IVT_OFF, &offset);
@@ -84,14 +84,14 @@
 		return -1;
 	}
 
-	header = (struct image_header *)(CONFIG_SPL_IMX_ROMAPI_LOADADDR);
+	header = (struct legacy_img_hdr *)(CONFIG_SPL_IMX_ROMAPI_LOADADDR);
 
 	printf("image offset 0x%x, pagesize 0x%x, ivt offset 0x%x\n",
 	       image_offset, pagesize, offset);
 
 	offset = spl_romapi_get_uboot_base(image_offset, rom_bt_dev);
 
-	size = ALIGN(sizeof(struct image_header), pagesize);
+	size = ALIGN(sizeof(struct legacy_img_hdr), pagesize);
 	ret = rom_api_download_image((u8 *)header, offset, size);
 
 	if (ret != ROM_API_OKAY) {
diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 3962f28..14c37ac 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -493,7 +493,7 @@
 }
 
 #ifdef CONFIG_ARM64
-void board_prep_linux(bootm_headers_t *images)
+void board_prep_linux(struct bootm_headers *images)
 {
 	debug("Linux kernel Image start = 0x%lx end = 0x%lx\n",
 	      images->os.start, images->os.end);
diff --git a/arch/arm/mach-k3/sysfw-loader.c b/arch/arm/mach-k3/sysfw-loader.c
index b3beeca..aea640b 100644
--- a/arch/arm/mach-k3/sysfw-loader.c
+++ b/arch/arm/mach-k3/sysfw-loader.c
@@ -88,10 +88,10 @@
  * Populate SPL hook to override the default load address used by the SPL
  * loader function with a custom address for SYSFW loading.
  */
-struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size)
 {
 	if (sysfw_loaded)
-		return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset);
+		return (struct legacy_img_hdr *)(CONFIG_SYS_TEXT_BASE + offset);
 	else if (sysfw_load_address)
 		return sysfw_load_address;
 	else
@@ -490,7 +490,7 @@
 	sysfw_loaded = true;
 
 	/* Ensure the SYSFW image is in FIT format */
-	if (image_get_magic((const image_header_t *)sysfw_load_address) !=
+	if (image_get_magic((const struct legacy_img_hdr *)sysfw_load_address) !=
 	    FDT_MAGIC)
 		panic("SYSFW image not in FIT format!\n");
 
diff --git a/arch/arm/mach-keystone/cmd_mon.c b/arch/arm/mach-keystone/cmd_mon.c
index e26296b..4734e4c 100644
--- a/arch/arm/mach-keystone/cmd_mon.c
+++ b/arch/arm/mach-keystone/cmd_mon.c
@@ -17,7 +17,7 @@
 {
 	u32 addr, dpsc_base = 0x1E80000, freq, load_addr, size;
 	int     rcode = 0;
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	u32 ecrypt_bm_addr = 0;
 
 	if (argc < 2)
@@ -27,7 +27,7 @@
 
 	addr = hextoul(argv[1], NULL);
 
-	header = (struct image_header *)addr;
+	header = (struct legacy_img_hdr *)addr;
 
 	if (image_get_magic(header) != IH_MAGIC) {
 		printf("## Please update monitor image\n");
@@ -36,7 +36,7 @@
 
 	load_addr = image_get_load(header);
 	size = image_get_data_size(header);
-	memcpy((void *)load_addr, (void *)(addr + sizeof(struct image_header)),
+	memcpy((void *)load_addr, (void *)(addr + sizeof(struct legacy_img_hdr)),
 	       size);
 
 	if (argc >=  3)
diff --git a/arch/arm/mach-socfpga/board.c b/arch/arm/mach-socfpga/board.c
index 7267163..b49006c 100644
--- a/arch/arm/mach-socfpga/board.c
+++ b/arch/arm/mach-socfpga/board.c
@@ -114,7 +114,7 @@
 #endif
 
 #if !IS_ENABLED(CONFIG_SPL_BUILD) && IS_ENABLED(CONFIG_FIT)
-void board_prep_linux(bootm_headers_t *images)
+void board_prep_linux(struct bootm_headers *images)
 {
 	if (!images->fit_uname_cfg) {
 		if (IS_ENABLED(CONFIG_SOCFPGA_SECURE_VAB_AUTH) &&
diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
index de9aa68..925bf85 100644
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
@@ -335,10 +335,10 @@
 			      struct spl_boot_device *bootdev)
 {
 	int ret = 0;
-	struct image_header *header;
-	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+	struct legacy_img_hdr *header;
 	uint32_t load_offset = sunxi_get_spl_size();
 
+	header = (struct legacy_img_hdr *)CONFIG_SYS_TEXT_BASE;
 	load_offset = max_t(uint32_t, load_offset, CONFIG_SYS_SPI_U_BOOT_OFFS);
 
 	spi0_init();
diff --git a/arch/arm/mach-tegra/xusb-padctl-common.c b/arch/arm/mach-tegra/xusb-padctl-common.c
index 8bdd44a..388ec49 100644
--- a/arch/arm/mach-tegra/xusb-padctl-common.c
+++ b/arch/arm/mach-tegra/xusb-padctl-common.c
@@ -282,7 +282,7 @@
 	debug("%s: count=%d\n", __func__, count);
 	for (i = 0; i < count; i++) {
 		debug("%s: i=%d, node=%p\n", __func__, i, nodes[i].np);
-		if (!ofnode_is_available(nodes[i]))
+		if (!ofnode_is_enabled(nodes[i]))
 			continue;
 
 		padctl.socdata = socdata;
diff --git a/arch/m68k/lib/bootm.c b/arch/m68k/lib/bootm.c
index 9cade92..c1c9bdc 100644
--- a/arch/m68k/lib/bootm.c
+++ b/arch/m68k/lib/bootm.c
@@ -36,7 +36,7 @@
 }
 
 int do_bootm_linux(int flag, int argc, char *const argv[],
-		   bootm_headers_t *images)
+		   struct bootm_headers *images)
 {
 	int ret;
 	struct bd_info  *kbd;
diff --git a/arch/microblaze/lib/bootm.c b/arch/microblaze/lib/bootm.c
index 31b6659..4a54214 100644
--- a/arch/microblaze/lib/bootm.c
+++ b/arch/microblaze/lib/bootm.c
@@ -37,7 +37,7 @@
 	arch_lmb_reserve_generic(lmb, get_sp(), gd->ram_top, 4096);
 }
 
-static void boot_jump_linux(bootm_headers_t *images, int flag)
+static void boot_jump_linux(struct bootm_headers *images, int flag)
 {
 	void (*thekernel)(char *cmdline, ulong rd, ulong dt);
 	ulong dt = (ulong)images->ft_addr;
@@ -71,7 +71,7 @@
 	}
 }
 
-static void boot_prep_linux(bootm_headers_t *images)
+static void boot_prep_linux(struct bootm_headers *images)
 {
 	if (CONFIG_IS_ENABLED(OF_LIBFDT) && CONFIG_IS_ENABLED(LMB) && images->ft_len) {
 		debug("using: FDT\n");
@@ -83,7 +83,7 @@
 }
 
 int do_bootm_linux(int flag, int argc, char *const argv[],
-		   bootm_headers_t *images)
+		   struct bootm_headers *images)
 {
 	images->cmdline_start = (ulong)env_get("bootargs");
 
diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c
index cab8da4..5fda914 100644
--- a/arch/mips/lib/bootm.c
+++ b/arch/mips/lib/bootm.c
@@ -71,7 +71,7 @@
 		debug("   arg %03d: %s\n", i, linux_argv[i]);
 }
 
-static void linux_cmdline_legacy(bootm_headers_t *images)
+static void linux_cmdline_legacy(struct bootm_headers *images)
 {
 	const char *bootargs, *next, *quote;
 
@@ -111,7 +111,7 @@
 	}
 }
 
-static void linux_cmdline_append(bootm_headers_t *images)
+static void linux_cmdline_append(struct bootm_headers *images)
 {
 	char buf[24];
 	ulong mem, rd_start, rd_size;
@@ -164,7 +164,7 @@
 	}
 }
 
-static void linux_env_legacy(bootm_headers_t *images)
+static void linux_env_legacy(struct bootm_headers *images)
 {
 	char env_buf[12];
 	const char *cp;
@@ -213,7 +213,7 @@
 	}
 }
 
-static int boot_reloc_fdt(bootm_headers_t *images)
+static int boot_reloc_fdt(struct bootm_headers *images)
 {
 	/*
 	 * In case of legacy uImage's, relocation of FDT is already done
@@ -243,7 +243,7 @@
 }
 #endif
 
-static int boot_setup_fdt(bootm_headers_t *images)
+static int boot_setup_fdt(struct bootm_headers *images)
 {
 	images->initrd_start = virt_to_phys((void *)images->initrd_start);
 	images->initrd_end = virt_to_phys((void *)images->initrd_end);
@@ -251,7 +251,7 @@
 		&images->lmb);
 }
 
-static void boot_prep_linux(bootm_headers_t *images)
+static void boot_prep_linux(struct bootm_headers *images)
 {
 	if (CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && images->ft_len) {
 		boot_reloc_fdt(images);
@@ -271,7 +271,7 @@
 	}
 }
 
-static void boot_jump_linux(bootm_headers_t *images)
+static void boot_jump_linux(struct bootm_headers *images)
 {
 	typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong);
 	kernel_entry_t kernel = (kernel_entry_t) images->ep;
@@ -302,7 +302,7 @@
 }
 
 int do_bootm_linux(int flag, int argc, char *const argv[],
-		   bootm_headers_t *images)
+		   struct bootm_headers *images)
 {
 	/* No need for those on MIPS */
 	if (flag & BOOTM_STATE_OS_BD_T)
diff --git a/arch/mips/mach-jz47xx/jz4780/jz4780.c b/arch/mips/mach-jz47xx/jz4780/jz4780.c
index a57ec78..4c40bd8 100644
--- a/arch/mips/mach-jz47xx/jz4780/jz4780.c
+++ b/arch/mips/mach-jz47xx/jz4780/jz4780.c
@@ -30,7 +30,7 @@
 	typedef void __noreturn (*image_entry_noargs_t)(void);
 	struct mmc *mmc;
 	unsigned long count;
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	int ret;
 
 	/* Set global data pointer */
@@ -58,8 +58,8 @@
 	if (ret)
 		hang();
 
-	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
-					 sizeof(struct image_header));
+	header = (struct legacy_img_hdr *)(CONFIG_SYS_TEXT_BASE -
+					 sizeof(struct legacy_img_hdr));
 
 	count = blk_dread(mmc_get_blk_desc(mmc),
 			  CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,
diff --git a/arch/mips/mach-mtmips/mt7621/spl/spl.c b/arch/mips/mach-mtmips/mt7621/spl/spl.c
index 91eebc6..aa5b267 100644
--- a/arch/mips/mach-mtmips/mt7621/spl/spl.c
+++ b/arch/mips/mach-mtmips/mt7621/spl/spl.c
@@ -64,7 +64,7 @@
 unsigned long spl_nor_get_uboot_base(void)
 {
 	const struct tpl_info *tpli;
-	const image_header_t *hdr;
+	const struct legacy_img_hdr *hdr;
 	u32 addr;
 
 	addr = FLASH_MMAP_BASE + TPL_INFO_OFFSET;
@@ -72,7 +72,7 @@
 
 	if (tpli->magic == TPL_INFO_MAGIC) {
 		addr = FLASH_MMAP_BASE + tpli->size;
-		hdr = (const image_header_t *)KSEG1ADDR(addr);
+		hdr = (const struct legacy_img_hdr *)KSEG1ADDR(addr);
 
 		if (image_get_magic(hdr) == IH_MAGIC) {
 			addr += sizeof(*hdr) + image_get_size(hdr);
diff --git a/arch/mips/mach-mtmips/mt7621/tpl/tpl.c b/arch/mips/mach-mtmips/mt7621/tpl/tpl.c
index 2a82890..d77592d 100644
--- a/arch/mips/mach-mtmips/mt7621/tpl/tpl.c
+++ b/arch/mips/mach-mtmips/mt7621/tpl/tpl.c
@@ -116,7 +116,7 @@
 
 void __noreturn tpl_main(void)
 {
-	const image_header_t *hdr = (const image_header_t *)__image_copy_end;
+	const struct legacy_img_hdr *hdr = (const struct legacy_img_hdr *)__image_copy_end;
 	image_entry_noargs_t image_entry;
 	u32 loadaddr, size;
 	uintptr_t data;
@@ -132,7 +132,7 @@
 	image_entry = (image_entry_noargs_t)image_get_ep(hdr);
 
 	/* Load TPL image to L2 cache */
-	data = (uintptr_t)__image_copy_end + sizeof(struct image_header);
+	data = (uintptr_t)__image_copy_end + sizeof(struct legacy_img_hdr);
 	fill_lock_l2cache(data, loadaddr, size);
 
 	/* Jump to SPL */
diff --git a/arch/nios2/lib/bootm.c b/arch/nios2/lib/bootm.c
index 3cb59bd..06c094d 100644
--- a/arch/nios2/lib/bootm.c
+++ b/arch/nios2/lib/bootm.c
@@ -17,7 +17,7 @@
 #define NIOS_MAGIC 0x534f494e /* enable command line and initrd passing */
 
 int do_bootm_linux(int flag, int argc, char *const argv[],
-		   bootm_headers_t *images)
+		   struct bootm_headers *images)
 {
 	void (*kernel)(int, int, int, char *) = (void *)images->ep;
 	char *commandline = env_get("bootargs");
diff --git a/arch/powerpc/lib/bootm.c b/arch/powerpc/lib/bootm.c
index b92df95..5127878 100644
--- a/arch/powerpc/lib/bootm.c
+++ b/arch/powerpc/lib/bootm.c
@@ -45,7 +45,7 @@
 #define CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE	(768*1024*1024)
 #endif
 
-static void boot_jump_linux(bootm_headers_t *images)
+static void boot_jump_linux(struct bootm_headers *images)
 {
 	void	(*kernel)(struct bd_info *, ulong r4, ulong r5, ulong r6,
 			      ulong r7, ulong r8, ulong r9);
@@ -151,7 +151,7 @@
 	return ;
 }
 
-static void boot_prep_linux(bootm_headers_t *images)
+static void boot_prep_linux(struct bootm_headers *images)
 {
 #ifdef CONFIG_MP
 	/*
@@ -163,7 +163,7 @@
 #endif
 }
 
-static int boot_cmdline_linux(bootm_headers_t *images)
+static int boot_cmdline_linux(struct bootm_headers *images)
 {
 	ulong of_size = images->ft_len;
 	struct lmb *lmb = &images->lmb;
@@ -184,7 +184,7 @@
 	return ret;
 }
 
-static int boot_bd_t_linux(bootm_headers_t *images)
+static int boot_bd_t_linux(struct bootm_headers *images)
 {
 	ulong of_size = images->ft_len;
 	struct lmb *lmb = &images->lmb;
@@ -205,7 +205,7 @@
 	return ret;
 }
 
-static int boot_body_linux(bootm_headers_t *images)
+static int boot_body_linux(struct bootm_headers *images)
 {
 	int ret;
 
@@ -224,7 +224,7 @@
 }
 
 noinline int do_bootm_linux(int flag, int argc, char *const argv[],
-			    bootm_headers_t *images)
+			    struct bootm_headers *images)
 {
 	int	ret;
 
@@ -273,7 +273,7 @@
 }
 
 #if defined(CONFIG_BOOTM_VXWORKS)
-void boot_prep_vxworks(bootm_headers_t *images)
+void boot_prep_vxworks(struct bootm_headers *images)
 {
 #if defined(CONFIG_OF_LIBFDT)
 	int off;
@@ -305,7 +305,7 @@
 #endif
 }
 
-void boot_jump_vxworks(bootm_headers_t *images)
+void boot_jump_vxworks(struct bootm_headers *images)
 {
 	/* PowerPC VxWorks boot interface conforms to the ePAPR standard
 	 * general purpuse registers:
diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
index 5e113ee..6851475 100644
--- a/arch/riscv/lib/andes_plic.c
+++ b/arch/riscv/lib/andes_plic.c
@@ -71,7 +71,7 @@
 			continue;
 
 		/* skip if hart is marked as not available */
-		if (!ofnode_is_available(node))
+		if (!ofnode_is_enabled(node))
 			continue;
 
 		/* read hart ID of CPU */
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
index 670d9c9..f5f8b4c 100644
--- a/arch/riscv/lib/bootm.c
+++ b/arch/riscv/lib/bootm.c
@@ -62,7 +62,7 @@
 	cleanup_before_linux();
 }
 
-static void boot_prep_linux(bootm_headers_t *images)
+static void boot_prep_linux(struct bootm_headers *images)
 {
 	if (CONFIG_IS_ENABLED(OF_LIBFDT) && CONFIG_IS_ENABLED(LMB) && images->ft_len) {
 		debug("using: FDT\n");
@@ -76,7 +76,7 @@
 	}
 }
 
-static void boot_jump_linux(bootm_headers_t *images, int flag)
+static void boot_jump_linux(struct bootm_headers *images, int flag)
 {
 	void (*kernel)(ulong hart, void *dtb);
 	int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
@@ -107,7 +107,7 @@
 }
 
 int do_bootm_linux(int flag, int argc, char *const argv[],
-		   bootm_headers_t *images)
+		   struct bootm_headers *images)
 {
 	/* No need for those on RISC-V */
 	if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
@@ -129,7 +129,7 @@
 }
 
 int do_bootm_vxworks(int flag, int argc, char *const argv[],
-		     bootm_headers_t *images)
+		     struct bootm_headers *images)
 {
 	return do_bootm_linux(flag, argc, argv, images);
 }
diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c
index c0f65af..4f073a0 100644
--- a/arch/riscv/lib/smp.c
+++ b/arch/riscv/lib/smp.c
@@ -27,7 +27,7 @@
 
 	ofnode_for_each_subnode(node, cpus) {
 		/* skip if hart is marked as not available in the device tree */
-		if (!ofnode_is_available(node))
+		if (!ofnode_is_enabled(node))
 			continue;
 
 		/* read hart ID of CPU */
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index d077948..636d354 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -3,19 +3,22 @@
  * Copyright (c) 2011 The Chromium OS Authors.
  */
 
+#define LOG_CATEGORY	LOGC_SANDBOX
+
 #include <common.h>
 #include <bootstage.h>
 #include <cpu_func.h>
 #include <errno.h>
 #include <log.h>
-#include <asm/global_data.h>
-#include <linux/delay.h>
-#include <linux/libfdt.h>
 #include <os.h>
+#include <asm/global_data.h>
 #include <asm/io.h>
 #include <asm/malloc.h>
 #include <asm/setjmp.h>
 #include <asm/state.h>
+#include <dm/ofnode.h>
+#include <linux/delay.h>
+#include <linux/libfdt.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -373,3 +376,28 @@
 
 	return (count - base_count) / 1000;
 }
+
+int sandbox_load_other_fdt(void **fdtp, int *sizep)
+{
+	const char *orig;
+	int ret, size;
+	void *fdt = *fdtp;
+
+	ret = state_load_other_fdt(&orig, &size);
+	if (ret) {
+		log_err("Cannot read other FDT\n");
+		return log_msg_ret("ld", ret);
+	}
+
+	if (!*fdtp) {
+		fdt = os_malloc(size);
+		if (!fdt)
+			return log_msg_ret("mem", -ENOMEM);
+		*sizep = size;
+	}
+
+	memcpy(fdt, orig, *sizep);
+	*fdtp = fdt;
+
+	return 0;
+}
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c
index 90a84e9..642be16 100644
--- a/arch/sandbox/cpu/start.c
+++ b/arch/sandbox/cpu/start.c
@@ -205,21 +205,19 @@
 static int sandbox_cmdline_cb_test_fdt(struct sandbox_state *state,
 				       const char *arg)
 {
-	const char *fmt = "/arch/sandbox/dts/test.dtb";
-	char *p;
+	char buf[256];
 	char *fname;
 	int len;
 
-	len = strlen(state->argv[0]) + strlen(fmt) + 1;
+	len = state_get_rel_filename("arch/sandbox/dts/test.dtb", buf,
+				     sizeof(buf));
+	if (len < 0)
+		return len;
+
 	fname = os_malloc(len);
 	if (!fname)
 		return -ENOMEM;
-	strcpy(fname, state->argv[0]);
-	p = strrchr(fname, '/');
-	if (!p)
-		p = fname + strlen(fname);
-	len -= p - fname;
-	snprintf(p, len, fmt);
+	strcpy(fname, buf);
 	state->fdt_fname = fname;
 
 	return 0;
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index e0d0112..fcc4a33 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -396,6 +396,54 @@
 	return old_val;
 }
 
+int state_get_rel_filename(const char *rel_path, char *buf, int size)
+{
+	struct sandbox_state *state = state_get_current();
+	int rel_len, prog_len;
+	char *p;
+	int len;
+
+	rel_len = strlen(rel_path);
+	p = strrchr(state->argv[0], '/');
+	prog_len = p ? p - state->argv[0] : 0;
+
+	/* allow space for a / and a terminator */
+	len = prog_len + 1 + rel_len + 1;
+	if (len > size)
+		return -ENOSPC;
+	strncpy(buf, state->argv[0], prog_len);
+	buf[prog_len] = '/';
+	strcpy(buf + prog_len + 1, rel_path);
+
+	return len;
+}
+
+int state_load_other_fdt(const char **bufp, int *sizep)
+{
+	struct sandbox_state *state = state_get_current();
+	char fname[256];
+	int len, ret;
+
+	/* load the file if needed */
+	if (!state->other_fdt_buf) {
+		len = state_get_rel_filename("arch/sandbox/dts/other.dtb",
+					     fname, sizeof(fname));
+		if (len < 0)
+			return len;
+
+		ret = os_read_file(fname, &state->other_fdt_buf,
+				   &state->other_size);
+		if (ret) {
+			log_err("Cannot read file '%s'\n", fname);
+			return ret;
+		}
+	}
+	*bufp = state->other_fdt_buf;
+	*sizep = state->other_size;
+
+	return 0;
+}
+
 int state_init(void)
 {
 	state = &main_state;
diff --git a/arch/sandbox/dts/Makefile b/arch/sandbox/dts/Makefile
index 6cbc9bb..b6a8847 100644
--- a/arch/sandbox/dts/Makefile
+++ b/arch/sandbox/dts/Makefile
@@ -5,7 +5,7 @@
 else
 dtb-$(CONFIG_SANDBOX) += sandbox.dtb
 endif
-dtb-$(CONFIG_UT_DM) += test.dtb
+dtb-$(CONFIG_UT_DM) += test.dtb other.dtb
 dtb-$(CONFIG_CMD_EXTENSION) += overlay0.dtbo overlay1.dtbo
 
 include $(srctree)/scripts/Makefile.dts
diff --git a/arch/sandbox/dts/other.dts b/arch/sandbox/dts/other.dts
new file mode 100644
index 0000000..395a792
--- /dev/null
+++ b/arch/sandbox/dts/other.dts
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Other devicetree file for running sandbox tests
+ *
+ * This used for tests which want to check they can access multiple device
+ * trees. This one is loaded and checks are made that it is actually visible.
+ */
+
+/dts-v1/;
+
+/ {
+	compatible = "sandbox-other";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	node {
+		target = <&target 3 4>;
+
+		subnode {
+			compatible = "sandbox-other2";
+			str-prop = "other";
+		};
+
+		subnode2 {
+		};
+	};
+
+	target: target {
+		compatible = "sandbox-other2";
+		#gpio-cells = <2>;
+		str-prop = "other";
+		reg = <0x8000 0x100>;
+		status = "disabled";
+	};
+};
diff --git a/arch/sandbox/include/asm/malloc.h b/arch/sandbox/include/asm/malloc.h
index a1467b5..8aaaa9c 100644
--- a/arch/sandbox/include/asm/malloc.h
+++ b/arch/sandbox/include/asm/malloc.h
@@ -6,6 +6,7 @@
  */
 
 #ifndef __ASM_MALLOC_H
+#define __ASM_MALLOC_H
 
 void *malloc(size_t size);
 void free(void *ptr);
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index 07c768a..fd42daa 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -108,6 +108,9 @@
 	bool hwspinlock;		/* Hardware Spinlock status */
 	bool allow_memio;		/* Allow readl() etc. to work */
 
+	void *other_fdt_buf;		/* 'other' FDT blob used by tests */
+	int other_size;			/* size of other FDT blob */
+
 	/*
 	 * This struct is getting large.
 	 *
@@ -266,6 +269,33 @@
 void state_show(struct sandbox_state *state);
 
 /**
+ * state_get_rel_filename() - Get a filename relative to the executable
+ *
+ * This uses argv[0] to obtain a filename path
+ *
+ * @rel_path: Relative path to build, e.g. "arch/sandbox/dts/test.dtb". Must not
+ * have a trailing /
+ * @buf: Buffer to use to return the filename
+ * @size: Size of buffer
+ * @return length of filename (including terminator), -ENOSPC if @size is too
+ * small
+ */
+int state_get_rel_filename(const char *rel_path, char *buf, int size);
+
+/**
+ * state_load_other_fdt() - load the 'other' FDT into a buffer
+ *
+ * This loads the other.dtb file into a buffer. This is typically used in tests.
+ *
+ * @bufp: Place to put allocated buffer pointer. The buffer is read using
+ * os_read_file() which calls os_malloc(), so does affect U-Boot's own malloc()
+ * space
+ * @sizep: Returns the size of the buffer
+ * @return 0 if OK, -ve on error
+ */
+int state_load_other_fdt(const char **bufp, int *sizep);
+
+/**
  * Initialize the test system state
  */
 int state_init(void);
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 53a036b..0406085 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -11,6 +11,8 @@
 #include <video.h>
 #include <pci_ids.h>
 
+struct unit_test_state;
+
 /* The sandbox driver always permits an I2C device with this address */
 #define SANDBOX_I2C_TEST_ADDR		0x59
 
@@ -315,4 +317,21 @@
  */
 void sandbox_set_fake_efi_mgr_dev(struct udevice *dev, bool fake_dev);
 
+/**
+ * sandbox_load_other_fdt() - load the 'other' FDT into the test state
+ *
+ * This copies the other.dtb file into the test state, so that a fresh version
+ * can be used for a test that is about to run.
+ *
+ * If @uts->other_fdt is NULL, as it is when first set up, this allocates a
+ * buffer for the other FDT and sets @uts->other_fdt_size to its size.
+ *
+ * In any case, the other FDT is copied from the sandbox state into
+ * @uts->other_fdt ready for use.
+ *
+ * @uts: Unit test state
+ * @return 0 if OK, -ve on error
+ */
+int sandbox_load_other_fdt(void **fdtp, int *sizep);
+
 #endif
diff --git a/arch/sandbox/lib/bootm.c b/arch/sandbox/lib/bootm.c
index d1d460b..c1742f9 100644
--- a/arch/sandbox/lib/bootm.c
+++ b/arch/sandbox/lib/bootm.c
@@ -50,7 +50,7 @@
 	return ret;
 }
 
-int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
+int do_bootm_linux(int flag, int argc, char *argv[], struct bootm_headers *images)
 {
 	if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
 		bootstage_mark(BOOTSTAGE_ID_RUN_OS);
diff --git a/arch/sh/lib/bootm.c b/arch/sh/lib/bootm.c
index 7ea0444..a5fad6c 100644
--- a/arch/sh/lib/bootm.c
+++ b/arch/sh/lib/bootm.c
@@ -40,7 +40,7 @@
 }
 
 int do_bootm_linux(int flag, int argc, char *const argv[],
-		   bootm_headers_t *images)
+		   struct bootm_headers *images)
 {
 	/* Linux kernel load address */
 	void (*kernel) (void) = (void (*)(void))images->ep;
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c
index 1bcdb3e..eafcddf 100644
--- a/arch/x86/lib/bootm.c
+++ b/arch/x86/lib/bootm.c
@@ -69,10 +69,10 @@
 #endif
 
 /* Subcommand: PREP */
-static int boot_prep_linux(bootm_headers_t *images)
+static int boot_prep_linux(struct bootm_headers *images)
 {
 	char *cmd_line_dest = NULL;
-	image_header_t *hdr;
+	struct legacy_img_hdr *hdr;
 	int is_zimage = 0;
 	void *data = NULL;
 	size_t len;
@@ -201,7 +201,7 @@
 }
 
 /* Subcommand: GO */
-static int boot_jump_linux(bootm_headers_t *images)
+static int boot_jump_linux(struct bootm_headers *images)
 {
 	debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n",
 	      images->ep, images->os.load);
@@ -211,7 +211,7 @@
 }
 
 int do_bootm_linux(int flag, int argc, char *const argv[],
-		   bootm_headers_t *images)
+		   struct bootm_headers *images)
 {
 	/* No need for those on x86 */
 	if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
diff --git a/arch/xtensa/lib/bootm.c b/arch/xtensa/lib/bootm.c
index 277af18..fee3392 100644
--- a/arch/xtensa/lib/bootm.c
+++ b/arch/xtensa/lib/bootm.c
@@ -134,7 +134,7 @@
  * Boot Linux.
  */
 
-int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
+int do_bootm_linux(int flag, int argc, char *argv[], struct bootm_headers *images)
 {
 	struct bp_tag *params, *params_start;
 	ulong initrd_start, initrd_end;
diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c
index 226fbba..4308c7e 100644
--- a/board/synopsys/hsdk/hsdk.c
+++ b/board/synopsys/hsdk/hsdk.c
@@ -844,7 +844,7 @@
 	return 0;
 }
 
-int board_prep_linux(bootm_headers_t *images)
+int board_prep_linux(struct bootm_headers *images)
 {
 	int ret, ofst;
 	char mask[15];
diff --git a/board/ti/ks2_evm/board.c b/board/ti/ks2_evm/board.c
index 0c5c2c9..5ba3aa3 100644
--- a/board/ti/ks2_evm/board.c
+++ b/board/ti/ks2_evm/board.c
@@ -64,9 +64,9 @@
 	return 0;
 }
 
-struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size)
 {
-	return (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+	return (struct legacy_img_hdr *)(CONFIG_SYS_TEXT_BASE);
 }
 
 int board_init(void)
diff --git a/boot/boot_fit.c b/boot/boot_fit.c
index dfc2a31..4a493b3 100644
--- a/boot/boot_fit.c
+++ b/boot/boot_fit.c
@@ -57,14 +57,14 @@
 
 void *locate_dtb_in_fit(const void *fit)
 {
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	int size;
 	int ret;
 
 	size = fdt_totalsize(fit);
 	size = (size + 3) & ~3;
 
-	header = (struct image_header *)fit;
+	header = (struct legacy_img_hdr *)fit;
 
 	if (image_get_magic(header) != FDT_MAGIC) {
 		debug("No FIT image appended to U-boot\n");
diff --git a/boot/bootm.c b/boot/bootm.c
index e3233fd..5b20b41 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -41,10 +41,10 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-bootm_headers_t images;		/* pointers to os/initrd/fdt images */
+struct bootm_headers images;		/* pointers to os/initrd/fdt images */
 
 static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
-				   char *const argv[], bootm_headers_t *images,
+				   char *const argv[], struct bootm_headers *images,
 				   ulong *os_data, ulong *os_len);
 
 __weak void board_quiesce_devices(void)
@@ -52,7 +52,7 @@
 }
 
 #ifdef CONFIG_LMB
-static void boot_start_lmb(bootm_headers_t *images)
+static void boot_start_lmb(struct bootm_headers *images)
 {
 	ulong		mem_start;
 	phys_size_t	mem_size;
@@ -65,7 +65,7 @@
 }
 #else
 #define lmb_reserve(lmb, base, size)
-static inline void boot_start_lmb(bootm_headers_t *images) { }
+static inline void boot_start_lmb(struct bootm_headers *images) { }
 #endif
 
 static int bootm_start(struct cmd_tbl *cmdtp, int flag, int argc,
@@ -397,9 +397,9 @@
 #endif
 
 #ifndef USE_HOSTCC
-static int bootm_load_os(bootm_headers_t *images, int boot_progress)
+static int bootm_load_os(struct bootm_headers *images, int boot_progress)
 {
-	image_info_t os = images->os;
+	struct image_info os = images->os;
 	ulong load = os.load;
 	ulong load_end;
 	ulong blob_start = os.start;
@@ -688,7 +688,7 @@
  *	unless the image type is standalone.
  */
 int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
-		    char *const argv[], int states, bootm_headers_t *images,
+		    char *const argv[], int states, struct bootm_headers *images,
 		    int boot_progress)
 {
 	boot_os_fn *boot_fn;
@@ -825,9 +825,9 @@
  *     pointer to a legacy image header if valid image was found
  *     otherwise return NULL
  */
-static image_header_t *image_get_kernel(ulong img_addr, int verify)
+static struct legacy_img_hdr *image_get_kernel(ulong img_addr, int verify)
 {
-	image_header_t *hdr = (image_header_t *)img_addr;
+	struct legacy_img_hdr *hdr = (struct legacy_img_hdr *)img_addr;
 
 	if (!image_check_magic(hdr)) {
 		puts("Bad Magic Number\n");
@@ -878,11 +878,11 @@
  *     address and length, otherwise NULL
  */
 static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
-				   char *const argv[], bootm_headers_t *images,
+				   char *const argv[], struct bootm_headers *images,
 				   ulong *os_data, ulong *os_len)
 {
 #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
-	image_header_t	*hdr;
+	struct legacy_img_hdr	*hdr;
 #endif
 	ulong		img_addr;
 	const void *buf;
@@ -940,7 +940,7 @@
 		 * kernel decompression.
 		 */
 		memmove(&images->legacy_hdr_os_copy, hdr,
-			sizeof(image_header_t));
+			sizeof(struct legacy_img_hdr));
 
 		/* save pointer to image header */
 		images->legacy_hdr_os = hdr;
@@ -1002,7 +1002,7 @@
 {
 	const char *fit_uname_config = NULL;
 	ulong data, len;
-	bootm_headers_t images;
+	struct bootm_headers images;
 	int noffset;
 	ulong load_end, buf_size;
 	uint8_t image_type;
diff --git a/boot/bootm_os.c b/boot/bootm_os.c
index 079224c..99ff0e6 100644
--- a/boot/bootm_os.c
+++ b/boot/bootm_os.c
@@ -24,7 +24,7 @@
 DECLARE_GLOBAL_DATA_PTR;
 
 static int do_bootm_standalone(int flag, int argc, char *const argv[],
-			       bootm_headers_t *images)
+			       struct bootm_headers *images)
 {
 	int (*appl)(int, char *const[]);
 
@@ -65,10 +65,11 @@
 
 #ifdef CONFIG_BOOTM_NETBSD
 static int do_bootm_netbsd(int flag, int argc, char *const argv[],
-			   bootm_headers_t *images)
+			   struct bootm_headers *images)
 {
-	void (*loader)(struct bd_info *, image_header_t *, char *, char *);
-	image_header_t *os_hdr, *hdr;
+	void (*loader)(struct bd_info *bd, struct legacy_img_hdr *hdr,
+		       char *console, char *cmdline);
+	struct legacy_img_hdr *os_hdr, *hdr;
 	ulong kernel_data, kernel_len;
 	char *cmdline;
 
@@ -115,7 +116,7 @@
 			cmdline = "";
 	}
 
-	loader = (void (*)(struct bd_info *, image_header_t *, char *, char *))images->ep;
+	loader = (void (*)(struct bd_info *, struct legacy_img_hdr *, char *, char *))images->ep;
 
 	printf("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
 	       (ulong)loader);
@@ -137,7 +138,7 @@
 
 #ifdef CONFIG_BOOTM_RTEMS
 static int do_bootm_rtems(int flag, int argc, char *const argv[],
-			  bootm_headers_t *images)
+			  struct bootm_headers *images)
 {
 	void (*entry_point)(struct bd_info *);
 
@@ -170,7 +171,7 @@
 
 #if defined(CONFIG_BOOTM_OSE)
 static int do_bootm_ose(int flag, int argc, char *const argv[],
-			bootm_headers_t *images)
+			struct bootm_headers *images)
 {
 	void (*entry_point)(void);
 
@@ -203,7 +204,7 @@
 
 #if defined(CONFIG_BOOTM_PLAN9)
 static int do_bootm_plan9(int flag, int argc, char *const argv[],
-			  bootm_headers_t *images)
+			  struct bootm_headers *images)
 {
 	void (*entry_point)(void);
 	char *s;
@@ -252,7 +253,7 @@
 #if defined(CONFIG_BOOTM_VXWORKS) && \
 	(defined(CONFIG_PPC) || defined(CONFIG_ARM))
 
-static void do_bootvx_fdt(bootm_headers_t *images)
+static void do_bootvx_fdt(struct bootm_headers *images)
 {
 #if defined(CONFIG_OF_LIBFDT)
 	int ret;
@@ -311,7 +312,7 @@
 }
 
 static int do_bootm_vxworks_legacy(int flag, int argc, char *const argv[],
-				   bootm_headers_t *images)
+				   struct bootm_headers *images)
 {
 	if (flag != BOOTM_STATE_OS_GO)
 		return 0;
@@ -329,7 +330,7 @@
 }
 
 int do_bootm_vxworks(int flag, int argc, char *const argv[],
-		     bootm_headers_t *images)
+		     struct bootm_headers *images)
 {
 	char *bootargs;
 	int pos;
@@ -365,7 +366,7 @@
 
 #if defined(CONFIG_CMD_ELF)
 static int do_bootm_qnxelf(int flag, int argc, char *const argv[],
-			   bootm_headers_t *images)
+			   struct bootm_headers *images)
 {
 	char *local_args[2];
 	char str[16];
@@ -403,7 +404,7 @@
 
 #ifdef CONFIG_INTEGRITY
 static int do_bootm_integrity(int flag, int argc, char *const argv[],
-			      bootm_headers_t *images)
+			      struct bootm_headers *images)
 {
 	void (*entry_point)(void);
 
@@ -436,7 +437,7 @@
 
 #ifdef CONFIG_BOOTM_OPENRTOS
 static int do_bootm_openrtos(int flag, int argc, char *const argv[],
-			     bootm_headers_t *images)
+			     struct bootm_headers *images)
 {
 	void (*entry_point)(void);
 
@@ -462,7 +463,7 @@
 
 #ifdef CONFIG_BOOTM_OPTEE
 static int do_bootm_tee(int flag, int argc, char *const argv[],
-			bootm_headers_t *images)
+			struct bootm_headers *images)
 {
 	int ret;
 
@@ -490,7 +491,7 @@
 
 #ifdef CONFIG_BOOTM_EFI
 static int do_bootm_efi(int flag, int argc, char *const argv[],
-			bootm_headers_t *images)
+			struct bootm_headers *images)
 {
 	int ret;
 	efi_status_t efi_ret;
@@ -589,7 +590,7 @@
 }
 
 int boot_selected_os(int argc, char *const argv[], int state,
-		     bootm_headers_t *images, boot_os_fn *boot_fn)
+		     struct bootm_headers *images, boot_os_fn *boot_fn)
 {
 	arch_preboot_os();
 	board_preboot_os();
diff --git a/boot/image-android.c b/boot/image-android.c
index 1fbbbba..2628db3 100644
--- a/boot/image-android.c
+++ b/boot/image-android.c
@@ -63,7 +63,7 @@
 			     ulong *os_data, ulong *os_len)
 {
 	u32 kernel_addr = android_image_get_kernel_addr(hdr);
-	const struct image_header *ihdr = (const struct image_header *)
+	const struct legacy_img_hdr *ihdr = (const struct legacy_img_hdr *)
 		((uintptr_t)hdr + hdr->page_size);
 
 	/*
@@ -159,8 +159,8 @@
 {
 	const void *p = (void *)((uintptr_t)hdr + hdr->page_size);
 
-	if (image_get_magic((image_header_t *)p) == IH_MAGIC)
-		return image_get_comp((image_header_t *)p);
+	if (image_get_magic((struct legacy_img_hdr *)p) == IH_MAGIC)
+		return image_get_comp((struct legacy_img_hdr *)p);
 	else if (get_unaligned_le32(p) == LZ4F_MAGIC)
 		return IH_COMP_LZ4;
 	else
diff --git a/boot/image-board.c b/boot/image-board.c
index 98f903f..34d1e5f 100644
--- a/boot/image-board.c
+++ b/boot/image-board.c
@@ -40,10 +40,10 @@
  *     pointer to a ramdisk image header, if image was found and valid
  *     otherwise, return NULL
  */
-static const image_header_t *image_get_ramdisk(ulong rd_addr, u8 arch,
-					       int verify)
+static const struct legacy_img_hdr *image_get_ramdisk(ulong rd_addr, u8 arch,
+						      int verify)
 {
-	const image_header_t *rd_hdr = (const image_header_t *)rd_addr;
+	const struct legacy_img_hdr *rd_hdr = (const struct legacy_img_hdr *)rd_addr;
 
 	if (!image_check_magic(rd_hdr)) {
 		puts("Bad Magic Number\n");
@@ -273,9 +273,9 @@
 int genimg_get_format(const void *img_addr)
 {
 	if (CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)) {
-		const image_header_t *hdr;
+		const struct legacy_img_hdr *hdr;
 
-		hdr = (const image_header_t *)img_addr;
+		hdr = (const struct legacy_img_hdr *)img_addr;
 		if (image_check_magic(hdr))
 			return IMAGE_FORMAT_LEGACY;
 	}
@@ -301,7 +301,7 @@
  *     0, no FIT support or no configuration found
  *     1, configuration found
  */
-int genimg_has_config(bootm_headers_t *images)
+int genimg_has_config(struct bootm_headers *images)
 {
 	if (CONFIG_IS_ENABLED(FIT) && images->fit_uname_cfg)
 		return 1;
@@ -320,7 +320,7 @@
  * Return: 0 if OK, -ENOPKG if no ramdisk (but an error should not be reported),
  *	other -ve value on other error
  */
-static int select_ramdisk(bootm_headers_t *images, const char *select, u8 arch,
+static int select_ramdisk(struct bootm_headers *images, const char *select, u8 arch,
 			  ulong *rd_datap, ulong *rd_lenp)
 {
 	const char *fit_uname_config;
@@ -389,7 +389,7 @@
 	switch (genimg_get_format(buf)) {
 	case IMAGE_FORMAT_LEGACY:
 		if (CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)) {
-			const image_header_t *rd_hdr;
+			const struct legacy_img_hdr *rd_hdr;
 
 			printf("## Loading init Ramdisk from Legacy Image at %08lx ...\n",
 			       rd_addr);
@@ -482,7 +482,7 @@
  *     1, if ramdisk image is found but corrupted, or invalid
  *     rd_start and rd_end are set to 0 if no ramdisk exists
  */
-int boot_get_ramdisk(int argc, char *const argv[], bootm_headers_t *images,
+int boot_get_ramdisk(int argc, char *const argv[], struct bootm_headers *images,
 		     u8 arch, ulong *rd_start, ulong *rd_end)
 {
 	ulong rd_data, rd_len;
@@ -646,7 +646,7 @@
 	return -1;
 }
 
-int boot_get_setup(bootm_headers_t *images, u8 arch,
+int boot_get_setup(struct bootm_headers *images, u8 arch,
 		   ulong *setup_start, ulong *setup_len)
 {
 	if (!CONFIG_IS_ENABLED(FIT))
@@ -655,7 +655,7 @@
 	return boot_get_setup_fit(images, arch, setup_start, setup_len);
 }
 
-int boot_get_fpga(int argc, char *const argv[], bootm_headers_t *images,
+int boot_get_fpga(int argc, char *const argv[], struct bootm_headers *images,
 		  u8 arch, const ulong *ld_start, ulong * const ld_len)
 {
 	ulong tmp_img_addr, img_data, img_len;
@@ -758,7 +758,7 @@
 			fit_loadable_handler->handler(img_data, img_len);
 }
 
-int boot_get_loadable(int argc, char *const argv[], bootm_headers_t *images,
+int boot_get_loadable(int argc, char *const argv[], struct bootm_headers *images,
 		      u8 arch, const ulong *ld_start, ulong * const ld_len)
 {
 	/*
@@ -919,7 +919,7 @@
 	return 0;
 }
 
-int image_setup_linux(bootm_headers_t *images)
+int image_setup_linux(struct bootm_headers *images)
 {
 	ulong of_size = images->ft_len;
 	char **of_flat_tree = &images->ft_addr;
diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index e75d051..884e089 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -37,9 +37,9 @@
 }
 
 #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
-static const image_header_t *image_get_fdt(ulong fdt_addr)
+static const struct legacy_img_hdr *image_get_fdt(ulong fdt_addr)
 {
-	const image_header_t *fdt_hdr = map_sysmem(fdt_addr, 0);
+	const struct legacy_img_hdr *fdt_hdr = map_sysmem(fdt_addr, 0);
 
 	image_print_contents(fdt_hdr);
 
@@ -291,7 +291,7 @@
  *	other -ve value on other error
  */
 
-static int select_fdt(bootm_headers_t *images, const char *select, u8 arch,
+static int select_fdt(struct bootm_headers *images, const char *select, u8 arch,
 		      ulong *fdt_addrp)
 {
 	const char *buf;
@@ -358,7 +358,7 @@
 	switch (genimg_get_format(buf)) {
 #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
 	case IMAGE_FORMAT_LEGACY: {
-			const image_header_t *fdt_hdr;
+			const struct legacy_img_hdr *fdt_hdr;
 			ulong load, load_end;
 			ulong image_start, image_data, image_end;
 
@@ -470,7 +470,7 @@
  *     of_flat_tree and of_size are set to 0 if no fdt exists
  */
 int boot_get_fdt(int flag, int argc, char *const argv[], uint8_t arch,
-		 bootm_headers_t *images, char **of_flat_tree, ulong *of_size)
+		 struct bootm_headers *images, char **of_flat_tree, ulong *of_size)
 {
 	ulong		img_addr;
 	ulong		fdt_addr;
@@ -602,7 +602,7 @@
 	return 0;
 }
 
-int image_setup_libfdt(bootm_headers_t *images, void *blob,
+int image_setup_libfdt(struct bootm_headers *images, void *blob,
 		       int of_size, struct lmb *lmb)
 {
 	ulong *initrd_start = &images->initrd_start;
@@ -669,6 +669,7 @@
 		struct event_ft_fixup fixup;
 
 		fixup.tree = oftree_default();
+		fixup.images = images;
 		ret = event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup));
 		if (ret) {
 			printf("ERROR: fdt fixup event failed: %d\n", ret);
diff --git a/boot/image-fit.c b/boot/image-fit.c
index f16eab9..6e503f8 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -1969,8 +1969,8 @@
 	return 0;
 }
 
-int fit_get_node_from_config(bootm_headers_t *images, const char *prop_name,
-			ulong addr)
+int fit_get_node_from_config(struct bootm_headers *images,
+			     const char *prop_name, ulong addr)
 {
 	int cfg_noffset;
 	void *fit_hdr;
@@ -2031,7 +2031,7 @@
 	return "unknown";
 }
 
-int fit_image_load(bootm_headers_t *images, ulong addr,
+int fit_image_load(struct bootm_headers *images, ulong addr,
 		   const char **fit_unamep, const char **fit_uname_configp,
 		   int arch, int image_type, int bootstage_id,
 		   enum fit_load_op load_op, ulong *datap, ulong *lenp)
@@ -2289,8 +2289,8 @@
 	return noffset;
 }
 
-int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
-			ulong *setup_start, ulong *setup_len)
+int boot_get_setup_fit(struct bootm_headers *images, uint8_t arch,
+		       ulong *setup_start, ulong *setup_len)
 {
 	int noffset;
 	ulong addr;
@@ -2310,9 +2310,9 @@
 }
 
 #ifndef USE_HOSTCC
-int boot_get_fdt_fit(bootm_headers_t *images, ulong addr,
-		   const char **fit_unamep, const char **fit_uname_configp,
-		   int arch, ulong *datap, ulong *lenp)
+int boot_get_fdt_fit(struct bootm_headers *images, ulong addr,
+		     const char **fit_unamep, const char **fit_uname_configp,
+		     int arch, ulong *datap, ulong *lenp)
 {
 	int fdt_noffset, cfg_noffset, count;
 	const void *fit;
diff --git a/boot/image.c b/boot/image.c
index a0d0cc2..9f95b32 100644
--- a/boot/image.c
+++ b/boot/image.c
@@ -220,11 +220,11 @@
 /*****************************************************************************/
 /* Legacy format routines */
 /*****************************************************************************/
-int image_check_hcrc(const image_header_t *hdr)
+int image_check_hcrc(const struct legacy_img_hdr *hdr)
 {
 	ulong hcrc;
 	ulong len = image_get_header_size();
-	image_header_t header;
+	struct legacy_img_hdr header;
 
 	/* Copy header so we can blank CRC field for re-calculation */
 	memmove(&header, (char *)hdr, image_get_header_size());
@@ -235,7 +235,7 @@
 	return (hcrc == image_get_hcrc(hdr));
 }
 
-int image_check_dcrc(const image_header_t *hdr)
+int image_check_dcrc(const struct legacy_img_hdr *hdr)
 {
 	ulong data = image_get_data(hdr);
 	ulong len = image_get_data_size(hdr);
@@ -257,7 +257,7 @@
  * returns:
  *     number of components
  */
-ulong image_multi_count(const image_header_t *hdr)
+ulong image_multi_count(const struct legacy_img_hdr *hdr)
 {
 	ulong i, count = 0;
 	uint32_t *size;
@@ -290,7 +290,7 @@
  *     data address and size of the component, if idx is valid
  *     0 in data and len, if idx is out of range
  */
-void image_multi_getimg(const image_header_t *hdr, ulong idx,
+void image_multi_getimg(const struct legacy_img_hdr *hdr, ulong idx,
 			ulong *data, ulong *len)
 {
 	int i;
@@ -326,7 +326,7 @@
 	}
 }
 
-static void image_print_type(const image_header_t *hdr)
+static void image_print_type(const struct legacy_img_hdr *hdr)
 {
 	const char __maybe_unused *os, *arch, *type, *comp;
 
@@ -352,7 +352,7 @@
  */
 void image_print_contents(const void *ptr)
 {
-	const image_header_t *hdr = (const image_header_t *)ptr;
+	const struct legacy_img_hdr *hdr = (const struct legacy_img_hdr *)ptr;
 	const char __maybe_unused *p;
 
 	p = IMAGE_INDENT_STRING;
diff --git a/boot/vbe_simple.c b/boot/vbe_simple.c
index 0fc5738..61b6322 100644
--- a/boot/vbe_simple.c
+++ b/boot/vbe_simple.c
@@ -240,7 +240,7 @@
 			continue;
 
 		/* Check if there is a node to fix up */
-		node = ofnode_path_root(tree, "/chosen/fwupd");
+		node = oftree_path(tree, "/chosen/fwupd");
 		if (!ofnode_valid(node))
 			continue;
 		node = ofnode_find_subnode(node, dev->name);
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 8ab0ff5..3041873 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -281,7 +281,7 @@
 		return EFI_SUCCESS;
 	}
 #else
-	bootm_headers_t img = { 0 };
+	struct bootm_headers img = { 0 };
 	efi_status_t ret;
 
 	if (fdt == EFI_FDT_USE_INTERNAL) {
diff --git a/cmd/booti.c b/cmd/booti.c
index 397d4b8..6ac3919 100644
--- a/cmd/booti.c
+++ b/cmd/booti.c
@@ -21,7 +21,7 @@
  * Image booting support
  */
 static int booti_start(struct cmd_tbl *cmdtp, int flag, int argc,
-		       char *const argv[], bootm_headers_t *images)
+		       char *const argv[], struct bootm_headers *images)
 {
 	int ret;
 	ulong ld;
diff --git a/cmd/bootm.c b/cmd/bootm.c
index 9fe8ce4..d764a27 100644
--- a/cmd/bootm.c
+++ b/cmd/bootm.c
@@ -511,7 +511,7 @@
 			continue;
 
 		for (off = 0; off < mtd->size; off += mtd->erasesize) {
-			const image_header_t *header;
+			const struct legacy_img_hdr *header;
 			int ret;
 
 			if (nand_block_isbad(mtd, off))
@@ -529,7 +529,7 @@
 			switch (genimg_get_format(buffer)) {
 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
 			case IMAGE_FORMAT_LEGACY:
-				header = (const image_header_t *)buffer;
+				header = (const struct legacy_img_hdr *)buffer;
 
 				len = image_get_image_size(header);
 				nand_imls_legacyimage(mtd, nand_dev, off, len);
diff --git a/cmd/bootz.c b/cmd/bootz.c
index 4f024bd..f142357 100644
--- a/cmd/bootz.c
+++ b/cmd/bootz.c
@@ -25,7 +25,7 @@
  * zImage booting support
  */
 static int bootz_start(struct cmd_tbl *cmdtp, int flag, int argc,
-		       char *const argv[], bootm_headers_t *images)
+		       char *const argv[], struct bootm_headers *images)
 {
 	int ret;
 	ulong zi_start, zi_end;
diff --git a/cmd/disk.c b/cmd/disk.c
index cb3b990..3d7bc2f 100644
--- a/cmd/disk.c
+++ b/cmd/disk.c
@@ -20,7 +20,7 @@
 	ulong cnt;
 	struct disk_partition info;
 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
-	image_header_t *hdr;
+	struct legacy_img_hdr *hdr;
 #endif
 	struct blk_desc *dev_desc;
 
@@ -68,7 +68,7 @@
 	switch (genimg_get_format((void *) addr)) {
 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
 	case IMAGE_FORMAT_LEGACY:
-		hdr = (image_header_t *) addr;
+		hdr = (struct legacy_img_hdr *)addr;
 
 		bootstage_mark(BOOTSTAGE_ID_IDE_FORMAT);
 
diff --git a/cmd/fpga.c b/cmd/fpga.c
index 9cf7651..8c64e957 100644
--- a/cmd/fpga.c
+++ b/cmd/fpga.c
@@ -288,7 +288,7 @@
 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
 	case IMAGE_FORMAT_LEGACY:
 	{
-		image_header_t *hdr = (image_header_t *)fpga_data;
+		struct legacy_img_hdr *hdr = (struct legacy_img_hdr *)fpga_data;
 		ulong data;
 		u8 comp;
 
diff --git a/cmd/nand.c b/cmd/nand.c
index e730484..5bb4379 100644
--- a/cmd/nand.c
+++ b/cmd/nand.c
@@ -975,7 +975,7 @@
 	char *s;
 	size_t cnt;
 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
-	image_header_t *hdr;
+	struct legacy_img_hdr *hdr;
 #endif
 #if defined(CONFIG_FIT)
 	const void *fit_hdr = NULL;
@@ -1004,7 +1004,7 @@
 	switch (genimg_get_format ((void *)addr)) {
 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
 	case IMAGE_FORMAT_LEGACY:
-		hdr = (image_header_t *)addr;
+		hdr = (struct legacy_img_hdr *)addr;
 
 		bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
 		image_print_contents (hdr);
diff --git a/cmd/source.c b/cmd/source.c
index 81e015b..698d9f8 100644
--- a/cmd/source.c
+++ b/cmd/source.c
@@ -46,7 +46,7 @@
 {
 	ulong		len;
 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
-	const image_header_t *hdr;
+	const struct legacy_img_hdr *hdr;
 #endif
 	u32		*data;
 	int		verify;
diff --git a/cmd/ximg.c b/cmd/ximg.c
index 63b2004..1c40fd2 100644
--- a/cmd/ximg.c
+++ b/cmd/ximg.c
@@ -42,7 +42,7 @@
 	int		part = 0;
 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
 	ulong		count;
-	image_header_t	*hdr = NULL;
+	struct legacy_img_hdr	*hdr = NULL;
 #endif
 #if defined(CONFIG_FIT)
 	const char	*uname = NULL;
@@ -78,7 +78,7 @@
 		printf("## Copying part %d from legacy image "
 			"at %08lx ...\n", part, addr);
 
-		hdr = (image_header_t *)addr;
+		hdr = (struct legacy_img_hdr *)addr;
 		if (!image_check_magic(hdr)) {
 			printf("Bad Magic Number\n");
 			return 1;
diff --git a/common/Kconfig b/common/Kconfig
index 6591acd..6608a4f 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -577,7 +577,7 @@
 	help
 	  This enables sending and processing of events, to allow interested
 	  parties to be alerted when something happens. This is an attempt to
-	  step the flow of weak functions, hooks, functions in board_f.c
+	  stem the flow of weak functions, hooks, functions in board_f.c
 	  and board_r.c and the Kconfig options below.
 
 	  See doc/develop/event.rst for more information.
diff --git a/common/board_r.c b/common/board_r.c
index 50670b5..6e1ad2b 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -234,6 +234,8 @@
 {
 	int ret;
 
+	oftree_reset();
+
 	/* Save the pre-reloc driver model and start a new one */
 	gd->dm_root_f = gd->dm_root;
 	gd->dm_root = NULL;
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index f48cd2a..41c7230 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -596,6 +596,9 @@
 ulong mem_malloc_end = 0;
 ulong mem_malloc_brk = 0;
 
+static bool malloc_testing;	/* enable test mode */
+static int malloc_max_allocs;	/* return NULL after this many calls to malloc() */
+
 void *sbrk(ptrdiff_t increment)
 {
 	ulong old = mem_malloc_brk;
@@ -1307,6 +1310,11 @@
 		return malloc_simple(bytes);
 #endif
 
+  if (CONFIG_IS_ENABLED(UNIT_TEST) && malloc_testing) {
+    if (--malloc_max_allocs < 0)
+      return NULL;
+  }
+
   /* check if mem_malloc_init() was run */
   if ((mem_malloc_start == 0) && (mem_malloc_end == 0)) {
     /* not initialized yet */
@@ -2470,6 +2478,17 @@
 	return 0;
 }
 
+void malloc_enable_testing(int max_allocs)
+{
+	malloc_testing = true;
+	malloc_max_allocs = max_allocs;
+}
+
+void malloc_disable_testing(void)
+{
+	malloc_testing = false;
+}
+
 /*
 
 History:
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 828f72f..752b5b2 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -227,7 +227,7 @@
 	/* Nothing to do! */
 }
 
-__weak struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+__weak struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size)
 {
 	return map_sysmem(CONFIG_SYS_TEXT_BASE + offset, 0);
 }
@@ -258,9 +258,9 @@
 #if CONFIG_IS_ENABLED(LOAD_FIT_FULL)
 /* Parse and load full fitImage in SPL */
 static int spl_load_fit_image(struct spl_image_info *spl_image,
-			      const struct image_header *header)
+			      const struct legacy_img_hdr *header)
 {
-	bootm_headers_t images;
+	struct bootm_headers images;
 	const char *fit_uname_config = NULL;
 	uintptr_t fdt_hack;
 	const char *uname;
@@ -359,7 +359,7 @@
 }
 
 __weak int spl_parse_legacy_header(struct spl_image_info *spl_image,
-				   const struct image_header *header)
+				   const struct legacy_img_hdr *header)
 {
 	/* LEGACY image not supported */
 	debug("Legacy boot image support not enabled, proceeding to other boot methods\n");
@@ -368,7 +368,7 @@
 
 int spl_parse_image_header(struct spl_image_info *spl_image,
 			   const struct spl_boot_device *bootdev,
-			   const struct image_header *header)
+			   const struct legacy_img_hdr *header)
 {
 #if CONFIG_IS_ENABLED(LOAD_FIT_FULL)
 	int ret = spl_load_fit_image(spl_image, header);
diff --git a/common/spl/spl_ext.c b/common/spl/spl_ext.c
index ebd914c..f117c63 100644
--- a/common/spl/spl_ext.c
+++ b/common/spl/spl_ext.c
@@ -15,7 +15,7 @@
 		       const char *filename)
 {
 	s32 err;
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	loff_t filelen, actlen;
 	struct disk_partition part_info = {};
 
@@ -41,7 +41,7 @@
 		puts("spl: ext4fs_open failed\n");
 		goto end;
 	}
-	err = ext4fs_read((char *)header, 0, sizeof(struct image_header), &actlen);
+	err = ext4fs_read((char *)header, 0, sizeof(struct legacy_img_hdr), &actlen);
 	if (err < 0) {
 		puts("spl: ext4fs_read failed\n");
 		goto end;
diff --git a/common/spl/spl_fat.c b/common/spl/spl_fat.c
index 5b27054..f8a5b80 100644
--- a/common/spl/spl_fat.c
+++ b/common/spl/spl_fat.c
@@ -60,7 +60,7 @@
 		       const char *filename)
 {
 	int err;
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 
 	err = spl_register_fat_device(block_dev, partition);
 	if (err)
@@ -68,7 +68,7 @@
 
 	header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));
 
-	err = file_fat_read(filename, header, sizeof(struct image_header));
+	err = file_fat_read(filename, header, sizeof(struct legacy_img_hdr));
 	if (err <= 0)
 		goto end;
 
@@ -78,7 +78,7 @@
 		if (err <= 0)
 			goto end;
 		err = spl_parse_image_header(spl_image, bootdev,
-				(struct image_header *)CONFIG_SYS_LOAD_ADDR);
+				(struct legacy_img_hdr *)CONFIG_SYS_LOAD_ADDR);
 		if (err == -EAGAIN)
 			return err;
 		if (err == 0)
diff --git a/common/spl/spl_legacy.c b/common/spl/spl_legacy.c
index ae8731c..b3624df 100644
--- a/common/spl/spl_legacy.c
+++ b/common/spl/spl_legacy.c
@@ -16,9 +16,9 @@
 #define LZMA_LEN	(1 << 20)
 
 int spl_parse_legacy_header(struct spl_image_info *spl_image,
-			    const struct image_header *header)
+			    const struct legacy_img_hdr *header)
 {
-	u32 header_size = sizeof(struct image_header);
+	u32 header_size = sizeof(struct legacy_img_hdr);
 
 	/* check uImage header CRC */
 	if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK) &&
@@ -67,7 +67,7 @@
  * following switch/case statement in spl_load_legacy_img() away due to
  * Dead Code Elimination.
  */
-static inline int spl_image_get_comp(const struct image_header *hdr)
+static inline int spl_image_get_comp(const struct legacy_img_hdr *hdr)
 {
 	if (IS_ENABLED(CONFIG_SPL_LZMA))
 		return image_get_comp(hdr);
@@ -81,7 +81,7 @@
 {
 	__maybe_unused SizeT lzma_len;
 	__maybe_unused void *src;
-	struct image_header hdr;
+	struct legacy_img_hdr hdr;
 	ulong dataptr;
 	int ret;
 
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 23a395e..e4135b2 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -20,7 +20,7 @@
 static int mmc_load_legacy(struct spl_image_info *spl_image,
 			   struct spl_boot_device *bootdev,
 			   struct mmc *mmc,
-			   ulong sector, struct image_header *header)
+			   ulong sector, struct legacy_img_hdr *header)
 {
 	u32 image_offset_sectors;
 	u32 image_size_sectors;
@@ -83,7 +83,7 @@
 			      struct mmc *mmc, unsigned long sector)
 {
 	unsigned long count;
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	struct blk_desc *bd = mmc_get_blk_desc(mmc);
 	int ret = 0;
 
diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c
index 7b7579a..a167388 100644
--- a/common/spl/spl_nand.c
+++ b/common/spl/spl_nand.c
@@ -78,7 +78,7 @@
 
 static int spl_nand_load_element(struct spl_image_info *spl_image,
 				 struct spl_boot_device *bootdev,
-				 int offset, struct image_header *header)
+				 int offset, struct legacy_img_hdr *header)
 {
 	struct mtd_info *mtd = nand_get_mtd();
 	int bl_len = mtd ? mtd->writesize : 1;
@@ -133,7 +133,7 @@
 			       struct spl_boot_device *bootdev)
 {
 	int err;
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	int *src __attribute__((unused));
 	int *dst __attribute__((unused));
 
diff --git a/common/spl/spl_net.c b/common/spl/spl_net.c
index a853e6a..b2c901b 100644
--- a/common/spl/spl_net.c
+++ b/common/spl/spl_net.c
@@ -28,7 +28,7 @@
 static int spl_net_load_image(struct spl_image_info *spl_image,
 			      struct spl_boot_device *bootdev)
 {
-	struct image_header *header = (struct image_header *)image_load_addr;
+	struct legacy_img_hdr *header = (struct legacy_img_hdr *)image_load_addr;
 	int rv;
 
 	env_init();
diff --git a/common/spl/spl_nor.c b/common/spl/spl_nor.c
index 7986e93..281c613 100644
--- a/common/spl/spl_nor.c
+++ b/common/spl/spl_nor.c
@@ -26,7 +26,7 @@
 static int spl_nor_load_image(struct spl_image_info *spl_image,
 			      struct spl_boot_device *bootdev)
 {
-	__maybe_unused const struct image_header *header;
+	__maybe_unused const struct legacy_img_hdr *header;
 	__maybe_unused struct spl_load_info load;
 
 	/*
@@ -41,7 +41,7 @@
 		 * Load Linux from its location in NOR flash to its defined
 		 * location in SDRAM
 		 */
-		header = (const struct image_header *)CONFIG_SYS_OS_BASE;
+		header = (const struct legacy_img_hdr *)CONFIG_SYS_OS_BASE;
 #ifdef CONFIG_SPL_LOAD_FIT
 		if (image_get_magic(header) == FDT_MAGIC) {
 			int ret;
@@ -72,7 +72,7 @@
 
 			memcpy((void *)spl_image->load_addr,
 			       (void *)(CONFIG_SYS_OS_BASE +
-					sizeof(struct image_header)),
+					sizeof(struct legacy_img_hdr)),
 			       spl_image->size);
 #ifdef CONFIG_SYS_SPL_ARGS_ADDR
 			spl_image->arg = (void *)CONFIG_SYS_SPL_ARGS_ADDR;
@@ -92,7 +92,7 @@
 	 * defined location in SDRAM
 	 */
 #ifdef CONFIG_SPL_LOAD_FIT
-	header = (const struct image_header *)spl_nor_get_uboot_base();
+	header = (const struct legacy_img_hdr *)spl_nor_get_uboot_base();
 	if (image_get_magic(header) == FDT_MAGIC) {
 		debug("Found FIT format U-Boot\n");
 		load.bl_len = 1;
diff --git a/common/spl/spl_onenand.c b/common/spl/spl_onenand.c
index f80769a..53a8c6d 100644
--- a/common/spl/spl_onenand.c
+++ b/common/spl/spl_onenand.c
@@ -18,7 +18,7 @@
 static int spl_onenand_load_image(struct spl_image_info *spl_image,
 				  struct spl_boot_device *bootdev)
 {
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	int ret;
 
 	debug("spl: onenand\n");
diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c
index d647108..2b1ac19 100644
--- a/common/spl/spl_ram.c
+++ b/common/spl/spl_ram.c
@@ -41,9 +41,9 @@
 static int spl_ram_load_image(struct spl_image_info *spl_image,
 			      struct spl_boot_device *bootdev)
 {
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 
-	header = (struct image_header *)CONFIG_SPL_LOAD_FIT_ADDRESS;
+	header = (struct legacy_img_hdr *)CONFIG_SPL_LOAD_FIT_ADDRESS;
 
 	if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)) {
 		unsigned long addr = (unsigned long)header;
@@ -53,7 +53,7 @@
 			return ret;
 
 		addr += image_load_offset;
-		header = (struct image_header *)addr;
+		header = (struct legacy_img_hdr *)addr;
 	}
 
 #if CONFIG_IS_ENABLED(DFU)
@@ -87,7 +87,7 @@
 			u_boot_pos = (ulong)spl_get_load_buffer(-sizeof(*header),
 								sizeof(*header));
 		}
-		header = (struct image_header *)map_sysmem(u_boot_pos, 0);
+		header = (struct legacy_img_hdr *)map_sysmem(u_boot_pos, 0);
 
 		spl_parse_image_header(spl_image, bootdev, header);
 	}
diff --git a/common/spl/spl_sata.c b/common/spl/spl_sata.c
index 6c36f2c..9ae0273 100644
--- a/common/spl/spl_sata.c
+++ b/common/spl/spl_sata.c
@@ -30,7 +30,7 @@
 		struct spl_boot_device *bootdev,
 		struct blk_desc *stor_dev, unsigned long sector)
 {
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	unsigned long count;
 	u32 image_size_sectors;
 	u32 image_offset_sectors;
diff --git a/common/spl/spl_semihosting.c b/common/spl/spl_semihosting.c
index df6aeb2..5b5e842 100644
--- a/common/spl/spl_semihosting.c
+++ b/common/spl/spl_semihosting.c
@@ -27,7 +27,7 @@
 	const char *filename = CONFIG_SPL_FS_LOAD_PAYLOAD_NAME;
 	int ret;
 	long fd, len;
-	struct image_header *header =
+	struct legacy_img_hdr *header =
 		spl_get_load_buffer(-sizeof(*header), sizeof(*header));
 
 	fd = smh_open(filename, MODE_READ | MODE_BINARY);
@@ -43,7 +43,7 @@
 	}
 	len = ret;
 
-	ret = smh_read_full(fd, header, sizeof(struct image_header));
+	ret = smh_read_full(fd, header, sizeof(struct legacy_img_hdr));
 	if (ret) {
 		log_debug("could not read image header: %d\n", ret);
 		goto out;
diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c
index d959ad1..da67424 100644
--- a/common/spl/spl_spi.c
+++ b/common/spl/spl_spi.c
@@ -26,7 +26,7 @@
 static int spi_load_image_os(struct spl_image_info *spl_image,
 			     struct spl_boot_device *bootdev,
 			     struct spi_flash *flash,
-			     struct image_header *header)
+			     struct legacy_img_hdr *header)
 {
 	int err;
 
@@ -92,7 +92,7 @@
 	int err = 0;
 	unsigned int payload_offs;
 	struct spi_flash *flash;
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	unsigned int sf_bus = spl_spi_boot_bus();
 	unsigned int sf_cs = spl_spi_boot_cs();
 
@@ -139,7 +139,7 @@
 			if (err)
 				return err;
 			err = spl_parse_image_header(spl_image, bootdev,
-					(struct image_header *)CONFIG_SYS_LOAD_ADDR);
+					(struct legacy_img_hdr *)CONFIG_SYS_LOAD_ADDR);
 		} else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
 			   image_get_magic(header) == FDT_MAGIC) {
 			struct spl_load_info load;
diff --git a/common/spl/spl_ubi.c b/common/spl/spl_ubi.c
index bdf5cc4..fb804f0 100644
--- a/common/spl/spl_ubi.c
+++ b/common/spl/spl_ubi.c
@@ -15,7 +15,7 @@
 int spl_ubi_load_image(struct spl_image_info *spl_image,
 		       struct spl_boot_device *bootdev)
 {
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	struct ubispl_info info;
 	struct ubispl_load volumes[2];
 	int ret = 1;
@@ -54,7 +54,7 @@
 
 		ret = ubispl_load_volumes(&info, volumes, 2);
 		if (!ret) {
-			header = (struct image_header *)volumes[0].load_addr;
+			header = (struct legacy_img_hdr *)volumes[0].load_addr;
 			spl_parse_image_header(spl_image, bootdev, header);
 			puts("Linux loaded.\n");
 			goto out;
diff --git a/common/spl/spl_xip.c b/common/spl/spl_xip.c
index e9a40b0..1258d85 100644
--- a/common/spl/spl_xip.c
+++ b/common/spl/spl_xip.c
@@ -25,6 +25,6 @@
 	}
 #endif
 	return(spl_parse_image_header(spl_image, bootdev,
-	       (const struct image_header *)CONFIG_SYS_UBOOT_BASE));
+	       (const struct legacy_img_hdr *)CONFIG_SYS_UBOOT_BASE));
 }
 SPL_LOAD_IMAGE_METHOD("XIP", 0, BOOT_DEVICE_XIP, spl_xip);
diff --git a/common/spl/spl_ymodem.c b/common/spl/spl_ymodem.c
index fdd5261..038b443 100644
--- a/common/spl/spl_ymodem.c
+++ b/common/spl/spl_ymodem.c
@@ -96,7 +96,7 @@
 	int ret;
 	connection_info_t info;
 	char buf[BUF_SIZE];
-	struct image_header *ih = NULL;
+	struct legacy_img_hdr *ih = NULL;
 	ulong addr = 0;
 
 	info.mode = xyzModem_ymodem;
@@ -111,9 +111,9 @@
 		goto end_stream;
 
 	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) &&
-	    image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
+	    image_get_magic((struct legacy_img_hdr *)buf) == FDT_MAGIC) {
 		addr = CONFIG_SYS_LOAD_ADDR;
-		ih = (struct image_header *)addr;
+		ih = (struct legacy_img_hdr *)addr;
 
 		memcpy((void *)addr, buf, res);
 		size += res;
@@ -129,7 +129,7 @@
 		if (ret)
 			return ret;
 	} else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
-	    image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
+	    image_get_magic((struct legacy_img_hdr *)buf) == FDT_MAGIC) {
 		struct spl_load_info load;
 		struct ymodem_fit_info info;
 
@@ -147,7 +147,7 @@
 		while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0)
 			size += res;
 	} else {
-		ih = (struct image_header *)buf;
+		ih = (struct legacy_img_hdr *)buf;
 		ret = spl_parse_image_header(spl_image, bootdev, ih);
 		if (ret)
 			goto end_stream;
@@ -158,7 +158,7 @@
 #endif
 			addr = spl_image->load_addr;
 		memcpy((void *)addr, buf, res);
-		ih = (struct image_header *)addr;
+		ih = (struct legacy_img_hdr *)addr;
 		size += res;
 		addr += res;
 
@@ -177,7 +177,7 @@
 
 #ifdef CONFIG_SPL_GZIP
 	if (!(IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
-	      image_get_magic((struct image_header *)buf) == FDT_MAGIC) &&
+	      image_get_magic((struct legacy_img_hdr *)buf) == FDT_MAGIC) &&
 	    (ih->ih_comp == IH_COMP_GZIP)) {
 		if (gunzip((void *)(spl_image->load_addr + sizeof(*ih)),
 			   CONFIG_SYS_BOOTM_LEN,
diff --git a/common/splash_source.c b/common/splash_source.c
index 2c03cbd..87e55a5 100644
--- a/common/splash_source.c
+++ b/common/splash_source.c
@@ -327,17 +327,17 @@
 	int external_splash_addr;
 	int external_splash_size;
 	bool is_splash_external = false;
-	struct image_header *img_header;
+	struct legacy_img_hdr *img_header;
 	const u32 *fit_header;
 	u32 fit_size;
-	const size_t header_size = sizeof(struct image_header);
+	const size_t header_size = sizeof(struct legacy_img_hdr);
 
 	/* Read in image header */
 	res = splash_storage_read_raw(location, bmp_load_addr, header_size);
 	if (res < 0)
 		return res;
 
-	img_header = (struct image_header *)bmp_load_addr;
+	img_header = (struct legacy_img_hdr *)bmp_load_addr;
 	if (image_get_magic(img_header) != FDT_MAGIC) {
 		printf("Could not find FDT magic\n");
 		return -EINVAL;
diff --git a/doc/develop/driver-model/livetree.rst b/doc/develop/driver-model/livetree.rst
index faf3eb5..55aa3ea 100644
--- a/doc/develop/driver-model/livetree.rst
+++ b/doc/develop/driver-model/livetree.rst
@@ -235,20 +235,9 @@
 work correctly even with OF_LIVE is enabled. But if a test modifies the flat
 device tree, then the live tree can become invalid. Any live tree tests that run
 after that point will use a corrupted tree, e.g. with an incorrect property name
-or worse. To deal with this we use a flag UT_TESTF_LIVE_OR_FLAT then ensures
-that tests which write to the flat tree are not run if OF_LIVE is enabled. Only
-the live tree version of the test is run, when OF_LIVE is enabled, with
-sandbox_flattree running the flat tree version.
-
-This is of course a work-around, even if a reasonable one. One solution to this
-problem would be to make a copy of the flat tree before the test and restore it
-afterwards, in the same memory location, so that the live tree pointers work
-again. Another would be to regenerate the live tree if a test modified the flat
-tree.
-
-Neither of these solutions is currently implemented, since the situation that
-causes the problem can only occur in sandbox tests, is somewhat esoteric and
-the UT_TESTF_LIVE_OR_FLAT flag deals with it in a reasonable way.
+or worse. To deal with this we take a copy of the device tree and restore it
+after any test that modifies it. Note that this copy is not made on other
+boards, only sandbox.
 
 
 Multiple livetrees
@@ -261,11 +250,14 @@
 It would be helpful to use livetree for fixups, since adding a lot of nodes and
 properties would involve less memory copying and be more efficient. As a step
 towards this, an `oftree` type has been introduced. It is normally set to
-oftree_default() but can be set to other values. Eventually this should allow
-the use of FDT fixups using the ofnode interface, instead of the low-level
-libfdt one.
+oftree_default() but can be set to other values using oftree_from_fdt().
+So long as OF_LIVE is disabled, it is possible to do fixups using the ofnode
+interface. The OF_LIVE support required addition of the flattening step at the
+end.
 
-See dm_test_ofnode_root() for some examples.
+See dm_test_ofnode_root() for some examples. The ofnode_path_root() function
+causes a flat device tree to be 'registered' such that it can be used by the
+ofnode interface.
 
 
 Internal implementation
@@ -329,10 +321,9 @@
 Future work
 -----------
 
-Live tree support was introduced in U-Boot 2017.07. There is still quite a bit
-of work to do to flesh this out:
+Live tree support was introduced in U-Boot 2017.07. Some possible enhancements
+are:
 
-- tests for all access functions
-- more support for livetree modification
-- addition of more access functions as needed
 - support for livetree in SPL and before relocation (if desired)
+- freeing leaked memory caused by writing new nodes / property values to the
+  livetree (ofnode_write_prop())
diff --git a/doc/uImage.FIT/source_file_format.txt b/doc/uImage.FIT/source_file_format.txt
index 6870111..0a03c94 100644
--- a/doc/uImage.FIT/source_file_format.txt
+++ b/doc/uImage.FIT/source_file_format.txt
@@ -23,7 +23,7 @@
 missing: FDT is not present for legacy platforms, ramdisk is always optional.
 Additionally, old uImage format has been extended to support multi sub-images
 but the support is limited by simple format of the legacy uImage structure.
-Single binary header 'struct image_header' is not flexible enough to cover all
+Single binary header 'struct legacy_img_hdr' is not flexible enough to cover all
 possible scenarios.
 
 All those factors combined clearly show that there is a need for new, more
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 007dc6a..c9bf5de 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -400,6 +400,30 @@
 	bool
 	default y if !OF_LIVE
 
+config OFNODE_MULTI_TREE
+	bool "Allow the ofnode interface to access any tree"
+	default y if EVENT && !DM_DEV_READ_INLINE && !DM_INLINE_OFNODE
+	help
+	  Normally U-Boot makes use of its control FDT, the one used to bind
+	  devices and provide options. In some cases, U-Boot must also process
+	  a separate FDT, e.g. one provided by the operating system, which
+	  needs additions to the /chosen node.
+
+	  This works fine with live tree (OF_LIVE), but with flat tree the
+	  offset provided in ofnode is only useful with the control FDT. This
+	  option adds a 'tree ID' to the offset, so that multiple trees can
+	  be used. Call oftree_from_fdt() to register a new tree.
+
+config OFNODE_MULTI_TREE_MAX
+	int "Maximum number of FDTs"
+	range 2 8
+	depends on OFNODE_MULTI_TREE
+	default 4
+	help
+	  Sets the maximum number of device trees which can be used with the
+	  ofnode interface when using flat trees (OF_LIVE). This is only
+	  available in U-Boot proper and only after relocation.
+
 config ACPIGEN
 	bool "Support ACPI table generation in driver model"
 	default y if SANDBOX || (GENERATE_ACPI_TABLE && !QEMU)
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
index c3a50a2..91bcd1a 100644
--- a/drivers/core/fdtaddr.c
+++ b/drivers/core/fdtaddr.c
@@ -21,6 +21,8 @@
 fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index)
 {
 #if CONFIG_IS_ENABLED(OF_REAL)
+	int offset = dev_of_offset(dev);
+	int parent = dev_of_offset(dev->parent);
 	fdt_addr_t addr;
 
 	if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
@@ -28,21 +30,19 @@
 		int len = 0;
 		int na, ns;
 
-		na = fdt_address_cells(gd->fdt_blob,
-				       dev_of_offset(dev->parent));
+		na = fdt_address_cells(gd->fdt_blob, parent);
 		if (na < 1) {
 			debug("bad #address-cells\n");
 			return FDT_ADDR_T_NONE;
 		}
 
-		ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
+		ns = fdt_size_cells(gd->fdt_blob, parent);
 		if (ns < 0) {
 			debug("bad #size-cells\n");
 			return FDT_ADDR_T_NONE;
 		}
 
-		reg = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "reg",
-				  &len);
+		reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
 		if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) {
 			debug("Req index out of range\n");
 			return FDT_ADDR_T_NONE;
@@ -56,7 +56,7 @@
 			 * bus setups.
 			 */
 			addr = fdt_translate_address((void *)gd->fdt_blob,
-						     dev_of_offset(dev), reg);
+						     offset, reg);
 		} else {
 			/* Non translatable if #size-cells == 0 */
 			addr = fdt_read_number(reg, na);
@@ -66,9 +66,9 @@
 		 * Use the "simple" translate function for less complex
 		 * bus setups.
 		 */
-		addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
-				dev_of_offset(dev->parent), dev_of_offset(dev),
-				"reg", index, NULL, false);
+		addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, parent,
+							offset, "reg", index,
+							NULL, false);
 		if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) {
 			if (device_get_uclass_id(dev->parent) ==
 			    UCLASS_SIMPLE_BUS)
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index df007e6..85f7da5 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -445,14 +445,15 @@
 	return np;
 }
 
-struct device_node *of_find_node_by_phandle(phandle handle)
+struct device_node *of_find_node_by_phandle(struct device_node *root,
+					    phandle handle)
 {
 	struct device_node *np;
 
 	if (!handle)
 		return NULL;
 
-	for_each_of_allnodes(np)
+	for_each_of_allnodes_from(root, np)
 		if (np->phandle == handle)
 			break;
 	(void)of_node_get(np);
@@ -470,8 +471,7 @@
  * @len:	requested length of property value
  *
  * Return: the property value on success, -EINVAL if the property does not
- * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
- * property data isn't large enough.
+ * exist and -EOVERFLOW if the property data isn't large enough.
  */
 static void *of_find_property_value_of_size(const struct device_node *np,
 					    const char *propname, u32 len)
@@ -480,8 +480,6 @@
 
 	if (!prop)
 		return ERR_PTR(-EINVAL);
-	if (!prop->value)
-		return ERR_PTR(-ENODATA);
 	if (len > prop->length)
 		return ERR_PTR(-EOVERFLOW);
 
@@ -697,7 +695,7 @@
 			 * below.
 			 */
 			if (cells_name || cur_index == index) {
-				node = of_find_node_by_phandle(phandle);
+				node = of_find_node_by_phandle(NULL, phandle);
 				if (!node) {
 					debug("%s: could not find phandle\n",
 					      np->full_name);
@@ -946,9 +944,6 @@
 		pp_last = pp;
 	}
 
-	if (!pp_last)
-		return -ENOENT;
-
 	/* Property does not exist -> append new property */
 	new = malloc(sizeof(struct property));
 	if (!new)
@@ -964,7 +959,73 @@
 	new->length = len;
 	new->next = NULL;
 
-	pp_last->next = new;
+	if (pp_last)
+		pp_last->next = new;
+	else
+		np->properties = new;
+
+	return 0;
+}
+
+int of_add_subnode(struct device_node *parent, const char *name, int len,
+		   struct device_node **childp)
+{
+	struct device_node *child, *new, *last_sibling = NULL;
+	char *new_name, *full_name;
+	int parent_fnl;
+
+	if (len == -1)
+		len = strlen(name);
+	__for_each_child_of_node(parent, child) {
+		/*
+		 * make sure we don't use a child called "trevor" when we are
+		 * searching for "trev".
+		 */
+		if (!strncmp(child->name, name, len) && strlen(name) == len) {
+			*childp = child;
+			return -EEXIST;
+		}
+		last_sibling = child;
+	}
+
+	/* Subnode does not exist -> append new subnode */
+	new = calloc(1, sizeof(struct device_node));
+	if (!new)
+		return -ENOMEM;
+
+	new_name = memdup(name, len + 1);
+	if (!new_name) {
+		free(new);
+		return -ENOMEM;
+	}
+	new_name[len] = '\0';
+
+	/*
+	 * if the parent is the root node (named "") we don't need to prepend
+	 * its full path
+	 */
+	parent_fnl = *parent->name ? strlen(parent->full_name) : 0;
+	full_name = calloc(1, parent_fnl + 1 + len + 1);
+	if (!full_name) {
+		free(new_name);
+		free(new);
+		return -ENOMEM;
+	}
+	new->name = new_name;	/* assign to constant pointer */
+
+	strcpy(full_name, parent->full_name); /* "" for root node */
+	full_name[parent_fnl] = '/';
+	strlcpy(&full_name[parent_fnl + 1], name, len + 1);
+	new->full_name = full_name;
+
+	/* Add as last sibling of the parent */
+	if (last_sibling)
+		last_sibling->sibling = new;
+	if (!parent->child)
+		parent->child = new;
+	new->parent = parent;
+
+	*childp = new;
 
 	return 0;
 }
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 42f3c09..14bbfe7 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -4,6 +4,8 @@
  * Written by Simon Glass <sjg@chromium.org>
  */
 
+#define LOG_CATEGORY	LOGC_DT
+
 #include <common.h>
 #include <dm.h>
 #include <fdtdec.h>
@@ -18,6 +20,186 @@
 #include <linux/ioport.h>
 #include <asm/global_data.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
+static void *oftree_list[CONFIG_OFNODE_MULTI_TREE_MAX];
+static int oftree_count;
+
+void oftree_reset(void)
+{
+	if (gd->flags & GD_FLG_RELOC) {
+		oftree_count = 0;
+		oftree_list[oftree_count++] = (void *)gd->fdt_blob;
+	}
+}
+
+static int oftree_find(const void *fdt)
+{
+	int i;
+
+	for (i = 0; i < oftree_count; i++) {
+		if (fdt == oftree_list[i])
+			return i;
+	}
+
+	return -1;
+}
+
+static oftree oftree_ensure(void *fdt)
+{
+	oftree tree;
+	int i;
+
+	if (gd->flags & GD_FLG_RELOC) {
+		i = oftree_find(fdt);
+		if (i == -1) {
+			if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
+				log_warning("Too many registered device trees (max %d)\n",
+					    CONFIG_OFNODE_MULTI_TREE_MAX);
+				return oftree_null();
+			}
+
+			/* register the new tree */
+			i = oftree_count++;
+			oftree_list[i] = fdt;
+			log_debug("oftree: registered tree %d: %p\n", i, fdt);
+		}
+	} else {
+		if (fdt != gd->fdt_blob) {
+			log_debug("Cannot only access control FDT before relocation\n");
+			return oftree_null();
+		}
+	}
+
+	tree.fdt = fdt;
+
+	return tree;
+}
+
+void *ofnode_lookup_fdt(ofnode node)
+{
+	if (gd->flags & GD_FLG_RELOC) {
+		uint i = OFTREE_TREE_ID(node.of_offset);
+
+		if (i > oftree_count) {
+			log_debug("Invalid tree ID %x\n", i);
+			return NULL;
+		}
+
+		return oftree_list[i];
+	} else {
+		return (void *)gd->fdt_blob;
+	}
+}
+
+void *ofnode_to_fdt(ofnode node)
+{
+#ifdef OF_CHECKS
+	if (of_live_active())
+		return NULL;
+#endif
+	if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
+		return ofnode_lookup_fdt(node);
+
+	/* Use the control FDT by default */
+	return (void *)gd->fdt_blob;
+}
+
+/**
+ * ofnode_to_offset() - convert an ofnode to a flat DT offset
+ *
+ * This cannot be called if the reference contains a node pointer.
+ *
+ * @node: Reference containing offset (possibly invalid)
+ * Return: DT offset (can be -1)
+ */
+int ofnode_to_offset(ofnode node)
+{
+#ifdef OF_CHECKS
+	if (of_live_active())
+		return -1;
+#endif
+	if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
+		return OFTREE_OFFSET(node.of_offset);
+
+	return node.of_offset;
+}
+
+oftree oftree_from_fdt(void *fdt)
+{
+	oftree tree;
+
+	if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
+		return oftree_ensure(fdt);
+
+	tree.fdt = fdt;
+
+	return tree;
+}
+
+/**
+ * noffset_to_ofnode() - convert a DT offset to an ofnode
+ *
+ * @other_node: Node in the same tree to use as a reference
+ * @of_offset: DT offset (either valid, or -1)
+ * Return: reference to the associated DT offset
+ */
+ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
+{
+	ofnode node;
+
+	if (of_live_active())
+		node.np = NULL;
+	else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
+		 !ofnode_valid(other_node))
+		node.of_offset = of_offset;
+	else
+		node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
+						  of_offset);
+
+	return node;
+}
+
+#else /* !OFNODE_MULTI_TREE */
+
+static inline int oftree_find(const void *fdt)
+{
+	return 0;
+}
+
+#endif /* OFNODE_MULTI_TREE */
+
+/**
+ * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
+ *
+ * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
+ * containing the tree ID).
+ *
+ * If @offset is < 0 then this returns an ofnode with that offset and no tree
+ * ID.
+ *
+ * @tree: tree to check
+ * @offset: offset within that tree (can be < 0)
+ * @return node for that offset, with the correct ID
+ */
+static ofnode ofnode_from_tree_offset(oftree tree, int offset)
+{
+	ofnode node;
+
+	if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
+		int tree_id = oftree_find(tree.fdt);
+
+		if (tree_id == -1)
+			return ofnode_null();
+		node.of_offset = OFTREE_NODE(tree_id, offset);
+	} else {
+		node.of_offset = offset;
+	}
+
+	return node;
+}
+
 bool ofnode_name_eq(ofnode node, const char *name)
 {
 	const char *node_name;
@@ -119,8 +301,8 @@
 		return of_read_u32_index(ofnode_to_np(node), propname, index,
 					 outp);
 
-	cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
-			   &len);
+	cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
+			   propname, &len);
 	if (!cell) {
 		debug("(not found)\n");
 		return -EINVAL;
@@ -165,8 +347,8 @@
 	if (ofnode_is_np(node))
 		return of_read_u64(ofnode_to_np(node), propname, outp);
 
-	cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
-			   &len);
+	cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
+			   propname, &len);
 	if (!cell || len < sizeof(*cell)) {
 		debug("(not found)\n");
 		return -EINVAL;
@@ -217,7 +399,7 @@
 			len = prop->length;
 		}
 	} else {
-		val = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
+		val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
 				  propname, &len);
 	}
 	if (!val) {
@@ -268,7 +450,7 @@
 	debug("%s: %s: ", __func__, subnode_name);
 
 	if (ofnode_is_np(node)) {
-		const struct device_node *np = ofnode_to_np(node);
+		struct device_node *np = ofnode_to_np(node);
 
 		for (np = np->child; np; np = np->sibling) {
 			if (!strcmp(subnode_name, np->name))
@@ -276,9 +458,9 @@
 		}
 		subnode = np_to_ofnode(np);
 	} else {
-		int ooffset = fdt_subnode_offset(gd->fdt_blob,
+		int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
 				ofnode_to_offset(node), subnode_name);
-		subnode = offset_to_ofnode(ooffset);
+		subnode = noffset_to_ofnode(node, ooffset);
 	}
 	debug("%s\n", ofnode_valid(subnode) ?
 	      ofnode_get_name(subnode) : "<none>");
@@ -296,9 +478,20 @@
 		return of_read_u32_array(ofnode_to_np(node), propname,
 					 out_values, sz);
 	} else {
-		return fdtdec_get_int_array(gd->fdt_blob,
-					    ofnode_to_offset(node), propname,
-					    out_values, sz);
+		int ret;
+
+		ret = fdtdec_get_int_array(ofnode_to_fdt(node),
+					   ofnode_to_offset(node), propname,
+					   out_values, sz);
+
+		/* get the error right, but space is more important in SPL */
+		if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
+			if (ret == -FDT_ERR_NOTFOUND)
+				return -EINVAL;
+			else if (ret == -FDT_ERR_BADLAYOUT)
+				return -EOVERFLOW;
+		}
+		return ret;
 	}
 }
 
@@ -308,7 +501,7 @@
 	if (ofnode_is_np(node)) {
 		return of_device_is_available(ofnode_to_np(node));
 	} else {
-		return fdtdec_get_is_enabled(gd->fdt_blob,
+		return fdtdec_get_is_enabled(ofnode_to_fdt(node),
 					     ofnode_to_offset(node));
 	}
 }
@@ -319,8 +512,8 @@
 	if (ofnode_is_np(node))
 		return np_to_ofnode(node.np->child);
 
-	return offset_to_ofnode(
-		fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node)));
+	return noffset_to_ofnode(node,
+		fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
 }
 
 ofnode ofnode_next_subnode(ofnode node)
@@ -329,8 +522,8 @@
 	if (ofnode_is_np(node))
 		return np_to_ofnode(node.np->sibling);
 
-	return offset_to_ofnode(
-		fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
+	return noffset_to_ofnode(node,
+		fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
 }
 #endif /* !DM_INLINE_OFNODE */
 
@@ -342,7 +535,7 @@
 	if (ofnode_is_np(node))
 		parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
 	else
-		parent.of_offset = fdt_parent_offset(gd->fdt_blob,
+		parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
 						     ofnode_to_offset(node));
 
 	return parent;
@@ -356,9 +549,9 @@
 	}
 
 	if (ofnode_is_np(node))
-		return strrchr(node.np->full_name, '/') + 1;
+		return node.np->name;
 
-	return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
+	return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
 }
 
 int ofnode_get_path(ofnode node, char *buf, int buflen)
@@ -375,7 +568,7 @@
 	} else {
 		int res;
 
-		res = fdt_get_path(gd->fdt_blob, ofnode_to_offset(node), buf,
+		res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
 				   buflen);
 		if (!res)
 			return res;
@@ -391,7 +584,7 @@
 	ofnode node;
 
 	if (of_live_active())
-		node = np_to_ofnode(of_find_node_by_phandle(phandle));
+		node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
 	else
 		node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
 							    phandle);
@@ -399,6 +592,20 @@
 	return node;
 }
 
+ofnode oftree_get_by_phandle(oftree tree, uint phandle)
+{
+	ofnode node;
+
+	if (of_live_active())
+		node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
+	else
+		node = ofnode_from_tree_offset(tree,
+			fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
+						   phandle));
+
+	return node;
+}
+
 static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
 					       fdt_size_t *size, bool translate)
 {
@@ -431,7 +638,7 @@
 	} else {
 		na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
 		ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
-		return fdtdec_get_addr_size_fixed(gd->fdt_blob,
+		return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
 						  ofnode_to_offset(node), "reg",
 						  index, na, ns, size,
 						  translate);
@@ -479,7 +686,7 @@
 	} else {
 		int ret;
 
-		ret = fdt_stringlist_search(gd->fdt_blob,
+		ret = fdt_stringlist_search(ofnode_to_fdt(node),
 					    ofnode_to_offset(node), property,
 					    string);
 		if (ret == -FDT_ERR_NOTFOUND)
@@ -500,7 +707,8 @@
 	} else {
 		int len;
 
-		*outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node),
+		*outp = fdt_stringlist_get(ofnode_to_fdt(node),
+					   ofnode_to_offset(node),
 					   property, index, &len);
 		if (len < 0)
 			return -EINVAL;
@@ -513,7 +721,7 @@
 	if (ofnode_is_np(node)) {
 		return of_property_count_strings(ofnode_to_np(node), property);
 	} else {
-		return fdt_stringlist_count(gd->fdt_blob,
+		return fdt_stringlist_count(ofnode_to_fdt(node),
 					    ofnode_to_offset(node), property);
 	}
 }
@@ -582,7 +790,7 @@
 		struct fdtdec_phandle_args args;
 		int ret;
 
-		ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
+		ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
 						     ofnode_to_offset(node),
 						     list_name, cells_name,
 						     cell_count, index, &args);
@@ -601,7 +809,7 @@
 		return of_count_phandle_with_args(ofnode_to_np(node),
 				list_name, cells_name, cell_count);
 	else
-		return fdtdec_parse_phandle_with_args(gd->fdt_blob,
+		return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
 				ofnode_to_offset(node), list_name, cells_name,
 				cell_count, -1, NULL);
 }
@@ -614,15 +822,27 @@
 		return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
 }
 
-ofnode ofnode_path_root(oftree tree, const char *path)
+ofnode oftree_root(oftree tree)
 {
-	if (of_live_active())
+	if (of_live_active()) {
+		return np_to_ofnode(tree.np);
+	} else {
+		return ofnode_from_tree_offset(tree, 0);
+	}
+}
+
+ofnode oftree_path(oftree tree, const char *path)
+{
+	if (of_live_active()) {
 		return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
 							      NULL));
-	else if (*path != '/' && tree.fdt != gd->fdt_blob)
+	} else if (*path != '/' && tree.fdt != gd->fdt_blob) {
 		return ofnode_null();  /* Aliases only on control FDT */
-	else
-		return offset_to_ofnode(fdt_path_offset(tree.fdt, path));
+	} else {
+		int offset = fdt_path_offset(tree.fdt, path);
+
+		return ofnode_from_tree_offset(tree, offset);
+	}
 }
 
 const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
@@ -776,11 +996,11 @@
 	if (ofnode_is_np(node))
 		return of_get_property(ofnode_to_np(node), propname, lenp);
 	else
-		return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
+		return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
 				   propname, lenp);
 }
 
-int ofnode_get_first_property(ofnode node, struct ofprop *prop)
+int ofnode_first_property(ofnode node, struct ofprop *prop)
 {
 	prop->node = node;
 
@@ -790,7 +1010,7 @@
 			return -FDT_ERR_NOTFOUND;
 	} else {
 		prop->offset =
-			fdt_first_property_offset(gd->fdt_blob,
+			fdt_first_property_offset(ofnode_to_fdt(node),
 						  ofnode_to_offset(prop->node));
 		if (prop->offset < 0)
 			return prop->offset;
@@ -799,7 +1019,7 @@
 	return 0;
 }
 
-int ofnode_get_next_property(struct ofprop *prop)
+int ofnode_next_property(struct ofprop *prop)
 {
 	if (ofnode_is_np(prop->node)) {
 		prop->prop = of_get_next_property(ofnode_to_np(prop->node),
@@ -807,8 +1027,9 @@
 		if (!prop->prop)
 			return -FDT_ERR_NOTFOUND;
 	} else {
-		prop->offset = fdt_next_property_offset(gd->fdt_blob,
-							prop->offset);
+		prop->offset =
+			fdt_next_property_offset(ofnode_to_fdt(prop->node),
+						 prop->offset);
 		if (prop->offset  < 0)
 			return prop->offset;
 	}
@@ -816,27 +1037,18 @@
 	return 0;
 }
 
-const void *ofnode_get_property_by_prop(const struct ofprop *prop,
-					const char **propname, int *lenp)
+const void *ofprop_get_property(const struct ofprop *prop,
+				const char **propname, int *lenp)
 {
 	if (ofnode_is_np(prop->node))
 		return of_get_property_by_prop(ofnode_to_np(prop->node),
 					       prop->prop, propname, lenp);
 	else
-		return fdt_getprop_by_offset(gd->fdt_blob,
+		return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
 					     prop->offset,
 					     propname, lenp);
 }
 
-bool ofnode_is_available(ofnode node)
-{
-	if (ofnode_is_np(node))
-		return of_device_is_available(ofnode_to_np(node));
-	else
-		return fdtdec_get_is_enabled(gd->fdt_blob,
-					     ofnode_to_offset(node));
-}
-
 fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
 				fdt_size_t *sizep)
 {
@@ -857,7 +1069,7 @@
 		else
 			return of_read_number(prop, na);
 	} else {
-		return fdtdec_get_addr_size(gd->fdt_blob,
+		return fdtdec_get_addr_size(ofnode_to_fdt(node),
 					    ofnode_to_offset(node), property,
 					    sizep);
 	}
@@ -876,7 +1088,7 @@
 		return (uint8_t *)prop;
 
 	} else {
-		return fdtdec_locate_byte_array(gd->fdt_blob,
+		return fdtdec_locate_byte_array(ofnode_to_fdt(node),
 				ofnode_to_offset(node), propname, sz);
 	}
 }
@@ -1012,10 +1224,10 @@
 	if (ofnode_is_np(node)) {
 		return of_n_addr_cells(ofnode_to_np(node));
 	} else {
-		int parent = fdt_parent_offset(gd->fdt_blob,
+		int parent = fdt_parent_offset(ofnode_to_fdt(node),
 					       ofnode_to_offset(node));
 
-		return fdt_address_cells(gd->fdt_blob, parent);
+		return fdt_address_cells(ofnode_to_fdt(node), parent);
 	}
 }
 
@@ -1024,10 +1236,10 @@
 	if (ofnode_is_np(node)) {
 		return of_n_size_cells(ofnode_to_np(node));
 	} else {
-		int parent = fdt_parent_offset(gd->fdt_blob,
+		int parent = fdt_parent_offset(ofnode_to_fdt(node),
 					       ofnode_to_offset(node));
 
-		return fdt_size_cells(gd->fdt_blob, parent);
+		return fdt_size_cells(ofnode_to_fdt(node), parent);
 	}
 }
 
@@ -1036,7 +1248,8 @@
 	if (ofnode_is_np(node))
 		return of_simple_addr_cells(ofnode_to_np(node));
 	else
-		return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
+		return fdt_address_cells(ofnode_to_fdt(node),
+					 ofnode_to_offset(node));
 }
 
 int ofnode_read_simple_size_cells(ofnode node)
@@ -1044,7 +1257,8 @@
 	if (ofnode_is_np(node))
 		return of_simple_size_cells(ofnode_to_np(node));
 	else
-		return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
+		return fdt_size_cells(ofnode_to_fdt(node),
+				      ofnode_to_offset(node));
 }
 
 bool ofnode_pre_reloc(ofnode node)
@@ -1081,7 +1295,8 @@
 		struct fdt_resource fres;
 		int ret;
 
-		ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node),
+		ret = fdt_get_resource(ofnode_to_fdt(node),
+				       ofnode_to_offset(node),
 				       "reg", index, &fres);
 		if (ret < 0)
 			return -EINVAL;
@@ -1110,7 +1325,8 @@
 	if (ofnode_is_np(node))
 		return of_translate_address(ofnode_to_np(node), in_addr);
 	else
-		return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
+		return fdt_translate_address(ofnode_to_fdt(node),
+					     ofnode_to_offset(node), in_addr);
 }
 
 u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
@@ -1118,7 +1334,8 @@
 	if (ofnode_is_np(node))
 		return of_translate_dma_address(ofnode_to_np(node), in_addr);
 	else
-		return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
+		return fdt_translate_dma_address(ofnode_to_fdt(node),
+						 ofnode_to_offset(node), in_addr);
 }
 
 int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
@@ -1126,7 +1343,8 @@
 	if (ofnode_is_np(node))
 		return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
 	else
-		return fdt_get_dma_range(gd->fdt_blob, ofnode_to_offset(node),
+		return fdt_get_dma_range(ofnode_to_fdt(node),
+					 ofnode_to_offset(node),
 					 cpu, bus, size);
 }
 
@@ -1136,7 +1354,7 @@
 		return of_device_is_compatible(ofnode_to_np(node), compat,
 					       NULL, NULL);
 	else
-		return !fdt_node_check_compatible(gd->fdt_blob,
+		return !fdt_node_check_compatible(ofnode_to_fdt(node),
 						  ofnode_to_offset(node),
 						  compat);
 }
@@ -1148,8 +1366,9 @@
 			(struct device_node *)ofnode_to_np(from), NULL,
 			compat));
 	} else {
-		return offset_to_ofnode(fdt_node_offset_by_compatible(
-				gd->fdt_blob, ofnode_to_offset(from), compat));
+		return noffset_to_ofnode(from,
+			fdt_node_offset_by_compatible(ofnode_to_fdt(from),
+					ofnode_to_offset(from), compat));
 	}
 }
 
@@ -1161,22 +1380,35 @@
 			(struct device_node *)ofnode_to_np(from), propname,
 			propval, proplen));
 	} else {
-		return offset_to_ofnode(fdt_node_offset_by_prop_value(
-				gd->fdt_blob, ofnode_to_offset(from),
-				propname, propval, proplen));
+		return noffset_to_ofnode(from,
+			 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
+				ofnode_to_offset(from), propname, propval,
+				proplen));
 	}
 }
 
 int ofnode_write_prop(ofnode node, const char *propname, const void *value,
-		      int len)
+		      int len, bool copy)
 {
-	if (of_live_active())
-		return of_write_prop(ofnode_to_npw(node), propname, len, value);
-	else
-		return fdt_setprop((void *)gd->fdt_blob, ofnode_to_offset(node),
-				   propname, value, len);
+	if (of_live_active()) {
+		void *newval;
+		int ret;
 
-	return 0;
+		if (copy) {
+			newval = malloc(len);
+			if (!newval)
+				return log_ret(-ENOMEM);
+			memcpy(newval, value, len);
+			value = newval;
+		}
+		ret = of_write_prop(ofnode_to_np(node), propname, len, value);
+		if (ret && copy)
+			free(newval);
+		return ret;
+	} else {
+		return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
+				   propname, value, len);
+	}
 }
 
 int ofnode_write_string(ofnode node, const char *propname, const char *value)
@@ -1185,7 +1417,8 @@
 
 	debug("%s: %s = %s", __func__, propname, value);
 
-	return ofnode_write_prop(node, propname, value, strlen(value) + 1);
+	return ofnode_write_prop(node, propname, value, strlen(value) + 1,
+				 false);
 }
 
 int ofnode_write_u32(ofnode node, const char *propname, u32 value)
@@ -1200,7 +1433,7 @@
 		return -ENOMEM;
 	*val = cpu_to_fdt32(value);
 
-	return ofnode_write_prop(node, propname, val, sizeof(value));
+	return ofnode_write_prop(node, propname, val, sizeof(value), false);
 }
 
 int ofnode_set_enabled(ofnode node, bool value)
@@ -1289,3 +1522,62 @@
 
 	return PHY_INTERFACE_MODE_NA;
 }
+
+int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
+{
+	ofnode subnode;
+	int ret = 0;
+
+	assert(ofnode_valid(node));
+
+	if (ofnode_is_np(node)) {
+		struct device_node *np, *child;
+
+		np = (struct device_node *)ofnode_to_np(node);
+		ret = of_add_subnode(np, name, -1, &child);
+		if (ret && ret != -EEXIST)
+			return ret;
+		subnode = np_to_ofnode(child);
+	} else {
+		void *fdt = ofnode_to_fdt(node);
+		int poffset = ofnode_to_offset(node);
+		int offset;
+
+		offset = fdt_add_subnode(fdt, poffset, name);
+		if (offset == -FDT_ERR_EXISTS) {
+			offset = fdt_subnode_offset(fdt, poffset, name);
+			ret = -EEXIST;
+		}
+		if (offset < 0)
+			return -EINVAL;
+		subnode = noffset_to_ofnode(node, offset);
+	}
+
+	*subnodep = subnode;
+
+	return ret;	/* 0 or -EEXIST */
+}
+
+int ofnode_copy_props(ofnode src, ofnode dst)
+{
+	struct ofprop prop;
+
+	ofnode_for_each_prop(prop, src) {
+		const char *name;
+		const char *val;
+		int len, ret;
+
+		val = ofprop_get_property(&prop, &name, &len);
+		if (!val) {
+			log_debug("Cannot read prop (err=%d)\n", len);
+			return log_msg_ret("get", -EINVAL);
+		}
+		ret = ofnode_write_prop(dst, name, val, len, true);
+		if (ret) {
+			log_debug("Cannot write prop (err=%d)\n", ret);
+			return log_msg_ret("wr", -EINVAL);
+		}
+	}
+
+	return 0;
+}
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 07ab8ab..3e5fea8 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -287,18 +287,18 @@
 
 int dev_read_first_prop(const struct udevice *dev, struct ofprop *prop)
 {
-	return ofnode_get_first_property(dev_ofnode(dev), prop);
+	return ofnode_first_property(dev_ofnode(dev), prop);
 }
 
 int dev_read_next_prop(struct ofprop *prop)
 {
-	return ofnode_get_next_property(prop);
+	return ofnode_next_property(prop);
 }
 
 const void *dev_read_prop_by_prop(struct ofprop *prop,
 				  const char **propname, int *lenp)
 {
-	return ofnode_get_property_by_prop(prop, propname, lenp);
+	return ofprop_get_property(prop, propname, lenp);
 }
 
 int dev_read_alias_seq(const struct udevice *dev, int *devnump)
diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c
index abddbef..b8eb2d2 100644
--- a/drivers/cpu/imx8_cpu.c
+++ b/drivers/cpu/imx8_cpu.c
@@ -144,7 +144,7 @@
 	ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
 		const char *device_type;
 
-		if (!ofnode_is_available(node))
+		if (!ofnode_is_enabled(node))
 			continue;
 
 		device_type = ofnode_read_string(node, "device_type");
diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c
index b30dceb..d6484d7 100644
--- a/drivers/cpu/riscv_cpu.c
+++ b/drivers/cpu/riscv_cpu.c
@@ -77,7 +77,7 @@
 		const char *device_type;
 
 		/* skip if hart is marked as not available in the device tree */
-		if (!ofnode_is_available(node))
+		if (!ofnode_is_enabled(node))
 			continue;
 
 		device_type = ofnode_read_string(node, "device_type");
diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c
index acd2992..8c0fb27 100644
--- a/drivers/crypto/fsl/jr.c
+++ b/drivers/crypto/fsl/jr.c
@@ -853,7 +853,7 @@
 
 	/* Check for enabled job ring node */
 	ofnode_for_each_subnode(node, dev_ofnode(dev)) {
-		if (!ofnode_is_available(node))
+		if (!ofnode_is_enabled(node))
 			continue;
 
 		jr_node = ofnode_read_u32_default(node, "reg", -1);
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 2b6211c..c3f3d1f 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -65,7 +65,7 @@
 		struct driver *drv = NULL;
 		u32 protocol_id;
 
-		if (!ofnode_is_available(node))
+		if (!ofnode_is_enabled(node))
 			continue;
 
 		if (ofnode_read_u32(node, "reg", &protocol_id))
diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c
index e86e3b7..3b785e6 100644
--- a/drivers/fpga/socfpga_arria10.c
+++ b/drivers/fpga/socfpga_arria10.c
@@ -555,14 +555,14 @@
 	/* Load image header into buffer */
 	ret = request_firmware_into_buf(dev,
 					fpga_loadfs->fpga_fsinfo->filename,
-					buffer_p, sizeof(struct image_header),
+					buffer_p, sizeof(struct legacy_img_hdr),
 					0);
 	if (ret < 0) {
 		debug("FPGA: Failed to read image header from flash.\n");
 		return -ENOENT;
 	}
 
-	if (image_get_magic((struct image_header *)buffer_p) != FDT_MAGIC) {
+	if (image_get_magic((struct legacy_img_hdr *)buffer_p) != FDT_MAGIC) {
 		debug("FPGA: No FDT magic was found.\n");
 		return -EBADF;
 	}
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 56aa58b..4886392 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -895,7 +895,7 @@
 	else
 		parts = ofnode_find_subnode(master->flash_node, "partitions");
 
-	if (!ofnode_valid(parts) || !ofnode_is_available(parts) ||
+	if (!ofnode_valid(parts) || !ofnode_is_enabled(parts) ||
 	    !ofnode_device_is_compatible(parts, "fixed-partitions"))
 		return 0;
 
@@ -905,7 +905,7 @@
 		fdt_addr_t offset;
 		fdt_size_t size;
 
-		if (!ofnode_is_available(child))
+		if (!ofnode_is_enabled(child))
 			continue;
 
 		offset = ofnode_get_addr_size_index_notrans(child, 0, &size);
diff --git a/drivers/mtd/nand/raw/zynq_nand.c b/drivers/mtd/nand/raw/zynq_nand.c
index 10e9cd1..14cb2ba 100644
--- a/drivers/mtd/nand/raw/zynq_nand.c
+++ b/drivers/mtd/nand/raw/zynq_nand.c
@@ -1095,7 +1095,7 @@
 		}
 	}
 
-	if (!ofnode_is_available(of_nand)) {
+	if (!ofnode_is_enabled(of_nand)) {
 		debug("Nand node in dt disabled\n");
 		return dm_scan_fdt_dev(dev);
 	}
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index 8bc2b46..bbc4434 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -1078,7 +1078,7 @@
 		return ret;
 	}
 
-	if (!ofnode_is_available(phandle_args.node))
+	if (!ofnode_is_enabled(phandle_args.node))
 		return -ENOENT;
 
 	priv->phy_of_node = phandle_args.node;
diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
index d43a85b..1fd5089 100644
--- a/drivers/net/fsl_enetc.c
+++ b/drivers/net/fsl_enetc.c
@@ -323,7 +323,7 @@
 	struct enetc_priv *priv = dev_get_priv(dev);
 	int res;
 
-	if (ofnode_valid(dev_ofnode(dev)) && !ofnode_is_available(dev_ofnode(dev))) {
+	if (ofnode_valid(dev_ofnode(dev)) && !ofnode_is_enabled(dev_ofnode(dev))) {
 		enetc_dbg(dev, "interface disabled\n");
 		return -ENODEV;
 	}
diff --git a/drivers/net/mscc_eswitch/felix_switch.c b/drivers/net/mscc_eswitch/felix_switch.c
index 709c9e3..2e5f45e 100644
--- a/drivers/net/mscc_eswitch/felix_switch.c
+++ b/drivers/net/mscc_eswitch/felix_switch.c
@@ -287,7 +287,7 @@
 	int err;
 
 	if (ofnode_valid(dev_ofnode(dev)) &&
-	    !ofnode_is_available(dev_ofnode(dev))) {
+	    !ofnode_is_enabled(dev_ofnode(dev))) {
 		dev_dbg(dev, "switch disabled\n");
 		return -ENODEV;
 	}
diff --git a/drivers/net/sja1105.c b/drivers/net/sja1105.c
index 4ca8709..48f044c 100644
--- a/drivers/net/sja1105.c
+++ b/drivers/net/sja1105.c
@@ -3316,7 +3316,7 @@
 	int rc;
 
 	if (ofnode_valid(dev_ofnode(dev)) &&
-	    !ofnode_is_available(dev_ofnode(dev))) {
+	    !ofnode_is_enabled(dev_ofnode(dev))) {
 		dev_dbg(dev, "switch disabled\n");
 		return -ENODEV;
 	}
diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c
index 9580fa3..b79e062 100644
--- a/drivers/net/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ti/am65-cpsw-nuss.c
@@ -719,7 +719,7 @@
 
 		node_name = ofnode_get_name(node);
 
-		disabled = !ofnode_is_available(node);
+		disabled = !ofnode_is_enabled(node);
 
 		ret = ofnode_read_u32(node, "reg", &port_id);
 		if (ret) {
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 16a6a69..058b2f6 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -766,7 +766,7 @@
 	if (ofnode_valid(dev_ofnode(parent)))
 		pci_dev_find_ofnode(parent, bdf, &node);
 
-	if (ofnode_valid(node) && !ofnode_is_available(node)) {
+	if (ofnode_valid(node) && !ofnode_is_enabled(node)) {
 		debug("%s: Ignoring disabled device\n", __func__);
 		return log_msg_ret("dis", -EPERM);
 	}
diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
index 5bd340a..93a7508 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -740,7 +740,7 @@
 
 	/* First phase: Fill mvebu_pcie struct for each port */
 	ofnode_for_each_subnode(subnode, dev_ofnode(parent)) {
-		if (!ofnode_is_available(subnode))
+		if (!ofnode_is_enabled(subnode))
 			continue;
 
 		pcie = calloc(1, sizeof(*pcie));
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
index bc489d5..29d5411 100644
--- a/drivers/pci/pci_tegra.c
+++ b/drivers/pci/pci_tegra.c
@@ -531,7 +531,7 @@
 
 		lanes |= num_lanes << (index << 3);
 
-		if (!ofnode_is_available(subnode))
+		if (!ofnode_is_enabled(subnode))
 			continue;
 
 		port = malloc(sizeof(*port));
diff --git a/drivers/pci/pcie_mediatek.c b/drivers/pci/pcie_mediatek.c
index 051a3bc..c6e30e2 100644
--- a/drivers/pci/pcie_mediatek.c
+++ b/drivers/pci/pcie_mediatek.c
@@ -657,7 +657,7 @@
 		struct fdt_pci_addr addr;
 		u32 slot = 0;
 
-		if (!ofnode_is_available(subnode))
+		if (!ofnode_is_enabled(subnode))
 			continue;
 
 		err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
@@ -696,7 +696,7 @@
 	pcie->priv = dev;
 
 	dev_for_each_subnode(subnode, dev) {
-		if (!ofnode_is_available(subnode))
+		if (!ofnode_is_enabled(subnode))
 			continue;
 
 		err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
diff --git a/drivers/power/pmic/sandbox.c b/drivers/power/pmic/sandbox.c
index d787091..acfeae2 100644
--- a/drivers/power/pmic/sandbox.c
+++ b/drivers/power/pmic/sandbox.c
@@ -4,11 +4,14 @@
  *  Przemyslaw Marczak  <p.marczak@samsung.com>
  */
 
+#define LOG_CATEGORY	UCLASS_PMIC
+
 #include <common.h>
 #include <fdtdec.h>
 #include <errno.h>
 #include <dm.h>
 #include <i2c.h>
+#include <log.h>
 #include <power/pmic.h>
 #include <power/regulator.h>
 #include <power/sandbox_pmic.h>
@@ -28,7 +31,7 @@
 			      const uint8_t *buff, int len)
 {
 	if (dm_i2c_write(dev, reg, buff, len)) {
-		pr_err("write error to device: %p register: %#x!\n", dev, reg);
+		log_err("write error to device: %p register: %#x!\n", dev, reg);
 		return -EIO;
 	}
 
@@ -39,7 +42,7 @@
 			     uint8_t *buff, int len)
 {
 	if (dm_i2c_read(dev, reg, buff, len)) {
-		pr_err("read error from device: %p register: %#x!\n", dev, reg);
+		log_err("read error from device: %p register: %#x!\n", dev, reg);
 		return -EIO;
 	}
 
@@ -49,8 +52,7 @@
 static int sandbox_pmic_bind(struct udevice *dev)
 {
 	if (!pmic_bind_children(dev, dev_ofnode(dev), pmic_children_info))
-		pr_err("%s:%d PMIC: %s - no child found!", __func__, __LINE__,
-							  dev->name);
+		log_err("PMIC: %s - no child found!\n", dev->name);
 
 	/* Always return success for this device - allows for PMIC I/O */
 	return 0;
diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c
index 74548ab..af4b167 100644
--- a/drivers/usb/gadget/f_sdp.c
+++ b/drivers/usb/gadget/f_sdp.c
@@ -835,7 +835,7 @@
 
 			printf("Found header at 0x%08x\n", sdp_func->jmp_address);
 
-			image_header_t *header =
+			struct legacy_img_hdr *header =
 				sdp_ptr(sdp_func->jmp_address);
 #ifdef CONFIG_SPL_LOAD_FIT
 			if (image_get_magic(header) == FDT_MAGIC) {
diff --git a/env/common.c b/env/common.c
index 8dd05ff..8beb8e6 100644
--- a/env/common.c
+++ b/env/common.c
@@ -539,12 +539,12 @@
 		return;
 	}
 
-	for (res = ofnode_get_first_property(node, &prop);
+	for (res = ofnode_first_property(node, &prop);
 	     !res;
-	     res = ofnode_get_next_property(&prop)) {
+	     res = ofnode_next_property(&prop)) {
 		const char *name, *val;
 
-		val = ofnode_get_property_by_prop(&prop, &name, NULL);
+		val = ofprop_get_property(&prop, &name, NULL);
 		env_set(name, val);
 	}
 }
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 4aeb61f..2d55fe2 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -646,6 +646,10 @@
 	 * @GD_FLG_SMP_READY: SMP initialization is complete
 	 */
 	GD_FLG_SMP_READY = 0x80000,
+	/**
+	 * @GD_FLG_FDT_CHANGED: Device tree change has been detected by tests
+	 */
+	GD_FLG_FDT_CHANGED = 0x100000,
 };
 
 #endif /* __ASSEMBLY__ */
diff --git a/include/bootm.h b/include/bootm.h
index 7ed5650..044a479 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -33,7 +33,7 @@
  * not return.
  */
 typedef int boot_os_fn(int flag, int argc, char *const argv[],
-			bootm_headers_t *images);
+			struct bootm_headers *images);
 
 extern boot_os_fn do_bootm_linux;
 extern boot_os_fn do_bootm_vxworks;
@@ -47,7 +47,7 @@
 #endif
 
 int boot_selected_os(int argc, char *const argv[], int state,
-		     bootm_headers_t *images, boot_os_fn *boot_fn);
+		     struct bootm_headers *images, boot_os_fn *boot_fn);
 
 ulong bootm_disable_interrupts(void);
 
@@ -56,7 +56,7 @@
 		      ulong size);
 
 int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
-		    char *const argv[], int states, bootm_headers_t *images,
+		    char *const argv[], int states, struct bootm_headers *images,
 		    int boot_progress);
 
 void arch_preboot_os(void);
diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h
index 15ae084..d9e95ab 100644
--- a/include/configs/uniphier.h
+++ b/include/configs/uniphier.h
@@ -169,7 +169,7 @@
 
 /* only for SPL */
 
-/* subtract sizeof(struct image_header) */
+/* subtract sizeof(struct legacy_img_hdr) */
 #define CONFIG_SYS_UBOOT_BASE			(0x130000 - 0x40)
 
 #endif /* __CONFIG_UNIPHIER_H__ */
diff --git a/include/dm/device.h b/include/dm/device.h
index 12c6ba3..f3f953c 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -253,7 +253,7 @@
  * @dev:	device to check
  * Return: reference of the device's DT node
  */
-static inline ofnode dev_ofnode(const struct udevice *dev)
+static inline __attribute_const__ ofnode dev_ofnode(const struct udevice *dev)
 {
 #if CONFIG_IS_ENABLED(OF_REAL)
 	return dev->node_;
@@ -273,7 +273,7 @@
 #define dev_get_dma_offset(_dev)		0
 #endif
 
-static inline int dev_of_offset(const struct udevice *dev)
+static inline __attribute_const__ int dev_of_offset(const struct udevice *dev)
 {
 #if CONFIG_IS_ENABLED(OF_REAL)
 	return ofnode_to_offset(dev_ofnode(dev));
@@ -282,7 +282,7 @@
 #endif
 }
 
-static inline bool dev_has_ofnode(const struct udevice *dev)
+static inline __attribute_const__ bool dev_has_ofnode(const struct udevice *dev)
 {
 #if CONFIG_IS_ENABLED(OF_REAL)
 	return ofnode_valid(dev_ofnode(dev));
diff --git a/include/dm/of.h b/include/dm/of.h
index 9c9065b..fce7cef 100644
--- a/include/dm/of.h
+++ b/include/dm/of.h
@@ -31,10 +31,21 @@
 /**
  * struct device_node: Device tree node
  *
- * @name: Node name
+ * The top of this tree is typically gd->of_root which points to the root node.
+ *
+ * The head of the list of children for the root node (and any other node) is
+ * in @child, with @sibling providing a link to the next child.
+ *
+ * Each child has a pointer to its parent in @parent.
+ *
+ * A node may have properties in which case the head of the list of properties
+ * @properties pointers to the first one, with struct property->@next pointing
+ * to the next one.
+ *
+ * @name: Node name, "" for the root node
  * @type: Node type (value of device_type property) or "<NULL>" if none
  * @phandle: Phandle value of this none, or 0 if none
- * @full_name: Full path to node, e.g. "/bus@1/spi@1100"
+ * @full_name: Full path to node, e.g. "/bus@1/spi@1100" ("/" for the root node)
  * @properties: Pointer to head of list of properties, or NULL if none
  * @parent: Pointer to parent node, or NULL if this is the root node
  * @child: Pointer to head of child node list, or NULL if no children
diff --git a/include/dm/of_access.h b/include/dm/of_access.h
index 83f34f0..c556a18 100644
--- a/include/dm/of_access.h
+++ b/include/dm/of_access.h
@@ -258,11 +258,13 @@
 /**
  * of_find_node_by_phandle() - Find a node given a phandle
  *
+ * @root:	root node to start from (NULL for default device tree)
  * @handle:	phandle of the node to find
  *
  * Return: node pointer, or NULL if not found
  */
-struct device_node *of_find_node_by_phandle(phandle handle);
+struct device_node *of_find_node_by_phandle(struct device_node *root,
+					    phandle handle);
 
 /**
  * of_read_u8() - Find and read a 8-bit integer from a property
@@ -325,8 +327,7 @@
  * @outp:	pointer to return value, modified only if return value is 0.
  *
  * Return:
- *   0 on success, -EINVAL if the property does not exist,
- *   -ENODATA if property does not have a value, and -EOVERFLOW if the
+ *   0 on success, -EINVAL if the property does not exist, or -EOVERFLOW if the
  *   property data isn't large enough.
  */
 int of_read_u32_index(const struct device_node *np, const char *propname,
@@ -343,8 +344,7 @@
  * @outp:	pointer to return value, modified only if return value is 0.
  *
  * Return:
- *   0 on success, -EINVAL if the property does not exist,
- *   -ENODATA if property does not have a value, and -EOVERFLOW if the
+ *   0 on success, -EINVAL if the property does not exist, or -EOVERFLOW if the
  *   property data isn't large enough.
  */
 int of_read_u64(const struct device_node *np, const char *propname, u64 *outp);
@@ -360,8 +360,8 @@
  * @out_values:	pointer to return value, modified only if return value is 0.
  * @sz:		number of array elements to read
  * Return:
- *   0 on success, -EINVAL if the property does not exist, -ENODATA
- *   if property does not have a value, and -EOVERFLOW is longer than sz.
+ *   0 on success, -EINVAL if the property does not exist, or -EOVERFLOW if
+ *   longer than sz.
  */
 int of_read_u32_array(const struct device_node *np, const char *propname,
 		      u32 *out_values, size_t sz);
@@ -563,4 +563,19 @@
 int of_write_prop(struct device_node *np, const char *propname, int len,
 		  const void *value);
 
+/**
+ * of_add_subnode() - add a new subnode to a node
+ *
+ * @node:	parent node to add to
+ * @name:	name of subnode
+ * @len:	length of name (so the caller does not need to nul-terminate a
+ *	partial string), or -1 for strlen(@name)
+ * @subnodep:	returns pointer to new subnode (valid if the function returns 0
+ *	or -EEXIST)
+ * Returns 0 if OK, -EEXIST if already exists, -ENOMEM if out of memory, other
+ * -ve on other error
+ */
+int of_add_subnode(struct device_node *node, const char *name, int len,
+		   struct device_node **subnodep);
+
 #endif
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index f608523..7aae2c2 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -27,40 +27,24 @@
 	uint32_t args[OF_MAX_PHANDLE_ARGS];
 };
 
+#if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
 /**
- * ofnode_to_np() - convert an ofnode to a live DT node pointer
+ * oftree_reset() - reset the state of the oftree list
  *
- * This cannot be called if the reference contains an offset.
- *
- * @node: Reference containing struct device_node * (possibly invalid)
- * Return: pointer to device node (can be NULL)
+ * Reset the oftree list so it can be started again. This should be called
+ * once the control FDT is in place, but before the ofnode interface is used.
  */
-static inline const struct device_node *ofnode_to_np(ofnode node)
-{
-#ifdef OF_CHECKS
-	if (!of_live_active())
-		return NULL;
-#endif
-	return node.np;
-}
+void oftree_reset(void);
 
 /**
- * ofnode_to_npw() - convert an ofnode to a writeable live DT node pointer
+ * ofnode_to_fdt() - convert an ofnode to a flat DT pointer
  *
- * This cannot be called if the reference contains an offset.
+ * This cannot be called if the reference contains a node pointer.
  *
- * @node: Reference containing struct device_node * (possibly invalid)
- * Return: pointer to device node (can be NULL)
+ * @node: Reference containing offset (possibly invalid)
+ * Return: DT offset (can be NULL)
  */
-static inline struct device_node *ofnode_to_npw(ofnode node)
-{
-#ifdef OF_CHECKS
-	if (!of_live_active())
-		return NULL;
-#endif
-	/* Drop constant */
-	return (struct device_node *)node.np;
-}
+__attribute_const__ void *ofnode_to_fdt(ofnode node);
 
 /**
  * ofnode_to_offset() - convert an ofnode to a flat DT offset
@@ -70,7 +54,40 @@
  * @node: Reference containing offset (possibly invalid)
  * Return: DT offset (can be -1)
  */
-static inline int ofnode_to_offset(ofnode node)
+__attribute_const__ int ofnode_to_offset(ofnode node);
+
+/**
+ * oftree_from_fdt() - Returns an oftree from a flat device tree pointer
+ *
+ * @fdt: Device tree to use
+ *
+ * Returns: reference to the given node
+ */
+oftree oftree_from_fdt(void *fdt);
+
+/**
+ * noffset_to_ofnode() - convert a DT offset to an ofnode
+ *
+ * @other_node: Node in the same tree to use as a reference
+ * @of_offset: DT offset (either valid, or -1)
+ * Return: reference to the associated DT offset
+ */
+ofnode noffset_to_ofnode(ofnode other_node, int of_offset);
+
+#else /* !OFNODE_MULTI_TREE */
+static inline void oftree_reset(void) {}
+
+static inline void *ofnode_to_fdt(ofnode node)
+{
+#ifdef OF_CHECKS
+	if (of_live_active())
+		return NULL;
+#endif
+	/* Use the control FDT by default */
+	return (void *)gd->fdt_blob;
+}
+
+static inline __attribute_const__ int ofnode_to_offset(ofnode node)
 {
 #ifdef OF_CHECKS
 	if (of_live_active())
@@ -79,11 +96,55 @@
 	return node.of_offset;
 }
 
+static inline oftree oftree_from_fdt(void *fdt)
+{
+	oftree tree;
+
+	/* we cannot access other trees without OFNODE_MULTI_TREE */
+	if (fdt == gd->fdt_blob)
+		tree.fdt = fdt;
+	else
+		tree.fdt = NULL;
+
+	return tree;
+}
+
+static inline ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
+{
+	ofnode node;
+
+	if (of_live_active())
+		node.np = NULL;
+	else
+		node.of_offset = of_offset;
+
+	return node;
+}
+
+#endif /* OFNODE_MULTI_TREE */
+
+/**
+ * ofnode_to_np() - convert an ofnode to a live DT node pointer
+ *
+ * This cannot be called if the reference contains an offset.
+ *
+ * @node: Reference containing struct device_node * (possibly invalid)
+ * Return: pointer to device node (can be NULL)
+ */
+static inline struct device_node *ofnode_to_np(ofnode node)
+{
+#ifdef OF_CHECKS
+	if (!of_live_active())
+		return NULL;
+#endif
+	return node.np;
+}
+
 /**
  * ofnode_valid() - check if an ofnode is valid
  *
  * @node: Reference containing offset (possibly invalid)
- * Return: true if the reference contains a valid ofnode, false if it is NULL
+ * Return: true if the reference contains a valid ofnode, false if not
  */
 static inline bool ofnode_valid(ofnode node)
 {
@@ -94,6 +155,22 @@
 }
 
 /**
+ * oftree_lookup_fdt() - obtain the FDT pointer from an oftree
+ *
+ * This can only be called when flat tree is enabled
+ *
+ * @tree: Tree to look at
+ * @return FDT pointer from the tree
+ */
+static inline void *oftree_lookup_fdt(oftree tree)
+{
+	if (of_live_active())
+		return NULL;
+	else
+		return tree.fdt;
+}
+
+/**
  * offset_to_ofnode() - convert a DT offset to an ofnode
  *
  * @of_offset: DT offset (either valid, or -1)
@@ -117,7 +194,7 @@
  * @np: Live node pointer (can be NULL)
  * Return: reference to the associated node pointer
  */
-static inline ofnode np_to_ofnode(const struct device_node *np)
+static inline ofnode np_to_ofnode(struct device_node *np)
 {
 	ofnode node;
 
@@ -165,6 +242,38 @@
 }
 
 /**
+ * oftree_valid() - check if an oftree is valid
+ *
+ * @tree: Reference containing oftree
+ * Return: true if the reference contains a valid oftree, false if node
+ */
+static inline bool oftree_valid(oftree tree)
+{
+	if (of_live_active())
+		return tree.np;
+	else
+		return tree.fdt;
+}
+
+/**
+ * oftree_null() - Obtain a null oftree
+ *
+ * This returns an oftree which points to no tree. It works both with the flat
+ * tree and livetree.
+ */
+static inline oftree oftree_null(void)
+{
+	oftree tree;
+
+	if (of_live_active())
+		tree.np = NULL;
+	else
+		tree.fdt = NULL;
+
+	return tree;
+}
+
+/**
  * ofnode_null() - Obtain a null ofnode
  *
  * This returns an ofnode which points to no node. It works both with the flat
@@ -195,6 +304,20 @@
 }
 
 /**
+ * ofprop_valid() - check if an ofprop is valid
+ *
+ * @prop: Pointer to ofprop to check
+ * Return: true if the reference contains a valid ofprop, false if not
+ */
+static inline bool ofprop_valid(struct ofprop *prop)
+{
+	if (of_live_active())
+		return prop->prop;
+	else
+		return prop->offset >= 0;
+}
+
+/**
  * oftree_default() - Returns the default device tree (U-Boot's control FDT)
  *
  * Returns: reference to the control FDT
@@ -212,6 +335,21 @@
 }
 
 /**
+ * oftree_from_np() - Returns an oftree from a node pointer
+ *
+ * @root: Root node of the tree
+ * Returns: reference to the given node
+ */
+static inline oftree oftree_from_np(struct device_node *root)
+{
+	oftree tree;
+
+	tree.np = root;
+
+	return tree;
+}
+
+/**
  * ofnode_name_eq() - Check if the node name is equivalent to a given name
  *                    ignoring the unit address
  *
@@ -377,12 +515,12 @@
  * @propname:	name of the property to read
  * @out_values:	pointer to return value, modified only if return value is 0
  * @sz:		number of array elements to read
- * Return: 0 if OK, -ve on error
+ * Return: 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough
  *
  * Search for a property in a device node and read 32-bit value(s) from
- * it. Returns 0 on success, -EINVAL if the property does not exist,
- * -ENODATA if property does not have a value, and -EOVERFLOW if the
- * property data isn't large enough.
+ * it.
  *
  * The out_values is modified only if a valid u32 value can be decoded.
  */
@@ -484,7 +622,7 @@
  * ofnode_get_name() - get the name of a node
  *
  * @node: valid node to look up
- * Return: name of node
+ * Return: name of node (for the root node this is "")
  */
 const char *ofnode_get_name(ofnode node);
 
@@ -501,12 +639,23 @@
 /**
  * ofnode_get_by_phandle() - get ofnode from phandle
  *
+ * This uses the default (control) device tree
+ *
  * @phandle:	phandle to look up
  * Return: ofnode reference to the phandle
  */
 ofnode ofnode_get_by_phandle(uint phandle);
 
 /**
+ * oftree_get_by_phandle() - get ofnode from phandle
+ *
+ * @tree:	tree to use
+ * @phandle:	phandle to look up
+ * Return: ofnode reference to the phandle
+ */
+ofnode oftree_get_by_phandle(oftree tree, uint phandle);
+
+/**
  * ofnode_read_size() - read the size of a property
  *
  * @node: node to check
@@ -723,18 +872,28 @@
 ofnode ofnode_path(const char *path);
 
 /**
- * ofnode_path_root() - find a node by full path from a root node
+ * oftree_path() - find a node by full path from a root node
  *
  * @tree: Device tree to use
  * @path: Full path to node, e.g. "/bus/spi@1"
  * Return: reference to the node found. Use ofnode_valid() to check if it exists
  */
-ofnode ofnode_path_root(oftree tree, const char *path);
+ofnode oftree_path(oftree tree, const char *path);
+
+/**
+ * oftree_root() - get the root node of a tree
+ *
+ * @tree: Device tree to use
+ * Return: reference to the root node
+ */
+ofnode oftree_root(oftree tree);
 
 /**
  * ofnode_read_chosen_prop() - get the value of a chosen property
  *
- * This looks for a property within the /chosen node and returns its value
+ * This looks for a property within the /chosen node and returns its value.
+ *
+ * This only works with the control FDT.
  *
  * @propname: Property name to look for
  * @sizep: Returns size of property, or  `FDT_ERR_...` error code if function
@@ -749,6 +908,8 @@
  * This looks for a property within the /chosen node and returns its value,
  * checking that it is a valid nul-terminated string
  *
+ * This only works with the control FDT.
+ *
  * @propname: Property name to look for
  * Return: string value if found, else NULL
  */
@@ -760,6 +921,8 @@
  * This looks up a named property in the chosen node and uses that as a path to
  * look up a code.
  *
+ * This only works with the control FDT.
+ *
  * @propname: Property name to look for
  * Return: the referenced node if present, else ofnode_null()
  */
@@ -770,6 +933,8 @@
  *
  * This looks for a property within the /aliases node and returns its value
  *
+ * This only works with the control FDT.
+ *
  * @propname: Property name to look for
  * @sizep: Returns size of property, or `FDT_ERR_...` error code if function
  *	returns NULL
@@ -783,6 +948,8 @@
  * This looks up a named property in the aliases node and uses that as a path to
  * look up a code.
  *
+ * This only works with the control FDT.
+ *
  * @propname: Property name to look for
  * Return: the referenced node if present, else ofnode_null()
  */
@@ -815,48 +982,64 @@
 const void *ofnode_get_property(ofnode node, const char *propname, int *lenp);
 
 /**
- * ofnode_get_first_property()- get the reference of the first property
+ * ofnode_first_property()- get the reference of the first property
  *
  * Get reference to the first property of the node, it is used to iterate
- * and read all the property with ofnode_get_property_by_prop().
+ * and read all the property with ofprop_get_property().
  *
  * @node: node to read
  * @prop: place to put argument reference
  * Return: 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
  */
-int ofnode_get_first_property(ofnode node, struct ofprop *prop);
+int ofnode_first_property(ofnode node, struct ofprop *prop);
 
 /**
- * ofnode_get_next_property() - get the reference of the next property
+ * ofnode_next_property() - get the reference of the next property
  *
  * Get reference to the next property of the node, it is used to iterate
- * and read all the property with ofnode_get_property_by_prop().
+ * and read all the property with ofprop_get_property().
  *
  * @prop: reference of current argument and place to put reference of next one
  * Return: 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
  */
-int ofnode_get_next_property(struct ofprop *prop);
+int ofnode_next_property(struct ofprop *prop);
 
 /**
- * ofnode_get_property_by_prop() - get a pointer to the value of a property
+ * ofnode_for_each_prop() - iterate over all properties of a node
+ *
+ * @prop:	struct ofprop
+ * @node:	node (lvalue, ofnode)
+ *
+ * This is a wrapper around a for loop and is used like this::
+ *
+ *   ofnode node;
+ *   struct ofprop prop;
+ *
+ *   ofnode_for_each_prop(prop, node) {
+ *       ...use prop...
+ *   }
+ *
+ * Note that this is implemented as a macro and @prop is used as
+ * iterator in the loop. The parent variable can be a constant or even a
+ * literal.
+ */
+#define ofnode_for_each_prop(prop, node) \
+	for (ofnode_first_property(node, &prop); \
+	     ofprop_valid(&prop); \
+	     ofnode_next_property(&prop))
+
+/**
+ * ofprop_get_property() - get a pointer to the value of a property
  *
  * Get value for the property identified by the provided reference.
  *
  * @prop: reference on property
  * @propname: If non-NULL, place to property name on success,
- * @lenp: If non-NULL, place to put length on success
- * Return: 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ * @lenp: If non-NULL, place to put length on success, or error code on failure
+ * Return: pointer to property, or NULL if not found
  */
-const void *ofnode_get_property_by_prop(const struct ofprop *prop,
-					const char **propname, int *lenp);
-
-/**
- * ofnode_is_available() - check if a node is marked available
- *
- * @node: node to check
- * Return: true if node's 'status' property is "okay" (or is missing)
- */
-bool ofnode_is_available(ofnode node);
+const void *ofprop_get_property(const struct ofprop *prop,
+				const char **propname, int *lenp);
 
 /**
  * ofnode_get_addr_size() - get address and size from a property
@@ -1046,8 +1229,9 @@
  * Find the next node after @from that has a @propname with a value
  * @propval and a length @proplen.
  *
- * @from: ofnode to start from (use ofnode_null() to start at the
- * beginning)
+ * @from: ofnode to start from. Use ofnode_null() to start at the
+ * beginning, or the return value from oftree_root() to start at the first
+ * child of the root
  * @propname: property name to check
  * @propval: property value to search for
  * @proplen: length of the value in propval
@@ -1166,19 +1350,23 @@
 /**
  * ofnode_write_prop() - Set a property of a ofnode
  *
- * Note that the value passed to the function is *not* allocated by the
- * function itself, but must be allocated by the caller if necessary. However
- * it does allocate memory for the property struct and name.
+ * Note that if @copy is false, the value passed to the function is *not*
+ * allocated by the function itself, but must be allocated by the caller if
+ * necessary. However it does allocate memory for the property struct and name.
  *
  * @node:	The node for whose property should be set
  * @propname:	The name of the property to set
  * @value:	The new value of the property (must be valid prior to calling
  *		the function)
  * @len:	The length of the new value of the property
+ * @copy: true to allocate memory for the value. This only has any effect with
+ *	live tree, since flat tree handles this automatically. It allows a
+ *	node's value to be written to the tree, without requiring that the
+ *	caller allocate it
  * Return: 0 if successful, -ve on error
  */
 int ofnode_write_prop(ofnode node, const char *propname, const void *value,
-		      int len);
+		      int len, bool copy);
 
 /**
  * ofnode_write_string() - Set a string property of a ofnode
@@ -1251,7 +1439,9 @@
  *
  * This reads a property from the /config node of the devicetree.
  *
- * See doc/config.txt for bindings
+ * This only works with the control FDT.
+ *
+ * See doc/device-tree-bindings/config.txt for bindings
  *
  * @prop_name:	property name to look up
  * Return: true, if it exists, false if not
@@ -1263,7 +1453,7 @@
  *
  * This reads a property from the /config node of the devicetree.
  *
- * See doc/config.txt for bindings
+ * See doc/device-tree-bindings/config.txt for bindings
  *
  * @prop_name: property name to look up
  * @default_val: default value to return if the property is not found
@@ -1276,7 +1466,9 @@
  *
  * This reads a property from the /config node of the devicetree.
  *
- * See doc/config.txt for bindings
+ * This only works with the control FDT.
+ *
+ * See doc/device-tree-bindings/config.txt for bindings
  *
  * @prop_name: property name to look up
  * Return: string value, if found, or NULL if not
@@ -1298,6 +1490,35 @@
 {
 	return NULL;
 }
+
 #endif /* CONFIG_DM */
 
+/**
+ * of_add_subnode() - add a new subnode to a node
+ *
+ * @parent:	parent node to add to
+ * @name:	name of subnode
+ * @nodep:	returns pointer to new subnode (valid if the function returns 0
+ *	or -EEXIST)
+ * Returns 0 if OK, -EEXIST if already exists, -ENOMEM if out of memory, other
+ * -ve on other error
+ */
+int ofnode_add_subnode(ofnode parent, const char *name, ofnode *nodep);
+
+/**
+ * ofnode_copy_props() - copy all properties from one node to another
+ *
+ * Makes a copy of all properties from the source note in the destination node.
+ * Existing properties in the destination node remain unchanged, except that
+ * any with the same name are overwritten, including changing the size of the
+ * property.
+ *
+ * For livetree, properties are copied / allocated, so the source tree does not
+ * need to be present afterwards.
+ *
+ * @src: Source node to read properties from
+ * @dst: Destination node to write properties too
+ */
+int ofnode_copy_props(ofnode src, ofnode dst);
+
 #endif
diff --git a/include/dm/ofnode_decl.h b/include/dm/ofnode_decl.h
index 266253d..5c2115a 100644
--- a/include/dm/ofnode_decl.h
+++ b/include/dm/ofnode_decl.h
@@ -31,18 +31,47 @@
  * this increases code size slightly due to the subtraction. Since it offers no
  * real benefit, the approach described here seems best.
  *
- * For now these points use constant types, since we don't allow writing
- * the DT.
+ * Where multiple trees are in use, this works without any trouble with live
+ * tree, except for aliases, such as ofnode_path("mmc0"), which only work on the
+ * control FDT. When the flat tree is in use, the trees are registered and a
+ * 'tree ID' is encoded into the top bits of @of_offset - see immediately below
+ * for the associated macro definitions. Note that 64-bit machines use the same
+ * encoding, even though there is more space available. This is partly because
+ * the FDT format contains 32-bit values for things like the string-table
+ * offset, therefore 64-bit offsets cannot be supported anyway.
+ *
+ * For the multiple-tree case, an invalid offset (i.e. with of_offset < 0) is
+ * still invalid. It does not contain a tree ID. So there is no way of knowing
+ * which tree produced the invalid offset.
  *
  * @np: Pointer to device node, used for live tree
  * @of_offset: Pointer into flat device tree, used for flat tree. Note that this
  *	is not a really a pointer to a node: it is an offset value. See above.
  */
 typedef union ofnode_union {
-	const struct device_node *np;
+	struct device_node *np;
 	long of_offset;
 } ofnode;
 
+/* shift for the tree ID within of_offset */
+#define OF_TREE_SHIFT 28
+
+/* mask to obtain the device tree offset from of_offset */
+#define OF_TREE_MASK ((1 << OF_TREE_SHIFT) - 1)
+
+/* encode a tree ID and node offset into an of_offset value */
+#define OFTREE_NODE(tree_id, offs)	((tree_id) << OF_TREE_SHIFT | (offs))
+
+/* decode the node offset from an of_offset value */
+#define OFTREE_OFFSET(of_offs)		((of_offs) & OF_TREE_MASK)
+
+/* decode the tree ID from an of_offset value */
+#define OFTREE_TREE_ID(of_offs)		((of_offs) >> OF_TREE_SHIFT)
+
+/* encode a node offset in the tree given by another node's of_offset value */
+#define OFTREE_MAKE_NODE(other_of_offset, offs)	\
+		(((offs) & OF_TREE_MASK) | ((other_of_offset) & ~OF_TREE_MASK))
+
 /**
  * struct ofprop - reference to a property of a device tree node
  *
@@ -57,7 +86,7 @@
  *
  * @node: Pointer to device node
  * @offset: Pointer into flat device tree, used for flat tree.
- * @prop: Pointer to property, used for live treee.
+ * @prop: Pointer to property, used for live tree.
  */
 
 struct ofprop {
diff --git a/include/dm/read.h b/include/dm/read.h
index 122b9cd..cc4f161 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -569,7 +569,7 @@
 int dev_read_first_prop(const struct udevice *dev, struct ofprop *prop);
 
 /**
- * ofnode_get_next_property() - get the reference of the next property
+ * ofnode_next_property() - get the reference of the next property
  *
  * Get reference to the next property of the node, it is used to iterate
  * and read all the property with dev_read_prop_by_prop().
@@ -1079,19 +1079,19 @@
 
 static inline int dev_read_first_prop(const struct udevice *dev, struct ofprop *prop)
 {
-	return ofnode_get_first_property(dev_ofnode(dev), prop);
+	return ofnode_first_property(dev_ofnode(dev), prop);
 }
 
 static inline int dev_read_next_prop(struct ofprop *prop)
 {
-	return ofnode_get_next_property(prop);
+	return ofnode_next_property(prop);
 }
 
 static inline const void *dev_read_prop_by_prop(struct ofprop *prop,
 						const char **propname,
 						int *lenp)
 {
-	return ofnode_get_property_by_prop(prop, propname, lenp);
+	return ofprop_get_property(prop, propname, lenp);
 }
 
 static inline int dev_read_alias_seq(const struct udevice *dev, int *devnump)
diff --git a/include/event.h b/include/event.h
index e8f2f55..3e6dcbc 100644
--- a/include/event.h
+++ b/include/event.h
@@ -60,9 +60,11 @@
 	 * struct event_ft_fixup - FDT fixup before booting
 	 *
 	 * @tree: tree to update
+	 * @images: images which are being booted
 	 */
 	struct event_ft_fixup {
 		oftree tree;
+		struct bootm_headers *images;
 	} ft_fixup;
 };
 
@@ -143,8 +145,8 @@
  * vbe_simple.c - so for now, make it global.
  */
 #define EVENT_SPY(_type, _func) \
-	__used ll_entry_declare(struct evspy_info, _type, evspy_info) = \
-	_ESPY_REC(_type, _func)
+	__used ll_entry_declare(struct evspy_info, _type ## _3_ ## _func, \
+		evspy_info) = _ESPY_REC(_type, _func)
 
 /**
  * event_register - register a new spy
diff --git a/include/image.h b/include/image.h
index 03424f0..eb2513c 100644
--- a/include/image.h
+++ b/include/image.h
@@ -263,7 +263,7 @@
  * Legacy format image header,
  * all data in network byte order (aka natural aka bigendian).
  */
-typedef struct image_header {
+struct legacy_img_hdr {
 	uint32_t	ih_magic;	/* Image Header Magic Number	*/
 	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
 	uint32_t	ih_time;	/* Image Creation Timestamp	*/
@@ -276,28 +276,28 @@
 	uint8_t		ih_type;	/* Image Type			*/
 	uint8_t		ih_comp;	/* Compression Type		*/
 	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
-} image_header_t;
+};
 
-typedef struct image_info {
+struct image_info {
 	ulong		start, end;		/* start/end of blob */
 	ulong		image_start, image_len; /* start of image within blob, len of image */
 	ulong		load;			/* load addr for the image */
 	uint8_t		comp, type, os;		/* compression, type of image, os type */
 	uint8_t		arch;			/* CPU architecture */
-} image_info_t;
+};
 
 /*
  * Legacy and FIT format headers used by do_bootm() and do_bootm_<os>()
  * routines.
  */
-typedef struct bootm_headers {
+struct bootm_headers {
 	/*
 	 * Legacy os image header, if it is a multi component image
 	 * then boot_get_ramdisk() and get_fdt() will attempt to get
 	 * data from second and third component accordingly.
 	 */
-	image_header_t	*legacy_hdr_os;		/* image header pointer */
-	image_header_t	legacy_hdr_os_copy;	/* header copy */
+	struct legacy_img_hdr	*legacy_hdr_os;		/* image header pointer */
+	struct legacy_img_hdr	legacy_hdr_os_copy;	/* header copy */
 	ulong		legacy_hdr_valid;
 
 	/*
@@ -324,7 +324,7 @@
 	int		fit_noffset_setup;/* x86 setup subimage node offset */
 
 #ifndef USE_HOSTCC
-	image_info_t	os;		/* os image info */
+	struct image_info	os;		/* os image info */
 	ulong		ep;		/* entry point of OS */
 
 	ulong		rd_start, rd_end;/* ramdisk start/end */
@@ -341,24 +341,24 @@
 
 	int		verify;		/* env_get("verify")[0] != 'n' */
 
-#define	BOOTM_STATE_START	(0x00000001)
-#define	BOOTM_STATE_FINDOS	(0x00000002)
-#define	BOOTM_STATE_FINDOTHER	(0x00000004)
-#define	BOOTM_STATE_LOADOS	(0x00000008)
-#define	BOOTM_STATE_RAMDISK	(0x00000010)
-#define	BOOTM_STATE_FDT		(0x00000020)
-#define	BOOTM_STATE_OS_CMDLINE	(0x00000040)
-#define	BOOTM_STATE_OS_BD_T	(0x00000080)
-#define	BOOTM_STATE_OS_PREP	(0x00000100)
-#define	BOOTM_STATE_OS_FAKE_GO	(0x00000200)	/* 'Almost' run the OS */
-#define	BOOTM_STATE_OS_GO	(0x00000400)
-#define	BOOTM_STATE_PRE_LOAD	0x00000800
+#define BOOTM_STATE_START	0x00000001
+#define BOOTM_STATE_FINDOS	0x00000002
+#define BOOTM_STATE_FINDOTHER	0x00000004
+#define BOOTM_STATE_LOADOS	0x00000008
+#define BOOTM_STATE_RAMDISK	0x00000010
+#define BOOTM_STATE_FDT		0x00000020
+#define BOOTM_STATE_OS_CMDLINE	0x00000040
+#define BOOTM_STATE_OS_BD_T	0x00000080
+#define BOOTM_STATE_OS_PREP	0x00000100
+#define BOOTM_STATE_OS_FAKE_GO	0x00000200	/* 'Almost' run the OS */
+#define BOOTM_STATE_OS_GO	0x00000400
+#define BOOTM_STATE_PRE_LOAD	0x00000800
 	int		state;
 
 #if defined(CONFIG_LMB) && !defined(USE_HOSTCC)
 	struct lmb	lmb;		/* for memory mgmt */
 #endif
-} bootm_headers_t;
+};
 
 #ifdef CONFIG_LMB
 #define images_lmb(_images)	(&(_images)->lmb)
@@ -366,7 +366,7 @@
 #define images_lmb(_images)	NULL
 #endif
 
-extern bootm_headers_t images;
+extern struct bootm_headers images;
 
 /*
  * Some systems (for example LWMON) have very short watchdog periods;
@@ -530,7 +530,7 @@
 	FIT_LOAD_REQUIRED,	/* Must be provided */
 };
 
-int boot_get_setup(bootm_headers_t *images, uint8_t arch, ulong *setup_start,
+int boot_get_setup(struct bootm_headers *images, uint8_t arch, ulong *setup_start,
 		   ulong *setup_len);
 
 /* Image format types, returned by _get_format() routine */
@@ -544,11 +544,11 @@
 			         const char **fit_uname_kernel);
 ulong genimg_get_kernel_addr(char * const img_addr);
 int genimg_get_format(const void *img_addr);
-int genimg_has_config(bootm_headers_t *images);
+int genimg_has_config(struct bootm_headers *images);
 
-int boot_get_fpga(int argc, char *const argv[], bootm_headers_t *images,
+int boot_get_fpga(int argc, char *const argv[], struct bootm_headers *images,
 		  uint8_t arch, const ulong *ld_start, ulong * const ld_len);
-int boot_get_ramdisk(int argc, char *const argv[], bootm_headers_t *images,
+int boot_get_ramdisk(int argc, char *const argv[], struct bootm_headers *images,
 		     uint8_t arch, ulong *rd_start, ulong *rd_end);
 
 /**
@@ -572,10 +572,10 @@
  *     0, if only valid images or no images are found
  *     error code, if an error occurs during fit_image_load
  */
-int boot_get_loadable(int argc, char *const argv[], bootm_headers_t *images,
+int boot_get_loadable(int argc, char *const argv[], struct bootm_headers *images,
 		      uint8_t arch, const ulong *ld_start, ulong *const ld_len);
 
-int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
+int boot_get_setup_fit(struct bootm_headers *images, uint8_t arch,
 		       ulong *setup_start, ulong *setup_len);
 
 /**
@@ -599,9 +599,9 @@
  *
  * Return: node offset of base image, or -ve error code on error
  */
-int boot_get_fdt_fit(bootm_headers_t *images, ulong addr,
-		   const char **fit_unamep, const char **fit_uname_configp,
-		   int arch, ulong *datap, ulong *lenp);
+int boot_get_fdt_fit(struct bootm_headers *images, ulong addr,
+		     const char **fit_unamep, const char **fit_uname_configp,
+		     int arch, ulong *datap, ulong *lenp);
 
 /**
  * fit_image_load() - load an image from a FIT
@@ -633,7 +633,7 @@
  * @param lenp		Returns length of loaded image
  * Return: node offset of image, or -ve error code on error
  */
-int fit_image_load(bootm_headers_t *images, ulong addr,
+int fit_image_load(struct bootm_headers *images, ulong addr,
 		   const char **fit_unamep, const char **fit_uname_configp,
 		   int arch, int image_type, int bootstage_id,
 		   enum fit_load_op load_op, ulong *datap, ulong *lenp);
@@ -677,11 +677,11 @@
  * @param prop_name	Property name to look up (FIT_..._PROP)
  * @param addr		Address of FIT in memory
  */
-int fit_get_node_from_config(bootm_headers_t *images, const char *prop_name,
-			ulong addr);
+int fit_get_node_from_config(struct bootm_headers *images,
+			     const char *prop_name, ulong addr);
 
 int boot_get_fdt(int flag, int argc, char *const argv[], uint8_t arch,
-		 bootm_headers_t *images,
+		 struct bootm_headers *images,
 		 char **of_flat_tree, ulong *of_size);
 void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob);
 int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size);
@@ -696,11 +696,11 @@
 /*******************************************************************/
 static inline uint32_t image_get_header_size(void)
 {
-	return (sizeof(image_header_t));
+	return sizeof(struct legacy_img_hdr);
 }
 
 #define image_get_hdr_l(f) \
-	static inline uint32_t image_get_##f(const image_header_t *hdr) \
+	static inline uint32_t image_get_##f(const struct legacy_img_hdr *hdr) \
 	{ \
 		return uimage_to_cpu(hdr->ih_##f); \
 	}
@@ -713,7 +713,7 @@
 image_get_hdr_l(dcrc)		/* image_get_dcrc */
 
 #define image_get_hdr_b(f) \
-	static inline uint8_t image_get_##f(const image_header_t *hdr) \
+	static inline uint8_t image_get_##f(const struct legacy_img_hdr *hdr) \
 	{ \
 		return hdr->ih_##f; \
 	}
@@ -722,12 +722,12 @@
 image_get_hdr_b(type)		/* image_get_type */
 image_get_hdr_b(comp)		/* image_get_comp */
 
-static inline char *image_get_name(const image_header_t *hdr)
+static inline char *image_get_name(const struct legacy_img_hdr *hdr)
 {
 	return (char *)hdr->ih_name;
 }
 
-static inline uint32_t image_get_data_size(const image_header_t *hdr)
+static inline uint32_t image_get_data_size(const struct legacy_img_hdr *hdr)
 {
 	return image_get_size(hdr);
 }
@@ -743,22 +743,23 @@
  * returns:
  *     image payload data start address
  */
-static inline ulong image_get_data(const image_header_t *hdr)
+static inline ulong image_get_data(const struct legacy_img_hdr *hdr)
 {
 	return ((ulong)hdr + image_get_header_size());
 }
 
-static inline uint32_t image_get_image_size(const image_header_t *hdr)
+static inline uint32_t image_get_image_size(const struct legacy_img_hdr *hdr)
 {
 	return (image_get_size(hdr) + image_get_header_size());
 }
-static inline ulong image_get_image_end(const image_header_t *hdr)
+
+static inline ulong image_get_image_end(const struct legacy_img_hdr *hdr)
 {
 	return ((ulong)hdr + image_get_image_size(hdr));
 }
 
 #define image_set_hdr_l(f) \
-	static inline void image_set_##f(image_header_t *hdr, uint32_t val) \
+	static inline void image_set_##f(struct legacy_img_hdr *hdr, uint32_t val) \
 	{ \
 		hdr->ih_##f = cpu_to_uimage(val); \
 	}
@@ -771,7 +772,7 @@
 image_set_hdr_l(dcrc)		/* image_set_dcrc */
 
 #define image_set_hdr_b(f) \
-	static inline void image_set_##f(image_header_t *hdr, uint8_t val) \
+	static inline void image_set_##f(struct legacy_img_hdr *hdr, uint8_t val) \
 	{ \
 		hdr->ih_##f = val; \
 	}
@@ -780,13 +781,13 @@
 image_set_hdr_b(type)		/* image_set_type */
 image_set_hdr_b(comp)		/* image_set_comp */
 
-static inline void image_set_name(image_header_t *hdr, const char *name)
+static inline void image_set_name(struct legacy_img_hdr *hdr, const char *name)
 {
 	strncpy(image_get_name(hdr), name, IH_NMLEN);
 }
 
-int image_check_hcrc(const image_header_t *hdr);
-int image_check_dcrc(const image_header_t *hdr);
+int image_check_hcrc(const struct legacy_img_hdr *hdr);
+int image_check_dcrc(const struct legacy_img_hdr *hdr);
 #ifndef USE_HOSTCC
 ulong env_get_bootm_low(void);
 phys_size_t env_get_bootm_size(void);
@@ -794,15 +795,17 @@
 #endif
 void memmove_wd(void *to, void *from, size_t len, ulong chunksz);
 
-static inline int image_check_magic(const image_header_t *hdr)
+static inline int image_check_magic(const struct legacy_img_hdr *hdr)
 {
 	return (image_get_magic(hdr) == IH_MAGIC);
 }
-static inline int image_check_type(const image_header_t *hdr, uint8_t type)
+
+static inline int image_check_type(const struct legacy_img_hdr *hdr, uint8_t type)
 {
 	return (image_get_type(hdr) == type);
 }
-static inline int image_check_arch(const image_header_t *hdr, uint8_t arch)
+
+static inline int image_check_arch(const struct legacy_img_hdr *hdr, uint8_t arch)
 {
 	/* Let's assume that sandbox can load any architecture */
 	if (!tools_build() && IS_ENABLED(CONFIG_SANDBOX))
@@ -810,19 +813,20 @@
 	return (image_get_arch(hdr) == arch) ||
 		(image_get_arch(hdr) == IH_ARCH_ARM && arch == IH_ARCH_ARM64);
 }
-static inline int image_check_os(const image_header_t *hdr, uint8_t os)
+
+static inline int image_check_os(const struct legacy_img_hdr *hdr, uint8_t os)
 {
 	return (image_get_os(hdr) == os);
 }
 
-ulong image_multi_count(const image_header_t *hdr);
-void image_multi_getimg(const image_header_t *hdr, ulong idx,
+ulong image_multi_count(const struct legacy_img_hdr *hdr);
+void image_multi_getimg(const struct legacy_img_hdr *hdr, ulong idx,
 			ulong *data, ulong *len);
 
 void image_print_contents(const void *hdr);
 
 #ifndef USE_HOSTCC
-static inline int image_check_target_arch(const image_header_t *hdr)
+static inline int image_check_target_arch(const struct legacy_img_hdr *hdr)
 {
 #ifndef IH_ARCH_DEFAULT
 # error "please define IH_ARCH_DEFAULT in your arch asm/u-boot.h"
@@ -871,7 +875,7 @@
  * @lmb:	Points to logical memory block structure
  * Return: 0 if ok, <0 on failure
  */
-int image_setup_libfdt(bootm_headers_t *images, void *blob,
+int image_setup_libfdt(struct bootm_headers *images, void *blob,
 		       int of_size, struct lmb *lmb);
 
 /**
@@ -883,7 +887,7 @@
  * @param images	Images information
  * Return: 0 if ok, <0 on failure
  */
-int image_setup_linux(bootm_headers_t *images);
+int image_setup_linux(struct bootm_headers *images);
 
 /**
  * bootz_setup() - Extract stat and size of a Linux xImage
diff --git a/include/log.h b/include/log.h
index df497ba..8a7b961 100644
--- a/include/log.h
+++ b/include/log.h
@@ -322,7 +322,10 @@
  *
  * or:
  *
- *	return log_msg_ret("fred failed", fred_call());
+ *	return log_msg_ret("get", fred_call());
+ *
+ * It is recommended to use <= 3 characters for the name since this will only
+ * use 4 bytes in rodata
  */
 #define log_ret(_ret) ({ \
 	int __ret = (_ret); \
diff --git a/include/malloc.h b/include/malloc.h
index e8c8b25..161ccbd 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -883,6 +883,18 @@
 
 void malloc_simple_info(void);
 
+/**
+ * malloc_enable_testing() - Put malloc() into test mode
+ *
+ * This only works if UNIT_TESTING is enabled
+ *
+ * @max_allocs: return -ENOMEM after max_allocs calls to malloc()
+ */
+void malloc_enable_testing(int max_allocs);
+
+/** malloc_disable_testing() - Put malloc() into normal mode */
+void malloc_disable_testing(void);
+
 #if CONFIG_IS_ENABLED(SYS_MALLOC_SIMPLE)
 #define malloc malloc_simple
 #define realloc realloc_simple
diff --git a/include/spl.h b/include/spl.h
index aac6648..0fc3686 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -17,7 +17,7 @@
 #include <mmc.h>
 
 struct blk_desc;
-struct image_header;
+struct legacy_img_hdr;
 
 /* Value in r0 indicates we booted from U-Boot */
 #define UBOOT_NOT_LOADED_FROM_SPL	0x13578642
@@ -29,7 +29,7 @@
 #define MMCSD_MODE_EMMCBOOT	3
 
 struct blk_desc;
-struct image_header;
+struct legacy_img_hdr;
 struct spl_boot_device;
 
 /*
@@ -476,7 +476,7 @@
  */
 int spl_parse_image_header(struct spl_image_info *spl_image,
 			   const struct spl_boot_device *bootdev,
-			   const struct image_header *header);
+			   const struct legacy_img_hdr *header);
 
 void spl_board_prepare_for_linux(void);
 
@@ -865,7 +865,7 @@
  * Returns memory area which can be populated by partial image data,
  * ie. uImage or fitImage header.
  */
-struct image_header *spl_get_load_buffer(ssize_t offset, size_t size);
+struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size);
 
 void spl_save_restore_data(void);
 #endif
diff --git a/include/tee/optee.h b/include/tee/optee.h
index 5412bc7..7772945 100644
--- a/include/tee/optee.h
+++ b/include/tee/optee.h
@@ -30,7 +30,7 @@
 };
 
 static inline uint32_t
-optee_image_get_entry_point(const struct image_header *hdr)
+optee_image_get_entry_point(const struct legacy_img_hdr *hdr)
 {
 	struct optee_header *optee_hdr = (struct optee_header *)(hdr + 1);
 
@@ -38,7 +38,7 @@
 }
 
 static inline uint32_t
-optee_image_get_load_addr(const struct image_header *hdr)
+optee_image_get_load_addr(const struct legacy_img_hdr *hdr)
 {
 	return optee_image_get_entry_point(hdr) - sizeof(struct optee_header);
 }
diff --git a/include/test/test.h b/include/test/test.h
index 2b68331..3bbd77c 100644
--- a/include/test/test.h
+++ b/include/test/test.h
@@ -20,6 +20,12 @@
  * @testdev: Test device
  * @force_fail_alloc: Force all memory allocs to fail
  * @skip_post_probe: Skip uclass post-probe processing
+ * @fdt_chksum: crc8 of the device tree contents
+ * @fdt_copy: Copy of the device tree
+ * @fdt_size: Size of the device-tree copy
+ * @other_fdt: Buffer for the other FDT (UT_TESTF_OTHER_FDT)
+ * @other_fdt_size: Size of the other FDT (UT_TESTF_OTHER_FDT)
+ * @of_other: Live tree for the other FDT
  * @runs_per_test: Number of times to run each test (typically 1)
  * @expect_str: Temporary string used to hold expected string value
  * @actual_str: Temporary string used to hold actual string value
@@ -33,6 +39,12 @@
 	struct udevice *testdev;
 	int force_fail_alloc;
 	int skip_post_probe;
+	uint fdt_chksum;
+	void *fdt_copy;
+	uint fdt_size;
+	void *other_fdt;
+	int other_fdt_size;
+	struct device_node *of_other;
 	int runs_per_test;
 	char expect_str[512];
 	char actual_str[512];
@@ -48,8 +60,7 @@
 	UT_TESTF_CONSOLE_REC	= BIT(5),	/* needs console recording */
 	/* do extra driver model init and uninit */
 	UT_TESTF_DM		= BIT(6),
-	/* live or flat device tree, but not both in the same executable */
-	UT_TESTF_LIVE_OR_FLAT	= BIT(4),
+	UT_TESTF_OTHER_FDT	= BIT(7),	/* read in other device tree */
 };
 
 /**
@@ -128,13 +139,24 @@
  */
 struct udevice *testbus_get_clear_removed(void);
 
+#ifdef CONFIG_SANDBOX
+#include <asm/state.h>
+#include <asm/test.h>
+#endif
+
 static inline void arch_reset_for_test(void)
 {
 #ifdef CONFIG_SANDBOX
-#include <asm/state.h>
-
 	state_reset_for_test(state_get_current());
 #endif
 }
+static inline int test_load_other_fdt(struct unit_test_state *uts)
+{
+	int ret = 0;
+#ifdef CONFIG_SANDBOX
+	ret = sandbox_load_other_fdt(&uts->other_fdt, &uts->other_fdt_size);
+#endif
+	return ret;
+}
 
 #endif /* __TEST_TEST_H */
diff --git a/include/test/ut.h b/include/test/ut.h
index f7d1d18..f7217aa 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -119,6 +119,11 @@
  */
 int ut_check_console_dump(struct unit_test_state *uts, int total_bytes);
 
+/* Report a failure, with printf() string */
+#define ut_reportf(fmt, args...)					\
+	ut_failf(uts, __FILE__, __LINE__, __func__, "report",		\
+		 fmt, ##args)
+
 /* Assert that a condition is non-zero */
 #define ut_assert(cond)							\
 	if (!(cond)) {							\
diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c
index d3923e5..838023c 100644
--- a/lib/efi_loader/efi_dt_fixup.c
+++ b/lib/efi_loader/efi_dt_fixup.c
@@ -145,7 +145,7 @@
 	efi_status_t ret;
 	size_t required_size;
 	size_t total_size;
-	bootm_headers_t img = { 0 };
+	struct bootm_headers img = { 0 };
 
 	EFI_ENTRY("%p, %p, %p, %d", this, dtb, buffer_size, flags);
 
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 96b6b71..64c5b3d 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -13,7 +13,6 @@
 #include <log.h>
 #include <malloc.h>
 #include <net.h>
-#include <dm/of_extra.h>
 #include <env.h>
 #include <errno.h>
 #include <fdtdec.h>
@@ -24,6 +23,8 @@
 #include <serial.h>
 #include <asm/global_data.h>
 #include <asm/sections.h>
+#include <dm/ofnode.h>
+#include <dm/of_extra.h>
 #include <linux/ctype.h>
 #include <linux/lzo.h>
 #include <linux/ioport.h>
@@ -1058,7 +1059,7 @@
 {
 	do {
 		mem = ofnode_by_prop_value(mem, "device_type", "memory", 7);
-	} while (!ofnode_is_available(mem));
+	} while (!ofnode_is_enabled(mem));
 
 	return mem;
 }
@@ -1668,6 +1669,8 @@
 	ret = fdtdec_prepare_fdt();
 	if (!ret)
 		ret = fdtdec_board_setup(gd->fdt_blob);
+	oftree_reset();
+
 	return ret;
 }
 
diff --git a/lib/of_live.c b/lib/of_live.c
index 30cae9a..1b5964d 100644
--- a/lib/of_live.c
+++ b/lib/of_live.c
@@ -97,6 +97,10 @@
 		char *fn;
 
 		fn = (char *)np + sizeof(*np);
+		if (new_format) {
+			np->name = pathp;
+			has_name = 1;
+		}
 		np->full_name = fn;
 		if (new_format) {
 			/* rebuild full path for new format */
@@ -202,7 +206,8 @@
 	}
 	if (!dryrun) {
 		*prev_pp = NULL;
-		np->name = of_get_property(np, "name", NULL);
+		if (!has_name)
+			np->name = of_get_property(np, "name", NULL);
 		np->type = of_get_property(np, "device_type", NULL);
 
 		if (!np->name)
diff --git a/net/dsa-uclass.c b/net/dsa-uclass.c
index 3bf4351..5b70464 100644
--- a/net/dsa-uclass.c
+++ b/net/dsa-uclass.c
@@ -432,7 +432,7 @@
 		 * skip registration if port id not found or if the port
 		 * is explicitly disabled in DT
 		 */
-		if (!ofnode_valid(pnode) || !ofnode_is_available(pnode))
+		if (!ofnode_valid(pnode) || !ofnode_is_enabled(pnode))
 			continue;
 
 		err = device_bind_driver_to_node(dev, DSA_PORT_CHILD_DRV_NAME,
diff --git a/scripts/event_dump.py b/scripts/event_dump.py
index 751f41b..6aadddf 100755
--- a/scripts/event_dump.py
+++ b/scripts/event_dump.py
@@ -17,8 +17,10 @@
 from binman import elf
 from patman import tools
 
+# A typical symbol looks like this:
+#   _u_boot_list_2_evspy_info_2_EVT_MISC_INIT_F_3_sandbox_misc_init_f
 PREFIX = '_u_boot_list_2_evspy_info_2_'
-RE_EVTYPE = re.compile('%s(.*)' % PREFIX)
+RE_EVTYPE = re.compile('%s(.*)_3_.*' % PREFIX)
 
 def show_sym(fname, data, endian, evtype, sym):
     """Show information about an evspy entry
diff --git a/test/boot/vbe_simple.c b/test/boot/vbe_simple.c
index 2f6979c..8acd777 100644
--- a/test/boot/vbe_simple.c
+++ b/test/boot/vbe_simple.c
@@ -74,29 +74,25 @@
 	node_ofs = fdt_add_subnode(fdt_buf, node_ofs, "firmware0");
 	ut_assert(node_ofs > 0);
 
-	/*
-	 * This can only work on the live tree, since the ofnode interface for
-	 * flat tree assumes that ofnode points to the control FDT
-	 */
-	ut_assertok(unflatten_device_tree(fdt_buf, &np));
+	if (of_live_active()) {
+		ut_assertok(unflatten_device_tree(fdt_buf, &np));
+		fixup.tree = oftree_from_np(np);
+	} else {
+		fixup.tree = oftree_from_fdt(fdt_buf);
+	}
 
 	/*
 	 * It would be better to call image_setup_libfdt() here, but that
 	 * function does not allow passing an ofnode. We can pass fdt_buf but
-	 * when it comes to send the evenr, it creates an ofnode that uses the
+	 * when it comes to send the event, it creates an ofnode that uses the
 	 * control FDT, since it has no way of accessing the live tree created
 	 * here.
 	 *
-	 * Two fix this we need:
-	 * - image_setup_libfdt() is updated to use ofnode
-	 * - ofnode updated to support access to an FDT other than the control
-	 *   FDT. This is partially implemented with live tree, but not with
-	 *   flat tree
+	 * Two fix this we need image_setup_libfdt() is updated to use ofnode
 	 */
-	fixup.tree.np = np;
 	ut_assertok(event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup)));
 
-	node = ofnode_path_root(fixup.tree, "/chosen/fwupd/firmware0");
+	node = oftree_path(fixup.tree, "/chosen/fwupd/firmware0");
 
 	version = ofnode_read_string(node, "cur-version");
 	ut_assertnonnull(version);
@@ -111,5 +107,4 @@
 
 	return 0;
 }
-BOOTSTD_TEST(vbe_simple_test_base, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
-	     UT_TESTF_LIVE_TREE);
+BOOTSTD_TEST(vbe_simple_test_base, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c
index f80993f..41811ec 100644
--- a/test/dm/ofnode.c
+++ b/test/dm/ofnode.c
@@ -1,4 +1,20 @@
 // SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 Google LLC
+ *
+ * There are two types of tests in this file:
+ * - normal ones which act on the control FDT (gd->fdt_blob or gd->of_root)
+ * - 'other' ones which act on the 'other' FDT (other.dts)
+ *
+ * The 'other' ones have an _ot suffix.
+ *
+ * The latter are used to check behaviour with multiple device trees,
+ * particularly with flat tree, where a tree ID is included in ofnode as part of
+ * the node offset. These tests are typically just for making sure that the
+ * offset makes it to libfdt correctly and that the resulting return value is
+ * correctly turned into an ofnode. The 'other' tests do not fully check the
+ * behaviour of each ofnode function, since that is done by the normal ones.
+ */
 
 #include <common.h>
 #include <dm.h>
@@ -13,6 +29,68 @@
 #include <test/test.h>
 #include <test/ut.h>
 
+/**
+ * get_other_oftree() - Convert a flat tree into an oftree object
+ *
+ * @uts: Test state
+ * @return: oftree object for the 'other' FDT (see sandbox' other.dts)
+ */
+oftree get_other_oftree(struct unit_test_state *uts)
+{
+	oftree tree;
+
+	if (of_live_active())
+		tree = oftree_from_np(uts->of_other);
+	else
+		tree = oftree_from_fdt(uts->other_fdt);
+
+	/* An invalid tree may cause failure or crashes */
+	if (!oftree_valid(tree))
+		ut_reportf("test needs the UT_TESTF_OTHER_FDT flag");
+
+	return tree;
+}
+
+/**
+ * get_oftree() - Convert a flat tree into an oftree object
+ *
+ * @uts: Test state
+ * @fdt: Pointer to flat tree
+ * @treep: Returns the tree, on success
+ * Return: 0 if OK, 1 if the tree failed to unflatten, -EOVERFLOW if there are
+ * too many flat trees to allow another one to be registers (see
+ * oftree_ensure())
+ */
+int get_oftree(struct unit_test_state *uts, void *fdt, oftree *treep)
+{
+	oftree tree;
+
+	if (of_live_active()) {
+		struct device_node *root;
+
+		ut_assertok(unflatten_device_tree(fdt, &root));
+		tree = oftree_from_np(root);
+	} else {
+		tree = oftree_from_fdt(fdt);
+		if (!oftree_valid(tree))
+			return -EOVERFLOW;
+	}
+	*treep = tree;
+
+	return 0;
+}
+
+/**
+ * free_oftree() - Free memory used by get_oftree()
+ *
+ * @tree: Tree to free
+ */
+void free_oftree(oftree tree)
+{
+	if (of_live_active())
+		free(tree.np);
+}
+
 static int dm_test_ofnode_compatible(struct unit_test_state *uts)
 {
 	ofnode root_node = ofnode_path("/");
@@ -22,7 +100,21 @@
 
 	return 0;
 }
-DM_TEST(dm_test_ofnode_compatible, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+DM_TEST(dm_test_ofnode_compatible,
+	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* check ofnode_device_is_compatible() with the 'other' FDT */
+static int dm_test_ofnode_compatible_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+	ofnode oroot = oftree_root(otree);
+
+	ut_assert(ofnode_valid(oroot));
+	ut_assert(ofnode_device_is_compatible(oroot, "sandbox-other"));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_compatible_ot, UT_TESTF_OTHER_FDT);
 
 static int dm_test_ofnode_get_by_phandle(struct unit_test_state *uts)
 {
@@ -36,37 +128,76 @@
 	/* test unknown phandle */
 	ut_assert(!ofnode_valid(ofnode_get_by_phandle(0x1000000)));
 
+	ut_assert(ofnode_valid(oftree_get_by_phandle(oftree_default(), 1)));
+
 	return 0;
 }
 DM_TEST(dm_test_ofnode_get_by_phandle, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
 
-static int dm_test_ofnode_by_prop_value(struct unit_test_state *uts)
+static int dm_test_ofnode_get_by_phandle_ot(struct unit_test_state *uts)
 {
-	const char propname[] = "compatible";
-	const char propval[] = "denx,u-boot-fdt-test";
+	oftree otree = get_other_oftree(uts);
+	ofnode node;
+
+	ut_assert(ofnode_valid(oftree_get_by_phandle(oftree_default(), 1)));
+	node = oftree_get_by_phandle(otree, 1);
+	ut_assert(ofnode_valid(node));
+	ut_asserteq_str("target", ofnode_get_name(node));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_get_by_phandle_ot, UT_TESTF_OTHER_FDT);
+
+static int check_prop_values(struct unit_test_state *uts, ofnode start,
+			     const char *propname, const char *propval,
+			     int expect_count)
+{
+	int proplen = strlen(propval) + 1;
 	const char *str;
-	ofnode node = ofnode_null();
+	ofnode node;
+	int count;
 
 	/* Find first matching node, there should be at least one */
-	node = ofnode_by_prop_value(node, propname, propval, sizeof(propval));
+	node = ofnode_by_prop_value(start, propname, propval, proplen);
 	ut_assert(ofnode_valid(node));
 	str = ofnode_read_string(node, propname);
 	ut_assert(str && !strcmp(str, propval));
 
 	/* Find the rest of the matching nodes */
+	count = 1;
 	while (true) {
-		node = ofnode_by_prop_value(node, propname, propval,
-					    sizeof(propval));
+		node = ofnode_by_prop_value(node, propname, propval, proplen);
 		if (!ofnode_valid(node))
 			break;
 		str = ofnode_read_string(node, propname);
-		ut_assert(str && !strcmp(str, propval));
+		ut_asserteq_str(propval, str);
+		count++;
 	}
+	ut_asserteq(expect_count, count);
+
+	return 0;
+}
+
+static int dm_test_ofnode_by_prop_value(struct unit_test_state *uts)
+{
+	ut_assertok(check_prop_values(uts, ofnode_null(), "compatible",
+				      "denx,u-boot-fdt-test", 11));
 
 	return 0;
 }
 DM_TEST(dm_test_ofnode_by_prop_value, UT_TESTF_SCAN_FDT);
 
+static int dm_test_ofnode_by_prop_value_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+
+	ut_assertok(check_prop_values(uts, oftree_root(otree), "str-prop",
+				      "other", 2));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_by_prop_value_ot, UT_TESTF_OTHER_FDT);
+
 static int dm_test_ofnode_fmap(struct unit_test_state *uts)
 {
 	struct fmap_entry entry;
@@ -108,6 +239,25 @@
 }
 DM_TEST(dm_test_ofnode_read, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
 
+static int dm_test_ofnode_read_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+	const char *val;
+	ofnode node;
+	int size;
+
+	node = oftree_path(otree, "/node/subnode");
+	ut_assert(ofnode_valid(node));
+
+	val = ofnode_read_prop(node, "str-prop", &size);
+	ut_assertnonnull(val);
+	ut_asserteq_str("other", val);
+	ut_asserteq(6, size);
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_read_ot, UT_TESTF_OTHER_FDT);
+
 static int dm_test_ofnode_phandle(struct unit_test_state *uts)
 {
 	struct ofnode_phandle_args args;
@@ -183,6 +333,34 @@
 }
 DM_TEST(dm_test_ofnode_phandle, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
 
+static int dm_test_ofnode_phandle_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+	struct ofnode_phandle_args args;
+	ofnode node;
+	int ret;
+
+	node = oftree_path(otree, "/node");
+
+	/* Test ofnode_count_phandle_with_args with cell name */
+	ret = ofnode_count_phandle_with_args(node, "missing", "#gpio-cells", 0);
+	ut_asserteq(-ENOENT, ret);
+	ret = ofnode_count_phandle_with_args(node, "target", "#invalid", 0);
+	ut_asserteq(-EINVAL, ret);
+	ret = ofnode_count_phandle_with_args(node, "target", "#gpio-cells", 0);
+	ut_asserteq(1, ret);
+
+	ret = ofnode_parse_phandle_with_args(node, "target", "#gpio-cells", 0,
+					     0, &args);
+	ut_assertok(ret);
+	ut_asserteq(2, args.args_count);
+	ut_asserteq(3, args.args[0]);
+	ut_asserteq(4, args.args[1]);
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_phandle_ot, UT_TESTF_OTHER_FDT);
+
 static int dm_test_ofnode_read_chosen(struct unit_test_state *uts)
 {
 	const char *str;
@@ -255,6 +433,27 @@
 DM_TEST(dm_test_ofnode_get_child_count,
 	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
 
+static int dm_test_ofnode_get_child_count_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+	ofnode node, child_node;
+	u32 val;
+
+	node = oftree_path(otree, "/node");
+	ut_assert(ofnode_valid(node));
+
+	val = ofnode_get_child_count(node);
+	ut_asserteq(2, val);
+
+	child_node = ofnode_first_subnode(node);
+	ut_assert(ofnode_valid(child_node));
+	val = ofnode_get_child_count(child_node);
+	ut_asserteq(0, val);
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_get_child_count_ot, UT_TESTF_OTHER_FDT);
+
 static int dm_test_ofnode_is_enabled(struct unit_test_state *uts)
 {
 	ofnode root_node = ofnode_path("/");
@@ -267,6 +466,19 @@
 }
 DM_TEST(dm_test_ofnode_is_enabled, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
 
+static int dm_test_ofnode_is_enabled_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+	ofnode root_node = oftree_root(otree);
+	ofnode node = oftree_path(otree, "/target");
+
+	ut_assert(ofnode_is_enabled(root_node));
+	ut_assert(!ofnode_is_enabled(node));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_is_enabled_ot, UT_TESTF_OTHER_FDT);
+
 static int dm_test_ofnode_get_reg(struct unit_test_state *uts)
 {
 	ofnode node;
@@ -303,27 +515,59 @@
 }
 DM_TEST(dm_test_ofnode_get_reg, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
 
+static int dm_test_ofnode_get_reg_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+	ofnode node = oftree_path(otree, "/target");
+	fdt_addr_t addr;
+
+	addr = ofnode_get_addr(node);
+	ut_asserteq(0x8000, addr);
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_get_reg_ot, UT_TESTF_OTHER_FDT);
+
 static int dm_test_ofnode_get_path(struct unit_test_state *uts)
 {
 	const char *path = "/translation-test@8000/noxlatebus@3,300/dev@42";
 	char buf[64];
 	ofnode node;
-	int res;
 
 	node = ofnode_path(path);
 	ut_assert(ofnode_valid(node));
 
-	res = ofnode_get_path(node, buf, 64);
-	ut_asserteq(0, res);
+	ut_assertok(ofnode_get_path(node, buf, sizeof(buf)));
 	ut_asserteq_str(path, buf);
 
-	res = ofnode_get_path(node, buf, 32);
-	ut_asserteq(-ENOSPC, res);
+	ut_asserteq(-ENOSPC, ofnode_get_path(node, buf, 32));
+
+	ut_assertok(ofnode_get_path(ofnode_root(), buf, 32));
+	ut_asserteq_str("/", buf);
 
 	return 0;
 }
 DM_TEST(dm_test_ofnode_get_path, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
 
+static int dm_test_ofnode_get_path_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+	const char *path = "/node/subnode";
+	ofnode node = oftree_path(otree, path);
+	char buf[64];
+
+	ut_assert(ofnode_valid(node));
+
+	ut_assertok(ofnode_get_path(node, buf, sizeof(buf)));
+	ut_asserteq_str(path, buf);
+
+	ut_assertok(ofnode_get_path(oftree_root(otree), buf, 32));
+	ut_asserteq_str("/", buf);
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_get_path_ot, UT_TESTF_OTHER_FDT);
+
 static int dm_test_ofnode_conf(struct unit_test_state *uts)
 {
 	ut_assert(!ofnode_conf_read_bool("missing"));
@@ -483,13 +727,17 @@
  * @uts: Test state
  * @fdt: Place to write FDT
  * @size: Maximum size of space for fdt
+ * @id: id value to add to the tree ('id' property in root node)
  */
-static int make_ofnode_fdt(struct unit_test_state *uts, void *fdt, int size)
+static int make_ofnode_fdt(struct unit_test_state *uts, void *fdt, int size,
+			   int id)
 {
 	ut_assertok(fdt_create(fdt, size));
 	ut_assertok(fdt_finish_reservemap(fdt));
 	ut_assert(fdt_begin_node(fdt, "") >= 0);
 
+	ut_assertok(fdt_property_u32(fdt, "id", id));
+
 	ut_assert(fdt_begin_node(fdt, "aliases") >= 0);
 	ut_assertok(fdt_property_string(fdt, "mmc0", "/new-mmc"));
 	ut_assertok(fdt_end_node(fdt));
@@ -505,37 +753,41 @@
 
 static int dm_test_ofnode_root(struct unit_test_state *uts)
 {
-	struct device_node *root = NULL;
 	char fdt[256];
 	oftree tree;
 	ofnode node;
+	int ret;
 
 	/* Check that aliases work on the control FDT */
 	node = ofnode_get_aliases_node("ethernet3");
 	ut_assert(ofnode_valid(node));
 	ut_asserteq_str("sbe5", ofnode_get_name(node));
 
-	ut_assertok(make_ofnode_fdt(uts, fdt, sizeof(fdt)));
-	if (of_live_active()) {
-		ut_assertok(unflatten_device_tree(fdt, &root));
-		tree.np = root;
-	} else {
-		tree.fdt = fdt;
-	}
+	ut_assert(!oftree_valid(oftree_null()));
+
+	ut_assertok(make_ofnode_fdt(uts, fdt, sizeof(fdt), 0));
+	ret = get_oftree(uts, fdt, &tree);
+
+	/* skip the rest of this test if multiple FDTs are not supported */
+	if (ret == -EOVERFLOW)
+		return 0;
+
+	ut_assertok(ret);
+	ut_assert(oftree_valid(tree));
 
 	/* Make sure they don't work on this new tree */
-	node = ofnode_path_root(tree, "mmc0");
+	node = oftree_path(tree, "mmc0");
 	ut_assert(!ofnode_valid(node));
 
 	/* It should appear in the new tree */
-	node = ofnode_path_root(tree, "/new-mmc");
+	node = oftree_path(tree, "/new-mmc");
 	ut_assert(ofnode_valid(node));
 
 	/* ...and not in the control FDT */
-	node = ofnode_path_root(oftree_default(), "/new-mmc");
+	node = oftree_path(oftree_default(), "/new-mmc");
 	ut_assert(!ofnode_valid(node));
 
-	free(root);
+	free_oftree(tree);
 
 	return 0;
 }
@@ -570,7 +822,8 @@
 	ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr(dev));
 	/* reg = 0x42, size = 0x100 */
 	ut_assertok(ofnode_write_prop(node, "reg",
-				      "\x00\x00\x00\x42\x00\x00\x01\x00", 8));
+				      "\x00\x00\x00\x42\x00\x00\x01\x00", 8,
+				      false));
 	ut_asserteq(0x42, dev_read_addr(dev));
 
 	/* Test disabling devices */
@@ -584,11 +837,71 @@
 	return 0;
 }
 DM_TEST(dm_test_ofnode_livetree_writing,
-	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT | UT_TESTF_LIVE_OR_FLAT);
+	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int check_write_prop(struct unit_test_state *uts, ofnode node)
+{
+	char prop[] = "middle-name";
+	char name[10];
+	int len;
+
+	strcpy(name, "cecil");
+	len = strlen(name) + 1;
+	ut_assertok(ofnode_write_prop(node, prop, name, len, false));
+	ut_asserteq_str(name, ofnode_read_string(node, prop));
+
+	/* change the underlying value, this should mess up the live tree */
+	strcpy(name, "tony");
+	if (of_live_active()) {
+		ut_asserteq_str(name, ofnode_read_string(node, prop));
+	} else {
+		ut_asserteq_str("cecil", ofnode_read_string(node, prop));
+	}
+
+	/* try again, this time copying the property */
+	strcpy(name, "mary");
+	ut_assertok(ofnode_write_prop(node, prop, name, len, true));
+	ut_asserteq_str(name, ofnode_read_string(node, prop));
+	strcpy(name, "leah");
+
+	/* both flattree and livetree behave the same */
+	ut_asserteq_str("mary", ofnode_read_string(node, prop));
+
+	return 0;
+}
+
+/* writing the tree with and without copying the property */
+static int dm_test_ofnode_write_copy(struct unit_test_state *uts)
+{
+	ofnode node;
+
+	node = ofnode_path("/a-test");
+	ut_assertok(check_write_prop(uts, node));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_write_copy, UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_write_copy_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+	ofnode node, check_node;
+
+	node = oftree_path(otree, "/node");
+	ut_assertok(check_write_prop(uts, node));
+
+	/* make sure the control FDT is not touched */
+	check_node = ofnode_path("/node");
+	ut_assertnull(ofnode_read_string(check_node, "middle-name"));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_write_copy_ot, UT_TESTF_OTHER_FDT);
 
 static int dm_test_ofnode_u32(struct unit_test_state *uts)
 {
 	ofnode node;
+	u32 val;
 
 	node = ofnode_path("/lcd");
 	ut_assert(ofnode_valid(node));
@@ -597,7 +910,328 @@
 	ut_asserteq(1367, ofnode_read_u32_default(node, "xres", 123));
 	ut_assertok(ofnode_write_u32(node, "xres", 1366));
 
+	node = ofnode_path("/backlight");
+	ut_assertok(ofnode_read_u32_index(node, "brightness-levels", 0, &val));
+	ut_asserteq(0, val);
+	ut_assertok(ofnode_read_u32_index(node, "brightness-levels", 1, &val));
+	ut_asserteq(16, val);
+	ut_assertok(ofnode_read_u32_index(node, "brightness-levels", 8, &val));
+	ut_asserteq(255, val);
+	ut_asserteq(-EOVERFLOW,
+		    ofnode_read_u32_index(node, "brightness-levels", 9, &val));
+	ut_asserteq(-EINVAL, ofnode_read_u32_index(node, "missing", 0, &val));
+
 	return 0;
 }
-DM_TEST(dm_test_ofnode_u32,
-	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT | UT_TESTF_LIVE_OR_FLAT);
+DM_TEST(dm_test_ofnode_u32, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_u32_array(struct unit_test_state *uts)
+{
+	ofnode node;
+	u32 val[10];
+
+	node = ofnode_path("/a-test");
+	ut_assert(ofnode_valid(node));
+	ut_assertok(ofnode_read_u32_array(node, "int-value", val, 1));
+	ut_asserteq(-EINVAL, ofnode_read_u32_array(node, "missing", val, 1));
+	ut_asserteq(-EOVERFLOW, ofnode_read_u32_array(node, "bool-value", val,
+						      1));
+
+	memset(val, '\0', sizeof(val));
+	ut_assertok(ofnode_read_u32_array(node, "int-array", val + 1, 3));
+	ut_asserteq(0, val[0]);
+	ut_asserteq(5678, val[1]);
+	ut_asserteq(9123, val[2]);
+	ut_asserteq(4567, val[3]);
+	ut_asserteq(0, val[4]);
+	ut_asserteq(-EOVERFLOW, ofnode_read_u32_array(node, "int-array", val,
+						      4));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_u32_array, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_u64(struct unit_test_state *uts)
+{
+	ofnode node;
+	u64 val;
+
+	node = ofnode_path("/a-test");
+	ut_assert(ofnode_valid(node));
+	ut_assertok(ofnode_read_u64(node, "int64-value", &val));
+	ut_asserteq_64(0x1111222233334444, val);
+	ut_asserteq(-EINVAL, ofnode_read_u64(node, "missing", &val));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_u64, UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_add_subnode(struct unit_test_state *uts)
+{
+	ofnode node, check, subnode;
+	char buf[128];
+
+	node = ofnode_path("/lcd");
+	ut_assert(ofnode_valid(node));
+	ut_assertok(ofnode_add_subnode(node, "edmund", &subnode));
+	check = ofnode_path("/lcd/edmund");
+	ut_asserteq(subnode.of_offset, check.of_offset);
+	ut_assertok(ofnode_get_path(subnode, buf, sizeof(buf)));
+	ut_asserteq_str("/lcd/edmund", buf);
+
+	if (of_live_active()) {
+		struct device_node *child;
+
+		ut_assertok(of_add_subnode((void *)ofnode_to_np(node), "edmund",
+					   2, &child));
+		ut_asserteq_str("ed", child->name);
+		ut_asserteq_str("/lcd/ed", child->full_name);
+		check = ofnode_path("/lcd/ed");
+		ut_asserteq_ptr(child, check.np);
+		ut_assertok(ofnode_get_path(np_to_ofnode(child), buf,
+					    sizeof(buf)));
+		ut_asserteq_str("/lcd/ed", buf);
+	}
+
+	/* An existing node should be returned with -EEXIST */
+	ut_asserteq(-EEXIST, ofnode_add_subnode(node, "edmund", &check));
+	ut_asserteq(subnode.of_offset, check.of_offset);
+
+	/* add a root node */
+	node = ofnode_path("/");
+	ut_assert(ofnode_valid(node));
+	ut_assertok(ofnode_add_subnode(node, "lcd2", &subnode));
+	check = ofnode_path("/lcd2");
+	ut_asserteq(subnode.of_offset, check.of_offset);
+	ut_assertok(ofnode_get_path(subnode, buf, sizeof(buf)));
+	ut_asserteq_str("/lcd2", buf);
+
+	if (of_live_active()) {
+		ulong start;
+		int i;
+
+		/*
+		 * Make sure each of the three malloc()checks in
+		 * of_add_subnode() work
+		 */
+		for (i = 0; i < 3; i++) {
+			malloc_enable_testing(i);
+			start = ut_check_free();
+			ut_asserteq(-ENOMEM, ofnode_add_subnode(node, "anthony",
+								&check));
+			ut_assertok(ut_check_delta(start));
+		}
+
+		/* This should pass since we allow 3 allocations */
+		malloc_enable_testing(3);
+		ut_assertok(ofnode_add_subnode(node, "anthony", &check));
+		malloc_disable_testing();
+	}
+
+	/* write to the empty node */
+	ut_assertok(ofnode_write_string(subnode, "example", "text"));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_add_subnode, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_for_each_prop(struct unit_test_state *uts)
+{
+	ofnode node, subnode;
+	struct ofprop prop;
+	int count;
+
+	node = ofnode_path("/buttons");
+	count = 0;
+
+	/* we expect "compatible" for each node */
+	ofnode_for_each_prop(prop, node)
+		count++;
+	ut_asserteq(1, count);
+
+	/* there are two nodes, each with 2 properties */
+	ofnode_for_each_subnode(subnode, node)
+		ofnode_for_each_prop(prop, subnode)
+			count++;
+	ut_asserteq(5, count);
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_for_each_prop, UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_by_compatible(struct unit_test_state *uts)
+{
+	const char *compat = "denx,u-boot-fdt-test";
+	ofnode node;
+	int count;
+
+	count = 0;
+	for (node = ofnode_null();
+	     node = ofnode_by_compatible(node, compat), ofnode_valid(node);)
+		count++;
+	ut_asserteq(11, count);
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_by_compatible, UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_by_compatible_ot(struct unit_test_state *uts)
+{
+	const char *compat = "sandbox-other2";
+	oftree otree = get_other_oftree(uts);
+	ofnode node;
+	int count;
+
+	count = 0;
+	for (node = oftree_root(otree);
+	     node = ofnode_by_compatible(node, compat), ofnode_valid(node);)
+		count++;
+	ut_asserteq(2, count);
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_by_compatible_ot, UT_TESTF_OTHER_FDT);
+
+static int dm_test_ofnode_find_subnode(struct unit_test_state *uts)
+{
+	ofnode node, subnode;
+
+	node = ofnode_path("/buttons");
+
+	subnode = ofnode_find_subnode(node, "btn1");
+	ut_assert(ofnode_valid(subnode));
+	ut_asserteq_str("btn1", ofnode_get_name(subnode));
+
+	subnode = ofnode_find_subnode(node, "btn");
+	ut_assert(!ofnode_valid(subnode));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_find_subnode, UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_find_subnode_ot(struct unit_test_state *uts)
+{
+	oftree otree = get_other_oftree(uts);
+	ofnode node, subnode;
+
+	node = oftree_path(otree, "/node");
+
+	subnode = ofnode_find_subnode(node, "subnode");
+	ut_assert(ofnode_valid(subnode));
+	ut_asserteq_str("subnode", ofnode_get_name(subnode));
+
+	subnode = ofnode_find_subnode(node, "btn");
+	ut_assert(!ofnode_valid(subnode));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_find_subnode_ot, UT_TESTF_OTHER_FDT);
+
+static int dm_test_ofnode_get_name(struct unit_test_state *uts)
+{
+	ofnode node;
+
+	node = ofnode_path("/buttons");
+	ut_assert(ofnode_valid(node));
+	ut_asserteq_str("buttons", ofnode_get_name(node));
+	ut_asserteq_str("", ofnode_get_name(ofnode_root()));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_get_name, UT_TESTF_SCAN_FDT);
+
+/* try to access more FDTs than is supported */
+static int dm_test_ofnode_too_many(struct unit_test_state *uts)
+{
+	const int max_trees = CONFIG_IS_ENABLED(OFNODE_MULTI_TREE,
+					(CONFIG_OFNODE_MULTI_TREE_MAX), (1));
+	const int fdt_size = 256;
+	const int num_trees = max_trees + 1;
+	char fdt[num_trees][fdt_size];
+	int i;
+
+	for (i = 0; i < num_trees; i++) {
+		oftree tree;
+		int ret;
+
+		ut_assertok(make_ofnode_fdt(uts, fdt[i], fdt_size, i));
+		ret = get_oftree(uts, fdt[i], &tree);
+
+		/*
+		 * With flat tree we have the control FDT using one slot. Live
+		 * tree has no limit since it uses pointers, not integer tree
+		 * IDs
+		 */
+		if (of_live_active() || i < max_trees - 1) {
+			ut_assertok(ret);
+		} else {
+			/*
+			 * tree should be invalid when we try to register too
+			 * many trees
+			 */
+			ut_asserteq(-EOVERFLOW, ret);
+		}
+	}
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_too_many, UT_TESTF_SCAN_FDT);
+
+static int check_copy_props(struct unit_test_state *uts, ofnode src,
+			    ofnode dst)
+{
+	u32 reg[2], val;
+
+	ut_assertok(ofnode_copy_props(src, dst));
+
+	ut_assertok(ofnode_read_u32(dst, "ping-expect", &val));
+	ut_asserteq(3, val);
+
+	ut_asserteq_str("denx,u-boot-fdt-test",
+			ofnode_read_string(dst, "compatible"));
+
+	/* check that a property with the same name is overwritten */
+	ut_assertok(ofnode_read_u32_array(dst, "reg", reg, ARRAY_SIZE(reg)));
+	ut_asserteq(3, reg[0]);
+	ut_asserteq(1, reg[1]);
+
+	/* reset the compatible so the live tree does not change */
+	ut_assertok(ofnode_write_string(dst, "compatible", "nothing"));
+
+	return 0;
+}
+
+static int dm_test_ofnode_copy_props(struct unit_test_state *uts)
+{
+	ofnode src, dst;
+
+	/*
+	 * These nodes are chosen so that the src node is before the destination
+	 * node in the tree. This doesn't matter with livetree, but with
+	 * flattree any attempt to insert a property earlier in the tree will
+	 * mess up the offsets after it.
+	 */
+	src = ofnode_path("/b-test");
+	dst = ofnode_path("/some-bus");
+
+	ut_assertok(check_copy_props(uts, src, dst));
+
+	/* check a property that is in the destination already */
+	ut_asserteq_str("mux0", ofnode_read_string(dst, "mux-control-names"));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_copy_props, UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_copy_props_ot(struct unit_test_state *uts)
+{
+	ofnode src, dst;
+	oftree otree = get_other_oftree(uts);
+
+	src = ofnode_path("/b-test");
+	dst = oftree_path(otree, "/node/subnode2");
+	ut_assertok(check_copy_props(uts, src, dst));
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_copy_props_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT);
diff --git a/test/dm/ofread.c b/test/dm/ofread.c
index 8c7dd82..3523860 100644
--- a/test/dm/ofread.c
+++ b/test/dm/ofread.c
@@ -5,7 +5,7 @@
 #include <dm/test.h>
 #include <test/ut.h>
 
-static int dm_test_ofnode_get_property_by_prop(struct unit_test_state *uts)
+static int dm_test_ofprop_get_property(struct unit_test_state *uts)
 {
 	ofnode node;
 	struct ofprop prop;
@@ -14,10 +14,10 @@
 	int res, len, count = 0;
 
 	node = ofnode_path("/cros-ec/flash");
-	for (res = ofnode_get_first_property(node, &prop);
+	for (res = ofnode_first_property(node, &prop);
 	     !res;
-	     res = ofnode_get_next_property(&prop)) {
-		value = ofnode_get_property_by_prop(&prop, &propname, &len);
+	     res = ofnode_next_property(&prop)) {
+		value = ofprop_get_property(&prop, &propname, &len);
 		ut_assertnonnull(value);
 		switch (count) {
 		case 0:
@@ -46,5 +46,4 @@
 
 	return 0;
 }
-DM_TEST(dm_test_ofnode_get_property_by_prop,
-	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+DM_TEST(dm_test_ofprop_get_property, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/image/spl_load.c b/test/image/spl_load.c
index df389e2..4e27ff4 100644
--- a/test/image/spl_load.c
+++ b/test/image/spl_load.c
@@ -49,7 +49,7 @@
 	return 0;
 }
 
-struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size)
 {
 	return map_sysmem(0x100000, 0);
 }
@@ -57,7 +57,7 @@
 static int spl_test_load(struct unit_test_state *uts)
 {
 	struct spl_image_info image;
-	struct image_header *header;
+	struct legacy_img_hdr *header;
 	struct text_ctx text_ctx;
 	struct spl_load_info load;
 	char fname[256];
diff --git a/test/test-main.c b/test/test-main.c
index ae34002..d74df29 100644
--- a/test/test-main.c
+++ b/test/test-main.c
@@ -9,14 +9,53 @@
 #include <cyclic.h>
 #include <dm.h>
 #include <event.h>
+#include <of_live.h>
+#include <os.h>
+#include <dm/ofnode.h>
 #include <dm/root.h>
 #include <dm/test.h>
 #include <dm/uclass-internal.h>
 #include <test/test.h>
 #include <test/ut.h>
+#include <u-boot/crc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/**
+ * enum fdtchk_t - what to do with the device tree (gd->fdt_blob)
+ *
+ * This affects what happens with the device tree before and after a test
+ *
+ * @FDTCHK_NONE: Do nothing
+ * @FDTCHK_CHECKSUM: Take a checksum of the FDT before the test runs and
+ *	compare it afterwards to detect any changes
+ * @FDTCHK_COPY: Make a copy of the FDT and restore it afterwards
+ */
+enum fdtchk_t {
+	FDTCHK_NONE,
+	FDTCHK_CHECKSUM,
+	FDTCHK_COPY,
+};
+
+/**
+ * fdt_action() - get the required action for the FDT
+ *
+ * @return the action that should be taken for this build
+ */
+static enum fdtchk_t fdt_action(void)
+{
+	/* Do a copy for sandbox (but only the U-Boot build, not SPL) */
+	if (CONFIG_IS_ENABLED(SANDBOX))
+		return FDTCHK_COPY;
+
+	/* For sandbox SPL builds, do nothing */
+	if (IS_ENABLED(CONFIG_SANDBOX))
+		return FDTCHK_NONE;
+
+	/* For all other boards, do a checksum */
+	return FDTCHK_CHECKSUM;
+}
+
 /* This is valid when a test is running, NULL otherwise */
 static struct unit_test_state *cur_test_state;
 
@@ -42,17 +81,26 @@
 {
 	bool of_live = uts->of_live;
 
+	if (of_live && (gd->flags & GD_FLG_FDT_CHANGED)) {
+		printf("Cannot run live tree test as device tree changed\n");
+		return -EFAULT;
+	}
 	uts->root = NULL;
 	uts->testdev = NULL;
 	uts->force_fail_alloc = false;
 	uts->skip_post_probe = false;
+	if (fdt_action() == FDTCHK_CHECKSUM)
+		uts->fdt_chksum = crc8(0, gd->fdt_blob,
+				       fdt_totalsize(gd->fdt_blob));
 	gd->dm_root = NULL;
+	malloc_disable_testing();
 	if (CONFIG_IS_ENABLED(UT_DM) && !CONFIG_IS_ENABLED(OF_PLATDATA))
 		memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count));
 	arch_reset_for_test();
 
 	/* Determine whether to make the live tree available */
 	gd_set_of_root(of_live ? uts->of_root : NULL);
+	oftree_reset();
 	ut_assertok(dm_init(of_live));
 	uts->root = dm_root();
 
@@ -63,6 +111,33 @@
 {
 	int id;
 
+	if (gd->fdt_blob) {
+		switch (fdt_action()) {
+		case FDTCHK_COPY:
+			memcpy((void *)gd->fdt_blob, uts->fdt_copy, uts->fdt_size);
+			break;
+		case FDTCHK_CHECKSUM: {
+			uint chksum;
+
+			chksum = crc8(0, gd->fdt_blob, fdt_totalsize(gd->fdt_blob));
+			if (chksum != uts->fdt_chksum) {
+				/*
+				 * We cannot run any more tests that need the
+				 * live tree, since its strings point into the
+				 * flat tree, which has changed. This likely
+				 * means that at least some of the pointers from
+				 * the live tree point to different things
+				 */
+				printf("Device tree changed: cannot run live tree tests\n");
+				gd->flags |= GD_FLG_FDT_CHANGED;
+			}
+			break;
+		}
+		case FDTCHK_NONE:
+			break;
+		}
+	}
+
 	/*
 	 * With of-platdata-inst the uclasses are created at build time. If we
 	 * destroy them we cannot get them back since uclass_add() is not
@@ -242,6 +317,20 @@
 	    (test->flags & UT_TESTF_SCAN_FDT))
 		ut_assertok(dm_extended_scan(false));
 
+	if (IS_ENABLED(CONFIG_SANDBOX) && (test->flags & UT_TESTF_OTHER_FDT)) {
+		/* make sure the other FDT is available */
+		ut_assertok(test_load_other_fdt(uts));
+
+		/*
+		 * create a new live tree with it for every test, in case a
+		 * test modifies the tree
+		 */
+		if (of_live_active()) {
+			ut_assertok(unflatten_device_tree(uts->other_fdt,
+							  &uts->of_other));
+		}
+	}
+
 	if (test->flags & UT_TESTF_CONSOLE_REC) {
 		int ret = console_record_reset_enable();
 
@@ -270,6 +359,9 @@
 	ut_assertok(cyclic_uninit());
 	ut_assertok(event_uninit());
 
+	free(uts->of_other);
+	uts->of_other = NULL;
+
 	return 0;
 }
 
@@ -340,11 +432,13 @@
 {
 	int runs;
 
+	if ((test->flags & UT_TESTF_OTHER_FDT) && !IS_ENABLED(CONFIG_SANDBOX))
+		return -EAGAIN;
+
 	/* Run with the live tree if possible */
 	runs = 0;
 	if (CONFIG_IS_ENABLED(OF_LIVE)) {
-		if (!(test->flags &
-		    (UT_TESTF_FLAT_TREE | UT_TESTF_LIVE_OR_FLAT))) {
+		if (!(test->flags & UT_TESTF_FLAT_TREE)) {
 			uts->of_live = true;
 			ut_assertok(ut_run_test(uts, test, test->name));
 			runs++;
@@ -352,11 +446,22 @@
 	}
 
 	/*
-	 * Run with the flat tree if we couldn't run it with live tree,
-	 * or it is a core test.
+	 * Run with the flat tree if:
+	 * - it is not marked for live tree only
+	 * - it doesn't require the 'other' FDT when OFNODE_MULTI_TREE_MAX is
+	 *   not enabled (since flat tree can only support a single FDT in that
+	 *   case
+	 * - we couldn't run it with live tree,
+	 * - it is a core test (dm tests except video)
+	 * - the FDT is still valid and has not been updated by an earlier test
+	 *   (for sandbox we handle this by copying the tree, but not for other
+	 *    boards)
 	 */
 	if (!(test->flags & UT_TESTF_LIVE_TREE) &&
-	    (!runs || ut_test_run_on_flattree(test))) {
+	    (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) ||
+	     !(test->flags & UT_TESTF_OTHER_FDT)) &&
+	    (!runs || ut_test_run_on_flattree(test)) &&
+	    !(gd->flags & GD_FLG_FDT_CHANGED)) {
 		uts->of_live = false;
 		ut_assertok(ut_run_test(uts, test, test->name));
 		runs++;
@@ -443,8 +548,25 @@
 
 	uts.of_root = gd_of_root();
 	uts.runs_per_test = runs_per_test;
+	if (fdt_action() == FDTCHK_COPY && gd->fdt_blob) {
+		uts.fdt_size = fdt_totalsize(gd->fdt_blob);
+		uts.fdt_copy = os_malloc(uts.fdt_size);
+		if (!uts.fdt_copy) {
+			printf("Out of memory for device tree copy\n");
+			return -ENOMEM;
+		}
+		memcpy(uts.fdt_copy, gd->fdt_blob, uts.fdt_size);
+	}
 	ret = ut_run_tests(&uts, prefix, tests, count, select_name);
 
+	/* Best efforts only...ignore errors */
+	if (has_dm_tests)
+		dm_test_restore(uts.of_root);
+	if (IS_ENABLED(CONFIG_SANDBOX)) {
+		os_free(uts.fdt_copy);
+		os_free(uts.other_fdt);
+	}
+
 	if (ret == -ENOENT)
 		printf("Test '%s' not found\n", select_name);
 	else
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index ecb3595..261107b 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -5782,7 +5782,7 @@
         # Check that the data appears in the file somewhere
         self.assertIn(U_BOOT_SPL_DATA, data)
 
-        # Get struct image_header -> ih_name
+        # Get struct legacy_img_hdr -> ih_name
         name = data[0x20:0x40]
 
         # Build the filename that we expect to be placed in there, by virtue of
@@ -5799,7 +5799,7 @@
         # Check that the data appears in the file somewhere
         self.assertIn(U_BOOT_SPL_DATA, data)
 
-        # Get struct image_header -> ih_name
+        # Get struct legacy_img_hdr -> ih_name
         name = data[0x20:0x40]
 
         # Build the filename that we expect to be placed in there, by virtue of
diff --git a/tools/default_image.c b/tools/default_image.c
index e164c0c..4a067e6 100644
--- a/tools/default_image.c
+++ b/tools/default_image.c
@@ -22,7 +22,7 @@
 #include <u-boot/crc.h>
 #include <imximage.h>
 
-static image_header_t header;
+static struct legacy_img_hdr header;
 
 static int image_check_image_types(uint8_t type)
 {
@@ -46,15 +46,15 @@
 	uint32_t len;
 	const unsigned char *data;
 	uint32_t checksum;
-	image_header_t header;
-	image_header_t *hdr = &header;
+	struct legacy_img_hdr header;
+	struct legacy_img_hdr *hdr = &header;
 
 	/*
 	 * create copy of header so that we can blank out the
 	 * checksum field for checking - this can't be done
 	 * on the PROT_READ mapped data.
 	 */
-	memcpy(hdr, ptr, sizeof(image_header_t));
+	memcpy(hdr, ptr, sizeof(struct legacy_img_hdr));
 
 	if (be32_to_cpu(hdr->ih_magic) != IH_MAGIC) {
 		debug("%s: Bad Magic Number: \"%s\" is no valid image\n",
@@ -63,7 +63,7 @@
 	}
 
 	data = (const unsigned char *)hdr;
-	len  = sizeof(image_header_t);
+	len  = sizeof(struct legacy_img_hdr);
 
 	checksum = be32_to_cpu(hdr->ih_hcrc);
 	hdr->ih_hcrc = cpu_to_be32(0);	/* clear for re-calculation */
@@ -74,8 +74,8 @@
 		return -FDT_ERR_BADSTATE;
 	}
 
-	data = (const unsigned char *)ptr + sizeof(image_header_t);
-	len  = image_size - sizeof(image_header_t) ;
+	data = (const unsigned char *)ptr + sizeof(struct legacy_img_hdr);
+	len  = image_size - sizeof(struct legacy_img_hdr);
 
 	checksum = be32_to_cpu(hdr->ih_dcrc);
 	if (crc32(0, data, len) != checksum) {
@@ -94,13 +94,12 @@
 	uint32_t imagesize;
 	uint32_t ep;
 	uint32_t addr;
-
-	image_header_t * hdr = (image_header_t *)ptr;
+	struct legacy_img_hdr *hdr = (struct legacy_img_hdr *)ptr;
 
 	checksum = crc32(0,
 			(const unsigned char *)(ptr +
-				sizeof(image_header_t)),
-			sbuf->st_size - sizeof(image_header_t));
+				sizeof(struct legacy_img_hdr)),
+			sbuf->st_size - sizeof(struct legacy_img_hdr));
 
 	time = imagetool_get_source_date(params->cmdname, sbuf->st_mtime);
 	ep = params->ep;
@@ -108,11 +107,11 @@
 
 	if (params->type == IH_TYPE_FIRMWARE_IVT)
 		/* Add size of CSF minus IVT */
-		imagesize = sbuf->st_size - sizeof(image_header_t)
+		imagesize = sbuf->st_size - sizeof(struct legacy_img_hdr)
 			    + 0x2060 - sizeof(flash_header_v2_t);
 
 	else
-		imagesize = sbuf->st_size - sizeof(image_header_t);
+		imagesize = sbuf->st_size - sizeof(struct legacy_img_hdr);
 
 	if (params->os == IH_OS_TEE) {
 		addr = optee_image_get_load_addr(hdr);
@@ -134,14 +133,14 @@
 	image_set_name(hdr, params->imagename);
 
 	checksum = crc32(0, (const unsigned char *)hdr,
-				sizeof(image_header_t));
+				sizeof(struct legacy_img_hdr));
 
 	image_set_hcrc(hdr, checksum);
 }
 
 static int image_extract_subimage(void *ptr, struct image_tool_params *params)
 {
-	const image_header_t *hdr = (const image_header_t *)ptr;
+	const struct legacy_img_hdr *hdr = (const struct legacy_img_hdr *)ptr;
 	ulong file_data;
 	ulong file_len;
 
@@ -175,7 +174,7 @@
 U_BOOT_IMAGE_TYPE(
 	defimage,
 	"Default Image support",
-	sizeof(image_header_t),
+	sizeof(struct legacy_img_hdr),
 	(void *)&header,
 	image_check_params,
 	image_verify_header,
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 979f241..923a975 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -22,7 +22,7 @@
 #include <version.h>
 #include <u-boot/crc.h>
 
-static image_header_t header;
+static struct legacy_img_hdr header;
 
 static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
 			     const char *tmpfile)
@@ -915,7 +915,7 @@
 U_BOOT_IMAGE_TYPE(
 	fitimage,
 	"FIT Image support",
-	sizeof(image_header_t),
+	sizeof(struct legacy_img_hdr),
 	(void *)&header,
 	fit_check_params,
 	fit_verify_header,
diff --git a/tools/imx8mimage.c b/tools/imx8mimage.c
index a4699de..35d0a92 100644
--- a/tools/imx8mimage.c
+++ b/tools/imx8mimage.c
@@ -318,7 +318,7 @@
 static int generate_ivt_for_fit(int fd, int fit_offset, uint32_t ep,
 				uint32_t *fit_load_addr)
 {
-	image_header_t image_header;
+	struct legacy_img_hdr image_header;
 	int ret;
 
 	uint32_t fit_size, load_addr;
@@ -330,8 +330,8 @@
 		exit(EXIT_FAILURE);
 	}
 
-	if (read(fd, (char *)&image_header, sizeof(image_header_t)) !=
-	    sizeof(image_header_t)) {
+	if (read(fd, (char *)&image_header, sizeof(struct legacy_img_hdr)) !=
+	    sizeof(struct legacy_img_hdr)) {
 		fprintf(stderr, "generate_ivt_for_fit read failed: %s\n",
 			strerror(errno));
 		exit(EXIT_FAILURE);
@@ -600,7 +600,7 @@
 			close(sld_fd);
 
 			file_off = sld_header_off;
-			file_off += sbuf.st_size + sizeof(image_header_t);
+			file_off += sbuf.st_size + sizeof(struct legacy_img_hdr);
 		}
 	}
 
diff --git a/tools/mkimage.c b/tools/mkimage.c
index 597cb3a..30c6df7 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -845,7 +845,7 @@
 	if (params.xflag) {
 		unsigned char *p = NULL;
 		/*
-		 * XIP: do not append the image_header_t at the
+		 * XIP: do not append the struct legacy_img_hdr at the
 		 * beginning of the file, but consume the space
 		 * reserved for it.
 		 */
diff --git a/tools/mtk_image.c b/tools/mtk_image.c
index 9b3136a..5ef9334 100644
--- a/tools/mtk_image.c
+++ b/tools/mtk_image.c
@@ -427,10 +427,10 @@
 
 static int mtk_image_verify_mt7621_header(const uint8_t *ptr, int print)
 {
-	const image_header_t *hdr = (const image_header_t *)ptr;
+	const struct legacy_img_hdr *hdr = (const struct legacy_img_hdr *)ptr;
 	struct mt7621_nand_header *nhdr;
 	uint32_t spl_size, crcval;
-	image_header_t header;
+	struct legacy_img_hdr header;
 	int ret;
 
 	spl_size = image_get_size(hdr);
@@ -490,7 +490,7 @@
 static int mtk_image_verify_header(unsigned char *ptr, int image_size,
 				   struct image_tool_params *params)
 {
-	image_header_t *hdr = (image_header_t *)ptr;
+	struct legacy_img_hdr *hdr = (struct legacy_img_hdr *)ptr;
 	union lk_hdr *lk = (union lk_hdr *)ptr;
 
 	/* nothing to verify for LK image header */
@@ -512,7 +512,7 @@
 
 static void mtk_image_print_header(const void *ptr)
 {
-	image_header_t *hdr = (image_header_t *)ptr;
+	struct legacy_img_hdr *hdr = (struct legacy_img_hdr *)ptr;
 	union lk_hdr *lk = (union lk_hdr *)ptr;
 
 	if (le32_to_cpu(lk->magic) == LK_PART_MAGIC) {
@@ -691,7 +691,7 @@
 static void mtk_image_set_mt7621_header(void *ptr, off_t filesize,
 					uint32_t loadaddr)
 {
-	image_header_t *hdr = (image_header_t *)ptr;
+	struct legacy_img_hdr *hdr = (struct legacy_img_hdr *)ptr;
 	struct mt7621_stage1_header *shdr;
 	struct mt7621_nand_header *nhdr;
 	uint32_t datasize, crcval;