summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/blspec.c78
-rw-r--r--common/firmware.c18
2 files changed, 96 insertions, 0 deletions
diff --git a/common/blspec.c b/common/blspec.c
index 83b05993dd..7fb62d310f 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -14,6 +14,7 @@
#include <environment.h>
#include <globalvar.h>
+#include <firmware.h>
#include <readkey.h>
#include <common.h>
#include <driver.h>
@@ -42,6 +43,78 @@ 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;
+ char *firmware_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;
+ }
+
+ /*
+ * 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);
+ 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 +127,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 +147,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 +167,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);
diff --git a/common/firmware.c b/common/firmware.c
index 9d55d73e7a..609cf11822 100644
--- a/common/firmware.c
+++ b/common/firmware.c
@@ -63,6 +63,24 @@ struct firmware_mgr *firmwaremgr_find(const char *id)
}
/*
+ * 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
*/