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