[U-Boot] [PATCH 3/3] ARM: tegra: represent RAM in 1 or 2 banks

Stephen Warren swarren at wwwdotorg.org
Sat Aug 8 00:12:45 CEST 2015


From: Stephen Warren <swarren at nvidia.com>

Represent all available RAM in either one or two banks. The first bank
describes any RAM below 4GB. The second bank describes any RAM above 4GB.

This split is driven by the following requirements:
- The NVIDIA L4T kernel requires separate entries in the DT /memory/reg
  property for memory below and above the 4GB boundary. The layout of that
  DT property is directly driven by the entries in the U-Boot bank array.
- On systems with RAM beyond a physical address of 4GB, the potential
  existence of a carve-out at the end of RAM below 4GB can only be
  represented using multiple banks, since usable RAM is not contiguous.

While making this change, add a lot more comments re: how and why RAM is
represented in banks, and implement a few more "semantic" functions that
define (and perhaps later detect at run-time) the size of any carve-out.

Signed-off-by: Stephen Warren <swarren at nvidia.com>
---
 arch/arm/mach-tegra/board2.c   | 120 ++++++++++++++++++++++++++++++++++++-----
 include/configs/tegra-common.h |   2 +-
 2 files changed, 107 insertions(+), 15 deletions(-)

diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c
index 37953cfda8a1..8ecc67459a10 100644
--- a/arch/arm/mach-tegra/board2.c
+++ b/arch/arm/mach-tegra/board2.c
@@ -10,6 +10,7 @@
 #include <errno.h>
 #include <ns16550.h>
 #include <linux/compiler.h>
+#include <linux/sizes.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #ifdef CONFIG_LCD
@@ -287,27 +288,118 @@ void pad_init_mmc(struct mmc_host *host)
 }
 #endif	/* MMC */
 
+/*
+ * In some SW environments, a memory carve-out exists to house a secure
+ * monitor, a trusted OS, and/or various statically allocated media buffers.
+ *
+ * This carveout exists at the highest possible address that is within a
+ * 32-bit physical address space.
+ *
+ * This function returns the total size of this carve-out. At present, the
+ * returned value is hard-coded for simplicity. In the future, it may be
+ * possible to determine the carve-out size:
+ * - By querying some run-time information source, such as:
+ *   - A structure passed to U-Boot by earlier boot software.
+ *   - SoC registers.
+ *   - A call into the secure monitor.
+ * - In the per-board U-Boot configuration header, based on knowledge of the
+ *   SW environment that U-Boot is being built for.
+ *
+ * For now, we support two configurations in U-Boot:
+ * - 32-bit ports without any form of carve-out.
+ * - 64 bit ports which are assumed to use a carve-out of a conservatively
+ *   hard-coded size.
+ */
+static ulong carveout_size(void)
+{
 #ifdef CONFIG_ARM64
+	return SZ_512M;
+#else
+	return 0;
+#endif
+}
+
+/*
+ * Determine the amount of usable RAM below 4GiB, taking into account any
+ * carve-out that may be assigned.
+ */
+static ulong usable_ram_size_below_4g(void)
+{
+	ulong total_size_below_4g;
+	ulong usable_size_below_4g;
+
+	/*
+	 * The total size of RAM below 4GiB is the lesser address of:
+	 * (a) 2GiB itself (RAM starts at 2GiB, and 4GiB - 2GiB == 2GiB).
+	 * (b) The size RAM physically present in the system.
+	 */
+	if (gd->ram_size < SZ_2G)
+		total_size_below_4g = gd->ram_size;
+	else
+		total_size_below_4g = SZ_2G;
+
+	/* Calculate usable RAM by subtracting out any carve-out size */
+	usable_size_below_4g = total_size_below_4g - carveout_size();
+
+	return usable_size_below_4g;
+}
+
+/*
+ * Represent all available RAM in either one or two banks.
+ *
+ * The first bank describes any usable RAM below 4GiB.
+ * The second bank describes any RAM above 4GiB.
+ *
+ * This split is driven by the following requirements:
+ * - The NVIDIA L4T kernel requires separate entries in the DT /memory/reg
+ *   property for memory below and above the 4GiB boundary. The layout of that
+ *   DT property is directly driven by the entries in the U-Boot bank array.
+ * - The potential existence of a carve-out at the end of RAM below 4GiB can
+ *   only be represented using multiple banks.
+ *
+ * Explicitly removing the carve-out RAM from the bank entries makes the RAM
+ * layout a bit more obvious, e.g. when running "bdinfo" at the U-Boot
+ * command-line.
+ *
+ * This does mean that the DT U-Boot passes to the Linux kernel will not
+ * include this RAM in /memory/reg at all. An alternative would be to include
+ * all RAM in the U-Boot banks (and hence DT), and add a /memreserve/ node
+ * into DT to stop the kernel from using the RAM. IIUC, I don't /think/ the
+ * Linux kernel will ever need to access any RAM in* the carve-out via a CPU
+ * mapping, so either way is acceptable.
+ *
+ * On 32-bit systems, we never define a bank for RAM above 4GiB, since the
+ * start address of that bank cannot be represented in the 32-bit .size
+ * field.
+ */
+void dram_init_banksize(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size = usable_ram_size_below_4g();
+
+#ifdef CONFIG_PHYS_64BIT
+	if (gd->ram_size > SZ_2G) {
+		gd->bd->bi_dram[1].start = 0x100000000;
+		gd->bd->bi_dram[1].size = gd->ram_size - SZ_2G;
+	} else
+#endif
+	{
+		gd->bd->bi_dram[1].start = 0;
+		gd->bd->bi_dram[1].size = 0;
+	}
+}
+
 /*
  * Most hardware on 64-bit Tegra is still restricted to DMA to the lower
  * 32-bits of the physical address space. Cap the maximum usable RAM area
  * at 4 GiB to avoid DMA buffers from being allocated beyond the 32-bit
- * boundary that most devices can address.
+ * boundary that most devices can address. Also, don't let U-Boot use any
+ * carve-out, as mentioned above.
  *
- * Additionally, ARM64 devices typically run a secure monitor in EL3 and
- * U-Boot in EL2, and set up some secure RAM carve-outs to contain the EL3
- * code and data. These carve-outs are located at the top of 32-bit address
- * space. Restrict U-Boot's RAM usage to well below the location of those
- * carve-outs. Ideally, we would the secure monitor would inform U-Boot of
- * exactly which RAM it could use at run-time. However, I'm not sure how to
- * do that at present (and even if such a mechanism does exist, it would
- * likely not be generic across all forms of secure monitor).
+ * This function is called before dram_init_banksize(), so we can't simply
+ * return gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size.
  */
 ulong board_get_usable_ram_top(ulong total_size)
 {
-	if (gd->ram_top > 0xe0000000)
-		return 0xe0000000;
-
-	return gd->ram_top;
+	return CONFIG_SYS_SDRAM_BASE + usable_ram_size_below_4g();
 }
-#endif
diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h
index ffe167e85ac3..5888555743db 100644
--- a/include/configs/tegra-common.h
+++ b/include/configs/tegra-common.h
@@ -115,7 +115,7 @@
 /*-----------------------------------------------------------------------
  * Physical Memory Map
  */
-#define CONFIG_NR_DRAM_BANKS	1
+#define CONFIG_NR_DRAM_BANKS	2
 #define PHYS_SDRAM_1		NV_PA_SDRC_CS0
 #define PHYS_SDRAM_1_SIZE	0x20000000	/* 512M */
 
-- 
1.9.1



More information about the U-Boot mailing list