summaryrefslogtreecommitdiffstats
path: root/drivers/of/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r--drivers/of/base.c557
1 files changed, 436 insertions, 121 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 42b8d24874..f0d3574148 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* base.c - basic devicetree functions
*
* Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
* based on Linux devicetree support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <common.h>
#include <deep-probe.h>
@@ -25,12 +17,43 @@
#include <linux/sizes.h>
#include <of_graph.h>
#include <string.h>
+#include <libfile.h>
+#include <linux/clk.h>
#include <linux/ctype.h>
-#include <linux/amba/bus.h>
#include <linux/err.h>
static struct device_node *root_node;
+/**
+ * of_node_has_prefix - Test if a node name has a given prefix
+ * @np: The node name to test
+ * @prefix: The prefix to see if @np starts with
+ *
+ * Returns:
+ * * strlen(@prefix) if @np starts with @prefix
+ * * 0 if @np does not start with @prefix
+ */
+size_t of_node_has_prefix(const struct device_node *np, const char *prefix)
+{
+ return np ? str_has_prefix(kbasename(np->full_name), prefix) : 0;
+}
+EXPORT_SYMBOL(of_node_has_prefix);
+
+bool of_node_name_eq(const struct device_node *np, const char *name)
+{
+ const char *node_name;
+ size_t len;
+
+ if (!np)
+ return false;
+
+ node_name = kbasename(np->full_name);
+ len = strchrnul(node_name, '@') - node_name;
+
+ return (strlen(name) == len) && (strncmp(node_name, name, len) == 0);
+}
+EXPORT_SYMBOL(of_node_name_eq);
+
/*
* Iterate over all nodes of a tree. As a devicetree does not
* have a dedicated list head, the start node (usually the root
@@ -146,8 +169,8 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np,
strncpy(ap->stem, stem, stem_len);
ap->stem[stem_len] = 0;
list_add_tail(&ap->link, &aliases_lookup);
- pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
- ap->alias, ap->stem, ap->id, np->full_name);
+ pr_debug("adding DT alias:%s: stem=%s id=%i node=%pOF\n",
+ ap->alias, ap->stem, ap->id, np);
}
static struct device_node *of_alias_resolve(struct device_node *root, struct property *pp)
@@ -179,8 +202,7 @@ static int of_alias_id_parse(const char *start, int *len)
* of_alias_scan - Scan all properties of 'aliases' node
*
* The function scans all the properties of 'aliases' node and populates
- * the global lookup table with the properties. It returns the
- * number of alias_prop found, or error code in error case.
+ * the global lookup table with the properties.
*/
void of_alias_scan(void)
{
@@ -524,7 +546,9 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
EXPORT_SYMBOL(of_get_cpu_node);
/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
+ * the device's "compatible" property. Returns 0 on mismatch and a
+ * positive score on match with the maximum being OF_DEVICE_COMPATIBLE_MAX_SCORE,
+ * which is only returned if the first compatible matched.
*/
int of_device_is_compatible(const struct device_node *device,
const char *compat)
@@ -537,7 +561,7 @@ int of_device_is_compatible(const struct device_node *device,
for (cp = of_prop_next_string(prop, NULL); cp;
cp = of_prop_next_string(prop, cp), index++) {
if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
- score = INT_MAX/2 - (index << 2);
+ score = OF_DEVICE_COMPATIBLE_MAX_SCORE - (index << 2);
break;
}
}
@@ -547,6 +571,29 @@ int of_device_is_compatible(const struct device_node *device,
EXPORT_SYMBOL(of_device_is_compatible);
/**
+ * of_find_node_by_name_address - Find a node by its full name
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned.
+ * @name: The name string to match against
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_node_by_name_address(struct device_node *from,
+ const char *name)
+{
+ struct device_node *np;
+
+ of_tree_for_each_node_from(np, from)
+ if (np->name && !of_node_cmp(np->name, name))
+ return np;
+
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_node_by_name_address);
+
+/**
* of_find_node_by_name - Find a node by its "name" property
* @from: The node to start searching from or NULL, the node
* you pass will not be searched, only the next one
@@ -562,7 +609,7 @@ struct device_node *of_find_node_by_name(struct device_node *from,
struct device_node *np;
of_tree_for_each_node_from(np, from)
- if (np->name && !of_node_cmp(np->name, name))
+ if (np->name && of_node_name_eq(np, name))
return np;
return NULL;
@@ -670,6 +717,9 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches,
if (score > best_score) {
best_match = matches;
best_score = score;
+
+ if (score == OF_DEVICE_COMPATIBLE_MAX_SCORE)
+ break;
}
}
@@ -710,11 +760,11 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from,
}
EXPORT_SYMBOL(of_find_matching_node_and_match);
-int of_match(struct device_d *dev, struct driver_d *drv)
+int of_match(struct device *dev, struct driver *drv)
{
const struct of_device_id *id;
- id = of_match_node(drv->of_compatible, dev->device_node);
+ id = of_match_node(drv->of_compatible, dev->of_node);
if (!id)
return 1;
@@ -803,7 +853,7 @@ int of_property_count_elems_of_size(const struct device_node *np,
if (!prop)
return -EINVAL;
- if (!prop->value)
+ if (!of_property_get_value(prop))
return -ENODATA;
if (prop->length % elem_size != 0) {
@@ -1020,7 +1070,7 @@ EXPORT_SYMBOL_GPL(of_property_read_string);
* This function searches a string list property and returns the index
* of a specific string value.
*/
-int of_property_match_string(struct device_node *np, const char *propname,
+int of_property_match_string(const struct device_node *np, const char *propname,
const char *string)
{
struct property *prop = of_find_property(np, propname, NULL);
@@ -1101,6 +1151,7 @@ EXPORT_SYMBOL_GPL(of_prop_next_string);
*
* @np: device node from which the property is to be set.
* @propname: name of the property to be set.
+ * @value true to set, false to delete
*
* Search for a property in a device node and create or delete the property.
* If the property already exists and write value is false, the property is
@@ -1443,15 +1494,13 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
*/
node = of_find_node_by_phandle(phandle);
if (!node) {
- pr_err("%s: could not find phandle\n",
- np->full_name);
+ pr_err("%pOF: could not find phandle\n", np);
goto err;
}
if (cells_name &&
of_property_read_u32(node, cells_name, &count)) {
- pr_err("%s: could not get %s for %s\n",
- np->full_name, cells_name,
- node->full_name);
+ pr_err("%pOF: could not get %s for %pOF\n",
+ np, cells_name, node);
goto err;
}
@@ -1460,8 +1509,7 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
* remaining property data length
*/
if (list + count > list_end) {
- pr_err("%s: arguments longer than property\n",
- np->full_name);
+ pr_err("%pOF: arguments longer than property\n", np);
goto err;
}
}
@@ -1727,7 +1775,7 @@ int barebox_register_of(struct device_node *root)
of_fix_tree(root);
if (IS_ENABLED(CONFIG_OFDEVICE)) {
- of_clk_init(root, NULL);
+ of_clk_init();
if (!deep_probe_is_supported())
return of_probe();
}
@@ -1961,9 +2009,9 @@ int of_property_read_string_helper(const struct device_node *np,
if (!prop)
return -EINVAL;
- if (!prop->value)
+ p = of_property_get_value(prop);
+ if (!p)
return -ENODATA;
- p = prop->value;
end = p + prop->length;
for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
@@ -1977,76 +2025,83 @@ int of_property_read_string_helper(const struct device_node *np,
return i <= 0 ? -ENODATA : i;
}
-static void __of_print_nodes(struct device_node *node, int indent, const char *prefix)
+static void __of_print_property_prefixed(const struct property *p, int indent,
+ unsigned maxpropsize, const char *prefix)
+{
+ unsigned length;
+
+ printf("%s%*s%s", prefix, indent * 8, "", p->name);
+
+ length = min_t(unsigned, p->length, maxpropsize);
+ if (length) {
+ printf(" = ");
+ of_print_property(of_property_get_value(p), length);
+ }
+ if (length != p->length)
+ printf(" /* %u more bytes omitted */", p->length - length);
+
+ printf(";\n");
+}
+
+static int __of_print_nodes(struct device_node *node, int indent,
+ unsigned maxpropsize, const char *prefix)
{
struct device_node *n;
struct property *p;
+ int ret;
if (!node)
- return;
+ return 0;
if (!prefix)
prefix = "";
printf("%s%*s%s%s\n", prefix, indent * 8, "", node->name, node->name ? " {" : "{");
- list_for_each_entry(p, &node->properties, list) {
- printf("%s%*s%s", prefix, (indent + 1) * 8, "", p->name);
- if (p->length) {
- printf(" = ");
- of_print_property(of_property_get_value(p), p->length);
- }
- printf(";\n");
- }
+ list_for_each_entry(p, &node->properties, list)
+ __of_print_property_prefixed(p, indent + 1, maxpropsize, prefix);
+
+ if (ctrlc())
+ return -EINTR;
list_for_each_entry(n, &node->children, parent_list) {
- __of_print_nodes(n, indent + 1, prefix);
+ ret = __of_print_nodes(n, indent + 1, maxpropsize, prefix);
+ if (ret)
+ return ret;
}
printf("%s%*s};\n", prefix, indent * 8, "");
+ return 0;
}
-void of_print_nodes(struct device_node *node, int indent)
+void of_print_nodes(struct device_node *node, int indent, unsigned maxpropsize)
{
- __of_print_nodes(node, indent, NULL);
+ __of_print_nodes(node, indent, maxpropsize, NULL);
}
-static void __of_print_property(struct property *p, int indent)
+static void __of_print_property(struct property *p, int indent, unsigned maxpropsize)
{
- int i;
-
- for (i = 0; i < indent; i++)
- printf("\t");
-
- printf("%s", p->name);
- if (p->length) {
- printf(" = ");
- of_print_property(of_property_get_value(p), p->length);
- }
- printf(";\n");
+ __of_print_property_prefixed(p, indent, maxpropsize, "");
}
-void of_print_properties(struct device_node *node)
+void of_print_properties(struct device_node *node, unsigned maxpropsize)
{
struct property *prop;
list_for_each_entry(prop, &node->properties, list)
- __of_print_property(prop, 0);
+ __of_print_property(prop, 0, maxpropsize);
}
static int __of_print_parents(struct device_node *node)
{
- int indent, i;
+ int indent;
if (!node->parent)
return 0;
indent = __of_print_parents(node->parent);
- for (i = 0; i < indent; i++)
- printf("\t");
-
- printf("%s {\n", node->name);
+ printf("%*s%s {\n", indent * 8, "", node->name);
return indent + 1;
}
@@ -2087,57 +2142,76 @@ static void of_print_close(struct device_node *node, int *printed)
* This function compares two device trees against each other and prints
* a diff-like result.
*/
-void of_diff(struct device_node *a, struct device_node *b, int indent)
+int of_diff(struct device_node *a, struct device_node *b, int indent)
{
struct property *ap, *bp;
struct device_node *ca, *cb;
- int printed = 0;
+ int printed = 0, diff = 0;
+ bool silent = indent < 0;
list_for_each_entry(ap, &a->properties, list) {
bp = of_find_property(b, ap->name, NULL);
if (!bp) {
+ diff++;
+ if (silent)
+ continue;
of_print_parents(a, &printed);
printf("- ");
- __of_print_property(ap, indent);
+ __of_print_property(ap, indent, ~0);
continue;
}
if (ap->length != bp->length || memcmp(of_property_get_value(ap), of_property_get_value(bp), bp->length)) {
+ diff++;
+ if (silent)
+ continue;
of_print_parents(a, &printed);
printf("- ");
- __of_print_property(ap, indent);
+ __of_print_property(ap, indent, ~0);
printf("+ ");
- __of_print_property(bp, indent);
+ __of_print_property(bp, indent, ~0);
}
}
list_for_each_entry(bp, &b->properties, list) {
ap = of_find_property(a, bp->name, NULL);
if (!ap) {
+ diff++;
+ if (silent)
+ continue;
of_print_parents(a, &printed);
printf("+ ");
- __of_print_property(bp, indent);
+ __of_print_property(bp, indent, ~0);
}
}
for_each_child_of_node(a, ca) {
cb = of_get_child_by_name(b, ca->name);
if (cb) {
- of_diff(ca, cb, indent + 1);
+ diff += of_diff(ca, cb, silent ? indent : indent + 1);
} else {
+ diff++;
+ if (silent)
+ continue;
of_print_parents(a, &printed);
- __of_print_nodes(ca, indent, "-");
+ __of_print_nodes(ca, indent, ~0, "- ");
}
}
for_each_child_of_node(b, cb) {
if (!of_get_child_by_name(a, cb->name)) {
+ diff++;
+ if (silent)
+ continue;
of_print_parents(a, &printed);
- __of_print_nodes(cb, indent, "+");
+ __of_print_nodes(cb, indent, ~0, "+ ");
}
}
- of_print_close(a, &printed);
+ if (!silent)
+ of_print_close(a, &printed);
+
+ return diff;
}
struct device_node *of_new_node(struct device_node *parent, const char *name)
@@ -2154,8 +2228,8 @@ struct device_node *of_new_node(struct device_node *parent, const char *name)
if (parent) {
node->name = xstrdup(name);
- node->full_name = basprintf("%s/%s",
- node->parent->full_name, name);
+ node->full_name = basprintf("%pOF/%s",
+ node->parent, name);
list_add(&node->list, &parent->list);
} else {
node->name = xstrdup("");
@@ -2166,6 +2240,21 @@ struct device_node *of_new_node(struct device_node *parent, const char *name)
return node;
}
+struct property *__of_new_property(struct device_node *node, const char *name,
+ void *data, int len)
+{
+ struct property *prop;
+
+ prop = xzalloc(sizeof(*prop));
+ prop->name = xstrdup(name);
+ prop->length = len;
+ prop->value = data;
+
+ list_add_tail(&prop->list, &node->properties);
+
+ return prop;
+}
+
/**
* of_new_property - Add a new property to a node
* @node: device node to which the property is added
@@ -2181,19 +2270,13 @@ struct device_node *of_new_node(struct device_node *parent, const char *name)
struct property *of_new_property(struct device_node *node, const char *name,
const void *data, int len)
{
- struct property *prop;
-
- prop = xzalloc(sizeof(*prop));
- prop->name = xstrdup(name);
- prop->length = len;
- prop->value = xzalloc(len);
+ char *buf;
+ buf = xzalloc(len);
if (data)
- memcpy(prop->value, data, len);
-
- list_add_tail(&prop->list, &node->properties);
+ memcpy(buf, data, len);
- return prop;
+ return __of_new_property(node, name, buf, len);
}
/**
@@ -2237,6 +2320,41 @@ void of_delete_property(struct property *pp)
free(pp);
}
+struct property *of_rename_property(struct device_node *np,
+ const char *old_name, const char *new_name)
+{
+ struct property *pp;
+
+ pp = of_find_property(np, old_name, NULL);
+ if (!pp)
+ return NULL;
+
+ of_property_write_bool(np, new_name, false);
+
+ free(pp->name);
+ pp->name = xstrdup(new_name);
+ return pp;
+}
+
+struct property *of_copy_property(const struct device_node *src,
+ const char *propname,
+ struct device_node *dst)
+{
+ struct property *prop;
+
+ prop = of_find_property(src, propname, NULL);
+ if (!prop)
+ return NULL;
+
+ if (of_property_present(dst, propname))
+ return ERR_PTR(-EEXIST);
+
+ return of_new_property(dst, propname,
+ of_property_get_value(prop), prop->length);
+}
+EXPORT_SYMBOL_GPL(of_copy_property);
+
+
/**
* of_set_property - create a property for a given node
* @node - the node
@@ -2265,6 +2383,99 @@ int of_set_property(struct device_node *np, const char *name, const void *val, i
return 0;
}
+int of_append_property(struct device_node *np, const char *name, const void *val, int len)
+{
+ struct property *pp;
+ int orig_len;
+ void *buf;
+
+ if (!np)
+ return -ENOENT;
+
+ pp = of_find_property(np, name, NULL);
+ if (!pp) {
+ of_new_property(np, name, val, len);
+ return 0;
+ }
+
+ orig_len = pp->length;
+ buf = realloc(pp->value, orig_len + len);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf + orig_len, val, len);
+
+ pp->value = buf;
+ pp->length += len;
+
+ if (pp->value_const) {
+ memcpy(buf, pp->value_const, orig_len);
+ pp->value_const = NULL;
+ }
+
+ return 0;
+}
+
+int of_prepend_property(struct device_node *np, const char *name, const void *val, int len)
+{
+ struct property *pp;
+ const void *oldval;
+ void *buf;
+ int oldlen;
+
+ pp = of_find_property(np, name, &oldlen);
+ if (!pp) {
+ of_new_property(np, name, val, len);
+ return 0;
+ }
+
+ oldval = of_property_get_value(pp);
+
+ buf = malloc(len + oldlen);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, val, len);
+ memcpy(buf + len, oldval, oldlen);
+
+ free(pp->value);
+ pp->value = buf;
+ pp->length = len + oldlen;
+ pp->value_const = NULL;
+
+ return 0;
+}
+
+int of_property_sprintf(struct device_node *np,
+ const char *propname, const char *fmt, ...)
+{
+ struct property *pp;
+ struct va_format vaf;
+ char *buf = NULL;
+ va_list args;
+ int len;
+
+ if (!np)
+ return -ENOENT;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+ len = asprintf(&buf, "%pV", &vaf);
+ va_end(args);
+
+ if (len < 0)
+ return -ENOMEM;
+
+ len++; /* trailing NUL */
+
+ pp = of_find_property(np, propname, NULL);
+ of_delete_property(pp);
+
+ __of_new_property(np, propname, buf, len);
+ return len;
+}
+
static int mem_bank_num;
int of_add_memory(struct device_node *node, bool dump)
@@ -2313,6 +2524,7 @@ const struct of_device_id of_default_bus_match_table[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, of_default_bus_match_table);
static int of_probe_memory(void)
{
@@ -2341,24 +2553,35 @@ mem_initcall(of_probe_memory);
static void of_platform_device_create_root(struct device_node *np)
{
- struct device_d *dev;
+ static struct device *dev;
int ret;
+ if (dev)
+ return;
+
dev = xzalloc(sizeof(*dev));
dev->id = DEVICE_ID_SINGLE;
- dev->device_node = np;
+ dev->of_node = np;
dev_set_name(dev, "machine");
ret = platform_device_register(dev);
if (ret)
- free(dev);
+ free_device(dev);
}
static const struct of_device_id reserved_mem_matches[] = {
{ .compatible = "nvmem-rmem" },
{}
};
+MODULE_DEVICE_TABLE(of, reserved_mem_matches);
+/**
+ * of_probe - Probe unflattened device tree starting at of_get_root_node
+ *
+ * The function walks the device tree and creates devices as needed.
+ * With care, it can be called more than once, but if you really need that,
+ * consider first if deep probe would help instead.
+ */
int of_probe(void)
{
struct device_node *node;
@@ -2367,6 +2590,12 @@ int of_probe(void)
return -ENODEV;
/*
+ * We do this first thing, so board drivers can patch the device
+ * tree prior to device creation if needed.
+ */
+ of_platform_device_create_root(root_node);
+
+ /*
* Handle certain compatibles explicitly, since we don't want to create
* platform_devices for every node in /reserved-memory with a
* "compatible",
@@ -2378,8 +2607,6 @@ int of_probe(void)
if (node)
of_platform_populate(node, NULL, NULL);
- of_platform_device_create_root(root_node);
-
of_platform_populate(root_node, of_default_bus_match_table, NULL);
return 0;
@@ -2429,25 +2656,35 @@ out:
return dn;
}
-struct device_node *of_copy_node(struct device_node *parent, const struct device_node *other)
+void of_merge_nodes(struct device_node *np, const struct device_node *other)
{
- struct device_node *np, *child;
+ struct device_node *child;
struct property *pp;
- np = of_new_node(parent, other->name);
- np->phandle = other->phandle;
-
list_for_each_entry(pp, &other->properties, list)
of_new_property(np, pp->name, pp->value, pp->length);
for_each_child_of_node(other, child)
of_copy_node(np, child);
+}
+
+struct device_node *of_copy_node(struct device_node *parent, const struct device_node *other)
+{
+ struct device_node *np;
+
+ np = of_new_node(parent, other->name);
+ np->phandle = other->phandle;
+
+ of_merge_nodes(np, other);
return np;
}
struct device_node *of_dup(const struct device_node *root)
{
+ if (IS_ERR_OR_NULL(root))
+ return ERR_CAST(root);
+
return of_copy_node(NULL, root);
}
@@ -2480,30 +2717,51 @@ void of_delete_node(struct device_node *node)
free(node);
}
-struct device_node *of_get_stdoutpath(unsigned int *baudrate)
-{
+/*
+ * of_find_node_by_chosen - Find a node given a chosen property pointing at it
+ * @propname: the name of the property containing a path or alias
+ * The function will lookup the first string in the property
+ * value up to the first : character or till \0.
+ * @options The Remainder (without : or \0 at the end) will be written
+ * to *options if not NULL.
+ */
+struct device_node *of_find_node_by_chosen(const char *propname,
+ const char **options)
+{
+ const char *value, *p;
+ char *buf;
struct device_node *dn;
- const char *name;
- const char *p;
- char *q;
- name = of_get_property(of_chosen, "stdout-path", NULL);
- if (!name)
- name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ value = of_get_property(of_chosen, propname, NULL);
+ if (!value)
+ return NULL;
- if (!name)
- return 0;
+ p = strchrnul(value, ':');
+ buf = xstrndup(value, p - value);
- p = strchrnul(name, ':');
+ dn = of_find_node_by_path_or_alias(NULL, buf);
- q = xstrndup(name, p - name);
+ free(buf);
+
+ if (options && *p)
+ *options = p + 1;
- dn = of_find_node_by_path_or_alias(NULL, q);
+ return dn;
+}
+
+struct device_node *of_get_stdoutpath(unsigned int *baudrate)
+{
+ const char *opts = NULL;
+ struct device_node *dn;
- free(q);
+ dn = of_find_node_by_chosen("stdout-path", &opts);
+ if (!dn)
+ dn = of_find_node_by_chosen("linux,stdout-path", &opts);
+ if (!dn)
+ return NULL;
- if (baudrate && *p) {
- unsigned rate = simple_strtoul(p + 1, NULL, 10);
+ if (baudrate && opts) {
+ unsigned rate = simple_strtoul(opts, NULL, 10);
if (rate)
*baudrate = rate;
}
@@ -2511,11 +2769,11 @@ struct device_node *of_get_stdoutpath(unsigned int *baudrate)
return dn;
}
-int of_device_is_stdout_path(struct device_d *dev, unsigned int *baudrate)
+int of_device_is_stdout_path(struct device *dev, unsigned int *baudrate)
{
unsigned int tmp = *baudrate;
- if (!dev || !dev->device_node || dev->device_node != of_get_stdoutpath(&tmp))
+ if (!dev || !dev->of_node || dev->of_node != of_get_stdoutpath(&tmp))
return false;
*baudrate = tmp;
@@ -2603,6 +2861,21 @@ int of_device_enable_path(const char *path)
}
/**
+ * of_device_enable_by_alias - enable a device node by alias
+ * @alias - the alias of the device tree node to enable
+ */
+int of_device_enable_by_alias(const char *alias)
+{
+ struct device_node *node;
+
+ node = of_find_node_by_alias(NULL, alias);
+ if (!node)
+ return -ENODEV;
+
+ return of_device_enable(node);
+}
+
+/**
* of_device_disable - disable a devicenode device
* @node - the node to disable
*
@@ -2646,6 +2919,37 @@ int of_device_disable_by_alias(const char *alias)
}
/**
+ * of_read_file - unflatten oftree file
+ * @filename - path to file to unflatten its contents
+ *
+ * Returns the root node of the tree or an error pointer on error.
+ */
+struct device_node *of_read_file(const char *filename)
+{
+ void *fdt;
+ size_t size;
+ struct device_node *root;
+
+ fdt = read_file(filename, &size);
+ if (!fdt) {
+ pr_err("unable to read %s: %m\n", filename);
+ return ERR_PTR(-errno);
+ }
+
+ if (IS_ENABLED(CONFIG_FILETYPE) && file_detect_type(fdt, size) != filetype_oftree) {
+ pr_err("%s is not a flat device tree file.\n", filename);
+ root = ERR_PTR(-EINVAL);
+ goto out;
+ }
+
+ root = of_unflatten_dtb(fdt, size);
+out:
+ free(fdt);
+
+ return root;
+}
+
+/**
* of_get_reproducible_name() - get a reproducible name of a node
* @node: The node to get a name from
*
@@ -2728,12 +3032,23 @@ struct device_node *of_find_node_by_reproducible_name(struct device_node *from,
return NULL;
}
+struct device_node *of_get_node_by_reproducible_name(struct device_node *dstroot,
+ struct device_node *srcnp)
+{
+ struct device_node *dstnp;
+ char *name;
+
+ name = of_get_reproducible_name(srcnp);
+ dstnp = of_find_node_by_reproducible_name(dstroot, name);
+ free(name);
+
+ return dstnp;
+}
+
/**
* of_graph_parse_endpoint() - parse common endpoint node properties
* @node: pointer to endpoint device_node
* @endpoint: pointer to the OF endpoint data structure
- *
- * The caller should hold a reference to @node.
*/
int of_graph_parse_endpoint(const struct device_node *node,
struct of_endpoint *endpoint)
@@ -2741,8 +3056,8 @@ int of_graph_parse_endpoint(const struct device_node *node,
struct device_node *port_node = of_get_parent(node);
if (!port_node)
- pr_warn("%s(): endpoint %s has no parent node\n",
- __func__, node->full_name);
+ pr_warn("%s(): endpoint %pOF has no parent node\n",
+ __func__, node);
memset(endpoint, 0, sizeof(*endpoint));
@@ -2814,15 +3129,15 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
port = of_get_child_by_name(parent, "port");
if (!port) {
- pr_err("%s(): no port node found in %s\n",
- __func__, parent->full_name);
+ pr_err("%s(): no port node found in %pOF\n",
+ __func__, parent);
return NULL;
}
} else {
port = of_get_parent(prev);
if (!port) {
- pr_warn("%s(): endpoint %s has no parent node\n",
- __func__, prev->full_name);
+ pr_warn("%s(): endpoint %pOF has no parent node\n",
+ __func__, prev);
return NULL;
}
}