Merge git://git.denx.de/u-boot-x86
diff --git a/.travis.yml b/.travis.yml
index 00b2a73..a1564ed 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -138,6 +138,12 @@
     - env:
         - BUILDMAN="aries"
     - env:
+        - JOB="Boundary Devices"
+          BUILDMAN="boundary"
+    - env:
+        - JOB="engicam"
+          BUILDMAN="engicam"
+    - env:
         - JOB="Freescale ARM32"
           BUILDMAN="freescale -x powerpc,m68k,aarch64"
     - env:
@@ -145,13 +151,17 @@
           BUILDMAN="freescale&aarch64"
     - env:
         - JOB="i.MX6 (non-Freescale)"
-          BUILDMAN="mx6 -x freescale"
+          BUILDMAN="mx6 -x freescale,toradex,boundary,engicam"
     - env:
         - JOB="i.MX (non-Freescale, non-i.MX6)"
-          BUILDMAN="mx -x freescale,mx6"
+          BUILDMAN="mx -x freescale,mx6,toradex"
+    - env:
+        - BUILDMAN="k2"
     - env:
         - BUILDMAN="samsung"
     - env:
+        - BUILDMAN="socfpga"
+    - env:
         - BUILDMAN="sun4i"
     - env:
         - BUILDMAN="sun5i"
@@ -167,21 +177,25 @@
         - BUILDMAN="sun50i"
     - env:
         - JOB="Catch-all ARM"
-          BUILDMAN="arm -x arm11,arm7,arm9,aarch64,atmel,aries,freescale,kirkwood,mvebu,siemens,tegra,uniphier,mx,samsung,sunxi,am33xx,omap3,omap4,omap5,pxa,rockchip"
+          BUILDMAN="arm -x arm11,arm7,arm9,aarch64,atmel,aries,freescale,kirkwood,mvebu,siemens,tegra,uniphier,mx,samsung,sunxi,am33xx,omap3,omap4,omap5,pxa,rockchip,toradex,socfpga,k2,xilinx"
     - env:
         - BUILDMAN="sandbox x86"
           TOOLCHAIN="x86_64"
     - env:
+        - BUILDMAN="toradex"
+    - env:
         - BUILDMAN="kirkwood"
     - env:
         - BUILDMAN="mvebu"
     - env:
-        - BUILDMAN="pxa"
+        - JOB="PXA"
+        - BUILDMAN="pxa -x toradex"
     - env:
         - BUILDMAN="m68k"
           TOOLCHAIN="m68k"
     - env:
-        - BUILDMAN="microblaze"
+        - JOB="Xilinx (ARM and MicroBlaze)"
+          BUILDMAN="xilinx"
           TOOLCHAIN="microblaze"
     - env:
         - BUILDMAN="mips"
@@ -207,7 +221,8 @@
     - env:
         - BUILDMAN="siemens"
     - env:
-        - BUILDMAN="tegra"
+        - JOB="tegra"
+          BUILDMAN="tegra -x toradex"
     - env:
         - JOB="am33xx"
           BUILDMAN="am33xx -x siemens"
@@ -220,7 +235,8 @@
     - env:
         - BUILDMAN="uniphier"
     - env:
-        - BUILDMAN="aarch64 -x tegra,freescale,mvebu,uniphier,sunxi,samsung,rockchip"
+        - JOB="aarch64"
+          BUILDMAN="aarch64 -x tegra,freescale,mvebu,uniphier,sunxi,samsung,rockchip"
     - env:
         - BUILDMAN="rockchip"
     - env:
@@ -286,6 +302,11 @@
           QEMU_TARGET="arm-softmmu"
           BUILDMAN="^integratorcp_cm926ejs$"
     - env:
+        - TEST_PY_BD="qemu_arm"
+          TEST_PY_TEST_SPEC="not sleep"
+          QEMU_TARGET="arm-softmmu"
+          BUILDMAN="^qemu_arm$"
+    - env:
         - TEST_PY_BD="qemu_mips"
           TEST_PY_TEST_SPEC="not sleep"
           QEMU_TARGET="mips-softmmu"
diff --git a/Makefile b/Makefile
index 1a2ef30..888486b 100644
--- a/Makefile
+++ b/Makefile
@@ -878,7 +878,7 @@
 quiet_cmd_copy = COPY    $@
       cmd_copy = cp $< $@
 
-ifeq ($(CONFIG_FIT_EMBED),y)
+ifeq ($(CONFIG_MULTI_DTB_FIT),y)
 
 fit-dtb.blob: dts/dt.dtb FORCE
 	$(call if_changed,mkimage)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 5d1ce3e..64e0ee4 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -631,6 +631,14 @@
 	select CPU_V7
 	select BOARD_EARLY_INIT_F
 
+config ARCH_QEMU
+	bool "QEMU Virtual Platform"
+	select CPU_V7
+	select ARCH_SUPPORT_PSCI
+	select DM
+	select DM_SERIAL
+	select OF_CONTROL
+
 config ARCH_RMOBILE
 	bool "Renesas ARM SoCs"
 	select DM
@@ -1171,6 +1179,8 @@
 
 source "arch/arm/mach-meson/Kconfig"
 
+source "arch/arm/mach-qemu/Kconfig"
+
 source "arch/arm/mach-rockchip/Kconfig"
 
 source "arch/arm/mach-s5pc1xx/Kconfig"
diff --git a/arch/arm/mach-omap2/hwinit-common.c b/arch/arm/mach-omap2/hwinit-common.c
index 7324d52..56890a0 100644
--- a/arch/arm/mach-omap2/hwinit-common.c
+++ b/arch/arm/mach-omap2/hwinit-common.c
@@ -165,9 +165,11 @@
 	 * to prevent overwrites.
 	 */
 	save_omap_boot_params();
-	spl_early_init();
 #endif
 	do_board_detect();
+#ifdef CONFIG_SPL_BUILD
+	spl_early_init();
+#endif
 	vcores_init();
 #ifdef CONFIG_DEBUG_UART_OMAP
 	debug_uart_init();
diff --git a/arch/arm/mach-omap2/utils.c b/arch/arm/mach-omap2/utils.c
index f2fafae..d4f171b 100644
--- a/arch/arm/mach-omap2/utils.c
+++ b/arch/arm/mach-omap2/utils.c
@@ -91,11 +91,10 @@
 		return 0;
 	}
 
-	res = part_get_info_by_name(dev_desc, part, &info);
-	if (res < 0) {
-		pr_err("cannot find partition: '%s'\n", part);
+	/* Check only for EFI (GPT) partition table */
+	res = part_get_info_by_name_type(dev_desc, part, &info, PART_TYPE_EFI);
+	if (res < 0)
 		return 0;
-	}
 
 	/* Calculate size in bytes */
 	sz = (info.size * (u64)info.blksz);
@@ -111,13 +110,10 @@
 	u32 sz_kb;
 
 	sz_kb = omap_mmc_get_part_size("userdata");
-	if (sz_kb == 0) {
-		buf[0] = '\0';
-		printf("Warning: fastboot.userdata_size: unable to calc\n");
-	} else {
-		sprintf(buf, "%u", sz_kb);
-	}
+	if (sz_kb == 0)
+		return; /* probably it's not Android partition table */
 
+	sprintf(buf, "%u", sz_kb);
 	env_set("fastboot.userdata_size", buf);
 }
 #else
