summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/generic/board-sead3.c17
-rw-r--r--arch/mips/generic/yamon-dt.c92
-rw-r--r--arch/mips/include/asm/yamon-dt.h22
3 files changed, 106 insertions, 25 deletions
diff --git a/arch/mips/generic/board-sead3.c b/arch/mips/generic/board-sead3.c
index 63fdc98738ba..97186a3a5d21 100644
--- a/arch/mips/generic/board-sead3.c
+++ b/arch/mips/generic/board-sead3.c
@@ -13,6 +13,7 @@
#include <linux/errno.h>
#include <linux/libfdt.h>
#include <linux/printk.h>
+#include <linux/sizes.h>
#include <asm/fw/fw.h>
#include <asm/io.h>
@@ -26,6 +27,15 @@
#define MIPS_REVISION_MACHINE (0xf << 4)
#define MIPS_REVISION_MACHINE_SEAD3 (0x4 << 4)
+/*
+ * Maximum 384MB RAM at physical address 0, preceding any I/O.
+ */
+static struct yamon_mem_region mem_regions[] __initdata = {
+ /* start size */
+ { 0, SZ_256M + SZ_128M },
+ {}
+};
+
static __init bool sead3_detect(void)
{
uint32_t rev;
@@ -34,6 +44,11 @@ static __init bool sead3_detect(void)
return (rev & MIPS_REVISION_MACHINE) == MIPS_REVISION_MACHINE_SEAD3;
}
+static __init int append_memory(void *fdt)
+{
+ return yamon_dt_append_memory(fdt, mem_regions);
+}
+
static __init int remove_gic(void *fdt)
{
const unsigned int cpu_ehci_int = 2;
@@ -145,7 +160,7 @@ static __init const void *sead3_fixup_fdt(const void *fdt,
if (err)
panic("Unable to patch FDT: %d", err);
- err = yamon_dt_append_memory(fdt_buf);
+ err = append_memory(fdt_buf);
if (err)
panic("Unable to patch FDT: %d", err);
diff --git a/arch/mips/generic/yamon-dt.c b/arch/mips/generic/yamon-dt.c
index 9a0c8da5a796..8e36a5baaa7e 100644
--- a/arch/mips/generic/yamon-dt.c
+++ b/arch/mips/generic/yamon-dt.c
@@ -17,6 +17,9 @@
#include <linux/printk.h>
#include <asm/fw/fw.h>
+#include <asm/yamon-dt.h>
+
+#define MAX_MEM_ARRAY_ENTRIES 2
__init int yamon_dt_append_cmdline(void *fdt)
{
@@ -43,23 +46,64 @@ __init int yamon_dt_append_cmdline(void *fdt)
return 0;
}
-__init int yamon_dt_append_memory(void *fdt)
+static unsigned int __init gen_fdt_mem_array(
+ const struct yamon_mem_region *regions,
+ __be32 *mem_array,
+ unsigned int max_entries,
+ unsigned long memsize)
+{
+ const struct yamon_mem_region *mr;
+ unsigned long size;
+ unsigned int entries = 0;
+
+ for (mr = regions; mr->size && memsize; ++mr) {
+ if (entries >= max_entries) {
+ pr_warn("Number of regions exceeds max %u\n",
+ max_entries);
+ break;
+ }
+
+ /* How much of the remaining RAM fits in the next region? */
+ size = min_t(unsigned long, memsize, mr->size);
+ memsize -= size;
+
+ /* Emit a memory region */
+ *(mem_array++) = cpu_to_be32(mr->start);
+ *(mem_array++) = cpu_to_be32(size);
+ ++entries;
+
+ /* Discard the next mr->discard bytes */
+ memsize -= min_t(unsigned long, memsize, mr->discard);
+ }
+ return entries;
+}
+
+__init int yamon_dt_append_memory(void *fdt,
+ const struct yamon_mem_region *regions)
{
unsigned long phys_memsize, memsize;
- __be32 mem_array[2];
- int err, mem_off;
- char *var;
+ __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
+ unsigned int mem_entries;
+ int i, err, mem_off;
+ char *var, param_name[10], *var_names[] = {
+ "ememsize", "memsize",
+ };
/* find memory size from the bootloader environment */
- var = fw_getenv("memsize");
- if (var) {
+ for (i = 0; i < ARRAY_SIZE(var_names); i++) {
+ var = fw_getenv(var_names[i]);
+ if (!var)
+ continue;
+
err = kstrtoul(var, 0, &phys_memsize);
- if (err) {
- pr_err("Failed to read memsize env variable '%s'\n",
- var);
- return -EINVAL;
- }
- } else {
+ if (!err)
+ break;
+
+ pr_warn("Failed to read the '%s' env variable '%s'\n",
+ var_names[i], var);
+ }
+
+ if (!phys_memsize) {
pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
phys_memsize = 32 << 20;
}
@@ -68,9 +112,14 @@ __init int yamon_dt_append_memory(void *fdt)
memsize = phys_memsize;
/* allow the user to override the usable memory */
- var = strstr(arcs_cmdline, "memsize=");
- if (var)
- memsize = memparse(var + strlen("memsize="), NULL);
+ for (i = 0; i < ARRAY_SIZE(var_names); i++) {
+ snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
+ var = strstr(arcs_cmdline, param_name);
+ if (!var)
+ continue;
+
+ memsize = memparse(var + strlen(param_name), NULL);
+ }
/* if the user says there's more RAM than we thought, believe them */
phys_memsize = max_t(unsigned long, phys_memsize, memsize);
@@ -90,18 +139,19 @@ __init int yamon_dt_append_memory(void *fdt)
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));
+ mem_entries = gen_fdt_mem_array(regions, mem_array,
+ MAX_MEM_ARRAY_ENTRIES, phys_memsize);
+ err = fdt_setprop(fdt, mem_off, "reg",
+ mem_array, mem_entries * 2 * sizeof(mem_array[0]));
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);
+ mem_entries = gen_fdt_mem_array(regions, mem_array,
+ MAX_MEM_ARRAY_ENTRIES, memsize);
err = fdt_setprop(fdt, mem_off, "linux,usable-memory",
- mem_array, sizeof(mem_array));
+ mem_array, mem_entries * 2 * sizeof(mem_array[0]));
if (err) {
pr_err("Unable to set linux,usable-memory property: %d\n", err);
return err;
diff --git a/arch/mips/include/asm/yamon-dt.h b/arch/mips/include/asm/yamon-dt.h
index 3f3367de4836..485cfe3e45e1 100644
--- a/arch/mips/include/asm/yamon-dt.h
+++ b/arch/mips/include/asm/yamon-dt.h
@@ -11,6 +11,20 @@
#ifndef __MIPS_ASM_YAMON_DT_H__
#define __MIPS_ASM_YAMON_DT_H__
+#include <linux/types.h>
+
+/**
+ * struct yamon_mem_region - Represents a contiguous range of physical RAM.
+ * @start: Start physical address.
+ * @size: Maximum size of region.
+ * @discard: Length of additional memory to discard after the region.
+ */
+struct yamon_mem_region {
+ phys_addr_t start;
+ phys_addr_t size;
+ phys_addr_t discard;
+};
+
/**
* yamon_dt_append_cmdline() - Append YAMON-provided command line to /chosen
* @fdt: the FDT blob
@@ -24,14 +38,16 @@ extern __init int yamon_dt_append_cmdline(void *fdt);
/**
* yamon_dt_append_memory() - Append YAMON-provided memory info to /memory
- * @fdt: the FDT blob
+ * @fdt: the FDT blob
+ * @regions: zero size terminated array of physical memory regions
*
* Generate a /memory node in @fdt based upon memory size information provided
- * by YAMON in its environment.
+ * by YAMON in its environment and the @regions array.
*
* Return: 0 on success, else -errno
*/
-extern __init int yamon_dt_append_memory(void *fdt);
+extern __init int yamon_dt_append_memory(void *fdt,
+ const struct yamon_mem_region *regions);
/**
* yamon_dt_serial_config() - Append YAMON-provided serial config to /chosen