Browse Source

Merge git://git.denx.de/u-boot-fdt

Tom Rini 7 years ago
parent
commit
08cebeeaad

+ 2 - 3
.travis.yml

@@ -26,12 +26,11 @@ addons:
     - grub-efi-ia32-bin
     - grub-efi-ia32-bin
     - rpm2cpio
     - rpm2cpio
     - wget
     - wget
-    - device-tree-compiler
 
 
 install:
 install:
  # install latest device tree compiler
  # install latest device tree compiler
- #- git clone --depth=1 git://git.kernel.org/pub/scm/utils/dtc/dtc.git /tmp/dtc
- #- make -j4 -C /tmp/dtc
+ - git clone --depth=1 git://git.kernel.org/pub/scm/utils/dtc/dtc.git /tmp/dtc
+ - make -j4 -C /tmp/dtc
  # Clone uboot-test-hooks
  # Clone uboot-test-hooks
  - git clone --depth=1 git://github.com/swarren/uboot-test-hooks.git /tmp/uboot-test-hooks
  - git clone --depth=1 git://github.com/swarren/uboot-test-hooks.git /tmp/uboot-test-hooks
  - ln -s travis-ci /tmp/uboot-test-hooks/bin/`hostname`
  - ln -s travis-ci /tmp/uboot-test-hooks/bin/`hostname`

+ 3 - 4
cmd/fdt.c

@@ -667,11 +667,10 @@ static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (!fdt_valid(&blob))
 		if (!fdt_valid(&blob))
 			return CMD_RET_FAILURE;
 			return CMD_RET_FAILURE;
 
 
-		ret = fdt_overlay_apply(working_fdt, blob);
-		if (ret) {
-			printf("fdt_overlay_apply(): %s\n", fdt_strerror(ret));
+		/* apply method prints messages on error */
+		ret = fdt_overlay_apply_verbose(working_fdt, blob);
+		if (ret)
 			return CMD_RET_FAILURE;
 			return CMD_RET_FAILURE;
-		}
 	}
 	}
 #endif
 #endif
 	/* resize the fdt */
 	/* resize the fdt */

+ 31 - 0
common/fdt_support.c

@@ -1655,3 +1655,34 @@ int fdt_fixup_display(void *blob, const char *path, const char *display)
 	}
 	}
 	return toff;
 	return toff;
 }
 }
+
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+/**
+ * fdt_overlay_apply_verbose - Apply an overlay with verbose error reporting
+ *
+ * @fdt: ptr to device tree
+ * @fdto: ptr to device tree overlay
+ *
+ * Convenience function to apply an overlay and display helpful messages
+ * in the case of an error
+ */
+int fdt_overlay_apply_verbose(void *fdt, void *fdto)
+{
+	int err;
+	bool has_symbols;
+
+	err = fdt_path_offset(fdt, "/__symbols__");
+	has_symbols = err >= 0;
+
+	err = fdt_overlay_apply(fdt, fdto);
+	if (err < 0) {
+		printf("failed on fdt_overlay_apply(): %s\n",
+				fdt_strerror(err));
+		if (!has_symbols) {
+			printf("base fdt does did not have a /__symbols__ node\n");
+			printf("make sure you've compiled with -@\n");
+		}
+	}
+	return err;
+}
+#endif

+ 3 - 4
common/image-fdt.c

@@ -356,17 +356,16 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,
 			if (fit_check_format(buf)) {
 			if (fit_check_format(buf)) {
 				ulong load, len;
 				ulong load, len;
 
 
-				fdt_noffset = fit_image_load(images,
+				fdt_noffset = boot_get_fdt_fit(images,
 					fdt_addr, &fit_uname_fdt,
 					fdt_addr, &fit_uname_fdt,
 					&fit_uname_config,
 					&fit_uname_config,
-					arch, IH_TYPE_FLATDT,
-					BOOTSTAGE_ID_FIT_FDT_START,
-					FIT_LOAD_OPTIONAL, &load, &len);
+					arch, &load, &len);
 
 
 				images->fit_hdr_fdt = map_sysmem(fdt_addr, 0);
 				images->fit_hdr_fdt = map_sysmem(fdt_addr, 0);
 				images->fit_uname_fdt = fit_uname_fdt;
 				images->fit_uname_fdt = fit_uname_fdt;
 				images->fit_noffset_fdt = fdt_noffset;
 				images->fit_noffset_fdt = fdt_noffset;
 				fdt_addr = load;
 				fdt_addr = load;
+
 				break;
 				break;
 			} else
 			} else
 #endif
 #endif

+ 199 - 11
common/image-fit.c

@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <errno.h>
 #include <mapmem.h>
 #include <mapmem.h>
 #include <asm/io.h>
 #include <asm/io.h>
+#include <malloc.h>
 DECLARE_GLOBAL_DATA_PTR;
 DECLARE_GLOBAL_DATA_PTR;
 #endif /* !USE_HOSTCC*/
 #endif /* !USE_HOSTCC*/
 
 
@@ -434,6 +435,10 @@ void fit_image_print(const void *fit, int image_noffset, const char *p)
 			printf("0x%08lx\n", load);
 			printf("0x%08lx\n", load);
 	}
 	}
 
 
+	/* optional load address for FDT */
+	if (type == IH_TYPE_FLATDT && !fit_image_get_load(fit, image_noffset, &load))
+		printf("%s  Load Address: 0x%08lx\n", p, load);
+
 	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
 	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
 	    (type == IH_TYPE_RAMDISK)) {
 	    (type == IH_TYPE_RAMDISK)) {
 		ret = fit_image_get_entry(fit, image_noffset, &entry);
 		ret = fit_image_get_entry(fit, image_noffset, &entry);
@@ -1454,6 +1459,8 @@ int fit_conf_get_node(const void *fit, const char *conf_uname)
 {
 {
 	int noffset, confs_noffset;
 	int noffset, confs_noffset;
 	int len;
 	int len;
+	const char *s;
+	char *conf_uname_copy = NULL;
 
 
 	confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
 	confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
 	if (confs_noffset < 0) {
 	if (confs_noffset < 0) {
@@ -1475,29 +1482,58 @@ int fit_conf_get_node(const void *fit, const char *conf_uname)
 		debug("Found default configuration: '%s'\n", conf_uname);
 		debug("Found default configuration: '%s'\n", conf_uname);
 	}
 	}
 
 
+	s = strchr(conf_uname, '#');
+	if (s) {
+		len = s - conf_uname;
+		conf_uname_copy = malloc(len + 1);
+		if (!conf_uname_copy) {
+			debug("Can't allocate uname copy: '%s'\n",
+					conf_uname);
+			return -ENOMEM;
+		}
+		memcpy(conf_uname_copy, conf_uname, len);
+		conf_uname_copy[len] = '\0';
+		conf_uname = conf_uname_copy;
+	}
+
 	noffset = fdt_subnode_offset(fit, confs_noffset, conf_uname);
 	noffset = fdt_subnode_offset(fit, confs_noffset, conf_uname);
 	if (noffset < 0) {
 	if (noffset < 0) {
 		debug("Can't get node offset for configuration unit name: '%s' (%s)\n",
 		debug("Can't get node offset for configuration unit name: '%s' (%s)\n",
 		      conf_uname, fdt_strerror(noffset));
 		      conf_uname, fdt_strerror(noffset));
 	}
 	}
 
 
+	if (conf_uname_copy)
+		free(conf_uname_copy);
+
 	return noffset;
 	return noffset;
 }
 }
 
 
-int fit_conf_get_prop_node(const void *fit, int noffset,
+int fit_conf_get_prop_node_count(const void *fit, int noffset,
 		const char *prop_name)
 		const char *prop_name)
 {
 {
-	char *uname;
+	return fdt_stringlist_count(fit, noffset, prop_name);
+}
+
+int fit_conf_get_prop_node_index(const void *fit, int noffset,
+		const char *prop_name, int index)
+{
+	const char *uname;
 	int len;
 	int len;
 
 
 	/* get kernel image unit name from configuration kernel property */
 	/* get kernel image unit name from configuration kernel property */
-	uname = (char *)fdt_getprop(fit, noffset, prop_name, &len);
+	uname = fdt_stringlist_get(fit, noffset, prop_name, index, &len);
 	if (uname == NULL)
 	if (uname == NULL)
 		return len;
 		return len;
 
 
 	return fit_image_get_node(fit, uname);
 	return fit_image_get_node(fit, uname);
 }
 }
 
 
+int fit_conf_get_prop_node(const void *fit, int noffset,
+		const char *prop_name)
+{
+	return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0);
+}
+
 /**
 /**
  * fit_conf_print - prints out the FIT configuration details
  * fit_conf_print - prints out the FIT configuration details
  * @fit: pointer to the FIT format image header
  * @fit: pointer to the FIT format image header
@@ -1515,7 +1551,7 @@ void fit_conf_print(const void *fit, int noffset, const char *p)
 	char *desc;
 	char *desc;
 	const char *uname;
 	const char *uname;
 	int ret;
 	int ret;
-	int loadables_index;
+	int fdt_index, loadables_index;
 
 
 	/* Mandatory properties */
 	/* Mandatory properties */
 	ret = fit_get_desc(fit, noffset, &desc);
 	ret = fit_get_desc(fit, noffset, &desc);
@@ -1537,9 +1573,17 @@ void fit_conf_print(const void *fit, int noffset, const char *p)
 	if (uname)
 	if (uname)
 		printf("%s  Init Ramdisk: %s\n", p, uname);
 		printf("%s  Init Ramdisk: %s\n", p, uname);
 
 
-	uname = fdt_getprop(fit, noffset, FIT_FDT_PROP, NULL);
-	if (uname)
-		printf("%s  FDT:          %s\n", p, uname);
+	for (fdt_index = 0;
+	     uname = fdt_stringlist_get(fit, noffset, FIT_FDT_PROP,
+					fdt_index, NULL), uname;
+	     fdt_index++) {
+
+		if (fdt_index == 0)
+			printf("%s  FDT:          ", p);
+		else
+			printf("%s                ", p);
+		printf("%s\n", uname);
+	}
 
 
 	uname = fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL);
 	uname = fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL);
 	if (uname)
 	if (uname)
@@ -1641,6 +1685,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 	int cfg_noffset, noffset;
 	int cfg_noffset, noffset;
 	const char *fit_uname;
 	const char *fit_uname;
 	const char *fit_uname_config;
 	const char *fit_uname_config;
+	const char *fit_base_uname_config;
 	const void *fit;
 	const void *fit;
 	const void *buf;
 	const void *buf;
 	size_t size;
 	size_t size;
@@ -1656,6 +1701,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 	fit = map_sysmem(addr, 0);
 	fit = map_sysmem(addr, 0);
 	fit_uname = fit_unamep ? *fit_unamep : NULL;
 	fit_uname = fit_unamep ? *fit_unamep : NULL;
 	fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL;
 	fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL;
+	fit_base_uname_config = NULL;
 	prop_name = fit_get_image_type_property(image_type);
 	prop_name = fit_get_image_type_property(image_type);
 	printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
 	printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
 
 
@@ -1689,11 +1735,11 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 					BOOTSTAGE_SUB_NO_UNIT_NAME);
 					BOOTSTAGE_SUB_NO_UNIT_NAME);
 			return -ENOENT;
 			return -ENOENT;
 		}
 		}
