Merge git://git.denx.de/u-boot-fdt
This commit is contained in:
commit
08cebeeaad
@ -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,27 +1482,56 @@ 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_count(const void *fit, int noffset,
|
||||
const char *prop_name)
|
||||
{
|
||||
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 = 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)
|
||||
{
|
||||
char *uname;
|
||||
int len;
|
||||
|
||||
/* get kernel image unit name from configuration kernel property */
|
||||
uname = (char *)fdt_getprop(fit, noffset, prop_name, &len);
|
||||
if (uname == NULL)
|
||||
return len;
|
||||
|
||||
return fit_image_get_node(fit, uname);
|
||||
return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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
|
||||
|
114
doc/README.fdt-overlays
Normal file
114
doc/README.fdt-overlays
Normal file
@ -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
|
||||
|
225
doc/uImage.FIT/overlay-fdt-boot.txt
Normal file
225
doc/uImage.FIT/overlay-fdt-boot.txt
Normal file
@ -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 */
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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 path_len;
|
||||
}
|
||||
/* return on error */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return fdt_path_offset(fdt, path);
|
||||
/* return pointer to path (if available) */
|
||||
if (pathp)
|
||||
*pathp = path ? path : NULL;
|
||||
|
||||
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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
21
test/overlay/test-fdt-overlay-stacked.dts
Normal file
21
test/overlay/test-fdt-overlay-stacked.dts
Normal file
@ -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()
|
||||
|
27
tools/dtoc/dtoc_test_addr32.dts
Normal file
27
tools/dtoc/dtoc_test_addr32.dts
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Test device tree file for dtoc
|
||||
*
|
||||
* Copyright 2017 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
test1 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "test1";
|
||||
reg = <0x1234 0x5678>;
|
||||
};
|
||||
|
||||
test2 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "test2";
|
||||
reg = <0x12345678 0x98765432 2 3>;
|
||||
};
|
||||
|
||||
};
|
33
tools/dtoc/dtoc_test_addr32_64.dts
Normal file
33
tools/dtoc/dtoc_test_addr32_64.dts
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Test device tree file for dtoc
|
||||
*
|
||||
* Copyright 2017 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <2>;
|
||||
|
||||
test1 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "test1";
|
||||
reg = <0x1234 0x5678 0x0>;
|
||||
};
|
||||
|
||||
test2 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "test2";
|
||||
reg = <0x12345678 0x98765432 0x10987654>;
|
||||
};
|
||||
|
||||
test3 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "test3";
|
||||
reg = <0x12345678 0x98765432 0x10987654 2 0 3>;
|
||||
};
|
||||
|
||||
};
|
33
tools/dtoc/dtoc_test_addr64.dts
Normal file
33
tools/dtoc/dtoc_test_addr64.dts
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Test device tree file for dtoc
|
||||
*
|
||||
* Copyright 2017 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
test1 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "test1";
|
||||
reg = /bits/ 64 <0x1234 0x5678>;
|
||||
};
|
||||
|
||||
test2 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "test2";
|
||||
reg = /bits/ 64 <0x1234567890123456 0x9876543210987654>;
|
||||
};
|
||||
|
||||
test3 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "test3";
|
||||
reg = /bits/ 64 <0x1234567890123456 0x9876543210987654 2 3>;
|
||||
};
|
||||
|
||||
};
|
33
tools/dtoc/dtoc_test_addr64_32.dts
Normal file
33
tools/dtoc/dtoc_test_addr64_32.dts
Normal file
@ -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>;
|
||||
};
|
||||
|
||||
};
|
@ -10,14 +10,28 @@
|
||||
|
||||
/ {
|
||||
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",
|
||||
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user