[U-Boot] [RFC PATCH 1/2] fdt: Add fdtdec_find_aliases() to deal with alias nodes

Simon Glass sjg at chromium.org
Mon Dec 26 23:31:49 CET 2011


Stephen Warren pointed out that we should use nodes whether or not they
have an alias in the /aliases section. The aliases section specifies the
order so far as it can, but is not essential. Operating without alisses
is useful when the enumerated order of nodes does not matter (admittedly
rare in U-Boot).

This is considerably more complex, and it is important to keep this
complexity out of driver code. This patch creates a function
fdtdec_find_aliases() which returns an ordered list of node offsets
for a particular compatible ID, taking account of alias nodes.

Signed-off-by: Simon Glass <sjg at chromium.org>
---
 include/fdtdec.h |   51 +++++++++++++++++++++++++++++++
 lib/fdtdec.c     |   89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 140 insertions(+), 0 deletions(-)

diff --git a/include/fdtdec.h b/include/fdtdec.h
index 5547676..0992130 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -228,3 +228,54 @@ int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
  * @return 0 if all ok or gpio was FDT_GPIO_NONE; -1 on error
  */
 int fdtdec_setup_gpio(struct fdt_gpio_state *gpio);
+
+/**
+ * Find the nodes for a peripheral and return a list of them in the correct
+ * order. This is used to enumerate all the peripherals of a certain type.
+ *
+ * To use this, optionally set up a /aliases node with alias properties for
+ * a peripheral. For example, for usb you could have:
+ *
+ * aliases {
+ *		usb0 = "/ehci at c5008000";
+ *		usb1 = "/ehci at c5000000";
+ * };
+ *
+ * Pass "usb" as the name to this function and will return a list of two
+ * nodes offsets: /ehci at c5008000 and ehci at c5000000.
+ *
+ * All nodes returned will match the compatible ID, as it is assumed that
+ * all peripherals use the same driver.
+ *
+ * If no alias node is found, then the node list will be returned in the
+ * order found in the fdt. If the aliases mention a node which doesn't
+ * exist, then this will be ignored. If nodes are found with no aliases,
+ * they will be added in any order.
+ *
+ * The array returned will not have any gaps.
+ *
+ * If there is a gap in the aliases, then this function will only return up
+ * to the number of nodes it found until the gap. It will also print a warning
+ * in this case. As an example, say you define aliases for usb2 and usb3, and
+ * have 3 nodes. Then in this case the node without an alias will become usb0
+ * and the aliases will be use for usb2 and usb3. But since there is no
+ * usb1, this function will only list one node (usb0), and will print a
+ * warning.
+ *
+ * This function does not check node properties - so it is possible that the
+ * node is marked disabled (status = "disabled"). The caller is expected to
+ * deal with this.
+ * TBD: It might be nicer to handle this here since we don't want a
+ * discontiguous list to result in the caller.
+ *
+ * Note: the algorithm used is O(maxcount).
+ *
+ * @param blob		FDT blob to use
+ * @param name		Root name of alias to search for
+ * @param id		Compatible ID to look for
+ * @param node		Place to put list of found nodes
+ * @param maxcount	Maximum number of nodes to find
+ * @return number of nodes found on success, FTD_ERR_... on error
+ */
+int fdtdec_find_aliases(const void *blob, const char *name,
+			enum fdt_compat_id id, int *node_list, int maxcount);
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index fb3d79d..b01978d 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -147,6 +147,95 @@ int fdtdec_next_alias(const void *blob, const char *name,
 	return node;
 }
 
+/* TODO: Can we tighten this code up a little? */
+int fdtdec_find_aliases(const void *blob, const char *name,
+			enum fdt_compat_id id, int *node_list, int maxcount)
+{
+	int nodes[maxcount];
+	int num_found = 0;
+	int alias_node;
+	int node;
+	int count;
+	int i, j;
+
+	/* find the alias node if present */
+	alias_node = fdt_path_offset(blob, "/aliases");
+
+	/*
+	 * start with nothing, and we can assume that the root node can't
+	 * match
+	 */
+	memset(nodes, '\0', sizeof(nodes));
+
+	/* First find all the compatible nodes */
+	node = 0;
+	for (node = count = 0; node >= 0 && count < maxcount;) {
+		node = fdtdec_next_compatible(blob, node, id);
+		if (node > 0)
+			nodes[count++] = node;
+	}
+
+	/* Now find all the aliases */
+	memset(node_list, '\0', sizeof(*node_list) * maxcount);
+	for (i = 0; i < maxcount; i++) {
+		int found;
+		const char *path;
+
+		path = fdt_getprop(blob, alias_node, name, NULL);
+		node = path ? fdt_path_offset(blob, path) : 0;
+		if (node <= 0)
+			continue;
+
+		/* Make sure the node we found is in our list! */
+		found = -1;
+		for (j = 0; j < count; j++)
+			if (nodes[j] == node) {
+				found = j;
+				break;
+			}
+
+		if (found == -1) {
+			printf("%s: warning: alias '%s' points to a node "
+				"'%s' that is missing or is not compatible "
+				" with '%s'\n", __func__, path,
+				fdt_get_name(blob, node, NULL),
+			       compat_names[id]);
+			continue;
+		}
+
+		/*
+		 * Add this node to our list in the right place, and mark it
+		 * as done.
+		 */
+		node_list[i] = node;
+		nodes[j] = 0;
+		if (j >= num_found)
+			num_found = j + 1;
+	}
+
+	/* Add any nodes not mentioned by an alias */
+	for (i = j = 0; i < maxcount; i++) {
+		if (!node_list[i]) {
+			for (; j < maxcount && !nodes[j]; j++)
+				;
+
+			/* Have we run out of nodes to add? */
+			if (j == maxcount)
+				break;
+
+			node_list[i] = nodes[j];
+		}
+	}
+
+	if (i != num_found) {
+		printf("%s: warning: for alias '%s' we found aliases up to "
+			"%d but only %d nodes, thus leaving a gap. Returning "
+			"only %d nodes\n", __func__, name, num_found, i, i);
+	}
+
+	return i;
+}
+
 /*
  * This function is a little odd in that it accesses global data. At some
  * point if the architecture board.c files merge this will make more sense.
-- 
1.7.3.1



More information about the U-Boot mailing list