diff options
author | Julius Werner <jwerner@chromium.org> | 2019-05-06 19:23:28 -0700 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2019-06-04 11:24:01 +0000 |
commit | 6d5695fac53f52e1f389f420b5428e92de5b8c9c (patch) | |
tree | 9a29412f481ab43a21ffbe4c86190e448113f632 | |
parent | fbec63d15f761e01c934078570acbef779e707ba (diff) | |
download | coreboot-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.h | 3 | ||||
-rw-r--r-- | src/lib/device_tree.c | 86 |
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) { |