]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
Merge git://git.denx.de/u-boot-x86
authorTom Rini <trini@konsulko.com>
Sun, 17 Sep 2017 15:46:51 +0000 (11:46 -0400)
committerTom Rini <trini@konsulko.com>
Sun, 17 Sep 2017 15:46:51 +0000 (11:46 -0400)
44 files changed:
.travis.yml
cmd/fdt.c
common/fdt_support.c
common/image-fdt.c
common/image-fit.c
configs/sandbox_defconfig
doc/README.fdt-overlays [new file with mode: 0644]
doc/driver-model/of-plat.txt
doc/uImage.FIT/command_syntax_extensions.txt
doc/uImage.FIT/overlay-fdt-boot.txt [new file with mode: 0644]
doc/uImage.FIT/source_file_format.txt
drivers/clk/clk-uclass.c
drivers/clk/rockchip/clk_rk3368.c
drivers/clk/rockchip/clk_rk3399.c
drivers/core/regmap.c
include/clk.h
include/dt-structs.h
include/fdt_support.h
include/fdtdec.h
include/image.h
include/regmap.h
include/syscon.h
lib/libfdt/fdt_overlay.c
lib/libfdt/fdt_rw.c
lib/libfdt/fdt_wip.c
lib/libfdt/libfdt.h
lib/libfdt/pylibfdt/libfdt.i
scripts/Makefile.lib
scripts/Makefile.spl
test/overlay/Makefile
test/overlay/cmd_ut_overlay.c
test/overlay/test-fdt-overlay-stacked.dts [new file with mode: 0644]
test/py/make_test_disk.py [deleted file]
test/py/tests/test_gpt.py
tools/dtoc/dtb_platdata.py
tools/dtoc/dtoc_test_addr32.dts [new file with mode: 0644]
tools/dtoc/dtoc_test_addr32_64.dts [new file with mode: 0644]
tools/dtoc/dtoc_test_addr64.dts [new file with mode: 0644]
tools/dtoc/dtoc_test_addr64_32.dts [new file with mode: 0644]
tools/dtoc/dtoc_test_phandle.dts
tools/dtoc/dtoc_test_simple.dts
tools/dtoc/fdt.py
tools/dtoc/fdt_util.py
tools/dtoc/test_dtoc.py

index 4b7f8dd8e4ded1b8a72af81e50acea54f8b89f9e..b81d733695e1c232ff4da7ce51cf094524dc95c0 100644 (file)
@@ -26,12 +26,11 @@ addons:
     - grub-efi-ia32-bin
     - rpm2cpio
     - wget