-		fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
-		printf("   Using '%s' configuration\n", fit_uname_config);
+		fit_base_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
+		printf("   Using '%s' configuration\n", fit_base_uname_config);
 		if (image_type == IH_TYPE_KERNEL) {
 		if (image_type == IH_TYPE_KERNEL) {
 			/* Remember (and possibly verify) this config */
 			/* Remember (and possibly verify) this config */
-			images->fit_uname_cfg = fit_uname_config;
+			images->fit_uname_cfg = fit_base_uname_config;
 			if (IMAGE_ENABLE_VERIFY && images->verify) {
 			if (IMAGE_ENABLE_VERIFY && images->verify) {
 				puts("   Verifying Hash Integrity ... ");
 				puts("   Verifying Hash Integrity ... ");
 				if (fit_config_verify(fit, cfg_noffset)) {
 				if (fit_config_verify(fit, cfg_noffset)) {
@@ -1849,7 +1895,8 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 	if (fit_unamep)
 	if (fit_unamep)
 		*fit_unamep = (char *)fit_uname;
 		*fit_unamep = (char *)fit_uname;
 	if (fit_uname_configp)
 	if (fit_uname_configp)
-		*fit_uname_configp = (char *)fit_uname_config;
+		*fit_uname_configp = (char *)(fit_uname_config ? :
+					      fit_base_uname_config);
 
 
 	return noffset;
 	return noffset;
 }
 }
@@ -1873,3 +1920,144 @@ int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
 
 
 	return ret;
 	return ret;
 }
 }
+
+#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 fdt_noffset, cfg_noffset, count;
+	const void *fit;
+	const char *fit_uname = NULL;
+	const char *fit_uname_config = NULL;
+	char *fit_uname_config_copy = NULL;
+	char *next_config = NULL;
+	ulong load, len;
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+	ulong image_start, image_end;
+	ulong ovload, ovlen;
+	const char *uconfig;
+	const char *uname;
+	void *base, *ov;
+	int i, err, noffset, ov_noffset;
+#endif
+
+	fit_uname = fit_unamep ? *fit_unamep : NULL;
+
+	if (fit_uname_configp && *fit_uname_configp) {
+		fit_uname_config_copy = strdup(*fit_uname_configp);
+		if (!fit_uname_config_copy)
+			return -ENOMEM;
+
+		next_config = strchr(fit_uname_config_copy, '#');
+		if (next_config)
+			*next_config++ = '\0';
+		if (next_config - 1 > fit_uname_config_copy)
+			fit_uname_config = fit_uname_config_copy;
+	}
+
+	fdt_noffset = fit_image_load(images,
+		addr, &fit_uname, &fit_uname_config,
+		arch, IH_TYPE_FLATDT,
+		BOOTSTAGE_ID_FIT_FDT_START,
+		FIT_LOAD_OPTIONAL, &load, &len);
+
+	if (fdt_noffset < 0)
+		goto out;
+
+	debug("fit_uname=%s, fit_uname_config=%s\n",
+			fit_uname ? fit_uname : "<NULL>",
+			fit_uname_config ? fit_uname_config : "<NULL>");
+
+	fit = map_sysmem(addr, 0);
+
+	cfg_noffset = fit_conf_get_node(fit, fit_uname_config);
+
+	/* single blob, or error just return as well */
+	count = fit_conf_get_prop_node_count(fit, cfg_noffset, FIT_FDT_PROP);
+	if (count <= 1 && !next_config)
+		goto out;
+
+	/* we need to apply overlays */
+
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+	image_start = addr;
+	image_end = addr + fit_get_size(fit);
+	/* verify that relocation took place by load address not being in fit */
+	if (load >= image_start && load < image_end) {
+		/* check is simplified; fit load checks for overlaps */
+		printf("Overlayed FDT requires relocation\n");
+		fdt_noffset = -EBADF;
+		goto out;
+	}
+
+	base = map_sysmem(load, len);
+
+	/* apply extra configs in FIT first, followed by args */
+	for (i = 1; ; i++) {
+		if (i < count) {
+			noffset = fit_conf_get_prop_node_index(fit, cfg_noffset,
+							       FIT_FDT_PROP, i);
+			uname = fit_get_name(fit, noffset, NULL);
+			uconfig = NULL;
+		} else {
+			if (!next_config)
+				break;
+			uconfig = next_config;
+			next_config = strchr(next_config, '#');
+			if (next_config)
+				*next_config++ = '\0';
+			uname = NULL;
+		}
+
+		debug("%d: using uname=%s uconfig=%s\n", i, uname, uconfig);
+
+		ov_noffset = fit_image_load(images,
+			addr, &uname, &uconfig,
+			arch, IH_TYPE_FLATDT,
+			BOOTSTAGE_ID_FIT_FDT_START,
+			FIT_LOAD_REQUIRED, &ovload, &ovlen);
+		if (ov_noffset < 0) {
+			printf("load of %s failed\n", uname);
+			continue;
+		}
+		debug("%s loaded at 0x%08lx len=0x%08lx\n",
+				uname, ovload, ovlen);
+		ov = map_sysmem(ovload, ovlen);
+
+		base = map_sysmem(load, len + ovlen);
+		err = fdt_open_into(base, base, len + ovlen);
+		if (err < 0) {
+			printf("failed on fdt_open_into\n");
+			fdt_noffset = err;
+			goto out;
+		}
+		/* the verbose method prints out messages on error */
+		err = fdt_overlay_apply_verbose(base, ov);
+		if (err < 0) {
+			fdt_noffset = err;
+			goto out;
+		}
+		fdt_pack(base);
+		len = fdt_totalsize(base);
+	}
+#else
+	printf("config with overlays but CONFIG_OF_LIBFDT_OVERLAY not set\n");
+	fdt_noffset = -EBADF;
+#endif
+
+out:
+	if (datap)
+		*datap = load;
+	if (lenp)
+		*lenp = len;
+	if (fit_unamep)
+		*fit_unamep = fit_uname;
+	if (fit_uname_configp)
+		*fit_uname_configp = fit_uname_config;
+
+	if (fit_uname_config_copy)
+		free(fit_uname_config_copy);
+	return fdt_noffset;
+}
+#endif

+ 2 - 0
configs/sandbox_defconfig

@@ -190,7 +190,9 @@ CONFIG_CMD_DHRYSTONE=y
 CONFIG_TPM=y
 CONFIG_TPM=y
 CONFIG_LZ4=y
 CONFIG_LZ4=y
 CONFIG_ERRNO_STR=y
 CONFIG_ERRNO_STR=y
+CONFIG_OF_LIBFDT_OVERLAY=y
 CONFIG_UNIT_TEST=y
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_UT_DM=y
 CONFIG_UT_ENV=y
 CONFIG_UT_ENV=y
+CONFIG_UT_OVERLAY=y

+ 114 - 0
doc/README.fdt-overlays

@@ -0,0 +1,114 @@
+U-Boot FDT Overlay usage
+=============================================
+
+Overlays Syntax
+---------------
+
+Overlays require slightly different syntax compared to traditional overlays.
+Please refer to dt-object-internal.txt in the dtc sources for information
+regarding the internal format of overlays:
+https://git.kernel.org/pub/scm/utils/dtc/dtc.git/tree/Documentation/dt-object-internal.txt
+
+Building Overlays
+-----------------
+
+In a nutshell overlays provides a means to manipulate a symbol a previous dtb
+or overlay has defined. It requires both the base and all the overlays
+to be compiled with the -@ command line switch so that symbol information is
+included.
+
+Note support for -@ option can only be found in dtc version 1.4.4 or newer.
+Only version 4.14 or higher of the Linux kernel includes a built in version
+of dtc that meets this requirement.
+
+Building an overlay follows the same process as building a traditional dtb.
+
+For example:
+
+base.dts
+--------
+
+	/dts-v1/;
+	/ {
+		foo: foonode {
+			foo-property;
+		};
+	};
+
+	$ dtc -@ -I dts -O dtb -o base.dtb base.dts
+
+bar.dts
+-------
+
+	/dts-v1/;
+	/plugin/;
+	/ {
+		fragment@1 {
+			target = <&foo>;
+			__overlay__ {
+				overlay-1-property;
+				bar: barnode {
+					bar-property;
+				};
+			};
+		};
+	};
+
+	$ dtc -@ -I dts -O dtb -o bar.dtb bar.dts
+
+Ways to Utilize Overlays in U-boot
+----------------------------------
+
+There are two ways to apply overlays in U-boot.
+1. Include and define overlays within a FIT image and have overlays
+   automatically applied.
+
+2. Manually load and apply overlays
+
+The remainder of this document will discuss using overlays via the manual
+approach. For information on using overlays as part of a FIT image please see:
+doc/uImage.FIT/overlay-fdt-boot.txt
+
+Manually Loading and Applying Overlays
+--------------------------------------
+
+1. Figure out where to place both the base device tree blob and the
+overlay. Make sure you have enough space to grow the base tree without
+overlapping anything.
+
+=> setenv fdtaddr 0x87f00000
+=> setenv fdtovaddr 0x87fc0000
+
+2. Load the base blob and overlay blobs
+
+=> load ${devtype} ${bootpart} ${fdtaddr} ${bootdir}/base.dtb
+=> load ${devtype} ${bootpart} ${fdtovaddr} ${bootdir}/overlay.dtb
+
+3. Set it as the working fdt tree.
+
+=> fdtaddr $fdtaddr
+
+4. Grow it enough so it can 'fit' all the applied overlays
+
+=> fdt resize 8192
+
+5. You are now ready to apply the overlay.
+
+=> fdt apply $fdtovaddr
+
+6. Boot system like you would do with a traditional dtb.
+
+For bootm:
+
+=> bootm ${kerneladdr} - ${fdtaddr}
+
+For bootz:
+
+=> bootz ${kerneladdr} - ${fdtaddr}
+
+Please note that in case of an error, both the base and overlays are going
+to be invalidated, so keep copies to avoid reloading.
+
+Pantelis Antoniou
+pantelis.antoniou@konsulko.com
+11/7/2017

+ 1 - 1
doc/driver-model/of-plat.txt

@@ -111,7 +111,7 @@ struct dtd_rockchip_rk3288_dw_mshc {
         bool            cap_sd_highspeed;
         bool            cap_sd_highspeed;
         fdt32_t         card_detect_delay;
         fdt32_t         card_detect_delay;
         fdt32_t         clock_freq_min_max[2];
         fdt32_t         clock_freq_min_max[2];
-        struct phandle_2_cell clocks[4];
+        struct phandle_1_arg clocks[4];
         bool            disable_wp;
         bool            disable_wp;
         fdt32_t         fifo_depth;
         fdt32_t         fifo_depth;
         fdt32_t         interrupts[3];
         fdt32_t         interrupts[3];

+ 11 - 1
doc/uImage.FIT/command_syntax_extensions.txt

@@ -36,7 +36,7 @@ Old uImage:
 New uImage:
 New uImage:
 8.  bootm <addr1>
 8.  bootm <addr1>
 9.  bootm [<addr1>]:<subimg1>
 9.  bootm [<addr1>]:<subimg1>
-10. bootm [<addr1>]#<conf>
+10. bootm [<addr1>]#<conf>[#<extra-conf[#...]]
 11. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2>
 11. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2>
 12. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> [<addr3>]:<subimg3>
 12. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> [<addr3>]:<subimg3>
 13. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> <addr3>
 13. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> <addr3>
@@ -129,6 +129,12 @@ following syntax:
 - new uImage configuration specification
 - new uImage configuration specification
 <addr>#<configuration unit_name>
 <addr>#<configuration unit_name>
 
 
+- new uImage configuration specification with extra configuration components
+<addr>#<configuration unit_name>[#<extra configuration unit_name>[#..]]
+
+The extra configuration currently is supported only for additional device tree
+overlays to apply on the base device tree supplied by the first configuration
+unit.
 
 
 Examples:
 Examples:
 
 
@@ -138,6 +144,10 @@ bootm 200000:kernel@1
 - boot configuration "cfg@1" from a new uImage located at 200000:
 - boot configuration "cfg@1" from a new uImage located at 200000:
 bootm 200000#cfg@1
 bootm 200000#cfg@1
 
 
+- boot configuration "cfg@1" with extra "cfg@2" from a new uImage located
+  at 200000:
+bootm 200000#cfg@1#cfg@2
+
 - boot "kernel@1" from a new uImage at 200000 with initrd "ramdisk@2" found in
 - boot "kernel@1" from a new uImage at 200000 with initrd "ramdisk@2" found in
   some other new uImage stored at address 800000:
   some other new uImage stored at address 800000:
 bootm 200000:kernel@1 800000:ramdisk@2
 bootm 200000:kernel@1 800000:ramdisk@2

+ 225 - 0
doc/uImage.FIT/overlay-fdt-boot.txt

@@ -0,0 +1,225 @@
+U-Boot FDT Overlay FIT usage
+============================
+
+Introduction
+------------
+In many cases it is desirable to have a single FIT image support a multitude
+of similar boards and their expansion options. The same kernel on DT enabled
+platforms can support this easily enough by providing a DT blob upon boot
+that matches the desired configuration.
+
+This document focuses on specifically using overlays as part of a FIT image.
+General information regarding overlays including its syntax and building it
+can be found in doc/README.fdt-overlays
+
+Configuration without overlays
+------------------------------
+
+Take a hypothetical board named 'foo' where there are different supported
+revisions, reva and revb. Assume that both board revisions can use add a bar
+add-on board, while only the revb board can use a baz add-on board.
+
+Without using overlays the configuration would be as follows for every case.
+
+	/dts-v1/;
+	/ {
+		images {
+			kernel@1 {
+				data = /incbin/("./zImage");
+				type = "kernel";
+				arch = "arm";
+				os = "linux";
+				load = <0x82000000>;
+				entry = <0x82000000>;
+			};
+			fdt@1 {
+				data = /incbin/("./foo-reva.dtb");
+				type = "flat_dt";
+				arch = "arm";
+			};
+			fdt@2 {
+				data = /incbin/("./foo-revb.dtb");
+				type = "flat_dt";
+				arch = "arm";
+			};
+			fdt@3 {
+				data = /incbin/("./foo-reva-bar.dtb");
+				type = "flat_dt";
+				arch = "arm";
+			};
+			fdt@4 {
+				data = /incbin/("./foo-revb-bar.dtb");
+				type = "flat_dt";
+				arch = "arm";
+			};
+			fdt@5 {
+				data = /incbin/("./foo-revb-baz.dtb");
+				type = "flat_dt";
+				arch = "arm";
+			};
+			fdt@6 {
+				data = /incbin/("./foo-revb-bar-baz.dtb");
+				type = "flat_dt";
+				arch = "arm";
+			};
+		};
+
+		configurations {
+			default = "foo-reva.dtb;
+			foo-reva.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@1";
+			};
+			foo-revb.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@2";
+			};
+			foo-reva-bar.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@3";
+			};
+			foo-revb-bar.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@4";
+			};
+			foo-revb-baz.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@5";
+			};
+			foo-revb-bar-baz.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@6";
+			};
+		};
+	};
+
+Note the blob needs to be compiled for each case and the combinatorial explosion of
+configurations. A typical device tree blob is in the low hunderds of kbytes so a
+multitude of configuration grows the image quite a bit.
+
+Booting this image is done by using
+
+	# bootm <addr>#<config>
+
+Where config is one of:
+	foo-reva.dtb, foo-revb.dtb, foo-reva-bar.dtb, foo-revb-bar.dtb,
+	foo-revb-baz.dtb, foo-revb-bar-baz.dtb
+
+This selects the DTB to use when booting.
+
+Configuration using overlays
+----------------------------
+
+Device tree overlays can be applied to a base DT and result in the same blob
+being passed to the booting kernel. This saves on space and avoid the combinatorial
+explosion problem.
+
+	/dts-v1/;
+	/ {
+		images {
+			kernel@1 {
+				data = /incbin/("./zImage");
+				type = "kernel";
+				arch = "arm";
+				os = "linux";
+				load = <0x82000000>;
+				entry = <0x82000000>;
+			};
+			fdt@1 {
+				data = /incbin/("./foo.dtb");
+				type = "flat_dt";
+				arch = "arm";
+				load = <0x87f00000>;
+			};
+			fdt@2 {
+				data = /incbin/("./reva.dtbo");
+				type = "flat_dt";
+				arch = "arm";
+				load = <0x87fc0000>;
+			};
+			fdt@3 {
+				data = /incbin/("./revb.dtbo");
+				type = "flat_dt";
+				arch = "arm";
+				load = <0x87fc0000>;
+			};
+			fdt@4 {
+				data = /incbin/("./bar.dtbo");
+				type = "flat_dt";
+				arch = "arm";
+				load = <0x87fc0000>;
+			};
+			fdt@5 {
+				data = /incbin/("./baz.dtbo");
+				type = "flat_dt";
+				arch = "arm";
+				load = <0x87fc0000>;
+			};
+		};
+
+		configurations {
+			default = "foo-reva.dtb;
+			foo-reva.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@1", "fdt@2";
+			};
+			foo-revb.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@1", "fdt@3";
+			};
+			foo-reva-bar.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@1", "fdt@2", "fdt@4";
+			};
+			foo-revb-bar.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@1", "fdt@3", "fdt@4";
+			};
+			foo-revb-baz.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@1", "fdt@3", "fdt@5";
+			};
+			foo-revb-bar-baz.dtb {
+				kernel = "kernel@1";
+				fdt = "fdt@1", "fdt@3", "fdt@4", "fdt@5";
+			};
+			bar {
+				fdt = "fdt@4";
+			};
+			baz {
+				fdt = "fdt@5";
+			};
+		};
+	};
+
+Booting this image is exactly the same as the non-overlay example.
+u-boot will retrieve the base blob and apply the overlays in sequence as
+they are declared in the configuration.
+
+Note the minimum amount of different DT blobs, as well as the requirement for
+the DT blobs to have a load address; the overlay application requires the blobs
+to be writeable.
+
+Configuration using overlays and feature selection
+--------------------------------------------------
+
+Although the configuration in the previous section works is a bit inflexible
+since it requires all possible configuration options to be laid out before
+hand in the FIT image. For the add-on boards the extra config selection method
+might make sense.
+
+Note the two bar & baz configuration nodes. To boot a reva board with
+the bar add-on board enabled simply use:
+
+	# bootm <addr>#foo-reva.dtb#bar
+
+While booting a revb with bar and baz is as follows:
+
+	# bootm <addr>#foo-revb.dtb#bar#baz
+
+The limitation for a feature selection configuration node is that a single
+fdt option is currently supported.
+
+Pantelis Antoniou
+pantelis.antoniou@konsulko.com
+12/6/2017

