| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * Copyright (C) 2019 Intel Corporation <www.intel.com> | |
| */ | |
| #include <init.h> | |
| #include <asm/global_data.h> | |
| #include <linux/sizes.h> | |
| #include <asm/e820.h> | |
| #include <asm/arch/slimbootloader.h> | |
| DECLARE_GLOBAL_DATA_PTR; | |
| /** | |
| * This returns a data pointer of memory map info from the guid hob. | |
| * | |
| * @return: A data pointer of memory map info hob | |
| */ | |
| static struct sbl_memory_map_info *get_memory_map_info(void) | |
| { | |
| struct sbl_memory_map_info *data; | |
| const efi_guid_t guid = SBL_MEMORY_MAP_INFO_GUID; | |
| if (!gd->arch.hob_list) | |
| return NULL; | |
| data = hob_get_guid_hob_data(gd->arch.hob_list, NULL, &guid); | |
| if (!data) | |
| panic("memory map info hob not found\n"); | |
| if (!data->count) | |
| panic("invalid number of memory map entries\n"); | |
| return data; | |
| } | |
| #define for_each_if(condition) if (!(condition)) {} else | |
| #define for_each_memory_map_entry_reversed(iter, entries) \ | |
| for (iter = entries->count - 1; iter >= 0; iter--) \ | |
| for_each_if(entries->entry[iter].type == E820_RAM) | |
| /** | |
| * This is to give usable memory region information for u-boot relocation. | |
| * so search usable memory region lower than 4GB. | |
| * The memory map entries from Slim Bootloader hob are already sorted. | |
| * | |
| * @total_size: The memory size that u-boot occupies | |
| * Return: : The top available memory address lower than 4GB | |
| */ | |
| phys_addr_t board_get_usable_ram_top(phys_size_t total_size) | |
| { | |
| struct sbl_memory_map_info *data; | |
| int i; | |
| u64 addr_start; | |
| u64 addr_end; | |
| ulong ram_top; | |
| data = get_memory_map_info(); | |
| /** | |
| * sorted memory map entries from Slim Bootloader based on physical | |
| * start memory address, from low to high. So do reversed search to | |
| * get highest usable, suitable size, 4KB aligned available memory | |
| * under 4GB. | |
| */ | |
| ram_top = 0; | |
| for_each_memory_map_entry_reversed(i, data) { | |
| addr_start = data->entry[i].addr; | |
| addr_end = addr_start + data->entry[i].size; | |
| if (addr_start > SZ_4G) | |
| continue; | |
| if (addr_end > SZ_4G) | |
| addr_end = SZ_4G; | |
| if (addr_end < total_size) | |
| continue; | |
| /* to relocate u-boot at 4K aligned memory */ | |
| addr_end = rounddown(addr_end - total_size, SZ_4K); | |
| if (addr_end >= addr_start) { | |
| ram_top = (ulong)addr_end + total_size; | |
| break; | |
| } | |
| } | |
| if (!ram_top) | |
| panic("failed to find available memory for relocation!"); | |
| return ram_top; | |
| } | |
| /** | |
| * The memory initialization has already been done in previous Slim Bootloader | |
| * stage thru FSP-M. Instead, this sets the ram_size from the memory map info | |
| * hob. | |
| */ | |
| int dram_init(void) | |
| { | |
| struct sbl_memory_map_info *data; | |
| int i; | |
| u64 ram_size; | |
| data = get_memory_map_info(); | |
| /** | |
| * sorted memory map entries from Slim Bootloader based on physical | |
| * start memory address, from low to high. So do reversed search to | |
| * simply get highest usable memory address as RAM size | |
| */ | |
| ram_size = 0; | |
| for_each_memory_map_entry_reversed(i, data) { | |
| /* simply use the highest usable memory address as RAM size */ | |
| ram_size = data->entry[i].addr + data->entry[i].size; | |
| break; | |
| } | |
| if (!ram_size) | |
| panic("failed to detect memory size"); | |
| gd->ram_size = ram_size; | |
| return 0; | |
| } | |
| int dram_init_banksize(void) | |
| { | |
| if (!CONFIG_NR_DRAM_BANKS) | |
| return 0; | |
| /* simply use a single bank to have whole size for now */ | |
| gd->bd->bi_dram[0].start = 0; | |
| gd->bd->bi_dram[0].size = gd->ram_size; | |
| return 0; | |
| } | |
| unsigned int install_e820_map(unsigned int max_entries, | |
| struct e820_entry *entries) | |
| { | |
| struct sbl_memory_map_info *data; | |
| unsigned int i; | |
| data = get_memory_map_info(); | |
| for (i = 0; i < data->count; i++) { | |
| entries[i].addr = data->entry[i].addr; | |
| entries[i].size = data->entry[i].size; | |
| entries[i].type = data->entry[i].type; | |
| } | |
| return i; | |
| } |