279 lines
9.3 KiB
C
279 lines
9.3 KiB
C
/* Copyright 2013-2014 IBM Corp.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
* implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef __DEVICE_H
|
|
#define __DEVICE_H
|
|
#include <ccan/list/list.h>
|
|
#include <ccan/short_types/short_types.h>
|
|
#include <compiler.h>
|
|
|
|
/* Any property or node with this prefix will not be passed to the kernel. */
|
|
#define DT_PRIVATE "skiboot,"
|
|
|
|
/*
|
|
* An in-memory representation of a node in the device tree.
|
|
*
|
|
* This is trivially flattened into an fdt.
|
|
*
|
|
* Note that the add_* routines will make a copy of the name if it's not
|
|
* a read-only string (ie. usually a string literal).
|
|
*/
|
|
struct dt_property {
|
|
struct list_node list;
|
|
const char *name;
|
|
size_t len;
|
|
char prop[/* len */];
|
|
};
|
|
|
|
struct dt_node {
|
|
const char *name;
|
|
struct list_node list;
|
|
struct list_head properties;
|
|
struct list_head children;
|
|
struct dt_node *parent;
|
|
u32 phandle;
|
|
};
|
|
|
|
/* This is shared with device_tree.c .. make it static when
|
|
* the latter is gone (hopefully soon)
|
|
*/
|
|
extern u32 last_phandle;
|
|
|
|
extern struct dt_node *dt_root;
|
|
extern struct dt_node *dt_chosen;
|
|
|
|
/* Create a root node: ie. a parentless one. */
|
|
struct dt_node *dt_new_root(const char *name);
|
|
|
|
/* Graft a root node into this tree. */
|
|
bool dt_attach_root(struct dt_node *parent, struct dt_node *root);
|
|
|
|
/* Wrappers for last_phandle operations */
|
|
static inline u32 get_last_phandle(void)
|
|
{
|
|
return last_phandle;
|
|
}
|
|
|
|
static inline void set_last_phandle(u32 phandle)
|
|
{
|
|
last_phandle = phandle;
|
|
}
|
|
|
|
static inline u32 new_phandle(void)
|
|
{
|
|
return ++last_phandle;
|
|
}
|
|
|
|
/* Add a child node. */
|
|
struct dt_node *dt_new(struct dt_node *parent, const char *name);
|
|
struct dt_node *dt_new_addr(struct dt_node *parent, const char *name,
|
|
uint64_t unit_addr);
|
|
struct dt_node *dt_new_2addr(struct dt_node *parent, const char *name,
|
|
uint64_t unit_addr0, uint64_t unit_addr1);
|
|
struct dt_node *dt_new_check(struct dt_node *parent, const char *name);
|
|
|
|
/* Copy node to new parent, including properties and subnodes */
|
|
struct dt_node *dt_copy(struct dt_node *node, struct dt_node *parent);
|
|
|
|
/* Add a property node, various forms. */
|
|
struct dt_property *dt_add_property(struct dt_node *node,
|
|
const char *name,
|
|
const void *val, size_t size);
|
|
struct dt_property *dt_add_property_string(struct dt_node *node,
|
|
const char *name,
|
|
const char *value);
|
|
struct dt_property *dt_add_property_nstr(struct dt_node *node,
|
|
const char *name,
|
|
const char *value, unsigned int vlen);
|
|
|
|
/* Given out enough GCC extensions, we will achieve enlightenment! */
|
|
#define dt_add_property_strings(node, name, ...) \
|
|
__dt_add_property_strings((node), ((name)), \
|
|
sizeof((const char *[]) { __VA_ARGS__ })/sizeof(const char *), \
|
|
__VA_ARGS__)
|
|
|
|
struct dt_property *__dt_add_property_strings(struct dt_node *node,
|
|
const char *name,
|
|
int count, ...);
|
|
|
|
/* Given out enough GCC extensions, we will achieve enlightenment! */
|
|
#define dt_add_property_cells(node, name, ...) \
|
|
__dt_add_property_cells((node), ((name)), \
|
|
sizeof((u32[]) { __VA_ARGS__ })/sizeof(u32), \
|
|
__VA_ARGS__)
|
|
|
|
struct dt_property *__dt_add_property_cells(struct dt_node *node,
|
|
const char *name,
|
|
int count, ...);
|
|
|
|
#define dt_add_property_u64s(node, name, ...) \
|
|
__dt_add_property_u64s((node), ((name)), \
|
|
sizeof((u64[]) { __VA_ARGS__ })/sizeof(u64), \
|
|
__VA_ARGS__)
|
|
|
|
struct dt_property *__dt_add_property_u64s(struct dt_node *node,
|
|
const char *name,
|
|
int count, ...);
|
|
|
|
static inline struct dt_property *dt_add_property_u64(struct dt_node *node,
|
|
const char *name, u64 val)
|
|
{
|
|
return dt_add_property_cells(node, name, (u32)(val >> 32), (u32)val);
|
|
}
|
|
|
|
void dt_del_property(struct dt_node *node, struct dt_property *prop);
|
|
|
|
void dt_check_del_prop(struct dt_node *node, const char *name);
|
|
|
|
/* Warning: moves *prop! */
|
|
void dt_resize_property(struct dt_property **prop, size_t len);
|
|
|
|
void dt_property_set_cell(struct dt_property *prop, u32 index, u32 val);
|
|
u32 dt_property_get_cell(const struct dt_property *prop, u32 index);
|
|
|
|
/* First child of this node. */
|
|
struct dt_node *dt_first(const struct dt_node *root);
|
|
|
|
/* Return next node, or NULL. */
|
|
struct dt_node *dt_next(const struct dt_node *root, const struct dt_node *prev);
|
|
|
|
/* Iterate nodes */
|
|
#define dt_for_each_node(root, node) \
|
|
for (node = dt_first(root); node; node = dt_next(root, node))
|
|
|
|
#define dt_for_each_child(parent, node) \
|
|
list_for_each(&parent->children, node, list)
|
|
|
|
/* Find a string in a string list */
|
|
bool dt_prop_find_string(const struct dt_property *p, const char *s);
|
|
|
|
/* Check a compatible property */
|
|
bool dt_node_is_compatible(const struct dt_node *node, const char *compat);
|
|
|
|
/* Find a node based on compatible property */
|
|
struct dt_node *dt_find_compatible_node(struct dt_node *root,
|
|
struct dt_node *prev,
|
|
const char *compat);
|
|
|
|
#define dt_for_each_compatible(root, node, compat) \
|
|
for (node = NULL; \
|
|
(node = dt_find_compatible_node(root, node, compat)) != NULL;)
|
|
|
|
struct dt_node *dt_find_compatible_node_on_chip(struct dt_node *root,
|
|
struct dt_node *prev,
|
|
const char *compat,
|
|
uint32_t chip_id);
|
|
|
|
#define dt_for_each_compatible_on_chip(root, node, compat, chip_id) \
|
|
for (node = NULL; \
|
|
(node = dt_find_compatible_node_on_chip(root, node,\
|
|
compat, chip_id)) != NULL;)
|
|
/* Check status property */
|
|
bool dt_node_is_enabled(struct dt_node *node);
|
|
|
|
/* Build the full path for a node. Return a new block of memory, caller
|
|
* shall free() it
|
|
*/
|
|
char *dt_get_path(const struct dt_node *node);
|
|
|
|
/* Find a node by path */
|
|
struct dt_node *dt_find_by_path(struct dt_node *root, const char *path);
|
|
|
|
/* Find a child node by name */
|
|
struct dt_node *dt_find_by_name(struct dt_node *root, const char *name);
|
|
|
|
/* Find a node by phandle */
|
|
struct dt_node *dt_find_by_phandle(struct dt_node *root, u32 phandle);
|
|
|
|
/* Find a property by name. */
|
|
const struct dt_property *dt_find_property(const struct dt_node *node,\
|
|
const char *name);
|
|
const struct dt_property *dt_require_property(const struct dt_node *node,
|
|
const char *name, int wanted_len);
|
|
|
|
/* non-const variant */
|
|
struct dt_property *__dt_find_property(struct dt_node *node, const char *name);
|
|
|
|
/* Find a property by name, check if it's the same as val. */
|
|
bool dt_has_node_property(const struct dt_node *node,
|
|
const char *name, const char *val);
|
|
|
|
/* Free a node (and any children). */
|
|
void dt_free(struct dt_node *node);
|
|
|
|
/* Parse an initial fdt */
|
|
void dt_expand(const void *fdt);
|
|
int dt_expand_node(struct dt_node *node, const void *fdt, int fdt_node) __warn_unused_result;
|
|
|
|
/* Simplified accessors */
|
|
u64 dt_prop_get_u64(const struct dt_node *node, const char *prop);
|
|
u64 dt_prop_get_u64_def(const struct dt_node *node, const char *prop, u64 def);
|
|
u32 dt_prop_get_u32(const struct dt_node *node, const char *prop);
|
|
u32 dt_prop_get_u32_def(const struct dt_node *node, const char *prop, u32 def);
|
|
const void *dt_prop_get(const struct dt_node *node, const char *prop);
|
|
const void *dt_prop_get_def(const struct dt_node *node, const char *prop,
|
|
void *def);
|
|
const void *dt_prop_get_def_size(const struct dt_node *node, const char *prop,
|
|
void *def, size_t *len);
|
|
u32 dt_prop_get_cell(const struct dt_node *node, const char *prop, u32 cell);
|
|
u32 dt_prop_get_cell_def(const struct dt_node *node, const char *prop, u32 cell, u32 def);
|
|
|
|
/* Parsing helpers */
|
|
u32 dt_n_address_cells(const struct dt_node *node);
|
|
u32 dt_n_size_cells(const struct dt_node *node);
|
|
u64 dt_get_number(const void *pdata, unsigned int cells);
|
|
|
|
/* Find an ibm,chip-id property in this node; if not found, walk up the parent
|
|
* nodes. */
|
|
u32 dt_get_chip_id(const struct dt_node *node);
|
|
|
|
/* Same as dt_get_chip_id except Returns -1 if no chip-id property exists. */
|
|
u32 __dt_get_chip_id(const struct dt_node *node);
|
|
|
|
/* Address accessors ("reg" properties parsing). No translation,
|
|
* only support "simple" address forms (1 or 2 cells). Asserts
|
|
* if address doesn't exist
|
|
*/
|
|
u64 dt_get_address(const struct dt_node *node, unsigned int index,
|
|
u64 *out_size);
|
|
|
|
/* Count "reg" property entries */
|
|
unsigned int dt_count_addresses(const struct dt_node *node);
|
|
|
|
/* Address translation
|
|
*
|
|
* WARNING: Current implementation is simplified and will not
|
|
* handle complex address formats with address space indicators
|
|
* nor will it handle "ranges" translations yet... (XX TODO)
|
|
*/
|
|
u64 dt_translate_address(const struct dt_node *node, unsigned int index,
|
|
u64 *out_size);
|
|
|
|
/* compare function used to sort child nodes by name when added to the
|
|
* tree. This is mainly here for testing.
|
|
*/
|
|
int dt_cmp_subnodes(const struct dt_node *a, const struct dt_node *b);
|
|
|
|
struct dt_node *__dt_find_by_name_addr(struct dt_node *parent, const char *name,
|
|
const char *addr);
|
|
struct dt_node *dt_find_by_name_addr(struct dt_node *parent, const char *name,
|
|
uint64_t addr);
|
|
|
|
/* phandle fixup helper */
|
|
void dt_adjust_subtree_phandle(struct dt_node *subtree,
|
|
const char** (get_properties_to_fix)(struct dt_node *n));
|
|
|
|
#endif /* __DEVICE_H */
|