diff --git a/arch/arm/mach-qemu/Kconfig b/arch/arm/mach-qemu/Kconfig
new file mode 100644
index 0000000..3500b56
--- /dev/null
+++ b/arch/arm/mach-qemu/Kconfig
@@ -0,0 +1,12 @@
+if ARCH_QEMU
+
+config SYS_VENDOR
+	default "emulation"
+
+config SYS_BOARD
+	default "qemu-arm"
+
+config SYS_CONFIG_NAME
+	default "qemu-arm"
+
+endif
diff --git a/board/emulation/qemu-arm/MAINTAINERS b/board/emulation/qemu-arm/MAINTAINERS
new file mode 100644
index 0000000..a803061
--- /dev/null
+++ b/board/emulation/qemu-arm/MAINTAINERS
@@ -0,0 +1,6 @@
+QEMU ARM 'VIRT' BOARD
+M:	Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
+S:	Maintained
+F:	board/emulation/qemu-arm/
+F:	include/configs/qemu-arm.h
+F:	configs/qemu_arm_defconfig
diff --git a/board/emulation/qemu-arm/Makefile b/board/emulation/qemu-arm/Makefile
new file mode 100644
index 0000000..716a6e9
--- /dev/null
+++ b/board/emulation/qemu-arm/Makefile
@@ -0,0 +1,5 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	+= qemu-arm.o
diff --git a/board/emulation/qemu-arm/qemu-arm.c b/board/emulation/qemu-arm/qemu-arm.c
new file mode 100644
index 0000000..e29ba46
--- /dev/null
+++ b/board/emulation/qemu-arm/qemu-arm.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Tuomas Tynkkynen
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <fdtdec.h>
+
+int board_init(void)
+{
+	return 0;
+}
+
+int dram_init(void)
+{
+	if (fdtdec_setup_memory_size() != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+int dram_init_banksize(void)
+{
+	fdtdec_setup_memory_banksize();
+
+	return 0;
+}
+
+void *board_fdt_blob_setup(void)
+{
+	/* QEMU loads a generated DTB for us at the start of RAM. */
+	return (void *)CONFIG_SYS_SDRAM_BASE;
+}
diff --git a/board/ti/ks2_evm/board_k2e.c b/board/ti/ks2_evm/board_k2e.c
index 266a66b..6c77d91 100644
--- a/board/ti/ks2_evm/board_k2e.c
+++ b/board/ti/ks2_evm/board_k2e.c
@@ -166,7 +166,7 @@
 }
 #endif
 
-#if defined(CONFIG_FIT_EMBED)
+#if defined(CONFIG_MULTI_DTB_FIT)
 int board_fit_config_name_match(const char *name)
 {
 	if (!strcmp(name, "keystone-k2e-evm"))
diff --git a/board/ti/ks2_evm/board_k2g.c b/board/ti/ks2_evm/board_k2g.c
index f1c4ddc..01328f1 100644
--- a/board/ti/ks2_evm/board_k2g.c
+++ b/board/ti/ks2_evm/board_k2g.c
@@ -217,7 +217,7 @@
 }
 #endif
 
-#if defined(CONFIG_FIT_EMBED)
+#if defined(CONFIG_MULTI_DTB_FIT)
 int board_fit_config_name_match(const char *name)
 {
 	bool eeprom_read = board_ti_was_eeprom_read();
diff --git a/board/ti/ks2_evm/board_k2hk.c b/board/ti/ks2_evm/board_k2hk.c
index c733099..e99e635 100644
--- a/board/ti/ks2_evm/board_k2hk.c
+++ b/board/ti/ks2_evm/board_k2hk.c
@@ -150,7 +150,7 @@
 }
 #endif
 
-#if defined(CONFIG_FIT_EMBED)
+#if defined(CONFIG_MULTI_DTB_FIT)
 int board_fit_config_name_match(const char *name)
 {
 	if (!strcmp(name, "keystone-k2hk-evm"))
diff --git a/board/ti/ks2_evm/board_k2l.c b/board/ti/ks2_evm/board_k2l.c
index 166367b..c65f331 100644
--- a/board/ti/ks2_evm/board_k2l.c
+++ b/board/ti/ks2_evm/board_k2l.c
@@ -138,7 +138,7 @@
 }
 #endif
 
-#if defined(CONFIG_FIT_EMBED)
+#if defined(CONFIG_MULTI_DTB_FIT)
 int board_fit_config_name_match(const char *name)
 {
 	if (!strcmp(name, "keystone-k2l-evm"))
diff --git a/cmd/gpt.c b/cmd/gpt.c
index d4406e3..9e04aff 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -633,6 +633,21 @@
 }
 
 #ifdef CONFIG_CMD_GPT_RENAME
+/*
+ * There are 3 malloc() calls in set_gpt_info() and there is no info about which
+ * failed.
+ */
+static void set_gpt_cleanup(char **str_disk_guid,
+			    disk_partition_t **partitions)
+{
+#ifdef CONFIG_RANDOM_UUID
+	if (str_disk_guid)
+		free(str_disk_guid);
+#endif
+	if (partitions)
+		free(partitions);
+}
+
 static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
 			       char *name1, char *name2)
 {
@@ -651,19 +666,27 @@
 	ret = get_disk_guid(dev_desc, disk_guid);
 	if (ret < 0)
 		return ret;
+	/*
+	 * Allocates disk_partitions, requiring matching call to del_gpt_info()
+	 * if successful.
+	 */
 	numparts = get_gpt_info(dev_desc);
 	if (numparts <=  0)
 		return numparts ? numparts : -ENODEV;
 
 	partlistlen = calc_parts_list_len(numparts);
 	partitions_list = malloc(partlistlen);
-	if (partitions_list == NULL)
+	if (!partitions_list) {
+		del_gpt_info();
 		return -ENOMEM;
+	}
 	memset(partitions_list, '\0', partlistlen);
 
 	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
-	if (ret < 0)
+	if (ret < 0) {
+		free(partitions_list);
 		return ret;
+	}
 	/*
 	 * Uncomment the following line to print a string that 'gpt write'
 	 * or 'gpt verify' will accept as input.
@@ -671,15 +694,23 @@
 	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
 	      (unsigned)strlen(partitions_list));
 
+	/* set_gpt_info allocates new_partitions and str_disk_guid */
 	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
 			   &new_partitions, &part_count);
-	if (ret < 0)
-		return ret;
+	if (ret < 0) {
+		del_gpt_info();
+		free(partitions_list);
+		if (ret == -ENOMEM)
+			set_gpt_cleanup(&str_disk_guid, &new_partitions);
+		else
+			goto out;
+	}
 
 	if (!strcmp(subcomm, "swap")) {
 		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
 			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 		list_for_each(pos, &disk_partitions) {
 			curr = list_entry(pos, struct disk_part, list);
@@ -693,21 +724,24 @@
 		}
 		if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
 			printf("Cannot swap partition names except in pairs.\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	} else { /* rename */
 		if (strlen(name2) > PART_NAME_LEN) {
 			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 		partnum = (int)simple_strtol(name1, NULL, 10);
 		if ((partnum < 0) || (partnum > numparts)) {
 			printf("Illegal partition number %s\n", name1);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 		ret = part_get_info(dev_desc, partnum, new_partitions);
 		if (ret < 0)
-			return ret;
+			goto out;
 
 		/* U-Boot partition numbering starts at 1 */
 		list_for_each(pos, &disk_partitions) {
@@ -722,33 +756,50 @@
 
 	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
 	if (ret < 0)
-		return ret;
+		goto out;
 	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
 	      (unsigned)strlen(partitions_list));
 
 	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
 			   &new_partitions, &part_count);
-	if (ret < 0)
-		return ret;
+	/*
+	 * Even though valid pointers are here passed into set_gpt_info(),
+	 * it mallocs again, and there's no way to tell which failed.
+	 */
+	if (ret < 0) {
+		del_gpt_info();
+		free(partitions_list);
+		if (ret == -ENOMEM)
+			set_gpt_cleanup(&str_disk_guid, &new_partitions);
+		else
+			goto out;
+	}
 
 	debug("Writing new partition table\n");
 	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
 	if (ret < 0) {
 		printf("Writing new partition table failed\n");
-		return ret;
+		goto out;
 	}
 
 	debug("Reading back new partition table\n");
+	/*
+	 * Empty the existing disk_partitions list, as otherwise the memory in
+	 * the original list is unreachable.
+	 */
+	del_gpt_info();
 	numparts = get_gpt_info(dev_desc);
-	if (numparts <=  0)
-		return numparts ? numparts : -ENODEV;
+	if (numparts <=  0) {
+		ret = numparts ? numparts : -ENODEV;
+		goto out;
+	}
 	printf("new partition table with %d partitions is:\n", numparts);
 	print_gpt_info();
-
 	del_gpt_info();
-	free(partitions_list);
-	free(str_disk_guid);
+ out:
 	free(new_partitions);
+	free(str_disk_guid);
+	free(partitions_list);
 	return ret;
 }
 #endif
diff --git a/cmd/nvedit.c b/cmd/nvedit.c
index 228e904..8752ff4 100644
--- a/cmd/nvedit.c
+++ b/cmd/nvedit.c
@@ -393,15 +393,18 @@
 		sprintf(message, "Please enter '%s': ", argv[1]);
 	} else {
 		/* env_ask envname message1 ... messagen [size] */
-		for (i = 2, pos = 0; i < argc; i++) {
+		for (i = 2, pos = 0; i < argc && pos < sizeof(message); i++) {
 			if (pos)
 				message[pos++] = ' ';
 
-			strcpy(message + pos, argv[i]);
+			strncpy(message + pos, argv[i], sizeof(message) - pos);
 			pos += strlen(argv[i]);
 		}
-		message[pos++] = ' ';
-		message[pos] = '\0';
+		if (pos < sizeof(message) - 1) {
+			message[pos++] = ' ';
+			message[pos] = '\0';
+		} else
+			message[CONFIG_SYS_CBSIZE - 1] = '\0';
 	}
 
 	if (size >= CONFIG_SYS_CBSIZE)
diff --git a/cmd/pxe.c b/cmd/pxe.c
index c5a770a..a62cbe1 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -616,7 +616,7 @@
 static int label_boot(cmd_tbl_t *cmdtp, struct pxe_label *label)
 {
 	char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
-	char initrd_str[22];
+	char initrd_str[28];
 	char mac_str[29] = "";
 	char ip_str[68] = "";
 	int bootm_argc = 2;
@@ -648,9 +648,9 @@
 		}
 
 		bootm_argv[2] = initrd_str;
-		strcpy(bootm_argv[2], env_get("ramdisk_addr_r"));
+		strncpy(bootm_argv[2], env_get("ramdisk_addr_r"), 18);
 		strcat(bootm_argv[2], ":");
-		strcat(bootm_argv[2], env_get("filesize"));
+		strncat(bootm_argv[2], env_get("filesize"), 9);
 	}
 
 	if (get_relfile_envaddr(cmdtp, label->kernel, "kernel_addr_r") < 0) {
@@ -689,9 +689,9 @@
 		}
 
 		if (label->append)
-			strcpy(bootargs, label->append);
-		strcat(bootargs, ip_str);
-		strcat(bootargs, mac_str);
+			strncpy(bootargs, label->append, sizeof(bootargs));
+		strncat(bootargs, ip_str, sizeof(bootargs) - strlen(bootargs));
+		strncat(bootargs, mac_str, sizeof(bootargs) - strlen(bootargs));
 
 		cli_simple_process_macros(bootargs, finalbootargs);
 		env_set("bootargs", finalbootargs);
diff --git a/cmd/time.c b/cmd/time.c
index de57e3b..2cd8b1a 100644
--- a/cmd/time.c
+++ b/cmd/time.c
@@ -28,7 +28,7 @@
 {
 	ulong cycles = 0;
 	int retval = 0;
-	int repeatable;
+	int repeatable = 0;
 
 	if (argc == 1)
 		return CMD_RET_USAGE;
diff --git a/common/Kconfig b/common/Kconfig
index 3c99650..f96a25f 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -403,22 +403,6 @@
 
 endmenu
 
-config DTB_RESELECT
-	bool "Support swapping dtbs at a later point in boot"
-	depends on FIT_EMBED
-	help
-	  It is possible during initial boot you may need to use a generic
-	  dtb until you can fully determine the board your running on. This
-	  config allows boards to implement a function at a later point
-	  during boot to switch to the "correct" dtb.
-
-config FIT_EMBED
-	bool "Support a FIT image embedded in the U-boot image"
-	help
-	  This option provides hooks to allow U-boot to parse an
-	  appended FIT image and enable board specific code to then select
-	  the correct DTB to be used.
-
 config DEFAULT_FDT_FILE
 	string "Default fdt file"
 	help
diff --git a/common/Makefile b/common/Makefile
index 801ea31..cec506f 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -103,7 +103,7 @@
 obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
 obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
-obj-$(CONFIG_FIT_EMBED) += boot_fit.o common_fit.o
+obj-$(CONFIG_$(SPL_)MULTI_DTB_FIT) += boot_fit.o common_fit.o
 obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += image-sig.o
 obj-$(CONFIG_IO_TRACE) += iotrace.o
 obj-y += memsize.o
diff --git a/common/boot_fit.c b/common/boot_fit.c
index 0a72315..add65c4 100644
--- a/common/boot_fit.c
+++ b/common/boot_fit.c
@@ -13,7 +13,7 @@
 #include <image.h>
 #include <libfdt.h>
 
-int fdt_offset(void *fit)
+static int fdt_offset(const void *fit)
 {
 	int images, node, fdt_len, fdt_node, fdt_offset;
 	const char *fdt_name;
@@ -55,7 +55,7 @@
 	return fdt_offset;
 }
 
-void *locate_dtb_in_fit(void *fit)
+void *locate_dtb_in_fit(const void *fit)
 {
 	struct image_header *header;
 	int size;
@@ -73,7 +73,7 @@
 
 	ret = fdt_offset(fit);
 
-	if (ret <= 0)
+	if (ret < 0)
 		return NULL;
 	else
 		return (void *)fit+size+ret;
diff --git a/common/common_fit.c b/common/common_fit.c
index 5f5f3f9..85b33d8 100644
--- a/common/common_fit.c
+++ b/common/common_fit.c
@@ -32,6 +32,9 @@
 {
 	const char *name;
 	int conf, node, len;
+	const char *dflt_conf_name;
+	const char *dflt_conf_desc = NULL;
+	int dflt_conf_node = -ENOENT;
 
 	conf = fdt_path_offset(fdt, FIT_CONFS_PATH);
 	if (conf < 0) {
@@ -39,6 +42,9 @@
 		      conf);
 		return -EINVAL;
 	}
+
+	dflt_conf_name = fdt_getprop(fdt, conf, "default", &len);
+
 	for (node = fdt_first_subnode(fdt, conf);
 	     node >= 0;
 	     node = fdt_next_subnode(fdt, node)) {
@@ -50,6 +56,15 @@
 #endif
 			return -EINVAL;
 		}
+
+		if (dflt_conf_name) {
+			const char *node_name = fdt_get_name(fdt, node, NULL);
+			if (strcmp(dflt_conf_name, node_name) == 0) {
+				dflt_conf_node = node;
+				dflt_conf_desc = name;
+			}
+		}
+
 		if (board_fit_config_name_match(name))
 			continue;
 
@@ -58,5 +73,10 @@
 		return node;
 	}
 
+	if (dflt_conf_node != -ENOENT) {
+		debug("Selecting default config '%s'", dflt_conf_desc);
+		return dflt_conf_node;
+	}
+
 	return -ENOENT;
 }
diff --git a/configs/k2e_evm_defconfig b/configs/k2e_evm_defconfig
index fed6add..b6a5282 100644
--- a/configs/k2e_evm_defconfig
+++ b/configs/k2e_evm_defconfig
@@ -12,7 +12,7 @@
 CONFIG_OF_BOARD_SETUP=y
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_DTB_RESELECT=y
-CONFIG_FIT_EMBED=y
+CONFIG_MULTI_DTB_FIT=y
 CONFIG_VERSION_VARIABLE=y
 CONFIG_BOARD_EARLY_INIT_F=y
 CONFIG_SPL=y
diff --git a/configs/k2g_evm_defconfig b/configs/k2g_evm_defconfig
index 2b29bf4..9c8b66d 100644
--- a/configs/k2g_evm_defconfig
+++ b/configs/k2g_evm_defconfig
@@ -12,7 +12,7 @@
 CONFIG_OF_BOARD_SETUP=y
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_DTB_RESELECT=y
-CONFIG_FIT_EMBED=y
+CONFIG_MULTI_DTB_FIT=y
 CONFIG_VERSION_VARIABLE=y
 CONFIG_BOARD_EARLY_INIT_F=y
 CONFIG_SPL=y
diff --git a/configs/k2hk_evm_defconfig b/configs/k2hk_evm_defconfig
index 80546ec..bfb95ab 100644
--- a/configs/k2hk_evm_defconfig
+++ b/configs/k2hk_evm_defconfig
@@ -12,7 +12,7 @@
 CONFIG_OF_BOARD_SETUP=y
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_DTB_RESELECT=y
-CONFIG_FIT_EMBED=y
+CONFIG_MULTI_DTB_FIT=y
 CONFIG_VERSION_VARIABLE=y
 CONFIG_BOARD_EARLY_INIT_F=y
 CONFIG_SPL=y
diff --git a/configs/k2l_evm_defconfig b/configs/k2l_evm_defconfig
index 732c9d2..7ab0d47 100644
--- a/configs/k2l_evm_defconfig
+++ b/configs/k2l_evm_defconfig
@@ -12,7 +12,7 @@
 CONFIG_OF_BOARD_SETUP=y
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_DTB_RESELECT=y
-CONFIG_FIT_EMBED=y
+CONFIG_MULTI_DTB_FIT=y
 CONFIG_VERSION_VARIABLE=y
 CONFIG_BOARD_EARLY_INIT_F=y
 CONFIG_SPL=y
diff --git a/configs/qemu_arm_defconfig b/configs/qemu_arm_defconfig
new file mode 100644
index 0000000..2a8594d
--- /dev/null
+++ b/configs/qemu_arm_defconfig
@@ -0,0 +1,28 @@
+CONFIG_ARM=y
+CONFIG_ARM_SMCCC=y
+CONFIG_ARCH_QEMU=y
+CONFIG_AHCI=y
+CONFIG_DISTRO_DEFAULTS=y
+# CONFIG_DISPLAY_CPUINFO is not set
+# CONFIG_DISPLAY_BOARDINFO is not set
+# CONFIG_CMD_IMLS is not set
+CONFIG_CMD_PCI=y
+CONFIG_CMD_USB=y
+CONFIG_OF_BOARD=y
+CONFIG_AHCI_PCI=y
+CONFIG_BLK=y
+# CONFIG_MMC is not set
+CONFIG_DM_ETH=y
+CONFIG_E1000=y
+CONFIG_NVME=y
+CONFIG_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_PCIE_ECAM_GENERIC=y
+CONFIG_SCSI=y
+CONFIG_DM_SCSI=y
+CONFIG_SYSRESET=y
+CONFIG_SYSRESET_PSCI=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_PCI=y
diff --git a/disk/part.c b/disk/part.c
index aa9183d..66b8101 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -21,6 +21,9 @@
 #define PRINTF(fmt,args...)
 #endif
 
+/* Check all partition types */
+#define PART_TYPE_ALL		-1
+
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifdef HAVE_BLOCK_DEVICE
@@ -626,8 +629,8 @@
 	return ret;
 }
 