+ 4 - 2
doc/uImage.FIT/source_file_format.txt

@@ -235,7 +235,7 @@ o config@1
   |- description = "configuration description"
   |- description = "configuration description"
   |- kernel = "kernel sub-node unit name"
   |- kernel = "kernel sub-node unit name"
   |- ramdisk = "ramdisk sub-node unit name"
   |- ramdisk = "ramdisk sub-node unit name"
-  |- fdt = "fdt sub-node unit-name"
+  |- fdt = "fdt sub-node unit-name" [, "fdt overlay sub-node unit-name", ...]
   |- fpga = "fpga sub-node unit-name"
   |- fpga = "fpga sub-node unit-name"
   |- loadables = "loadables sub-node unit-name"
   |- loadables = "loadables sub-node unit-name"
 
 
@@ -249,7 +249,9 @@ o config@1
   - ramdisk : Unit name of the corresponding ramdisk image (component image
   - ramdisk : Unit name of the corresponding ramdisk image (component image
     node of a "ramdisk" type).
     node of a "ramdisk" type).
   - fdt : Unit name of the corresponding fdt blob (component image node of a
   - fdt : Unit name of the corresponding fdt blob (component image node of a
-    "fdt type").
+    "fdt type"). Additional fdt overlay nodes can be supplied which signify
+    that the resulting device tree blob is generated by the first base fdt
+    blob with all subsequent overlays applied.
   - setup : Unit name of the corresponding setup binary (used for booting
   - setup : Unit name of the corresponding setup binary (used for booting
     an x86 kernel). This contains the setup.bin file built by the kernel.
     an x86 kernel). This contains the setup.bin file built by the kernel.
   - fpga : Unit name of the corresponding fpga bitstream blob
   - fpga : Unit name of the corresponding fpga bitstream blob

+ 2 - 2
drivers/clk/clk-uclass.c

@@ -23,7 +23,7 @@ static inline struct clk_ops *clk_dev_ops(struct udevice *dev)
 #if CONFIG_IS_ENABLED(OF_CONTROL)
 #if CONFIG_IS_ENABLED(OF_CONTROL)
 # if CONFIG_IS_ENABLED(OF_PLATDATA)
 # if CONFIG_IS_ENABLED(OF_PLATDATA)
 int clk_get_by_index_platdata(struct udevice *dev, int index,
 int clk_get_by_index_platdata(struct udevice *dev, int index,
-			      struct phandle_2_cell *cells, struct clk *clk)
+			      struct phandle_1_arg *cells, struct clk *clk)
 {
 {
 	int ret;
 	int ret;
 
 
@@ -32,7 +32,7 @@ int clk_get_by_index_platdata(struct udevice *dev, int index,
 	ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
 	ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
-	clk->id = cells[0].id;
+	clk->id = cells[0].arg[0];
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 1
drivers/clk/rockchip/clk_rk3368.c

@@ -471,7 +471,7 @@ static int rk3368_clk_probe(struct udevice *dev)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 	struct rk3368_clk_plat *plat = dev_get_platdata(dev);
 	struct rk3368_clk_plat *plat = dev_get_platdata(dev);
 
 
-	priv->cru = map_sysmem(plat->dtd.reg[1], plat->dtd.reg[3]);
+	priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
 #endif
 #endif
 #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
 #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
 	rkclk_init(priv->cru);
 	rkclk_init(priv->cru);

+ 2 - 2
drivers/clk/rockchip/clk_rk3399.c

@@ -963,7 +963,7 @@ static int rk3399_clk_probe(struct udevice *dev)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 	struct rk3399_clk_plat *plat = dev_get_platdata(dev);
 	struct rk3399_clk_plat *plat = dev_get_platdata(dev);
 
 
-	priv->cru = map_sysmem(plat->dtd.reg[1], plat->dtd.reg[3]);
+	priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
 #endif
 #endif
 	rkclk_init(priv->cru);
 	rkclk_init(priv->cru);
 #endif
 #endif
@@ -1145,7 +1145,7 @@ static int rk3399_pmuclk_probe(struct udevice *dev)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 	struct rk3399_pmuclk_plat *plat = dev_get_platdata(dev);
 	struct rk3399_pmuclk_plat *plat = dev_get_platdata(dev);
 
 
-	priv->pmucru = map_sysmem(plat->dtd.reg[1], plat->dtd.reg[3]);
+	priv->pmucru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
 #endif
 #endif
 
 
 #ifndef CONFIG_SPL_BUILD
 #ifndef CONFIG_SPL_BUILD

+ 1 - 1
drivers/core/regmap.c

@@ -40,7 +40,7 @@ static struct regmap *regmap_alloc_count(int count)
 }
 }
 
 
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
-int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
+int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
 			     struct regmap **mapp)
 			     struct regmap **mapp)
 {
 {
 	struct regmap_range *range;
 	struct regmap_range *range;

+ 2 - 2
include/clk.h

@@ -61,9 +61,9 @@ struct clk {
 };
 };
 
 
 #if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(CLK)
 #if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(CLK)
-struct phandle_2_cell;
+struct phandle_1_arg;
 int clk_get_by_index_platdata(struct udevice *dev, int index,
 int clk_get_by_index_platdata(struct udevice *dev, int index,
-			      struct phandle_2_cell *cells, struct clk *clk);
+			      struct phandle_1_arg *cells, struct clk *clk);
 
 
 /**
 /**
  * clock_get_by_index - Get/request a clock by integer index.
  * clock_get_by_index - Get/request a clock by integer index.

+ 13 - 3
include/dt-structs.h

@@ -9,11 +9,21 @@
 
 
 /* These structures may only be used in SPL */
 /* These structures may only be used in SPL */
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
-struct phandle_2_cell {
+struct phandle_0_arg {
 	const void *node;
 	const void *node;
-	int id;
+	int arg[0];
 };
 };
-#include <generated/dt-structs.h>
+
+struct phandle_1_arg {
+	const void *node;
+	int arg[1];
+};
+
+struct phandle_2_arg {
+	const void *node;
+	int arg[2];
+};
+#include <generated/dt-structs-gen.h>
 #endif
 #endif
 
 
 #endif
 #endif

+ 2 - 0
include/fdt_support.h

@@ -264,6 +264,8 @@ int arch_fixup_memory_node(void *blob);
 int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
 int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
 			    u32 height, u32 stride, const char *format);
 			    u32 height, u32 stride, const char *format);
 
 
+int fdt_overlay_apply_verbose(void *fdt, void *fdto);
+
 #endif /* ifdef CONFIG_OF_LIBFDT */
 #endif /* ifdef CONFIG_OF_LIBFDT */
 
 
 #ifdef USE_HOSTCC
 #ifdef USE_HOSTCC

+ 2 - 0
include/fdtdec.h

@@ -27,10 +27,12 @@ typedef phys_size_t fdt_size_t;
 #define FDT_ADDR_T_NONE (-1ULL)
 #define FDT_ADDR_T_NONE (-1ULL)
 #define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
 #define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
 #define fdt_size_to_cpu(reg) be64_to_cpu(reg)
 #define fdt_size_to_cpu(reg) be64_to_cpu(reg)
+typedef fdt64_t fdt_val_t;
 #else
 #else
 #define FDT_ADDR_T_NONE (-1U)
 #define FDT_ADDR_T_NONE (-1U)
 #define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
 #define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
 #define fdt_size_to_cpu(reg) be32_to_cpu(reg)
 #define fdt_size_to_cpu(reg) be32_to_cpu(reg)
+typedef fdt32_t fdt_val_t;
 #endif
 #endif
 
 
 /* Information obtained about memory from the FDT */
 /* Information obtained about memory from the FDT */

