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