diff options
author | Michael Tretter <m.tretter@pengutronix.de> | 2019-09-13 15:14:43 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2019-09-16 09:06:18 +0200 |
commit | f41d37ce080c24e296b10b3997a43dfa88591593 (patch) | |
tree | 18341ca093572874b71c782de3ae1629c7d9d316 /drivers/of | |
parent | 32559cecae49998091dd5645b386ed917f5c468d (diff) | |
download | barebox-f41d37ce080c24e296b10b3997a43dfa88591593.tar.gz barebox-f41d37ce080c24e296b10b3997a43dfa88591593.tar.xz |
firmware: add support to load firmware from dt overlay
fpga-region device tree nodes have the firmware-name property that
contains the file name of firmware in the firmware search path (but not
the path) that shall be loaded before the overlay is applied.
Add the of_firmware_load_overlay() function that accepts an overlay and a
firmware search path, finds the responsible firmware_mgr and loads the
firmware.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/Makefile | 2 | ||||
-rw-r--r-- | drivers/of/of_firmware.c | 86 |
2 files changed, 87 insertions, 1 deletions
diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 9c6f8de814..b6847752d2 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -6,4 +6,4 @@ obj-y += partition.o obj-y += of_net.o obj-$(CONFIG_MTD) += of_mtd.o obj-$(CONFIG_OF_BAREBOX_DRIVERS) += barebox.o -obj-$(CONFIG_OF_OVERLAY) += overlay.o resolver.o +obj-$(CONFIG_OF_OVERLAY) += overlay.o resolver.o of_firmware.o diff --git a/drivers/of/of_firmware.c b/drivers/of/of_firmware.c new file mode 100644 index 0000000000..0135631fb8 --- /dev/null +++ b/drivers/of/of_firmware.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Pengutronix, Michael Tretter <m.tretter@pengutronix.de> + */ +#include <common.h> +#include <firmware.h> +#include <of.h> + +struct overlay_info { + const char *firmware_path; +}; + +static struct firmware_mgr *of_node_get_mgr(struct device_node *np) +{ + struct device_node *mgr_node; + + do { + if (of_device_is_compatible(np, "fpga-region")) { + mgr_node = of_parse_phandle(np, "fpga-mgr", 0); + if (mgr_node) + return firmwaremgr_find_by_node(mgr_node); + } + } while ((np = of_get_parent(np)) != NULL); + + return NULL; +} + +static int load_firmware(struct device_node *target, + struct device_node *fragment, void *data) +{ + struct overlay_info *info = data; + const char *firmware_name; + const char *firmware_path = info->firmware_path; + char *firmware; + int err; + struct firmware_mgr *mgr; + + err = of_property_read_string(fragment, + "firmware-name", &firmware_name); + /* Nothing to do if property does not exist. */ + if (err == -EINVAL) + return 0; + else if (err) + return -EINVAL; + + mgr = of_node_get_mgr(target); + if (!mgr) + return -EINVAL; + + firmware = basprintf("%s/%s", firmware_path, firmware_name); + if (!firmware) + return -ENOMEM; + + err = firmwaremgr_load_file(mgr, firmware); + + free(firmware); + + return err; +} + +int of_firmware_load_overlay(struct device_node *overlay, const char *path) +{ + struct overlay_info info = { + .firmware_path = path, + }; + int err; + struct device_node *root; + struct device_node *resolved; + struct device_node *ovl; + + root = of_get_root_node(); + /* + * If we cannot resolve the symbols in the overlay, ensure that the + * overlay does depend on firmware to be loaded. + */ + resolved = of_resolve_phandles(root, overlay); + ovl = resolved ? resolved : overlay; + + err = of_process_overlay(root, ovl, + load_firmware, &info); + + if (resolved) + of_delete_node(resolved); + + return err; +} |