summaryrefslogtreecommitdiffstats
path: root/common/oftree.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/oftree.c')
-rw-r--r--common/oftree.c228
1 files changed, 193 insertions, 35 deletions
diff --git a/common/oftree.c b/common/oftree.c
index 09cb660212..c12b3cfb16 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <environment.h>
#include <fdt.h>
@@ -14,6 +16,9 @@
#include <bootsource.h>
#include <i2c/i2c.h>
#include <reset_source.h>
+#include <watchdog.h>
+#include <globalvar.h>
+#include <magicvar.h>
#define MAX_LEVEL 32 /* how deeply nested we will go */
@@ -113,20 +118,16 @@ void of_print_cmdline(struct device_node *root)
cmdline = of_get_property(node, "bootargs", NULL);
- printf("commandline: %s\n", cmdline);
+ pr_info("commandline: %s\n", cmdline);
}
static int of_fixup_bootargs_bootsource(struct device_node *root,
struct device_node *chosen)
{
- char *alias_name = bootsource_get_alias_name();
struct device_node *bootsource;
int ret = 0;
- if (!alias_name)
- return 0;
-
- bootsource = of_find_node_by_alias(root, alias_name);
+ bootsource = bootsource_of_node_get(root);
/*
* If kernel DTB doesn't have the appropriate alias set up,
* give up and exit early. No error is reported.
@@ -135,29 +136,89 @@ static int of_fixup_bootargs_bootsource(struct device_node *root,
ret = of_set_property(chosen, "bootsource", bootsource->full_name,
strlen(bootsource->full_name) + 1, true);
- free(alias_name);
return ret;
}
-static int of_fixup_bootargs(struct device_node *root, void *unused)
+static void watchdog_build_bootargs(struct watchdog *watchdog, struct device_node *root)
+{
+ int alias_id;
+ char *buf;
+
+ if (!watchdog)
+ return;
+
+ alias_id = watchdog_get_alias_id_from(watchdog, root);
+ if (alias_id < 0)
+ return;
+
+ buf = basprintf("systemd.watchdog-device=/dev/watchdog%d", alias_id);
+ if (!buf)
+ return;
+
+ globalvar_add_simple("linux.bootargs.dyn.watchdog", buf);
+ free(buf);
+}
+
+static int bootargs_append = 0;
+BAREBOX_MAGICVAR(global.linux.bootargs_append, "append to original oftree bootargs");
+
+static int of_write_bootargs(struct device_node *node)
{
- struct device_node *node;
const char *str;
- int err;
- int instance = reset_source_get_instance();
- struct device_d *dev;
+ char *buf = NULL;
+ int ret;
+
+ if (IS_ENABLED(CONFIG_SYSTEMD_OF_WATCHDOG))
+ watchdog_build_bootargs(boot_get_enabled_watchdog(), of_get_parent(node));
str = linux_bootargs_get();
if (!str)
return 0;
+ str = skip_spaces(str);
+ if (strlen(str) == 0)
+ return 0;
+
+ if (bootargs_append) {
+ const char *oldstr;
+
+ ret = of_property_read_string(node, "bootargs", &oldstr);
+ if (!ret) {
+ str = buf = basprintf("%s %s", oldstr, str);
+ if (!buf)
+ return -ENOMEM;
+ }
+ }
+
+ ret = of_property_write_string(node, "bootargs", str);
+ free(buf);
+ return ret;
+}
+
+static int of_fixup_bootargs(struct device_node *root, void *unused)
+{
+ struct device_node *node;
+ int err;
+ int instance = reset_source_get_instance();
+ struct device *dev;
+ const char *serialno;
+ const char *compat;
+
+ serialno = barebox_get_serial_number();
+ if (serialno)
+ of_property_write_string(root, "serial-number", serialno);
+
+ compat = barebox_get_of_machine_compatible();
+ if (compat)
+ of_prepend_machine_compatible(root, compat);
+
node = of_create_node(root, "/chosen");
if (!node)
return -ENOMEM;
of_property_write_string(node, "barebox-version", release_string);
- err = of_property_write_string(node, "bootargs", str);
+ err = of_write_bootargs(node);
if (err)
return err;
@@ -167,10 +228,10 @@ static int of_fixup_bootargs(struct device_node *root, void *unused)
dev = reset_source_get_device();
- if (dev && dev->device_node) {
+ if (dev && dev->of_node) {
phandle phandle;
- phandle = of_node_create_phandle(dev->device_node);
+ phandle = of_node_create_phandle(dev->of_node);
err = of_property_write_u32(node,
"reset-source-device", phandle);
@@ -178,15 +239,76 @@ static int of_fixup_bootargs(struct device_node *root, void *unused)
return err;
}
- return of_fixup_bootargs_bootsource(root, node);
+ err = of_fixup_bootargs_bootsource(root, node);
+ if (err)
+ return err;
+
+ if (IS_ENABLED(CONFIG_RISCV)) {
+ const char *hartid;
+
+ hartid = getenv("global.hartid");
+ if (hartid) {
+ unsigned long id;
+
+ err = kstrtoul(hartid, 10, &id);
+ if (!err)
+ err = of_property_write_u32(node, "boot-hartid", id);
+ }
+ }
+
+ return err;
}
static int of_register_bootargs_fixup(void)
{
+ globalvar_add_simple_bool("linux.bootargs_append", &bootargs_append);
return of_register_fixup(of_fixup_bootargs, NULL);
}
late_initcall(of_register_bootargs_fixup);
+int of_fixup_reserved_memory(struct device_node *root, void *_res)
+{
+ struct resource *res = _res;
+ struct device_node *node, *child;
+ struct property *pp;
+ unsigned addr_n_cells = sizeof(void *) / sizeof(__be32),
+ size_n_cells = sizeof(void *) / sizeof(__be32);
+ unsigned rangelen = 0;
+ __be32 reg[4];
+ int ret;
+
+ node = of_get_child_by_name(root, "reserved-memory") ?: of_new_node(root, "reserved-memory");
+
+ ret = of_property_read_u32(node, "#address-cells", &addr_n_cells);
+ if (ret)
+ of_property_write_u32(node, "#address-cells", addr_n_cells);
+
+ ret = of_property_read_u32(node, "#size-cells", &size_n_cells);
+ if (ret)
+ of_property_write_u32(node, "#size-cells", size_n_cells);
+
+ pp = of_find_property(node, "ranges", &rangelen);
+ if (!pp) {
+ of_new_property(node, "ranges", NULL, 0);
+ } else if (rangelen) {
+ pr_warn("reserved-memory ranges not 1:1 mapped. Aborting fixup\n");
+ return -EINVAL;
+ }
+
+ child = of_get_child_by_name(node, res->name) ?: of_new_node(node, res->name);
+
+ if (res->flags & IORESOURCE_BUSY)
+ of_property_write_bool(child, "no-map", true);
+
+ of_write_number(reg, res->start, addr_n_cells);
+ of_write_number(reg + addr_n_cells, resource_size(res), size_n_cells);
+
+ of_set_property(child, "reg", reg,
+ (addr_n_cells + size_n_cells) * sizeof(*reg), true);
+
+ return 0;
+}
+
struct of_fixup_status_data {
const char *path;
bool status;
@@ -223,13 +345,12 @@ int of_register_set_status_fixup(const char *path, bool status)
return of_register_fixup(of_fixup_status, (void *)data);
}
-struct of_fixup {
- int (*fixup)(struct device_node *, void *);
- void *context;
- struct list_head list;
-};
+LIST_HEAD(of_fixup_list);
-static LIST_HEAD(of_fixup_list);
+static inline bool of_fixup_disabled(struct of_fixup *fixup)
+{
+ return fixup->disabled;
+}
int of_register_fixup(int (*fixup)(struct device_node *, void *), void *context)
{
@@ -266,19 +387,22 @@ int of_unregister_fixup(int (*fixup)(struct device_node *, void *),
* Apply registered fixups for the given fdt. The fdt must have
* enough free space to apply the fixups.
*/
-int of_fix_tree(struct device_node *node)
+void 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) {
+ if (of_fixup_disabled(of_fixup))
+ continue;
+
ret = of_fixup->fixup(node, of_fixup->context);
if (ret)
pr_warn("Failed to fixup node in %pS: %s\n",
of_fixup->fixup, strerror(-ret));
}
-
- return 0;
}
/*
@@ -287,10 +411,10 @@ int of_fix_tree(struct device_node *node)
* It increases the size of the tree and applies the registered
* fixups.
*/
-struct fdt_header *of_get_fixed_tree(struct device_node *node)
+struct fdt_header *of_get_fixed_tree(const struct device_node *node)
{
- int ret;
- struct fdt_header *fdt;
+ struct fdt_header *fdt = NULL;
+ struct device_node *np;
if (!node) {
node = of_get_root_node();
@@ -298,14 +422,17 @@ struct fdt_header *of_get_fixed_tree(struct device_node *node)
return NULL;
}
- ret = of_fix_tree(node);
- if (ret)
- return NULL;
+ np = of_dup(node);
- fdt = of_flatten_dtb(node);
- if (!fdt)
+ if (!np)
return NULL;
+ of_fix_tree(np);
+
+ fdt = of_flatten_dtb(np);
+
+ of_delete_node(np);
+
return fdt;
}
@@ -323,7 +450,7 @@ int of_autoenable_device_by_path(char *path)
struct device_node *node;
int ret;
- node = of_find_node_by_name(NULL, path);
+ node = of_find_node_by_name_address(NULL, path);
if (!node)
node = of_find_node_by_path(path);
@@ -360,7 +487,7 @@ int of_autoenable_i2c_by_component(char *path)
if (!IS_ENABLED(CONFIG_I2C))
return -ENODEV;
- node = of_find_node_by_name(NULL, path);
+ node = of_find_node_by_name_address(NULL, path);
if (!node)
node = of_find_node_by_path(path);
if (!node)
@@ -396,3 +523,34 @@ int of_autoenable_i2c_by_component(char *path)
return ret;
}
+
+int of_prepend_machine_compatible(struct device_node *root, const char *compat)
+{
+ int cclen = 0, clen = strlen(compat) + 1;
+ const char *curcompat;
+ void *buf;
+
+ if (!root) {
+ root = of_get_root_node();
+ if (!root)
+ return -ENODEV;
+ }
+
+ if (of_device_is_compatible(root, compat))
+ return 0;
+
+ curcompat = of_get_property(root, "compatible", &cclen);
+
+ buf = xzalloc(cclen + clen);
+
+ memcpy(buf, compat, clen);
+
+ if (curcompat)
+ memcpy(buf + clen, curcompat, cclen);
+
+ of_set_property(root, "compatible", buf, cclen + clen, true);
+
+ free(buf);
+
+ return 0;
+}