summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2019-05-06 19:23:28 -0700
committerPatrick Georgi <pgeorgi@google.com>2019-06-04 11:24:01 +0000
commit6d5695fac53f52e1f389f420b5428e92de5b8c9c (patch)
tree9a29412f481ab43a21ffbe4c86190e448113f632
parentfbec63d15f761e01c934078570acbef779e707ba (diff)
downloadcoreboot-6d5695fac53f52e1f389f420b5428e92de5b8c9c.tar.xz
device_tree: Add support for aliases
This patch adds support to lookup nodes via the "/aliases" mechanism in device trees. This may be required for overlay support (don't quite remember tbh) and is also just a generally useful feature. It was adapted from depthcharge's http://crosreview.com/1249703 and http://crosreview.com/1542702. Change-Id: I1289ab2f02c4877a2d0111040384827e2b48a34a Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/32866 Reviewed-by: Hung-Te Lin <hungte@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r--src/include/device_tree.h3
-rw-r--r--src/lib/device_tree.c86
2 files changed, 77 insertions, 12 deletions
diff --git a/src/include/device_tree.h b/src/include/device_tree.h
index 6eaeacd6f0..e3723c86ac 100644
--- a/src/include/device_tree.h
+++ b/src/include/device_tree.h
@@ -146,6 +146,9 @@ struct device_tree_node *dt_find_node_by_phandle(struct device_tree_node *root,
// represented as a string of '/' separated node names.
struct device_tree_node *dt_find_node_by_path(struct device_tree *tree,
const char *path, u32 *addrcp, u32 *sizecp, int create);
+// Look up a node through an alias.
+struct device_tree_node *dt_find_node_by_alias(struct device_tree *tree,
+ const char *alias);
// Look up a node relative to a parent node, through its compatible string.
struct device_tree_node *dt_find_compat(struct device_tree_node *parent, const char *compatible);
// Look up the next child of a parent node, through its compatible string. It
diff --git a/src/lib/device_tree.c b/src/lib/device_tree.c
index e26021e9ee..bbcd7c06f6 100644
--- a/src/lib/device_tree.c
+++ b/src/lib/device_tree.c
@@ -564,27 +564,65 @@ struct device_tree_node *dt_find_node(struct device_tree_node *parent,
* @param create 1: Create node(s) if not found. 0: Return NULL instead.
* @return The found/created node, or NULL.
*
- * It is the caller responsibility to provide the correct path string, namely
- * starting with a '/', not ending in a '/' and not having "//" anywhere in it.
- */
+ * It is the caller responsibility to provide a path string that doesn't end
+ * with a '/' and doesn't contain any "//". If the path does not start with a
+ * '/', the first segment is interpreted as an alias. */
struct device_tree_node *dt_find_node_by_path(struct device_tree *tree,
const char *path, u32 *addrcp,
u32 *sizecp, int create)
{
- char *dup_path = strdup(&path[1]); /* remove leading '/' */
+ char *sub_path;
+ char *duped_str;
+ struct device_tree_node *parent;
+ char *next_slash;
/* Hopefully enough depth for any node. */
const char *path_array[15];
int i;
- char *next_slash;
struct device_tree_node *node = NULL;
- if (!dup_path)
- return NULL;
+ if (path[0] == '/') { // regular path
+ if (path[1] == '\0') { // special case: "/" is root node
+ dt_read_cell_props(tree->root, addrcp, sizecp);
+ return tree->root;
+ }
- next_slash = dup_path;
- path_array[0] = dup_path;
- for (i = 1; i < (ARRAY_SIZE(path_array) - 1); i++) {
+ sub_path = duped_str = strdup(&path[1]);
+ if (!sub_path)
+ return NULL;
+
+ parent = tree->root;
+ } else { // alias
+ char *alias;
+
+ alias = duped_str = strdup(path);
+ if (!alias)
+ return NULL;
+
+ sub_path = strchr(alias, '/');
+ if (sub_path)
+ *sub_path = '\0';
+
+ parent = dt_find_node_by_alias(tree, alias);
+ if (!parent) {
+ printk(BIOS_DEBUG,
+ "Could not find node '%s', alias '%s' does not exist\n",
+ path, alias);
+ free(duped_str);
+ return NULL;
+ }
+
+ if (!sub_path) {
+ // it's just the alias, no sub-path
+ free(duped_str);
+ return parent;
+ }
+ sub_path++;
+ }
+
+ next_slash = sub_path;
+ path_array[0] = sub_path;
+ for (i = 1; i < (ARRAY_SIZE(path_array) - 1); i++) {
next_slash = strchr(next_slash, '/');
if (!next_slash)
break;
@@ -595,14 +633,38 @@ struct device_tree_node *dt_find_node_by_path(struct device_tree *tree,
if (!next_slash) {
path_array[i] = NULL;
- node = dt_find_node(tree->root, path_array,
+ node = dt_find_node(parent, path_array,
addrcp, sizecp, create);
}
- free(dup_path);
+ free(duped_str);
return node;
}
+/*
+ * Find a node from an alias
+ *
+ * @param tree The device tree.
+ * @param alias The alias name.
+ * @return The found node, or NULL.
+ */
+struct device_tree_node *dt_find_node_by_alias(struct device_tree *tree,
+ const char *alias)
+{
+ struct device_tree_node *node;
+ const char *alias_path;
+
+ node = dt_find_node_by_path(tree, "/aliases", NULL, NULL, 0);
+ if (!node)
+ return NULL;
+
+ alias_path = dt_find_string_prop(node, alias);
+ if (!alias_path)
+ return NULL;
+
+ return dt_find_node_by_path(tree, alias_path, NULL, NULL, 0);
+}
+
struct device_tree_node *dt_find_node_by_phandle(struct device_tree_node *root,
uint32_t phandle)
{