Patrick Georgi has submitted this change and it was merged. ( https://review.coreboot.org/c/coreboot/+/32866 )
Change subject: device_tree: Add support for aliases ......................................................................
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 --- M src/include/device_tree.h M src/lib/device_tree.c 2 files changed, 77 insertions(+), 12 deletions(-)
Approvals: build bot (Jenkins): Verified Hung-Te Lin: Looks good to me, approved
diff --git a/src/include/device_tree.h b/src/include/device_tree.h index 6eaeacd..e3723c8 100644 --- a/src/include/device_tree.h +++ b/src/include/device_tree.h @@ -146,6 +146,9 @@ // 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 e26021e..bbcd7c0 100644 --- a/src/lib/device_tree.c +++ b/src/lib/device_tree.c @@ -564,27 +564,65 @@ * @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; + 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 @@
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) {