-    - device-tree-compiler
 
 install:
  # 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
  - 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`
index d7654b2c4fd5de88c935a8cbc4e2e52be8450eb4..955a0088c6ef31f16c77e5befee761a21fdded69 100644 (file)
--- a/cmd/fdt.c
+++ b/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))
                        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;
-               }
        }
 #endif
        /* resize the fdt */
index 916a448c11d43a82e25155f001c919cd8b5e9541..f4f9543d5475d804e9059a51ccb199604605fc7b 100644 (file)
@@ -1655,3 +1655,34 @@ int fdt_fixup_display(void *blob, const char *path, const char *display)
        }
        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
index da4d0070815db68782bdd0731b59bbf211067710..a2ef409836535438be6c1467bcd0ff631e92e0cb 100644 (file)
@@ -356,17 +356,16 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,
                        if (fit_check_format(buf)) {
                                ulong load, len;
 
-                               fdt_noffset = fit_image_load(images,
+                               fdt_noffset = boot_get_fdt_fit(images,
                                        fdt_addr, &fit_uname_fdt,
                                        &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_uname_fdt = fit_uname_fdt;
                                images->fit_noffset_fdt = fdt_noffset;
                                fdt_addr = load;
+
                                break;
                        } else
 #endif
index 109ecfaaccb79f2a6401938e2180c511e3af9eef..7f17fd1410ed8a3b37e48f33f7ddf14dd4b54f65 100644 (file)
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <mapmem.h>
 #include <asm/io.h>
+#include <malloc.h>
 DECLARE_GLOBAL_DATA_PTR;
 #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);
        }
 
+       /* 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) ||
            (type == IH_TYPE_RAMDISK)) {
                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 len;
+       const char *s;
+       char *conf_uname_copy = NULL;
 
        confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
        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);
        }
 
+       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);
        if (noffset < 0) {
                debug("Can't get node offset for configuration unit name: '%s' (%s)\n",
                      conf_uname, fdt_strerror(noffset));
        }
 
+       if (conf_uname_copy)
+               free(conf_uname_copy);
+
        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)
 {
-       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;
 
        /* 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)
                return len;
 
        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: 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;
        const char *uname;
        int ret;
-       int loadables_index;
+       int fdt_index, loadables_index;
 
        /* Mandatory properties */
        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)
                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);
        if (uname)
@@ -1641,6 +1685,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
        int cfg_noffset, noffset;
        const char *fit_uname;
        const char *fit_uname_config;
+       const char *fit_base_uname_config;
        const void *fit;
        const void *buf;
        size_t size;
@@ -1656,6 +1701,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
        fit = map_sysmem(addr, 0);
        fit_uname = fit_unamep ? *fit_unamep : 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);
        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);
                        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) {
                        /* 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) {
                                puts("   Verifying Hash Integrity ... ");
                                if (fit_config_verify(fit, cfg_noffset)) {
@@ -1849,7 +1895,8 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
        if (fit_unamep)
                *fit_unamep = (char *)fit_uname;
        if (fit_uname_configp)
-               *fit_uname_configp = (char *)fit_uname_config;
+               *fit_uname_configp = (char *)(fit_uname_config ? :
+                                             fit_base_uname_config);
 
        return noffset;
 }
@@ -1873,3 +1920,144 @@ int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
 
        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
index d92f7357a2e28bdac99c1710e8d513cdda80eb8a..310b8acc293a35bfea9a99dea2ebb2e758f9be5c 100644 (file)
@@ -189,7 +189,9 @@ CONFIG_CMD_DHRYSTONE=y
 CONFIG_TPM=y
 CONFIG_LZ4=y
 CONFIG_ERRNO_STR=y
+CONFIG_OF_LIBFDT_OVERLAY=y
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_UT_ENV=y
+CONFIG_UT_OVERLAY=y
diff --git a/doc/README.fdt-overlays b/doc/README.fdt-overlays
new file mode 100644 (file)
index 0000000..39139cb
--- /dev/null
@@ -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
index 3ed8c759d691d925c8c7a9be703c17bc59ca6970..732bc34f067d5736456123c9c11988f0ba8ecae3 100644 (file)
@@ -111,7 +111,7 @@ struct dtd_rockchip_rk3288_dw_mshc {
         bool            cap_sd_highspeed;
         fdt32_t         card_detect_delay;
         fdt32_t         clock_freq_min_max[2];
-        struct phandle_2_cell clocks[4];
+        struct phandle_1_arg clocks[4];
         bool            disable_wp;
         fdt32_t         fifo_depth;
         fdt32_t         interrupts[3];
index 6c99b1c1594432a0e4622819ccd3f5bb23edc346..676f992f9044ba53c7dca01497c00a2fe11e628c 100644 (file)
@@ -36,7 +36,7 @@ Old uImage:
 New uImage:
 8.  bootm <addr1>
 9.  bootm [<addr1>]:<subimg1>
-10. bootm [<addr1>]#<conf>
+10. bootm [<addr1>]#<conf>[#<extra-conf[#...]]
 11. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2>
 12. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> [<addr3>]:<subimg3>
 13. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> <addr3>
@@ -129,6 +129,12 @@ following syntax:
 - new uImage configuration specification
 <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:
 
@@ -138,6 +144,10 @@ bootm 200000:kernel@1
 - boot configuration "cfg@1" from a new uImage located at 200000:
 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
   some other new uImage stored at address 800000:
 bootm 200000:kernel@1 800000:ramdisk@2
diff --git a/doc/uImage.FIT/overlay-fdt-boot.txt b/doc/uImage.FIT/overlay-fdt-boot.txt
new file mode 100644 (file)
index 0000000..63e47da
--- /dev/null
@@ -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
index 32825eda8d571b1d3eca1e100aec394ed0a3ec63..6f727a1e8a2fe7d91f4af7d7ed4a9170a9369e01 100644 (file)
@@ -235,7 +235,7 @@ o config@1
   |- description = "configuration description"
   |- kernel = "kernel 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"
   |- loadables = "loadables sub-node unit-name"
 
@@ -249,7 +249,9 @@ o config@1
   - ramdisk : Unit name of the corresponding ramdisk image (component image
     node of a "ramdisk" type).
   - 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
     an x86 kernel). This contains the setup.bin file built by the kernel.
   - fpga : Unit name of the corresponding fpga bitstream blob
index e68d9279b96322737e14125d25d65ae029688e30..83ba13374c78a36acb25c45107c781df82a40925 100644 (file)
@@ -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_PLATDATA)
 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;
 
@@ -32,7 +32,7 @@ int clk_get_by_index_platdata(struct udevice *dev, int index,
        ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
        if (ret)
                return ret;
-       clk->id = cells[0].id;
+       clk->id = cells[0].arg[0];
 
        return 0;
 }
index 2be1f572d7212a166cf96680fb26b71464d360ba..0160d50c0385c8a63f40bed9909de91f8afc7d55 100644 (file)
@@ -471,7 +471,7 @@ static int rk3368_clk_probe(struct udevice *dev)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
        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
 #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
        rkclk_init(priv->cru);
index 3edafea140073a5f7c53df3af07a956cb195ae8f..723280672410a470ecb45b0026cf21c641a33cc7 100644 (file)
@@ -963,7 +963,7 @@ static int rk3399_clk_probe(struct udevice *dev)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
        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
        rkclk_init(priv->cru);
 #endif
@@ -1145,7 +1145,7 @@ static int rk3399_pmuclk_probe(struct udevice *dev)
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
        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
 
 #ifndef CONFIG_SPL_BUILD
index d4e16a27ef345fc078d3bb258e1d409bd959edaf..0f1d30820c693ac6def8a01650b62ac63541908c 100644 (file)
@@ -40,7 +40,7 @@ static struct regmap *regmap_alloc_count(int count)
 }
 
 #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_range *range;
index c5988f78a8f1a1c7fc3f6b777eb00848db490757..e7ce3e8576883f8e6df0d21d19347bfd9d7047be 100644 (file)
@@ -61,9 +61,9 @@ struct 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,
-                             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.
index 0732c442ff8d9e600c39979327d911b2dc0c6300..c0f56951b530843e2fda58e091bc74da57eafaa0 100644 (file)
@@ -9,11 +9,21 @@
 
 /* These structures may only be used in SPL */
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
-struct phandle_2_cell {
+struct phandle_0_arg {
        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
index 5ef78cce6e0f2e27fa6f9b1d4b9ed3b45ca7758b..2bca4d7889180936b92e423c16a91740338c3090 100644 (file)
@@ -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,
                            u32 height, u32 stride, const char *format);
 
+int fdt_overlay_apply_verbose(void *fdt, void *fdto);
+
 #endif /* ifdef CONFIG_OF_LIBFDT */
 
 #ifdef USE_HOSTCC
index 4a0947c6266a8a92cf423895a7490bbed8133767..1ba02be8e1b1f4bc200ac7d18008ee8d82ce1962 100644 (file)
@@ -27,10 +27,12 @@ typedef phys_size_t fdt_size_t;
 #define FDT_ADDR_T_NONE (-1ULL)
 #define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
 #define fdt_size_to_cpu(reg) be64_to_cpu(reg)
+typedef fdt64_t fdt_val_t;
 #else
 #define FDT_ADDR_T_NONE (-1U)
 #define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
 #define fdt_size_to_cpu(reg) be32_to_cpu(reg)
+typedef fdt32_t fdt_val_t;
 #endif
 
 /* Information obtained about memory from the FDT */
index 339f79c6dc0c6b9dfc7178dd5c24403411184214..af98ed9f25c860111f8e42f2c5813cbdd54e255d 100644 (file)
@@ -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,
                       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
  *
index 1eed94e47a32d4eaa67e01a6ba22d05f5951ffe7..493a5d8eff84d0d443c680604bb495ba9835c7fd 100644 (file)
@@ -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)
  * @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);
 
 /**
index 34842aa4705891928df2f1346f22803f80116caa..5d52b1cc3c3d0a7d86bd54cf32383641fe7966f7 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __SYSCON_H
 #define __SYSCON_H
 
+#include <fdtdec.h>
+
 /**
  * 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
  * they need to use OF_PLATDATA, something is horribly wrong with the
  * education of our hardware engineers.
+ *
+ * Update: 64-bit is now supported and we have an education crisis.
  */
 struct syscon_base_platdata {
-       u32 reg[2];
+       fdt_val_t reg[2];
 };
 #endif
 
index ceb968786e55b692413e384a8f6a47684a46e7df..bd81241e6658d296cfe1a36a379eaeabb8632bed 100644 (file)
@@ -39,6 +39,7 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
  * @fdt: Base device tree blob
  * @fdto: Device tree overlay blob
  * @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
  * 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
  */
 static int overlay_get_target(const void *fdt, const void *fdto,
-                             int fragment)
+                             int fragment, char const **pathp)
 {
        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 */
        phandle = overlay_get_target_phandle(fdto, fragment);
        if (phandle == (uint32_t)-1)
                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.
  *
- * 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
  * 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)
                        return overlay;
 
-               target = overlay_get_target(fdt, fdto, fragment);
+               target = overlay_get_target(fdt, fdto, fragment, NULL);
                if (target < 0)
                        return target;
 
@@ -630,6 +641,175 @@ static int overlay_merge(void *fdt, void *fdto)
        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)
 {
        uint32_t delta = fdt_get_max_phandle(fdt);
@@ -654,6 +834,10 @@ int fdt_overlay_apply(void *fdt, void *fdto)
        if (ret)
                goto err;
 
+       ret = overlay_symbol_update(fdt, fdto);
+       if (ret)
+               goto err;
+
        /*
         * The overlay has been damaged, erase its magic.
         */
index 80a321214153708b85a962a94f38186335c29a20..3dc775261fb1073b14de83e669e4c592c4dfa15f 100644 (file)
@@ -228,8 +228,8 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
        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;
        int err;
@@ -242,8 +242,22 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
        if (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)
-               memcpy(prop->data, val, len);
+               memcpy(prop_data, val, len);
        return 0;
 }
 
index 45fb9641206f4f74948c639004e7c8b92958a54e..01adad0ee97b18693cbd90f2b6f19f9b23f6e410 100644 (file)
@@ -115,7 +115,7 @@ int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
                     struct fdt_region region[], int max_regions,
                     char *path, int path_len, int add_string_tab)
 {
-       int stack[FDT_MAX_DEPTH];
+       int stack[FDT_MAX_DEPTH] = { 0 };
        char *end;
        int nextoffset = 0;
        uint32_t tag;
index f3f9cad18409448fea2ead78a79b1db79be414a9..6af94cb3f755e1915d1bee389d4c0357dbd6cecf 100644 (file)
@@ -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,
                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: pointer to the device tree blob
index 146f4b942aabd73edbc1503cb2f1dbab3f10b548..5b1a8cf4d493a9a492e1b8060d68c7e9ca234fa9 100644 (file)
@@ -130,6 +130,23 @@ class Fdt:
         self._fdt = bytearray(data)
         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=()):
         """Get the offset for a given path
 
@@ -304,6 +321,47 @@ class Fdt:
             return pdata
         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:
     """Holds a device tree property name and value.
index 9ce47b4d22713ff376436acc00ea75e1ad5241c4..2a7ed70cf26b3cd8d72d772d1bb1ae6a6c9f5773 100644 (file)
@@ -321,6 +321,23 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
 
 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
 # ---------------------------------------------------------------------------
 
index dd8065d87d0608113ac338cca94046f967eaae28..b86ea76bab260d15bf6bbdebda75f141b65e6a8c 100644 (file)
@@ -257,14 +257,15 @@ cmd_dtoch = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o
 quiet_cmd_plat = PLAT    $@
 cmd_plat = $(CC) $(c_flags) -c $< -o $@
 
-$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c include/generated/dt-structs.h
+$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c \
+               include/generated/dt-structs-gen.h
        $(call if_changed,plat)
 
 PHONY += dts_dir
 dts_dir:
        $(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
 
-include/generated/dt-structs.h: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
+include/generated/dt-structs-gen.h: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
        $(call if_changed,dtoch)
 
 $(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
index 907f085446194650e422580d13b0a408e554a3f8..416645c88428b1e7a14957707351afa0416d5d01 100644 (file)
@@ -13,3 +13,4 @@ DTC_FLAGS += -@
 # DT overlays
 obj-y += test-fdt-base.dtb.o
 obj-y += test-fdt-overlay.dtb.o
+obj-y += test-fdt-overlay-stacked.dtb.o
index cbef720b4c091fd0b8075e0c60ca852b582032ff..24891ee829018e5d1ae75af1df0f5bb9358befa3 100644 (file)
@@ -20,8 +20,9 @@
 
 extern u32 __dtb_test_fdt_base_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,
                                    u32 *out)
 {
@@ -42,10 +43,10 @@ static int fdt_getprop_u32_by_index(void *fdt, const char *path,
        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)
 {
-       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,
@@ -68,7 +69,7 @@ static int fdt_overlay_change_int_property(struct unit_test_state *uts)
        void *fdt = uts->priv;
        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));
        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);
        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));
        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));
        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);
        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));
        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));
        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);
 
+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[])
 {
        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;
        void *fdt_base = &__dtb_test_fdt_base_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));
        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)
                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
         *
@@ -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,
                                  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 */
        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)
                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);
 
+       free(fdt_overlay_stacked_copy);
        free(fdt_overlay_copy);
        free(fdt_base_copy);
        free(uts);
diff --git a/test/overlay/test-fdt-overlay-stacked.dts b/test/overlay/test-fdt-overlay-stacked.dts
new file mode 100644 (file)
index 0000000..9fb7c7b
--- /dev/null
@@ -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>;
+               };
+       };
+};
diff --git a/test/py/make_test_disk.py b/test/py/make_test_disk.py
deleted file mode 100755 (executable)
index 5288295..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (c) 2017 Alison Chaiken
-#
-# SPDX-License-Identifier: GPL-2.0
-#
-# Create a block device for testing of 'gpt' and 'part' commands.
-
-import os
-
-def makeDisk():
-    if (os.path.exists("testdisk.raw")):
-        os.remove("testdisk.raw")
-    fd = os.open("testdisk.raw", os.O_RDWR|os.O_CREAT )
-    os.ftruncate(fd, 4194304)
-    os.close(fd)
-    os.spawnl(os.P_WAIT, "/sbin/sgdisk", "sgdisk", "-U",
-          "375a56f7-d6c9-4e81-b5f0-09d41ca89efe", "testdisk.raw")
-    os.spawnl(os.P_WAIT, "/sbin/sgdisk", "sgdisk", "--new=1:2048:2560", "testdisk.raw")
-    os.spawnl(os.P_WAIT, "/sbin/sgdisk", "sgdisk", "--new=2:4096:4608", "testdisk.raw")
-    os.spawnl(os.P_WAIT, "/sbin/gdisk", "sgdisk", "-l", "testdisk.raw")
index 06f24b66cef8732c86879a8f72bf7ba787046d59..e2bbd08e6d42a6cbc4bb9da73684c37f46c2b95a 100644 (file)
@@ -1,4 +1,5 @@
 # Copyright (c) 2017 Alison Chaiken
+# Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
 #
 # SPDX-License-Identifier: GPL-2.0
 
@@ -7,42 +8,88 @@
 import os
 import pytest
 import u_boot_utils
-import make_test_disk
 
 """
-These tests rely on a 4 MB block device called testdisk.raw
-which is automatically removed at the end of the tests.
+These tests rely on a 4 MB disk image, which is automatically created by
+the test.
 """
 
+class GptTestDiskImage(object):
+    """Disk Image used by the GPT tests."""
+
+    def __init__(self, u_boot_console):
+        """Initialize a new GptTestDiskImage object.
+
+        Args:
+            u_boot_console: A U-Boot console.
+
+        Returns:
+            Nothing.
+        """
+
+        filename = 'test_gpt_disk_image.bin'
+        self.path = u_boot_console.config.persistent_data_dir + '/' + filename
+
+        if os.path.exists(self.path):
+            u_boot_console.log.action('Disk image file ' + self.path +
+                ' already exists')
+        else:
+            u_boot_console.log.action('Generating ' + self.path)
+            fd = os.open(self.path, os.O_RDWR | os.O_CREAT)
+            os.ftruncate(fd, 4194304)
+            os.close(fd)
+            sgdisk = '/sbin/sgdisk'
+            cmd = (sgdisk, '-U', '375a56f7-d6c9-4e81-b5f0-09d41ca89efe',
+                self.path)
+            u_boot_utils.run_and_log(u_boot_console, cmd)
+            cmd = (sgdisk, '--new=1:2048:2560', self.path)
+            u_boot_utils.run_and_log(u_boot_console, cmd)
+            cmd = (sgdisk, '--new=2:4096:4608', self.path)
+            u_boot_utils.run_and_log(u_boot_console, cmd)
+            cmd = (sgdisk, '-l', self.path)
+            u_boot_utils.run_and_log(u_boot_console, cmd)
+
+gtdi = None
+@pytest.fixture(scope='function')
+def state_disk_image(u_boot_console):
+    """pytest fixture to provide a GptTestDiskImage object to tests.
+    This is function-scoped because it uses u_boot_console, which is also
+    function-scoped. However, we don't need to actually do any function-scope
+    work, so this simply returns the same object over and over each time."""
+
+    global gtdi
+    if not gtdi:
+        gtdi = GptTestDiskImage(u_boot_console)
+    return gtdi
+
+@pytest.mark.boardspec('sandbox')
 @pytest.mark.buildconfigspec('cmd_gpt')
-def test_gpt_guid(u_boot_console):
+def test_gpt_guid(state_disk_image, u_boot_console):
     """Test the gpt guid command."""
 
-    if u_boot_console.config.buildconfig.get('config_cmd_gpt', 'n') != 'y':
-        pytest.skip('gpt command not supported')
-    make_test_disk.makeDisk()
-    u_boot_console.run_command('host bind 0 testdisk.raw')
+    u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
     output = u_boot_console.run_command('gpt guid host 0')
     assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
 
+@pytest.mark.boardspec('sandbox')
 @pytest.mark.buildconfigspec('cmd_gpt')
-def test_gpt_save_guid(u_boot_console):
+def test_gpt_save_guid(state_disk_image, u_boot_console):
     """Test the gpt guid command to save GUID into a string."""
 
     if u_boot_console.config.buildconfig.get('config_cmd_gpt', 'n') != 'y':
         pytest.skip('gpt command not supported')
-    u_boot_console.run_command('host bind 0 testdisk.raw')
+    u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
     output = u_boot_console.run_command('gpt guid host 0 newguid')
     output = u_boot_console.run_command('printenv newguid')
     assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
 
+@pytest.mark.boardspec('sandbox')
 @pytest.mark.buildconfigspec('cmd_gpt')
-def test_gpt_rename_partition(u_boot_console):
+@pytest.mark.buildconfigspec('cmd_gpt_rename')
+def test_gpt_rename_partition(state_disk_image, u_boot_console):
     """Test the gpt rename command to write partition names."""
 
-    if u_boot_console.config.buildconfig.get('config_cmd_gpt_rename', 'n') != 'y':
-        pytest.skip('gpt rename command not supported')
-    u_boot_console.run_command('host bind 0 testdisk.raw')
+    u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
     u_boot_console.run_command('gpt rename host 0 1 first')
     output = u_boot_console.run_command('gpt read host 0')
     assert 'name first' in output
@@ -50,15 +97,14 @@ def test_gpt_rename_partition(u_boot_console):
     output = u_boot_console.run_command('gpt read host 0')
     assert 'name second' in output
 
+@pytest.mark.boardspec('sandbox')
 @pytest.mark.buildconfigspec('cmd_gpt')
-def test_gpt_swap_partitions(u_boot_console):
+@pytest.mark.buildconfigspec('cmd_gpt_rename')
+@pytest.mark.buildconfigspec('cmd_part')
+def test_gpt_swap_partitions(state_disk_image, u_boot_console):
     """Test the gpt swap command to exchange two partition names."""
 
-    if u_boot_console.config.buildconfig.get('config_cmd_gpt_rename', 'n') != 'y':
-        pytest.skip('gpt rename command not supported')
-    if u_boot_console.config.buildconfig.get('config_cmd_part', 'n') != 'y':
-        pytest.skip('gpt swap test needs CMD_PART')
-    u_boot_console.run_command('host bind 0 testdisk.raw')
+    u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
     output = u_boot_console.run_command('part list host 0')
     assert '0x000007ff "first"' in output
     assert '0x000017ff "second"' in output
@@ -66,4 +112,3 @@ def test_gpt_swap_partitions(u_boot_console):
     output = u_boot_console.run_command('part list host 0')
     assert '0x000007ff "second"' in output
     assert '0x000017ff "first"' in output
-    os.remove('testdisk.raw')
index 041a33188ff9e8ecae75d8f62ff6646185894cb9..dc9c0d9f45883b2a2c51f5ccd79c0f14a78bc8ae 100644 (file)
@@ -12,6 +12,7 @@ This supports converting device tree data to C structures definitions and
 static data.
 """
 
+import collections
 import copy
 import sys
 
@@ -38,11 +39,20 @@ TYPE_NAMES = {
     fdt.TYPE_BYTE: 'unsigned char',
     fdt.TYPE_STRING: 'const char *',
     fdt.TYPE_BOOL: 'bool',
+    fdt.TYPE_INT64: 'fdt64_t',
 }
 
 STRUCT_PREFIX = 'dtd_'
 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):
     """Convert a device-tree name to a C identifier
 
@@ -95,6 +105,8 @@ def get_value(ftype, value):
         return '"%s"' % value
     elif ftype == fdt.TYPE_BOOL:
         return 'true'
+    elif ftype == fdt.TYPE_INT64:
+        return '%#x' % value
 
 def get_compat_name(node):
     """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:]
     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):
     """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
         _valid_nodes: A list of Node object with compatible strings
         _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)
         _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):
         self._fdt = None
         self._dtb_fname = dtb_fname
         self._valid_nodes = None
         self._include_disabled = include_disabled
-        self._phandle_nodes = {}
         self._outfile = None
         self._lines = []
         self._aliases = {}
@@ -196,6 +190,53 @@ class DtbPlatdata(object):
         self._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):
         """Scan the device tree to obtain a tree of nodes and properties
 
@@ -207,8 +248,7 @@ class DtbPlatdata(object):
     def scan_node(self, root):
         """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:
             root: Root node for scan
@@ -219,10 +259,6 @@ class DtbPlatdata(object):
                 if (not self._include_disabled and not status or
                         status.value != 'disabled'):
                     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
             self.scan_node(node)
@@ -231,14 +267,72 @@ class DtbPlatdata(object):
         """Scan the device tree for useful information
 
         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
                 platform data
         """
-        self._phandle_nodes = {}
         self._valid_nodes = []
         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):
         """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():
                 if pname in PROP_IGNORE_LIST or pname[0] == '#':
                     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):
@@ -322,6 +420,7 @@ class DtbPlatdata(object):
         definitions for node in self._valid_nodes. See the documentation in
         README.of-plat for more information.
         """
+        self.out_header()
         self.out('#include <stdbool.h>\n')
         self.out('#include <libfdt.h>\n')
 
@@ -330,11 +429,13 @@ class DtbPlatdata(object):
             self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
             for pname in sorted(structs[name]):
                 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
-                    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),
-                                             len(prop.value) / 2))
+                                             len(info.args)))
                 else:
                     ptype = TYPE_NAMES[prop.type]
                     self.out('\t%s%s' % (tab_to(2, ptype),
@@ -370,19 +471,32 @@ class DtbPlatdata(object):
                 vals = []
                 # For phandles, output a reference to the platform data
                 # 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)
-                    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)
-                        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)
-                        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:
                     for val in prop.value:
                         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('}')
             else:
                 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
         information.
         """
+        self.out_header()
         self.out('#include <common.h>\n')
         self.out('#include <dm.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.scan_dtb()
     plat.scan_tree()
+    plat.scan_reg_sizes()
     plat.setup_output(output)
     structs = plat.scan_structs()
     plat.scan_phandles()
diff --git a/tools/dtoc/dtoc_test_addr32.dts b/tools/dtoc/dtoc_test_addr32.dts
new file mode 100644 (file)
index 0000000..bcfdcae
--- /dev/null
@@ -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>;
+       };
+
+};
diff --git a/tools/dtoc/dtoc_test_addr32_64.dts b/tools/dtoc/dtoc_test_addr32_64.dts
new file mode 100644 (file)
index 0000000..1c96243
--- /dev/null
@@ -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>;
+       };
+
+};
diff --git a/tools/dtoc/dtoc_test_addr64.dts b/tools/dtoc/dtoc_test_addr64.dts
new file mode 100644 (file)
index 0000000..4c0ad0e
--- /dev/null
@@ -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>;
+       };
+
+};
diff --git a/tools/dtoc/dtoc_test_addr64_32.dts b/tools/dtoc/dtoc_test_addr64_32.dts
new file mode 100644 (file)
index 0000000..c36f6b7
--- /dev/null
@@ -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>;
+       };
+
+};
index e9828a695b5b6343226e0e92976203b29321e894..ba12b0fe65ea88ef49744ceae31f283131e124a1 100644 (file)
 
 / {
        phandle: phandle-target {
+               u-boot,dm-pre-reloc;
+               compatible = "target";
+               intval = <0>;
+                #clock-cells = <0>;
+       };
+
+       phandle_1: phandle2-target {
                u-boot,dm-pre-reloc;
                compatible = "target";
                intval = <1>;
+               #clock-cells = <1>;
+       };
+       phandle_2: phandle3-target {
+               u-boot,dm-pre-reloc;
+               compatible = "target";
+               intval = <2>;
+               #clock-cells = <2>;
        };
 
        phandle-source {
                u-boot,dm-pre-reloc;
                compatible = "source";
-               clocks = <&phandle 1>;
+               clocks = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
        };
 };
index c7366862637a99b44a320e66dbc31cd53663d921..6afe674b1f571b69084527df2b2d9a3dd5873824 100644 (file)
@@ -9,6 +9,8 @@
  /dts-v1/;
 
 / {
+       #address-cells = <1>;
+       #size-cells = <1>;
        spl-test {
                u-boot,dm-pre-reloc;
                compatible = "sandbox,spl-test";
                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;
+               };
+       };
 };
index 63a32ea2d7bfcaeb9897406a986ff8dc65ac61c5..dbc338653bca6f542f8ab0676f3a1bb76e1a7b3a 100644 (file)
@@ -21,7 +21,7 @@ import libfdt
 # so it is fairly efficient.
 
 # 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):
     if errnum:
@@ -174,8 +174,9 @@ class Node:
         props: A dict of properties for this node, each a Prop object.
             Keyed by property name
     """
-    def __init__(self, fdt, offset, name, path):
+    def __init__(self, fdt, parent, offset, name, path):
         self._fdt = fdt
+        self.parent = parent
         self._offset = offset
         self.name = name
         self.path = path
@@ -211,13 +212,17 @@ class Node:
         searching into subnodes so that the entire tree is built.
         """
         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())
         while offset >= 0:
             sep = '' if self.path[-1] == '/' else '/'
             name = self._fdt._fdt_obj.get_name(offset)
             path = self.path + sep + name
-            node = Node(self._fdt, offset, name, path)
+            node = Node(self._fdt, self, offset, name, path)
             self.subnodes.append(node)
 
             node.Scan()
@@ -262,6 +267,7 @@ class Fdt:
     def __init__(self, fname):
         self._fname = fname
         self._cached_offsets = False
+        self.phandle_to_node = {}
         if self._fname:
             self._fname = fdt_util.EnsureCompiled(self._fname)
 
@@ -279,7 +285,7 @@ class Fdt:
 
         TODO(sjg@chromium.org): Implement the 'root' parameter
         """
-        self._root = self.Node(self, 0, '/', '/')
+        self._root = self.Node(self, None, 0, '/', '/')
         self._root.Scan()
 
     def GetRoot(self):
@@ -386,7 +392,7 @@ class Fdt:
         return libfdt.fdt_off_dt_struct(self._fdt) + offset
 
     @classmethod
-    def Node(self, fdt, offset, name, path):
+    def Node(self, fdt, parent, offset, name, path):
         """Create a new node
 
         This is used by Fdt.Scan() to create a new node using the correct
@@ -394,11 +400,12 @@ class Fdt:
 
         Args:
             fdt: Fdt object
+            parent: Parent node, or None if this is the root node
             offset: Offset of node
             name: Node name
             path: Full path to node
         """
-        node = Node(fdt, offset, name, path)
+        node = Node(fdt, parent, offset, name, path)
         return node
 
 def FdtScan(fname):
index b9dfae8d0e7b606c28fac252f82afcaef801fe49..338d47a5e1489622399f4f7294388a36103044bf 100644 (file)
@@ -29,6 +29,22 @@ def fdt32_to_cpu(val):
         val = val.encode('raw_unicode_escape')
     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):
     """Compile an fdt .dts source file into a .dtb binary blob if needed.
 
index 8b95c4124f02a5d2acc5c26cbf5a6dc9e8a1a7e6..cc009b2a256a248fc0f1faff6b303a7381f22066 100644 (file)
@@ -121,6 +121,12 @@ class TestDtoc(unittest.TestCase):
             data = infile.read()
         self.assertEqual('''#include <stdbool.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 {
 \tbool\t\tboolval;
 \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.byteval\t\t= 0x5,
 \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.boolval\t\t= true,
 \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.byteval\t\t= 0x8,
 \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.intarray\t\t= {0x5, 0x0, 0x0, 0x0},
 \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),
 };
 
+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)
 
     def test_phandle(self):
@@ -202,7 +228,7 @@ U_BOOT_DEVICE(spl_test4) = {
         self.assertEqual('''#include <stdbool.h>
 #include <libfdt.h>
 struct dtd_source {
-\tstruct phandle_2_cell clocks[1];
+\tstruct phandle_2_arg clocks[4];
 };
 struct dtd_target {
 \tfdt32_t\t\tintval;
@@ -217,7 +243,7 @@ struct dtd_target {
 #include <dt-structs.h>
 
 static struct dtd_target dtv_phandle_target = {
-\t.intval\t\t\t= 0x1,
+\t.intval\t\t\t= 0x0,
 };
 U_BOOT_DEVICE(phandle_target) = {
 \t.name\t\t= "target",
@@ -225,8 +251,30 @@ U_BOOT_DEVICE(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 = {
-\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) = {
 \t.name\t\t= "source",
@@ -268,4 +316,216 @@ U_BOOT_DEVICE(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)