Merge tag 'v3.10.13' into lsk/v3.10/topic/kvm
[firefly-linux-kernel-4.4.55.git] / drivers / of / fdt.c
index 808be06bb67e7d4eeaf4f7250fae2dace0cc0f8d..4911158cba8a154b80aaeac44ef39a05741d93df 100644 (file)
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/sizes.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
+#include <linux/memblock.h>
+#include <linux/libfdt.h>
 
 #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
 #ifdef CONFIG_PPC
 
 #include <asm/page.h>
 
-char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
-{
-       return ((char *)blob) +
-               be32_to_cpu(blob->off_dt_strings) + offset;
-}
-
-/**
- * of_fdt_get_property - Given a node in the given flat blob, return
- * the property ptr
- */
-void *of_fdt_get_property(struct boot_param_header *blob,
-                      unsigned long node, const char *name,
-                      unsigned long *size)
-{
-       unsigned long p = node;
-
-       do {
-               u32 tag = be32_to_cpup((__be32 *)p);
-               u32 sz, noff;
-               const char *nstr;
-
-               p += 4;
-               if (tag == OF_DT_NOP)
-                       continue;
-               if (tag != OF_DT_PROP)
-                       return NULL;
-
-               sz = be32_to_cpup((__be32 *)p);
-               noff = be32_to_cpup((__be32 *)(p + 4));
-               p += 8;
-               if (be32_to_cpu(blob->version) < 0x10)
-                       p = ALIGN(p, sz >= 8 ? 8 : 4);
-
-               nstr = of_fdt_get_string(blob, noff);
-               if (nstr == NULL) {
-                       pr_warning("Can't find property index name !\n");
-                       return NULL;
-               }
-               if (strcmp(name, nstr) == 0) {
-                       if (size)
-                               *size = sz;
-                       return (void *)p;
-               }
-               p += sz;
-               p = ALIGN(p, 4);
-       } while (1);
-}
-
 /**
  * of_fdt_is_compatible - Return true if given node from the given blob has
  * compat in its compatible list
@@ -87,9 +43,10 @@ int of_fdt_is_compatible(struct boot_param_header *blob,
                      unsigned long node, const char *compat)
 {
        const char *cp;
-       unsigned long cplen, l, score = 0;
+       int cplen;
+       unsigned long l, score = 0;
 
-       cp = of_fdt_get_property(blob, node, "compatible", &cplen);
+       cp = fdt_getprop(blob, node, "compatible", &cplen);
        if (cp == NULL)
                return 0;
        while (cplen > 0) {
@@ -125,12 +82,12 @@ int of_fdt_match(struct boot_param_header *blob, unsigned long node,
        return score;
 }
 
-static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
+static void *unflatten_dt_alloc(void **mem, unsigned long size,
                                       unsigned long align)
 {
        void *res;
 
-       *mem = ALIGN(*mem, align);
+       *mem = PTR_ALIGN(*mem, align);
        res = (void *)*mem;
        *mem += size;
 
@@ -146,30 +103,29 @@ static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
  * @allnextpp: pointer to ->allnext from last allocated device_node
  * @fpsize: Size of the node path up at the current depth.
  */
