diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Kconfig | 4 | ||||
-rw-r--r-- | common/Makefile | 1 | ||||
-rw-r--r-- | common/bbu.c | 27 | ||||
-rw-r--r-- | common/blspec.c | 99 | ||||
-rw-r--r-- | common/bootm.c | 4 | ||||
-rw-r--r-- | common/console.c | 20 | ||||
-rw-r--r-- | common/deep-probe.c | 39 | ||||
-rw-r--r-- | common/efi/efi.c | 2 | ||||
-rw-r--r-- | common/firmware.c | 109 | ||||
-rw-r--r-- | common/image-fit.c | 2 | ||||
-rw-r--r-- | common/oftree.c | 4 | ||||
-rw-r--r-- | common/state/backend_format_dtb.c | 2 |
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)); |