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
13DECLARE_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 */
20static 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 */
51phys_addr_t board_get_usable_ram_top(phys_size_t 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 */
100int 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
127int 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
138unsigned 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