dm: core: Add the ofnode multi-tree implementation
Add the logic to redirect requests for the device tree through a function which can look up the tree ID. This works by using the top bits of ofnode.of_offset to encode a tree. It is assumed that there will only be a few device trees used at runtime, typically the control FDT (always tree ID 0) and possibly a separate FDT to be passed the OS. The maximum number of device trees supported at runtime is 8, with this implementation. That would use bits 30:28 of the node-offset value, meaning that the positive offset range is limited to bits 27:0, versus 30:1 with this feature disabled. That still allows a device tree of up to 256MB, which should be enough for most FITs. Larger ones can be supported by using external data with the FIT, or by enabling OF_LIVE. Update the documentation a little and fix up the comment for ofnode_valid(). Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -250,11 +250,14 @@ a flat tree.
|
||||
It would be helpful to use livetree for fixups, since adding a lot of nodes and
|
||||
properties would involve less memory copying and be more efficient. As a step
|
||||
towards this, an `oftree` type has been introduced. It is normally set to
|
||||
oftree_default() but can be set to other values. Eventually this should allow
|
||||
the use of FDT fixups using the ofnode interface, instead of the low-level
|
||||
libfdt one.
|
||||
oftree_default() but can be set to other values using oftree_from_fdt().
|
||||
So long as OF_LIVE is disabled, it is possible to do fixups using the ofnode
|
||||
interface. The OF_LIVE support required addition of the flattening step at the
|
||||
end.
|
||||
|
||||
See dm_test_ofnode_root() for some examples.
|
||||
See dm_test_ofnode_root() for some examples. The ofnode_path_root() function
|
||||
causes a flat device tree to be 'registered' such that it can be used by the
|
||||
ofnode interface.
|
||||
|
||||
|
||||
Internal implementation
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY LOGC_DT
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
@@ -18,22 +20,182 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <asm/global_data.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
|
||||
static void *oftree_list[CONFIG_OFNODE_MULTI_TREE_MAX];
|
||||
static int oftree_count;
|
||||
|
||||
void oftree_reset(void)
|
||||
{
|
||||
if (gd->flags & GD_FLG_RELOC) {
|
||||
oftree_count = 0;
|
||||
oftree_list[oftree_count++] = (void *)gd->fdt_blob;
|
||||
}
|
||||
}
|
||||
|
||||
static int oftree_find(const void *fdt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < oftree_count; i++) {
|
||||
if (fdt == oftree_list[i])
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static oftree oftree_ensure(void *fdt)
|
||||
{
|
||||
oftree tree;
|
||||
int i;
|
||||
|
||||
if (gd->flags & GD_FLG_RELOC) {
|
||||
i = oftree_find(fdt);
|
||||
if (i == -1) {
|
||||
if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
|
||||
log_warning("Too many registered device trees (max %d)\n",
|
||||
CONFIG_OFNODE_MULTI_TREE_MAX);
|
||||
return oftree_null();
|
||||
}
|
||||
|
||||
/* register the new tree */
|
||||
i = oftree_count++;
|
||||
oftree_list[i] = fdt;
|
||||
log_debug("oftree: registered tree %d: %p\n", i, fdt);
|
||||
}
|
||||
} else {
|
||||
if (fdt != gd->fdt_blob) {
|
||||
log_debug("Cannot only access control FDT before relocation\n");
|
||||
return oftree_null();
|
||||
}
|
||||
}
|
||||
|
||||
tree.fdt = fdt;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void *ofnode_lookup_fdt(ofnode node)
|
||||
{
|
||||
if (gd->flags & GD_FLG_RELOC) {
|
||||
uint i = OFTREE_TREE_ID(node.of_offset);
|
||||
|
||||
if (i > oftree_count) {
|
||||
log_debug("Invalid tree ID %x\n", i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return oftree_list[i];
|
||||
} else {
|
||||
return (void *)gd->fdt_blob;
|
||||
}
|
||||
}
|
||||
|
||||
void *ofnode_to_fdt(ofnode node)
|
||||
{
|
||||
#ifdef OF_CHECKS
|
||||
if (of_live_active())
|
||||
return NULL;
|
||||
#endif
|
||||
if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
|
||||
return ofnode_lookup_fdt(node);
|
||||
|
||||
/* Use the control FDT by default */
|
||||
return (void *)gd->fdt_blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* ofnode_to_offset() - convert an ofnode to a flat DT offset
|
||||
*
|
||||
* This cannot be called if the reference contains a node pointer.
|
||||
*
|
||||
* @node: Reference containing offset (possibly invalid)
|
||||
* Return: DT offset (can be -1)
|
||||
*/
|
||||
int ofnode_to_offset(ofnode node)
|
||||
{
|
||||
#ifdef OF_CHECKS
|
||||
if (of_live_active())
|
||||
return -1;
|
||||
#endif
|
||||
if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
|
||||
return OFTREE_OFFSET(node.of_offset);
|
||||
|
||||
return node.of_offset;
|
||||
}
|
||||
|
||||
oftree oftree_from_fdt(void *fdt)
|
||||
{
|
||||
oftree tree;
|
||||
|
||||
if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
|
||||
return oftree_ensure(fdt);
|
||||
|
||||
tree.fdt = fdt;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* noffset_to_ofnode() - convert a DT offset to an ofnode
|
||||
*
|
||||
* @other_node: Node in the same tree to use as a reference
|
||||
* @of_offset: DT offset (either valid, or -1)
|
||||
* Return: reference to the associated DT offset
|
||||
*/
|
||||
ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
|
||||
{
|
||||
ofnode node;
|
||||
|
||||
if (of_live_active())
|
||||
node.np = NULL;
|
||||
else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
|
||||
!ofnode_valid(other_node))
|
||||
node.of_offset = of_offset;
|
||||
else
|
||||
node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
|
||||
of_offset);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
#else /* !OFNODE_MULTI_TREE */
|
||||
|
||||
static inline int oftree_find(const void *fdt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* OFNODE_MULTI_TREE */
|
||||
|
||||
/**
|
||||
* ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
|
||||
*
|
||||
* Looks up the tree and returns an ofnode with the correct of_offset
|
||||
* Looks up the tree and returns an ofnode with the correct of_offset (i.e.
|
||||
* containing the tree ID).
|
||||
*
|
||||
* If @offset is < 0 then this returns an ofnode with that offset
|
||||
* If @offset is < 0 then this returns an ofnode with that offset and no tree
|
||||
* ID.
|
||||
*
|
||||
* @tree: tree to check
|
||||
* @offset: offset within that tree (can be < 0)
|
||||
* @return node for that offset
|
||||
* @return node for that offset, with the correct ID
|
||||
*/
|
||||
static ofnode ofnode_from_tree_offset(oftree tree, int offset)
|
||||
{
|
||||
ofnode node;
|
||||
|
||||
node.of_offset = offset;
|
||||
if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
|
||||
int tree_id = oftree_find(tree.fdt);
|
||||
|
||||
if (tree_id == -1)
|
||||
return ofnode_null();
|
||||
node.of_offset = OFTREE_NODE(tree_id, offset);
|
||||
} else {
|
||||
node.of_offset = offset;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -27,13 +27,14 @@ struct ofnode_phandle_args {
|
||||
uint32_t args[OF_MAX_PHANDLE_ARGS];
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
|
||||
/**
|
||||
* oftree_reset() - reset the state of the oftree list
|
||||
*
|
||||
* Reset the oftree list so it can be started again. This should be called
|
||||
* once the control FDT is in place, but before the ofnode interface is used.
|
||||
*/
|
||||
static inline void oftree_reset(void) {}
|
||||
void oftree_reset(void);
|
||||
|
||||
/**
|
||||
* ofnode_to_fdt() - convert an ofnode to a flat DT pointer
|
||||
@@ -43,16 +44,7 @@ static inline void oftree_reset(void) {}
|
||||
* @node: Reference containing offset (possibly invalid)
|
||||
* Return: DT offset (can be NULL)
|
||||
*/
|
||||
static inline void *ofnode_to_fdt(ofnode node)
|
||||
{
|
||||
#ifdef OF_CHECKS
|
||||
if (of_live_active())
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
/* Use the control FDT by default */
|
||||
return (void *)gd->fdt_blob;
|
||||
}
|
||||
__attribute_const__ void *ofnode_to_fdt(ofnode node);
|
||||
|
||||
/**
|
||||
* ofnode_to_offset() - convert an ofnode to a flat DT offset
|
||||
@@ -62,7 +54,40 @@ static inline void *ofnode_to_fdt(ofnode node)
|
||||
* @node: Reference containing offset (possibly invalid)
|
||||
* Return: DT offset (can be -1)
|
||||
*/
|
||||
static inline int ofnode_to_offset(ofnode node)
|
||||
__attribute_const__ int ofnode_to_offset(ofnode node);
|
||||
|
||||
/**
|
||||
* oftree_from_fdt() - Returns an oftree from a flat device tree pointer
|
||||
*
|
||||
* @fdt: Device tree to use
|
||||
*
|
||||
* Returns: reference to the given node
|
||||
*/
|
||||
oftree oftree_from_fdt(void *fdt);
|
||||
|
||||
/**
|
||||
* noffset_to_ofnode() - convert a DT offset to an ofnode
|
||||
*
|
||||
* @other_node: Node in the same tree to use as a reference
|
||||
* @of_offset: DT offset (either valid, or -1)
|
||||
* Return: reference to the associated DT offset
|
||||
*/
|
||||
ofnode noffset_to_ofnode(ofnode other_node, int of_offset);
|
||||
|
||||
#else /* !OFNODE_MULTI_TREE */
|
||||
static inline void oftree_reset(void) {}
|
||||
|
||||
static inline void *ofnode_to_fdt(ofnode node)
|
||||
{
|
||||
#ifdef OF_CHECKS
|
||||
if (of_live_active())
|
||||
return NULL;
|
||||
#endif
|
||||
/* Use the control FDT by default */
|
||||
return (void *)gd->fdt_blob;
|
||||
}
|
||||
|
||||
static inline __attribute_const__ int ofnode_to_offset(ofnode node)
|
||||
{
|
||||
#ifdef OF_CHECKS
|
||||
if (of_live_active())
|
||||
@@ -71,6 +96,33 @@ static inline int ofnode_to_offset(ofnode node)
|
||||
return node.of_offset;
|
||||
}
|
||||
|
||||
static inline oftree oftree_from_fdt(void *fdt)
|
||||
{
|
||||
oftree tree;
|
||||
|
||||
/* we cannot access other trees without OFNODE_MULTI_TREE */
|
||||
if (fdt == gd->fdt_blob)
|
||||
tree.fdt = fdt;
|
||||
else
|
||||
tree.fdt = NULL;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
static inline ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
|
||||
{
|
||||
ofnode node;
|
||||
|
||||
if (of_live_active())
|
||||
node.np = NULL;
|
||||
else
|
||||
node.of_offset = of_offset;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
#endif /* OFNODE_MULTI_TREE */
|
||||
|
||||
/**
|
||||
* ofnode_to_np() - convert an ofnode to a live DT node pointer
|
||||
*
|
||||
@@ -88,30 +140,11 @@ static inline struct device_node *ofnode_to_np(ofnode node)
|
||||
return node.np;
|
||||
}
|
||||
|
||||
/**
|
||||
* noffset_to_ofnode() - convert a DT offset to an ofnode
|
||||
*
|
||||
* @other_node: Node in the same tree to use as a reference
|
||||
* @of_offset: DT offset (either valid, or -1)
|
||||
* Return: reference to the associated DT offset
|
||||
*/
|
||||
static inline ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
|
||||
{
|
||||
ofnode node;
|
||||
|
||||
if (of_live_active())
|
||||
node.np = NULL;
|
||||
else
|
||||
node.of_offset = of_offset;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* ofnode_valid() - check if an ofnode is valid
|
||||
*
|
||||
* @node: Reference containing offset (possibly invalid)
|
||||
* Return: true if the reference contains a valid ofnode, false if it is NULL
|
||||
* Return: true if the reference contains a valid ofnode, false if not
|
||||
*/
|
||||
static inline bool ofnode_valid(ofnode node)
|
||||
{
|
||||
@@ -316,22 +349,6 @@ static inline oftree oftree_from_np(struct device_node *root)
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* oftree_from_fdt() - Returns an oftree from a flat device tree pointer
|
||||
*
|
||||
* @fdt: Device tree to use
|
||||
*
|
||||
* Returns: reference to the given node
|
||||
*/
|
||||
static inline oftree oftree_from_fdt(void *fdt)
|
||||
{
|
||||
oftree tree;
|
||||
|
||||
tree.fdt = fdt;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* ofnode_name_eq() - Check if the node name is equivalent to a given name
|
||||
* ignoring the unit address
|
||||
|
||||
Reference in New Issue
Block a user