-static unsigned long unflatten_dt_node(struct boot_param_header *blob,
-                               unsigned long mem,
-                               unsigned long *p,
+static void * unflatten_dt_node(struct boot_param_header *blob,
+                               void *mem,
+                               int *poffset,
                                struct device_node *dad,
                                struct device_node ***allnextpp,
                                unsigned long fpsize)
 {
+       const __be32 *p;
        struct device_node *np;
        struct property *pp, **prev_pp = NULL;
-       char *pathp;
-       u32 tag;
+       const char *pathp;
        unsigned int l, allocl;
+       static int depth = 0;
+       int old_depth;
+       int offset;
        int has_name = 0;
        int new_format = 0;
 
-       tag = be32_to_cpup((__be32 *)(*p));
-       if (tag != OF_DT_BEGIN_NODE) {
-               pr_err("Weird tag at start of node: %x\n", tag);
+       pathp = fdt_get_name(blob, *poffset, &l);
+       if (!pathp)
                return mem;
-       }
-       *p += 4;
-       pathp = (char *)*p;
-       l = allocl = strlen(pathp) + 1;
-       *p = ALIGN(*p + l, 4);
+
+       allocl = l++;
 
        /* version 0x10 has a more compact unit name here instead of the full
         * path. we accumulate the full path size using "fpsize", we'll rebuild
@@ -187,7 +143,7 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                        fpsize = 1;
                        allocl = 2;
                        l = 1;
-                       *pathp = '\0';
+                       pathp = "";
                } else {
                        /* account for '/' and path size minus terminal 0
                         * already in 'l'
@@ -235,32 +191,23 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                kref_init(&np->kref);
        }
        /* process properties */
-       while (1) {
-               u32 sz, noff;
-               char *pname;
-
-               tag = be32_to_cpup((__be32 *)(*p));
-               if (tag == OF_DT_NOP) {
-                       *p += 4;
-                       continue;
-               }
-               if (tag != OF_DT_PROP)
+       for (offset = fdt_first_property_offset(blob, *poffset);
+            (offset >= 0);
+            (offset = fdt_next_property_offset(blob, offset))) {
+               const char *pname;
+               u32 sz;
+
+               if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) {
+                       offset = -FDT_ERR_INTERNAL;
                        break;
-               *p += 4;
-               sz = be32_to_cpup((__be32 *)(*p));
-               noff = be32_to_cpup((__be32 *)((*p) + 4));
-               *p += 8;
-               if (be32_to_cpu(blob->version) < 0x10)
-                       *p = ALIGN(*p, sz >= 8 ? 8 : 4);
-
-               pname = of_fdt_get_string(blob, noff);
+               }
+
                if (pname == NULL) {
                        pr_info("Can't find property name in list !\n");
                        break;
                }
                if (strcmp(pname, "name") == 0)
                        has_name = 1;
-               l = strlen(pname) + 1;
                pp = unflatten_dt_alloc(&mem, sizeof(struct property),
                                        __alignof__(struct property));
                if (allnextpp) {
@@ -272,26 +219,25 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                        if ((strcmp(pname, "phandle") == 0) ||
                            (strcmp(pname, "linux,phandle") == 0)) {
                                if (np->phandle == 0)
-                                       np->phandle = be32_to_cpup((__be32*)*p);
+                                       np->phandle = be32_to_cpup(p);
                        }
                        /* And we process the "ibm,phandle" property
                         * used in pSeries dynamic device tree
                         * stuff */
                        if (strcmp(pname, "ibm,phandle") == 0)
-                               np->phandle = be32_to_cpup((__be32 *)*p);
-                       pp->name = pname;
+                               np->phandle = be32_to_cpup(p);
+                       pp->name = (char *)pname;
                        pp->length = sz;
-                       pp->value = (void *)*p;
+                       pp->value = (__be32 *)p;
                        *prev_pp = pp;
                        prev_pp = &pp->next;
                }
-               *p = ALIGN((*p) + sz, 4);
        }
        /* with version 0x10 we may not have the name property, recreate
         * it here from the unit name if absent
         */
        if (!has_name) {
-               char *p1 = pathp, *ps = pathp, *pa = NULL;
+               const char *p1 = pathp, *ps = pathp, *pa = NULL;
                int sz;
 
                while (*p1) {
@@ -328,19 +274,18 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                if (!np->type)
                        np->type = "<NULL>";
        }
-       while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
-               if (tag == OF_DT_NOP)
-                       *p += 4;
-               else
-                       mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
-                                               fpsize);
-               tag = be32_to_cpup((__be32 *)(*p));
-       }
-       if (tag != OF_DT_END_NODE) {
-               pr_err("Weird tag at end of node: %x\n", tag);
-               return mem;
-       }
-       *p += 4;
+
+       old_depth = depth;
+       *poffset = fdt_next_node(blob, *poffset, &depth);
+       if (depth < 0)
+               depth = 0;
+       while (*poffset > 0 && depth > old_depth)
+               mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp,
+                                       fpsize);
+
+       if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
+               pr_err("unflatten: error %d processing FDT\n", *poffset);
+
        return mem;
 }
 
