summaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorMichael Tretter <m.tretter@pengutronix.de>2019-09-13 15:14:43 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2019-09-16 09:06:18 +0200
commitf41d37ce080c24e296b10b3997a43dfa88591593 (patch)
tree18341ca093572874b71c782de3ae1629c7d9d316 /drivers/of
parent32559cecae49998091dd5645b386ed917f5c468d (diff)
downloadbarebox-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/Makefile2
-rw-r--r--drivers/of/of_firmware.c86
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;
+}