summaryrefslogtreecommitdiff
path: root/arch/x86/cpu/slimbootloader/sdram.c
blob: 33e91fb6366b59d17dcfb37308b52ad027281b1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2019 Intel Corporation <www.intel.com>
 */

#include <common.h>
#include <init.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
 */
ulong board_get_usable_ram_top(ulong 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;
}