diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-tegra/board2.c | 120 |
1 files changed, 106 insertions, 14 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 <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 |