[PATCH v2 2/2] arm64: versal2: Populate DRAM banks before page table size calculation
Pranav Sanwal
pranav.sanwal at amd.com
Wed Dec 10 13:15:39 CET 2025
Move DRAM bank detection from fdtdec to custom implementation to
ensure memory banks are populated before get_page_table_size() is
called during MMU initialization.
The current fdtdec-based approach populates gd->bd->bi_dram[] too
late in the boot sequence, causing get_page_table_size() to be
called with unpopulated DRAM information. This prevents dynamic
page table sizing based on actual memory configuration.
Parse /memory nodes in dram_init() to fill versal2_mem_map[]
early enough for MMU setup. Supports up to
CONFIG_NR_DRAM_BANKS (36) non-contiguous banks with high memory
regions (>4GB) and use __weak get_page_table_size implementation
to estimate page table size based on the populated DRAM banks.
Signed-off-by: Pranav Sanwal <pranav.sanwal at amd.com>
---
arch/arm/mach-versal2/cpu.c | 57 ++++++++++++---
.../arm/mach-versal2/include/mach/sys_proto.h | 4 +-
board/amd/versal2/board.c | 70 +++++++++++++++----
3 files changed, 107 insertions(+), 24 deletions(-)
diff --git a/arch/arm/mach-versal2/cpu.c b/arch/arm/mach-versal2/cpu.c
index 2dfcadb369e..896ff958bc0 100644
--- a/arch/arm/mach-versal2/cpu.c
+++ b/arch/arm/mach-versal2/cpu.c
@@ -63,30 +63,71 @@ static struct mm_region versal2_mem_map[VERSAL2_MEM_MAP_MAX] = {
}
};
-void mem_map_fill(void)
+/**
+ * mem_map_fill() - Populate global memory map with DRAM banks
+ * @bank_info: Array of memory regions parsed from device tree
+ * @num_banks: Number of valid DRAM banks in bank_info array
+ *
+ * Copies DRAM bank information into the global versal2_mem_map[] array
+ * starting at index VERSAL2_MEM_MAP_USED (5), which is after the fixed
+ * device mappings. This must be called early in boot before MMU
+ * initialization so that get_page_table_size() can calculate the
+ * required page table size based on actual memory configuration.
+ */
+void mem_map_fill(struct mm_region *bank_info, u32 num_banks)
{
int banks = VERSAL2_MEM_MAP_USED;
- for (int i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
- /* Zero size means no more DDR that's this is end */
- if (!gd->bd->bi_dram[i].size)
- break;
+ for (int i = 0; i < num_banks; i++) {
+ if (banks > VERSAL2_MEM_MAP_MAX)
+ return;
- versal2_mem_map[banks].virt = gd->bd->bi_dram[i].start;
- versal2_mem_map[banks].phys = gd->bd->bi_dram[i].start;
- versal2_mem_map[banks].size = gd->bd->bi_dram[i].size;
+ versal2_mem_map[banks].virt = bank_info[i].phys;
+ versal2_mem_map[banks].phys = bank_info[i].phys;
+ versal2_mem_map[banks].size = bank_info[i].size;
versal2_mem_map[banks].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE;
banks = banks + 1;
}
}
+/**
+ * fill_gd_mem_info() - Copy DRAM banks from mem_map to bd_info
+ *
+ * Transfers DRAM bank information from the global versal2_mem_map[]
+ * array to bd->bi_dram[] for passing memory configuration to the
+ * Linux kernel via boot parameters (ATAGS/FDT). Each bank's physical
+ * address and size are copied.
+ *
+ * This is called during dram_init_banksize() after the memory map
+ * has been populated by mem_map_fill() in dram_init().
+ *
+ * Context: Called after dram_init() but before kernel handoff
+ * Side effects: Modifies bd->bi_dram[] array
+ */
+void fill_bd_mem_info(void)
+{
+ struct bd_info *bd = gd->bd;
+ int banks = VERSAL2_MEM_MAP_USED;
+
+ for (int i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ if (!versal2_mem_map[banks].size)
+ break;
+
+ bd->bi_dram[i].start = versal2_mem_map[banks].phys;
+ bd->bi_dram[i].size = versal2_mem_map[banks].size;
+ banks++;
+ }
+}
+
struct mm_region *mem_map = versal2_mem_map;
+#if CONFIG_IS_ENABLED(SYS_MEM_RSVD_FOR_MMU)
u64 get_page_table_size(void)
{
return 0x14000;
}
+#endif
U_BOOT_DRVINFO(soc_amd_versal2) = {
.name = "soc_amd_versal2",
diff --git a/arch/arm/mach-versal2/include/mach/sys_proto.h b/arch/arm/mach-versal2/include/mach/sys_proto.h
index 7b1726a7ef4..cee13488620 100644
--- a/arch/arm/mach-versal2/include/mach/sys_proto.h
+++ b/arch/arm/mach-versal2/include/mach/sys_proto.h
@@ -5,5 +5,7 @@
*/
#include <linux/build_bug.h>
+#include <asm/armv8/mmu.h>
-void mem_map_fill(void);
+void mem_map_fill(struct mm_region *bank_info, u32 num_banks);
+void fill_bd_mem_info(void);
diff --git a/board/amd/versal2/board.c b/board/amd/versal2/board.c
index 7d91d288d2e..2139e93b865 100644
--- a/board/amd/versal2/board.c
+++ b/board/amd/versal2/board.c
@@ -18,6 +18,7 @@
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sys_proto.h>
+#include <asm/sections.h>
#include <dm/device.h>
#include <dm/uclass.h>
#include <versalpl.h>
@@ -26,6 +27,7 @@
#include <linux/bitfield.h>
#include <debug_uart.h>
#include <generated/dt.h>
+#include <linux/ioport.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -339,28 +341,66 @@ int board_late_init(void)
int dram_init_banksize(void)
{
- int ret;
-
- ret = fdtdec_setup_memory_banksize();
- if (ret)
- return ret;
-
- mem_map_fill();
-
+ fill_bd_mem_info();
return 0;
}
int dram_init(void)
{
- int ret;
+ struct mm_region bank_info[CONFIG_NR_DRAM_BANKS];
+ ofnode mem = ofnode_null();
+ struct resource res;
+ int ret, i, reg = 0;
+ u32 num_banks = 0;
+ u64 text = (u64)_start;
+
+ gd->ram_base = (unsigned long)~0;
+
+ mem = get_next_memory_node(mem);
+ if (!ofnode_valid(mem)) {
+ printf("%s: Missing /memory node\n", __func__);
+ return -EINVAL;
+ }
- if (IS_ENABLED(CONFIG_SYS_MEM_RSVD_FOR_MMU))
- ret = fdtdec_setup_mem_size_base();
- else
- ret = fdtdec_setup_mem_size_base_lowest();
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ ret = ofnode_read_resource(mem, reg++, &res);
+ if (ret < 0) {
+ reg = 0;
+ mem = get_next_memory_node(mem);
+ if (!ofnode_valid(mem))
+ break;
+
+ ret = ofnode_read_resource(mem, reg++, &res);
+ if (ret < 0)
+ break;
+ }
- if (ret)
- return -EINVAL;
+ if (ret != 0)
+ return -EINVAL;
+
+ bank_info[i].phys = (phys_addr_t)res.start;
+ bank_info[i].size = (phys_size_t)(res.end - res.start + 1);
+
+ if (bank_info[i].size == 0)
+ break;
+
+ debug("%s: DRAM Bank #%d: start = 0x%llx, size = 0x%llx\n",
+ __func__, i, (unsigned long long)bank_info[i].phys,
+ (unsigned long long)bank_info[i].size);
+
+ if (text > bank_info[i].phys &&
+ text < (bank_info[i].phys + bank_info[i].size)) {
+ gd->ram_base = bank_info[i].phys;
+ gd->ram_size = bank_info[i].size;
+ debug("%s:TEXT BASE = 0x%llx,\n", __func__, text);
+ }
+ num_banks++;
+ }
+
+ mem_map_fill(bank_info, num_banks);
+
+ debug("%s: Initial DRAM base %lx size %lx\n", __func__,
+ gd->ram_base, (unsigned long)gd->ram_size);
return 0;
}
--
2.34.1
More information about the U-Boot
mailing list