[PATCH 21/21] dm: core: Add the ofnode multi-tree implementation

Simon Glass sjg at chromium.org
Wed Aug 31 05:08:17 CEST 2022


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.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 doc/develop/driver-model/livetree.rst |  13 +--
 drivers/core/ofnode.c                 | 124 +++++++++++++++++++++++++-
 include/dm/ofnode.h                   |  41 ++++++---
 3 files changed, 161 insertions(+), 17 deletions(-)

diff --git a/doc/develop/driver-model/livetree.rst b/doc/develop/driver-model/livetree.rst
index 4ef8c517325..76be89b9633 100644
--- a/doc/develop/driver-model/livetree.rst
+++ b/doc/develop/driver-model/livetree.rst
@@ -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.
-
-See dm_test_ofnode_root() for some examples.
+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. 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
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index a5c6e309615..b2b4b8d54cc 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -4,6 +4,8 @@
  * Written by Simon Glass <sjg at chromium.org>
  */
 
+#define LOG_CATEGORY	LOGC_DT
+
 #include <common.h>
 #include <dm.h>
 #include <fdtdec.h>
@@ -18,6 +20,126 @@
 #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 ofnode oftree_ensure(void *fdt, const char *path)
+{
+	int offset, i;
+	ofnode node;
+
+	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 ofnode_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 ofnode_null();
+		}
+	}
+
+	offset = fdt_path_offset(fdt, path);
+	if (offset < 0) {
+		log_debug("Unable to find path '%s' in tree %p\n", path, fdt);
+		return ofnode_null();
+	}
+
+	node.of_offset = OFTREE_NODE(i, offset);
+
+	return node;
+}
+
+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;
+}
+
+#else /* !OFNODE_MULTI_TREE */
+
+static ofnode oftree_ensure(void *fdt, const char *path)
+{
+	return offset_to_ofnode(fdt_path_offset(fdt, path));
+}
+#endif /* OFNODE_MULTI_TREE */
+
 bool ofnode_name_eq(ofnode node, const char *name)
 {
 	const char *node_name;
@@ -575,7 +697,7 @@ ofnode ofnode_path_root(oftree tree, const char *path)
 	else if (*path != '/' && tree.fdt != gd->fdt_blob)
 		return ofnode_null();  /* Aliases only on control FDT */
 	else
-		return offset_to_ofnode(fdt_path_offset(tree.fdt, path));
+		return oftree_ensure(tree.fdt, path);
 }
 
 const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index a79909c12e1..4d614b0a6e3 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -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,26 +44,32 @@ static inline void oftree_reset(void) {}
  * @node: Reference containing offset (possibly invalid)
  * Return: DT offset (can be NULL)
  */
+__attribute_const__ void *ofnode_to_fdt(ofnode node);
+
+/**
+ * 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)
+ */
+__attribute_const__ int ofnode_to_offset(ofnode node);
+
+#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;
 }
 
-/**
- * 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)
- */
-static inline int ofnode_to_offset(ofnode node)
+static inline __attribute_const__ int ofnode_to_offset(ofnode node)
 {
 #ifdef OF_CHECKS
 	if (of_live_active())
@@ -70,6 +77,7 @@ static inline int ofnode_to_offset(ofnode node)
 #endif
 	return node.of_offset;
 }
+#endif /* OFNODE_MULTI_TREE */
 
 /**
  * ofnode_to_np() - convert an ofnode to a live DT node pointer
@@ -139,6 +147,17 @@ static inline bool ofnode_valid(ofnode node)
 		return node.of_offset >= 0;
 }
 
+/**
+ * ofnode_lookup_fdt() - look up the FDT for a node
+ *
+ * Given a node this returns a pointer to the device tree containing that node.
+ * This can only be called when the flat tree is in use
+ *
+ * @node: Node to look up, may be ofnode_null()
+ * @return associated device tree, or gd->fdt_blob if @node is ofnode_null()
+ */
+void *ofnode_lookup_fdt(ofnode node);
+
 /**
  * oftree_lookup_fdt() - object the FDT pointer from an oftree
  *
-- 
2.37.2.672.g94769d06f0-goog



More information about the U-Boot mailing list