mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
xen/arm: Add helpers to use the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
1 parent
fb97eb614a
commit
dbd1243248
2 files changed
+282
-33
No files matched your search
+144
-18
@@ -72,7 +72,8 @@ static LIST_HEAD(aliases_lookup);
|
||||
# define dt_dprintk(fmt, args...) do {} while ( 0 )
|
||||
#endif
|
||||
|
||||
bool_t device_tree_node_matches(const void *fdt, int node, const char *match)
|
||||
bool_t __init device_tree_node_matches(const void *fdt, int node,
|
||||
const char *match)
|
||||
{
|
||||
const char *name;
|
||||
size_t match_len;
|
||||
@@ -86,7 +87,8 @@ bool_t device_tree_node_matches(const void *fdt, int node, const char *match)
|
||||
&& (name[match_len] == '@' || name[match_len] == '\0');
|
||||
}
|
||||
|
||||
bool_t device_tree_type_matches(const void *fdt, int node, const char *match)
|
||||
bool_t __init device_tree_type_matches(const void *fdt, int node,
|
||||
const char *match)
|
||||
{
|
||||
const void *prop;
|
||||
|
||||
@@ -94,20 +96,24 @@ bool_t device_tree_type_matches(const void *fdt, int node, const char *match)
|
||||
if ( prop == NULL )
|
||||
return 0;
|
||||
|
||||
return !strcmp(prop, match);
|
||||
return !dt_node_cmp(prop, match);
|
||||
}
|
||||
|
||||
bool_t device_tree_node_compatible(const void *fdt, int node, const char *match)
|
||||
bool_t __init device_tree_node_compatible(const void *fdt, int node,
|
||||
const char *match)
|
||||
{
|
||||
int len, l;
|
||||
int mlen;
|
||||
const void *prop;
|
||||
|
||||
mlen = strlen(match);
|
||||
|
||||
prop = fdt_getprop(fdt, node, "compatible", &len);
|
||||
if ( prop == NULL )
|
||||
return 0;
|
||||
|
||||
while ( len > 0 ) {
|
||||
if ( !strcmp(prop, match) )
|
||||
if ( !dt_compat_cmp(prop, match, mlen) )
|
||||
return 1;
|
||||
l = strlen(prop) + 1;
|
||||
prop += l;
|
||||
@@ -117,7 +123,7 @@ bool_t device_tree_node_compatible(const void *fdt, int node, const char *match)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int device_tree_nr_reg_ranges(const struct fdt_property *prop,
|
||||
static __init int device_tree_nr_reg_ranges(const struct fdt_property *prop,
|
||||
u32 address_cells, u32 size_cells)
|
||||
{
|
||||
u32 reg_cells = address_cells + size_cells;
|
||||
@@ -138,14 +144,14 @@ static void __init get_val(const u32 **cell, u32 cells, u64 *val)
|
||||
}
|
||||
}
|
||||
|
||||
void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells,
|
||||
u64 *start, u64 *size)
|
||||
void __init device_tree_get_reg(const u32 **cell, u32 address_cells,
|
||||
u32 size_cells, u64 *start, u64 *size)
|
||||
{
|
||||
get_val(cell, address_cells, start);
|
||||
get_val(cell, size_cells, size);
|
||||
}
|
||||
|
||||
static void set_val(u32 **cell, u32 cells, u64 val)
|
||||
static void __init set_val(u32 **cell, u32 cells, u64 val)
|
||||
{
|
||||
u32 c = cells;
|
||||
|
||||
@@ -157,15 +163,15 @@ static void set_val(u32 **cell, u32 cells, u64 val)
|
||||
(*cell) += cells;
|
||||
}
|
||||
|
||||
void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells,
|
||||
u64 start, u64 size)
|
||||
void __init device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells,
|
||||
u64 start, u64 size)
|
||||
{
|
||||
set_val(cell, address_cells, start);
|
||||
set_val(cell, size_cells, size);
|
||||
}
|
||||
|
||||
u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name,
|
||||
u32 dflt)
|
||||
u32 __init device_tree_get_u32(const void *fdt, int node, const char *prop_name,
|
||||
u32 dflt)
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
|
||||
@@ -187,8 +193,8 @@ u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name,
|
||||
* Returns 0 if all nodes were iterated over successfully. If @func
|
||||
* returns a value different from 0, that value is returned immediately.
|
||||
*/
|
||||
int device_tree_for_each_node(const void *fdt,
|
||||
device_tree_node_func func, void *data)
|
||||
int __init device_tree_for_each_node(const void *fdt,
|
||||
device_tree_node_func func, void *data)
|
||||
{
|
||||
int node;
|
||||
int depth;
|
||||
@@ -254,8 +260,8 @@ static int _find_compatible_node(const void *fdt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int find_compatible_node(const char *compatible, int *node, int *depth,
|
||||
u32 *address_cells, u32 *size_cells)
|
||||
int __init find_compatible_node(const char *compatible, int *node, int *depth,
|
||||
u32 *address_cells, u32 *size_cells)
|
||||
{
|
||||
int ret;
|
||||
struct find_compat c;
|
||||
@@ -327,7 +333,7 @@ static int dump_node(const void *fdt, int node, const char *name, int depth,
|
||||
* device_tree_dump - print a text representation of a device tree
|
||||
* @fdt: flat device tree to print
|
||||
*/
|
||||
void device_tree_dump(const void *fdt)
|
||||
void __init device_tree_dump(const void *fdt)
|
||||
{
|
||||
device_tree_for_each_node(fdt, dump_node, NULL);
|
||||
}
|
||||
@@ -579,6 +585,54 @@ const void *dt_get_property(const struct dt_device_node *np,
|
||||
return pp ? pp->value : NULL;
|
||||
}
|
||||
|
||||
bool_t dt_device_is_compatible(const struct dt_device_node *device,
|
||||
const char *compat)
|
||||
{
|
||||
const char* cp;
|
||||
u32 cplen, l;
|
||||
|
||||
cp = dt_get_property(device, "compatible", &cplen);
|
||||
if ( cp == NULL )
|
||||
return 0;
|
||||
while ( cplen > 0 )
|
||||
{
|
||||
if ( dt_compat_cmp(cp, compat, strlen(compat)) == 0 )
|
||||
return 1;
|
||||
l = strlen(cp) + 1;
|
||||
cp += l;
|
||||
cplen -= l;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool_t dt_machine_is_compatible(const char *compat)
|
||||
{
|
||||
const struct dt_device_node *root;
|
||||
bool_t rc = 0;
|
||||
|
||||
root = dt_find_node_by_path("/");
|
||||
if ( root )
|
||||
{
|
||||
rc = dt_device_is_compatible(root, compat);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from,
|
||||
const char *name)
|
||||
{
|
||||
struct dt_device_node *np;
|
||||
struct dt_device_node *dt;
|
||||
|
||||
dt = from ? from->allnext : dt_host;
|
||||
for_each_device_node(dt, np)
|
||||
if ( np->name && (dt_node_cmp(np->name, name) == 0) )
|
||||
break;
|
||||
|
||||
return np;
|
||||
}
|
||||
|
||||
struct dt_device_node *dt_find_node_by_path(const char *path)
|
||||
{
|
||||
struct dt_device_node *np;
|
||||
@@ -590,6 +644,78 @@ struct dt_device_node *dt_find_node_by_path(const char *path)
|
||||
return np;
|
||||
}
|
||||
|
||||
struct dt_device_node *dt_find_node_by_alias(const char *alias)
|
||||
{
|
||||
const struct dt_alias_prop *app;
|
||||
|
||||
list_for_each_entry( app, &aliases_lookup, link )
|
||||
{
|
||||
if ( !strcmp(app->alias, alias) )
|
||||
return app->np;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct dt_device_node *dt_get_parent(const struct dt_device_node *node)
|
||||
{
|
||||
if ( !node )
|
||||
return NULL;
|
||||
|
||||
return node->parent;
|
||||
}
|
||||
|
||||
struct dt_device_node *
|
||||
dt_find_compatible_node(struct dt_device_node *from,
|
||||
const char *type,
|
||||
const char *compatible)
|
||||
{
|
||||
struct dt_device_node *np;
|
||||
struct dt_device_node *dt;
|
||||
|
||||
dt = from ? from->allnext : dt_host;
|
||||
for_each_device_node(dt, np)
|
||||
{
|
||||
if ( type
|
||||
&& !(np->type && (dt_node_cmp(np->type, type) == 0)) )
|
||||
continue;
|
||||
if ( dt_device_is_compatible(np, compatible) )
|
||||
break;
|
||||
}
|
||||
|
||||
return np;
|
||||
}
|
||||
|
||||
int dt_n_addr_cells(const struct dt_device_node *np)
|
||||
{
|
||||
const __be32 *ip;
|
||||
|
||||
do {
|
||||
if ( np->parent )
|
||||
np = np->parent;
|
||||
ip = dt_get_property(np, "#address-cells", NULL);
|
||||
if ( ip )
|
||||
return be32_to_cpup(ip);
|
||||
} while ( np->parent );
|
||||
/* No #address-cells property for the root node */
|
||||
return DT_ROOT_NODE_ADDR_CELLS_DEFAULT;
|
||||
}
|
||||
|
||||
int dt_n_size_cells(const struct dt_device_node *np)
|
||||
{
|
||||
const __be32 *ip;
|
||||
|
||||
do {
|
||||
if ( np->parent )
|
||||
np = np->parent;
|
||||
ip = dt_get_property(np, "#size-cells", NULL);
|
||||
if ( ip )
|
||||
return be32_to_cpup(ip);
|
||||
} while ( np->parent );
|
||||
/* No #address-cells property for the root node */
|
||||
return DT_ROOT_NODE_SIZE_CELLS_DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* unflatten_dt_node - Alloc and populate a device_node from the flat tree
|
||||
* @fdt: The parent device tree blob
|
||||
|
||||
+138
-15
@@ -107,22 +107,25 @@ typedef int (*device_tree_node_func)(const void *fdt,
|
||||
extern struct dt_early_info early_info;
|
||||
extern void *device_tree_flattened;
|
||||
|
||||
size_t device_tree_early_init(const void *fdt);
|
||||
size_t __init device_tree_early_init(const void *fdt);
|
||||
|
||||
void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells,
|
||||
u64 *start, u64 *size);
|
||||
void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells,
|
||||
u64 start, u64 size);
|
||||
u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name,
|
||||
u32 dflt);
|
||||
bool_t device_tree_node_matches(const void *fdt, int node, const char *match);
|
||||
bool_t device_tree_node_compatible(const void *fdt, int node, const char *match);
|
||||
int find_compatible_node(const char *compatible, int *node, int *depth,
|
||||
u32 *address_cells, u32 *size_cells);
|
||||
int device_tree_for_each_node(const void *fdt,
|
||||
device_tree_node_func func, void *data);
|
||||
const char *device_tree_bootargs(const void *fdt);
|
||||
void device_tree_dump(const void *fdt);
|
||||
void __init device_tree_get_reg(const u32 **cell, u32 address_cells,
|
||||
u32 size_cells,
|
||||
u64 *start, u64 *size);
|
||||
void __init device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells,
|
||||
u64 start, u64 size);
|
||||
u32 __init device_tree_get_u32(const void *fdt, int node,
|
||||
const char *prop_name, u32 dflt);
|
||||
bool_t __init device_tree_node_matches(const void *fdt, int node,
|
||||
const char *match);
|
||||
bool_t __init device_tree_node_compatible(const void *fdt, int node,
|
||||
const char *match);
|
||||
int __init find_compatible_node(const char *compatible, int *node, int *depth,
|
||||
u32 *address_cells, u32 *size_cells);
|
||||
int __init device_tree_for_each_node(const void *fdt,
|
||||
device_tree_node_func func, void *data);
|
||||
const char __init *device_tree_bootargs(const void *fdt);
|
||||
void __init device_tree_dump(const void *fdt);
|
||||
|
||||
/**
|
||||
* dt_unflatten_host_device_tree - Unflatten the host device tree
|
||||
@@ -141,17 +144,72 @@ extern struct dt_device_node *dt_host;
|
||||
#define dt_node_cmp(s1, s2) strcmp((s1), (s2))
|
||||
#define dt_compat_cmp(s1, s2, l) strnicmp((s1), (s2), l)
|
||||
|
||||
/* Default #address and #size cells */
|
||||
#define DT_ROOT_NODE_ADDR_CELLS_DEFAULT 1
|
||||
#define DT_ROOT_NODE_SIZE_CELLS_DEFAULT 1
|
||||
|
||||
#define for_each_property_of_node(dn, pp) \
|
||||
for ( pp = dn->properties; pp != NULL; pp = pp->next )
|
||||
|
||||
#define for_each_device_node(dt, dn) \
|
||||
for ( dn = dt; dn != NULL; dn = dn->allnext )
|
||||
|
||||
/* Helper to read a big number; size is in cells (not bytes) */
|
||||
static inline u64 dt_read_number(const __be32 *cell, int size)
|
||||
{
|
||||
u64 r = 0;
|
||||
|
||||
while ( size-- )
|
||||
r = (r << 32) | be32_to_cpu(*(cell++));
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline const char *dt_node_full_name(const struct dt_device_node *np)
|
||||
{
|
||||
return (np && np->full_name) ? np->full_name : "<no-node>";
|
||||
}
|
||||
|
||||
static inline const char *dt_node_name(const struct dt_device_node *np)
|
||||
{
|
||||
return (np && np->name) ? np->name : "<no-node>";
|
||||
}
|
||||
|
||||
static inline bool_t
|
||||
dt_device_type_is_equal(const struct dt_device_node *device,
|
||||
const char *type)
|
||||
{
|
||||
return !dt_node_cmp(device->type, type);
|
||||
}
|
||||
|
||||
static inline void dt_device_set_used_by(struct dt_device_node *device,
|
||||
domid_t used_by)
|
||||
{
|
||||
/* TODO: children must inherit to the used_by thing */
|
||||
device->used_by = used_by;
|
||||
}
|
||||
|
||||
static inline domid_t dt_device_used_by(const struct dt_device_node *device)
|
||||
{
|
||||
return device->used_by;
|
||||
}
|
||||
|
||||
/**
|
||||
* dt_find_compatible_node - Find a node based on type and one of the
|
||||
* tokens in its "compatible" property
|
||||
* @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.
|
||||
* @type: The type string to match "device_type" or NULL to ignore
|
||||
* @compatible: The string to match to one of the tokens in the device
|
||||
* "compatible" list.
|
||||
*
|
||||
* Returns a node pointer.
|
||||
*/
|
||||
struct dt_device_node *dt_find_compatible_node(struct dt_device_node *from,
|
||||
const char *type,
|
||||
const char *compatible);
|
||||
|
||||
/**
|
||||
* Find a property with a given name for a given node
|
||||
* and return the value.
|
||||
@@ -159,6 +217,44 @@ static inline const char *dt_node_full_name(const struct dt_device_node *np)
|
||||
const void *dt_get_property(const struct dt_device_node *np,
|
||||
const char *name, u32 *lenp);
|
||||
|
||||
/**
|
||||
* Checks if the given "compat" string matches one of the strings in
|
||||
* the device's "compatible" property
|
||||
*/
|
||||
bool_t dt_device_is_compatible(const struct dt_device_node *device,
|
||||
const char *compat);
|
||||
|
||||
/**
|
||||
* dt_machine_is_compatible - Test root of device tree for a given compatible value
|
||||
* @compat: compatible string to look for in root node's compatible property.
|
||||
*
|
||||
* Returns true if the root node has the given value in its
|
||||
* compatible property.
|
||||
*/
|
||||
bool_t dt_machine_is_compatible(const char *compat);
|
||||
|
||||
/**
|
||||
* dt_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
|
||||
* will; typically, you pass what the previous call
|
||||
* returned. of_node_put() will be called on it
|
||||
* @name: The name string to match against
|
||||
*
|
||||
* Returns a node pointer with refcount incremented, use
|
||||
* of_node_put() on it when done.
|
||||
*/
|
||||
struct dt_device_node *dt_find_node_by_name(struct dt_device_node *node,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* df_find_node_by_alias - Find a node matching an alias
|
||||
* @alias: The alias to match
|
||||
*
|
||||
* Returns a node pointer.
|
||||
*/
|
||||
struct dt_device_node *dt_find_node_by_alias(const char *alias);
|
||||
|
||||
/**
|
||||
* dt_find_node_by_path - Find a node matching a full DT path
|
||||
* @path: The full path to match
|
||||
@@ -166,4 +262,31 @@ const void *dt_get_property(const struct dt_device_node *np,
|
||||
* Returns a node pointer.
|
||||
*/
|
||||
struct dt_device_node *dt_find_node_by_path(const char *path);
|
||||
|
||||
/**
|
||||
* dt_get_parent - Get a node's parent if any
|
||||
* @node: Node to get parent
|
||||
*
|
||||
* Returns a node pointer.
|
||||
*/
|
||||
const struct dt_device_node *dt_get_parent(const struct dt_device_node *node);
|
||||
|
||||
/**
|
||||
* dt_n_size_cells - Helper to retrieve the number of cell for the size
|
||||
* @np: node to get the value
|
||||
*
|
||||
* This function retrieves for a give device-tree node the number of
|
||||
* cell for the size field.
|
||||
*/
|
||||
int dt_n_size_cells(const struct dt_device_node *np);
|
||||
|
||||
/**
|
||||
* dt_n_addr_cells - Helper to retrieve the number of cell for the address
|
||||
* @np: node to get the value
|
||||
*
|
||||
* This function retrieves for a give device-tree node the number of
|
||||
* cell for the address field.
|
||||
*/
|
||||
int dt_n_addr_cells(const struct dt_device_node *np);
|
||||
|
||||
#endif
|
||||