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