+ 25 - 0
include/image.h

@@ -593,6 +593,31 @@ int boot_get_loadable(int argc, char * const argv[], bootm_headers_t *images,
 int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
 int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
 		       ulong *setup_start, ulong *setup_len);
 		       ulong *setup_start, ulong *setup_len);
 
 
+/**
+ * boot_get_fdt_fit() - load a DTB from a FIT file (applying overlays)
+ *
+ * This deals with all aspects of loading an DTB from a FIT.
+ * The correct base image based on configuration will be selected, and
+ * then any overlays specified will be applied (as present in fit_uname_configp).
+ *
+ * @param images	Boot images structure
+ * @param addr		Address of FIT in memory
+ * @param fit_unamep	On entry this is the requested image name
+ *			(e.g. "kernel@1") or NULL to use the default. On exit
+ *			points to the selected image name
+ * @param fit_uname_configp	On entry this is the requested configuration
+ *			name (e.g. "conf@1") or NULL to use the default. On
+ *			exit points to the selected configuration name.
+ * @param arch		Expected architecture (IH_ARCH_...)
+ * @param datap		Returns address of loaded image
+ * @param lenp		Returns length of loaded image
+ *
+ * @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);
+
 /**
 /**
  * fit_image_load() - load an image from a FIT
  * fit_image_load() - load an image from a FIT
  *
  *

+ 1 - 1
include/regmap.h

@@ -69,7 +69,7 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp);
  * @count:	Number of pairs (e.g. 1 if the regmap has a single entry)
  * @count:	Number of pairs (e.g. 1 if the regmap has a single entry)
  * @mapp:	Returns allocated map
  * @mapp:	Returns allocated map
  */
  */
-int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
+int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
 			     struct regmap **mapp);
 			     struct regmap **mapp);
 
 
 /**
 /**

+ 5 - 1
include/syscon.h

@@ -8,6 +8,8 @@
 #ifndef __SYSCON_H
 #ifndef __SYSCON_H
 #define __SYSCON_H
 #define __SYSCON_H
 
 
+#include <fdtdec.h>
+
 /**
 /**
  * struct syscon_uc_info - Information stored by the syscon UCLASS_UCLASS
  * struct syscon_uc_info - Information stored by the syscon UCLASS_UCLASS
  *
  *
@@ -28,9 +30,11 @@ struct syscon_ops {
  * We don't support 64-bit machines. If they are so resource-contrained that
  * We don't support 64-bit machines. If they are so resource-contrained that
  * they need to use OF_PLATDATA, something is horribly wrong with the
  * they need to use OF_PLATDATA, something is horribly wrong with the
  * education of our hardware engineers.
  * education of our hardware engineers.
+ *
+ * Update: 64-bit is now supported and we have an education crisis.
  */
  */
 struct syscon_base_platdata {
 struct syscon_base_platdata {
-	u32 reg[2];
+	fdt_val_t reg[2];
 };
 };
 #endif
 #endif
 
 

+ 206 - 22
lib/libfdt/fdt_overlay.c

@@ -39,6 +39,7 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
  * @fdt: Base device tree blob
  * @fdt: Base device tree blob
  * @fdto: Device tree overlay blob
  * @fdto: Device tree overlay blob
  * @fragment: node offset of the fragment in the overlay
  * @fragment: node offset of the fragment in the overlay
+ * @pathp: pointer which receives the path of the target (or NULL)
  *
  *
  * overlay_get_target() retrieves the target offset in the base
  * overlay_get_target() retrieves the target offset in the base
  * device tree of a fragment, no matter how the actual targetting is
  * device tree of a fragment, no matter how the actual targetting is
@@ -49,37 +50,47 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
  *      Negative error code on error
  *      Negative error code on error
  */
  */
 static int overlay_get_target(const void *fdt, const void *fdto,
 static int overlay_get_target(const void *fdt, const void *fdto,
-			      int fragment)
+			      int fragment, char const **pathp)
 {
 {
 	uint32_t phandle;
 	uint32_t phandle;
-	const char *path;
-	int path_len;
+	const char *path = NULL;
+	int path_len = 0, ret;
 
 
 	/* Try first to do a phandle based lookup */
 	/* Try first to do a phandle based lookup */
 	phandle = overlay_get_target_phandle(fdto, fragment);
 	phandle = overlay_get_target_phandle(fdto, fragment);
 	if (phandle == (uint32_t)-1)
 	if (phandle == (uint32_t)-1)
 		return -FDT_ERR_BADPHANDLE;
 		return -FDT_ERR_BADPHANDLE;
 
 
-	if (phandle)
-		return fdt_node_offset_by_phandle(fdt, phandle);
+	/* no phandle, try path */
+	if (!phandle) {
+		/* And then a path based lookup */
+		path = fdt_getprop(fdto, fragment, "target-path", &path_len);
+		if (path)
+			ret = fdt_path_offset(fdt, path);
+		else
+			ret = path_len;
+	} else
+		ret = fdt_node_offset_by_phandle(fdt, phandle);
 
 
-	/* And then a path based lookup */
-	path = fdt_getprop(fdto, fragment, "target-path", &path_len);
-	if (!path) {
-		/*
-		 * If we haven't found either a target or a
-		 * target-path property in a node that contains a
-		 * __overlay__ subnode (we wouldn't be called
-		 * otherwise), consider it a improperly written
-		 * overlay
-		 */
-		if (path_len == -FDT_ERR_NOTFOUND)
-			return -FDT_ERR_BADOVERLAY;
+	/*
+	* If we haven't found either a target or a
+	* target-path property in a node that contains a
+	* __overlay__ subnode (we wouldn't be called
+	* otherwise), consider it a improperly written
+	* overlay
+	*/
+	if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
+		ret = -FDT_ERR_BADOVERLAY;
+
+	/* return on error */
+	if (ret < 0)
+		return ret;
 
 
-		return path_len;
-	}
+	/* return pointer to path (if available) */
+	if (pathp)
+		*pathp = path ? path : NULL;
 
 
-	return fdt_path_offset(fdt, path);
+	return ret;
 }
 }
 
 
 /**
 /**
@@ -590,7 +601,7 @@ static int overlay_apply_node(void *fdt, int target,
  *
  *
  * overlay_merge() merges an overlay into its base device tree.
  * overlay_merge() merges an overlay into its base device tree.
  *
  *
- * This is the final step in the device tree overlay application
+ * This is the next to last step in the device tree overlay application
  * process, when all the phandles have been adjusted and resolved and
  * process, when all the phandles have been adjusted and resolved and
  * you just have to merge overlay into the base device tree.
  * you just have to merge overlay into the base device tree.
  *
  *
@@ -618,7 +629,7 @@ static int overlay_merge(void *fdt, void *fdto)
 		if (overlay < 0)
 		if (overlay < 0)
 			return overlay;
 			return overlay;
 
 
-		target = overlay_get_target(fdt, fdto, fragment);
+		target = overlay_get_target(fdt, fdto, fragment, NULL);
 		if (target < 0)
 		if (target < 0)
 			return target;
 			return target;
 
 
@@ -630,6 +641,175 @@ static int overlay_merge(void *fdt, void *fdto)
 	return 0;
 	return 0;
 }
 }
 
 
+static int get_path_len(const void *fdt, int nodeoffset)
+{
+	int len = 0, namelen;
+	const char *name;
+
+	FDT_CHECK_HEADER(fdt);
+
+	for (;;) {
+		name = fdt_get_name(fdt, nodeoffset, &namelen);
+		if (!name)
+			return namelen;
+
+		/* root? we're done */
+		if (namelen == 0)
+			break;
+
+		nodeoffset = fdt_parent_offset(fdt, nodeoffset);
+		if (nodeoffset < 0)
+			return nodeoffset;
+		len += namelen + 1;
+	}
+
+	/* in case of root pretend it's "/" */
+	if (len == 0)
+		len++;
+	return len;
+}
+
+/**
+ * overlay_symbol_update - Update the symbols of base tree after a merge
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ *
+ * overlay_symbol_update() updates the symbols of the base tree with the
+ * symbols of the applied overlay
+ *
+ * This is the last step in the device tree overlay application
+ * process, allowing the reference of overlay symbols by subsequent
+ * overlay operations.
+ *
+ * returns:
+ *      0 on success
+ *      Negative error code on failure
+ */
+static int overlay_symbol_update(void *fdt, void *fdto)
+{
+	int root_sym, ov_sym, prop, path_len, fragment, target;
+	int len, frag_name_len, ret, rel_path_len;
+	const char *s, *e;
+	const char *path;
+	const char *name;
+	const char *frag_name;
+	const char *rel_path;
+	const char *target_path;
+	char *buf;
+	void *p;
+
+	ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
+
+	/* if no overlay symbols exist no problem */
+	if (ov_sym < 0)
+		return 0;
+
+	root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
+
+	/* it no root symbols exist we should create them */
+	if (root_sym == -FDT_ERR_NOTFOUND)
+		root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
+
+	/* any error is fatal now */
+	if (root_sym < 0)
+		return root_sym;
+
+	/* iterate over each overlay symbol */
+	fdt_for_each_property_offset(prop, fdto, ov_sym) {
+		path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
+		if (!path)
+			return path_len;
+
+		/* verify it's a string property (terminated by a single \0) */
+		if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
+			return -FDT_ERR_BADVALUE;
+
+		/* keep end marker to avoid strlen() */
+		e = path + path_len;
+
+		/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
+
+		if (*path != '/')
+			return -FDT_ERR_BADVALUE;
+
+		/* get fragment name first */
+		s = strchr(path + 1, '/');
+		if (!s)
+			return -FDT_ERR_BADOVERLAY;
+
+		frag_name = path + 1;
+		frag_name_len = s - path - 1;
+
+		/* verify format; safe since "s" lies in \0 terminated prop */
+		len = sizeof("/__overlay__/") - 1;
+		if ((e - s) < len || memcmp(s, "/__overlay__/", len))
+			return -FDT_ERR_BADOVERLAY;
+
+		rel_path = s + len;
+		rel_path_len = e - rel_path;
+
+		/* find the fragment index in which the symbol lies */
+		ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
+					       frag_name_len);
+		/* not found? */
+		if (ret < 0)
+			return -FDT_ERR_BADOVERLAY;
+		fragment = ret;
+
+		/* an __overlay__ subnode must exist */
+		ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
+		if (ret < 0)
+			return -FDT_ERR_BADOVERLAY;
+
+		/* get the target of the fragment */
+		ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+		if (ret < 0)
+			return ret;
+		target = ret;
+
+		/* if we have a target path use */
+		if (!target_path) {
+			ret = get_path_len(fdt, target);
+			if (ret < 0)
+				return ret;
+			len = ret;
+		} else {
+			len = strlen(target_path);
+		}
+
+		ret = fdt_setprop_placeholder(fdt, root_sym, name,
+				len + (len > 1) + rel_path_len + 1, &p);
+		if (ret < 0)
+			return ret;
+
+		if (!target_path) {
+			/* again in case setprop_placeholder changed it */
+			ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+			if (ret < 0)
+				return ret;
+			target = ret;
+		}
+
+		buf = p;
+		if (len > 1) { /* target is not root */
+			if (!target_path) {
+				ret = fdt_get_path(fdt, target, buf, len + 1);
+				if (ret < 0)
+					return ret;
+			} else
+				memcpy(buf, target_path, len + 1);
+
+		} else
+			len--;
+
+		buf[len] = '/';
+		memcpy(buf + len + 1, rel_path, rel_path_len);
+		buf[len + 1 + rel_path_len] = '\0';
+	}
+
+	return 0;
+}
+
 int fdt_overlay_apply(void *fdt, void *fdto)
 int fdt_overlay_apply(void *fdt, void *fdto)
 {
 {
 	uint32_t delta = fdt_get_max_phandle(fdt);
 	uint32_t delta = fdt_get_max_phandle(fdt);
@@ -654,6 +834,10 @@ int fdt_overlay_apply(void *fdt, void *fdto)
 	if (ret)
 	if (ret)
 		goto err;
 		goto err;
 
 
+	ret = overlay_symbol_update(fdt, fdto);
+	if (ret)
+		goto err;
+
 	/*
 	/*
 	 * The overlay has been damaged, erase its magic.
 	 * The overlay has been damaged, erase its magic.
 	 */
 	 */

+ 17 - 3
lib/libfdt/fdt_rw.c

@@ -228,8 +228,8 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
 	return 0;
 	return 0;
 }
 }
 
 
