blob: 0af297470a64befa66cdccccf8c559b908e99e72 [file] [log] [blame]
Caleb Connolly059d5262024-02-26 17:26:24 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Common initialisation for Qualcomm Snapdragon boards.
4 *
5 * Copyright (c) 2024 Linaro Ltd.
6 * Author: Caleb Connolly <caleb.connolly@linaro.org>
7 */
8
9#include "time.h"
10#include <asm/armv8/mmu.h>
11#include <asm/gpio.h>
12#include <asm/io.h>
13#include <asm/psci.h>
14#include <asm/system.h>
15#include <dm/device.h>
16#include <dm/pinctrl.h>
17#include <dm/uclass-internal.h>
18#include <dm/read.h>
Caleb Connolly1751d3c2024-04-03 14:07:47 +020019#include <power/regulator.h>
Caleb Connolly059d5262024-02-26 17:26:24 +000020#include <env.h>
Caleb Connolly82efffc2024-08-09 01:59:24 +020021#include <fdt_support.h>
Caleb Connolly059d5262024-02-26 17:26:24 +000022#include <init.h>
23#include <linux/arm-smccc.h>
24#include <linux/bug.h>
25#include <linux/psci.h>
26#include <linux/sizes.h>
Caleb Connollya2364d92024-02-26 17:26:25 +000027#include <lmb.h>
Caleb Connolly059d5262024-02-26 17:26:24 +000028#include <malloc.h>
Volodymyr Babchuk86eb5d82024-03-11 21:33:45 +000029#include <fdt_support.h>
Caleb Connolly059d5262024-02-26 17:26:24 +000030#include <usb.h>
Caleb Connollyc6f49852024-02-26 17:26:27 +000031#include <sort.h>
Caleb Connolly059d5262024-02-26 17:26:24 +000032
Caleb Connolly06db7f92024-04-03 14:07:45 +020033#include "qcom-priv.h"
34
Caleb Connolly059d5262024-02-26 17:26:24 +000035DECLARE_GLOBAL_DATA_PTR;
36
37static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } };
38
39struct mm_region *mem_map = rbx_mem_map;
40
Caleb Connolly2f99cea2024-08-09 01:59:25 +020041static struct {
42 phys_addr_t start;
43 phys_size_t size;
44} prevbl_ddr_banks[CONFIG_NR_DRAM_BANKS] __section(".data") = { 0 };
45
Caleb Connolly059d5262024-02-26 17:26:24 +000046int dram_init(void)
47{
Caleb Connolly2f99cea2024-08-09 01:59:25 +020048 /*
49 * gd->ram_base / ram_size have been setup already
50 * in qcom_parse_memory().
51 */
52 return 0;
Caleb Connolly059d5262024-02-26 17:26:24 +000053}
54
55static int ddr_bank_cmp(const void *v1, const void *v2)
56{
57 const struct {
58 phys_addr_t start;
59 phys_size_t size;
60 } *res1 = v1, *res2 = v2;
61
62 if (!res1->size)
63 return 1;
64 if (!res2->size)
65 return -1;
66
67 return (res1->start >> 24) - (res2->start >> 24);
68}
69
Caleb Connolly2f99cea2024-08-09 01:59:25 +020070/* This has to be done post-relocation since gd->bd isn't preserved */
71static void qcom_configure_bi_dram(void)
72{
73 int i;
74
75 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
76 gd->bd->bi_dram[i].start = prevbl_ddr_banks[i].start;
77 gd->bd->bi_dram[i].size = prevbl_ddr_banks[i].size;
78 }
79}
80
Caleb Connolly059d5262024-02-26 17:26:24 +000081int dram_init_banksize(void)
82{
Caleb Connolly2f99cea2024-08-09 01:59:25 +020083 qcom_configure_bi_dram();
Caleb Connolly059d5262024-02-26 17:26:24 +000084
85 return 0;
86}
87
Caleb Connolly2f99cea2024-08-09 01:59:25 +020088static void qcom_parse_memory(void)
89{
90 ofnode node;
91 const fdt64_t *memory;
92 int memsize;
93 phys_addr_t ram_end = 0;
94 int i, j, banks;
95
96 node = ofnode_path("/memory");
97 if (!ofnode_valid(node)) {
98 log_err("No memory node found in device tree!\n");
99 return;
100 }
101 memory = ofnode_read_prop(node, "reg", &memsize);
102 if (!memory) {
103 log_err("No memory configuration was provided by the previous bootloader!\n");
104 return;
105 }
106
107 banks = min(memsize / (2 * sizeof(u64)), (ulong)CONFIG_NR_DRAM_BANKS);
108
109 if (memsize / sizeof(u64) > CONFIG_NR_DRAM_BANKS * 2)
110 log_err("Provided more than the max of %d memory banks\n", CONFIG_NR_DRAM_BANKS);
111
112 if (banks > CONFIG_NR_DRAM_BANKS)
113 log_err("Provided more memory banks than we can handle\n");
114
115 for (i = 0, j = 0; i < banks * 2; i += 2, j++) {
116 prevbl_ddr_banks[j].start = get_unaligned_be64(&memory[i]);
117 prevbl_ddr_banks[j].size = get_unaligned_be64(&memory[i + 1]);
118 /* SM8650 boards sometimes have empty regions! */
119 if (!prevbl_ddr_banks[j].size) {
120 j--;
121 continue;
122 }
123 ram_end = max(ram_end, prevbl_ddr_banks[j].start + prevbl_ddr_banks[j].size);
124 }
125
126 /* Sort our RAM banks -_- */
127 qsort(prevbl_ddr_banks, banks, sizeof(prevbl_ddr_banks[0]), ddr_bank_cmp);
128
129 gd->ram_base = prevbl_ddr_banks[0].start;
130 gd->ram_size = ram_end - gd->ram_base;
131 debug("ram_base = %#011lx, ram_size = %#011llx, ram_end = %#011llx\n",
132 gd->ram_base, gd->ram_size, ram_end);
133}
134
Caleb Connolly059d5262024-02-26 17:26:24 +0000135static void show_psci_version(void)
136{
137 struct arm_smccc_res res;
138
139 arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
140
141 debug("PSCI: v%ld.%ld\n",
142 PSCI_VERSION_MAJOR(res.a0),
143 PSCI_VERSION_MINOR(res.a0));
144}
145
Caleb Connolly82efffc2024-08-09 01:59:24 +0200146/* We support booting U-Boot with an internal DT when running as a first-stage bootloader
147 * or for supporting quirky devices where it's easier to leave the downstream DT in place
148 * to improve ABL compatibility. Otherwise, we use the DT provided by ABL.
149 */
Caleb Connolly059d5262024-02-26 17:26:24 +0000150void *board_fdt_blob_setup(int *err)
151{
Caleb Connolly82efffc2024-08-09 01:59:24 +0200152 struct fdt_header *fdt;
153 bool internal_valid, external_valid;
154
Caleb Connolly059d5262024-02-26 17:26:24 +0000155 *err = 0;
Caleb Connolly82efffc2024-08-09 01:59:24 +0200156 fdt = (struct fdt_header *)get_prev_bl_fdt_addr();
157 external_valid = fdt && !fdt_check_header(fdt);
158 internal_valid = !fdt_check_header(gd->fdt_blob);
Caleb Connolly059d5262024-02-26 17:26:24 +0000159
160 /*
Caleb Connolly82efffc2024-08-09 01:59:24 +0200161 * There is no point returning an error here, U-Boot can't do anything useful in this situation.
162 * Bail out while we can still print a useful error message.
Caleb Connolly059d5262024-02-26 17:26:24 +0000163 */
Caleb Connolly82efffc2024-08-09 01:59:24 +0200164 if (!internal_valid && !external_valid)
165 panic("Internal FDT is invalid and no external FDT was provided! (fdt=%#llx)\n",
166 (phys_addr_t)fdt);
Volodymyr Babchuk86eb5d82024-03-11 21:33:45 +0000167
Caleb Connolly82efffc2024-08-09 01:59:24 +0200168 if (internal_valid) {
169 debug("Using built in FDT\n");
Caleb Connolly82efffc2024-08-09 01:59:24 +0200170 } else {
171 debug("Using external FDT\n");
Caleb Connolly2f99cea2024-08-09 01:59:25 +0200172 /* So we can use it before returning */
173 gd->fdt_blob = fdt;
Caleb Connolly059d5262024-02-26 17:26:24 +0000174 }
Caleb Connolly2f99cea2024-08-09 01:59:25 +0200175
176 /*
177 * Parse the /memory node while we're here,
178 * this makes it easy to do other things early.
179 */
180 qcom_parse_memory();
181
182 return (void *)gd->fdt_blob;
Caleb Connolly059d5262024-02-26 17:26:24 +0000183}
184
185void reset_cpu(void)
186{
187 psci_system_reset();
188}
189
190/*
191 * Some Qualcomm boards require GPIO configuration when switching USB modes.
192 * Support setting this configuration via pinctrl state.
193 */
194int board_usb_init(int index, enum usb_init_type init)
195{
196 struct udevice *usb;
197 int ret = 0;
198
199 /* USB device */
200 ret = uclass_find_device_by_seq(UCLASS_USB, index, &usb);
201 if (ret) {
202 printf("Cannot find USB device\n");
203 return ret;
204 }
205
206 ret = dev_read_stringlist_search(usb, "pinctrl-names",
207 "device");
208 /* No "device" pinctrl state, so just bail */
209 if (ret < 0)
210 return 0;
211
212 /* Select "default" or "device" pinctrl */
213 switch (init) {
214 case USB_INIT_HOST:
215 pinctrl_select_state(usb, "default");
216 break;
217 case USB_INIT_DEVICE:
218 pinctrl_select_state(usb, "device");
219 break;
220 default:
221 debug("Unknown usb_init_type %d\n", init);
222 break;
223 }
224
225 return 0;
226}
227
228/*
229 * Some boards still need board specific init code, they can implement that by
230 * overriding this function.
231 *
232 * FIXME: get rid of board specific init code
233 */
234void __weak qcom_board_init(void)
235{
236}
237
238int board_init(void)
239{
Caleb Connolly1751d3c2024-04-03 14:07:47 +0200240 regulators_enable_boot_on(false);
Caleb Connolly059d5262024-02-26 17:26:24 +0000241 show_psci_version();
Caleb Connolly06db7f92024-04-03 14:07:45 +0200242 qcom_of_fixup_nodes();
Caleb Connolly059d5262024-02-26 17:26:24 +0000243 qcom_board_init();
244 return 0;
245}
246
Caleb Connolly3819a6d2024-08-09 01:59:27 +0200247/**
248 * out_len includes the trailing null space
249 */
250static int get_cmdline_option(const char *cmdline, const char *key, char *out, int out_len)
251{
252 const char *p, *p_end;
253 int len;
254
255 p = strstr(cmdline, key);
256 if (!p)
257 return -ENOENT;
258
259 p += strlen(key);
260 p_end = strstr(p, " ");
261 if (!p_end)
262 return -ENOENT;
263
264 len = p_end - p;
265 if (len > out_len)
266 len = out_len;
267
268 strncpy(out, p, len);
269 out[len] = '\0';
270
271 return 0;
272}
273
274/* The bootargs are populated by the previous stage bootloader */
275static const char *get_cmdline(void)
276{
277 ofnode node;
278 static const char *cmdline = NULL;
279
280 if (cmdline)
281 return cmdline;
282
283 node = ofnode_path("/chosen");
284 if (!ofnode_valid(node))
285 return NULL;
286
287 cmdline = ofnode_read_string(node, "bootargs");
288
289 return cmdline;
290}
291
292void qcom_set_serialno(void)
293{
294 const char *cmdline = get_cmdline();
295 char serial[32];
296
297 if (!cmdline) {
298 log_debug("Failed to get bootargs\n");
299 return;
300 }
301
302 get_cmdline_option(cmdline, "androidboot.serialno=", serial, sizeof(serial));
303 if (serial[0] != '\0')
304 env_set("serial#", serial);
305}
306
Caleb Connolly2bdc48f2024-02-26 17:26:26 +0000307/* Sets up the "board", and "soc" environment variables as well as constructing the devicetree
308 * path, with a few quirks to handle non-standard dtb filenames. This is not meant to be a
309 * comprehensive solution to automatically picking the DTB, but aims to be correct for the
310 * majority case. For most devices it should be possible to make this algorithm work by
311 * adjusting the root compatible property in the U-Boot DTS. Handling devices with multiple
312 * variants that are all supported by a single U-Boot image will require implementing device-
313 * specific detection.
314 */
315static void configure_env(void)
316{
317 const char *first_compat, *last_compat;
318 char *tmp;
319 char buf[32] = { 0 };
320 /*
321 * Most DTB filenames follow the scheme: qcom/<soc>-[vendor]-<board>.dtb
322 * The vendor is skipped when it's a Qualcomm reference board, or the
323 * db845c.
324 */
325 char dt_path[64] = { 0 };
326 int compat_count, ret;
327 ofnode root;
328
329 root = ofnode_root();
330 /* This is almost always 2, but be explicit that we want the first and last compatibles
331 * not the first and second.
332 */
333 compat_count = ofnode_read_string_count(root, "compatible");
334 if (compat_count < 2) {
335 log_warning("%s: only one root compatible bailing!\n", __func__);
336 return;
337 }
338
339 /* The most specific device compatible (e.g. "thundercomm,db845c") */
340 ret = ofnode_read_string_index(root, "compatible", 0, &first_compat);
341 if (ret < 0) {
342 log_warning("Can't read first compatible\n");
343 return;
344 }
345
346 /* The last compatible is always the SoC compatible */
347 ret = ofnode_read_string_index(root, "compatible", compat_count - 1, &last_compat);
348 if (ret < 0) {
349 log_warning("Can't read second compatible\n");
350 return;
351 }
352
353 /* Copy the second compat (e.g. "qcom,sdm845") into buf */
354 strlcpy(buf, last_compat, sizeof(buf) - 1);
355 tmp = buf;
356
357 /* strsep() is destructive, it replaces the comma with a \0 */
358 if (!strsep(&tmp, ",")) {
359 log_warning("second compatible '%s' has no ','\n", buf);
360 return;
361 }
362
363 /* tmp now points to just the "sdm845" part of the string */
364 env_set("soc", tmp);
365
366 /* Now figure out the "board" part from the first compatible */
367 memset(buf, 0, sizeof(buf));
368 strlcpy(buf, first_compat, sizeof(buf) - 1);
369 tmp = buf;
370
371 /* The Qualcomm reference boards (RBx, HDK, etc) */
372 if (!strncmp("qcom", buf, strlen("qcom"))) {
373 /*
374 * They all have the first compatible as "qcom,<soc>-<board>"
375 * (e.g. "qcom,qrb5165-rb5"). We extract just the part after
376 * the dash.
377 */
378 if (!strsep(&tmp, "-")) {
379 log_warning("compatible '%s' has no '-'\n", buf);
380 return;
381 }
382 /* tmp is now "rb5" */
383 env_set("board", tmp);
384 } else {
385 if (!strsep(&tmp, ",")) {
386 log_warning("compatible '%s' has no ','\n", buf);
387 return;
388 }
389 /* for thundercomm we just want the bit after the comma (e.g. "db845c"),
390 * for all other boards we replace the comma with a '-' and take both
391 * (e.g. "oneplus-enchilada")
392 */
393 if (!strncmp("thundercomm", buf, strlen("thundercomm"))) {
394 env_set("board", tmp);
395 } else {
396 *(tmp - 1) = '-';
397 env_set("board", buf);
398 }
399 }
400
401 /* Now build the full path name */
402 snprintf(dt_path, sizeof(dt_path), "qcom/%s-%s.dtb",
403 env_get("soc"), env_get("board"));
404 env_set("fdtfile", dt_path);
Caleb Connolly3819a6d2024-08-09 01:59:27 +0200405
406 qcom_set_serialno();
Caleb Connolly2bdc48f2024-02-26 17:26:26 +0000407}
408
Caleb Connollya2364d92024-02-26 17:26:25 +0000409void __weak qcom_late_init(void)
410{
411}
412
413#define KERNEL_COMP_SIZE SZ_64M
Caleb Connolly8bf5cad2024-08-09 01:59:28 +0200414#ifdef CONFIG_FASTBOOT_BUF_SIZE
415#define FASTBOOT_BUF_SIZE CONFIG_FASTBOOT_BUF_SIZE
416#else
417#define FASTBOOT_BUF_SIZE 0
418#endif
Caleb Connollya2364d92024-02-26 17:26:25 +0000419
Sughosh Ganued17a332024-08-26 17:29:18 +0530420#define addr_alloc(size) lmb_alloc(size, SZ_2M)
Caleb Connollya2364d92024-02-26 17:26:25 +0000421
422/* Stolen from arch/arm/mach-apple/board.c */
423int board_late_init(void)
424{
Caleb Connollya2364d92024-02-26 17:26:25 +0000425 u32 status = 0;
Caleb Connollya9337c62024-08-09 01:59:30 +0200426 phys_addr_t addr;
Caleb Connollyf05b69e2024-08-09 01:59:29 +0200427 struct fdt_header *fdt_blob = (struct fdt_header *)gd->fdt_blob;
Caleb Connollya2364d92024-02-26 17:26:25 +0000428
Caleb Connollya2364d92024-02-26 17:26:25 +0000429 /* We need to be fairly conservative here as we support boards with just 1G of TOTAL RAM */
Caleb Connollya9337c62024-08-09 01:59:30 +0200430 addr = addr_alloc(SZ_128M);
431 status |= env_set_hex("kernel_addr_r", addr);
432 status |= env_set_hex("loadaddr", addr);
Sughosh Ganued17a332024-08-26 17:29:18 +0530433 status |= env_set_hex("ramdisk_addr_r", addr_alloc(SZ_128M));
434 status |= env_set_hex("kernel_comp_addr_r", addr_alloc(KERNEL_COMP_SIZE));
Caleb Connollya2364d92024-02-26 17:26:25 +0000435 status |= env_set_hex("kernel_comp_size", KERNEL_COMP_SIZE);
Caleb Connolly8bf5cad2024-08-09 01:59:28 +0200436 if (IS_ENABLED(CONFIG_FASTBOOT))
437 status |= env_set_hex("fastboot_addr_r", addr_alloc(FASTBOOT_BUF_SIZE));
Sughosh Ganued17a332024-08-26 17:29:18 +0530438 status |= env_set_hex("scriptaddr", addr_alloc(SZ_4M));
439 status |= env_set_hex("pxefile_addr_r", addr_alloc(SZ_4M));
Caleb Connollya9337c62024-08-09 01:59:30 +0200440 addr = addr_alloc(SZ_2M);
441 status |= env_set_hex("fdt_addr_r", addr);
Caleb Connollya2364d92024-02-26 17:26:25 +0000442
443 if (status)
444 log_warning("%s: Failed to set run time variables\n", __func__);
445
Caleb Connollyf05b69e2024-08-09 01:59:29 +0200446 /* By default copy U-Boots FDT, it will be used as a fallback */
Caleb Connollya9337c62024-08-09 01:59:30 +0200447 memcpy((void *)addr, (void *)gd->fdt_blob, fdt32_to_cpu(fdt_blob->totalsize));
Caleb Connollyf05b69e2024-08-09 01:59:29 +0200448
Caleb Connolly2bdc48f2024-02-26 17:26:26 +0000449 configure_env();
Caleb Connollya2364d92024-02-26 17:26:25 +0000450 qcom_late_init();
451
452 return 0;
453}
454
Caleb Connolly059d5262024-02-26 17:26:24 +0000455static void build_mem_map(void)
456{
Caleb Connollyc6f49852024-02-26 17:26:27 +0000457 int i, j;
Caleb Connolly059d5262024-02-26 17:26:24 +0000458
459 /*
460 * Ensure the peripheral block is sized to correctly cover the address range
461 * up to the first memory bank.
462 * Don't map the first page to ensure that we actually trigger an abort on a
463 * null pointer access rather than just hanging.
464 * FIXME: we should probably split this into more precise regions
465 */
466 mem_map[0].phys = 0x1000;
467 mem_map[0].virt = mem_map[0].phys;
468 mem_map[0].size = gd->bd->bi_dram[0].start - mem_map[0].phys;
469 mem_map[0].attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
470 PTE_BLOCK_NON_SHARE |
471 PTE_BLOCK_PXN | PTE_BLOCK_UXN;
472
Caleb Connollyc6f49852024-02-26 17:26:27 +0000473 for (i = 1, j = 0; i < ARRAY_SIZE(rbx_mem_map) - 1 && gd->bd->bi_dram[j].size; i++, j++) {
474 mem_map[i].phys = gd->bd->bi_dram[j].start;
475 mem_map[i].virt = mem_map[i].phys;
476 mem_map[i].size = gd->bd->bi_dram[j].size;
477 mem_map[i].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | \
478 PTE_BLOCK_INNER_SHARE;
Caleb Connolly059d5262024-02-26 17:26:24 +0000479 }
Caleb Connollyc6f49852024-02-26 17:26:27 +0000480
481 mem_map[i].phys = UINT64_MAX;
482 mem_map[i].size = 0;
483
484#ifdef DEBUG
485 debug("Configured memory map:\n");
486 for (i = 0; mem_map[i].size; i++)
487 debug(" 0x%016llx - 0x%016llx: entry %d\n",
488 mem_map[i].phys, mem_map[i].phys + mem_map[i].size, i);
489#endif
Caleb Connolly059d5262024-02-26 17:26:24 +0000490}
491
492u64 get_page_table_size(void)
493{
Neil Armstrongd57a6da2024-08-09 01:59:26 +0200494 return SZ_1M;
Caleb Connolly059d5262024-02-26 17:26:24 +0000495}
496
Caleb Connollyc6f49852024-02-26 17:26:27 +0000497static int fdt_cmp_res(const void *v1, const void *v2)
498{
499 const struct fdt_resource *res1 = v1, *res2 = v2;
500
501 return res1->start - res2->start;
502}
503
504#define N_RESERVED_REGIONS 32
505
506/* Mark all no-map regions as PTE_TYPE_FAULT to prevent speculative access.
507 * On some platforms this is enough to trigger a security violation and trap
508 * to EL3.
509 */
510static void carve_out_reserved_memory(void)
511{
512 static struct fdt_resource res[N_RESERVED_REGIONS] = { 0 };
513 int parent, rmem, count, i = 0;
514 phys_addr_t start;
515 size_t size;
516
517 /* Some reserved nodes must be carved out, as the cache-prefetcher may otherwise
518 * attempt to access them, causing a security exception.
519 */
520 parent = fdt_path_offset(gd->fdt_blob, "/reserved-memory");
521 if (parent <= 0) {
522 log_err("No reserved memory regions found\n");
523 return;
524 }
525
526 /* Collect the reserved memory regions */
527 fdt_for_each_subnode(rmem, gd->fdt_blob, parent) {
528 const fdt32_t *ptr;
529 int len;
530 if (!fdt_getprop(gd->fdt_blob, rmem, "no-map", NULL))
531 continue;
532
533 if (i == N_RESERVED_REGIONS) {
534 log_err("Too many reserved regions!\n");
535 break;
536 }
537
538 /* Read the address and size out from the reg property. Doing this "properly" with
539 * fdt_get_resource() takes ~70ms on SDM845, but open-coding the happy path here
540 * takes <1ms... Oh the woes of no dcache.
541 */
542 ptr = fdt_getprop(gd->fdt_blob, rmem, "reg", &len);
543 if (ptr) {
544 /* Qualcomm devices use #address/size-cells = <2> but all reserved regions are within
545 * the 32-bit address space. So we can cheat here for speed.
546 */
547 res[i].start = fdt32_to_cpu(ptr[1]);
548 res[i].end = res[i].start + fdt32_to_cpu(ptr[3]);
549 i++;
550 }
551 }
552
553 /* Sort the reserved memory regions by address */
554 count = i;
555 qsort(res, count, sizeof(struct fdt_resource), fdt_cmp_res);
556
557 /* Now set the right attributes for them. Often a lot of the regions are tightly packed together
558 * so we can optimise the number of calls to mmu_change_region_attr() by combining adjacent
559 * regions.
560 */
561 start = ALIGN_DOWN(res[0].start, SZ_2M);
562 size = ALIGN(res[0].end - start, SZ_2M);
563 for (i = 1; i <= count; i++) {
564 /* We ideally want to 2M align everything for more efficient pagetables, but we must avoid
565 * overwriting reserved memory regions which shouldn't be mapped as FAULT (like those with
566 * compatible properties).
567 * If within 2M of the previous region, bump the size to include this region. Otherwise
568 * start a new region.
569 */
570 if (i == count || start + size < res[i].start - SZ_2M) {
571 debug(" 0x%016llx - 0x%016llx: reserved\n",
572 start, start + size);
573 mmu_change_region_attr(start, size, PTE_TYPE_FAULT);
574 /* If this is the final region then quit here before we index
575 * out of bounds...
576 */
577 if (i == count)
578 break;
579 start = ALIGN_DOWN(res[i].start, SZ_2M);
580 size = ALIGN(res[i].end - start, SZ_2M);
581 } else {
582 /* Bump size if this region is immediately after the previous one */
583 size = ALIGN(res[i].end - start, SZ_2M);
584 }
585 }
586}
587
588/* This function open-codes setup_all_pgtables() so that we can
589 * insert additional mappings *before* turning on the MMU.
590 */
Caleb Connolly059d5262024-02-26 17:26:24 +0000591void enable_caches(void)
592{
Caleb Connollyc6f49852024-02-26 17:26:27 +0000593 u64 tlb_addr = gd->arch.tlb_addr;
594 u64 tlb_size = gd->arch.tlb_size;
595 u64 pt_size;
596 ulong carveout_start;
597
598 gd->arch.tlb_fillptr = tlb_addr;
599
Caleb Connolly059d5262024-02-26 17:26:24 +0000600 build_mem_map();
601
602 icache_enable();
Caleb Connollyc6f49852024-02-26 17:26:27 +0000603
604 /* Create normal system page tables */
605 setup_pgtables();
606
607 pt_size = (uintptr_t)gd->arch.tlb_fillptr -
608 (uintptr_t)gd->arch.tlb_addr;
609 debug("Primary pagetable size: %lluKiB\n", pt_size / 1024);
610
611 /* Create emergency page tables */
612 gd->arch.tlb_size -= pt_size;
613 gd->arch.tlb_addr = gd->arch.tlb_fillptr;
614 setup_pgtables();
615 gd->arch.tlb_emerg = gd->arch.tlb_addr;
616 gd->arch.tlb_addr = tlb_addr;
617 gd->arch.tlb_size = tlb_size;
618
Sam Day3ceaa822024-05-07 18:41:23 +0000619 /* We do the carveouts only for QCS404, for now. */
620 if (fdt_node_check_compatible(gd->fdt_blob, 0, "qcom,qcs404") == 0) {
621 carveout_start = get_timer(0);
622 /* Takes ~20-50ms on SDM845 */
623 carve_out_reserved_memory();
624 debug("carveout time: %lums\n", get_timer(carveout_start));
625 }
Caleb Connolly059d5262024-02-26 17:26:24 +0000626 dcache_enable();
627}