-int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
-	disk_partition_t *info)
+int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
+			       disk_partition_t *info, int part_type)
 {
 	struct part_driver *first_drv =
 		ll_entry_start(struct part_driver, part_driver);
@@ -638,6 +641,8 @@
 		int ret;
 		int i;
 		for (i = 1; i < part_drv->max_entries; i++) {
+			if (part_type >= 0 && part_type != part_drv->part_type)
+				break;
 			ret = part_drv->get_info(dev_desc, i, info);
 			if (ret != 0) {
 				/* no more entries in table */
@@ -652,6 +657,12 @@
 	return -1;
 }
 
+int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
+			  disk_partition_t *info)
+{
+	return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
+}
+
 void part_set_generic_name(const struct blk_desc *dev_desc,
 	int part_num, char *name)
 {
diff --git a/doc/README.multi-dtb-fit b/doc/README.multi-dtb-fit
new file mode 100644
index 0000000..6cc4965
--- /dev/null
+++ b/doc/README.multi-dtb-fit
@@ -0,0 +1,65 @@
+MULTI DTB FIT and SPL_MULTI_DTB_FIT
+
+The purpose of this feature is to enable U-Boot or the SPL to select its DTB
+from a FIT appended at the end of the binary.
+It comes in two flavors: U-Boot (CONFIG_MULTI_DTB_FIT) and SPL
+(CONFIG_SPL_MULTI_DTB_FIT).
+
+U-Boot flavor:
+Usually the DTB is selected by the SPL and passed down to U-Boot. But some
+platforms don't use the SPL. In this case MULTI_DTB_FIT can used to provide
+U-Boot with a choice of DTBs.
+The relevant DTBs are packed into a FIT (list provided by CONFIG__OF_LIST). The
+FIT is automatically generated at the end of the compilation and appended to
+u-boot.bin so that U-Boot can locate it and select the correct DTB from inside
+the FIT.
+The selection is done using board_fit_config_name_match() (same as what the SPL
+uses to select the DTB for U-Boot). The selection happens during fdtdec_setup()
+which is called during before relocation by board_init_f().
+
+SPL flavor:
+the SPL uses only a small subset of the DTB and it usually depends more
+on the SOC than on the board. So it's usually fine to include a DTB in the
+SPL that doesn't exactly match the board. There are howerver some cases
+where it's not possible. In the later case, in order to support multiple
+boards (or board revisions) with the same SPL binary, SPL_MULTI_DTB_FIT
+can be used.
+The relevant DTBs are packed into a FIT. This FIT is automatically generated
+at the end of the compilation, compressed and appended to u-boot-spl.bin, so
+that SPL can locate it and select the correct DTB from inside the FIT.
+CONFIG_SPL__OF_LIST is used to list the relevant DTBs.
+The compression stage is optional but reduces the impact on the size of the
+SPL. LZO and GZIP compressions are supported. By default, the area where the
+FIT is uncompressed is dynamicaly allocated but this behaviour can be changed
+for platforms that don't provide a HEAP big enough to contain the uncompressed
+FIT.
+The SPL uses board_fit_config_name_match() to find the correct DTB within the
+FIT (same as what the SPL uses to select the DTB for U-Boot).
+Uncompression and selection stages happen in fdtdec_setup() which is called
+during the early initialization stage of the SPL (spl_early_init() or
+spl_init())
+
+Impacts and performances (SPL flavor):
+The impact of this option is relatively small. Here are some numbers measured
+for a TI DRA72 platform:
+
+                            +----------+------------+-----------+------------+
+                            |  size    | size delta | SPL boot  | boot time  |
+                            |  (bytes) | (bytes)    | time (s)  | delta (s)  |
++---------------------------+----------+------------+-----------+------------+
+| 1 DTB                     |          |            |           |            |
++---------------------------+----------+------------+-----------+------------+
+| reference                 |   125305 |          0 |     1.389 |          0 |
+| LZO (dynamic allocation)  |   125391 |         86 |     1.381 |     -0.008 |
++---------------------------+----------+------------+-----------+------------+
+| 4 DTBs (DRA7, DRA71,      |          |            |           |            |
+| DRA72, DRA72 revC)        |          |            |           |            |
++---------------------------+----------+------------+-----------+------------+
+| LZO (dynamic allocation)  |   125991 |        686 |      1.39 |      0.001 |
+| LZO (user defined area)   |   125927 |        622 |     1.403 |      0.014 |
+| GZIP (user defined area)  |   133880 |       8575 |     1.421 |      0.032 |
+| No compression (in place) |   137472 |      12167 |     1.412 |      0.023 |
++---------------------------+----------+------------+-----------+------------+
+
+Note: SPL boot time is the time elapsed between the 'reset' command is entered
+and the time when the first U-Boot (not SPL) version string is displayed.
diff --git a/doc/device-tree-bindings/regulator/regulator.txt b/doc/device-tree-bindings/regulator/regulator.txt
index 2cf4b9d..918711e 100644
--- a/doc/device-tree-bindings/regulator/regulator.txt
+++ b/doc/device-tree-bindings/regulator/regulator.txt
@@ -10,10 +10,10 @@
 regulator: drivers/power/regulator/max77686.c
 
 For the node name e.g.: "prefix[:alpha:]num { ... }":
-- the driver prefix should be: "prefix" or "PREFIX" - case insensitive
+- the driver prefix should be: "prefix" - case sensitive
 - the node name's "num" is set as "dev->driver_data" on bind
 
-Example the prefix "ldo" will pass for: "ldo1", "ldo@1", "LDO1", "LDOREG@1"...
+Example the prefix "ldo" will pass for: "ldo1", "ldo@1", "ldoreg@1, ...
 
 Optional properties:
 - regulator-name: a string, required by the regulator uclass
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 8af2470..58f128d 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -33,6 +33,14 @@
 	help
 	  Enable PCI memory and I/O space resource allocation and assignment.
 
+config PCIE_ECAM_GENERIC
+	bool "Generic ECAM-based PCI host controller support"
+	default n
+	depends on DM_PCI
+	help
+	  Say Y here if you want to enable support for generic ECAM-based
+	  PCIe host controllers, such as the one emulated by QEMU.
+
 config PCIE_DW_MVEBU
 	bool "Enable Armada-8K PCIe driver (DesignWare core)"
 	depends on DM_PCI
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index ad44e83..5eb12ef 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -17,6 +17,7 @@
 endif
 obj-$(CONFIG_PCI) += pci_auto_common.o pci_common.o
 
+obj-$(CONFIG_PCIE_ECAM_GENERIC) += pcie_ecam_generic.o
 obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
 obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
 obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 86df141..5a24eb6 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -518,6 +518,64 @@
 	return sub_bus;
 }
 
+int pci_generic_mmap_write_config(
+	struct udevice *bus,
+	int (*addr_f)(struct udevice *bus, pci_dev_t bdf, uint offset, void **addrp),
+	pci_dev_t bdf,
+	uint offset,
+	ulong value,
+	enum pci_size_t size)
+{
+	void *address;
+
+	if (addr_f(bus, bdf, offset, &address) < 0)
+		return 0;
+
+	switch (size) {
+	case PCI_SIZE_8:
+		writeb(value, address);
+		return 0;
+	case PCI_SIZE_16:
+		writew(value, address);
+		return 0;
+	case PCI_SIZE_32:
+		writel(value, address);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+int pci_generic_mmap_read_config(
+	struct udevice *bus,
+	int (*addr_f)(struct udevice *bus, pci_dev_t bdf, uint offset, void **addrp),
+	pci_dev_t bdf,
+	uint offset,
+	ulong *valuep,
+	enum pci_size_t size)
+{
+	void *address;
+
+	if (addr_f(bus, bdf, offset, &address) < 0) {
+		*valuep = pci_get_ff(size);
+		return 0;
+	}
+
+	switch (size) {
+	case PCI_SIZE_8:
+		*valuep = readb(address);
+		return 0;
+	case PCI_SIZE_16:
+		*valuep = readw(address);
+		return 0;
+	case PCI_SIZE_32:
+		*valuep = readl(address);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
 int dm_pci_hose_probe_bus(struct udevice *bus)
 {
 	int sub_bus;
diff --git a/drivers/pci/pcie_ecam_generic.c b/drivers/pci/pcie_ecam_generic.c
new file mode 100644
index 0000000..c7540ff
--- /dev/null
+++ b/drivers/pci/pcie_ecam_generic.c
@@ -0,0 +1,143 @@
+/*
+ * Generic PCIE host provided by e.g. QEMU
+ *
+ * Heavily based on drivers/pci/pcie_xilinx.c
+ *
+ * Copyright (C) 2016 Imagination Technologies
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+
+#include <asm/io.h>
+
+/**
+ * struct generic_ecam_pcie - generic_ecam PCIe controller state
+ * @cfg_base: The base address of memory mapped configuration space
+ */
+struct generic_ecam_pcie {
+	void *cfg_base;
+};
+
+/**
+ * pci_generic_ecam_conf_address() - Calculate the address of a config access
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @paddress: Pointer to the pointer to write the calculates address to
+ *
+ * Calculates the address that should be accessed to perform a PCIe
+ * configuration space access for a given device identified by the PCIe
+ * controller device @pcie and the bus, device & function numbers in @bdf. If
+ * access to the device is not valid then the function will return an error
+ * code. Otherwise the address to access will be written to the pointer pointed
+ * to by @paddress.
+ */
+static int pci_generic_ecam_conf_address(struct udevice *bus, pci_dev_t bdf,
+					    uint offset, void **paddress)
+{
+	struct generic_ecam_pcie *pcie = dev_get_priv(bus);
+	void *addr;
+
+	addr = pcie->cfg_base;
+	addr += PCI_BUS(bdf) << 20;
+	addr += PCI_DEV(bdf) << 15;
+	addr += PCI_FUNC(bdf) << 12;
+	addr += offset;
+	*paddress = addr;
+
+	return 0;
+}
+
+/**
+ * pci_generic_ecam_read_config() - Read from configuration space
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ */
+static int pci_generic_ecam_read_config(struct udevice *bus, pci_dev_t bdf,
+				   uint offset, ulong *valuep,
+				   enum pci_size_t size)
+{
+	return pci_generic_mmap_read_config(bus, pci_generic_ecam_conf_address,
+					    bdf, offset, valuep, size);
+}
+
+/**
+ * pci_generic_ecam_write_config() - Write to configuration space
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ */
+static int pci_generic_ecam_write_config(struct udevice *bus, pci_dev_t bdf,
+				    uint offset, ulong value,
+				    enum pci_size_t size)
+{
+	return pci_generic_mmap_write_config(bus, pci_generic_ecam_conf_address,
+					     bdf, offset, value, size);
+}
+
+/**
+ * pci_generic_ecam_ofdata_to_platdata() - Translate from DT to device state
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int pci_generic_ecam_ofdata_to_platdata(struct udevice *dev)
+{
+	struct generic_ecam_pcie *pcie = dev_get_priv(dev);
+	struct fdt_resource reg_res;
+	DECLARE_GLOBAL_DATA_PTR;
+	int err;
+
+	err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg",
+			       0, &reg_res);
+	if (err < 0) {
+		pr_err("\"reg\" resource not found\n");
+		return err;
+	}
+
+	pcie->cfg_base = map_physmem(reg_res.start,
+				     fdt_resource_size(&reg_res),
+				     MAP_NOCACHE);
+
+	return 0;
+}
+
+static const struct dm_pci_ops pci_generic_ecam_ops = {
+	.read_config	= pci_generic_ecam_read_config,
+	.write_config	= pci_generic_ecam_write_config,
+};
+
+static const struct udevice_id pci_generic_ecam_ids[] = {
+	{ .compatible = "pci-host-ecam-generic" },
+	{ }
+};
+
+U_BOOT_DRIVER(pci_generic_ecam) = {
+	.name			= "pci_generic_ecam",
+	.id			= UCLASS_PCI,
+	.of_match		= pci_generic_ecam_ids,
+	.ops			= &pci_generic_ecam_ops,
+	.ofdata_to_platdata	= pci_generic_ecam_ofdata_to_platdata,
+	.priv_auto_alloc_size	= sizeof(struct generic_ecam_pcie),
+};
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c
index 610f85c..0cb7f6d 100644
--- a/drivers/pci/pcie_layerscape.c
+++ b/drivers/pci/pcie_layerscape.c
@@ -241,14 +241,19 @@
 	return 0;
 }
 
-void *ls_pcie_conf_address(struct ls_pcie *pcie, pci_dev_t bdf,
-				   int offset)
+int ls_pcie_conf_address(struct udevice *bus, pci_dev_t bdf,
+			 uint offset, void **paddress)
 {
-	struct udevice *bus = pcie->bus;
+	struct ls_pcie *pcie = dev_get_priv(bus);
 	u32 busdev;
 
-	if (PCI_BUS(bdf) == bus->seq)
-		return pcie->dbi + offset;
+	if (ls_pcie_addr_valid(pcie, bdf))
+		return -EINVAL;
+
+	if (PCI_BUS(bdf) == bus->seq) {
+		*paddress = pcie->dbi + offset;
+		return 0;
+	}
 
 	busdev = PCIE_ATU_BUS(PCI_BUS(bdf)) |
 		 PCIE_ATU_DEV(PCI_DEV(bdf)) |
@@ -256,67 +261,28 @@
 
 	if (PCI_BUS(bdf) == bus->seq + 1) {
 		ls_pcie_cfg0_set_busdev(pcie, busdev);
-		return pcie->cfg0 + offset;
+		*paddress = pcie->cfg0 + offset;
 	} else {
 		ls_pcie_cfg1_set_busdev(pcie, busdev);
-		return pcie->cfg1 + offset;
+		*paddress = pcie->cfg1 + offset;
 	}
+	return 0;
 }
 
 static int ls_pcie_read_config(struct udevice *bus, pci_dev_t bdf,
 			       uint offset, ulong *valuep,
 			       enum pci_size_t size)
 {
-	struct ls_pcie *pcie = dev_get_priv(bus);
-	void *address;
-
-	if (ls_pcie_addr_valid(pcie, bdf)) {
-		*valuep = pci_get_ff(size);
-		return 0;
-	}
-
-	address = ls_pcie_conf_address(pcie, bdf, offset);
-
-	switch (size) {
-	case PCI_SIZE_8:
-		*valuep = readb(address);
-		return 0;
-	case PCI_SIZE_16:
-		*valuep = readw(address);
-		return 0;
-	case PCI_SIZE_32:
-		*valuep = readl(address);
-		return 0;
-	default:
-		return -EINVAL;
-	}
+	return pci_generic_mmap_read_config(bus, ls_pcie_conf_address,
+					    bdf, offset, valuep, size);
 }
 
 static int ls_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
 				uint offset, ulong value,
 				enum pci_size_t size)
 {
-	struct ls_pcie *pcie = dev_get_priv(bus);
-	void *address;
-
-	if (ls_pcie_addr_valid(pcie, bdf))
-		return 0;
-
-	address = ls_pcie_conf_address(pcie, bdf, offset);
-
-	switch (size) {
-	case PCI_SIZE_8:
-		writeb(value, address);
-		return 0;
-	case PCI_SIZE_16:
-		writew(value, address);
-		return 0;
-	case PCI_SIZE_32:
-		writel(value, address);
-		return 0;
-	default:
-		return -EINVAL;
-	}
+	return pci_generic_mmap_write_config(bus, ls_pcie_conf_address,
+					     bdf, offset, value, size);
 }
 
 /* Clear multi-function bit */
diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c
index 6425825..57112f5 100644
--- a/drivers/pci/pcie_xilinx.c
+++ b/drivers/pci/pcie_xilinx.c
@@ -41,7 +41,7 @@
 
 /**
  * pcie_xilinx_config_address() - Calculate the address of a config access
- * @pcie: Pointer to the PCI controller state
+ * @udev: Pointer to the PCI bus
  * @bdf: Identifies the PCIe device to access
  * @offset: The offset into the device's configuration space
  * @paddress: Pointer to the pointer to write the calculates address to
@@ -55,9 +55,10 @@
  *
  * Return: 0 on success, else -ENODEV
  */
-static int pcie_xilinx_config_address(struct xilinx_pcie *pcie, pci_dev_t bdf,
+static int pcie_xilinx_config_address(struct udevice *udev, pci_dev_t bdf,
 				      uint offset, void **paddress)
 {
+	struct xilinx_pcie *pcie = dev_get_priv(udev);
 	unsigned int bus = PCI_BUS(bdf);
 	unsigned int dev = PCI_DEV(bdf);
 	unsigned int func = PCI_FUNC(bdf);
@@ -101,29 +102,8 @@
 				   uint offset, ulong *valuep,
 				   enum pci_size_t size)
 {
-	struct xilinx_pcie *pcie = dev_get_priv(bus);
-	void *address;
-	int err;
-
-	err = pcie_xilinx_config_address(pcie, bdf, offset, &address);
-	if (err < 0) {
-		*valuep = pci_get_ff(size);
-		return 0;
-	}
-
-	switch (size) {
-	case PCI_SIZE_8:
-		*valuep = __raw_readb(address);
-		return 0;
-	case PCI_SIZE_16:
-		*valuep = __raw_readw(address);
-		return 0;
-	case PCI_SIZE_32:
-		*valuep = __raw_readl(address);
-		return 0;
-	default:
-		return -EINVAL;
-	}
+	return pci_generic_mmap_read_config(bus, pcie_xilinx_config_address,
+					    bdf, offset, valuep, size);
 }
 
 /**
@@ -144,27 +124,8 @@
 				    uint offset, ulong value,
 				    enum pci_size_t size)
 {
-	struct xilinx_pcie *pcie = dev_get_priv(bus);
-	void *address;
-	int err;
-
-	err = pcie_xilinx_config_address(pcie, bdf, offset, &address);
-	if (err < 0)
-		return 0;
-
-	switch (size) {
-	case PCI_SIZE_8:
-		__raw_writeb(value, address);
-		return 0;
-	case PCI_SIZE_16:
-		__raw_writew(value, address);
-		return 0;
-	case PCI_SIZE_32:
-		__raw_writel(value, address);
-		return 0;
-	default:
-		return -EINVAL;
-	}
+	return pci_generic_mmap_write_config(bus, pcie_xilinx_config_address,
+					     bdf, offset, value, size);
 }
 
 /**
diff --git a/dts/Kconfig b/dts/Kconfig
index 4ee0510..daa757d 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -102,7 +102,7 @@
 
 config OF_LIST
 	string "List of device tree files to include for DT control"
-	depends on SPL_LOAD_FIT || FIT_EMBED
+	depends on SPL_LOAD_FIT || MULTI_DTB_FIT
 	default DEFAULT_DEVICE_TREE
 	help
 	  This option specifies a list of device tree files to use for DT
@@ -112,6 +112,107 @@
 	  device tree files (without the directory or .dtb suffix)
 	  separated by <space>.
 
+
+config DTB_RESELECT
+	bool "Support swapping dtbs at a later point in boot"
+	depends on MULTI_DTB_FIT
+	help
+	  It is possible during initial boot you may need to use a generic
+	  dtb until you can fully determine the board your running on. This
+	  config allows boards to implement a function at a later point
+	  during boot to switch to the "correct" dtb.
+
+config MULTI_DTB_FIT
+	bool "Support embedding several DTBs in a FIT image for u-boot"
+	help
+	  This option provides hooks to allow U-boot to parse an
+	  appended FIT image and enable board specific code to then select
+	  the correct DTB to be used. Use this if you need to support
+	  multiple DTBs but don't use the SPL.
+
+
+config SPL_MULTI_DTB_FIT
+	depends on SPL_LOAD_FIT && SPL_OF_CONTROL && !SPL_OF_PLATDATA
+	bool "Support embedding several DTBs in a FIT image for the SPL"
+	help
+	  This option provides the SPL with the ability to select its own
+	  DTB at runtime from an appended FIT image containing several DTBs.
+	  This allows using the same SPL binary on multiple platforms.
+	  The primary purpose is to handle different versions of
+	  the same platform without tweaking the platform code if the
+	  differences can be expressed in the DTBs (common examples are: bus
+	  capabilities, pad configurations).
+
+config SPL_OF_LIST
+	string "List of device tree files to include for DT control in SPL"
+	depends on SPL_MULTI_DTB_FIT
+	default OF_LIST
+	help
+	  This option specifies a list of device tree files to use for DT
+	  control in the SPL. These will be packaged into a FIT. At run-time,
+	  the SPL will select the correct DT to use by examining the
+	  hardware (e.g. reading a board ID value). This is a list of
+	  device tree files (without the directory or .dtb suffix)
+	  separated by <space>.
+
+choice
+	prompt "SPL OF LIST compression"
+	depends on SPL_MULTI_DTB_FIT
+	default SPL_MULTI_DTB_FIT_LZO
+
+config SPL_MULTI_DTB_FIT_LZO
+	bool "LZO"
+	depends on SYS_MALLOC_F
+	select SPL_LZO
+	help
+	  Compress the FIT image containing the DTBs available for the SPL
+	  using LZO compression. (requires lzop on host).
+
+config SPL_MULTI_DTB_FIT_GZIP
+	bool "GZIP"
+	depends on SYS_MALLOC_F
+	select SPL_GZIP
+	help
+	  Compress the FIT image containing the DTBs available for the SPL
+	  using GZIP compression. (requires gzip on host)
+
+config SPL_MULTI_DTB_FIT_NO_COMPRESSION
+	bool "No compression"
+	help
+	  Do not compress the FIT image containing the DTBs available for the SPL.
+	  Use this options only if LZO is not available and the DTBs are very small.
+endchoice
+
+choice
+	prompt "Location of uncompressed DTBs "
+	depends on (SPL_MULTI_DTB_FIT_GZIP || SPL_MULTI_DTB_FIT_LZO)
+	default SPL_MULTI_DTB_FIT_DYN_ALLOC if SYS_MALLOC_F
+
+config SPL_MULTI_DTB_FIT_DYN_ALLOC
+	bool "Dynamically allocate the memory"
+	depends on SYS_MALLOC_F
+
+config SPL_MULTI_DTB_FIT_USER_DEFINED_AREA
+	bool "User-defined location"
+endchoice
+
+config SPL_MULTI_DTB_FIT_UNCOMPRESS_SZ
+	hex "Size of memory reserved to uncompress the DTBs"
+	depends on (SPL_MULTI_DTB_FIT_GZIP || SPL_MULTI_DTB_FIT_LZO)
+	default 0x8000
+	help
+	   This is the size of this area where the DTBs are uncompressed.
+	   If this area is dynamically allocated, make sure that
+	   SPL_SYS_MALLOC_F_LEN is big enough to contain it.
+
+config SPL_MULTI_DTB_FIT_USER_DEF_ADDR
+	hex "Address of memory where dtbs are uncompressed"
+	depends on SPL_MULTI_DTB_FIT_USER_DEFINED_AREA
+	help
+	   the FIT image containing the DTBs is uncompressed in an area defined
+	   at compilation time. This is the address of this area. It must be
+	   aligned on 2-byte boundary.
+
 config OF_SPL_REMOVE_PROPS
 	string "List of device tree properties to drop for SPL"
 	depends on SPL_OF_CONTROL
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
index 621c61e..31952f4 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -432,6 +432,10 @@
 		crc = ext2fs_crc16(crc, desc, offset);
 		offset += sizeof(desc->bg_checksum);	/* skip checksum */
 		assert(offset == sizeof(*desc));
+		if (offset < fs->gdsize) {
+			crc = ext2fs_crc16(crc, (__u8 *)desc + offset,
+					   fs->gdsize - offset);
+		}
 	}
 
 	return crc;
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
index 081509d..b0c7303 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -167,6 +167,7 @@
 				  FILETYPE_DIRECTORY);
 	if (status != 1) {
 		printf("** Can not find directory. **\n");
+		ext4fs_free_node(dirnode, &ext4fs_root->diropen);
 		return 1;
 	}
 
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 36a309c..3d3e17e 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -710,13 +710,14 @@
 	itr->fsdata = parent->fsdata;
 	if (clustnum > 0) {
 		itr->clust = clustnum;
+		itr->is_root = 0;
 	} else {
 		itr->clust = parent->fsdata->root_cluster;
+		itr->is_root = 1;
 	}
 	itr->dent = NULL;
 	itr->remaining = 0;
 	itr->last_cluster = 0;
-	itr->is_root = 0;
 }
 
 static void *next_cluster(fat_itr *itr)
diff --git a/include/boot_fit.h b/include/boot_fit.h
index b7d2462..e16ae5b 100644
--- a/include/boot_fit.h
+++ b/include/boot_fit.h
@@ -5,5 +5,10 @@
  * SPDX-License-Identifier:     GPL-2.0+
  */
 
-int fdt_offset(void *fit);
-void *locate_dtb_in_fit(void *fit);
+/**
+ * locate_dtb_in_fit - Find a DTB matching the board in a FIT image
+ * @fit:	pointer to the FIT image
+ *
+ * @return a pointer to a matching DTB blob if found, NULL otherwise
+ */
+void *locate_dtb_in_fit(const void *fit);
diff --git a/include/common.h b/include/common.h
index 1896335..4b521e1 100644
--- a/include/common.h
+++ b/include/common.h
@@ -609,6 +609,7 @@
 ulong	ticks2usec    (unsigned long ticks);
 
 /* lib/gunzip.c */
+int gzip_parse_header(const unsigned char *src, unsigned long len);
 int gunzip(void *, int, unsigned char *, unsigned long *);
 int zunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp,
 						int stoponerr, int offset);
diff --git a/include/configs/qemu-arm.h b/include/configs/qemu-arm.h
new file mode 100644
index 0000000..4376a24
--- /dev/null
+++ b/include/configs/qemu-arm.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017 Tuomas Tynkkynen
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <linux/sizes.h>
+
+/* Physical memory map */
+#define CONFIG_SYS_TEXT_BASE		0x00000000
+
+#define CONFIG_NR_DRAM_BANKS		1
+#define CONFIG_SYS_SDRAM_BASE		0x40000000
+
+/* The DTB generated by QEMU is placed at start of RAM, stay away from there */
+#define CONFIG_SYS_INIT_SP_ADDR         (CONFIG_SYS_SDRAM_BASE + SZ_2M)
+#define CONFIG_SYS_LOAD_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_2M)
+#define CONFIG_SYS_MALLOC_LEN		SZ_16M
+
+/* QEMU's PL011 serial port is detected via FDT using the device model */
+#define CONFIG_PL01X_SERIAL
+
+/* QEMU implements a 62.5MHz architected timer */
+/* FIXME: can we rely on CNTFREQ instead of hardcoding this fact here? */
+#define CONFIG_SYS_ARCH_TIMER
+#define CONFIG_SYS_HZ                       1000
+#define CONFIG_SYS_HZ_CLOCK                 62500000
+
+/* For block devices, QEMU emulates an ICH9 AHCI controller over PCI */
+#define CONFIG_SYS_SCSI_MAX_SCSI_ID 6
+#define CONFIG_SCSI_AHCI
+#define CONFIG_LIBATA
+
+/* Environment options */
+#define CONFIG_ENV_SIZE				SZ_64K
+
+#include <config_distro_defaults.h>
+
+#define BOOT_TARGET_DEVICES(func) \
+	func(SCSI, scsi, 0)
+
+#include <config_distro_bootcmd.h>
+
+#define CONFIG_PREBOOT "pci enum"
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	"fdt_high=0xffffffff\0" \
+	"initrd_high=0xffffffff\0" \
+	"fdt_addr=0x40000000\0" \
+	"scriptaddr=0x40200000\0" \
+	"pxefile_addr_r=0x40300000\0" \
+	"kernel_addr_r=0x40400000\0" \
+	"ramdisk_addr_r=0x44000000\0" \
+	BOOTENV
+
+#endif /* __CONFIG_H */
diff --git a/include/image.h b/include/image.h
index af98ed9..93451dd 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1299,6 +1299,19 @@
 #define FDT_ERROR	((ulong)(-1))
 
 ulong fdt_getprop_u32(const void *fdt, int node, const char *prop);
+
+/**
+ * fit_find_config_node() - Find the node for the best DTB in a FIT image
+ *
+ * A FIT image contains one or more DTBs. This function parses the
+ * configurations described in the FIT images and returns the node of
+ * the first matching DTB. To check if a DTB matches a board, this function
+ * calls board_fit_config_name_match(). If no matching DTB is found, it returns
+ * the node described by the default configuration if it exists.
+ *
+ * @fdt: pointer to flat device tree
+ * @return the node if found, -ve otherwise
+ */
 int fit_find_config_node(const void *fdt);
 
 /**
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 0b61671..87d2d95 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -57,6 +57,11 @@
 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+	({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+
+#define DIV_ROUND_UP_ULL(ll, d)		DIV_ROUND_DOWN_ULL((ll) + (d) - 1, (d))
+
 #if BITS_PER_LONG == 32
 # define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d)
 #else
diff --git a/include/linux/lzo.h b/include/linux/lzo.h
index 88687fa..8981d04 100644
--- a/include/linux/lzo.h
+++ b/include/linux/lzo.h
@@ -31,6 +31,9 @@
 int lzop_decompress(const unsigned char *src, size_t src_len,
 		    unsigned char *dst, size_t *dst_len);
 
+/* check if the header is valid (based on magic numbers) */
+bool lzop_is_valid_header(const unsigned char *src);
+
 /*
  * Return values (< 0 = Error)
  */
diff --git a/include/part.h b/include/part.h
index b2e820e..0caceaf 100644
--- a/include/part.h
+++ b/include/part.h
@@ -174,6 +174,21 @@
 			    disk_partition_t *info, int allow_whole_dev);
 
 /**
+ * part_get_info_by_name_type() - Search for a partition by name
+ *                                for only specified partition type
+ *
+ * @param dev_desc - block device descriptor
+ * @param gpt_name - the specified table entry name
+ * @param info - returns the disk partition info
+ * @param part_type - only search in partitions of this type
+ *
+ * @return - the partition number on match (starting on 1), -1 on no match,
+ * otherwise error
+ */
+int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
+			       disk_partition_t *info, int part_type);
+
+/**
  * part_get_info_by_name() - Search for a partition by name
  *                           among all available registered partitions
  *
diff --git a/include/pci.h b/include/pci.h
index c8ef997..7adc043 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -1086,6 +1086,57 @@
 int pci_read_config16(pci_dev_t pcidev, int offset, u16 *valuep);
 int pci_read_config8(pci_dev_t pcidev, int offset, u8 *valuep);
 
+/**
+ * pci_generic_mmap_write_config() - Generic helper for writing to
+ * memory-mapped PCI configuration space.
+ * @bus: Pointer to the PCI bus
+ * @addr_f: Callback for calculating the config space address
+ * @bdf: Identifies the PCI device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus. The callback function @addr_f is
+ * responsible for calculating the CPU address of the respective configuration
+ * space offset.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+int pci_generic_mmap_write_config(
+	struct udevice *bus,
+	int (*addr_f)(struct udevice *bus, pci_dev_t bdf, uint offset, void **addrp),
+	pci_dev_t bdf,
+	uint offset,
+	ulong value,
+	enum pci_size_t size);
+
+/**
+ * pci_generic_mmap_read_config() - Generic helper for reading from
+ * memory-mapped PCI configuration space.
+ * @bus: Pointer to the PCI bus
+ * @addr_f: Callback for calculating the config space address
+ * @bdf: Identifies the PCI device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus. The callback function @addr_f is responsible for
+ * calculating the CPU address of the respective configuration space offset.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+int pci_generic_mmap_read_config(
+	struct udevice *bus,
+	int (*addr_f)(struct udevice *bus, pci_dev_t bdf, uint offset, void **addrp),
+	pci_dev_t bdf,
+	uint offset,
+	ulong *valuep,
+	enum pci_size_t size);
+
 #ifdef CONFIG_DM_PCI_COMPAT
 /* Compatibility with old naming */
 static inline int pci_write_config_dword(pci_dev_t pcidev, int offset,
diff --git a/lib/Kconfig b/lib/Kconfig
index aef940f..18663ba 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -180,6 +180,11 @@
 	help
 	  This enables support for LZO compression algorithm.r
 
+config SPL_LZO
+	bool "Enable LZO decompression support in SPL"
+	help
+	  This enables support for LZO compression algorithm in the SPL.
+
 config SPL_GZIP
 	bool "Enable gzip decompression support for SPL build"
 	select SPL_ZLIB
diff --git a/lib/Makefile b/lib/Makefile
index 80216c2..8cd779f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -11,7 +11,6 @@
 obj-$(CONFIG_EFI_LOADER) += efi_loader/
 obj-$(CONFIG_EFI_LOADER) += efi_selftest/
 obj-$(CONFIG_LZMA) += lzma/
-obj-$(CONFIG_LZO) += lzo/
 obj-$(CONFIG_BZIP2) += bzip2/
 obj-$(CONFIG_TIZEN) += tizen/
 obj-$(CONFIG_FIT) += libfdt/
@@ -52,6 +51,8 @@
 
 obj-$(CONFIG_$(SPL_)ZLIB) += zlib/
 obj-$(CONFIG_$(SPL_)GZIP) += gunzip.o
+obj-$(CONFIG_$(SPL_)LZO) += lzo/
+
 
 obj-$(CONFIG_$(SPL_TPL_)SAVEENV) += qsort.o
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += libfdt/
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 107a892..45f3fe7 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -4,17 +4,18 @@
  */
 
 #ifndef USE_HOSTCC
-#include <boot_fit.h>
 #include <common.h>
+#include <boot_fit.h>
 #include <dm.h>
+#include <dm/of_extra.h>
 #include <errno.h>
-#include <serial.h>
-#include <libfdt.h>
-#include <fdt_support.h>
 #include <fdtdec.h>
+#include <fdt_support.h>
+#include <libfdt.h>
+#include <serial.h>
 #include <asm/sections.h>
-#include <dm/of_extra.h>
 #include <linux/ctype.h>
+#include <linux/lzo.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -1203,9 +1204,66 @@
 }
 #endif
 
+#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\
+	CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO)
+static int uncompress_blob(const void *src, ulong sz_src, void **dstp)
+{
+	size_t sz_out = CONFIG_SPL_MULTI_DTB_FIT_UNCOMPRESS_SZ;
+	ulong sz_in = sz_src;
+	void *dst;
+	int rc;
+
+	if (CONFIG_IS_ENABLED(GZIP))
+		if (gzip_parse_header(src, sz_in) < 0)
+			return -1;
+	if (CONFIG_IS_ENABLED(LZO))
+		if (!lzop_is_valid_header(src))
+			return -EBADMSG;
+
+	if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) {
+		dst = malloc(sz_out);
+		if (!dst) {
+			puts("uncompress_blob: Unable to allocate memory\n");
+			return -ENOMEM;
+		}
+	} else  {
+#  if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA)
+		dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR);
+#  else
+		return -ENOTSUPP;
+#  endif
+	}
+
+	if (CONFIG_IS_ENABLED(GZIP))
+		rc = gunzip(dst, sz_out, (u8 *)src, &sz_in);
+	else if (CONFIG_IS_ENABLED(LZO))
+		rc = lzop_decompress(src, sz_in, dst, &sz_out);
+
+	if (rc < 0) {
+		/* not a valid compressed blob */
+		puts("uncompress_blob: Unable to uncompress\n");
+		if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC))
+			free(dst);
+		return -EBADMSG;
+	}
+	*dstp = dst;
+	return 0;
+}
+# else
+static int uncompress_blob(const void *src, ulong sz_src, void **dstp)
+{
+	return -ENOTSUPP;
+}
+# endif
+#endif
+
 int fdtdec_setup(void)
 {
 #if CONFIG_IS_ENABLED(OF_CONTROL)
+# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+	void *fdt_blob;
+# endif
 # ifdef CONFIG_OF_EMBED
 	/* Get a pointer to the FDT */
 	gd->fdt_blob = __dtb_dt_begin;
@@ -1216,15 +1274,6 @@
 		gd->fdt_blob = (ulong *)&_image_binary_end;
 	else
 		gd->fdt_blob = (ulong *)&__bss_end;
-
-#  elif defined CONFIG_FIT_EMBED
-	gd->fdt_blob = locate_dtb_in_fit(&_end);
-
-	if (gd->fdt_blob == NULL || gd->fdt_blob <= ((void *)&_end)) {
-		puts("Failed to find proper dtb in embedded FIT Image\n");
-		return -1;
-	}
-
 #  else
 	/* FDT is at end of image */
 	gd->fdt_blob = (ulong *)&_end;
@@ -1243,7 +1292,27 @@
 	gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16,
 						(uintptr_t)gd->fdt_blob);
 # endif
