From: Pranav Sanwal <[email protected]> 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 <[email protected]> Signed-off-by: Michal Simek <[email protected]> --- arch/arm/mach-versal2/cpu.c | 57 ++++++++++++--- .../arm/mach-versal2/include/mach/sys_proto.h | 4 +- board/amd/versal2/board.c | 70 +++++++++++++++---- include/dm/ofnode.h | 2 + 4 files changed, 109 insertions(+), 24 deletions(-) diff --git a/arch/arm/mach-versal2/cpu.c b/arch/arm/mach-versal2/cpu.c index 2dfcadb369eb..896ff958bc02 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 7b1726a7ef40..cee134886208 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 1fd05a1157ab..ba5900cc3d2e 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> @@ -27,6 +28,7 @@ #include <linux/bitfield.h> #include <debug_uart.h> #include <generated/dt.h> +#include <linux/ioport.h> DECLARE_GLOBAL_DATA_PTR; @@ -361,28 +363,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: start = 0x%lx, size = 0x%lx\n", __func__, + gd->ram_base, (unsigned long)gd->ram_size); return 0; } diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 120393426dbf..5be9513f5238 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -1886,4 +1886,6 @@ int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src, */ int ofnode_delete(ofnode *nodep); +ofnode get_next_memory_node(ofnode mem); + #endif -- 2.43.0 base-commit: ed4a3618875869287b87b6b57fd55f4c6a36f046 branch: debian-sent3

