summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig4
-rw-r--r--common/Makefile1
-rw-r--r--common/bbu.c27
-rw-r--r--common/blspec.c99
-rw-r--r--common/bootm.c4
-rw-r--r--common/console.c20
-rw-r--r--common/deep-probe.c39
-rw-r--r--common/efi/efi.c2
-rw-r--r--common/firmware.c109
-rw-r--r--common/image-fit.c2
-rw-r--r--common/oftree.c4
-rw-r--r--common/state/backend_format_dtb.c2
12 files changed, 225 insertions, 88 deletions
diff --git a/common/Kconfig b/common/Kconfig
index d4e518bf8a..2d7888b9fa 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1477,6 +1477,10 @@ config DEBUG_INITCALLS
help
If enabled this will print initcall traces.
+config DEBUG_PROBES
+ bool "Trace driver probes"
+ help
+ If enabled this will print driver probe traces.
config PBL_BREAK
bool "Execute software break on pbl start"
diff --git a/common/Makefile b/common/Makefile
index 382a4f661f..daa022ff54 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -3,6 +3,7 @@ obj-y += memory_display.o
pbl-$(CONFIG_PBL_CONSOLE) += memory_display.o
obj-y += clock.o
obj-y += console_common.o
+obj-y += deep-probe.o
obj-y += startup.o
obj-y += misc.o
obj-pbl-y += memsize.o
diff --git a/common/bbu.c b/common/bbu.c
index 1a1edda96b..cd7bdc40b7 100644
--- a/common/bbu.c
+++ b/common/bbu.c
@@ -4,6 +4,9 @@
*
* Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*/
+
+#define pr_fmt(fmt) "bbu: " fmt
+
#include <common.h>
#include <bbu.h>
#include <linux/list.h>
@@ -32,12 +35,32 @@ static void append_bbu_entry(struct bbu_handler *handler, struct file_list *file
free(name);
}
+static bool bbu_handler_is_available(struct bbu_handler *handler)
+{
+ struct stat s;
+ int ret;
+
+ device_detect_by_name(devpath_to_name(handler->devicefile));
+
+ ret = stat(handler->devicefile, &s);
+ if (ret)
+ return false;
+
+ return true;
+}
+
void bbu_append_handlers_to_file_list(struct file_list *files)
{
struct bbu_handler *handler;
- list_for_each_entry(handler, &bbu_image_handlers, list)
- append_bbu_entry(handler, files);
+ list_for_each_entry(handler, &bbu_image_handlers, list) {
+ if (bbu_handler_is_available(handler)) {
+ append_bbu_entry(handler, files);
+ } else {
+ pr_info("Skipping unavailable handler bbu-%s\n",
+ handler->name);
+ }
+ }
}
int bbu_force(struct bbu_data *data, const char *fmt, ...)
diff --git a/common/blspec.c b/common/blspec.c
index ad80d7a8cd..6cb1fea9e8 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -32,79 +32,33 @@ 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)
+static int blspec_overlay_fixup(struct device_node *root, void *ctx)
{
+ struct blspec_entry *entry = ctx;
+ const char *overlays;
char *overlay;
char *sep, *freep;
+ overlays = blspec_entry_var_get(entry, "devicetree-overlay");
+
sep = freep = xstrdup(overlays);
while ((overlay = strsep(&sep, " "))) {
+ char *path;
+
if (!*overlay)
continue;
- blspec_apply_oftree_overlay(overlay, abspath, dryrun);
+
+ path = basprintf("%s/%s", entry->rootpath, overlay);
+
+ of_overlay_apply_file(root, path, false);
+
+ free(path);
}
free(freep);
+
+ return 0;
}
/*
@@ -121,6 +75,8 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
const char *abspath, *devicetree, *options, *initrd, *linuximage;
const char *overlays;
const char *appendroot;
+ const char *old_fws;
+ char *fws;
struct bootm_data data = {
.dryrun = dryrun,
};
@@ -159,7 +115,7 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
}
if (overlays)
- blspec_apply_oftree_overlays(overlays, abspath, dryrun);
+ of_register_fixup(blspec_overlay_fixup, entry);
if (initrd)
data.initrd_file = basprintf("%s/%s", abspath, initrd);
@@ -183,9 +139,26 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
(entry->cdev && entry->cdev->dev) ?
dev_name(entry->cdev->dev) : "none");
+ of_overlay_set_basedir(abspath);
+
+ old_fws = firmware_get_searchpath();
+ if (old_fws && *old_fws)
+ fws = basprintf("%s/lib/firmware:%s", abspath, old_fws);
+ else
+ fws = basprintf("%s/lib/firmware", abspath);
+ firmware_set_searchpath(fws);
+ free(fws);
+
ret = bootm_boot(&data);
if (ret)
pr_err("Booting failed\n");
+
+ if (overlays)
+ of_unregister_fixup(blspec_overlay_fixup, entry);
+
+ of_overlay_set_basedir("/");
+ firmware_set_searchpath(old_fws);
+
err_out:
free((char *)data.oftree_file);
free((char *)data.initrd_file);
@@ -490,7 +463,7 @@ static bool entry_is_of_compatible(struct blspec_entry *entry)
goto out;
}
- root = of_unflatten_dtb(fdt);
+ root = of_unflatten_dtb(fdt, size);
if (IS_ERR(root)) {
ret = false;
root = NULL;
diff --git a/common/bootm.c b/common/bootm.c
index 644443a021..89e3e93f2c 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -361,7 +361,7 @@ void *bootm_get_devicetree(struct image_data *data)
if (ret)
return ERR_PTR(ret);
- data->of_root_node = of_unflatten_dtb(of_tree);
+ data->of_root_node = of_unflatten_dtb(of_tree, of_size);
} else if (data->oftree_file) {
size_t size;
@@ -389,7 +389,7 @@ void *bootm_get_devicetree(struct image_data *data)
if (ret)
return ERR_PTR(ret);
- data->of_root_node = of_unflatten_dtb(oftree);
+ data->of_root_node = of_unflatten_dtb(oftree, size);
free(oftree);
diff --git a/common/console.c b/common/console.c
index 8a0af75a1f..ad1a6aaab2 100644
--- a/common/console.c
+++ b/common/console.c
@@ -220,7 +220,7 @@ static void console_init_early(void)
initialized = CONSOLE_INITIALIZED_BUFFER;
}
-static void console_set_stdoutpath(struct console_device *cdev)
+static void console_set_stdoutpath(struct console_device *cdev, unsigned baudrate)
{
int id;
char *str;
@@ -232,8 +232,7 @@ static void console_set_stdoutpath(struct console_device *cdev)
if (id < 0)
return;
- str = basprintf("console=%s%d,%dn8", cdev->linux_console_name, id,
- cdev->baudrate);
+ str = basprintf("console=%s%d,%dn8", cdev->linux_console_name, id, baudrate);
globalvar_add_simple("linux.bootargs.console", str);
@@ -297,6 +296,7 @@ int console_register(struct console_device *newcdev)
struct device_node *serdev_node = console_is_serdev_node(newcdev);
struct device_d *dev = &newcdev->class_dev;
int activate = 0, ret;
+ unsigned baudrate = CONFIG_BAUDRATE;
if (!serdev_node && initialized == CONSOLE_UNINITIALIZED)
console_init_early();
@@ -327,11 +327,16 @@ int console_register(struct console_device *newcdev)
if (serdev_node)
return of_platform_populate(serdev_node, NULL, dev);
+ if (newcdev->dev && of_device_is_stdout_path(newcdev->dev, &baudrate)) {
+ activate = 1;
+ console_set_stdoutpath(newcdev, baudrate);
+ }
+
if (newcdev->setbrg) {
- ret = newcdev->setbrg(newcdev, CONFIG_BAUDRATE);
+ ret = newcdev->setbrg(newcdev, baudrate);
if (ret)
return ret;
- newcdev->baudrate_param = newcdev->baudrate = CONFIG_BAUDRATE;
+ newcdev->baudrate_param = newcdev->baudrate = baudrate;
dev_add_param_uint32(dev, "baudrate", console_baudrate_set,
NULL, &newcdev->baudrate_param, "%u", newcdev);
}
@@ -349,11 +354,6 @@ int console_register(struct console_device *newcdev)
activate = 1;
}
- if (newcdev->dev && of_device_is_stdout_path(newcdev->dev)) {
- activate = 1;
- console_set_stdoutpath(newcdev);
- }
-
list_add_tail(&newcdev->list, &console_list);
if (activate)
diff --git a/common/deep-probe.c b/common/deep-probe.c
new file mode 100644
index 0000000000..1020ad93b7
--- /dev/null
+++ b/common/deep-probe.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <deep-probe.h>
+#include <of.h>
+
+enum deep_probe_state {
+ DEEP_PROBE_UNKONWN = -1,
+ DEEP_PROBE_NOT_SUPPORTED,
+ DEEP_PROBE_SUPPORTED
+};
+
+static enum deep_probe_state boardstate = DEEP_PROBE_UNKONWN;
+
+bool deep_probe_is_supported(void)
+{
+ struct deep_probe_entry *board;
+
+ if (boardstate > DEEP_PROBE_UNKONWN)
+ return boardstate;
+
+ /* determine boardstate */
+ for (board = &__barebox_deep_probe_start;
+ board != &__barebox_deep_probe_end; board++) {
+ const struct of_device_id *matches = board->device_id;
+
+ for (; matches->compatible; matches++) {
+ if (of_machine_is_compatible(matches->compatible)) {
+ boardstate = DEEP_PROBE_SUPPORTED;
+ printk("Deep probe supported due to %s\n", matches->compatible);
+ return true;
+ }
+ }
+ }
+
+ boardstate = DEEP_PROBE_NOT_SUPPORTED;
+ return false;
+}
+EXPORT_SYMBOL_GPL(deep_probe_is_supported);
diff --git a/common/efi/efi.c b/common/efi/efi.c
index 01003dc00f..7f12342cf9 100644
--- a/common/efi/efi.c
+++ b/common/efi/efi.c
@@ -437,7 +437,7 @@ static int efi_late_init(void)
return -EINVAL;
}
- root = of_unflatten_dtb(fdt);
+ root = of_unflatten_dtb(fdt, size);
free(fdt);
diff --git a/common/firmware.c b/common/firmware.c
index 58509d5da6..b33acff77f 100644
--- a/common/firmware.c
+++ b/common/firmware.c
@@ -11,9 +11,13 @@
#include <libbb.h>
#include <libfile.h>
#include <fs.h>
+#include <globalvar.h>
+#include <magicvar.h>
#include <linux/list.h>
#include <linux/stat.h>
#include <linux/err.h>
+#include <uncompress.h>
+#include <filetype.h>
#define BUFSIZ 4096
@@ -61,13 +65,25 @@ struct firmware_mgr *firmwaremgr_find(const char *id)
* 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 *firmwaremgr_find_by_node(struct device_node *np)
{
struct firmware_mgr *mgr;
+ char *na, *nb;
- list_for_each_entry(mgr, &firmwaremgr_list, list)
- if (mgr->handler->dev->parent->device_node == np)
+ na = of_get_reproducible_name(np);
+
+ list_for_each_entry(mgr, &firmwaremgr_list, list) {
+ nb = of_get_reproducible_name(mgr->handler->device_node);
+ if (!strcmp(na, nb)) {
+ free(na);
+ free(nb);
return mgr;
+ }
+
+ free(nb);
+ }
+
+ free(na);
return NULL;
}
@@ -206,17 +222,96 @@ out:
return ret;
}
+static char *firmware_path;
+
+const char *firmware_get_searchpath(void)
+{
+ return firmware_path;
+}
+
+void firmware_set_searchpath(const char *path)
+{
+ free(firmware_path);
+ firmware_path = strdup(path);
+}
+
+static bool file_exists(const char *filename)
+{
+ struct stat s;
+
+ return !stat(filename, &s);
+}
+
/*
* firmware_load_file - load a firmware to a device
*/
int firmwaremgr_load_file(struct firmware_mgr *mgr, const char *firmware)
{
- int ret;
- char *name = basprintf("/dev/%s", mgr->handler->id);
+ char *dst;
+ enum filetype type;
+ int ret = 0;
+ char *fw = NULL;
+ int firmwarefd = 0;
+ int devicefd = 0;
+
+ if (!firmware)
+ return -EINVAL;
+
+ if (!mgr->handler->id) {
+ pr_err("id not defined for handler\n");
+ return -ENODEV;
+ }
+
+ dst = basprintf("/dev/%s", mgr->handler->id);
+
+ if (*firmware != '/') {
+ fw = find_path(firmware_path, firmware, file_exists);
+ if (fw)
+ firmware = fw;
+ }
+
+ firmwarefd = open(firmware, O_RDONLY);
+ if (firmwarefd < 0) {
+ printf("could not open %s: %s\n", firmware,
+ errno_str());
+ ret = firmwarefd;
+ goto out;
+ }
+
+ type = file_name_detect_type(firmware);
- ret = copy_file(firmware, name, 0);
+ devicefd = open(dst, O_WRONLY);
+ if (devicefd < 0) {
+ printf("could not open %s: %s\n", dst, errno_str());
+ ret = devicefd;
+ goto out;
+ }
- free(name);
+ if (file_is_compressed_file(type))
+ ret = uncompress_fd_to_fd(firmwarefd, devicefd,
+ uncompress_err_stdout);
+ else
+ ret = copy_fd(firmwarefd, devicefd);
+
+out:
+ free(dst);
+ free(fw);
+
+ if (firmwarefd > 0)
+ close(firmwarefd);
+ if (devicefd > 0)
+ close(devicefd);
return ret;
}
+
+static int firmware_init(void)
+{
+ firmware_path = strdup("/env/firmware");
+ globalvar_add_simple_string("firmware.path", &firmware_path);
+
+ return 0;
+}
+device_initcall(firmware_init);
+
+BAREBOX_MAGICVAR(global.firmware.path, "Firmware search path");
diff --git a/common/image-fit.c b/common/image-fit.c
index 2c5ef7f687..c1a34a4405 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -754,7 +754,7 @@ static int fit_do_open(struct fit_handle *handle)
const char *desc = "(no description)";
struct device_node *root;
- root = of_unflatten_dtb_const(handle->fit);
+ root = of_unflatten_dtb_const(handle->fit, handle->size);
if (IS_ERR(root))
return PTR_ERR(root);
diff --git a/common/oftree.c b/common/oftree.c
index 1fcc5277c5..962fff244d 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -343,6 +343,8 @@ int of_fix_tree(struct device_node *node)
struct of_fixup *of_fixup;
int ret;
+ of_overlay_load_firmware_clear();
+
list_for_each_entry(of_fixup, &of_fixup_list, list) {
ret = of_fixup->fixup(node, of_fixup->context);
if (ret)
@@ -370,7 +372,7 @@ struct fdt_header *of_get_fixed_tree(struct device_node *node)
if (!node)
return NULL;
- freenp = node = of_copy_node(NULL, node);
+ freenp = node = of_dup(node);
if (!node)
return NULL;
}
diff --git a/common/state/backend_format_dtb.c b/common/state/backend_format_dtb.c
index 48f30db1f5..d0fc948859 100644
--- a/common/state/backend_format_dtb.c
+++ b/common/state/backend_format_dtb.c
@@ -59,7 +59,7 @@ static int state_backend_format_dtb_verify(struct state_backend_format *format,
fdtb->root = NULL;
}
- root = of_unflatten_dtb(buf);
+ root = of_unflatten_dtb(buf, dtb_len);
if (IS_ERR(root)) {
dev_err(fdtb->dev, "Failed to unflatten dtb from buffer with length %zd, %ld\n",
len, PTR_ERR(root));