Merge git://git.denx.de/u-boot-fdt
This commit is contained in:
commit
08cebeeaad
|
|
@ -26,12 +26,11 @@ addons:
|
||||||
- grub-efi-ia32-bin
|
- grub-efi-ia32-bin
|
||||||
- rpm2cpio
|
- rpm2cpio
|
||||||
- wget
|
- wget
|
||||||
- device-tree-compiler
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# install latest device tree compiler
|
# install latest device tree compiler
|
||||||
#- git clone --depth=1 git://git.kernel.org/pub/scm/utils/dtc/dtc.git /tmp/dtc
|
- git clone --depth=1 git://git.kernel.org/pub/scm/utils/dtc/dtc.git /tmp/dtc
|
||||||
#- make -j4 -C /tmp/dtc
|
- make -j4 -C /tmp/dtc
|
||||||
# Clone uboot-test-hooks
|
# Clone uboot-test-hooks
|
||||||
- git clone --depth=1 git://github.com/swarren/uboot-test-hooks.git /tmp/uboot-test-hooks
|
- git clone --depth=1 git://github.com/swarren/uboot-test-hooks.git /tmp/uboot-test-hooks
|
||||||
- ln -s travis-ci /tmp/uboot-test-hooks/bin/`hostname`
|
- ln -s travis-ci /tmp/uboot-test-hooks/bin/`hostname`
|
||||||
|
|
|
||||||
|
|
@ -667,12 +667,11 @@ static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
if (!fdt_valid(&blob))
|
if (!fdt_valid(&blob))
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
|
|
||||||
ret = fdt_overlay_apply(working_fdt, blob);
|
/* apply method prints messages on error */
|
||||||
if (ret) {
|
ret = fdt_overlay_apply_verbose(working_fdt, blob);
|
||||||
printf("fdt_overlay_apply(): %s\n", fdt_strerror(ret));
|
if (ret)
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
/* resize the fdt */
|
/* resize the fdt */
|
||||||
else if (strncmp(argv[1], "re", 2) == 0) {
|
else if (strncmp(argv[1], "re", 2) == 0) {
|
||||||
|
|
|
||||||
|
|
@ -1655,3 +1655,34 @@ int fdt_fixup_display(void *blob, const char *path, const char *display)
|
||||||
}
|
}
|
||||||
return toff;
|
return toff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF_LIBFDT_OVERLAY
|
||||||
|
/**
|
||||||
|
* fdt_overlay_apply_verbose - Apply an overlay with verbose error reporting
|
||||||
|
*
|
||||||
|
* @fdt: ptr to device tree
|
||||||
|
* @fdto: ptr to device tree overlay
|
||||||
|
*
|
||||||
|
* Convenience function to apply an overlay and display helpful messages
|
||||||
|
* in the case of an error
|
||||||
|
*/
|
||||||
|
int fdt_overlay_apply_verbose(void *fdt, void *fdto)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
bool has_symbols;
|
||||||
|
|
||||||
|
err = fdt_path_offset(fdt, "/__symbols__");
|
||||||
|
has_symbols = err >= 0;
|
||||||
|
|
||||||
|
err = fdt_overlay_apply(fdt, fdto);
|
||||||
|
if (err < 0) {
|
||||||
|
printf("failed on fdt_overlay_apply(): %s\n",
|
||||||
|
fdt_strerror(err));
|
||||||
|
if (!has_symbols) {
|
||||||
|
printf("base fdt does did not have a /__symbols__ node\n");
|
||||||
|
printf("make sure you've compiled with -@\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -356,17 +356,16 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,
|
||||||
if (fit_check_format(buf)) {
|
if (fit_check_format(buf)) {
|
||||||
ulong load, len;
|
ulong load, len;
|
||||||
|
|
||||||
fdt_noffset = fit_image_load(images,
|
fdt_noffset = boot_get_fdt_fit(images,
|
||||||
fdt_addr, &fit_uname_fdt,
|
fdt_addr, &fit_uname_fdt,
|
||||||
&fit_uname_config,
|
&fit_uname_config,
|
||||||
arch, IH_TYPE_FLATDT,
|
arch, &load, &len);
|
||||||
BOOTSTAGE_ID_FIT_FDT_START,
|
|
||||||
FIT_LOAD_OPTIONAL, &load, &len);
|
|
||||||
|
|
||||||
images->fit_hdr_fdt = map_sysmem(fdt_addr, 0);
|
images->fit_hdr_fdt = map_sysmem(fdt_addr, 0);
|
||||||
images->fit_uname_fdt = fit_uname_fdt;
|
images->fit_uname_fdt = fit_uname_fdt;
|
||||||
images->fit_noffset_fdt = fdt_noffset;
|
images->fit_noffset_fdt = fdt_noffset;
|
||||||
fdt_addr = load;
|
fdt_addr = load;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <mapmem.h>
|
#include <mapmem.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
#include <malloc.h>
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
#endif /* !USE_HOSTCC*/
|
#endif /* !USE_HOSTCC*/
|
||||||
|
|
||||||
|
|
@ -434,6 +435,10 @@ void fit_image_print(const void *fit, int image_noffset, const char *p)
|
||||||
printf("0x%08lx\n", load);
|
printf("0x%08lx\n", load);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* optional load address for FDT */
|
||||||
|
if (type == IH_TYPE_FLATDT && !fit_image_get_load(fit, image_noffset, &load))
|
||||||
|
printf("%s Load Address: 0x%08lx\n", p, load);
|
||||||
|
|
||||||
if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
|
if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
|
||||||
(type == IH_TYPE_RAMDISK)) {
|
(type == IH_TYPE_RAMDISK)) {
|
||||||
ret = fit_image_get_entry(fit, image_noffset, &entry);
|
ret = fit_image_get_entry(fit, image_noffset, &entry);
|
||||||
|
|
@ -1454,6 +1459,8 @@ int fit_conf_get_node(const void *fit, const char *conf_uname)
|
||||||
{
|
{
|
||||||
int noffset, confs_noffset;
|
int noffset, confs_noffset;
|
||||||
int len;
|
int len;
|
||||||
|
const char *s;
|
||||||
|
char *conf_uname_copy = NULL;
|
||||||
|
|
||||||
confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
|
confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
|
||||||
if (confs_noffset < 0) {
|
if (confs_noffset < 0) {
|
||||||
|
|
@ -1475,27 +1482,56 @@ int fit_conf_get_node(const void *fit, const char *conf_uname)
|
||||||
debug("Found default configuration: '%s'\n", conf_uname);
|
debug("Found default configuration: '%s'\n", conf_uname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s = strchr(conf_uname, '#');
|
||||||
|
if (s) {
|
||||||
|
len = s - conf_uname;
|
||||||
|
conf_uname_copy = malloc(len + 1);
|
||||||
|
if (!conf_uname_copy) {
|
||||||
|
debug("Can't allocate uname copy: '%s'\n",
|
||||||
|
conf_uname);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
memcpy(conf_uname_copy, conf_uname, len);
|
||||||
|
conf_uname_copy[len] = '\0';
|
||||||
|
conf_uname = conf_uname_copy;
|
||||||
|
}
|
||||||
|
|
||||||
noffset = fdt_subnode_offset(fit, confs_noffset, conf_uname);
|
noffset = fdt_subnode_offset(fit, confs_noffset, conf_uname);
|
||||||
if (noffset < 0) {
|
if (noffset < 0) {
|
||||||
debug("Can't get node offset for configuration unit name: '%s' (%s)\n",
|
debug("Can't get node offset for configuration unit name: '%s' (%s)\n",
|
||||||
conf_uname, fdt_strerror(noffset));
|
conf_uname, fdt_strerror(noffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conf_uname_copy)
|
||||||
|
free(conf_uname_copy);
|
||||||
|
|
||||||
return noffset;
|
return noffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fit_conf_get_prop_node_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,
|
int fit_conf_get_prop_node(const void *fit, int noffset,
|
||||||
const char *prop_name)
|
const char *prop_name)
|
||||||
{
|
{
|
||||||
char *uname;
|
return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1515,7 +1551,7 @@ void fit_conf_print(const void *fit, int noffset, const char *p)
|
||||||
char *desc;
|
char *desc;
|
||||||
const char *uname;
|
const char *uname;
|
||||||
int ret;
|
int ret;
|
||||||
int loadables_index;
|
int fdt_index, loadables_index;
|
||||||
|
|
||||||
/* Mandatory properties */
|
/* Mandatory properties */
|
||||||
ret = fit_get_desc(fit, noffset, &desc);
|
ret = fit_get_desc(fit, noffset, &desc);
|
||||||
|
|
@ -1537,9 +1573,17 @@ void fit_conf_print(const void *fit, int noffset, const char *p)
|
||||||
if (uname)
|
if (uname)
|
||||||
printf("%s Init Ramdisk: %s\n", p, uname);
|
printf("%s Init Ramdisk: %s\n", p, uname);
|
||||||
|
|
||||||
uname = fdt_getprop(fit, noffset, FIT_FDT_PROP, NULL);
|
for (fdt_index = 0;
|
||||||
if (uname)
|
uname = fdt_stringlist_get(fit, noffset, FIT_FDT_PROP,
|
||||||
printf("%s FDT: %s\n", p, uname);
|
fdt_index, NULL), uname;
|
||||||
|
fdt_index++) {
|
||||||
|
|
||||||
|
if (fdt_index == 0)
|
||||||
|
printf("%s FDT: ", p);
|
||||||
|
else
|
||||||
|
printf("%s ", p);
|
||||||
|
printf("%s\n", uname);
|
||||||
|
}
|
||||||
|
|
||||||
uname = fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL);
|
uname = fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL);
|
||||||
if (uname)
|
if (uname)
|
||||||
|
|
@ -1641,6 +1685,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
|
||||||
int cfg_noffset, noffset;
|
int cfg_noffset, noffset;
|
||||||
const char *fit_uname;
|
const char *fit_uname;
|
||||||
const char *fit_uname_config;
|
const char *fit_uname_config;
|
||||||
|
const char *fit_base_uname_config;
|
||||||
const void *fit;
|
const void *fit;
|
||||||
const void *buf;
|
const void *buf;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
@ -1656,6 +1701,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
|
||||||
fit = map_sysmem(addr, 0);
|
fit = map_sysmem(addr, 0);
|
||||||
fit_uname = fit_unamep ? *fit_unamep : NULL;
|
fit_uname = fit_unamep ? *fit_unamep : NULL;
|
||||||
fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL;
|
fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL;
|
||||||
|
fit_base_uname_config = NULL;
|
||||||
prop_name = fit_get_image_type_property(image_type);
|
prop_name = fit_get_image_type_property(image_type);
|
||||||
printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
|
printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
|
||||||
|
|
||||||
|
|
@ -1689,11 +1735,11 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
|
||||||
BOOTSTAGE_SUB_NO_UNIT_NAME);
|
BOOTSTAGE_SUB_NO_UNIT_NAME);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
|
fit_base_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
|
||||||
printf(" Using '%s' configuration\n", fit_uname_config);
|
printf(" Using '%s' configuration\n", fit_base_uname_config);
|
||||||
if (image_type == IH_TYPE_KERNEL) {
|
if (image_type == IH_TYPE_KERNEL) {
|
||||||
/* Remember (and possibly verify) this config */
|
/* Remember (and possibly verify) this config */
|
||||||
images->fit_uname_cfg = fit_uname_config;
|
images->fit_uname_cfg = fit_base_uname_config;
|
||||||
if (IMAGE_ENABLE_VERIFY && images->verify) {
|
if (IMAGE_ENABLE_VERIFY && images->verify) {
|
||||||
puts(" Verifying Hash Integrity ... ");
|
puts(" Verifying Hash Integrity ... ");
|
||||||
if (fit_config_verify(fit, cfg_noffset)) {
|
if (fit_config_verify(fit, cfg_noffset)) {
|
||||||
|
|
@ -1849,7 +1895,8 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
|
||||||
if (fit_unamep)
|
if (fit_unamep)
|
||||||
*fit_unamep = (char *)fit_uname;
|
*fit_unamep = (char *)fit_uname;
|
||||||
if (fit_uname_configp)
|
if (fit_uname_configp)
|
||||||
*fit_uname_configp = (char *)fit_uname_config;
|
*fit_uname_configp = (char *)(fit_uname_config ? :
|
||||||
|
fit_base_uname_config);
|
||||||
|
|
||||||
return noffset;
|
return noffset;
|
||||||
}
|
}
|
||||||
|
|
@ -1873,3 +1920,144 @@ int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef USE_HOSTCC
|
||||||
|
int boot_get_fdt_fit(bootm_headers_t *images, ulong addr,
|
||||||
|
const char **fit_unamep, const char **fit_uname_configp,
|
||||||
|
int arch, ulong *datap, ulong *lenp)
|
||||||
|
{
|
||||||
|
int fdt_noffset, cfg_noffset, count;
|
||||||
|
const void *fit;
|
||||||
|
const char *fit_uname = NULL;
|
||||||
|
const char *fit_uname_config = NULL;
|
||||||
|
char *fit_uname_config_copy = NULL;
|
||||||
|
char *next_config = NULL;
|
||||||
|
ulong load, len;
|
||||||
|
#ifdef CONFIG_OF_LIBFDT_OVERLAY
|
||||||
|
ulong image_start, image_end;
|
||||||
|
ulong ovload, ovlen;
|
||||||
|
const char *uconfig;
|
||||||
|
const char *uname;
|
||||||
|
void *base, *ov;
|
||||||
|
int i, err, noffset, ov_noffset;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fit_uname = fit_unamep ? *fit_unamep : NULL;
|
||||||
|
|
||||||
|
if (fit_uname_configp && *fit_uname_configp) {
|
||||||
|
fit_uname_config_copy = strdup(*fit_uname_configp);
|
||||||
|
if (!fit_uname_config_copy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
next_config = strchr(fit_uname_config_copy, '#');
|
||||||
|
if (next_config)
|
||||||
|
*next_config++ = '\0';
|
||||||
|
if (next_config - 1 > fit_uname_config_copy)
|
||||||
|
fit_uname_config = fit_uname_config_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt_noffset = fit_image_load(images,
|
||||||
|
addr, &fit_uname, &fit_uname_config,
|
||||||
|
arch, IH_TYPE_FLATDT,
|
||||||
|
BOOTSTAGE_ID_FIT_FDT_START,
|
||||||
|
FIT_LOAD_OPTIONAL, &load, &len);
|
||||||
|
|
||||||
|
if (fdt_noffset < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
debug("fit_uname=%s, fit_uname_config=%s\n",
|
||||||
|
fit_uname ? fit_uname : "<NULL>",
|
||||||
|
fit_uname_config ? fit_uname_config : "<NULL>");
|
||||||
|
|
||||||
|
fit = map_sysmem(addr, 0);
|
||||||
|
|
||||||
|
cfg_noffset = fit_conf_get_node(fit, fit_uname_config);
|
||||||
|
|
||||||
|
/* single blob, or error just return as well */
|
||||||
|
count = fit_conf_get_prop_node_count(fit, cfg_noffset, FIT_FDT_PROP);
|
||||||
|
if (count <= 1 && !next_config)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* we need to apply overlays */
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF_LIBFDT_OVERLAY
|
||||||
|
image_start = addr;
|
||||||
|
image_end = addr + fit_get_size(fit);
|
||||||
|
/* verify that relocation took place by load address not being in fit */
|
||||||
|
if (load >= image_start && load < image_end) {
|
||||||
|
/* check is simplified; fit load checks for overlaps */
|
||||||
|
printf("Overlayed FDT requires relocation\n");
|
||||||
|
fdt_noffset = -EBADF;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
base = map_sysmem(load, len);
|
||||||
|
|
||||||
|
/* apply extra configs in FIT first, followed by args */
|
||||||
|
for (i = 1; ; i++) {
|
||||||
|
if (i < count) {
|
||||||
|
noffset = fit_conf_get_prop_node_index(fit, cfg_noffset,
|
||||||
|
FIT_FDT_PROP, i);
|
||||||
|
uname = fit_get_name(fit, noffset, NULL);
|
||||||
|
uconfig = NULL;
|
||||||
|
} else {
|
||||||
|
if (!next_config)
|
||||||
|
break;
|
||||||
|
uconfig = next_config;
|
||||||
|
next_config = strchr(next_config, '#');
|
||||||
|
if (next_config)
|
||||||
|
*next_config++ = '\0';
|
||||||
|
uname = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("%d: using uname=%s uconfig=%s\n", i, uname, uconfig);
|
||||||
|
|
||||||
|
ov_noffset = fit_image_load(images,
|
||||||
|
addr, &uname, &uconfig,
|
||||||
|
arch, IH_TYPE_FLATDT,
|
||||||
|
BOOTSTAGE_ID_FIT_FDT_START,
|
||||||
|
FIT_LOAD_REQUIRED, &ovload, &ovlen);
|
||||||
|
if (ov_noffset < 0) {
|
||||||
|
printf("load of %s failed\n", uname);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
debug("%s loaded at 0x%08lx len=0x%08lx\n",
|
||||||
|
uname, ovload, ovlen);
|
||||||
|
ov = map_sysmem(ovload, ovlen);
|
||||||
|
|
||||||
|
base = map_sysmem(load, len + ovlen);
|
||||||
|
err = fdt_open_into(base, base, len + ovlen);
|
||||||
|
if (err < 0) {
|
||||||
|
printf("failed on fdt_open_into\n");
|
||||||
|
fdt_noffset = err;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* the verbose method prints out messages on error */
|
||||||
|
err = fdt_overlay_apply_verbose(base, ov);
|
||||||
|
if (err < 0) {
|
||||||
|
fdt_noffset = err;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
fdt_pack(base);
|
||||||
|
len = fdt_totalsize(base);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
printf("config with overlays but CONFIG_OF_LIBFDT_OVERLAY not set\n");
|
||||||
|
fdt_noffset = -EBADF;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (datap)
|
||||||
|
*datap = load;
|
||||||
|
if (lenp)
|
||||||
|
*lenp = len;
|
||||||
|
if (fit_unamep)
|
||||||
|
*fit_unamep = fit_uname;
|
||||||
|
if (fit_uname_configp)
|
||||||
|
*fit_uname_configp = fit_uname_config;
|
||||||
|
|
||||||
|
if (fit_uname_config_copy)
|
||||||
|
free(fit_uname_config_copy);
|
||||||
|
return fdt_noffset;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,9 @@ CONFIG_CMD_DHRYSTONE=y
|
||||||
CONFIG_TPM=y
|
CONFIG_TPM=y
|
||||||
CONFIG_LZ4=y
|
CONFIG_LZ4=y
|
||||||
CONFIG_ERRNO_STR=y
|
CONFIG_ERRNO_STR=y
|
||||||
|
CONFIG_OF_LIBFDT_OVERLAY=y
|
||||||
CONFIG_UNIT_TEST=y
|
CONFIG_UNIT_TEST=y
|
||||||
CONFIG_UT_TIME=y
|
CONFIG_UT_TIME=y
|
||||||
CONFIG_UT_DM=y
|
CONFIG_UT_DM=y
|
||||||
CONFIG_UT_ENV=y
|
CONFIG_UT_ENV=y
|
||||||
|
CONFIG_UT_OVERLAY=y
|
||||||
|
|
|
||||||
|
|
@ -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;
|
bool cap_sd_highspeed;
|
||||||
fdt32_t card_detect_delay;
|
fdt32_t card_detect_delay;
|
||||||
fdt32_t clock_freq_min_max[2];
|
fdt32_t clock_freq_min_max[2];
|
||||||
struct phandle_2_cell clocks[4];
|
struct phandle_1_arg clocks[4];
|
||||||
bool disable_wp;
|
bool disable_wp;
|
||||||
fdt32_t fifo_depth;
|
fdt32_t fifo_depth;
|
||||||
fdt32_t interrupts[3];
|
fdt32_t interrupts[3];
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ Old uImage:
|
||||||
New uImage:
|
New uImage:
|
||||||
8. bootm <addr1>
|
8. bootm <addr1>
|
||||||
9. bootm [<addr1>]:<subimg1>
|
9. bootm [<addr1>]:<subimg1>
|
||||||
10. bootm [<addr1>]#<conf>
|
10. bootm [<addr1>]#<conf>[#<extra-conf[#...]]
|
||||||
11. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2>
|
11. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2>
|
||||||
12. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> [<addr3>]:<subimg3>
|
12. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> [<addr3>]:<subimg3>
|
||||||
13. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> <addr3>
|
13. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> <addr3>
|
||||||
|
|
@ -129,6 +129,12 @@ following syntax:
|
||||||
- new uImage configuration specification
|
- new uImage configuration specification
|
||||||
<addr>#<configuration unit_name>
|
<addr>#<configuration unit_name>
|
||||||
|
|
||||||
|
- new uImage configuration specification with extra configuration components
|
||||||
|
<addr>#<configuration unit_name>[#<extra configuration unit_name>[#..]]
|
||||||
|
|
||||||
|
The extra configuration currently is supported only for additional device tree
|
||||||
|
overlays to apply on the base device tree supplied by the first configuration
|
||||||
|
unit.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
|
@ -138,6 +144,10 @@ bootm 200000:kernel@1
|
||||||
- boot configuration "cfg@1" from a new uImage located at 200000:
|
- boot configuration "cfg@1" from a new uImage located at 200000:
|
||||||
bootm 200000#cfg@1
|
bootm 200000#cfg@1
|
||||||
|
|
||||||
|
- boot configuration "cfg@1" with extra "cfg@2" from a new uImage located
|
||||||
|
at 200000:
|
||||||
|
bootm 200000#cfg@1#cfg@2
|
||||||
|
|
||||||
- boot "kernel@1" from a new uImage at 200000 with initrd "ramdisk@2" found in
|
- boot "kernel@1" from a new uImage at 200000 with initrd "ramdisk@2" found in
|
||||||
some other new uImage stored at address 800000:
|
some other new uImage stored at address 800000:
|
||||||
bootm 200000:kernel@1 800000:ramdisk@2
|
bootm 200000:kernel@1 800000:ramdisk@2
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|- description = "configuration description"
|
||||||
|- kernel = "kernel sub-node unit name"
|
|- kernel = "kernel sub-node unit name"
|
||||||
|- ramdisk = "ramdisk sub-node unit name"
|
|- ramdisk = "ramdisk sub-node unit name"
|
||||||
|- fdt = "fdt sub-node unit-name"
|
|- fdt = "fdt sub-node unit-name" [, "fdt overlay sub-node unit-name", ...]
|
||||||
|- fpga = "fpga sub-node unit-name"
|
|- fpga = "fpga sub-node unit-name"
|
||||||
|- loadables = "loadables sub-node unit-name"
|
|- loadables = "loadables sub-node unit-name"
|
||||||
|
|
||||||
|
|
@ -249,7 +249,9 @@ o config@1
|
||||||
- ramdisk : Unit name of the corresponding ramdisk image (component image
|
- ramdisk : Unit name of the corresponding ramdisk image (component image
|
||||||
node of a "ramdisk" type).
|
node of a "ramdisk" type).
|
||||||
- fdt : Unit name of the corresponding fdt blob (component image node of a
|
- fdt : Unit name of the corresponding fdt blob (component image node of a
|
||||||
"fdt type").
|
"fdt type"). Additional fdt overlay nodes can be supplied which signify
|
||||||
|
that the resulting device tree blob is generated by the first base fdt
|
||||||
|
blob with all subsequent overlays applied.
|
||||||
- setup : Unit name of the corresponding setup binary (used for booting
|
- setup : Unit name of the corresponding setup binary (used for booting
|
||||||
an x86 kernel). This contains the setup.bin file built by the kernel.
|
an x86 kernel). This contains the setup.bin file built by the kernel.
|
||||||
- fpga : Unit name of the corresponding fpga bitstream blob
|
- fpga : Unit name of the corresponding fpga bitstream blob
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ static inline struct clk_ops *clk_dev_ops(struct udevice *dev)
|
||||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||||
# if CONFIG_IS_ENABLED(OF_PLATDATA)
|
# if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
int clk_get_by_index_platdata(struct udevice *dev, int index,
|
int clk_get_by_index_platdata(struct udevice *dev, int index,
|
||||||
struct phandle_2_cell *cells, struct clk *clk)
|
struct phandle_1_arg *cells, struct clk *clk)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ int clk_get_by_index_platdata(struct udevice *dev, int index,
|
||||||
ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
|
ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
clk->id = cells[0].id;
|
clk->id = cells[0].arg[0];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -471,7 +471,7 @@ static int rk3368_clk_probe(struct udevice *dev)
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
struct rk3368_clk_plat *plat = dev_get_platdata(dev);
|
struct rk3368_clk_plat *plat = dev_get_platdata(dev);
|
||||||
|
|
||||||
priv->cru = map_sysmem(plat->dtd.reg[1], plat->dtd.reg[3]);
|
priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
|
||||||
#endif
|
#endif
|
||||||
#if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
|
#if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
|
||||||
rkclk_init(priv->cru);
|
rkclk_init(priv->cru);
|
||||||
|
|
|
||||||
|
|
@ -963,7 +963,7 @@ static int rk3399_clk_probe(struct udevice *dev)
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
struct rk3399_clk_plat *plat = dev_get_platdata(dev);
|
struct rk3399_clk_plat *plat = dev_get_platdata(dev);
|
||||||
|
|
||||||
priv->cru = map_sysmem(plat->dtd.reg[1], plat->dtd.reg[3]);
|
priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
|
||||||
#endif
|
#endif
|
||||||
rkclk_init(priv->cru);
|
rkclk_init(priv->cru);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1145,7 +1145,7 @@ static int rk3399_pmuclk_probe(struct udevice *dev)
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
struct rk3399_pmuclk_plat *plat = dev_get_platdata(dev);
|
struct rk3399_pmuclk_plat *plat = dev_get_platdata(dev);
|
||||||
|
|
||||||
priv->pmucru = map_sysmem(plat->dtd.reg[1], plat->dtd.reg[3]);
|
priv->pmucru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_SPL_BUILD
|
#ifndef CONFIG_SPL_BUILD
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ static struct regmap *regmap_alloc_count(int count)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
|
int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
|
||||||
struct regmap **mapp)
|
struct regmap **mapp)
|
||||||
{
|
{
|
||||||
struct regmap_range *range;
|
struct regmap_range *range;
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,9 @@ struct clk {
|
||||||
};
|
};
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(CLK)
|
#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(CLK)
|
||||||
struct phandle_2_cell;
|
struct phandle_1_arg;
|
||||||
int clk_get_by_index_platdata(struct udevice *dev, int index,
|
int clk_get_by_index_platdata(struct udevice *dev, int index,
|
||||||
struct phandle_2_cell *cells, struct clk *clk);
|
struct phandle_1_arg *cells, struct clk *clk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clock_get_by_index - Get/request a clock by integer index.
|
* clock_get_by_index - Get/request a clock by integer index.
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,21 @@
|
||||||
|
|
||||||
/* These structures may only be used in SPL */
|
/* These structures may only be used in SPL */
|
||||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
struct phandle_2_cell {
|
struct phandle_0_arg {
|
||||||
const void *node;
|
const void *node;
|
||||||
int id;
|
int arg[0];
|
||||||
};
|
};
|
||||||
#include <generated/dt-structs.h>
|
|
||||||
|
struct phandle_1_arg {
|
||||||
|
const void *node;
|
||||||
|
int arg[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct phandle_2_arg {
|
||||||
|
const void *node;
|
||||||
|
int arg[2];
|
||||||
|
};
|
||||||
|
#include <generated/dt-structs-gen.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,8 @@ int arch_fixup_memory_node(void *blob);
|
||||||
int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
|
int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
|
||||||
u32 height, u32 stride, const char *format);
|
u32 height, u32 stride, const char *format);
|
||||||
|
|
||||||
|
int fdt_overlay_apply_verbose(void *fdt, void *fdto);
|
||||||
|
|
||||||
#endif /* ifdef CONFIG_OF_LIBFDT */
|
#endif /* ifdef CONFIG_OF_LIBFDT */
|
||||||
|
|
||||||
#ifdef USE_HOSTCC
|
#ifdef USE_HOSTCC
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,12 @@ typedef phys_size_t fdt_size_t;
|
||||||
#define FDT_ADDR_T_NONE (-1ULL)
|
#define FDT_ADDR_T_NONE (-1ULL)
|
||||||
#define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
|
#define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
|
||||||
#define fdt_size_to_cpu(reg) be64_to_cpu(reg)
|
#define fdt_size_to_cpu(reg) be64_to_cpu(reg)
|
||||||
|
typedef fdt64_t fdt_val_t;
|
||||||
#else
|
#else
|
||||||
#define FDT_ADDR_T_NONE (-1U)
|
#define FDT_ADDR_T_NONE (-1U)
|
||||||
#define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
|
#define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
|
||||||
#define fdt_size_to_cpu(reg) be32_to_cpu(reg)
|
#define fdt_size_to_cpu(reg) be32_to_cpu(reg)
|
||||||
|
typedef fdt32_t fdt_val_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Information obtained about memory from the FDT */
|
/* Information obtained about memory from the FDT */
|
||||||
|
|
|
||||||
|
|
@ -593,6 +593,31 @@ int boot_get_loadable(int argc, char * const argv[], bootm_headers_t *images,
|
||||||
int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
|
int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
|
||||||
ulong *setup_start, ulong *setup_len);
|
ulong *setup_start, ulong *setup_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* boot_get_fdt_fit() - load a DTB from a FIT file (applying overlays)
|
||||||
|
*
|
||||||
|
* This deals with all aspects of loading an DTB from a FIT.
|
||||||
|
* The correct base image based on configuration will be selected, and
|
||||||
|
* then any overlays specified will be applied (as present in fit_uname_configp).
|
||||||
|
*
|
||||||
|
* @param images Boot images structure
|
||||||
|
* @param addr Address of FIT in memory
|
||||||
|
* @param fit_unamep On entry this is the requested image name
|
||||||
|
* (e.g. "kernel@1") or NULL to use the default. On exit
|
||||||
|
* points to the selected image name
|
||||||
|
* @param fit_uname_configp On entry this is the requested configuration
|
||||||
|
* name (e.g. "conf@1") or NULL to use the default. On
|
||||||
|
* exit points to the selected configuration name.
|
||||||
|
* @param arch Expected architecture (IH_ARCH_...)
|
||||||
|
* @param datap Returns address of loaded image
|
||||||
|
* @param lenp Returns length of loaded image
|
||||||
|
*
|
||||||
|
* @return node offset of base image, or -ve error code on error
|
||||||
|
*/
|
||||||
|
int boot_get_fdt_fit(bootm_headers_t *images, ulong addr,
|
||||||
|
const char **fit_unamep, const char **fit_uname_configp,
|
||||||
|
int arch, ulong *datap, ulong *lenp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fit_image_load() - load an image from a FIT
|
* fit_image_load() - load an image from a FIT
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp);
|
||||||
* @count: Number of pairs (e.g. 1 if the regmap has a single entry)
|
* @count: Number of pairs (e.g. 1 if the regmap has a single entry)
|
||||||
* @mapp: Returns allocated map
|
* @mapp: Returns allocated map
|
||||||
*/
|
*/
|
||||||
int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
|
int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
|
||||||
struct regmap **mapp);
|
struct regmap **mapp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
#ifndef __SYSCON_H
|
#ifndef __SYSCON_H
|
||||||
#define __SYSCON_H
|
#define __SYSCON_H
|
||||||
|
|
||||||
|
#include <fdtdec.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct syscon_uc_info - Information stored by the syscon UCLASS_UCLASS
|
* struct syscon_uc_info - Information stored by the syscon UCLASS_UCLASS
|
||||||
*
|
*
|
||||||
|
|
@ -28,9 +30,11 @@ struct syscon_ops {
|
||||||
* We don't support 64-bit machines. If they are so resource-contrained that
|
* We don't support 64-bit machines. If they are so resource-contrained that
|
||||||
* they need to use OF_PLATDATA, something is horribly wrong with the
|
* they need to use OF_PLATDATA, something is horribly wrong with the
|
||||||
* education of our hardware engineers.
|
* education of our hardware engineers.
|
||||||
|
*
|
||||||
|
* Update: 64-bit is now supported and we have an education crisis.
|
||||||
*/
|
*/
|
||||||
struct syscon_base_platdata {
|
struct syscon_base_platdata {
|
||||||
u32 reg[2];
|
fdt_val_t reg[2];
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
|
||||||
* @fdt: Base device tree blob
|
* @fdt: Base device tree blob
|
||||||
* @fdto: Device tree overlay blob
|
* @fdto: Device tree overlay blob
|
||||||
* @fragment: node offset of the fragment in the overlay
|
* @fragment: node offset of the fragment in the overlay
|
||||||
|
* @pathp: pointer which receives the path of the target (or NULL)
|
||||||
*
|
*
|
||||||
* overlay_get_target() retrieves the target offset in the base
|
* overlay_get_target() retrieves the target offset in the base
|
||||||
* device tree of a fragment, no matter how the actual targetting is
|
* device tree of a fragment, no matter how the actual targetting is
|
||||||
|
|
@ -49,23 +50,28 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
|
||||||
* Negative error code on error
|
* Negative error code on error
|
||||||
*/
|
*/
|
||||||
static int overlay_get_target(const void *fdt, const void *fdto,
|
static int overlay_get_target(const void *fdt, const void *fdto,
|
||||||
int fragment)
|
int fragment, char const **pathp)
|
||||||
{
|
{
|
||||||
uint32_t phandle;
|
uint32_t phandle;
|
||||||
const char *path;
|
const char *path = NULL;
|
||||||
int path_len;
|
int path_len = 0, ret;
|
||||||
|
|
||||||
/* Try first to do a phandle based lookup */
|
/* Try first to do a phandle based lookup */
|
||||||
phandle = overlay_get_target_phandle(fdto, fragment);
|
phandle = overlay_get_target_phandle(fdto, fragment);
|
||||||
if (phandle == (uint32_t)-1)
|
if (phandle == (uint32_t)-1)
|
||||||
return -FDT_ERR_BADPHANDLE;
|
return -FDT_ERR_BADPHANDLE;
|
||||||
|
|
||||||
if (phandle)
|
/* no phandle, try path */
|
||||||
return fdt_node_offset_by_phandle(fdt, phandle);
|
if (!phandle) {
|
||||||
|
|
||||||
/* And then a path based lookup */
|
/* And then a path based lookup */
|
||||||
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
|
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
|
||||||
if (!path) {
|
if (path)
|
||||||
|
ret = fdt_path_offset(fdt, path);
|
||||||
|
else
|
||||||
|
ret = path_len;
|
||||||
|
} else
|
||||||
|
ret = fdt_node_offset_by_phandle(fdt, phandle);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we haven't found either a target or a
|
* If we haven't found either a target or a
|
||||||
* target-path property in a node that contains a
|
* target-path property in a node that contains a
|
||||||
|
|
@ -73,13 +79,18 @@ static int overlay_get_target(const void *fdt, const void *fdto,
|
||||||
* otherwise), consider it a improperly written
|
* otherwise), consider it a improperly written
|
||||||
* overlay
|
* overlay
|
||||||
*/
|
*/
|
||||||
if (path_len == -FDT_ERR_NOTFOUND)
|
if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
|
||||||
return -FDT_ERR_BADOVERLAY;
|
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.
|
* overlay_merge() merges an overlay into its base device tree.
|
||||||
*
|
*
|
||||||
* This is the final step in the device tree overlay application
|
* This is the next to last step in the device tree overlay application
|
||||||
* process, when all the phandles have been adjusted and resolved and
|
* process, when all the phandles have been adjusted and resolved and
|
||||||
* you just have to merge overlay into the base device tree.
|
* you just have to merge overlay into the base device tree.
|
||||||
*
|
*
|
||||||
|
|
@ -618,7 +629,7 @@ static int overlay_merge(void *fdt, void *fdto)
|
||||||
if (overlay < 0)
|
if (overlay < 0)
|
||||||
return overlay;
|
return overlay;
|
||||||
|
|
||||||
target = overlay_get_target(fdt, fdto, fragment);
|
target = overlay_get_target(fdt, fdto, fragment, NULL);
|
||||||
if (target < 0)
|
if (target < 0)
|
||||||
return target;
|
return target;
|
||||||
|
|
||||||
|
|
@ -630,6 +641,175 @@ static int overlay_merge(void *fdt, void *fdto)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_path_len(const void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
int len = 0, namelen;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
name = fdt_get_name(fdt, nodeoffset, &namelen);
|
||||||
|
if (!name)
|
||||||
|
return namelen;
|
||||||
|
|
||||||
|
/* root? we're done */
|
||||||
|
if (namelen == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
nodeoffset = fdt_parent_offset(fdt, nodeoffset);
|
||||||
|
if (nodeoffset < 0)
|
||||||
|
return nodeoffset;
|
||||||
|
len += namelen + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* in case of root pretend it's "/" */
|
||||||
|
if (len == 0)
|
||||||
|
len++;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_symbol_update - Update the symbols of base tree after a merge
|
||||||
|
* @fdt: Base Device Tree blob
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
*
|
||||||
|
* overlay_symbol_update() updates the symbols of the base tree with the
|
||||||
|
* symbols of the applied overlay
|
||||||
|
*
|
||||||
|
* This is the last step in the device tree overlay application
|
||||||
|
* process, allowing the reference of overlay symbols by subsequent
|
||||||
|
* overlay operations.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_symbol_update(void *fdt, void *fdto)
|
||||||
|
{
|
||||||
|
int root_sym, ov_sym, prop, path_len, fragment, target;
|
||||||
|
int len, frag_name_len, ret, rel_path_len;
|
||||||
|
const char *s, *e;
|
||||||
|
const char *path;
|
||||||
|
const char *name;
|
||||||
|
const char *frag_name;
|
||||||
|
const char *rel_path;
|
||||||
|
const char *target_path;
|
||||||
|
char *buf;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
|
||||||
|
|
||||||
|
/* if no overlay symbols exist no problem */
|
||||||
|
if (ov_sym < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
|
||||||
|
|
||||||
|
/* it no root symbols exist we should create them */
|
||||||
|
if (root_sym == -FDT_ERR_NOTFOUND)
|
||||||
|
root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
|
||||||
|
|
||||||
|
/* any error is fatal now */
|
||||||
|
if (root_sym < 0)
|
||||||
|
return root_sym;
|
||||||
|
|
||||||
|
/* iterate over each overlay symbol */
|
||||||
|
fdt_for_each_property_offset(prop, fdto, ov_sym) {
|
||||||
|
path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
|
||||||
|
if (!path)
|
||||||
|
return path_len;
|
||||||
|
|
||||||
|
/* verify it's a string property (terminated by a single \0) */
|
||||||
|
if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
|
||||||
|
return -FDT_ERR_BADVALUE;
|
||||||
|
|
||||||
|
/* keep end marker to avoid strlen() */
|
||||||
|
e = path + path_len;
|
||||||
|
|
||||||
|
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
|
||||||
|
|
||||||
|
if (*path != '/')
|
||||||
|
return -FDT_ERR_BADVALUE;
|
||||||
|
|
||||||
|
/* get fragment name first */
|
||||||
|
s = strchr(path + 1, '/');
|
||||||
|
if (!s)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
frag_name = path + 1;
|
||||||
|
frag_name_len = s - path - 1;
|
||||||
|
|
||||||
|
/* verify format; safe since "s" lies in \0 terminated prop */
|
||||||
|
len = sizeof("/__overlay__/") - 1;
|
||||||
|
if ((e - s) < len || memcmp(s, "/__overlay__/", len))
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
rel_path = s + len;
|
||||||
|
rel_path_len = e - rel_path;
|
||||||
|
|
||||||
|
/* find the fragment index in which the symbol lies */
|
||||||
|
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
|
||||||
|
frag_name_len);
|
||||||
|
/* not found? */
|
||||||
|
if (ret < 0)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
fragment = ret;
|
||||||
|
|
||||||
|
/* an __overlay__ subnode must exist */
|
||||||
|
ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
|
||||||
|
if (ret < 0)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
/* get the target of the fragment */
|
||||||
|
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
target = ret;
|
||||||
|
|
||||||
|
/* if we have a target path use */
|
||||||
|
if (!target_path) {
|
||||||
|
ret = get_path_len(fdt, target);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
len = ret;
|
||||||
|
} else {
|
||||||
|
len = strlen(target_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fdt_setprop_placeholder(fdt, root_sym, name,
|
||||||
|
len + (len > 1) + rel_path_len + 1, &p);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!target_path) {
|
||||||
|
/* again in case setprop_placeholder changed it */
|
||||||
|
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
target = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = p;
|
||||||
|
if (len > 1) { /* target is not root */
|
||||||
|
if (!target_path) {
|
||||||
|
ret = fdt_get_path(fdt, target, buf, len + 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
} else
|
||||||
|
memcpy(buf, target_path, len + 1);
|
||||||
|
|
||||||
|
} else
|
||||||
|
len--;
|
||||||
|
|
||||||
|
buf[len] = '/';
|
||||||
|
memcpy(buf + len + 1, rel_path, rel_path_len);
|
||||||
|
buf[len + 1 + rel_path_len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int fdt_overlay_apply(void *fdt, void *fdto)
|
int fdt_overlay_apply(void *fdt, void *fdto)
|
||||||
{
|
{
|
||||||
uint32_t delta = fdt_get_max_phandle(fdt);
|
uint32_t delta = fdt_get_max_phandle(fdt);
|
||||||
|
|
@ -654,6 +834,10 @@ int fdt_overlay_apply(void *fdt, void *fdto)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
ret = overlay_symbol_update(fdt, fdto);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The overlay has been damaged, erase its magic.
|
* The overlay has been damaged, erase its magic.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -228,8 +228,8 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
|
||||||
const void *val, int len)
|
int len, void **prop_data)
|
||||||
{
|
{
|
||||||
struct fdt_property *prop;
|
struct fdt_property *prop;
|
||||||
int err;
|
int err;
|
||||||
|
|
@ -242,8 +242,22 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
*prop_data = prop->data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||||
|
const void *val, int len)
|
||||||
|
{
|
||||||
|
void *prop_data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
if (len)
|
if (len)
|
||||||
memcpy(prop->data, val, len);
|
memcpy(prop_data, val, len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
|
||||||
struct fdt_region region[], int max_regions,
|
struct fdt_region region[], int max_regions,
|
||||||
char *path, int path_len, int add_string_tab)
|
char *path, int path_len, int add_string_tab)
|
||||||
{
|
{
|
||||||
int stack[FDT_MAX_DEPTH];
|
int stack[FDT_MAX_DEPTH] = { 0 };
|
||||||
char *end;
|
char *end;
|
||||||
int nextoffset = 0;
|
int nextoffset = 0;
|
||||||
uint32_t tag;
|
uint32_t tag;
|
||||||
|
|
|
||||||
|
|
@ -1404,6 +1404,37 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name);
|
||||||
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||||
const void *val, int len);
|
const void *val, int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_setprop _placeholder - allocate space for a property
|
||||||
|
* @fdt: pointer to the device tree blob
|
||||||
|
* @nodeoffset: offset of the node whose property to change
|
||||||
|
* @name: name of the property to change
|
||||||
|
* @len: length of the property value
|
||||||
|
* @prop_data: return pointer to property data
|
||||||
|
*
|
||||||
|
* fdt_setprop_placeholer() allocates the named property in the given node.
|
||||||
|
* If the property exists it is resized. In either case a pointer to the
|
||||||
|
* property data is returned.
|
||||||
|
*
|
||||||
|
* This function may insert or delete data from the blob, and will
|
||||||
|
* therefore change the offsets of some existing nodes.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
|
||||||
|
* contain the new property value
|
||||||
|
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||||
|
* -FDT_ERR_BADLAYOUT,
|
||||||
|
* -FDT_ERR_BADMAGIC,
|
||||||
|
* -FDT_ERR_BADVERSION,
|
||||||
|
* -FDT_ERR_BADSTATE,
|
||||||
|
* -FDT_ERR_BADSTRUCTURE,
|
||||||
|
* -FDT_ERR_BADLAYOUT,
|
||||||
|
* -FDT_ERR_TRUNCATED, standard meanings
|
||||||
|
*/
|
||||||
|
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
|
||||||
|
int len, void **prop_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_setprop_u32 - set a property to a 32-bit integer
|
* fdt_setprop_u32 - set a property to a 32-bit integer
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,23 @@ class Fdt:
|
||||||
self._fdt = bytearray(data)
|
self._fdt = bytearray(data)
|
||||||
check_err(fdt_check_header(self._fdt));
|
check_err(fdt_check_header(self._fdt));
|
||||||
|
|
||||||
|
def subnode_offset(self, parentoffset, name, quiet=()):
|
||||||
|
"""Get the offset of a named subnode
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parentoffset: Offset of the parent node to check
|
||||||
|
name: Name of the required subnode, e.g. 'subnode@1'
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The node offset of the found node, if any
|
||||||
|
|
||||||
|
Raises
|
||||||
|
FdtException if there is no node with that name, or other error
|
||||||
|
"""
|
||||||
|
return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
|
||||||
|
quiet)
|
||||||
|
|
||||||
def path_offset(self, path, quiet=()):
|
def path_offset(self, path, quiet=()):
|
||||||
"""Get the offset for a given path
|
"""Get the offset for a given path
|
||||||
|
|
||||||
|
|
@ -304,6 +321,47 @@ class Fdt:
|
||||||
return pdata
|
return pdata
|
||||||
return bytearray(pdata[0])
|
return bytearray(pdata[0])
|
||||||
|
|
||||||
|
def get_phandle(self, nodeoffset):
|
||||||
|
"""Get the phandle of a node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Node offset to check
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
phandle of node, or 0 if the node has no phandle or another error
|
||||||
|
occurs
|
||||||
|
"""
|
||||||
|
return fdt_get_phandle(self._fdt, nodeoffset)
|
||||||
|
|
||||||
|
def parent_offset(self, nodeoffset, quiet=()):
|
||||||
|
"""Get the offset of a node's parent
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Node offset to check
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The offset of the parent node, if any
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if no parent found or other error occurs
|
||||||
|
"""
|
||||||
|
return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
|
||||||
|
|
||||||
|
def node_offset_by_phandle(self, phandle, quiet=()):
|
||||||
|
"""Get the offset of a node with the given phandle
|
||||||
|
|
||||||
|
Args:
|
||||||
|
phandle: Phandle to search for
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The offset of node with that phandle, if any
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if no node found or other error occurs
|
||||||
|
"""
|
||||||
|
return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
|
||||||
|
|
||||||
class Property:
|
class Property:
|
||||||
"""Holds a device tree property name and value.
|
"""Holds a device tree property name and value.
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,23 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
|
||||||
|
|
||||||
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
|
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
|
||||||
|
|
||||||
|
# DTCO
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
quiet_cmd_dtco = DTCO $@
|
||||||
|
# Rule for objects only; does not put specific u-boot include at the end
|
||||||
|
# No generation of assembly file either
|
||||||
|
# Modified for U-Boot
|
||||||
|
cmd_dtco = mkdir -p $(dir ${dtc-tmp}) ; \
|
||||||
|
$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ; \
|
||||||
|
$(DTC) -@ -O dtb -o $@ -b 0 \
|
||||||
|
-i $(dir $<) $(DTC_FLAGS) \
|
||||||
|
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
|
||||||
|
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
|
||||||
|
|
||||||
|
$(obj)/%.dtbo: $(src)/%.dts FORCE
|
||||||
|
$(call if_changed_dep,dtco)
|
||||||
|
|
||||||
# Fonts
|
# Fonts
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -257,14 +257,15 @@ cmd_dtoch = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o
|
||||||
quiet_cmd_plat = PLAT $@
|
quiet_cmd_plat = PLAT $@
|
||||||
cmd_plat = $(CC) $(c_flags) -c $< -o $@
|
cmd_plat = $(CC) $(c_flags) -c $< -o $@
|
||||||
|
|
||||||
$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c include/generated/dt-structs.h
|
$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c \
|
||||||
|
include/generated/dt-structs-gen.h
|
||||||
$(call if_changed,plat)
|
$(call if_changed,plat)
|
||||||
|
|
||||||
PHONY += dts_dir
|
PHONY += dts_dir
|
||||||
dts_dir:
|
dts_dir:
|
||||||
$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
|
$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
|
||||||
|
|
||||||
include/generated/dt-structs.h: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
|
include/generated/dt-structs-gen.h: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
|
||||||
$(call if_changed,dtoch)
|
$(call if_changed,dtoch)
|
||||||
|
|
||||||
$(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
|
$(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,4 @@ DTC_FLAGS += -@
|
||||||
# DT overlays
|
# DT overlays
|
||||||
obj-y += test-fdt-base.dtb.o
|
obj-y += test-fdt-base.dtb.o
|
||||||
obj-y += test-fdt-overlay.dtb.o
|
obj-y += test-fdt-overlay.dtb.o
|
||||||
|
obj-y += test-fdt-overlay-stacked.dtb.o
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,9 @@
|
||||||
|
|
||||||
extern u32 __dtb_test_fdt_base_begin;
|
extern u32 __dtb_test_fdt_base_begin;
|
||||||
extern u32 __dtb_test_fdt_overlay_begin;
|
extern u32 __dtb_test_fdt_overlay_begin;
|
||||||
|
extern u32 __dtb_test_fdt_overlay_stacked_begin;
|
||||||
|
|
||||||
static int fdt_getprop_u32_by_index(void *fdt, const char *path,
|
static int ut_fdt_getprop_u32_by_index(void *fdt, const char *path,
|
||||||
const char *name, int index,
|
const char *name, int index,
|
||||||
u32 *out)
|
u32 *out)
|
||||||
{
|
{
|
||||||
|
|
@ -42,10 +43,10 @@ static int fdt_getprop_u32_by_index(void *fdt, const char *path,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fdt_getprop_u32(void *fdt, const char *path, const char *name,
|
static int ut_fdt_getprop_u32(void *fdt, const char *path, const char *name,
|
||||||
u32 *out)
|
u32 *out)
|
||||||
{
|
{
|
||||||
return fdt_getprop_u32_by_index(fdt, path, name, 0, out);
|
return ut_fdt_getprop_u32_by_index(fdt, path, name, 0, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fdt_getprop_str(void *fdt, const char *path, const char *name,
|
static int fdt_getprop_str(void *fdt, const char *path, const char *name,
|
||||||
|
|
@ -68,7 +69,7 @@ static int fdt_overlay_change_int_property(struct unit_test_state *uts)
|
||||||
void *fdt = uts->priv;
|
void *fdt = uts->priv;
|
||||||
u32 val = 0;
|
u32 val = 0;
|
||||||
|
|
||||||
ut_assertok(fdt_getprop_u32(fdt, "/test-node", "test-int-property",
|
ut_assertok(ut_fdt_getprop_u32(fdt, "/test-node", "test-int-property",
|
||||||
&val));
|
&val));
|
||||||
ut_asserteq(43, val);
|
ut_asserteq(43, val);
|
||||||
|
|
||||||
|
|
@ -158,11 +159,11 @@ static int fdt_overlay_local_phandle(struct unit_test_state *uts)
|
||||||
local_phandle = fdt_get_phandle(fdt, off);
|
local_phandle = fdt_get_phandle(fdt, off);
|
||||||
ut_assert(local_phandle);
|
ut_assert(local_phandle);
|
||||||
|
|
||||||
ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
|
ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
|
||||||
0, &val));
|
0, &val));
|
||||||
ut_asserteq(local_phandle, val);
|
ut_asserteq(local_phandle, val);
|
||||||
|
|
||||||
ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
|
ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
|
||||||
1, &val));
|
1, &val));
|
||||||
ut_asserteq(local_phandle, val);
|
ut_asserteq(local_phandle, val);
|
||||||
|
|
||||||
|
|
@ -189,11 +190,11 @@ static int fdt_overlay_local_phandles(struct unit_test_state *uts)
|
||||||
test_phandle = fdt_get_phandle(fdt, off);
|
test_phandle = fdt_get_phandle(fdt, off);
|
||||||
ut_assert(test_phandle);
|
ut_assert(test_phandle);
|
||||||
|
|
||||||
ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0,
|
ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0,
|
||||||
&val));
|
&val));
|
||||||
ut_asserteq(test_phandle, val);
|
ut_asserteq(test_phandle, val);
|
||||||
|
|
||||||
ut_assertok(fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1,
|
ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1,
|
||||||
&val));
|
&val));
|
||||||
ut_asserteq(local_phandle, val);
|
ut_asserteq(local_phandle, val);
|
||||||
|
|
||||||
|
|
@ -201,6 +202,19 @@ static int fdt_overlay_local_phandles(struct unit_test_state *uts)
|
||||||
}
|
}
|
||||||
OVERLAY_TEST(fdt_overlay_local_phandles, 0);
|
OVERLAY_TEST(fdt_overlay_local_phandles, 0);
|
||||||
|
|
||||||
|
static int fdt_overlay_stacked(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
void *fdt = uts->priv;
|
||||||
|
u32 val = 0;
|
||||||
|
|
||||||
|
ut_assertok(ut_fdt_getprop_u32(fdt, "/new-local-node",
|
||||||
|
"stacked-test-int-property", &val));
|
||||||
|
ut_asserteq(43, val);
|
||||||
|
|
||||||
|
return CMD_RET_SUCCESS;
|
||||||
|
}
|
||||||
|
OVERLAY_TEST(fdt_overlay_stacked, 0);
|
||||||
|
|
||||||
int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = ll_entry_start(struct unit_test,
|
struct unit_test *tests = ll_entry_start(struct unit_test,
|
||||||
|
|
@ -210,7 +224,8 @@ int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
struct unit_test *test;
|
struct unit_test *test;
|
||||||
void *fdt_base = &__dtb_test_fdt_base_begin;
|
void *fdt_base = &__dtb_test_fdt_base_begin;
|
||||||
void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
|
void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
|
||||||
void *fdt_base_copy, *fdt_overlay_copy;
|
void *fdt_overlay_stacked = &__dtb_test_fdt_overlay_stacked_begin;
|
||||||
|
void *fdt_base_copy, *fdt_overlay_copy, *fdt_overlay_stacked_copy;
|
||||||
|
|
||||||
uts = calloc(1, sizeof(*uts));
|
uts = calloc(1, sizeof(*uts));
|
||||||
if (!uts)
|
if (!uts)
|
||||||
|
|
@ -228,6 +243,10 @@ int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
if (!fdt_overlay_copy)
|
if (!fdt_overlay_copy)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE);
|
||||||
|
if (!fdt_overlay_stacked_copy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resize the FDT to 4k so that we have room to operate on
|
* Resize the FDT to 4k so that we have room to operate on
|
||||||
*
|
*
|
||||||
|
|
@ -245,9 +264,21 @@ int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy,
|
ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy,
|
||||||
FDT_COPY_SIZE));
|
FDT_COPY_SIZE));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resize the stacked overlay to 4k so that we have room to operate on
|
||||||
|
*
|
||||||
|
* (and relocate it since the memory might be mapped
|
||||||
|
* read-only)
|
||||||
|
*/
|
||||||
|
ut_assertok(fdt_open_into(fdt_overlay_stacked, fdt_overlay_stacked_copy,
|
||||||
|
FDT_COPY_SIZE));
|
||||||
|
|
||||||
/* Apply the overlay */
|
/* Apply the overlay */
|
||||||
ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_copy));
|
ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_copy));
|
||||||
|
|
||||||
|
/* Apply the stacked overlay */
|
||||||
|
ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_stacked_copy));
|
||||||
|
|
||||||
if (argc == 1)
|
if (argc == 1)
|
||||||
printf("Running %d environment tests\n", n_ents);
|
printf("Running %d environment tests\n", n_ents);
|
||||||
|
|
||||||
|
|
@ -263,6 +294,7 @@ int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
|
|
||||||
printf("Failures: %d\n", uts->fail_count);
|
printf("Failures: %d\n", uts->fail_count);
|
||||||
|
|
||||||
|
free(fdt_overlay_stacked_copy);
|
||||||
free(fdt_overlay_copy);
|
free(fdt_overlay_copy);
|
||||||
free(fdt_base_copy);
|
free(fdt_base_copy);
|
||||||
free(uts);
|
free(uts);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
static data.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import collections
|
||||||
import copy
|
import copy
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
@ -38,11 +39,20 @@ TYPE_NAMES = {
|
||||||
fdt.TYPE_BYTE: 'unsigned char',
|
fdt.TYPE_BYTE: 'unsigned char',
|
||||||
fdt.TYPE_STRING: 'const char *',
|
fdt.TYPE_STRING: 'const char *',
|
||||||
fdt.TYPE_BOOL: 'bool',
|
fdt.TYPE_BOOL: 'bool',
|
||||||
|
fdt.TYPE_INT64: 'fdt64_t',
|
||||||
}
|
}
|
||||||
|
|
||||||
STRUCT_PREFIX = 'dtd_'
|
STRUCT_PREFIX = 'dtd_'
|
||||||
VAL_PREFIX = 'dtv_'
|
VAL_PREFIX = 'dtv_'
|
||||||
|
|
||||||
|
# This holds information about a property which includes phandles.
|
||||||
|
#
|
||||||
|
# max_args: integer: Maximum number or arguments that any phandle uses (int).
|
||||||
|
# args: Number of args for each phandle in the property. The total number of
|
||||||
|
# phandles is len(args). This is a list of integers.
|
||||||
|
PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
|
||||||
|
|
||||||
|
|
||||||
def conv_name_to_c(name):
|
def conv_name_to_c(name):
|
||||||
"""Convert a device-tree name to a C identifier
|
"""Convert a device-tree name to a C identifier
|
||||||
|
|
||||||
|
|
@ -95,6 +105,8 @@ def get_value(ftype, value):
|
||||||
return '"%s"' % value
|
return '"%s"' % value
|
||||||
elif ftype == fdt.TYPE_BOOL:
|
elif ftype == fdt.TYPE_BOOL:
|
||||||
return 'true'
|
return 'true'
|
||||||
|
elif ftype == fdt.TYPE_INT64:
|
||||||
|
return '%#x' % value
|
||||||
|
|
||||||
def get_compat_name(node):
|
def get_compat_name(node):
|
||||||
"""Get a node's first compatible string as a C identifier
|
"""Get a node's first compatible string as a C identifier
|
||||||
|
|
@ -113,21 +125,6 @@ def get_compat_name(node):
|
||||||
compat, aliases = compat[0], compat[1:]
|
compat, aliases = compat[0], compat[1:]
|
||||||
return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases]
|
return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases]
|
||||||
|
|
||||||
def is_phandle(prop):
|
|
||||||
"""Check if a node contains phandles
|
|
||||||
|
|
||||||
We have no reliable way of detecting whether a node uses a phandle
|
|
||||||
or not. As an interim measure, use a list of known property names.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
prop: Prop object to check
|
|
||||||
Return:
|
|
||||||
True if the object value contains phandles, else False
|
|
||||||
"""
|
|
||||||
if prop.name in ['clocks']:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class DtbPlatdata(object):
|
class DtbPlatdata(object):
|
||||||
"""Provide a means to convert device tree binary data to platform data
|
"""Provide a means to convert device tree binary data to platform data
|
||||||
|
|
@ -141,17 +138,14 @@ class DtbPlatdata(object):
|
||||||
_dtb_fname: Filename of the input device tree binary file
|
_dtb_fname: Filename of the input device tree binary file
|
||||||
_valid_nodes: A list of Node object with compatible strings
|
_valid_nodes: A list of Node object with compatible strings
|
||||||
_include_disabled: true to include nodes marked status = "disabled"
|
_include_disabled: true to include nodes marked status = "disabled"
|
||||||
_phandle_nodes: A dict of nodes indexed by phandle number (1, 2...)
|
|
||||||
_outfile: The current output file (sys.stdout or a real file)
|
_outfile: The current output file (sys.stdout or a real file)
|
||||||
_lines: Stashed list of output lines for outputting in the future
|
_lines: Stashed list of output lines for outputting in the future
|
||||||
_phandle_nodes: A dict of Nodes indexed by phandle (an integer)
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, dtb_fname, include_disabled):
|
def __init__(self, dtb_fname, include_disabled):
|
||||||
self._fdt = None
|
self._fdt = None
|
||||||
self._dtb_fname = dtb_fname
|
self._dtb_fname = dtb_fname
|
||||||
self._valid_nodes = None
|
self._valid_nodes = None
|
||||||
self._include_disabled = include_disabled
|
self._include_disabled = include_disabled
|
||||||
self._phandle_nodes = {}
|
|
||||||
self._outfile = None
|
self._outfile = None
|
||||||
self._lines = []
|
self._lines = []
|
||||||
self._aliases = {}
|
self._aliases = {}
|
||||||
|
|
@ -196,6 +190,53 @@ class DtbPlatdata(object):
|
||||||
self._lines = []
|
self._lines = []
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
def out_header(self):
|
||||||
|
"""Output a message indicating that this is an auto-generated file"""
|
||||||
|
self.out('''/*
|
||||||
|
* DO NOT MODIFY
|
||||||
|
*
|
||||||
|
* This file was generated by dtoc from a .dtb (device tree binary) file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
''')
|
||||||
|
|
||||||
|
def get_phandle_argc(self, prop, node_name):
|
||||||
|
"""Check if a node contains phandles
|
||||||
|
|
||||||
|
We have no reliable way of detecting whether a node uses a phandle
|
||||||
|
or not. As an interim measure, use a list of known property names.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop: Prop object to check
|
||||||
|
Return:
|
||||||
|
Number of argument cells is this is a phandle, else None
|
||||||
|
"""
|
||||||
|
if prop.name in ['clocks']:
|
||||||
|
val = prop.value
|
||||||
|
if not isinstance(val, list):
|
||||||
|
val = [val]
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
max_args = 0
|
||||||
|
args = []
|
||||||
|
while i < len(val):
|
||||||
|
phandle = fdt_util.fdt32_to_cpu(val[i])
|
||||||
|
target = self._fdt.phandle_to_node.get(phandle)
|
||||||
|
if not target:
|
||||||
|
raise ValueError("Cannot parse '%s' in node '%s'" %
|
||||||
|
(prop.name, node_name))
|
||||||
|
prop_name = '#clock-cells'
|
||||||
|
cells = target.props.get(prop_name)
|
||||||
|
if not cells:
|
||||||
|
raise ValueError("Node '%s' has no '%s' property" %
|
||||||
|
(target.name, prop_name))
|
||||||
|
num_args = fdt_util.fdt32_to_cpu(cells.value)
|
||||||
|
max_args = max(max_args, num_args)
|
||||||
|
args.append(num_args)
|
||||||
|
i += 1 + num_args
|
||||||
|
return PhandleInfo(max_args, args)
|
||||||
|
return None
|
||||||
|
|
||||||
def scan_dtb(self):
|
def scan_dtb(self):
|
||||||
"""Scan the device tree to obtain a tree of nodes and properties
|
"""Scan the device tree to obtain a tree of nodes and properties
|
||||||
|
|
||||||
|
|
@ -207,8 +248,7 @@ class DtbPlatdata(object):
|
||||||
def scan_node(self, root):
|
def scan_node(self, root):
|
||||||
"""Scan a node and subnodes to build a tree of node and phandle info
|
"""Scan a node and subnodes to build a tree of node and phandle info
|
||||||
|
|
||||||
This adds each node to self._valid_nodes and each phandle to
|
This adds each node to self._valid_nodes.
|
||||||
self._phandle_nodes.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
root: Root node for scan
|
root: Root node for scan
|
||||||
|
|
@ -219,10 +259,6 @@ class DtbPlatdata(object):
|
||||||
if (not self._include_disabled and not status or
|
if (not self._include_disabled and not status or
|
||||||
status.value != 'disabled'):
|
status.value != 'disabled'):
|
||||||
self._valid_nodes.append(node)
|
self._valid_nodes.append(node)
|
||||||
phandle_prop = node.props.get('phandle')
|
|
||||||
if phandle_prop:
|
|
||||||
phandle = phandle_prop.GetPhandle()
|
|
||||||
self._phandle_nodes[phandle] = node
|
|
||||||
|
|
||||||
# recurse to handle any subnodes
|
# recurse to handle any subnodes
|
||||||
self.scan_node(node)
|
self.scan_node(node)
|
||||||
|
|
@ -231,14 +267,72 @@ class DtbPlatdata(object):
|
||||||
"""Scan the device tree for useful information
|
"""Scan the device tree for useful information
|
||||||
|
|
||||||
This fills in the following properties:
|
This fills in the following properties:
|
||||||
_phandle_nodes: A dict of Nodes indexed by phandle (an integer)
|
|
||||||
_valid_nodes: A list of nodes we wish to consider include in the
|
_valid_nodes: A list of nodes we wish to consider include in the
|
||||||
platform data
|
platform data
|
||||||
"""
|
"""
|
||||||
self._phandle_nodes = {}
|
|
||||||
self._valid_nodes = []
|
self._valid_nodes = []
|
||||||
return self.scan_node(self._fdt.GetRoot())
|
return self.scan_node(self._fdt.GetRoot())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_num_cells(node):
|
||||||
|
"""Get the number of cells in addresses and sizes for this node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
node: Node to check
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple:
|
||||||
|
Number of address cells for this node
|
||||||
|
Number of size cells for this node
|
||||||
|
"""
|
||||||
|
parent = node.parent
|
||||||
|
na, ns = 2, 2
|
||||||
|
if parent:
|
||||||
|
na_prop = parent.props.get('#address-cells')
|
||||||
|
ns_prop = parent.props.get('#size-cells')
|
||||||
|
if na_prop:
|
||||||
|
na = fdt_util.fdt32_to_cpu(na_prop.value)
|
||||||
|
if ns_prop:
|
||||||
|
ns = fdt_util.fdt32_to_cpu(ns_prop.value)
|
||||||
|
return na, ns
|
||||||
|
|
||||||
|
def scan_reg_sizes(self):
|
||||||
|
"""Scan for 64-bit 'reg' properties and update the values
|
||||||
|
|
||||||
|
This finds 'reg' properties with 64-bit data and converts the value to
|
||||||
|
an array of 64-values. This allows it to be output in a way that the
|
||||||
|
C code can read.
|
||||||
|
"""
|
||||||
|
for node in self._valid_nodes:
|
||||||
|
reg = node.props.get('reg')
|
||||||
|
if not reg:
|
||||||
|
continue
|
||||||
|
na, ns = self.get_num_cells(node)
|
||||||
|
total = na + ns
|
||||||
|
|
||||||
|
if reg.type != fdt.TYPE_INT:
|
||||||
|
raise ValueError("Node '%s' reg property is not an int")
|
||||||
|
if len(reg.value) % total:
|
||||||
|
raise ValueError("Node '%s' reg property has %d cells "
|
||||||
|
'which is not a multiple of na + ns = %d + %d)' %
|
||||||
|
(node.name, len(reg.value), na, ns))
|
||||||
|
reg.na = na
|
||||||
|
reg.ns = ns
|
||||||
|
if na != 1 or ns != 1:
|
||||||
|
reg.type = fdt.TYPE_INT64
|
||||||
|
i = 0
|
||||||
|
new_value = []
|
||||||
|
val = reg.value
|
||||||
|
if not isinstance(val, list):
|
||||||
|
val = [val]
|
||||||
|
while i < len(val):
|
||||||
|
addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
|
||||||
|
i += na
|
||||||
|
size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
|
||||||
|
i += ns
|
||||||
|
new_value += [addr, size]
|
||||||
|
reg.value = new_value
|
||||||
|
|
||||||
def scan_structs(self):
|
def scan_structs(self):
|
||||||
"""Scan the device tree building up the C structures we will use.
|
"""Scan the device tree building up the C structures we will use.
|
||||||
|
|
||||||
|
|
@ -305,14 +399,18 @@ class DtbPlatdata(object):
|
||||||
for pname, prop in node.props.items():
|
for pname, prop in node.props.items():
|
||||||
if pname in PROP_IGNORE_LIST or pname[0] == '#':
|
if pname in PROP_IGNORE_LIST or pname[0] == '#':
|
||||||
continue
|
continue
|
||||||
if isinstance(prop.value, list):
|
info = self.get_phandle_argc(prop, node.name)
|
||||||
if is_phandle(prop):
|
if info:
|
||||||
|
if not isinstance(prop.value, list):
|
||||||
|
prop.value = [prop.value]
|
||||||
# Process the list as pairs of (phandle, id)
|
# Process the list as pairs of (phandle, id)
|
||||||
value_it = iter(prop.value)
|
pos = 0
|
||||||
for phandle_cell, _ in zip(value_it, value_it):
|
for args in info.args:
|
||||||
|
phandle_cell = prop.value[pos]
|
||||||
phandle = fdt_util.fdt32_to_cpu(phandle_cell)
|
phandle = fdt_util.fdt32_to_cpu(phandle_cell)
|
||||||
target_node = self._phandle_nodes[phandle]
|
target_node = self._fdt.phandle_to_node[phandle]
|
||||||
node.phandles.add(target_node)
|
node.phandles.add(target_node)
|
||||||
|
pos += 1 + args
|
||||||
|
|
||||||
|
|
||||||
def generate_structs(self, structs):
|
def generate_structs(self, structs):
|
||||||
|
|
@ -322,6 +420,7 @@ class DtbPlatdata(object):
|
||||||
definitions for node in self._valid_nodes. See the documentation in
|
definitions for node in self._valid_nodes. See the documentation in
|
||||||
README.of-plat for more information.
|
README.of-plat for more information.
|
||||||
"""
|
"""
|
||||||
|
self.out_header()
|
||||||
self.out('#include <stdbool.h>\n')
|
self.out('#include <stdbool.h>\n')
|
||||||
self.out('#include <libfdt.h>\n')
|
self.out('#include <libfdt.h>\n')
|
||||||
|
|
||||||
|
|
@ -330,11 +429,13 @@ class DtbPlatdata(object):
|
||||||
self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
|
self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
|
||||||
for pname in sorted(structs[name]):
|
for pname in sorted(structs[name]):
|
||||||
prop = structs[name][pname]
|
prop = structs[name][pname]
|
||||||
if is_phandle(prop):
|
info = self.get_phandle_argc(prop, structs[name])
|
||||||
|
if info:
|
||||||
# For phandles, include a reference to the target
|
# For phandles, include a reference to the target
|
||||||
self.out('\t%s%s[%d]' % (tab_to(2, 'struct phandle_2_cell'),
|
struct_name = 'struct phandle_%d_arg' % info.max_args
|
||||||
|
self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
|
||||||
conv_name_to_c(prop.name),
|
conv_name_to_c(prop.name),
|
||||||
len(prop.value) / 2))
|
len(info.args)))
|
||||||
else:
|
else:
|
||||||
ptype = TYPE_NAMES[prop.type]
|
ptype = TYPE_NAMES[prop.type]
|
||||||
self.out('\t%s%s' % (tab_to(2, ptype),
|
self.out('\t%s%s' % (tab_to(2, ptype),
|
||||||
|
|
@ -370,19 +471,32 @@ class DtbPlatdata(object):
|
||||||
vals = []
|
vals = []
|
||||||
# For phandles, output a reference to the platform data
|
# For phandles, output a reference to the platform data
|
||||||
# of the target node.
|
# of the target node.
|
||||||
if is_phandle(prop):
|
info = self.get_phandle_argc(prop, node.name)
|
||||||
|
if info:
|
||||||
# Process the list as pairs of (phandle, id)
|
# Process the list as pairs of (phandle, id)
|
||||||
value_it = iter(prop.value)
|
pos = 0
|
||||||
for phandle_cell, id_cell in zip(value_it, value_it):
|
for args in info.args:
|
||||||
|
phandle_cell = prop.value[pos]
|
||||||
phandle = fdt_util.fdt32_to_cpu(phandle_cell)
|
phandle = fdt_util.fdt32_to_cpu(phandle_cell)
|
||||||
id_num = fdt_util.fdt32_to_cpu(id_cell)
|
target_node = self._fdt.phandle_to_node[phandle]
|
||||||
target_node = self._phandle_nodes[phandle]
|
|
||||||
name = conv_name_to_c(target_node.name)
|
name = conv_name_to_c(target_node.name)
|
||||||
vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num))
|
arg_values = []
|
||||||
|
for i in range(args):
|
||||||
|
arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
|
||||||
|
pos += 1 + args
|
||||||
|
vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name,
|
||||||
|
', '.join(arg_values)))
|
||||||
|
for val in vals:
|
||||||
|
self.buf('\n\t\t%s,' % val)
|
||||||
else:
|
else:
|
||||||
for val in prop.value:
|
for val in prop.value:
|
||||||
vals.append(get_value(prop.type, val))
|
vals.append(get_value(prop.type, val))
|
||||||
self.buf(', '.join(vals))
|
|
||||||
|
# Put 8 values per line to avoid very long lines.
|
||||||
|
for i in xrange(0, len(vals), 8):
|
||||||
|
if i:
|
||||||
|
self.buf(',\n\t\t')
|
||||||
|
self.buf(', '.join(vals[i:i + 8]))
|
||||||
self.buf('}')
|
self.buf('}')
|
||||||
else:
|
else:
|
||||||
self.buf(get_value(prop.type, prop.value))
|
self.buf(get_value(prop.type, prop.value))
|
||||||
|
|
@ -409,6 +523,7 @@ class DtbPlatdata(object):
|
||||||
See the documentation in doc/driver-model/of-plat.txt for more
|
See the documentation in doc/driver-model/of-plat.txt for more
|
||||||
information.
|
information.
|
||||||
"""
|
"""
|
||||||
|
self.out_header()
|
||||||
self.out('#include <common.h>\n')
|
self.out('#include <common.h>\n')
|
||||||
self.out('#include <dm.h>\n')
|
self.out('#include <dm.h>\n')
|
||||||
self.out('#include <dt-structs.h>\n')
|
self.out('#include <dt-structs.h>\n')
|
||||||
|
|
@ -442,6 +557,7 @@ def run_steps(args, dtb_file, include_disabled, output):
|
||||||
plat = DtbPlatdata(dtb_file, include_disabled)
|
plat = DtbPlatdata(dtb_file, include_disabled)
|
||||||
plat.scan_dtb()
|
plat.scan_dtb()
|
||||||
plat.scan_tree()
|
plat.scan_tree()
|
||||||
|
plat.scan_reg_sizes()
|
||||||
plat.setup_output(output)
|
plat.setup_output(output)
|
||||||
structs = plat.scan_structs()
|
structs = plat.scan_structs()
|
||||||
plat.scan_phandles()
|
plat.scan_phandles()
|
||||||
|
|
|
||||||
|
|
@ -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>;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
@ -10,14 +10,28 @@
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
phandle: phandle-target {
|
phandle: phandle-target {
|
||||||
|
u-boot,dm-pre-reloc;
|
||||||
|
compatible = "target";
|
||||||
|
intval = <0>;
|
||||||
|
#clock-cells = <0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
phandle_1: phandle2-target {
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-reloc;
|
||||||
compatible = "target";
|
compatible = "target";
|
||||||
intval = <1>;
|
intval = <1>;
|
||||||
|
#clock-cells = <1>;
|
||||||
|
};
|
||||||
|
phandle_2: phandle3-target {
|
||||||
|
u-boot,dm-pre-reloc;
|
||||||
|
compatible = "target";
|
||||||
|
intval = <2>;
|
||||||
|
#clock-cells = <2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
phandle-source {
|
phandle-source {
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-reloc;
|
||||||
compatible = "source";
|
compatible = "source";
|
||||||
clocks = <&phandle 1>;
|
clocks = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
spl-test {
|
spl-test {
|
||||||
u-boot,dm-pre-reloc;
|
u-boot,dm-pre-reloc;
|
||||||
compatible = "sandbox,spl-test";
|
compatible = "sandbox,spl-test";
|
||||||
|
|
@ -45,4 +47,16 @@
|
||||||
compatible = "sandbox,spl-test.2";
|
compatible = "sandbox,spl-test.2";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
i2c@0 {
|
||||||
|
compatible = "sandbox,i2c-test";
|
||||||
|
u-boot,dm-pre-reloc;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
pmic@9 {
|
||||||
|
compatible = "sandbox,pmic-test";
|
||||||
|
u-boot,dm-pre-reloc;
|
||||||
|
reg = <9>;
|
||||||
|
low-power;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import libfdt
|
||||||
# so it is fairly efficient.
|
# so it is fairly efficient.
|
||||||
|
|
||||||
# A list of types we support
|
# A list of types we support
|
||||||
(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
|
(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, TYPE_INT64) = range(5)
|
||||||
|
|
||||||
def CheckErr(errnum, msg):
|
def CheckErr(errnum, msg):
|
||||||
if errnum:
|
if errnum:
|
||||||
|
|
@ -174,8 +174,9 @@ class Node:
|
||||||
props: A dict of properties for this node, each a Prop object.
|
props: A dict of properties for this node, each a Prop object.
|
||||||
Keyed by property name
|
Keyed by property name
|
||||||
"""
|
"""
|
||||||
def __init__(self, fdt, offset, name, path):
|
def __init__(self, fdt, parent, offset, name, path):
|
||||||
self._fdt = fdt
|
self._fdt = fdt
|
||||||
|
self.parent = parent
|
||||||
self._offset = offset
|
self._offset = offset
|
||||||
self.name = name
|
self.name = name
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
@ -211,13 +212,17 @@ class Node:
|
||||||
searching into subnodes so that the entire tree is built.
|
searching into subnodes so that the entire tree is built.
|
||||||
"""
|
"""
|
||||||
self.props = self._fdt.GetProps(self)
|
self.props = self._fdt.GetProps(self)
|
||||||
|
phandle = self.props.get('phandle')
|
||||||
|
if phandle:
|
||||||
|
val = fdt_util.fdt32_to_cpu(phandle.value)
|
||||||
|
self._fdt.phandle_to_node[val] = self
|
||||||
|
|
||||||
offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
|
offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
|
||||||
while offset >= 0:
|
while offset >= 0:
|
||||||
sep = '' if self.path[-1] == '/' else '/'
|
sep = '' if self.path[-1] == '/' else '/'
|
||||||
name = self._fdt._fdt_obj.get_name(offset)
|
name = self._fdt._fdt_obj.get_name(offset)
|
||||||
path = self.path + sep + name
|
path = self.path + sep + name
|
||||||
node = Node(self._fdt, offset, name, path)
|
node = Node(self._fdt, self, offset, name, path)
|
||||||
self.subnodes.append(node)
|
self.subnodes.append(node)
|
||||||
|
|
||||||
node.Scan()
|
node.Scan()
|
||||||
|
|
@ -262,6 +267,7 @@ class Fdt:
|
||||||
def __init__(self, fname):
|
def __init__(self, fname):
|
||||||
self._fname = fname
|
self._fname = fname
|
||||||
self._cached_offsets = False
|
self._cached_offsets = False
|
||||||
|
self.phandle_to_node = {}
|
||||||
if self._fname:
|
if self._fname:
|
||||||
self._fname = fdt_util.EnsureCompiled(self._fname)
|
self._fname = fdt_util.EnsureCompiled(self._fname)
|
||||||
|
|
||||||
|
|
@ -279,7 +285,7 @@ class Fdt:
|
||||||
|
|
||||||
TODO(sjg@chromium.org): Implement the 'root' parameter
|
TODO(sjg@chromium.org): Implement the 'root' parameter
|
||||||
"""
|
"""
|
||||||
self._root = self.Node(self, 0, '/', '/')
|
self._root = self.Node(self, None, 0, '/', '/')
|
||||||
self._root.Scan()
|
self._root.Scan()
|
||||||
|
|
||||||
def GetRoot(self):
|
def GetRoot(self):
|
||||||
|
|
@ -386,7 +392,7 @@ class Fdt:
|
||||||
return libfdt.fdt_off_dt_struct(self._fdt) + offset
|
return libfdt.fdt_off_dt_struct(self._fdt) + offset
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def Node(self, fdt, offset, name, path):
|
def Node(self, fdt, parent, offset, name, path):
|
||||||
"""Create a new node
|
"""Create a new node
|
||||||
|
|
||||||
This is used by Fdt.Scan() to create a new node using the correct
|
This is used by Fdt.Scan() to create a new node using the correct
|
||||||
|
|
@ -394,11 +400,12 @@ class Fdt:
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fdt: Fdt object
|
fdt: Fdt object
|
||||||
|
parent: Parent node, or None if this is the root node
|
||||||
offset: Offset of node
|
offset: Offset of node
|
||||||
name: Node name
|
name: Node name
|
||||||
path: Full path to node
|
path: Full path to node
|
||||||
"""
|
"""
|
||||||
node = Node(fdt, offset, name, path)
|
node = Node(fdt, parent, offset, name, path)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def FdtScan(fname):
|
def FdtScan(fname):
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,22 @@ def fdt32_to_cpu(val):
|
||||||
val = val.encode('raw_unicode_escape')
|
val = val.encode('raw_unicode_escape')
|
||||||
return struct.unpack('>I', val)[0]
|
return struct.unpack('>I', val)[0]
|
||||||
|
|
||||||
|
def fdt_cells_to_cpu(val, cells):
|
||||||
|
"""Convert one or two cells to a long integer
|
||||||
|
|
||||||
|
Args:
|
||||||
|
Value to convert (array of one or more 4-character strings)
|
||||||
|
|
||||||
|
Return:
|
||||||
|
A native-endian long value
|
||||||
|
"""
|
||||||
|
if not cells:
|
||||||
|
return 0
|
||||||
|
out = long(fdt32_to_cpu(val[0]))
|
||||||
|
if cells == 2:
|
||||||
|
out = out << 32 | fdt32_to_cpu(val[1])
|
||||||
|
return out
|
||||||
|
|
||||||
def EnsureCompiled(fname):
|
def EnsureCompiled(fname):
|
||||||
"""Compile an fdt .dts source file into a .dtb binary blob if needed.
|
"""Compile an fdt .dts source file into a .dtb binary blob if needed.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,12 @@ class TestDtoc(unittest.TestCase):
|
||||||
data = infile.read()
|
data = infile.read()
|
||||||
self.assertEqual('''#include <stdbool.h>
|
self.assertEqual('''#include <stdbool.h>
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
struct dtd_sandbox_i2c_test {
|
||||||
|
};
|
||||||
|
struct dtd_sandbox_pmic_test {
|
||||||
|
\tbool\t\tlow_power;
|
||||||
|
\tfdt64_t\t\treg[2];
|
||||||
|
};
|
||||||
struct dtd_sandbox_spl_test {
|
struct dtd_sandbox_spl_test {
|
||||||
\tbool\t\tboolval;
|
\tbool\t\tboolval;
|
||||||
\tunsigned char\tbytearray[3];
|
\tunsigned char\tbytearray[3];
|
||||||
|
|
@ -146,7 +152,8 @@ static struct dtd_sandbox_spl_test dtv_spl_test = {
|
||||||
\t.bytearray\t\t= {0x6, 0x0, 0x0},
|
\t.bytearray\t\t= {0x6, 0x0, 0x0},
|
||||||
\t.byteval\t\t= 0x5,
|
\t.byteval\t\t= 0x5,
|
||||||
\t.intval\t\t\t= 0x1,
|
\t.intval\t\t\t= 0x1,
|
||||||
\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11},
|
\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
|
||||||
|
\t\t0x11},
|
||||||
\t.stringval\t\t= "message",
|
\t.stringval\t\t= "message",
|
||||||
\t.boolval\t\t= true,
|
\t.boolval\t\t= true,
|
||||||
\t.intarray\t\t= {0x2, 0x3, 0x4, 0x0},
|
\t.intarray\t\t= {0x2, 0x3, 0x4, 0x0},
|
||||||
|
|
@ -162,7 +169,8 @@ static struct dtd_sandbox_spl_test dtv_spl_test2 = {
|
||||||
\t.bytearray\t\t= {0x1, 0x23, 0x34},
|
\t.bytearray\t\t= {0x1, 0x23, 0x34},
|
||||||
\t.byteval\t\t= 0x8,
|
\t.byteval\t\t= 0x8,
|
||||||
\t.intval\t\t\t= 0x3,
|
\t.intval\t\t\t= 0x3,
|
||||||
\t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
\t.longbytearray\t\t= {0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
\t\t0x0},
|
||||||
\t.stringval\t\t= "message2",
|
\t.stringval\t\t= "message2",
|
||||||
\t.intarray\t\t= {0x5, 0x0, 0x0, 0x0},
|
\t.intarray\t\t= {0x5, 0x0, 0x0, 0x0},
|
||||||
\t.stringarray\t\t= {"another", "multi-word", "message"},
|
\t.stringarray\t\t= {"another", "multi-word", "message"},
|
||||||
|
|
@ -190,6 +198,24 @@ U_BOOT_DEVICE(spl_test4) = {
|
||||||
\t.platdata_size\t= sizeof(dtv_spl_test4),
|
\t.platdata_size\t= sizeof(dtv_spl_test4),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(i2c_at_0) = {
|
||||||
|
\t.name\t\t= "sandbox_i2c_test",
|
||||||
|
\t.platdata\t= &dtv_i2c_at_0,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_i2c_at_0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
|
||||||
|
\t.low_power\t\t= true,
|
||||||
|
\t.reg\t\t\t= {0x9, 0x0},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(pmic_at_9) = {
|
||||||
|
\t.name\t\t= "sandbox_pmic_test",
|
||||||
|
\t.platdata\t= &dtv_pmic_at_9,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_pmic_at_9),
|
||||||
|
};
|
||||||
|
|
||||||
''', data)
|
''', data)
|
||||||
|
|
||||||
def test_phandle(self):
|
def test_phandle(self):
|
||||||
|
|
@ -202,7 +228,7 @@ U_BOOT_DEVICE(spl_test4) = {
|
||||||
self.assertEqual('''#include <stdbool.h>
|
self.assertEqual('''#include <stdbool.h>
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
struct dtd_source {
|
struct dtd_source {
|
||||||
\tstruct phandle_2_cell clocks[1];
|
\tstruct phandle_2_arg clocks[4];
|
||||||
};
|
};
|
||||||
struct dtd_target {
|
struct dtd_target {
|
||||||
\tfdt32_t\t\tintval;
|
\tfdt32_t\t\tintval;
|
||||||
|
|
@ -217,7 +243,7 @@ struct dtd_target {
|
||||||
#include <dt-structs.h>
|
#include <dt-structs.h>
|
||||||
|
|
||||||
static struct dtd_target dtv_phandle_target = {
|
static struct dtd_target dtv_phandle_target = {
|
||||||
\t.intval\t\t\t= 0x1,
|
\t.intval\t\t\t= 0x0,
|
||||||
};
|
};
|
||||||
U_BOOT_DEVICE(phandle_target) = {
|
U_BOOT_DEVICE(phandle_target) = {
|
||||||
\t.name\t\t= "target",
|
\t.name\t\t= "target",
|
||||||
|
|
@ -225,8 +251,30 @@ U_BOOT_DEVICE(phandle_target) = {
|
||||||
\t.platdata_size\t= sizeof(dtv_phandle_target),
|
\t.platdata_size\t= sizeof(dtv_phandle_target),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct dtd_target dtv_phandle2_target = {
|
||||||
|
\t.intval\t\t\t= 0x1,
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(phandle2_target) = {
|
||||||
|
\t.name\t\t= "target",
|
||||||
|
\t.platdata\t= &dtv_phandle2_target,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_phandle2_target),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dtd_target dtv_phandle3_target = {
|
||||||
|
\t.intval\t\t\t= 0x2,
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(phandle3_target) = {
|
||||||
|
\t.name\t\t= "target",
|
||||||
|
\t.platdata\t= &dtv_phandle3_target,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_phandle3_target),
|
||||||
|
};
|
||||||
|
|
||||||
static struct dtd_source dtv_phandle_source = {
|
static struct dtd_source dtv_phandle_source = {
|
||||||
\t.clocks\t\t\t= {{&dtv_phandle_target, 1}},
|
\t.clocks\t\t\t= {
|
||||||
|
\t\t\t{&dtv_phandle_target, {}},
|
||||||
|
\t\t\t{&dtv_phandle2_target, {11}},
|
||||||
|
\t\t\t{&dtv_phandle3_target, {12, 13}},
|
||||||
|
\t\t\t{&dtv_phandle_target, {}},},
|
||||||
};
|
};
|
||||||
U_BOOT_DEVICE(phandle_source) = {
|
U_BOOT_DEVICE(phandle_source) = {
|
||||||
\t.name\t\t= "source",
|
\t.name\t\t= "source",
|
||||||
|
|
@ -268,4 +316,216 @@ U_BOOT_DEVICE(spl_test) = {
|
||||||
\t.platdata_size\t= sizeof(dtv_spl_test),
|
\t.platdata_size\t= sizeof(dtv_spl_test),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
''', data)
|
||||||
|
|
||||||
|
def test_addresses64(self):
|
||||||
|
"""Test output from a node with a 'reg' property with na=2, ns=2"""
|
||||||
|
dtb_file = get_dtb_file('dtoc_test_addr64.dts')
|
||||||
|
output = tools.GetOutputFilename('output')
|
||||||
|
dtb_platdata.run_steps(['struct'], dtb_file, False, output)
|
||||||
|
with open(output) as infile:
|
||||||
|
data = infile.read()
|
||||||
|
self.assertEqual('''#include <stdbool.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
struct dtd_test1 {
|
||||||
|
\tfdt64_t\t\treg[2];
|
||||||
|
};
|
||||||
|
struct dtd_test2 {
|
||||||
|
\tfdt64_t\t\treg[2];
|
||||||
|
};
|
||||||
|
struct dtd_test3 {
|
||||||
|
\tfdt64_t\t\treg[4];
|
||||||
|
};
|
||||||
|
''', data)
|
||||||
|
|
||||||
|
dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
|
||||||
|
with open(output) as infile:
|
||||||
|
data = infile.read()
|
||||||
|
self.assertEqual('''#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <dt-structs.h>
|
||||||
|
|
||||||
|
static struct dtd_test1 dtv_test1 = {
|
||||||
|
\t.reg\t\t\t= {0x1234, 0x5678},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test1) = {
|
||||||
|
\t.name\t\t= "test1",
|
||||||
|
\t.platdata\t= &dtv_test1,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test1),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dtd_test2 dtv_test2 = {
|
||||||
|
\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test2) = {
|
||||||
|
\t.name\t\t= "test2",
|
||||||
|
\t.platdata\t= &dtv_test2,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test2),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dtd_test3 dtv_test3 = {
|
||||||
|
\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test3) = {
|
||||||
|
\t.name\t\t= "test3",
|
||||||
|
\t.platdata\t= &dtv_test3,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test3),
|
||||||
|
};
|
||||||
|
|
||||||
|
''', data)
|
||||||
|
|
||||||
|
def test_addresses32(self):
|
||||||
|
"""Test output from a node with a 'reg' property with na=1, ns=1"""
|
||||||
|
dtb_file = get_dtb_file('dtoc_test_addr32.dts')
|
||||||
|
output = tools.GetOutputFilename('output')
|
||||||
|
dtb_platdata.run_steps(['struct'], dtb_file, False, output)
|
||||||
|
with open(output) as infile:
|
||||||
|
data = infile.read()
|
||||||
|
self.assertEqual('''#include <stdbool.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
struct dtd_test1 {
|
||||||
|
\tfdt32_t\t\treg[2];
|
||||||
|
};
|
||||||
|
struct dtd_test2 {
|
||||||
|
\tfdt32_t\t\treg[4];
|
||||||
|
};
|
||||||
|
''', data)
|
||||||
|
|
||||||
|
dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
|
||||||
|
with open(output) as infile:
|
||||||
|
data = infile.read()
|
||||||
|
self.assertEqual('''#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <dt-structs.h>
|
||||||
|
|
||||||
|
static struct dtd_test1 dtv_test1 = {
|
||||||
|
\t.reg\t\t\t= {0x1234, 0x5678},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test1) = {
|
||||||
|
\t.name\t\t= "test1",
|
||||||
|
\t.platdata\t= &dtv_test1,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test1),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dtd_test2 dtv_test2 = {
|
||||||
|
\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test2) = {
|
||||||
|
\t.name\t\t= "test2",
|
||||||
|
\t.platdata\t= &dtv_test2,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test2),
|
||||||
|
};
|
||||||
|
|
||||||
|
''', data)
|
||||||
|
|
||||||
|
def test_addresses64_32(self):
|
||||||
|
"""Test output from a node with a 'reg' property with na=2, ns=1"""
|
||||||
|
dtb_file = get_dtb_file('dtoc_test_addr64_32.dts')
|
||||||
|
output = tools.GetOutputFilename('output')
|
||||||
|
dtb_platdata.run_steps(['struct'], dtb_file, False, output)
|
||||||
|
with open(output) as infile:
|
||||||
|
data = infile.read()
|
||||||
|
self.assertEqual('''#include <stdbool.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
struct dtd_test1 {
|
||||||
|
\tfdt64_t\t\treg[2];
|
||||||
|
};
|
||||||
|
struct dtd_test2 {
|
||||||
|
\tfdt64_t\t\treg[2];
|
||||||
|
};
|
||||||
|
struct dtd_test3 {
|
||||||
|
\tfdt64_t\t\treg[4];
|
||||||
|
};
|
||||||
|
''', data)
|
||||||
|
|
||||||
|
dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
|
||||||
|
with open(output) as infile:
|
||||||
|
data = infile.read()
|
||||||
|
self.assertEqual('''#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <dt-structs.h>
|
||||||
|
|
||||||
|
static struct dtd_test1 dtv_test1 = {
|
||||||
|
\t.reg\t\t\t= {0x123400000000, 0x5678},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test1) = {
|
||||||
|
\t.name\t\t= "test1",
|
||||||
|
\t.platdata\t= &dtv_test1,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test1),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dtd_test2 dtv_test2 = {
|
||||||
|
\t.reg\t\t\t= {0x1234567890123456, 0x98765432},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test2) = {
|
||||||
|
\t.name\t\t= "test2",
|
||||||
|
\t.platdata\t= &dtv_test2,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test2),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dtd_test3 dtv_test3 = {
|
||||||
|
\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test3) = {
|
||||||
|
\t.name\t\t= "test3",
|
||||||
|
\t.platdata\t= &dtv_test3,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test3),
|
||||||
|
};
|
||||||
|
|
||||||
|
''', data)
|
||||||
|
|
||||||
|
def test_addresses32_64(self):
|
||||||
|
"""Test output from a node with a 'reg' property with na=1, ns=2"""
|
||||||
|
dtb_file = get_dtb_file('dtoc_test_addr32_64.dts')
|
||||||
|
output = tools.GetOutputFilename('output')
|
||||||
|
dtb_platdata.run_steps(['struct'], dtb_file, False, output)
|
||||||
|
with open(output) as infile:
|
||||||
|
data = infile.read()
|
||||||
|
self.assertEqual('''#include <stdbool.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
struct dtd_test1 {
|
||||||
|
\tfdt64_t\t\treg[2];
|
||||||
|
};
|
||||||
|
struct dtd_test2 {
|
||||||
|
\tfdt64_t\t\treg[2];
|
||||||
|
};
|
||||||
|
struct dtd_test3 {
|
||||||
|
\tfdt64_t\t\treg[4];
|
||||||
|
};
|
||||||
|
''', data)
|
||||||
|
|
||||||
|
dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
|
||||||
|
with open(output) as infile:
|
||||||
|
data = infile.read()
|
||||||
|
self.assertEqual('''#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <dt-structs.h>
|
||||||
|
|
||||||
|
static struct dtd_test1 dtv_test1 = {
|
||||||
|
\t.reg\t\t\t= {0x1234, 0x567800000000},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test1) = {
|
||||||
|
\t.name\t\t= "test1",
|
||||||
|
\t.platdata\t= &dtv_test1,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test1),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dtd_test2 dtv_test2 = {
|
||||||
|
\t.reg\t\t\t= {0x12345678, 0x9876543210987654},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test2) = {
|
||||||
|
\t.name\t\t= "test2",
|
||||||
|
\t.platdata\t= &dtv_test2,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test2),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dtd_test3 dtv_test3 = {
|
||||||
|
\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
|
||||||
|
};
|
||||||
|
U_BOOT_DEVICE(test3) = {
|
||||||
|
\t.name\t\t= "test3",
|
||||||
|
\t.platdata\t= &dtv_test3,
|
||||||
|
\t.platdata_size\t= sizeof(dtv_test3),
|
||||||
|
};
|
||||||
|
|
||||||
''', data)
|
''', data)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue