From bbc1b99e8b8a1b87c2d0d959a1fcd1990abe82dd Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 7 Aug 2015 16:12:45 -0600 Subject: [PATCH] ARM: tegra: represent RAM in 1 or 2 banks 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 Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- 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 37953cfda8..8ecc67459a 100644 --- a/arch/arm/mach-tegra/board2.c +++ b/arch/arm/mach-tegra/board2.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #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 145f63587f..6fe5f2ce65 100644 --- a/include/configs/tegra-common.h +++ b/include/configs/tegra-common.h @@ -111,7 +111,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 */ -- 2.39.5