-int fdt_setprop(void *fdt, int nodeoffset, const char *name,
-		const void *val, int len)
+int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
+			    int len, void **prop_data)
 {
 {
 	struct fdt_property *prop;
 	struct fdt_property *prop;
 	int err;
 	int err;
@@ -242,8 +242,22 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
+	*prop_data = prop->data;
+	return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len)
+{
+	void *prop_data;
+	int err;
+
+	err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
+	if (err)
+		return err;
+
 	if (len)
 	if (len)
-		memcpy(prop->data, val, len);
+		memcpy(prop_data, val, len);
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
lib/libfdt/fdt_wip.c

@@ -115,7 +115,7 @@ int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
 		     struct fdt_region region[], int max_regions,
 		     struct fdt_region region[], int max_regions,
 		     char *path, int path_len, int add_string_tab)
 		     char *path, int path_len, int add_string_tab)
 {
 {
-	int stack[FDT_MAX_DEPTH];
+	int stack[FDT_MAX_DEPTH] = { 0 };
 	char *end;
 	char *end;
 	int nextoffset = 0;
 	int nextoffset = 0;
 	uint32_t tag;
 	uint32_t tag;

+ 31 - 0
lib/libfdt/libfdt.h

@@ -1404,6 +1404,37 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name);
 int fdt_setprop(void *fdt, int nodeoffset, const char *name,
 int fdt_setprop(void *fdt, int nodeoffset, const char *name,
 		const void *val, int len);
 		const void *val, int len);
 
 
+/**
+ * fdt_setprop _placeholder - allocate space for a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @len: length of the property value
+ * @prop_data: return pointer to property data
+ *
+ * fdt_setprop_placeholer() allocates the named property in the given node.
+ * If the property exists it is resized. In either case a pointer to the
+ * property data is returned.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
+			    int len, void **prop_data);
+
 /**
 /**
  * fdt_setprop_u32 - set a property to a 32-bit integer
  * fdt_setprop_u32 - set a property to a 32-bit integer
  * @fdt: pointer to the device tree blob
  * @fdt: pointer to the device tree blob

+ 58 - 0
lib/libfdt/pylibfdt/libfdt.i

@@ -130,6 +130,23 @@ class Fdt:
         self._fdt = bytearray(data)
         self._fdt = bytearray(data)
         check_err(fdt_check_header(self._fdt));
         check_err(fdt_check_header(self._fdt));
 
 
+    def subnode_offset(self, parentoffset, name, quiet=()):
+        """Get the offset of a named subnode
+
+        Args:
+            parentoffset: Offset of the parent node to check
+            name: Name of the required subnode, e.g. 'subnode@1'
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            The node offset of the found node, if any
+
+        Raises
+            FdtException if there is no node with that name, or other error
+        """
+        return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
+                         quiet)
+
     def path_offset(self, path, quiet=()):
     def path_offset(self, path, quiet=()):
         """Get the offset for a given path
         """Get the offset for a given path
 
 
@@ -304,6 +321,47 @@ class Fdt:
             return pdata
             return pdata
         return bytearray(pdata[0])
         return bytearray(pdata[0])
 
 
+    def get_phandle(self, nodeoffset):
+        """Get the phandle of a node
+
+        Args:
+            nodeoffset: Node offset to check
+
+        Returns:
+            phandle of node, or 0 if the node has no phandle or another error
+            occurs
+        """
+        return fdt_get_phandle(self._fdt, nodeoffset)
+
+    def parent_offset(self, nodeoffset, quiet=()):
+        """Get the offset of a node's parent
+
+        Args:
+            nodeoffset: Node offset to check
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            The offset of the parent node, if any
+
+        Raises:
+            FdtException if no parent found or other error occurs
+        """
+        return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
+
+    def node_offset_by_phandle(self, phandle, quiet=()):
+        """Get the offset of a node with the given phandle
+
+        Args:
+            phandle: Phandle to search for
+            quiet: Errors to ignore (empty to raise on all errors)
+
+        Returns:
+            The offset of node with that phandle, if any
+
+        Raises:
+            FdtException if no node found or other error occurs
+        """
+        return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
 
 
 class Property:
 class Property:
     """Holds a device tree property name and value.
     """Holds a device tree property name and value.

+ 17 - 0
scripts/Makefile.lib

@@ -321,6 +321,23 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
 
 
 dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
 dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
 
 
+# DTCO
+# ---------------------------------------------------------------------------
+
+quiet_cmd_dtco = DTCO    $@
+# Rule for objects only; does not put specific u-boot include at the end
+# No generation of assembly file either
+# Modified for U-Boot
+cmd_dtco = mkdir -p $(dir ${dtc-tmp}) ; \
+	$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ; \
+	$(DTC) -@ -O dtb -o $@ -b 0 \
+		-i $(dir $<) $(DTC_FLAGS) \
+		-d $(depfile).dtc.tmp $(dtc-tmp) ; \
+	cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
+
+$(obj)/%.dtbo: $(src)/%.dts FORCE
+	$(call if_changed_dep,dtco)
+
 # Fonts
 # Fonts
 # ---------------------------------------------------------------------------
 # ---------------------------------------------------------------------------
 
 

+ 3 - 2
scripts/Makefile.spl

@@ -257,14 +257,15 @@ cmd_dtoch = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o
 quiet_cmd_plat = PLAT    $@
 quiet_cmd_plat = PLAT    $@
 cmd_plat = $(CC) $(c_flags) -c $< -o $@
 cmd_plat = $(CC) $(c_flags) -c $< -o $@
 
 
-$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c include/generated/dt-structs.h
+$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c \
+		include/generated/dt-structs-gen.h
 	$(call if_changed,plat)
 	$(call if_changed,plat)
 
 
 PHONY += dts_dir
 PHONY += dts_dir
 dts_dir:
 dts_dir:
 	$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
 	$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
 
 
-include/generated/dt-structs.h: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
+include/generated/dt-structs-gen.h: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
 	$(call if_changed,dtoch)
 	$(call if_changed,dtoch)
 
 
 $(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
 $(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc

+ 1 - 0
test/overlay/Makefile

@@ -13,3 +13,4 @@ DTC_FLAGS += -@
 # DT overlays
 # DT overlays
 obj-y += test-fdt-base.dtb.o
 obj-y += test-fdt-base.dtb.o
 obj-y += test-fdt-overlay.dtb.o
 obj-y += test-fdt-overlay.dtb.o
+obj-y += test-fdt-overlay-stacked.dtb.o

+ 41 - 9
test/overlay/cmd_ut_overlay.c

@@ -20,8 +20,9 @@
 
 
 extern u32 __dtb_test_fdt_base_begin;
 extern u32 __dtb_test_fdt_base_begin;
 extern u32 __dtb_test_fdt_overlay_begin;
 extern u32 __dtb_test_fdt_overlay_begin;
+extern u32 __dtb_test_fdt_overlay_stacked_begin;
 
 
-static int fdt_getprop_u32_by_index(void *fdt, const char *path,
+static int ut_fdt_getprop_u32_by_index(void *fdt, const char *path,
 				    const char *name, int index,
 				    const char *name, int index,
 				    u32 *out)
 				    u32 *out)
 {
 {
@@ -42,10 +43,10 @@ static int fdt_getprop_u32_by_index(void *fdt, const char *path,
 	return 0;
 	return 0;
 }
 }
 
 
-static int fdt_getprop_u32(void *fdt, const char *path, const char *name,
+static int ut_fdt_getprop_u32(void *fdt, const char *path, const char *name,
 			   u32 *out)
 			   u32 *out)
 {
 {
-	return fdt_getprop_u32_by_index(fdt, path, name, 0, out);
+	return ut_fdt_getprop_u32_by_index(fdt, path, name, 0, out);
 }
 }
 
 
 static int fdt_getprop_str(void *fdt, const char *path, const char *name,
 static int fdt_getprop_str(void *fdt, const char *path, const char *name,
@@ -68,7 +69,7 @@ static int fdt_overlay_change_int_property(struct unit_test_state *uts)
 	void *fdt = uts->priv;
 	void *fdt = uts->priv;
 	u32 val = 0;
 	u32 val = 0;
 
 
-	ut_assertok(fdt_getprop_u32(fdt, "/test-node", "test-int-property",
+	ut_assertok(ut_fdt_getprop_u32(fdt, "/test-node", "test-int-property",
 				    &val));
 				    &val));
 	ut_asserteq(43, val);
 	ut_asserteq(43, val);
 
 
@@ -158,11 +159,11 @@ static int fdt_overlay_local_phandle(struct unit_test_state *uts)
 	local_phandle = fdt_get_phandle(fdt, off);
 	local_phandle = fdt_get_phandle(fdt, off);
 	ut_assert(local_phandle);
 	ut_assert(local_phandle);
 
 
-	ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
+	ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
 					     0, &val));
 					     0, &val));
 	ut_asserteq(local_phandle, val);
 	ut_asserteq(local_phandle, val);
 
 
-	ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
+	ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
 					     1, &val));
 					     1, &val));
 	ut_asserteq(local_phandle, val);
 	ut_asserteq(local_phandle, val);
 
 
@@ -189,11 +190,11 @@ static int fdt_overlay_local_phandles(struct unit_test_state *uts)
 	test_phandle = fdt_get_phandle(fdt, off);
 	test_phandle = fdt_get_phandle(fdt, off);
 	ut_assert(test_phandle);
 	ut_assert(test_phandle);
 
 
-	ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0,
+	ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0,
 					     &val));
 					     &val));
 	ut_asserteq(test_phandle, val);
 	ut_asserteq(test_phandle, val);
 
 
-	ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1,
+	ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1,
 					     &val));
 					     &val));
 	ut_asserteq(local_phandle, val);
 	ut_asserteq(local_phandle, val);
 
 
@@ -201,6 +202,19 @@ static int fdt_overlay_local_phandles(struct unit_test_state *uts)
 }
 }
 OVERLAY_TEST(fdt_overlay_local_phandles, 0);
 OVERLAY_TEST(fdt_overlay_local_phandles, 0);
 
 
+static int fdt_overlay_stacked(struct unit_test_state *uts)
+{
+	void *fdt = uts->priv;
+	u32 val = 0;
+
+	ut_assertok(ut_fdt_getprop_u32(fdt, "/new-local-node",
+				       "stacked-test-int-property", &val));
+	ut_asserteq(43, val);
+
+	return CMD_RET_SUCCESS;
+}
+OVERLAY_TEST(fdt_overlay_stacked, 0);
+
 int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 {
 	struct unit_test *tests = ll_entry_start(struct unit_test,
 	struct unit_test *tests = ll_entry_start(struct unit_test,
@@ -210,7 +224,8 @@ int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	struct unit_test *test;
 	struct unit_test *test;
 	void *fdt_base = &__dtb_test_fdt_base_begin;
 	void *fdt_base = &__dtb_test_fdt_base_begin;
 	void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
 	void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
-	void *fdt_base_copy, *fdt_overlay_copy;
+	void *fdt_overlay_stacked = &__dtb_test_fdt_overlay_stacked_begin;
+	void *fdt_base_copy, *fdt_overlay_copy, *fdt_overlay_stacked_copy;
 
 
 	uts = calloc(1, sizeof(*uts));
 	uts = calloc(1, sizeof(*uts));
 	if (!uts)
 	if (!uts)
@@ -228,6 +243,10 @@ int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (!fdt_overlay_copy)
 	if (!fdt_overlay_copy)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
+	fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE);
+	if (!fdt_overlay_stacked_copy)
+		return -ENOMEM;
+
 	/*
 	/*
 	 * Resize the FDT to 4k so that we have room to operate on
 	 * Resize the FDT to 4k so that we have room to operate on
 	 *
 	 *
@@ -245,9 +264,21 @@ int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy,
 	ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy,
 				  FDT_COPY_SIZE));
 				  FDT_COPY_SIZE));
 
 
+	/*
+	 * Resize the stacked overlay to 4k so that we have room to operate on
+	 *
+	 * (and relocate it since the memory might be mapped
+	 * read-only)
+	 */
+	ut_assertok(fdt_open_into(fdt_overlay_stacked, fdt_overlay_stacked_copy,
+				  FDT_COPY_SIZE));
+
 	/* Apply the overlay */
 	/* Apply the overlay */
 	ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_copy));
 	ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_copy));
 
 
+	/* Apply the stacked overlay */
+	ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_stacked_copy));
+
 	if (argc == 1)
 	if (argc == 1)
 		printf("Running %d environment tests\n", n_ents);
 		printf("Running %d environment tests\n", n_ents);
 
 
