]> git.ipfire.org Git - thirdparty/u-boot.git/blob - arch/arm/mach-tegra/cboot.c
common: Drop net.h from common header
[thirdparty/u-boot.git] / arch / arm / mach-tegra / cboot.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2016-2018, NVIDIA CORPORATION.
4 */
5
6 #include <common.h>
7 #include <env.h>
8 #include <fdt_support.h>
9 #include <fdtdec.h>
10 #include <hang.h>
11 #include <malloc.h>
12 #include <net.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include <linux/ctype.h>
17 #include <linux/sizes.h>
18
19 #include <asm/arch/tegra.h>
20 #include <asm/arch-tegra/cboot.h>
21 #include <asm/armv8/mmu.h>
22
23 /*
24 * Size of a region that's large enough to hold the relocated U-Boot and all
25 * other allocations made around it (stack, heap, page tables, etc.)
26 * In practice, running "bdinfo" at the shell prompt, the stack reaches about
27 * 5MB from the address selected for ram_top as of the time of writing,
28 * so a 16MB region should be plenty.
29 */
30 #define MIN_USABLE_RAM_SIZE SZ_16M
31 /*
32 * The amount of space we expect to require for stack usage. Used to validate
33 * that all reservations fit into the region selected for the relocation target
34 */
35 #define MIN_USABLE_STACK_SIZE SZ_1M
36
37 DECLARE_GLOBAL_DATA_PTR;
38
39 extern struct mm_region tegra_mem_map[];
40
41 /*
42 * These variables are written to before relocation, and hence cannot be
43 * in.bss, since .bss overlaps the DTB that's appended to the U-Boot binary.
44 * The section attribute forces this into .data and avoids this issue. This
45 * also has the nice side-effect of the content being valid after relocation.
46 */
47
48 /* The number of valid entries in ram_banks[] */
49 static int ram_bank_count __attribute__((section(".data")));
50
51 /*
52 * The usable top-of-RAM for U-Boot. This is both:
53 * a) Below 4GB to avoid issues with peripherals that use 32-bit addressing.
54 * b) At the end of a region that has enough space to hold the relocated U-Boot
55 * and all other allocations made around it (stack, heap, page tables, etc.)
56 */
57 static u64 ram_top __attribute__((section(".data")));
58 /* The base address of the region of RAM that ends at ram_top */
59 static u64 region_base __attribute__((section(".data")));
60
61 /*
62 * Explicitly put this in the .data section because it is written before the
63 * .bss section is zeroed out but it needs to persist.
64 */
65 unsigned long cboot_boot_x0 __attribute__((section(".data")));
66
67 void cboot_save_boot_params(unsigned long x0, unsigned long x1,
68 unsigned long x2, unsigned long x3)
69 {
70 cboot_boot_x0 = x0;
71 }
72
73 int cboot_dram_init(void)
74 {
75 unsigned int na, ns;
76 const void *cboot_blob = (void *)cboot_boot_x0;
77 int node, len, i;
78 const u32 *prop;
79
80 if (!cboot_blob)
81 return -EINVAL;
82
83 na = fdtdec_get_uint(cboot_blob, 0, "#address-cells", 2);
84 ns = fdtdec_get_uint(cboot_blob, 0, "#size-cells", 2);
85
86 node = fdt_path_offset(cboot_blob, "/memory");
87 if (node < 0) {
88 pr_err("Can't find /memory node in cboot DTB");
89 hang();
90 }
91 prop = fdt_getprop(cboot_blob, node, "reg", &len);
92 if (!prop) {
93 pr_err("Can't find /memory/reg property in cboot DTB");
94 hang();
95 }
96
97 /* Calculate the true # of base/size pairs to read */
98 len /= 4; /* Convert bytes to number of cells */
99 len /= (na + ns); /* Convert cells to number of banks */
100 if (len > CONFIG_NR_DRAM_BANKS)
101 len = CONFIG_NR_DRAM_BANKS;
102
103 /* Parse the /memory node, and save useful entries */
104 gd->ram_size = 0;
105 ram_bank_count = 0;
106 for (i = 0; i < len; i++) {
107 u64 bank_start, bank_end, bank_size, usable_bank_size;
108
109 /* Extract raw memory region data from DTB */
110 bank_start = fdt_read_number(prop, na);
111 prop += na;
112 bank_size = fdt_read_number(prop, ns);
113 prop += ns;
114 gd->ram_size += bank_size;
115 bank_end = bank_start + bank_size;
116 debug("Bank %d: %llx..%llx (+%llx)\n", i,
117 bank_start, bank_end, bank_size);
118
119 /*
120 * Align the bank to MMU section size. This is not strictly
121 * necessary, since the translation table construction code
122 * handles page granularity without issue. However, aligning
123 * the MMU entries reduces the size and number of levels in the
124 * page table, so is worth it.
125 */
126 bank_start = ROUND(bank_start, SZ_2M);
127 bank_end = bank_end & ~(SZ_2M - 1);
128 bank_size = bank_end - bank_start;
129 debug(" aligned: %llx..%llx (+%llx)\n",
130 bank_start, bank_end, bank_size);
131 if (bank_end <= bank_start)
132 continue;
133
134 /* Record data used to create MMU translation tables */
135 ram_bank_count++;
136 /* Index below is deliberately 1-based to skip MMIO entry */
137 tegra_mem_map[ram_bank_count].virt = bank_start;
138 tegra_mem_map[ram_bank_count].phys = bank_start;
139 tegra_mem_map[ram_bank_count].size = bank_size;
140 tegra_mem_map[ram_bank_count].attrs =
141 PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE;
142
143 /* Determine best bank to relocate U-Boot into */
144 if (bank_end > SZ_4G)
145 bank_end = SZ_4G;
146 debug(" end %llx (usable)\n", bank_end);
147 usable_bank_size = bank_end - bank_start;
148 debug(" size %llx (usable)\n", usable_bank_size);
149 if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) &&
150 (bank_end > ram_top)) {
151 ram_top = bank_end;
152 region_base = bank_start;
153 debug("ram top now %llx\n", ram_top);
154 }
155 }
156
157 /* Ensure memory map contains the desired sentinel entry */
158 tegra_mem_map[ram_bank_count + 1].virt = 0;
159 tegra_mem_map[ram_bank_count + 1].phys = 0;
160 tegra_mem_map[ram_bank_count + 1].size = 0;
161 tegra_mem_map[ram_bank_count + 1].attrs = 0;
162
163 /* Error out if a relocation target couldn't be found */
164 if (!ram_top) {
165 pr_err("Can't find a usable RAM top");
166 hang();
167 }
168
169 return 0;
170 }
171
172 int cboot_dram_init_banksize(void)
173 {
174 int i;
175
176 if (ram_bank_count == 0)
177 return -EINVAL;
178
179 if ((gd->start_addr_sp - region_base) < MIN_USABLE_STACK_SIZE) {
180 pr_err("Reservations exceed chosen region size");
181 hang();
182 }
183
184 for (i = 0; i < ram_bank_count; i++) {
185 gd->bd->bi_dram[i].start = tegra_mem_map[1 + i].virt;
186 gd->bd->bi_dram[i].size = tegra_mem_map[1 + i].size;
187 }
188
189 #ifdef CONFIG_PCI
190 gd->pci_ram_top = ram_top;
191 #endif
192
193 return 0;
194 }
195
196 ulong cboot_get_usable_ram_top(ulong total_size)
197 {
198 return ram_top;
199 }
200
201 /*
202 * The following few functions run late during the boot process and dynamically
203 * calculate the load address of various binaries. To keep track of multiple
204 * allocations, some writable list of RAM banks must be used. tegra_mem_map[]
205 * is used for this purpose to avoid making yet another copy of the list of RAM
206 * banks. This is safe because tegra_mem_map[] is only used once during very
207 * early boot to create U-Boot's page tables, long before this code runs. If
208 * this assumption becomes invalid later, we can just fix the code to copy the
209 * list of RAM banks into some private data structure before running.
210 */
211
212 static char *gen_varname(const char *var, const char *ext)
213 {
214 size_t len_var = strlen(var);
215 size_t len_ext = strlen(ext);
216 size_t len = len_var + len_ext + 1;
217 char *varext = malloc(len);
218
219 if (!varext)
220 return 0;
221 strcpy(varext, var);
222 strcpy(varext + len_var, ext);
223 return varext;
224 }
225
226 static void mark_ram_allocated(int bank, u64 allocated_start, u64 allocated_end)
227 {
228 u64 bank_start = tegra_mem_map[bank].virt;
229 u64 bank_size = tegra_mem_map[bank].size;
230 u64 bank_end = bank_start + bank_size;
231 bool keep_front = allocated_start != bank_start;
232 bool keep_tail = allocated_end != bank_end;
233
234 if (keep_front && keep_tail) {
235 /*
236 * There are CONFIG_NR_DRAM_BANKS DRAM entries in the array,
237 * starting at index 1 (index 0 is MMIO). So, we are at DRAM
238 * entry "bank" not "bank - 1" as for a typical 0-base array.
239 * The number of remaining DRAM entries is therefore
240 * "CONFIG_NR_DRAM_BANKS - bank". We want to duplicate the
241 * current entry and shift up the remaining entries, dropping
242 * the last one. Thus, we must copy one fewer entry than the
243 * number remaining.
244 */
245 memmove(&tegra_mem_map[bank + 1], &tegra_mem_map[bank],
246 CONFIG_NR_DRAM_BANKS - bank - 1);
247 tegra_mem_map[bank].size = allocated_start - bank_start;
248 bank++;
249 tegra_mem_map[bank].virt = allocated_end;
250 tegra_mem_map[bank].phys = allocated_end;
251 tegra_mem_map[bank].size = bank_end - allocated_end;
252 } else if (keep_front) {
253 tegra_mem_map[bank].size = allocated_start - bank_start;
254 } else if (keep_tail) {
255 tegra_mem_map[bank].virt = allocated_end;
256 tegra_mem_map[bank].phys = allocated_end;
257 tegra_mem_map[bank].size = bank_end - allocated_end;
258 } else {
259 /*
260 * We could move all subsequent banks down in the array but
261 * that's not necessary for subsequent allocations to work, so
262 * we skip doing so.
263 */
264 tegra_mem_map[bank].size = 0;
265 }
266 }
267
268 static void reserve_ram(u64 start, u64 size)
269 {
270 int bank;
271 u64 end = start + size;
272
273 for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
274 u64 bank_start = tegra_mem_map[bank].virt;
275 u64 bank_size = tegra_mem_map[bank].size;
276 u64 bank_end = bank_start + bank_size;
277
278 if (end <= bank_start || start > bank_end)
279 continue;
280 mark_ram_allocated(bank, start, end);
281 break;
282 }
283 }
284
285 static u64 alloc_ram(u64 size, u64 align, u64 offset)
286 {
287 int bank;
288
289 for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
290 u64 bank_start = tegra_mem_map[bank].virt;
291 u64 bank_size = tegra_mem_map[bank].size;
292 u64 bank_end = bank_start + bank_size;
293 u64 allocated = ROUND(bank_start, align) + offset;
294 u64 allocated_end = allocated + size;
295
296 if (allocated_end > bank_end)
297 continue;
298 mark_ram_allocated(bank, allocated, allocated_end);
299 return allocated;
300 }
301 return 0;
302 }
303
304 static void set_calculated_aliases(char *aliases, u64 address)
305 {
306 char *tmp, *alias;
307 int err;
308
309 aliases = strdup(aliases);
310 if (!aliases) {
311 pr_err("strdup(aliases) failed");
312 return;
313 }
314
315 tmp = aliases;
316 while (true) {
317 alias = strsep(&tmp, " ");
318 if (!alias)
319 break;
320 debug("%s: alias: %s\n", __func__, alias);
321 err = env_set_hex(alias, address);
322 if (err)
323 pr_err("Could not set %s\n", alias);
324 }
325
326 free(aliases);
327 }
328
329 static void set_calculated_env_var(const char *var)
330 {
331 char *var_size;
332 char *var_align;
333 char *var_offset;
334 char *var_aliases;
335 u64 size;
336 u64 align;
337 u64 offset;
338 char *aliases;
339 u64 address;
340 int err;
341
342 var_size = gen_varname(var, "_size");
343 if (!var_size)
344 return;
345 var_align = gen_varname(var, "_align");
346 if (!var_align)
347 goto out_free_var_size;
348 var_offset = gen_varname(var, "_offset");
349 if (!var_offset)
350 goto out_free_var_align;
351 var_aliases = gen_varname(var, "_aliases");
352 if (!var_aliases)
353 goto out_free_var_offset;
354
355 size = env_get_hex(var_size, 0);
356 if (!size) {
357 pr_err("%s not set or zero\n", var_size);
358 goto out_free_var_aliases;
359 }
360 align = env_get_hex(var_align, 1);
361 /* Handle extant variables, but with a value of 0 */
362 if (!align)
363 align = 1;
364 offset = env_get_hex(var_offset, 0);
365 aliases = env_get(var_aliases);
366
367 debug("%s: Calc var %s; size=%llx, align=%llx, offset=%llx\n",
368 __func__, var, size, align, offset);
369 if (aliases)
370 debug("%s: Aliases: %s\n", __func__, aliases);
371
372 address = alloc_ram(size, align, offset);
373 if (!address) {
374 pr_err("Could not allocate %s\n", var);
375 goto out_free_var_aliases;
376 }
377 debug("%s: Address %llx\n", __func__, address);
378
379 err = env_set_hex(var, address);
380 if (err)
381 pr_err("Could not set %s\n", var);
382 if (aliases)
383 set_calculated_aliases(aliases, address);
384
385 out_free_var_aliases:
386 free(var_aliases);
387 out_free_var_offset:
388 free(var_offset);
389 out_free_var_align:
390 free(var_align);
391 out_free_var_size:
392 free(var_size);
393 }
394
395 #ifdef DEBUG
396 static void dump_ram_banks(void)
397 {
398 int bank;
399
400 for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
401 u64 bank_start = tegra_mem_map[bank].virt;
402 u64 bank_size = tegra_mem_map[bank].size;
403 u64 bank_end = bank_start + bank_size;
404
405 if (!bank_size)
406 continue;
407 printf("%d: %010llx..%010llx (+%010llx)\n", bank - 1,
408 bank_start, bank_end, bank_size);
409 }
410 }
411 #endif
412
413 static void set_calculated_env_vars(void)
414 {
415 char *vars, *tmp, *var;
416
417 #ifdef DEBUG
418 printf("RAM banks before any calculated env. var.s:\n");
419 dump_ram_banks();
420 #endif
421
422 reserve_ram(cboot_boot_x0, fdt_totalsize(cboot_boot_x0));
423
424 #ifdef DEBUG
425 printf("RAM after reserving cboot DTB:\n");
426 dump_ram_banks();
427 #endif
428
429 vars = env_get("calculated_vars");
430 if (!vars) {
431 debug("%s: No env var calculated_vars\n", __func__);
432 return;
433 }
434
435 vars = strdup(vars);
436 if (!vars) {
437 pr_err("strdup(calculated_vars) failed");
438 return;
439 }
440
441 tmp = vars;
442 while (true) {
443 var = strsep(&tmp, " ");
444 if (!var)
445 break;
446 debug("%s: var: %s\n", __func__, var);
447 set_calculated_env_var(var);
448 #ifdef DEBUG
449 printf("RAM banks after allocating %s:\n", var);
450 dump_ram_banks();
451 #endif
452 }
453
454 free(vars);
455 }
456
457 static int set_fdt_addr(void)
458 {
459 int ret;
460
461 ret = env_set_hex("fdt_addr", cboot_boot_x0);
462 if (ret) {
463 printf("Failed to set fdt_addr to point at DTB: %d\n", ret);
464 return ret;
465 }
466
467 return 0;
468 }
469
470 /*
471 * Attempt to use /chosen/nvidia,ether-mac in the cboot DTB to U-Boot's
472 * ethaddr environment variable if possible.
473 */
474 static int cboot_get_ethaddr_legacy(const void *fdt, uint8_t mac[ETH_ALEN])
475 {
476 const char *const properties[] = {
477 "nvidia,ethernet-mac",
478 "nvidia,ether-mac",
479 };
480 const char *prop;
481 unsigned int i;
482 int node, len;
483
484 node = fdt_path_offset(fdt, "/chosen");
485 if (node < 0) {
486 printf("Can't find /chosen node in cboot DTB\n");
487 return node;
488 }
489
490 for (i = 0; i < ARRAY_SIZE(properties); i++) {
491 prop = fdt_getprop(fdt, node, properties[i], &len);
492 if (prop)
493 break;
494 }
495
496 if (!prop) {
497 printf("Can't find Ethernet MAC address in cboot DTB\n");
498 return -ENOENT;
499 }
500
501 string_to_enetaddr(prop, mac);
502
503 if (!is_valid_ethaddr(mac)) {
504 printf("Invalid MAC address: %s\n", prop);
505 return -EINVAL;
506 }
507
508 debug("Legacy MAC address: %pM\n", mac);
509
510 return 0;
511 }
512
513 int cboot_get_ethaddr(const void *fdt, uint8_t mac[ETH_ALEN])
514 {
515 int node, len, err = 0;
516 const uchar *prop;
517 const char *path;
518
519 path = fdt_get_alias(fdt, "ethernet");
520 if (!path) {
521 err = -ENOENT;
522 goto out;
523 }
524
525 debug("ethernet alias found: %s\n", path);
526
527 node = fdt_path_offset(fdt, path);
528 if (node < 0) {
529 err = -ENOENT;
530 goto out;
531 }
532
533 prop = fdt_getprop(fdt, node, "local-mac-address", &len);
534 if (!prop) {
535 err = -ENOENT;
536 goto out;
537 }
538
539 if (len != ETH_ALEN) {
540 err = -EINVAL;
541 goto out;
542 }
543
544 debug("MAC address: %pM\n", prop);
545 memcpy(mac, prop, ETH_ALEN);
546
547 out:
548 if (err < 0)
549 err = cboot_get_ethaddr_legacy(fdt, mac);
550
551 return err;
552 }
553
554 static char *strip(const char *ptr)
555 {
556 const char *end;
557
558 while (*ptr && isblank(*ptr))
559 ptr++;
560
561 /* empty string */
562 if (*ptr == '\0')
563 return strdup(ptr);
564
565 end = ptr;
566
567 while (end[1])
568 end++;
569
570 while (isblank(*end))
571 end--;
572
573 return strndup(ptr, end - ptr + 1);
574 }
575
576 static char *cboot_get_bootargs(const void *fdt)
577 {
578 const char *args;
579 int offset, len;
580
581 offset = fdt_path_offset(fdt, "/chosen");
582 if (offset < 0)
583 return NULL;
584
585 args = fdt_getprop(fdt, offset, "bootargs", &len);
586 if (!args)
587 return NULL;
588
589 return strip(args);
590 }
591
592 int cboot_late_init(void)
593 {
594 const void *fdt = (const void *)cboot_boot_x0;
595 uint8_t mac[ETH_ALEN];
596 char *bootargs;
597 int err;
598
599 set_calculated_env_vars();
600 /*
601 * Ignore errors here; the value may not be used depending on
602 * extlinux.conf or boot script content.
603 */
604 set_fdt_addr();
605
606 /* Ignore errors here; not all cases care about Ethernet addresses */
607 err = cboot_get_ethaddr(fdt, mac);
608 if (!err) {
609 void *blob = (void *)gd->fdt_blob;
610
611 err = fdtdec_set_ethernet_mac_address(blob, mac, sizeof(mac));
612 if (err < 0)
613 printf("failed to set MAC address %pM: %d\n", mac, err);
614 }
615
616 bootargs = cboot_get_bootargs(fdt);
617 if (bootargs) {
618 env_set("cbootargs", bootargs);
619 free(bootargs);
620 }
621
622 return 0;
623 }