diff --git a/boot/image-fit.c b/boot/image-fit.c index 02f1d28c77..3cc556b727 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -802,6 +802,40 @@ int fit_image_get_comp(const void *fit, int noffset, uint8_t *comp) return 0; } +/** + * fit_image_get_phase() - get the phase for a configuration node + * @fit: pointer to the FIT format image header + * @offset: configuration-node offset + * @phasep: returns the phase + * + * Finds the phase property in a given configuration node. If the property is + * found, its (string) value is translated to the numeric id which is returned + * to the caller. + * + * Returns: 0 on success, -ENOENT if missing, -EINVAL for invalid value + */ +int fit_image_get_phase(const void *fit, int offset, enum image_phase_t *phasep) +{ + const void *data; + int len, ret; + + /* Get phase name from property data */ + data = fdt_getprop(fit, offset, FIT_PHASE_PROP, &len); + if (!data) { + fit_get_debug(fit, offset, FIT_PHASE_PROP, len); + *phasep = 0; + return -ENOENT; + } + + /* Translate phase name to id */ + ret = genimg_get_phase_id(data); + if (ret < 0) + return ret; + *phasep = ret; + + return 0; +} + static int fit_image_get_address(const void *fit, int noffset, char *name, ulong *load) { @@ -1867,10 +1901,37 @@ int fit_conf_get_prop_node_index(const void *fit, int noffset, return fit_image_get_node(fit, uname); } -int fit_conf_get_prop_node(const void *fit, int noffset, - const char *prop_name) +int fit_conf_get_prop_node(const void *fit, int noffset, const char *prop_name, + enum image_phase_t sel_phase) { - return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0); + int i, count; + + if (sel_phase == IH_PHASE_NONE) + return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0); + + count = fit_conf_get_prop_node_count(fit, noffset, prop_name); + if (count < 0) + return count; + + /* check each image in the list */ + for (i = 0; i < count; i++) { + enum image_phase_t phase; + int ret, node; + + node = fit_conf_get_prop_node_index(fit, noffset, prop_name, i); + ret = fit_image_get_phase(fit, node, &phase); + + /* if the image is for any phase, let's use it */ + if (ret == -ENOENT) + return node; + else if (ret < 0) + return ret; + + if (phase == sel_phase) + return node; + } + + return -ENOENT; } static int fit_get_data_tail(const void *fit, int noffset, @@ -1906,7 +1967,8 @@ int fit_get_data_conf_prop(const void *fit, const char *prop_name, { int noffset = fit_conf_get_node(fit, NULL); - noffset = fit_conf_get_prop_node(fit, noffset, prop_name); + noffset = fit_conf_get_prop_node(fit, noffset, prop_name, + IH_PHASE_NONE); return fit_get_data_tail(fit, noffset, data, size); } @@ -1944,7 +2006,8 @@ int fit_get_node_from_config(struct bootm_headers *images, return -EINVAL; } - noffset = fit_conf_get_prop_node(fit_hdr, cfg_noffset, prop_name); + noffset = fit_conf_get_prop_node(fit_hdr, cfg_noffset, prop_name, + IH_PHASE_NONE); if (noffset < 0) { debug("* %s: no '%s' in config\n", prop_name, prop_name); return -ENOENT; @@ -1990,9 +2053,10 @@ static const char *fit_get_image_type_property(int type) int fit_image_load(struct bootm_headers *images, ulong addr, const char **fit_unamep, const char **fit_uname_configp, - int arch, int image_type, int bootstage_id, + int arch, int ph_type, int bootstage_id, enum fit_load_op load_op, ulong *datap, ulong *lenp) { + int image_type = image_ph_type(ph_type); int cfg_noffset, noffset; const char *fit_uname; const char *fit_uname_config; @@ -2038,8 +2102,7 @@ int fit_image_load(struct bootm_headers *images, ulong addr, if (IS_ENABLED(CONFIG_FIT_BEST_MATCH) && !fit_uname_config) { cfg_noffset = fit_conf_find_compat(fit, gd_fdt_blob()); } else { - cfg_noffset = fit_conf_get_node(fit, - fit_uname_config); + cfg_noffset = fit_conf_get_node(fit, fit_uname_config); } if (cfg_noffset < 0) { puts("Could not find configuration node\n"); @@ -2067,8 +2130,8 @@ int fit_image_load(struct bootm_headers *images, ulong addr, bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG); - noffset = fit_conf_get_prop_node(fit, cfg_noffset, - prop_name); + noffset = fit_conf_get_prop_node(fit, cfg_noffset, prop_name, + image_ph_phase(ph_type)); fit_uname = fit_get_name(fit, noffset, NULL); } if (noffset < 0) { diff --git a/doc/uImage.FIT/howto.txt b/doc/uImage.FIT/howto.txt index 019dda24a0..6dbd17dc8c 100644 --- a/doc/uImage.FIT/howto.txt +++ b/doc/uImage.FIT/howto.txt @@ -70,6 +70,12 @@ The SPL also records to a DT all additional images (called loadables) which are loaded. The information about loadables locations is passed via the DT node with fit-images name. +Finally, if there are multiple xPL phases (e.g. SPL, VPL), images can be marked +as intended for a particular phase using the 'phase' property. For example, if +fit_image_load() is called with image_ph(IH_PHASE_SPL, IH_TYPE_FIRMWARE), then +only the image listed into the "firmware" property where phase is set to "spl" +will be loaded. + Loadables Example ----------------- Consider the following case for an ARM64 platform where U-Boot runs in EL2 diff --git a/include/image.h b/include/image.h index 7c3dcc407c..65d0d4f438 100644 --- a/include/image.h +++ b/include/image.h @@ -691,9 +691,10 @@ int boot_get_fdt_fit(struct bootm_headers *images, ulong addr, * 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 image_type Required image type (IH_TYPE_...). If this is + * @param image_ph_type Required image type (IH_TYPE_...). If this is * IH_TYPE_KERNEL then we allow IH_TYPE_KERNEL_NOLOAD - * also. + * also. If a phase is required, this is included also, + * see image_phase_and_type() * @param bootstage_id ID of starting bootstage to use for progress updates. * This will be added to the BOOTSTAGE_SUB values when * calling bootstage_mark() @@ -704,7 +705,7 @@ int boot_get_fdt_fit(struct bootm_headers *images, ulong addr, */ int fit_image_load(struct bootm_headers *images, ulong addr, const char **fit_unamep, const char **fit_uname_configp, - int arch, int image_type, int bootstage_id, + int arch, int image_ph_type, int bootstage_id, enum fit_load_op load_op, ulong *datap, ulong *lenp); /** @@ -1349,14 +1350,15 @@ int fit_conf_get_prop_node_index(const void *fit, int noffset, * @fit: FIT to check * @noffset: Offset of conf@xxx node to check * @prop_name: Property to read from the conf node + * @phase: Image phase to use, IH_PHASE_NONE for any * * The conf- nodes contain references to other nodes, using properties * like 'kernel = "kernel"'. Given such a property name (e.g. "kernel"), * return the offset of the node referred to (e.g. offset of node * "/images/kernel". */ -int fit_conf_get_prop_node(const void *fit, int noffset, - const char *prop_name); +int fit_conf_get_prop_node(const void *fit, int noffset, const char *prop_name, + enum image_phase_t phase); int fit_check_ramdisk(const void *fit, int os_noffset, uint8_t arch, int verify);