@@ -360,7 +305,9 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
                             struct device_node **mynodes,
                             void * (*dt_alloc)(u64 size, u64 align))
 {
-       unsigned long start, mem, size;
+       unsigned long size;
+       int start;
+       void *mem;
        struct device_node **allnextp = mynodes;
 
        pr_debug(" -> unflatten_device_tree()\n");
@@ -381,28 +328,25 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
        }
 
        /* First pass, scan for size */
-       start = ((unsigned long)blob) +
-               be32_to_cpu(blob->off_dt_struct);
-       size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
-       size = (size | 3) + 1;
+       start = 0;
+       size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
+       size = ALIGN(size, 4);
 
        pr_debug("  size is %lx, allocating...\n", size);
 
        /* Allocate memory for the expanded device tree */
-       mem = (unsigned long)
-               dt_alloc(size + 4, __alignof__(struct device_node));
+       mem = dt_alloc(size + 4, __alignof__(struct device_node));
+
+       memset((void *)mem, 0, size);
 
        ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
 
-       pr_debug("  unflattening %lx...\n", mem);
+       pr_debug("  unflattening %p...\n", mem);
 
        /* Second pass, do actual unflattening */
-       start = ((unsigned long)blob) +
-               be32_to_cpu(blob->off_dt_struct);
+       start = 0;
        unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
-       if (be32_to_cpup((__be32 *)start) != OF_DT_END)
-               pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
-       if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
+       if (be32_to_cpup(mem + size) != 0xdeadbeef)
                pr_warning("End of tree marker overwritten: %08x\n",
                           be32_to_cpu(((__be32 *)mem)[size / 4]));
        *allnextp = NULL;
@@ -440,6 +384,129 @@ struct boot_param_header *initial_boot_params;
 
 #ifdef CONFIG_OF_EARLY_FLATTREE
 
