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

master
Tom Rini 7 years ago
commit 08cebeeaad
  1. 5
      .travis.yml
  2. 7
      cmd/fdt.c
  3. 31
      common/fdt_support.c
  4. 7
      common/image-fdt.c
  5. 210
      common/image-fit.c
  6. 2
      configs/sandbox_defconfig
  7. 114
      doc/README.fdt-overlays
  8. 2
      doc/driver-model/of-plat.txt
  9. 12
      doc/uImage.FIT/command_syntax_extensions.txt
  10. 225
      doc/uImage.FIT/overlay-fdt-boot.txt
  11. 6
      doc/uImage.FIT/source_file_format.txt
  12. 4
      drivers/clk/clk-uclass.c
  13. 2
      drivers/clk/rockchip/clk_rk3368.c
  14. 4
      drivers/clk/rockchip/clk_rk3399.c
  15. 2
      drivers/core/regmap.c
  16. 4
      include/clk.h
  17. 16
      include/dt-structs.h
  18. 2
      include/fdt_support.h
  19. 2
      include/fdtdec.h
  20. 25
      include/image.h
  21. 2
      include/regmap.h
  22. 6
      include/syscon.h
  23. 228
      lib/libfdt/fdt_overlay.c
  24. 20
      lib/libfdt/fdt_rw.c
  25. 2
      lib/libfdt/fdt_wip.c
  26. 31
      lib/libfdt/libfdt.h
  27. 58
      lib/libfdt/pylibfdt/libfdt.i
  28. 17
      scripts/Makefile.lib
  29. 5
      scripts/Makefile.spl
  30. 1
      test/overlay/Makefile
  31. 50
      test/overlay/cmd_ut_overlay.c
  32. 21
      test/overlay/test-fdt-overlay-stacked.dts
  33. 204
      tools/dtoc/dtb_platdata.py
  34. 27
      tools/dtoc/dtoc_test_addr32.dts
  35. 33
      tools/dtoc/dtoc_test_addr32_64.dts
  36. 33
      tools/dtoc/dtoc_test_addr64.dts
  37. 33
      tools/dtoc/dtoc_test_addr64_32.dts
  38. 16
      tools/dtoc/dtoc_test_phandle.dts
  39. 14
      tools/dtoc/dtoc_test_simple.dts
  40. 19
      tools/dtoc/fdt.py
  41. 16
      tools/dtoc/fdt_util.py
  42. 270
      tools/dtoc/test_dtoc.py

@ -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`

@ -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 */

@ -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

@ -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

@ -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

@ -190,7 +190,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

@ -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

@ -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];

@ -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

@ -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

@ -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

@ -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;
}

@ -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);

@ -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

@ -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;

@ -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.

@ -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

@ -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

@ -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 */

@ -594,6 +594,31 @@ 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
*
* This deals with all aspects of loading an image from a FIT, including

@ -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);
/**

@ -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

@ -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.
*/

@ -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;
}

@ -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;

@ -1405,6 +1405,37 @@ 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
* @nodeoffset: offset of the node whose property to change

@ -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.

@ -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
# ---------------------------------------------------------------------------

@ -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

@ -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

@ -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);

@ -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>;
};
};
};

@ -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()

@ -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>;
};
};

@ -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>;
};
};

@ -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>;
};
};

@ -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>;
};
};

@ -12,12 +12,26 @@
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>;
};
};

@ -9,6 +9,8 @@
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
spl-test {
u-boot,dm-pre-reloc;
compatible = "sandbox,spl-test";
@ -45,4 +47,16 @@
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;
};
};
};

@ -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):

@ -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.

@ -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",
@ -269,3 +317,215 @@ U_BOOT_DEVICE(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)

Loading…
Cancel
Save