[RFC 2/3] OLPC: add missing elements to device tree

Daniel Drake dsd at laptop.org
Sat Mar 5 04:12:34 EST 2011


In response to new device tree code in the kernel, OLPC will start
using it for probing of certain devices. However, some firmware fixes
are needed to put the devicetree into a usable state.

Retain compatibility with old firmware by fixing up the device tree
at boot-time if it does not contain the new nodes/properties that
we need for probing.

Signed-off-by: Daniel Drake <dsd at laptop.org>
---
 arch/x86/platform/olpc/olpc_dt.c |   87 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 87 insertions(+), 0 deletions(-)

diff --git a/arch/x86/platform/olpc/olpc_dt.c b/arch/x86/platform/olpc/olpc_dt.c
index 09cbede..58bba78 100644
--- a/arch/x86/platform/olpc/olpc_dt.c
+++ b/arch/x86/platform/olpc/olpc_dt.c
@@ -22,6 +22,7 @@
 #include <linux/of_platform.h>
 #include <linux/of_pdt.h>
 #include <asm/olpc_ofw.h>
+#include <asm/olpc.h>
 
 static phandle __init olpc_dt_getsibling(phandle node)
 {
@@ -164,6 +165,91 @@ static struct of_pdt_ops prom_olpc_ops __initdata = {
 	.pkg2path = olpc_dt_pkg2path,
 };
 
+static char __init *prom_alloc_string(const char *str, int *len)
+{
+	int _len = strlen(str);
+	char *output = prom_early_alloc(_len + 1);
+
+	strcpy(output, str);
+	if (len)
+		*len = _len;
+	return output;
+}
+
+static void __init prom_alloc_property(struct device_node *node,
+	const char *name, const char *value)
+{
+	struct property *p = prom_early_alloc(sizeof(struct property));
+
+	p->name = prom_alloc_string(name, NULL);
+	p->value = prom_alloc_string(value, &p->length);
+	prom_add_property(node, p);
+}
+
+/* Add dcon device as child of display */
+static void __init add_dcon_node(struct device_node *display)
+{
+	struct device_node *node = prom_early_alloc(sizeof(struct device_node));
+	unsigned long flags;
+
+	kref_init(&node->kref);
+	node->name = prom_alloc_string("dcon", NULL);
+	node->full_name = (char *) node->name;
+	node->parent = display;
+
+	write_lock_irqsave(&devtree_lock, flags);
+	node->sibling = node->parent->child;
+	node->allnext = allnodes;
+	node->parent->child = node;
+	allnodes = node;
+	write_unlock_irqrestore(&devtree_lock, flags);
+
+	prom_alloc_property(node, "compatible", "olpc,xo1-dcon");
+}
+
+static void __init olpc_dt_fixup(void)
+{
+	struct device_node *node;
+
+	/*
+	 * Use battery's compatible property to determine if we're running a
+	 * new-enough firmware. If we have this property, no fixups are needed.
+	 */
+	node = of_find_node_by_name(NULL, "battery");
+	if (node && of_get_property(node, "compatible", NULL)) {
+		of_node_put(node);
+		return;
+	}
+
+	/*
+	 * Add "compatible" property to battery, it was missing from earlier
+	 * firmware releases.
+	 */
+	prom_alloc_property(node, "compatible", "olpc,xo1-battery");
+	of_node_put(node);
+
+	/*
+	 * Mark XO-1 RTC as compatible with olpc,xo1-rtc - this was not done in
+	 * earlier firmware releases.
+	 */
+	node = of_find_node_by_name(NULL, "rtc");
+	if (olpc_platform_info.boardrev < olpc_board_pre(0xd0) && node) {
+		struct property *p = of_get_property(node, "compatible", NULL);
+		prom_remove_property(node, p);
+		prom_alloc_property(node, "compatible", "olpc,xo1-rtc");
+	}
+	of_node_put(node);
+
+	/*
+	 * Add "dcon" device node, it was missing from earlier firmware
+	 * releases.
+	 */
+	node = of_find_node_by_name(NULL, "display");
+	if (node)
+		add_dcon_node(node);
+	of_node_put(node);
+}
+
 void __init olpc_dt_build_devicetree(void)
 {
 	phandle root;
@@ -177,6 +263,7 @@ void __init olpc_dt_build_devicetree(void)
 		return;
 	}
 	of_pdt_build_devicetree(root, &prom_olpc_ops);
+	olpc_dt_fixup();
 
 	pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
 			prom_early_allocated);
-- 
1.7.4



More information about the devicetree-discuss mailing list