+/**
+ * res_mem_reserve_reg() - reserve all memory described in 'reg' property
+ */
+static int __init __reserved_mem_reserve_reg(unsigned long node,
+                                            const char *uname)
+{
+       int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
+       phys_addr_t base, size;
+       int len;
+       const __be32 *prop;
+       int nomap, first = 1;
+
+       prop = of_get_flat_dt_prop(node, "reg", &len);
+       if (!prop)
+               return -ENOENT;
+
+       if (len && len % t_len != 0) {
+               pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
+                      uname);
+               return -EINVAL;
+       }
+
+       nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
+
+       while (len >= t_len) {
+               base = dt_mem_next_cell(dt_root_addr_cells, &prop);
+               size = dt_mem_next_cell(dt_root_size_cells, &prop);
+
+               if (base && size &&
+                   early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
+                       pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
+                               uname, &base, (unsigned long)size / SZ_1M);
+               else
+                       pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
+                               uname, &base, (unsigned long)size / SZ_1M);
+
+               len -= t_len;
+               if (first) {
+                       fdt_reserved_mem_save_node(node, uname, base, size);
+                       first = 0;
+               }
+       }
+       return 0;
+}
+
+/**
+ * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
+ * in /reserved-memory matches the values supported by the current implementation,
+ * also check if ranges property has been provided
+ */
+static int __init __reserved_mem_check_root(unsigned long node)
+{
+       const __be32 *prop;
+
+       prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
+       if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
+               return -EINVAL;
+
+       prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
+       if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
+               return -EINVAL;
+
+       prop = of_get_flat_dt_prop(node, "ranges", NULL);
+       if (!prop)
+               return -EINVAL;
+       return 0;
+}
+
+/**
+ * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
+ */
+static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
+                                         int depth, void *data)
+{
+       static int found;
+       const char *status;
+       int err;
+
+       if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
+               if (__reserved_mem_check_root(node) != 0) {
+                       pr_err("Reserved memory: unsupported node format, ignoring\n");
+                       /* break scan */
+                       return 1;
+               }
+               found = 1;
+               /* scan next node */
+               return 0;
+       } else if (!found) {
+               /* scan next node */
+               return 0;
+       } else if (found && depth < 2) {
+               /* scanning of /reserved-memory has been finished */
+               return 1;
+       }
+
+       status = of_get_flat_dt_prop(node, "status", NULL);
+       if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0)
+               return 0;
+
+       err = __reserved_mem_reserve_reg(node, uname);
+       if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
+               fdt_reserved_mem_save_node(node, uname, 0, 0);
+
+       /* scan next node */
+       return 0;
+}
+
+/**
+ * early_init_fdt_scan_reserved_mem() - create reserved memory regions
+ *
+ * This function grabs memory from early allocator for device exclusive use
+ * defined in device tree structures. It should be called by arch specific code
+ * once the early allocator (i.e. memblock) has been fully activated.
+ */
+void __init early_init_fdt_scan_reserved_mem(void)
+{
+       if (!initial_boot_params)
+               return;
+
+       of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
+       fdt_init_reserved_mem();
+}
+
 /**
  * of_scan_flat_dt - scan flattened tree blob and call callback on each.
  * @it: callback function
@@ -454,47 +521,19 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
                                     void *data),
                           void *data)
 {
-       unsigned long p = ((unsigned long)initial_boot_params) +
-               be32_to_cpu(initial_boot_params->off_dt_struct);
-       int rc = 0;
-       int depth = -1;
-
-       do {
-               u32 tag = be32_to_cpup((__be32 *)p);
-               const 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 = be32_to_cpup((__be32 *)p);
-                       p += 8;
-                       if (be32_to_cpu(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);
+       const void *blob = initial_boot_params;
+       const char *pathp;
+       int offset, rc = 0, depth = -1;
+
+        for (offset = fdt_next_node(blob, -1, &depth);
+             offset >= 0 && depth >= 0 && !rc;
+             offset = fdt_next_node(blob, offset, &depth)) {
+
+               pathp = fdt_get_name(blob, offset, NULL);
                if (*pathp == '/')
                        pathp = kbasename(pathp);
-               rc = it(p, pathp, depth, data);
-               if (rc != 0)
-                       break;
-       } while (1);
-
+               rc = it(offset, pathp, depth, data);
+       }
        return rc;
 }
 
@@ -503,14 +542,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
  */
 unsigned long __init of_get_flat_dt_root(void)
 {
-       unsigned long p = ((unsigned long)initial_boot_params) +
-               be32_to_cpu(initial_boot_params->off_dt_struct);
-
-       while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
-               p += 4;
-       BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
-       p += 4;
-       return ALIGN(p + strlen((char *)p) + 1, 4);
+       return 0;
 }
 
 /**
@@ -519,10 +551,10 @@ unsigned long __init of_get_flat_dt_root(void)
  * This function can be used within scan_flattened_dt callback to get
  * access to properties
  */
-void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
-                                unsigned long *size)
+const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
+                                      int *size)
 {
-       return of_fdt_get_property(initial_boot_params, node, name, size);
+       return fdt_getprop(initial_boot_params, node, name, size);
 }
 
 /**
@@ -543,6 +575,15 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
        return of_fdt_match(initial_boot_params, node, compat);
 }
 
+struct fdt_scan_status {
+       const char *name;
+       int namelen;
+       int depth;
+       int found;
+       int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
+       void *data;
+};
+
 #ifdef CONFIG_BLK_DEV_INITRD
 /**
  * early_init_dt_check_for_initrd - Decode initrd location from flat tree
@@ -550,23 +591,25 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
  */
 void __init early_init_dt_check_for_initrd(unsigned long node)
 {
-       unsigned long start, end, len;
-       __be32 *prop;
+       u64 start, end;
+       int len;
+       const __be32 *prop;
 
        pr_debug("Looking for initrd properties... ");
 
        prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
        if (!prop)
                return;
-       start = of_read_ulong(prop, len/4);
+       start = of_read_number(prop, len/4);
 
        prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
        if (!prop)
                return;
-       end = of_read_ulong(prop, len/4);
+       end = of_read_number(prop, len/4);
 
        early_init_dt_setup_initrd_arch(start, end);
-       pr_debug("initrd_start=0x%lx  initrd_end=0x%lx\n", start, end);
+       pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n",
+                (unsigned long long)start, (unsigned long long)end);
 }
 #else
 inline void early_init_dt_check_for_initrd(unsigned long node)
