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