diff mbox series

lib: fdt: Introduce fdtdec_setup_mem_size_base_lowest()

Message ID 7c3eeac130d3c58327efdafa9ed50980ad335ff4.1594299767.git.michal.simek@xilinx.com
State New
Headers show
Series lib: fdt: Introduce fdtdec_setup_mem_size_base_lowest() | expand

Commit Message

Michal Simek July 9, 2020, 1:02 p.m. UTC
New function should be called from board dram_init() because it initialized
gd->ram_base/ram_size. It finds the lowest available memory.

On systems with multiple memory nodes finding out the first memory node by
fdtdec_setup_mem_size_base() is not enough because this memory can be above
actual U-Boot VA mapping. Currently only mapping till 39bit is supported
(Full 44bit mapping was removed by commit 7985cdf74b28 ("arm64: Remove
non-full-va map code")).
If DT starts with the first memory node above 39bit address then system can
be unpredictable.

The function is available only when multiple memory bank support is
enabled.

Calling fdtdec_setup_memory_banksize() from dram_init() is not possible
because fdtdec_setup_memory_banksize() is saving dram information to bd
structure which is placed on stack but not initialized at this time. Also
stack is placed at location setup in dram_init().

Signed-off-by: Michal Simek <michal.simek at xilinx.com>
---

 board/xilinx/versal/board.c |  2 +-
 include/fdtdec.h            | 17 ++++++++++++++
 lib/fdtdec.c                | 44 +++++++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 1 deletion(-)

Comments

Simon Glass July 10, 2020, 12:35 a.m. UTC | #1
Hi Michal,

On Thu, 9 Jul 2020 at 07:02, Michal Simek <michal.simek at xilinx.com> wrote:
>
> New function should be called from board dram_init() because it initialized
> gd->ram_base/ram_size. It finds the lowest available memory.
>
> On systems with multiple memory nodes finding out the first memory node by
> fdtdec_setup_mem_size_base() is not enough because this memory can be above
> actual U-Boot VA mapping. Currently only mapping till 39bit is supported
> (Full 44bit mapping was removed by commit 7985cdf74b28 ("arm64: Remove
> non-full-va map code")).
> If DT starts with the first memory node above 39bit address then system can
> be unpredictable.
>
> The function is available only when multiple memory bank support is
> enabled.
>
> Calling fdtdec_setup_memory_banksize() from dram_init() is not possible
> because fdtdec_setup_memory_banksize() is saving dram information to bd
> structure which is placed on stack but not initialized at this time. Also
> stack is placed at location setup in dram_init().
>
> Signed-off-by: Michal Simek <michal.simek at xilinx.com>
> ---
>
>  board/xilinx/versal/board.c |  2 +-
>  include/fdtdec.h            | 17 ++++++++++++++
>  lib/fdtdec.c                | 44 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 62 insertions(+), 1 deletion(-)

This should move over to the livetree API (using ofnode) and please
add a little test. We should be trying to retire fdtdec. Probably
should split the xilinx patch separately too.

Regards,
Simon
diff mbox series

Patch

diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c
index 45cf1d2d0cad..3dc7044b213e 100644
--- a/board/xilinx/versal/board.c
+++ b/board/xilinx/versal/board.c
@@ -229,7 +229,7 @@  int dram_init_banksize(void)
 
 int dram_init(void)
 {
-	if (fdtdec_setup_mem_size_base() != 0)
+	if (fdtdec_setup_mem_size_base_lowest() != 0)
 		return -EINVAL;
 
 	return 0;
diff --git a/include/fdtdec.h b/include/fdtdec.h
index abd6d4267194..6e378028e975 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -946,6 +946,23 @@  int fdtdec_setup_mem_size_base_fdt(const void *blob);
  */
 int fdtdec_setup_mem_size_base(void);
 
+/**
+ * fdtdec_setup_mem_size_base_lowest() - decode and setup gd->ram_size and
+ * gd->ram_start by lowest available memory base
+ *
+ * Decode the /memory 'reg' property to determine the lowest start of the memory
+ * bank bank and populate the global data with it.
+ *
+ * This function should be called from a boards dram_init(). This helper
+ * function allows for boards to query the device tree for DRAM size and start
+ * address instead of hard coding the value in the case where the memory size
+ * and start address cannot be detected automatically.
+ *
+ * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or
+ * invalid
+ */
+int fdtdec_setup_mem_size_base_lowest(void);
+
 /**
  * fdtdec_setup_memory_banksize_fdt() - decode and populate gd->bd->bi_dram
  *
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 0dd7ff1ac3f7..04b32f675876 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -1115,7 +1115,51 @@  int fdtdec_setup_memory_banksize_fdt(const void *blob)
 int fdtdec_setup_memory_banksize(void)
 {
 	return fdtdec_setup_memory_banksize_fdt(gd->fdt_blob);
+}
+
+int fdtdec_setup_mem_size_base_lowest(void)
+{
+	int bank, ret, mem, reg = 0;
+	struct fdt_resource res;
+	unsigned long base;
+	phys_size_t size;
+	const void *blob = gd->fdt_blob;
+
+	gd->ram_base = (unsigned long)~0;
+
+	mem = get_next_memory_node(blob, -1);
+	if (mem < 0) {
+		debug("%s: Missing /memory node\n", __func__);
+		return -EINVAL;
+	}
 
+	for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+		ret = fdt_get_resource(blob, mem, "reg", reg++, &res);
+		if (ret == -FDT_ERR_NOTFOUND) {
+			reg = 0;
+			mem = get_next_memory_node(blob, mem);
+			if (mem == -FDT_ERR_NOTFOUND)
+				break;
+
+			ret = fdt_get_resource(blob, mem, "reg", reg++, &res);
+			if (ret == -FDT_ERR_NOTFOUND)
+				break;
+		}
+		if (ret != 0)
+			return -EINVAL;
+
+		base = (unsigned long)res.start;
+		size = (phys_size_t)(res.end - res.start + 1);
+
+		if (gd->ram_base > base && size) {
+			gd->ram_base = base;
+			gd->ram_size = size;
+			debug("%s: Initial DRAM base %lx size %lx\n",
+			      __func__, base, (unsigned long)size);
+		}
+	}
+
+	return 0;
 }
 #endif