blob: faf1b2a6c3540498e42f785a76c309fb7098b0d1 [file] [log] [blame]
Aamir Bohra3ee54bb2018-10-17 11:55:01 +05301/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2018 Intel Corp.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <arch/ebda.h>
Aamir Bohra3ee54bb2018-10-17 11:55:01 +053017#include <cbmem.h>
18#include <chip.h>
19#include <console/console.h>
20#include <device/device.h>
21#include <device/pci.h>
22#include <fsp/util.h>
23#include <intelblocks/ebda.h>
24#include <intelblocks/systemagent.h>
25#include <soc/pci_devs.h>
26#include <soc/smm.h>
27#include <soc/systemagent.h>
28#include <stdlib.h>
29
30void smm_region(void **start, size_t *size)
31{
32 *start = (void *)sa_get_tseg_base();
33 *size = sa_get_tseg_size();
34}
35
36/*
37 * Subregions within SMM
38 * +-------------------------+ BGSM
39 * | IED | IED_REGION_SIZE
40 * +-------------------------+
41 * | External Stage Cache | SMM_RESERVED_SIZE
42 * +-------------------------+
43 * | code and data |
44 * | (TSEG) |
45 * +-------------------------+ TSEG
46 */
47int smm_subregion(int sub, void **start, size_t *size)
48{
49 uintptr_t sub_base;
50 size_t sub_size;
51 void *smm_base;
52 const size_t ied_size = CONFIG_IED_REGION_SIZE;
53 const size_t cache_size = CONFIG_SMM_RESERVED_SIZE;
54
55 smm_region(&smm_base, &sub_size);
56 sub_base = (uintptr_t)smm_base;
57
58 switch (sub) {
59 case SMM_SUBREGION_HANDLER:
60 /* Handler starts at the base of TSEG. */
61 sub_size -= ied_size;
62 sub_size -= cache_size;
63 break;
64 case SMM_SUBREGION_CACHE:
65 /* External cache is in the middle of TSEG. */
66 sub_base += sub_size - (ied_size + cache_size);
67 sub_size = cache_size;
68 break;
69 case SMM_SUBREGION_CHIPSET:
70 /* IED is at the top. */
71 sub_base += sub_size - ied_size;
72 sub_size = ied_size;
73 break;
74 default:
75 return -1;
76 }
77
78 *start = (void *)sub_base;
79 *size = sub_size;
80
81 return 0;
82}
83
84/* Calculate ME Stolen size */
85static size_t get_imr_size(void)
86{
87 size_t imr_size;
88
89 /* ME stolen memory */
90 imr_size = MCHBAR32(IMRLIMIT) - MCHBAR32(IMRBASE);
91
92 return imr_size;
93}
94
95/* Calculate PRMRR size based on user input PRMRR size and alignment */
96static size_t get_prmrr_size(uintptr_t dram_base,
97 const struct soc_intel_icelake_config *config)
98{
99 uintptr_t prmrr_base = dram_base;
100 size_t prmrr_size;
101
102 prmrr_size = config->PrmrrSize;
103
104 /* Allocate PRMRR memory for C6DRAM */
105 if (!prmrr_size) {
106 if (config->enable_c6dram)
107 prmrr_size = 1*MiB;
108 else
109 return 0;
110 }
111
112 /*
113 * PRMRR Sizes that are > 1MB and < 32MB are
114 * not supported and will fail out.
115 */
116 if ((prmrr_size > 1*MiB) && (prmrr_size < 32*MiB))
117 die("PRMRR Sizes that are > 1MB and < 32MB are not"
118 "supported!\n");
119
120 prmrr_base -= prmrr_size;
121 if (prmrr_size >= 32*MiB)
122 prmrr_base = ALIGN_DOWN(prmrr_base, 128*MiB);
123 else
124 prmrr_base = ALIGN_DOWN(prmrr_base, 16*MiB);
125 /* PRMRR Area Size */
126 prmrr_size = dram_base - prmrr_base;
127
128 return prmrr_size;
129}
130
131/* Calculate Intel Traditional Memory size based on GSM, DSM, TSEG and DPR. */
132static size_t calculate_traditional_mem_size(uintptr_t dram_base,
133 const struct device *dev)
134{
135 uintptr_t traditional_mem_base = dram_base;
136 size_t traditional_mem_size;
137
138 if (dev->enabled) {
139 /* Read BDSM from Host Bridge */
140 traditional_mem_base -= sa_get_dsm_size();
141
142 /* Read BGSM from Host Bridge */
143 traditional_mem_base -= sa_get_gsm_size();
144 }
145 /* Get TSEG size */
146 traditional_mem_base -= sa_get_tseg_size();
147
148 /* Get DPR size */
149 if (IS_ENABLED(CONFIG_SA_ENABLE_DPR))
150 traditional_mem_base -= sa_get_dpr_size();
151
152 /* Traditional Area Size */
153 traditional_mem_size = dram_base - traditional_mem_base;
154
155 return traditional_mem_size;
156}
157
158/*
159 * Calculate Intel Reserved Memory size based on
160 * PRMRR size, Me stolen memory and PTT selection.
161 */
162static size_t calculate_reserved_mem_size(uintptr_t dram_base,
163 const struct device *dev)
164{
165 uintptr_t reserve_mem_base = dram_base;
166 size_t reserve_mem_size;
167 const struct soc_intel_icelake_config *config;
168
169 config = dev->chip_info;
170
171 /* Get PRMRR size */
172 reserve_mem_base -= get_prmrr_size(reserve_mem_base, config);
173
174 /* Get Tracehub size */
175 reserve_mem_base -= get_imr_size();
176
177 /* Traditional Area Size */
178 reserve_mem_size = dram_base - reserve_mem_base;
179
180 return reserve_mem_size;
181}
182
183/*
184 * Host Memory Map:
185 *
186 * +--------------------------+ TOUUD
187 * | |
188 * +--------------------------+ 4GiB
189 * | PCI Address Space |
190 * +--------------------------+ TOLUD (also maps into MC address space)
191 * | iGD |
192 * +--------------------------+ BDSM
193 * | GTT |
194 * +--------------------------+ BGSM
195 * | TSEG |
196 * +--------------------------+ TSEGMB
197 * | DMA Protected Region |
198 * +--------------------------+ DPR
199 * | PRM (C6DRAM/SGX) |
200 * +--------------------------+ PRMRR
201 * | ME Stolen Memory |
202 * +--------------------------+ ME Stolen
203 * | PTT |
204 * +--------------------------+ top_of_ram
205 * | Reserved - FSP/CBMEM |
206 * +--------------------------+ TOLUM
207 * | Usage DRAM |
208 * +--------------------------+ 0
209 *
210 * Some of the base registers above can be equal making the size of those
211 * regions 0. The reason is because the memory controller internally subtracts
212 * the base registers from each other to determine sizes of the regions. In
213 * other words, the memory map is in a fixed order no matter what.
214 */
215static uintptr_t calculate_dram_base(size_t *reserved_mem_size)
216{
217 uintptr_t dram_base;
218 const struct device *dev;
219
220 dev = dev_find_slot(0, PCI_DEVFN(SA_DEV_SLOT_IGD, 0));
221 if (!dev)
222 die("ERROR - IGD device not found!");
223
224 /* Read TOLUD from Host Bridge offset */
225 dram_base = sa_get_tolud_base();
226
227 /* Get Intel Traditional Memory Range Size */
228 dram_base -= calculate_traditional_mem_size(dram_base, dev);
229
230 /* Get Intel Reserved Memory Range Size */
231 *reserved_mem_size = calculate_reserved_mem_size(dram_base, dev);
232
233 dram_base -= *reserved_mem_size;
234
235 return dram_base;
236}
237
238/*
239 * SoC implementation
240 *
241 * SoC call to summarize all Intel Reserve MMIO size and report to SA
242 */
243size_t soc_reserved_mmio_size(void)
244{
245 struct ebda_config cfg;
246
247 retrieve_ebda_object(&cfg);
248
249 /* Get Intel Reserved Memory Range Size */
250 return cfg.reserved_mem_size;
251}
252
253/* Fill up memory layout information */
254void fill_soc_memmap_ebda(struct ebda_config *cfg)
255{
256 size_t chipset_mem_size;
257
258 cfg->tolum_base = calculate_dram_base(&chipset_mem_size);
259 cfg->reserved_mem_size = chipset_mem_size;
260}
261
262void cbmem_top_init(void)
263{
264 /* Fill up EBDA area */
265 fill_ebda_area();
266}
267
268/*
269 * +-------------------------+ Top of RAM (aligned)
270 * | System Management Mode |
271 * | code and data | Length: CONFIG_TSEG_SIZE
272 * | (TSEG) |
273 * +-------------------------+ SMM base (aligned)
274 * | |
275 * | Chipset Reserved Memory |
276 * | |
277 * +-------------------------+ top_of_ram (aligned)
278 * | |
279 * | CBMEM Root |
280 * | |
281 * +-------------------------+
282 * | |
283 * | FSP Reserved Memory |
284 * | |
285 * +-------------------------+
286 * | |
287 * | Various CBMEM Entries |
288 * | |
289 * +-------------------------+ top_of_stack (8 byte aligned)
290 * | |
291 * | stack (CBMEM Entry) |
292 * | |
293 * +-------------------------+
294 */
295void *cbmem_top(void)
296{
297 struct ebda_config ebda_cfg;
298
299 /*
300 * Check if Tseg has been initialized, we will use this as a flag
301 * to check if the MRC is done, and only then continue to read the
302 * PRMMR_BASE MSR. The system hangs if PRMRR_BASE MSR is read before
303 * PRMRR_MASK MSR lock bit is set.
304 */
305 if (sa_get_tseg_base() == 0)
306 return NULL;
307
308 retrieve_ebda_object(&ebda_cfg);
309
310 return (void *)(uintptr_t)ebda_cfg.tolum_base;
311}