+
+# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+	/*
+	 * Try and uncompress the blob.
+	 * Unfortunately there is no way to know how big the input blob really
+	 * is. So let us set the maximum input size arbitrarily high. 16MB
+	 * ought to be more than enough for packed DTBs.
+	 */
+	if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0)
+		gd->fdt_blob = fdt_blob;
+
+	/*
+	 * Check if blob is a FIT images containings DTBs.
+	 * If so, pick the most relevant
+	 */
+	fdt_blob = locate_dtb_in_fit(gd->fdt_blob);
+	if (fdt_blob)
+		gd->fdt_blob = fdt_blob;
+# endif
 #endif
+
 	return fdtdec_prepare_fdt();
 }
 
diff --git a/lib/gunzip.c b/lib/gunzip.c
index 832b306..adb86c7 100644
--- a/lib/gunzip.c
+++ b/lib/gunzip.c
@@ -42,7 +42,7 @@
 	free (addr);
 }
 
-int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp)
+int gzip_parse_header(const unsigned char *src, unsigned long len)
 {
 	int i, flags;
 
@@ -63,12 +63,21 @@
 			;
 	if ((flags & HEAD_CRC) != 0)
 		i += 2;
-	if (i >= *lenp) {
+	if (i >= len) {
 		puts ("Error: gunzip out of data in header\n");
 		return (-1);
 	}
+	return i;
+}
+
+int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp)
+{
+	int offset = gzip_parse_header(src, *lenp);
+
+	if (offset < 0)
+		return offset;
 
-	return zunzip(dst, dstlen, src, lenp, 1, i);
+	return zunzip(dst, dstlen, src, lenp, 1, offset);
 }
 
 #ifdef CONFIG_CMD_UNZIP
