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>
This commit is contained in:
parent
fbec63d15f
commit
6d5695fac5
|
@ -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.
|
// represented as a string of '/' separated node names.
|
||||||
struct device_tree_node *dt_find_node_by_path(struct device_tree *tree,
|
struct device_tree_node *dt_find_node_by_path(struct device_tree *tree,
|
||||||
const char *path, u32 *addrcp, u32 *sizecp, int create);
|
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.
|
// 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);
|
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
|
// Look up the next child of a parent node, through its compatible string. It
|
||||||
|
|
|
@ -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.
|
* @param create 1: Create node(s) if not found. 0: Return NULL instead.
|
||||||
* @return The found/created node, or NULL.
|
* @return The found/created node, or NULL.
|
||||||
*
|
*
|
||||||
* It is the caller responsibility to provide the correct path string, namely
|
* It is the caller responsibility to provide a path string that doesn't end
|
||||||
* starting with a '/', not ending in a '/' and not having "//" anywhere in it.
|
* 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,
|
struct device_tree_node *dt_find_node_by_path(struct device_tree *tree,
|
||||||
const char *path, u32 *addrcp,
|
const char *path, u32 *addrcp,
|
||||||
u32 *sizecp, int create)
|
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. */
|
/* Hopefully enough depth for any node. */
|
||||||
const char *path_array[15];
|
const char *path_array[15];
|
||||||
int i;
|
int i;
|
||||||
char *next_slash;
|
|
||||||
struct device_tree_node *node = NULL;
|
struct device_tree_node *node = NULL;
|
||||||
|
|
||||||
if (!dup_path)
|
if (path[0] == '/') { // regular path
|
||||||
return NULL;
|
if (path[1] == '\0') { // special case: "/" is root node
|
||||||
|
dt_read_cell_props(tree->root, addrcp, sizecp);
|
||||||
|
return tree->root;
|
||||||
|
}
|
||||||
|
|
||||||
next_slash = dup_path;
|
sub_path = duped_str = strdup(&path[1]);
|
||||||
path_array[0] = dup_path;
|
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++) {
|
for (i = 1; i < (ARRAY_SIZE(path_array) - 1); i++) {
|
||||||
|
|
||||||
next_slash = strchr(next_slash, '/');
|
next_slash = strchr(next_slash, '/');
|
||||||
if (!next_slash)
|
if (!next_slash)
|
||||||
break;
|
break;
|
||||||
|
@ -595,14 +633,38 @@ struct device_tree_node *dt_find_node_by_path(struct device_tree *tree,
|
||||||
|
|
||||||
if (!next_slash) {
|
if (!next_slash) {
|
||||||
path_array[i] = NULL;
|
path_array[i] = NULL;
|
||||||
node = dt_find_node(tree->root, path_array,
|
node = dt_find_node(parent, path_array,
|
||||||
addrcp, sizecp, create);
|
addrcp, sizecp, create);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(dup_path);
|
free(duped_str);
|
||||||
return node;
|
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,
|
struct device_tree_node *dt_find_node_by_phandle(struct device_tree_node *root,
|
||||||
uint32_t phandle)
|
uint32_t phandle)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue