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