@@ -263,6 +294,7 @@ int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
 
 	printf("Failures: %d\n", uts->fail_count);
 	printf("Failures: %d\n", uts->fail_count);
 
 
+	free(fdt_overlay_stacked_copy);
 	free(fdt_overlay_copy);
 	free(fdt_overlay_copy);
 	free(fdt_base_copy);
 	free(fdt_base_copy);
 	free(uts);
 	free(uts);

+ 21 - 0
test/overlay/test-fdt-overlay-stacked.dts

@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016 NextThing Co
+ * Copyright (c) 2016 Free Electrons
+ * Copyright (c) 2018 Konsulko Group
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	/* Test that we can reference an overlay symbol */
+	fragment@0 {
+		target = <&local>;
+
+		__overlay__ {
+			stacked-test-int-property = <43>;
+		};
+	};
+};

+ 160 - 44
tools/dtoc/dtb_platdata.py

@@ -12,6 +12,7 @@ This supports converting device tree data to C structures definitions and
 static data.
 static data.
 """
 """
 
 
+import collections
 import copy
 import copy
 import sys
 import sys
 
 
@@ -38,11 +39,20 @@ TYPE_NAMES = {
     fdt.TYPE_BYTE: 'unsigned char',
     fdt.TYPE_BYTE: 'unsigned char',
     fdt.TYPE_STRING: 'const char *',
     fdt.TYPE_STRING: 'const char *',
     fdt.TYPE_BOOL: 'bool',
     fdt.TYPE_BOOL: 'bool',
+    fdt.TYPE_INT64: 'fdt64_t',
 }
 }
 
 
 STRUCT_PREFIX = 'dtd_'
 STRUCT_PREFIX = 'dtd_'
 VAL_PREFIX = 'dtv_'
 VAL_PREFIX = 'dtv_'
 
 
+# This holds information about a property which includes phandles.
+#
+# max_args: integer: Maximum number or arguments that any phandle uses (int).
+# args: Number of args for each phandle in the property. The total number of
+#     phandles is len(args). This is a list of integers.
+PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
+
+
 def conv_name_to_c(name):
 def conv_name_to_c(name):
     """Convert a device-tree name to a C identifier
     """Convert a device-tree name to a C identifier
 
 
@@ -95,6 +105,8 @@ def get_value(ftype, value):
         return '"%s"' % value
         return '"%s"' % value
     elif ftype == fdt.TYPE_BOOL:
     elif ftype == fdt.TYPE_BOOL:
         return 'true'
         return 'true'
+    elif ftype == fdt.TYPE_INT64:
+        return '%#x' % value
 
 
 def get_compat_name(node):
 def get_compat_name(node):
     """Get a node's first compatible string as a C identifier
     """Get a node's first compatible string as a C identifier
@@ -113,21 +125,6 @@ def get_compat_name(node):
         compat, aliases = compat[0], compat[1:]
         compat, aliases = compat[0], compat[1:]
     return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases]
     return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases]
 
 
-def is_phandle(prop):
-    """Check if a node contains phandles
-
-    We have no reliable way of detecting whether a node uses a phandle
-    or not. As an interim measure, use a list of known property names.
-
-    Args:
-        prop: Prop object to check
-    Return:
-        True if the object value contains phandles, else False
-    """
-    if prop.name in ['clocks']:
-        return True
-    return False
-
 
 
 class DtbPlatdata(object):
 class DtbPlatdata(object):
     """Provide a means to convert device tree binary data to platform data
     """Provide a means to convert device tree binary data to platform data
@@ -141,17 +138,14 @@ class DtbPlatdata(object):
         _dtb_fname: Filename of the input device tree binary file
         _dtb_fname: Filename of the input device tree binary file
         _valid_nodes: A list of Node object with compatible strings
         _valid_nodes: A list of Node object with compatible strings
         _include_disabled: true to include nodes marked status = "disabled"
         _include_disabled: true to include nodes marked status = "disabled"
-        _phandle_nodes: A dict of nodes indexed by phandle number (1, 2...)
         _outfile: The current output file (sys.stdout or a real file)
         _outfile: The current output file (sys.stdout or a real file)
         _lines: Stashed list of output lines for outputting in the future
         _lines: Stashed list of output lines for outputting in the future
-        _phandle_nodes: A dict of Nodes indexed by phandle (an integer)
     """
     """
     def __init__(self, dtb_fname, include_disabled):
     def __init__(self, dtb_fname, include_disabled):
         self._fdt = None
         self._fdt = None
         self._dtb_fname = dtb_fname
         self._dtb_fname = dtb_fname
         self._valid_nodes = None
         self._valid_nodes = None
         self._include_disabled = include_disabled
         self._include_disabled = include_disabled
-        self._phandle_nodes = {}
         self._outfile = None
         self._outfile = None
         self._lines = []
         self._lines = []
         self._aliases = {}
         self._aliases = {}
@@ -196,6 +190,53 @@ class DtbPlatdata(object):
         self._lines = []
         self._lines = []
         return lines
         return lines
 
 
+    def out_header(self):
+        """Output a message indicating that this is an auto-generated file"""
+        self.out('''/*
+ * DO NOT MODIFY
+ *
+ * This file was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+''')
+
+    def get_phandle_argc(self, prop, node_name):
+        """Check if a node contains phandles
+
+        We have no reliable way of detecting whether a node uses a phandle
+        or not. As an interim measure, use a list of known property names.
+
+        Args:
+            prop: Prop object to check
+        Return:
+            Number of argument cells is this is a phandle, else None
+        """
+        if prop.name in ['clocks']:
+            val = prop.value
+            if not isinstance(val, list):
+                val = [val]
+            i = 0
+
+            max_args = 0
+            args = []
+            while i < len(val):
+                phandle = fdt_util.fdt32_to_cpu(val[i])
+                target = self._fdt.phandle_to_node.get(phandle)
+                if not target:
+                    raise ValueError("Cannot parse '%s' in node '%s'" %
+                                     (prop.name, node_name))
+                prop_name = '#clock-cells'
+                cells = target.props.get(prop_name)
+                if not cells:
+                    raise ValueError("Node '%s' has no '%s' property" %
+                            (target.name, prop_name))
+                num_args = fdt_util.fdt32_to_cpu(cells.value)
+                max_args = max(max_args, num_args)
+                args.append(num_args)
+                i += 1 + num_args
+            return PhandleInfo(max_args, args)
+        return None
+
     def scan_dtb(self):
     def scan_dtb(self):
         """Scan the device tree to obtain a tree of nodes and properties
         """Scan the device tree to obtain a tree of nodes and properties
 
 
@@ -207,8 +248,7 @@ class DtbPlatdata(object):
     def scan_node(self, root):
     def scan_node(self, root):
         """Scan a node and subnodes to build a tree of node and phandle info
         """Scan a node and subnodes to build a tree of node and phandle info
 
 
-        This adds each node to self._valid_nodes and each phandle to
-        self._phandle_nodes.
+        This adds each node to self._valid_nodes.
 
 
         Args:
         Args:
             root: Root node for scan
             root: Root node for scan
@@ -219,10 +259,6 @@ class DtbPlatdata(object):
                 if (not self._include_disabled and not status or
                 if (not self._include_disabled and not status or
                         status.value != 'disabled'):
                         status.value != 'disabled'):
                     self._valid_nodes.append(node)
                     self._valid_nodes.append(node)
-                    phandle_prop = node.props.get('phandle')
-                    if phandle_prop:
-                        phandle = phandle_prop.GetPhandle()
-                        self._phandle_nodes[phandle] = node
 
 
             # recurse to handle any subnodes
             # recurse to handle any subnodes
             self.scan_node(node)
             self.scan_node(node)
@@ -231,14 +267,72 @@ class DtbPlatdata(object):
         """Scan the device tree for useful information
         """Scan the device tree for useful information
 
 
         This fills in the following properties:
         This fills in the following properties:
-            _phandle_nodes: A dict of Nodes indexed by phandle (an integer)
             _valid_nodes: A list of nodes we wish to consider include in the
             _valid_nodes: A list of nodes we wish to consider include in the
                 platform data
                 platform data
         """
         """
-        self._phandle_nodes = {}
         self._valid_nodes = []
         self._valid_nodes = []
         return self.scan_node(self._fdt.GetRoot())
         return self.scan_node(self._fdt.GetRoot())
 
 
+    @staticmethod
+    def get_num_cells(node):
+        """Get the number of cells in addresses and sizes for this node
+
+        Args:
+            node: Node to check
+
+        Returns:
+            Tuple:
+                Number of address cells for this node
+                Number of size cells for this node
+        """
+        parent = node.parent
+        na, ns = 2, 2
+        if parent:
+            na_prop = parent.props.get('#address-cells')
+            ns_prop = parent.props.get('#size-cells')
+            if na_prop:
+                na = fdt_util.fdt32_to_cpu(na_prop.value)
+            if ns_prop:
+                ns = fdt_util.fdt32_to_cpu(ns_prop.value)
+        return na, ns
+
+    def scan_reg_sizes(self):
+        """Scan for 64-bit 'reg' properties and update the values
+
+        This finds 'reg' properties with 64-bit data and converts the value to
+        an array of 64-values. This allows it to be output in a way that the
+        C code can read.
+        """
+        for node in self._valid_nodes:
+            reg = node.props.get('reg')
+            if not reg:
+                continue
+            na, ns = self.get_num_cells(node)
+            total = na + ns
+
+            if reg.type != fdt.TYPE_INT:
+                raise ValueError("Node '%s' reg property is not an int")
+            if len(reg.value) % total:
+                raise ValueError("Node '%s' reg property has %d cells "
+                        'which is not a multiple of na + ns = %d + %d)' %
+                        (node.name, len(reg.value), na, ns))
+            reg.na = na
+            reg.ns = ns
+            if na != 1 or ns != 1:
+                reg.type = fdt.TYPE_INT64
+                i = 0
+                new_value = []
+                val = reg.value
+                if not isinstance(val, list):
+                    val = [val]
+                while i < len(val):
+                    addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
+                    i += na
+                    size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
+                    i += ns
+                    new_value += [addr, size]
+                reg.value = new_value
+
     def scan_structs(self):
     def scan_structs(self):
         """Scan the device tree building up the C structures we will use.
         """Scan the device tree building up the C structures we will use.
 
 
@@ -305,14 +399,18 @@ class DtbPlatdata(object):
             for pname, prop in node.props.items():
             for pname, prop in node.props.items():
                 if pname in PROP_IGNORE_LIST or pname[0] == '#':
                 if pname in PROP_IGNORE_LIST or pname[0] == '#':
                     continue
                     continue
-                if isinstance(prop.value, list):
-                    if is_phandle(prop):
-                        # Process the list as pairs of (phandle, id)
-                        value_it = iter(prop.value)
-                        for phandle_cell, _ in zip(value_it, value_it):
-                            phandle = fdt_util.fdt32_to_cpu(phandle_cell)
-                            target_node = self._phandle_nodes[phandle]
-                            node.phandles.add(target_node)
+                info = self.get_phandle_argc(prop, node.name)
+                if info:
+                    if not isinstance(prop.value, list):
+                        prop.value = [prop.value]
+                    # Process the list as pairs of (phandle, id)
+                    pos = 0
+                    for args in info.args:
+                        phandle_cell = prop.value[pos]
+                        phandle = fdt_util.fdt32_to_cpu(phandle_cell)
+                        target_node = self._fdt.phandle_to_node[phandle]
+                        node.phandles.add(target_node)
+                        pos += 1 + args
 
 
 
 
     def generate_structs(self, structs):
     def generate_structs(self, structs):
@@ -322,6 +420,7 @@ class DtbPlatdata(object):
         definitions for node in self._valid_nodes. See the documentation in
         definitions for node in self._valid_nodes. See the documentation in
         README.of-plat for more information.
         README.of-plat for more information.
         """
         """
+        self.out_header()
         self.out('#include <stdbool.h>\n')
         self.out('#include <stdbool.h>\n')
         self.out('#include <libfdt.h>\n')
         self.out('#include <libfdt.h>\n')
 
 
@@ -330,11 +429,13 @@ class DtbPlatdata(object):
             self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
             self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
             for pname in sorted(structs[name]):
             for pname in sorted(structs[name]):
                 prop = structs[name][pname]
                 prop = structs[name][pname]
-                if is_phandle(prop):
+                info = self.get_phandle_argc(prop, structs[name])
+                if info:
                     # For phandles, include a reference to the target
                     # For phandles, include a reference to the target
