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