x86: slimbootloader: Add memory configuration
[oweals/u-boot.git] / arch / x86 / cpu / slimbootloader / sdram.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2019 Intel Corporation <www.intel.com>
4  */
5
6 #include <common.h>
7 #include <linux/sizes.h>
8 #include <asm/e820.h>
9 #include <asm/arch/slimbootloader.h>
10
11 DECLARE_GLOBAL_DATA_PTR;
12
13 /**
14  * This returns a data pointer of memory map info from the guid hob.
15  *
16  * @return: A data pointer of memory map info hob
17  */
18 static struct sbl_memory_map_info *get_memory_map_info(void)
19 {
20         struct sbl_memory_map_info *data;
21         const efi_guid_t guid = SBL_MEMORY_MAP_INFO_GUID;
22
23         if (!gd->arch.hob_list)
24                 return NULL;
25
26         data = hob_get_guid_hob_data(gd->arch.hob_list, NULL, &guid);
27         if (!data)
28                 panic("memory map info hob not found\n");
29         if (!data->count)
30                 panic("invalid number of memory map entries\n");
31
32         return data;
33 }
34
35 #define for_each_if(condition) if (!(condition)) {} else
36
37 #define for_each_memory_map_entry_reversed(iter, entries) \
38         for (iter = entries->count - 1; iter >= 0; iter--) \
39                 for_each_if(entries->entry[iter].type == E820_RAM)
40
41 /**
42  * This is to give usable memory region information for u-boot relocation.
43  * so search usable memory region lower than 4GB.
44  * The memory map entries from Slim Bootloader hob are already sorted.
45  *
46  * @total_size: The memory size that u-boot occupies
47  * @return    : The top available memory address lower than 4GB
48  */
49 ulong board_get_usable_ram_top(ulong total_size)
50 {
51         struct sbl_memory_map_info *data;
52         int i;
53         u64 addr_start;
54         u64 addr_end;
55         ulong ram_top;
56
57         data = get_memory_map_info();
58
59         /**
60          * sorted memory map entries from Slim Bootloader based on physical
61          * start memory address, from low to high. So do reversed search to
62          * get highest usable, suitable size, 4KB aligned available memory
63          * under 4GB.
64          */
65         ram_top = 0;
66         for_each_memory_map_entry_reversed(i, data) {
67                 addr_start = data->entry[i].addr;
68                 addr_end = addr_start + data->entry[i].size;
69
70                 if (addr_start > SZ_4G)
71                         continue;
72
73                 if (addr_end > SZ_4G)
74                         addr_end = SZ_4G;
75
76                 if (addr_end < total_size)
77                         continue;
78
79                 /* to relocate u-boot at 4K aligned memory */
80                 addr_end = rounddown(addr_end - total_size, SZ_4K);
81                 if (addr_end >= addr_start) {
82                         ram_top = (ulong)addr_end + total_size;
83                         break;
84                 }
85         }
86
87         if (!ram_top)
88                 panic("failed to find available memory for relocation!");
89
90         return ram_top;
91 }
92
93 /**
94  * The memory initialization has already been done in previous Slim Bootloader
95  * stage thru FSP-M. Instead, this sets the ram_size from the memory map info
96  * hob.
97  */
98 int dram_init(void)
99 {
100         struct sbl_memory_map_info *data;
101         int i;
102         u64 ram_size;
103
104         data = get_memory_map_info();
105
106         /**
107          * sorted memory map entries from Slim Bootloader based on physical
108          * start memory address, from low to high. So do reversed search to
109          * simply get highest usable memory address as RAM size
110          */
111         ram_size = 0;
112         for_each_memory_map_entry_reversed(i, data) {
113                 /* simply use the highest usable memory address as RAM size */
114                 ram_size = data->entry[i].addr + data->entry[i].size;
115                 break;
116         }
117
118         if (!ram_size)
119                 panic("failed to detect memory size");
120
121         gd->ram_size = ram_size;
122         return 0;
123 }
124
125 int dram_init_banksize(void)
126 {
127         if (!CONFIG_NR_DRAM_BANKS)
128                 return 0;
129
130         /* simply use a single bank to have whole size for now */
131         gd->bd->bi_dram[0].start = 0;
132         gd->bd->bi_dram[0].size = gd->ram_size;
133         return 0;
134 }
135
136 unsigned int install_e820_map(unsigned int max_entries,
137                               struct e820_entry *entries)
138 {
139         struct sbl_memory_map_info *data;
140         unsigned int i;
141
142         data = get_memory_map_info();
143
144         for (i = 0; i < data->count; i++) {
145                 entries[i].addr = data->entry[i].addr;
146                 entries[i].size = data->entry[i].size;
147                 entries[i].type = data->entry[i].type;
148         }
149
150         return i;
151 }