-                    self.out('\t%s%s[%d]' % (tab_to(2, 'struct phandle_2_cell'),
+                    struct_name = 'struct phandle_%d_arg' % info.max_args
+                    self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
                                              conv_name_to_c(prop.name),
                                              conv_name_to_c(prop.name),
-                                             len(prop.value) / 2))
+                                             len(info.args)))
                 else:
                 else:
                     ptype = TYPE_NAMES[prop.type]
                     ptype = TYPE_NAMES[prop.type]
                     self.out('\t%s%s' % (tab_to(2, ptype),
                     self.out('\t%s%s' % (tab_to(2, ptype),
@@ -370,19 +471,32 @@ class DtbPlatdata(object):
                 vals = []
                 vals = []
                 # For phandles, output a reference to the platform data
                 # For phandles, output a reference to the platform data
                 # of the target node.
                 # of the target node.
-                if is_phandle(prop):
+                info = self.get_phandle_argc(prop, node.name)
+                if info:
                     # Process the list as pairs of (phandle, id)
                     # Process the list as pairs of (phandle, id)
-                    value_it = iter(prop.value)
-                    for phandle_cell, id_cell in zip(value_it, value_it):
+                    pos = 0
+                    for args in info.args:
+                        phandle_cell = prop.value[pos]
                         phandle = fdt_util.fdt32_to_cpu(phandle_cell)
                         phandle = fdt_util.fdt32_to_cpu(phandle_cell)
-                        id_num = fdt_util.fdt32_to_cpu(id_cell)
-                        target_node = self._phandle_nodes[phandle]
+                        target_node = self._fdt.phandle_to_node[phandle]
                         name = conv_name_to_c(target_node.name)
                         name = conv_name_to_c(target_node.name)
-                        vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num))
+                        arg_values = []
+                        for i in range(args):
+                            arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
+                        pos += 1 + args
+                        vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name,
+                                                     ', '.join(arg_values)))
+                    for val in vals:
+                        self.buf('\n\t\t%s,' % val)
                 else:
                 else:
                     for val in prop.value:
                     for val in prop.value:
                         vals.append(get_value(prop.type, val))
                         vals.append(get_value(prop.type, val))
-                self.buf(', '.join(vals))
+
+                    # Put 8 values per line to avoid very long lines.
+                    for i in xrange(0, len(vals), 8):
+                        if i:
+                            self.buf(',\n\t\t')
+                        self.buf(', '.join(vals[i:i + 8]))
                 self.buf('}')
                 self.buf('}')
             else:
             else:
                 self.buf(get_value(prop.type, prop.value))
                 self.buf(get_value(prop.type, prop.value))
@@ -409,6 +523,7 @@ class DtbPlatdata(object):
         See the documentation in doc/driver-model/of-plat.txt for more
         See the documentation in doc/driver-model/of-plat.txt for more
         information.
         information.
         """
         """
+        self.out_header()
         self.out('#include <common.h>\n')
         self.out('#include <common.h>\n')
         self.out('#include <dm.h>\n')
         self.out('#include <dm.h>\n')
         self.out('#include <dt-structs.h>\n')
         self.out('#include <dt-structs.h>\n')
@@ -442,6 +557,7 @@ def run_steps(args, dtb_file, include_disabled, output):
     plat = DtbPlatdata(dtb_file, include_disabled)
     plat = DtbPlatdata(dtb_file, include_disabled)
     plat.scan_dtb()
     plat.scan_dtb()
     plat.scan_tree()
     plat.scan_tree()
+    plat.scan_reg_sizes()
     plat.setup_output(output)
     plat.setup_output(output)
     structs = plat.scan_structs()
     structs = plat.scan_structs()
     plat.scan_phandles()
     plat.scan_phandles()

+ 27 - 0
tools/dtoc/dtoc_test_addr32.dts

@@ -0,0 +1,27 @@
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+ /dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	test1 {
+		u-boot,dm-pre-reloc;
+		compatible = "test1";
+		reg = <0x1234 0x5678>;
+	};
+
+	test2 {
+		u-boot,dm-pre-reloc;
+		compatible = "test2";
+		reg = <0x12345678 0x98765432 2 3>;
+	};
+
+};

+ 33 - 0
tools/dtoc/dtoc_test_addr32_64.dts

@@ -0,0 +1,33 @@
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+ /dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <2>;
+
+	test1 {
+		u-boot,dm-pre-reloc;
+		compatible = "test1";
+		reg = <0x1234 0x5678 0x0>;
+	};
+
+	test2 {
+		u-boot,dm-pre-reloc;
+		compatible = "test2";
+		reg = <0x12345678 0x98765432 0x10987654>;
+	};
+
+	test3 {
+		u-boot,dm-pre-reloc;
+		compatible = "test3";
+		reg = <0x12345678 0x98765432 0x10987654 2 0 3>;
+	};
+
+};

+ 33 - 0
tools/dtoc/dtoc_test_addr64.dts

@@ -0,0 +1,33 @@
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+ /dts-v1/;
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	test1 {
+		u-boot,dm-pre-reloc;
+		compatible = "test1";
+		reg = /bits/ 64 <0x1234 0x5678>;
+	};
+
+	test2 {
+		u-boot,dm-pre-reloc;
+		compatible = "test2";
+		reg = /bits/ 64 <0x1234567890123456 0x9876543210987654>;
+	};
+
+	test3 {
+		u-boot,dm-pre-reloc;
+		compatible = "test3";
+		reg = /bits/ 64 <0x1234567890123456 0x9876543210987654 2 3>;
+	};
+
+};

+ 33 - 0
tools/dtoc/dtoc_test_addr64_32.dts

@@ -0,0 +1,33 @@
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+ /dts-v1/;
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <1>;
+
+	test1 {
+		u-boot,dm-pre-reloc;
+		compatible = "test1";
+		reg = <0x1234 0x0 0x5678>;
+	};
+
+	test2 {
+		u-boot,dm-pre-reloc;
+		compatible = "test2";
+		reg = <0x12345678 0x90123456 0x98765432>;
+	};
+
+	test3 {
+		u-boot,dm-pre-reloc;
+		compatible = "test3";
+		reg = <0x12345678 0x90123456 0x98765432 0 2 3>;
+	};
+
+};

+ 15 - 1
tools/dtoc/dtoc_test_phandle.dts

@@ -10,14 +10,28 @@
 
 
 / {
 / {
 	phandle: phandle-target {
 	phandle: phandle-target {
+		u-boot,dm-pre-reloc;
+		compatible = "target";
+		intval = <0>;
+                #clock-cells = <0>;
+	};
+
+	phandle_1: phandle2-target {
 		u-boot,dm-pre-reloc;
 		u-boot,dm-pre-reloc;
 		compatible = "target";
 		compatible = "target";
 		intval = <1>;
 		intval = <1>;
+		#clock-cells = <1>;
+	};
+	phandle_2: phandle3-target {
+		u-boot,dm-pre-reloc;
+		compatible = "target";
+		intval = <2>;
+		#clock-cells = <2>;
 	};
 	};
 
 
 	phandle-source {
 	phandle-source {
 		u-boot,dm-pre-reloc;
 		u-boot,dm-pre-reloc;
 		compatible = "source";
 		compatible = "source";
-		clocks = <&phandle 1>;
+		clocks = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
 	};
 	};
 };
 };

+ 14 - 0
tools/dtoc/dtoc_test_simple.dts

@@ -9,6 +9,8 @@
  /dts-v1/;
  /dts-v1/;
 
 
 / {
 / {
+	#address-cells = <1>;
+	#size-cells = <1>;
 	spl-test {
 	spl-test {
 		u-boot,dm-pre-reloc;
 		u-boot,dm-pre-reloc;
 		compatible = "sandbox,spl-test";
 		compatible = "sandbox,spl-test";
@@ -45,4 +47,16 @@
 		compatible = "sandbox,spl-test.2";
 		compatible = "sandbox,spl-test.2";
 	};
 	};
 
 
+	i2c@0 {
+		compatible = "sandbox,i2c-test";
+		u-boot,dm-pre-reloc;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pmic@9 {
+			compatible = "sandbox,pmic-test";
+			u-boot,dm-pre-reloc;
+			reg = <9>;
+			low-power;
+		};
+	};
 };
 };

+ 13 - 6
tools/dtoc/fdt.py

@@ -21,7 +21,7 @@ import libfdt
 # so it is fairly efficient.
 # so it is fairly efficient.
 
 
 # A list of types we support
 # A list of types we support
-(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
+(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, TYPE_INT64) = range(5)
 
 
 def CheckErr(errnum, msg):
 def CheckErr(errnum, msg):
     if errnum:
     if errnum:
@@ -174,8 +174,9 @@ class Node:
         props: A dict of properties for this node, each a Prop object.
         props: A dict of properties for this node, each a Prop object.
             Keyed by property name
             Keyed by property name
     """
     """
-    def __init__(self, fdt, offset, name, path):
+    def __init__(self, fdt, parent, offset, name, path):
         self._fdt = fdt
         self._fdt = fdt
+        self.parent = parent
         self._offset = offset
         self._offset = offset
         self.name = name
         self.name = name
         self.path = path
         self.path = path
@@ -211,13 +212,17 @@ class Node:
         searching into subnodes so that the entire tree is built.
         searching into subnodes so that the entire tree is built.
         """
         """
         self.props = self._fdt.GetProps(self)
         self.props = self._fdt.GetProps(self)
+        phandle = self.props.get('phandle')
+        if phandle:
+            val = fdt_util.fdt32_to_cpu(phandle.value)
+            self._fdt.phandle_to_node[val] = self
 
 
         offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
         offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
         while offset >= 0:
         while offset >= 0:
             sep = '' if self.path[-1] == '/' else '/'
             sep = '' if self.path[-1] == '/' else '/'
             name = self._fdt._fdt_obj.get_name(offset)
             name = self._fdt._fdt_obj.get_name(offset)
             path = self.path + sep + name
             path = self.path + sep + name
-            node = Node(self._fdt, offset, name, path)
+            node = Node(self._fdt, self, offset, name, path)
             self.subnodes.append(node)
             self.subnodes.append(node)
 
 
             node.Scan()
             node.Scan()
@@ -262,6 +267,7 @@ class Fdt:
     def __init__(self, fname):
     def __init__(self, fname):
         self._fname = fname
         self._fname = fname
         self._cached_offsets = False
         self._cached_offsets = False
+        self.phandle_to_node = {}
         if self._fname:
         if self._fname:
             self._fname = fdt_util.EnsureCompiled(self._fname)
             self._fname = fdt_util.EnsureCompiled(self._fname)
 
 
@@ -279,7 +285,7 @@ class Fdt:
 
 
         TODO(sjg@chromium.org): Implement the 'root' parameter
         TODO(sjg@chromium.org): Implement the 'root' parameter
         """
         """
-        self._root = self.Node(self, 0, '/', '/')
+        self._root = self.Node(self, None, 0, '/', '/')
         self._root.Scan()
         self._root.Scan()
 
 
     def GetRoot(self):
     def GetRoot(self):
@@ -386,7 +392,7 @@ class Fdt:
         return libfdt.fdt_off_dt_struct(self._fdt) + offset
         return libfdt.fdt_off_dt_struct(self._fdt) + offset
 
 
     @classmethod
     @classmethod
-    def Node(self, fdt, offset, name, path):
+    def Node(self, fdt, parent, offset, name, path):
         """Create a new node
         """Create a new node
 
 
         This is used by Fdt.Scan() to create a new node using the correct
         This is used by Fdt.Scan() to create a new node using the correct
@@ -394,11 +400,12 @@ class Fdt:
 
 
         Args:
         Args:
             fdt: Fdt object
             fdt: Fdt object
+            parent: Parent node, or None if this is the root node
             offset: Offset of node
             offset: Offset of node
             name: Node name
             name: Node name
             path: Full path to node
             path: Full path to node
         """
         """
-        node = Node(fdt, offset, name, path)
+        node = Node(fdt, parent, offset, name, path)
         return node
         return node
 
 
 def FdtScan(fname):
 def FdtScan(fname):

+ 16 - 0
tools/dtoc/fdt_util.py

@@ -29,6 +29,22 @@ def fdt32_to_cpu(val):
         val = val.encode('raw_unicode_escape')
         val = val.encode('raw_unicode_escape')
     return struct.unpack('>I', val)[0]
     return struct.unpack('>I', val)[0]
 
 
+def fdt_cells_to_cpu(val, cells):
+    """Convert one or two cells to a long integer
+
+    Args:
+        Value to convert (array of one or more 4-character strings)
+
+    Return:
+        A native-endian long value
+    """
+    if not cells:
+        return 0
+    out = long(fdt32_to_cpu(val[0]))
+    if cells == 2:
+        out = out << 32 | fdt32_to_cpu(val[1])
+    return out
+
 def EnsureCompiled(fname):
 def EnsureCompiled(fname):
     """Compile an fdt .dts source file into a .dtb binary blob if needed.
     """Compile an fdt .dts source file into a .dtb binary blob if needed.
 
 

+ 265 - 5
tools/dtoc/test_dtoc.py

@@ -121,6 +121,12 @@ class TestDtoc(unittest.TestCase):
             data = infile.read()
             data = infile.read()
         self.assertEqual('''#include <stdbool.h>
         self.assertEqual('''#include <stdbool.h>
 #include <libfdt.h>
 #include <libfdt.h>
+struct dtd_sandbox_i2c_test {
+};
+struct dtd_sandbox_pmic_test {
+\tbool\t\tlow_power;
+\tfdt64_t\t\treg[2];
+};
 struct dtd_sandbox_spl_test {
 struct dtd_sandbox_spl_test {
 \tbool\t\tboolval;
 \tbool\t\tboolval;
 \tunsigned char\tbytearray[3];
 \tunsigned char\tbytearray[3];
@@ -146,7 +152,8 @@ static struct dtd_sandbox_spl_test dtv_spl_test = {
 \t.bytearray\t\t= {0x6, 0x0, 0x0},
 \t.bytearray\t\t= {0x6, 0x0, 0x0},
 \t.byteval\t\t= 0x5,
 \t.byteval\t\t= 0x5,
 \t.intval\t\t\t= 0x1,
 \t.intval\t\t\t= 0x1,
-\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11},
+\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
+\t\t0x11},
 \t.stringval\t\t= "message",
 \t.stringval\t\t= "message",
 \t.boolval\t\t= true,
 \t.boolval\t\t= true,
 \t.intarray\t\t= {0x2, 0x3, 0x4, 0x0},
 \t.intarray\t\t= {0x2, 0x3, 0x4, 0x0},
@@ -162,7 +169,8 @@ static struct dtd_sandbox_spl_test dtv_spl_test2 = {
 \t.bytearray\t\t= {0x1, 0x23, 0x34},
 \t.bytearray\t\t= {0x1, 0x23, 0x34},
 \t.byteval\t\t= 0x8,
 \t.byteval\t\t= 0x8,
 \t.intval\t\t\t= 0x3,
 \t.intval\t\t\t= 0x3,
-\t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+\t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+\t\t0x0},
 \t.stringval\t\t= "message2",
 \t.stringval\t\t= "message2",
 \t.intarray\t\t= {0x5, 0x0, 0x0, 0x0},
 \t.intarray\t\t= {0x5, 0x0, 0x0, 0x0},
 \t.stringarray\t\t= {"another", "multi-word", "message"},
 \t.stringarray\t\t= {"another", "multi-word", "message"},
@@ -190,6 +198,24 @@ U_BOOT_DEVICE(spl_test4) = {
 \t.platdata_size\t= sizeof(dtv_spl_test4),
 \t.platdata_size\t= sizeof(dtv_spl_test4),
 };
 };
 
 
+static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
+};
+U_BOOT_DEVICE(i2c_at_0) = {
+\t.name\t\t= "sandbox_i2c_test",
+\t.platdata\t= &dtv_i2c_at_0,
+\t.platdata_size\t= sizeof(dtv_i2c_at_0),
+};
+
+static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
+\t.low_power\t\t= true,
+\t.reg\t\t\t= {0x9, 0x0},
+};
+U_BOOT_DEVICE(pmic_at_9) = {
+\t.name\t\t= "sandbox_pmic_test",
+\t.platdata\t= &dtv_pmic_at_9,
+\t.platdata_size\t= sizeof(dtv_pmic_at_9),
+};
+
 ''', data)
 ''', data)
 
 
     def test_phandle(self):
     def test_phandle(self):
