summaryrefslogtreecommitdiffstats
path: root/drivers/of/fdt.c
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2009-11-23 18:54:23 -0700
committerGrant Likely <grant.likely@secretlab.ca>2009-11-23 18:54:23 -0700
commitc8cb7a59842c0b512b44f6f818cdb0b5a3ddc89e (patch)
tree74d7b5c8dac3d5167b0394b5967bad52681dc28e /drivers/of/fdt.c
parente169cfbef46d62e042614ffafa8880eed1d894bb (diff)
of/flattree: merge of_scan_flat_dt
Merge common code between PowerPC and Microblaze Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Reviewed-by: Wolfram Sang <w.sang@pengutronix.de> Tested-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'drivers/of/fdt.c')
-rw-r--r--drivers/of/fdt.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 9faa9a5cbdf..dd9057cb7aa 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -19,3 +19,67 @@ char *find_flat_dt_string(u32 offset)
return ((char *)initial_boot_params) +
initial_boot_params->off_dt_strings + offset;
}
+
+/**
+ * of_scan_flat_dt - scan flattened tree blob and call callback on each.
+ * @it: callback function
+ * @data: context data pointer
+ *
+ * This function is used to scan the flattened device-tree, it is
+ * used to extract the memory information at boot before we can
+ * unflatten the tree
+ */
+int __init of_scan_flat_dt(int (*it)(unsigned long node,
+ const char *uname, int depth,
+ void *data),
+ void *data)
+{
+ unsigned long p = ((unsigned long)initial_boot_params) +
+ initial_boot_params->off_dt_struct;
+ int rc = 0;
+ int depth = -1;
+
+ do {
+ u32 tag = *((u32 *)p);
+ char *pathp;
+
+ p += 4;
+ if (tag == OF_DT_END_NODE) {
+ depth--;
+ continue;
+ }
+ if (tag == OF_DT_NOP)
+ continue;
+ if (tag == OF_DT_END)
+ break;
+ if (tag == OF_DT_PROP) {
+ u32 sz = *((u32 *)p);
+ p += 8;
+ if (initial_boot_params->version < 0x10)
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ p += sz;
+ p = _ALIGN(p, 4);
+ continue;
+ }
+ if (tag != OF_DT_BEGIN_NODE) {
+ pr_err("Invalid tag %x in flat device tree!\n", tag);
+ return -EINVAL;
+ }
+ depth++;
+ pathp = (char *)p;
+ p = _ALIGN(p + strlen(pathp) + 1, 4);
+ if ((*pathp) == '/') {
+ char *lp, *np;
+ for (lp = NULL, np = pathp; *np; np++)
+ if ((*np) == '/')
+ lp = np+1;
+ if (lp != NULL)
+ pathp = lp;
+ }
+ rc = it(p, pathp, depth, data);
+ if (rc != 0)
+ break;
+ } while (1);
+
+ return rc;
+}