@@ -580,7 +623,7 @@ inline void early_init_dt_check_for_initrd(unsigned long node)
 int __init early_init_dt_scan_root(unsigned long node, const char *uname,
                                   int depth, void *data)
 {
-       __be32 *prop;
+       const __be32 *prop;
 
        if (depth != 0)
                return 0;
@@ -602,9 +645,9 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname,
        return 1;
 }
 
-u64 __init dt_mem_next_cell(int s, __be32 **cellp)
+u64 __init dt_mem_next_cell(int s, const __be32 **cellp)
 {
-       __be32 *p = *cellp;
+       const __be32 *p = *cellp;
 
        *cellp = p + s;
        return of_read_number(p, s);
@@ -616,9 +659,9 @@ u64 __init dt_mem_next_cell(int s, __be32 **cellp)
 int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
                                     int depth, void *data)
 {
-       char *type = of_get_flat_dt_prop(node, "device_type", NULL);
-       __be32 *reg, *endp;
-       unsigned long l;
+       const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+       const __be32 *reg, *endp;
+       int l;
 
        /* We are scanning "memory" nodes only */
        if (type == NULL) {
@@ -639,7 +682,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
 
        endp = reg + (l / sizeof(__be32));
 
-       pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
+       pr_debug("memory scan node %s, reg size %d, data: %x %x %x %x,\n",
            uname, l, reg[0], reg[1], reg[2], reg[3]);
 
        while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
@@ -662,8 +705,8 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
 int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
                                     int depth, void *data)
 {
-       unsigned long l;
-       char *p;
+       int l;
+       const char *p;
 
        pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
 
@@ -696,6 +739,80 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
        return 1;
 }
 
+#ifdef CONFIG_HAVE_MEMBLOCK
+void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+       const u64 phys_offset = __pa(PAGE_OFFSET);
+       base &= PAGE_MASK;
+       size &= PAGE_MASK;
+       if (base + size < phys_offset) {
+               pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
+                          base, base + size);
+               return;
+       }
+       if (base < phys_offset) {
+               pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
+                          base, phys_offset);
+               size -= phys_offset - base;
+               base = phys_offset;
+       }
+       memblock_add(base, size);
+}
+
+int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
+                                       phys_addr_t size, bool nomap)
+{
+       if (memblock_is_region_reserved(base, size))
+               return -EBUSY;
+       if (nomap)
+               return memblock_remove(base, size);
+       return memblock_reserve(base, size);
+}
+
+/*
+ * called from unflatten_device_tree() to bootstrap devicetree itself
+ * Architectures can override this definition if memblock isn't used
+ */
+void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+       return __va(memblock_alloc(size, align));
+}
+#else
+int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
+                                       phys_addr_t size, bool nomap)
+{
+       pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n",
+                 base, size, nomap ? " (nomap)" : "");
+       return -ENOSYS;
+}
+#endif
+
+bool __init early_init_dt_scan(void *params)
+{
+       if (!params)
+               return false;
+
+       /* Setup flat device-tree pointer */
+       initial_boot_params = params;
+
+       /* check device tree validity */
+       if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
+               initial_boot_params = NULL;
+               return false;
+       }
+
+       /* Retrieve various information from the /chosen node */
+       of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
+
+       /* Initialize {size,address}-cells info */
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+
+       /* Setup memory, calling early_init_dt_add_memory_arch */
+       of_scan_flat_dt(early_init_dt_scan_memory, NULL);
+
+       return true;
+}
+
 /**
  * unflatten_device_tree - create tree of device_nodes from flat blob
  *