@@ -202,7 +228,7 @@ U_BOOT_DEVICE(spl_test4) = {
         self.assertEqual('''#include <stdbool.h>
         self.assertEqual('''#include <stdbool.h>
 #include <libfdt.h>
 #include <libfdt.h>
 struct dtd_source {
 struct dtd_source {
-\tstruct phandle_2_cell clocks[1];
+\tstruct phandle_2_arg clocks[4];
 };
 };
 struct dtd_target {
 struct dtd_target {
 \tfdt32_t\t\tintval;
 \tfdt32_t\t\tintval;
@@ -217,7 +243,7 @@ struct dtd_target {
 #include <dt-structs.h>
 #include <dt-structs.h>
 
 
 static struct dtd_target dtv_phandle_target = {
 static struct dtd_target dtv_phandle_target = {
-\t.intval\t\t\t= 0x1,
+\t.intval\t\t\t= 0x0,
 };
 };
 U_BOOT_DEVICE(phandle_target) = {
 U_BOOT_DEVICE(phandle_target) = {
 \t.name\t\t= "target",
 \t.name\t\t= "target",
@@ -225,8 +251,30 @@ U_BOOT_DEVICE(phandle_target) = {
 \t.platdata_size\t= sizeof(dtv_phandle_target),
 \t.platdata_size\t= sizeof(dtv_phandle_target),
 };
 };
 
 
+static struct dtd_target dtv_phandle2_target = {
+\t.intval\t\t\t= 0x1,
+};
+U_BOOT_DEVICE(phandle2_target) = {
+\t.name\t\t= "target",
+\t.platdata\t= &dtv_phandle2_target,
+\t.platdata_size\t= sizeof(dtv_phandle2_target),
+};
+
+static struct dtd_target dtv_phandle3_target = {
+\t.intval\t\t\t= 0x2,
+};
+U_BOOT_DEVICE(phandle3_target) = {
+\t.name\t\t= "target",
+\t.platdata\t= &dtv_phandle3_target,
+\t.platdata_size\t= sizeof(dtv_phandle3_target),
+};
+
 static struct dtd_source dtv_phandle_source = {
 static struct dtd_source dtv_phandle_source = {
-\t.clocks\t\t\t= {{&dtv_phandle_target, 1}},
+\t.clocks\t\t\t= {
+\t\t\t{&dtv_phandle_target, {}},
+\t\t\t{&dtv_phandle2_target, {11}},
+\t\t\t{&dtv_phandle3_target, {12, 13}},
+\t\t\t{&dtv_phandle_target, {}},},
 };
 };
 U_BOOT_DEVICE(phandle_source) = {
 U_BOOT_DEVICE(phandle_source) = {
 \t.name\t\t= "source",
 \t.name\t\t= "source",
@@ -268,4 +316,216 @@ U_BOOT_DEVICE(spl_test) = {
 \t.platdata_size\t= sizeof(dtv_spl_test),
 \t.platdata_size\t= sizeof(dtv_spl_test),
 };
 };
 
 
+''', data)
+
+    def test_addresses64(self):
+        """Test output from a node with a 'reg' property with na=2, ns=2"""
+        dtb_file = get_dtb_file('dtoc_test_addr64.dts')
+        output = tools.GetOutputFilename('output')
+        dtb_platdata.run_steps(['struct'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self.assertEqual('''#include <stdbool.h>
+#include <libfdt.h>
+struct dtd_test1 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test2 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test3 {
+\tfdt64_t\t\treg[4];
+};
+''', data)
+
+        dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self.assertEqual('''#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+static struct dtd_test1 dtv_test1 = {
+\t.reg\t\t\t= {0x1234, 0x5678},
+};
+U_BOOT_DEVICE(test1) = {
+\t.name\t\t= "test1",
+\t.platdata\t= &dtv_test1,
+\t.platdata_size\t= sizeof(dtv_test1),
+};
+
+static struct dtd_test2 dtv_test2 = {
+\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
+};
+U_BOOT_DEVICE(test2) = {
+\t.name\t\t= "test2",
+\t.platdata\t= &dtv_test2,
+\t.platdata_size\t= sizeof(dtv_test2),
+};
+
+static struct dtd_test3 dtv_test3 = {
+\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
+};
+U_BOOT_DEVICE(test3) = {
+\t.name\t\t= "test3",
+\t.platdata\t= &dtv_test3,
+\t.platdata_size\t= sizeof(dtv_test3),
+};
+
+''', data)
+
+    def test_addresses32(self):
+        """Test output from a node with a 'reg' property with na=1, ns=1"""
+        dtb_file = get_dtb_file('dtoc_test_addr32.dts')
+        output = tools.GetOutputFilename('output')
+        dtb_platdata.run_steps(['struct'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self.assertEqual('''#include <stdbool.h>
+#include <libfdt.h>
+struct dtd_test1 {
+\tfdt32_t\t\treg[2];
+};
+struct dtd_test2 {
+\tfdt32_t\t\treg[4];
+};
+''', data)
+
+        dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self.assertEqual('''#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+static struct dtd_test1 dtv_test1 = {
+\t.reg\t\t\t= {0x1234, 0x5678},
+};
+U_BOOT_DEVICE(test1) = {
+\t.name\t\t= "test1",
+\t.platdata\t= &dtv_test1,
+\t.platdata_size\t= sizeof(dtv_test1),
+};
+
+static struct dtd_test2 dtv_test2 = {
+\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
+};
+U_BOOT_DEVICE(test2) = {
+\t.name\t\t= "test2",
+\t.platdata\t= &dtv_test2,
+\t.platdata_size\t= sizeof(dtv_test2),
+};
+
+''', data)
+
+    def test_addresses64_32(self):
+        """Test output from a node with a 'reg' property with na=2, ns=1"""
+        dtb_file = get_dtb_file('dtoc_test_addr64_32.dts')
+        output = tools.GetOutputFilename('output')
+        dtb_platdata.run_steps(['struct'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self.assertEqual('''#include <stdbool.h>
+#include <libfdt.h>
+struct dtd_test1 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test2 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test3 {
+\tfdt64_t\t\treg[4];
+};
+''', data)
+
+        dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self.assertEqual('''#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+static struct dtd_test1 dtv_test1 = {
+\t.reg\t\t\t= {0x123400000000, 0x5678},
+};
+U_BOOT_DEVICE(test1) = {
+\t.name\t\t= "test1",
+\t.platdata\t= &dtv_test1,
+\t.platdata_size\t= sizeof(dtv_test1),
+};
+
+static struct dtd_test2 dtv_test2 = {
+\t.reg\t\t\t= {0x1234567890123456, 0x98765432},
+};
+U_BOOT_DEVICE(test2) = {
+\t.name\t\t= "test2",
+\t.platdata\t= &dtv_test2,
+\t.platdata_size\t= sizeof(dtv_test2),
+};
+
+static struct dtd_test3 dtv_test3 = {
+\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
+};
+U_BOOT_DEVICE(test3) = {
+\t.name\t\t= "test3",
+\t.platdata\t= &dtv_test3,
+\t.platdata_size\t= sizeof(dtv_test3),
+};
+
+''', data)
+
+    def test_addresses32_64(self):
+        """Test output from a node with a 'reg' property with na=1, ns=2"""
+        dtb_file = get_dtb_file('dtoc_test_addr32_64.dts')
+        output = tools.GetOutputFilename('output')
+        dtb_platdata.run_steps(['struct'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self.assertEqual('''#include <stdbool.h>
+#include <libfdt.h>
+struct dtd_test1 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test2 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test3 {
+\tfdt64_t\t\treg[4];
+};
+''', data)
+
+        dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
+        with open(output) as infile:
+            data = infile.read()
+        self.assertEqual('''#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+static struct dtd_test1 dtv_test1 = {
+\t.reg\t\t\t= {0x1234, 0x567800000000},
+};
+U_BOOT_DEVICE(test1) = {
+\t.name\t\t= "test1",
+\t.platdata\t= &dtv_test1,
+\t.platdata_size\t= sizeof(dtv_test1),
+};
+
+static struct dtd_test2 dtv_test2 = {
+\t.reg\t\t\t= {0x12345678, 0x9876543210987654},
+};
+U_BOOT_DEVICE(test2) = {
+\t.name\t\t= "test2",
+\t.platdata\t= &dtv_test2,
+\t.platdata_size\t= sizeof(dtv_test2),
+};
+
+static struct dtd_test3 dtv_test3 = {
+\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
+};
+U_BOOT_DEVICE(test3) = {
+\t.name\t\t= "test3",
+\t.platdata\t= &dtv_test3,
+\t.platdata_size\t= sizeof(dtv_test3),
+};
+
 ''', data)
 ''', data)