diff options
author | Gabe Black <gabeblack@chromium.org> | 2012-10-25 16:31:10 +0000 |
---|---|---|
committer | Gerald Van Baren <gvb@unssw.com> | 2012-11-12 23:14:57 -0500 |
commit | d95f6ec7334076a1e4b13f3748ebfd1b58ac90f6 (patch) | |
tree | b45f3e30b135e0af09a7005920205fc8470147f7 /common | |
parent | 67e1ea26e89e19a550d86d6408f39d815eedaa7f (diff) | |
download | u-boot-imx-d95f6ec7334076a1e4b13f3748ebfd1b58ac90f6.zip u-boot-imx-d95f6ec7334076a1e4b13f3748ebfd1b58ac90f6.tar.gz u-boot-imx-d95f6ec7334076a1e4b13f3748ebfd1b58ac90f6.tar.bz2 |
fdt: Add option to default to most compatible conf in a fit image
When booting a fit image with multiple configurations, the user either has to
specify which configuration to use explicitly, or there has to be a default
defined which is chosen automatically. This change adds an option to change
that behavior so that a configuration can be selected explicitly, or the
configuration which has the device tree that claims to be compatible with the
earliest item in U-Boot's device tree.
In other words, if U-Boot claimed to be compatible with A, B, and then C, and
the configurations claimed to be compatible with A, D and B, D and D, E, the
first configuration, A, D, would be chosen. Both the first and second
configurations match, but the first one matches a more specific entry in
U-Boot's device tree. The order in the kernel's device tree is ignored.
Signed-off-by: Gabe Black <gabeblack@google.com>
Commit-Ready: Gabe Black <gabeblack@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'common')
-rw-r--r-- | common/cmd_bootm.c | 11 | ||||
-rw-r--r-- | common/image.c | 127 |
2 files changed, 138 insertions, 0 deletions
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index d256ddf..4dbe952 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -949,8 +949,19 @@ static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, * node */ bootstage_mark(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); +#ifdef CONFIG_FIT_BEST_MATCH + if (fit_uname_config) + cfg_noffset = + fit_conf_get_node(fit_hdr, + fit_uname_config); + else + cfg_noffset = + fit_conf_find_compat(fit_hdr, + gd->fdt_blob); +#else cfg_noffset = fit_conf_get_node(fit_hdr, fit_uname_config); +#endif if (cfg_noffset < 0) { bootstage_error(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); return NULL; diff --git a/common/image.c b/common/image.c index df642e6..e93b6e8 100644 --- a/common/image.c +++ b/common/image.c @@ -3049,6 +3049,133 @@ int fit_check_format(const void *fit) return 1; } + +/** + * fit_conf_find_compat + * @fit: pointer to the FIT format image header + * @fdt: pointer to the device tree to compare against + * + * fit_conf_find_compat() attempts to find the configuration whose fdt is the + * most compatible with the passed in device tree. + * + * Example: + * + * / o image-tree + * |-o images + * | |-o fdt@1 + * | |-o fdt@2 + * | + * |-o configurations + * |-o config@1 + * | |-fdt = fdt@1 + * | + * |-o config@2 + * |-fdt = fdt@2 + * + * / o U-Boot fdt + * |-compatible = "foo,bar", "bim,bam" + * + * / o kernel fdt1 + * |-compatible = "foo,bar", + * + * / o kernel fdt2 + * |-compatible = "bim,bam", "baz,biz" + * + * Configuration 1 would be picked because the first string in U-Boot's + * compatible list, "foo,bar", matches a compatible string in the root of fdt1. + * "bim,bam" in fdt2 matches the second string which isn't as good as fdt1. + * + * returns: + * offset to the configuration to use if one was found + * -1 otherwise + */ +int fit_conf_find_compat(const void *fit, const void *fdt) +{ + int ndepth = 0; + int noffset, confs_noffset, images_noffset; + const void *fdt_compat; + int fdt_compat_len; + int best_match_offset = 0; + int best_match_pos = 0; + + confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); + images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (confs_noffset < 0 || images_noffset < 0) { + debug("Can't find configurations or images nodes.\n"); + return -1; + } + + fdt_compat = fdt_getprop(fdt, 0, "compatible", &fdt_compat_len); + if (!fdt_compat) { + debug("Fdt for comparison has no \"compatible\" property.\n"); + return -1; + } + + /* + * Loop over the configurations in the FIT image. + */ + for (noffset = fdt_next_node(fit, confs_noffset, &ndepth); + (noffset >= 0) && (ndepth > 0); + noffset = fdt_next_node(fit, noffset, &ndepth)) { + const void *kfdt; + const char *kfdt_name; + int kfdt_noffset; + const char *cur_fdt_compat; + int len; + size_t size; + int i; + + if (ndepth > 1) + continue; + + kfdt_name = fdt_getprop(fit, noffset, "fdt", &len); + if (!kfdt_name) { + debug("No fdt property found.\n"); + continue; + } + kfdt_noffset = fdt_subnode_offset(fit, images_noffset, + kfdt_name); + if (kfdt_noffset < 0) { + debug("No image node named \"%s\" found.\n", + kfdt_name); + continue; + } + /* + * Get a pointer to this configuration's fdt. + */ + if (fit_image_get_data(fit, kfdt_noffset, &kfdt, &size)) { + debug("Failed to get fdt \"%s\".\n", kfdt_name); + continue; + } + + len = fdt_compat_len; + cur_fdt_compat = fdt_compat; + /* + * Look for a match for each U-Boot compatibility string in + * turn in this configuration's fdt. + */ + for (i = 0; len > 0 && + (!best_match_offset || best_match_pos > i); i++) { + int cur_len = strlen(cur_fdt_compat) + 1; + + if (!fdt_node_check_compatible(kfdt, 0, + cur_fdt_compat)) { + best_match_offset = noffset; + best_match_pos = i; + break; + } + len -= cur_len; + cur_fdt_compat += cur_len; + } + } + if (!best_match_offset) { + debug("No match found.\n"); + return -1; + } + + return best_match_offset; +} + /** * fit_conf_get_node - get node offset for configuration of a given unit name * @fit: pointer to the FIT format image header |