diff --git a/lib/lzo/lzo1x_decompress.c b/lib/lzo/lzo1x_decompress.c
index ccc90b8..65fef0b 100644
--- a/lib/lzo/lzo1x_decompress.c
+++ b/lib/lzo/lzo1x_decompress.c
@@ -30,16 +30,29 @@
 
 #define HEADER_HAS_FILTER	0x00000800L
 
-static inline const unsigned char *parse_header(const unsigned char *src)
+
+bool lzop_is_valid_header(const unsigned char *src)
 {
-	u16 version;
 	int i;
-
 	/* read magic: 9 first bytes */
 	for (i = 0; i < ARRAY_SIZE(lzop_magic); i++) {
 		if (*src++ != lzop_magic[i])
-			return NULL;
+			return false;
 	}
+	return true;
+}
+
+static inline const unsigned char *parse_header(const unsigned char *src)
+{
+	u16 version;
+	int i;
+
+	if (!lzop_is_valid_header(src))
+		return NULL;
+
+	/* skip header */
+	src += 9;
+
 	/* get version (2bytes), skip library version (2),
 	 * 'need to be extracted' version (2) and
 	 * method (1) */
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index b86ea76..49b27ac 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -209,10 +209,21 @@
 quiet_cmd_copy = COPY    $@
       cmd_copy = cp $< $@
 
+ifneq ($(CONFIG_SPL_MULTI_DTB_FIT),y)
+FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).dtb
+else ifeq ($(CONFIG_SPL_MULTI_DTB_FIT_LZO),y)
+FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit.lzo
+else ifeq ($(CONFIG_SPL_MULTI_DTB_FIT_GZIP),y)
+FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit.gz
+else
+FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit
+endif
+
+
 ifeq ($(CONFIG_$(SPL_TPL_)OF_CONTROL)$(CONFIG_OF_SEPARATE)$(CONFIG_$(SPL_TPL_)OF_PLATDATA),yy)
 $(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin \
 		$(if $(CONFIG_SPL_SEPARATE_BSS),,$(obj)/$(SPL_BIN)-pad.bin) \
-		$(obj)/$(SPL_BIN).dtb FORCE
+		$(FINAL_DTB_CONTAINER)  FORCE
 	$(call if_changed,cat)
 
 $(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN)-dtb.bin FORCE
@@ -383,6 +394,28 @@
 PHONY += FORCE
 FORCE:
 
+PHONY += dtbs
+dtbs:
+	$(Q)$(MAKE) $(build)=dts dtbs
+
 # Declare the contents of the .PHONY variable as phony.  We keep that
 # information in a variable so we can use it in if_changed and friends.
 .PHONY: $(PHONY)
+
+SHRUNK_ARCH_DTB = $(patsubst %,$(obj)/dts/%.dtb,$(subst ",,$(CONFIG_SPL_OF_LIST)))
+.SECONDEXPANSION:
+$(SHRUNK_ARCH_DTB): $$(patsubst $(obj)/dts/%, arch/$(ARCH)/dts/%, $$@)
+	$(call if_changed,fdtgrep)
+
+MKIMAGEFLAGS_$(SPL_BIN).multidtb.fit = -f auto -A $(ARCH) -T firmware -C none -O u-boot \
+	-n "Multi DTB fit image for $(SPL_BIN)" -E \
+	$(patsubst %,-b %,$(SHRUNK_ARCH_DTB))
+
+$(obj)/$(SPL_BIN).multidtb.fit: /dev/null $(SHRUNK_ARCH_DTB) FORCE
+	$(call if_changed,mkimage)
+
+$(obj)/$(SPL_BIN).multidtb.fit.gz: $(obj)/$(SPL_BIN).multidtb.fit
+	@gzip -kf9 $< > $@
+
+$(obj)/$(SPL_BIN).multidtb.fit.lzo: $(obj)/$(SPL_BIN).multidtb.fit
+	@lzop -f9 $< > $@
diff --git a/test/dm/eth.c b/test/dm/eth.c
index 122fab9..67fd660 100644
--- a/test/dm/eth.c
+++ b/test/dm/eth.c
@@ -110,6 +110,7 @@
 	char ethaddr[DM_TEST_ETH_NUM][18];
 	int i;
 
+	memset(ethaddr, '\0', sizeof(ethaddr));
 	net_ping_ip = string_to_ip("1.1.2.2");
 
 	/* Prepare the test scenario */
@@ -119,7 +120,7 @@
 		ut_assertok(device_remove(dev[i], DM_REMOVE_NORMAL));
 
 		/* Invalidate MAC address */
-		strcpy(ethaddr[i], env_get(addrname[i]));
+		strncpy(ethaddr[i], env_get(addrname[i]), 17);
 		/* Must disable access protection for ethaddr before clearing */
 		env_set(".flags", addrname[i]);
 		env_set(addrname[i], NULL);
@@ -187,7 +188,8 @@
 	net_ping_ip = string_to_ip("1.1.2.2");
 
 	/* Invalidate eth1's MAC address */
-	strcpy(ethaddr, env_get("eth1addr"));
+	memset(ethaddr, '\0', sizeof(ethaddr));
+	strncpy(ethaddr, env_get("eth1addr"), 17);
 	/* Must disable access protection for eth1addr before clearing */
 	env_set(".flags", "eth1addr");
 	env_set("eth1addr", NULL);
@@ -200,7 +202,7 @@
 
 	if (!retval) {
 		/* Invalidate eth0's MAC address */
-		strcpy(ethaddr, env_get("ethaddr"));
+		strncpy(ethaddr, env_get("ethaddr"), 17);
 		/* Must disable access protection for ethaddr before clearing */
 		env_set(".flags", "ethaddr");
 		env_set("ethaddr", NULL);
diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh
index b194864..20d5dd8 100755
--- a/test/fs/fs-test.sh
+++ b/test/fs/fs-test.sh
@@ -9,14 +9,18 @@
 # It currently tests the fs/sb and native commands for ext4 and fat partitions
 # Expected results are as follows:
 # EXT4 tests:
-# fs-test.sb.ext4.out: Summary: PASS: 23 FAIL: 0
-# fs-test.ext4.out: Summary: PASS: 23 FAIL: 0
-# fs-test.fs.ext4.out: Summary: PASS: 23 FAIL: 0
-# FAT tests:
-# fs-test.sb.fat.out: Summary: PASS: 23 FAIL: 0
-# fs-test.fat.out: Summary: PASS: 20 FAIL: 3
-# fs-test.fs.fat.out: Summary: PASS: 20 FAIL: 3
-# Total Summary: TOTAL PASS: 132 TOTAL FAIL: 6
+# fs-test.sb.ext4.out: Summary: PASS: 24 FAIL: 0
+# fs-test.ext4.out: Summary: PASS: 24 FAIL: 0
+# fs-test.fs.ext4.out: Summary: PASS: 24 FAIL: 0
+# FAT16 tests:
+# fs-test.sb.fat16.out: Summary: PASS: 24 FAIL: 0
+# fs-test.fat16.out: Summary: PASS: 21 FAIL: 3
+# fs-test.fs.fat16.out: Summary: PASS: 21 FAIL: 3
+# FAT32 tests:
+# fs-test.sb.fat32.out: Summary: PASS: 24 FAIL: 0
+# fs-test.fat32.out: Summary: PASS: 21 FAIL: 3
+# fs-test.fs.fat32.out: Summary: PASS: 21 FAIL: 3
+# Total Summary: TOTAL PASS: 204 TOTAL FAIL: 12
 
 # pre-requisite binaries list.
 PREREQ_BINS="md5sum mkfs mount umount dd fallocate mkdir"
@@ -41,7 +45,7 @@
 BIG_FILE="2.5GB.file"
 
 # $MD5_FILE will have the expected md5s when we do the test
-# They shall have a suffix which represents their file system (ext4/fat)
+# They shall have a suffix which represents their file system (ext4/fat16/...)
 MD5_FILE="${OUT_DIR}/md5s.list"
 
 # $OUT shall be the prefix of the test output. Their suffix will be .out
@@ -104,15 +108,25 @@
 }
 
 # 1st parameter is the name of the image file to be created
-# 2nd parameter is the filesystem - fat ext4 etc
+# 2nd parameter is the filesystem - fat16 ext4 etc
 # -F cant be used with fat as it means something else.
 function create_image() {
 	# Create image if not already present - saves time, while debugging
-	if [ "$2" = "ext4" ]; then
+	case "$2" in
+		fat16)
+		MKFS_OPTION="-F 16"
+		FS_TYPE="fat"
+		;;
+		fat32)
+		MKFS_OPTION="-F 32"
+		FS_TYPE="fat"
+		;;
+		ext4)
 		MKFS_OPTION="-F"
-	else
-		MKFS_OPTION=""
-	fi
+		FS_TYPE="ext4"
+		;;
+	esac
+
 	if [ ! -f "$1" ]; then
 		fallocate -l 3G "$1" &> /dev/null
 		if [ $? -ne 0 ]; then
@@ -123,8 +137,8 @@
 				exit $?
 			fi
 		fi
-		mkfs -t "$2" $MKFS_OPTION "$1" &> /dev/null
-		if [ $? -ne 0 -a "$2" = "fat" ]; then
+		mkfs -t "$FS_TYPE" $MKFS_OPTION "$1" &> /dev/null
+		if [ $? -ne 0 -a "$FS_TYPE" = "fat" ]; then
 			# If we fail and we did fat, try vfat.
 			mkfs -t vfat $MKFS_OPTION "$1" &> /dev/null
 		fi
@@ -136,7 +150,7 @@
 }
 
 # 1st parameter is image file
