static unsigned char fdt_buf[16 << 10] __initdata;
 
+static int append_memory(void *fdt)
+{
+       unsigned long phys_memsize, memsize;
+       __be32 mem_array[2];
+       int err, mem_off;
+       char *var;
+
+       /* find memory size from the bootloader environment */
+       var = fw_getenv("memsize");
+       if (var) {
+               err = kstrtoul(var, 0, &phys_memsize);
+               if (err) {
+                       pr_err("Failed to read memsize env variable '%s'\n",
+                              var);
+                       return -EINVAL;
+               }
+       } else {
+               pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
+               phys_memsize = 32 << 20;
+       }
+
+       /* default to using all available RAM */
+       memsize = phys_memsize;
+
+       /* allow the user to override the usable memory */
+       var = strstr(arcs_cmdline, "memsize=");
+       if (var)
+               memsize = memparse(var + strlen("memsize="), NULL);
+
+       /* if the user says there's more RAM than we thought, believe them */
+       phys_memsize = max_t(unsigned long, phys_memsize, memsize);
+
+       /* find or add a memory node */
+       mem_off = fdt_path_offset(fdt, "/memory");
+       if (mem_off == -FDT_ERR_NOTFOUND)
+               mem_off = fdt_add_subnode(fdt, 0, "memory");
+       if (mem_off < 0) {
+               pr_err("Unable to find or add memory DT node: %d\n", mem_off);
+               return mem_off;
+       }
+
+       err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
+       if (err) {
+               pr_err("Unable to set memory node device_type: %d\n", err);
+               return err;
+       }
+
+       mem_array[0] = 0;
+       mem_array[1] = cpu_to_be32(phys_memsize);
+       err = fdt_setprop(fdt, mem_off, "reg", mem_array, sizeof(mem_array));
+       if (err) {
+               pr_err("Unable to set memory regs property: %d\n", err);
+               return err;
+       }
+
+       mem_array[0] = 0;
+       mem_array[1] = cpu_to_be32(memsize);
+       err = fdt_setprop(fdt, mem_off, "linux,usable-memory",
+                         mem_array, sizeof(mem_array));
+       if (err) {
+               pr_err("Unable to set linux,usable-memory property: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
 static int remove_gic(void *fdt)
 {
        const unsigned int cpu_ehci_int = 2;
        if (err)
                panic("Unable to open FDT: %d", err);
 
+       err = append_memory(fdt_buf);
+       if (err)
+               panic("Unable to patch FDT: %d", err);
+
        err = remove_gic(fdt_buf);
        if (err)
                panic("Unable to patch FDT: %d", err);
 
 #include <linux/of_fdt.h>
 
 #include <asm/prom.h>
-#include <asm/fw/fw.h>
 
 #include <asm/mach-sead3/sead3-dtshim.h>
 #include <asm/mips-boards/generic.h>
        return "MIPS SEAD3";
 }
 
-static uint32_t get_memsize_from_cmdline(void)
-{
-       int memsize = 0;
-       char *p = arcs_cmdline;
-       char *s = "memsize=";
-
-       p = strstr(p, s);
-       if (p) {
-               p += strlen(s);
-               memsize = memparse(p, NULL);
-       }
-
-       return memsize;
-}
-
-static uint32_t get_memsize_from_env(void)
-{
-       int memsize = 0;
-       char *p;
-
-       p = fw_getenv("memsize");
-       if (p)
-               memsize = memparse(p, NULL);
-
-       return memsize;
-}
-
-static uint32_t get_memsize(void)
-{
-       uint32_t memsize;
-
-       memsize = get_memsize_from_cmdline();
-       if (memsize)
-               return memsize;
-
-       return get_memsize_from_env();
-}
-
-static void __init parse_memsize_param(void)
-{
-       int offset;
-       const uint64_t *prop_value;
-       int prop_len;
-       uint32_t memsize = get_memsize();
-
-       if (!memsize)
-               return;
-
-       offset = fdt_path_offset(__dtb_start, "/memory");
-       if (offset > 0) {
-               uint64_t new_value;
-               /*
-                * reg contains 2 32-bits BE values, offset and size. We just
-                * want to replace the size value without affecting the offset
-                */
-               prop_value = fdt_getprop(__dtb_start, offset, "reg", &prop_len);
-               new_value = be64_to_cpu(*prop_value);
-               new_value =  (new_value & ~0xffffffffllu) | memsize;
-               fdt_setprop_inplace_u64(__dtb_start, offset, "reg", new_value);
-       }
-}
-
 void __init *plat_get_fdt(void)
 {
        return (void *)__dtb_start;
 {
        void *fdt = plat_get_fdt();
 
-       /* allow command line/bootloader env to override memory size in DT */
-       parse_memsize_param();
-
        fdt = sead3_dt_shim(fdt);
        __dt_setup_arch(fdt);
 }