From da2c36c0a911992d80448f9afa5acc9d70871ed0 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Sep 2019 15:14:40 +0200 Subject: blspec: add support for devicetree overlays Read the devicetree-overlay property from the blspec entry and register the overlays when booting the blspec entry. Do not fail the boot if an overlay cannot be loaded, because if Linux fails to boot without an overlay, the base device tree is broken. Signed-off-by: Michael Tretter Signed-off-by: Sascha Hauer --- common/blspec.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'common') diff --git a/common/blspec.c b/common/blspec.c index 66e5033e35..fbba2fc78c 100644 --- a/common/blspec.c +++ b/common/blspec.c @@ -42,6 +42,62 @@ int blspec_entry_var_set(struct blspec_entry *entry, const char *name, val ? strlen(val) + 1 : 0, 1); } +static int blspec_apply_oftree_overlay(char *file, const char *abspath, + int dryrun) +{ + int ret = 0; + struct fdt_header *fdt; + struct device_node *overlay; + char *path; + + path = basprintf("%s/%s", abspath, file); + + fdt = read_file(path, NULL); + if (!fdt) { + pr_warn("unable to read \"%s\"\n", path); + ret = -EINVAL; + goto out; + } + + overlay = of_unflatten_dtb(fdt); + free(fdt); + if (IS_ERR(overlay)) { + ret = PTR_ERR(overlay); + goto out; + } + + if (dryrun) { + pr_info("dry run: skip overlay %s\n", path); + of_delete_node(overlay); + goto out; + } + + ret = of_register_overlay(overlay); + if (ret) { + pr_warn("cannot register devicetree overlay \"%s\"\n", path); + of_delete_node(overlay); + } + +out: + free(path); + + return ret; +} + +static void blspec_apply_oftree_overlays(const char *overlays, + const char *abspath, int dryrun) +{ + char *overlay; + char *sep, *freep; + + sep = freep = xstrdup(overlays); + + while ((overlay = strsep(&sep, " "))) + blspec_apply_oftree_overlay(overlay, abspath, dryrun); + + free(freep); +} + /* * blspec_boot - boot an entry * @@ -54,6 +110,7 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun) struct blspec_entry *entry = container_of(be, struct blspec_entry, entry); int ret; const char *abspath, *devicetree, *options, *initrd, *linuximage; + const char *overlays; const char *appendroot; struct bootm_data data = { .initrd_address = UIMAGE_INVALID_ADDRESS, @@ -73,6 +130,7 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun) initrd = blspec_entry_var_get(entry, "initrd"); options = blspec_entry_var_get(entry, "options"); linuximage = blspec_entry_var_get(entry, "linux"); + overlays = blspec_entry_var_get(entry, "devicetree-overlay"); if (entry->rootpath) abspath = entry->rootpath; @@ -92,6 +150,9 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun) } } + if (overlays) + blspec_apply_oftree_overlays(overlays, abspath, dryrun); + if (initrd) data.initrd_file = basprintf("%s/%s", abspath, initrd); -- cgit v1.2.3 From 32559cecae49998091dd5645b386ed917f5c468d Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Sep 2019 15:14:42 +0200 Subject: firmware: add function to find firmware by devicetree node Allows to get the firmware manager using a phandle from the devicetree. Signed-off-by: Michael Tretter Signed-off-by: Sascha Hauer --- common/firmware.c | 18 ++++++++++++++++++ include/firmware.h | 15 +++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'common') diff --git a/common/firmware.c b/common/firmware.c index 9d55d73e7a..609cf11822 100644 --- a/common/firmware.c +++ b/common/firmware.c @@ -62,6 +62,24 @@ struct firmware_mgr *firmwaremgr_find(const char *id) return NULL; } +/* + * firmwaremgr_find_by_node - find a firmware device handler + * + * Find a firmware device handler using the device node of the firmware + * handler. This allows to retrieve the firmware handler with a phandle from + * the device tree. + */ +struct firmware_mgr *firmwaremgr_find_by_node(const struct device_node *np) +{ + struct firmware_mgr *mgr; + + list_for_each_entry(mgr, &firmwaremgr_list, list) + if (mgr->handler->dev->parent->device_node == np) + return mgr; + + return NULL; +} + /* * firmwaremgr_list_handlers - list registered firmware device handlers * in pretty format diff --git a/include/firmware.h b/include/firmware.h index 284e0f9705..7c01a77118 100644 --- a/include/firmware.h +++ b/include/firmware.h @@ -34,10 +34,25 @@ struct firmware_mgr; int firmwaremgr_register(struct firmware_handler *); struct firmware_mgr *firmwaremgr_find(const char *); +#ifdef CONFIG_FIRMWARE +struct firmware_mgr *firmwaremgr_find_by_node(const struct device_node *np); +#else +static inline struct firmware_mgr *firmwaremgr_find_by_node(const struct device_node *np) +{ + return NULL; +} +#endif void firmwaremgr_list_handlers(void); +#ifdef CONFIG_FIRMWARE int firmwaremgr_load_file(struct firmware_mgr *, const char *path); +#else +static inline int firmwaremgr_load_file(struct firmware_mgr *mgr, const char *path) +{ + return -ENOSYS; +} +#endif #define get_builtin_firmware(name, start, size) \ { \ -- cgit v1.2.3 From 7fdca8aa1fef0d9739ba89cd632ef76da6f86760 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Sep 2019 15:14:44 +0200 Subject: blspec: load firmware if specified in dt overlay If a device tree overlay referenced by the blspec depends on firmware, try to load the firmware from the default Linux firmware search path /lib/firmware in the about to be started rootfs. Signed-off-by: Michael Tretter Signed-off-by: Sascha Hauer --- common/blspec.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'common') diff --git a/common/blspec.c b/common/blspec.c index fbba2fc78c..7c27e0b869 100644 --- a/common/blspec.c +++ b/common/blspec.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -49,6 +50,7 @@ static int blspec_apply_oftree_overlay(char *file, const char *abspath, struct fdt_header *fdt; struct device_node *overlay; char *path; + char *firmware_path; path = basprintf("%s/%s", abspath, file); @@ -72,6 +74,21 @@ static int blspec_apply_oftree_overlay(char *file, const char *abspath, goto out; } + /* + * Unfortunately the device tree overlay contains only the filename of + * the firmware and relies on the firmware search paths to find the + * actual file. Use /lib/firmware in the Linux root directory and hope + * for the best. + */ + firmware_path = basprintf("%s/%s", abspath, "/lib/firmware"); + ret = of_firmware_load_overlay(overlay, firmware_path); + free(firmware_path); + if (ret) { + pr_warn("failed to load firmware: skip overlay \"%s\"\n", path); + of_delete_node(overlay); + goto out; + } + ret = of_register_overlay(overlay); if (ret) { pr_warn("cannot register devicetree overlay \"%s\"\n", path); -- cgit v1.2.3