-# 2nd parameter is file system type - fat/ext4
+# 2nd parameter is file system type - fat16/ext4/...
 # 3rd parameter is name of small file
 # 4th parameter is name of big file
 # 5th parameter is fs/nonfs/sb - to dictate generic fs commands or
@@ -149,7 +163,7 @@
 	length="0x00100000"
 
 	case "$2" in
-		fat)
+		fat*)
 		FPATH=""
 		PREFIX="fat"
 		WRITE="write"
@@ -215,10 +229,14 @@
 # We want ${PREFIX}size host 0:0 $3 for host commands and
 # sb size hostfs - $3 for hostfs commands.
 # 1MB is 0x0010 0000
-# Test Case 2 - size of small file
+# Test Case 2a - size of small file
 ${PREFIX}size host${SUFFIX} ${FPATH}$FILE_SMALL
 printenv filesize
 setenv filesize
+# Test Case 2b - size of small file via a path using '..'
+${PREFIX}size host${SUFFIX} ${FPATH}SUBDIR/../$FILE_SMALL
+printenv filesize
+setenv filesize
 
 # 2.5GB (1024*1024*2500) is 0x9C40 0000
 # Test Case 3 - size of big file
@@ -333,6 +351,9 @@
 	mkdir -p "$MOUNT_DIR"
 	sudo mount -o loop,rw "$1" "$MOUNT_DIR"
 
+	# Create a subdirectory.
+	sudo mkdir -p "$MOUNT_DIR/SUBDIR"
+
 	# Create big file in this image.
 	# Note that we work only on the start 1MB, couple MBs in the 2GB range
 	# and the last 1 MB of the huge 2.5GB file.
@@ -439,16 +460,19 @@
 	FAIL=0
 
 	# Check if the ls is showing correct results for 2.5 gb file
-	grep -A6 "Test Case 1 " "$1" | egrep -iq "2621440000 *$4"
+	grep -A7 "Test Case 1 " "$1" | egrep -iq "2621440000 *$4"
 	pass_fail "TC1: ls of $4"
 
 	# Check if the ls is showing correct results for 1 mb file
-	grep -A6 "Test Case 1 " "$1" | egrep -iq "1048576 *$3"
+	grep -A7 "Test Case 1 " "$1" | egrep -iq "1048576 *$3"
 	pass_fail "TC1: ls of $3"
 
 	# Check size command on 1MB.file
-	egrep -A3 "Test Case 2 " "$1" | grep -q "filesize=100000"
+	egrep -A3 "Test Case 2a " "$1" | grep -q "filesize=100000"
 	pass_fail "TC2: size of $3"
+	# Check size command on 1MB.file via a path using '..'
+	egrep -A3 "Test Case 2b " "$1" | grep -q "filesize=100000"
+	pass_fail "TC2: size of $3 via a path using '..'"
 
 	# Check size command on 2.5GB.file
 	egrep -A3 "Test Case 3 " "$1" | grep -q "filesize=9c400000"
@@ -550,7 +574,7 @@
 # In each loop, for a given file system image, we test both the
 # fs command, like load/size/write, the file system specific command
 # like: ext4load/ext4size/ext4write and the sb load/ls/save commands.
-for fs in ext4 fat; do
+for fs in ext4 fat16 fat32; do
 
 	echo "Creating $fs image if not already present."
 	IMAGE=${IMG}.${fs}.img
@@ -563,11 +587,14 @@
 
 	# Lets mount the image and test sb hostfs commands
 	mkdir -p "$MOUNT_DIR"
-	if [ "$fs" = "fat" ]; then
+	case "$fs" in
+		fat*)
 		uid="uid=`id -u`"
-	else
+		;;
+		*)
 		uid=""
-	fi
+		;;
+	esac
 	sudo mount -o loop,rw,$uid "$IMAGE" "$MOUNT_DIR"
 	sudo chmod 777 "$MOUNT_DIR"
 
diff --git a/test/overlay/cmd_ut_overlay.c b/test/overlay/cmd_ut_overlay.c
index 24891ee..c730a11 100644
--- a/test/overlay/cmd_ut_overlay.c
+++ b/test/overlay/cmd_ut_overlay.c
@@ -226,6 +226,7 @@
 	void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
 	void *fdt_overlay_stacked = &__dtb_test_fdt_overlay_stacked_begin;
 	void *fdt_base_copy, *fdt_overlay_copy, *fdt_overlay_stacked_copy;
+	int ret = -ENOMEM;
 
 	uts = calloc(1, sizeof(*uts));
 	if (!uts)
@@ -236,16 +237,16 @@
 
 	fdt_base_copy = malloc(FDT_COPY_SIZE);
 	if (!fdt_base_copy)
-		return -ENOMEM;
+		goto err1;
 	uts->priv = fdt_base_copy;
 
 	fdt_overlay_copy = malloc(FDT_COPY_SIZE);
 	if (!fdt_overlay_copy)
-		return -ENOMEM;
+		goto err2;
 
 	fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE);
 	if (!fdt_overlay_stacked_copy)
-		return -ENOMEM;
+		goto err3;
 
 	/*
 	 * Resize the FDT to 4k so that we have room to operate on
@@ -293,11 +294,18 @@
 	}
 
 	printf("Failures: %d\n", uts->fail_count);
+	if (!uts->fail_count)
+		ret = 0;
+	else
+		ret = CMD_RET_FAILURE;
 
 	free(fdt_overlay_stacked_copy);
+err3:
 	free(fdt_overlay_copy);
+err2:
 	free(fdt_base_copy);
+err1:
 	free(uts);
 
-	return uts->fail_count ? CMD_RET_FAILURE : 0;
+	return ret;
 }
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 4dc8bd8..c602656 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -372,7 +372,7 @@
 	if (fd < 0) {
 		fprintf(stderr, "%s: Can't open %s: %s\n",
 			params->cmdname, fname, strerror(errno));
-		goto err;
+		goto err_buf;
 	}
 	ret = write(fd, buf, size);
 	if (ret != size) {
@@ -501,6 +501,7 @@
 		ret = -EIO;
 		goto err;
 	}
+	free(buf);
 	close(fd);
 	return 0;
 
@@ -601,6 +602,7 @@
 	ret = 0;
 
 err:
+	munmap(old_fdt, sbuf.st_size);
 	free(fdt);
 	close(fd);
 	return ret;