2 * Copyright (c) 2016-2018, NVIDIA CORPORATION.
4 * SPDX-License-Identifier: GPL-2.0+
9 #include <fdt_support.h>
11 #include <asm/arch/tegra.h>
12 #include <asm/armv8/mmu.h>
14 DECLARE_GLOBAL_DATA_PTR;
16 extern unsigned long nvtboot_boot_x0;
19 * The following few functions run late during the boot process and dynamically
20 * calculate the load address of various binaries. To keep track of multiple
21 * allocations, some writable list of RAM banks must be used. tegra_mem_map[]
22 * is used for this purpose to avoid making yet another copy of the list of RAM
23 * banks. This is safe because tegra_mem_map[] is only used once during very
24 * early boot to create U-Boot's page tables, long before this code runs. If
25 * this assumption becomes invalid later, we can just fix the code to copy the
26 * list of RAM banks into some private data structure before running.
29 extern struct mm_region tegra_mem_map[];
31 static char *gen_varname(const char *var, const char *ext)
33 size_t len_var = strlen(var);
34 size_t len_ext = strlen(ext);
35 size_t len = len_var + len_ext + 1;
36 char *varext = malloc(len);
41 strcpy(varext + len_var, ext);
45 static void mark_ram_allocated(int bank, u64 allocated_start, u64 allocated_end)
47 u64 bank_start = tegra_mem_map[bank].virt;
48 u64 bank_size = tegra_mem_map[bank].size;
49 u64 bank_end = bank_start + bank_size;
50 bool keep_front = allocated_start != bank_start;
51 bool keep_tail = allocated_end != bank_end;
53 if (keep_front && keep_tail) {
55 * There are CONFIG_NR_DRAM_BANKS DRAM entries in the array,
56 * starting at index 1 (index 0 is MMIO). So, we are at DRAM
57 * entry "bank" not "bank - 1" as for a typical 0-base array.
58 * The number of remaining DRAM entries is therefore
59 * "CONFIG_NR_DRAM_BANKS - bank". We want to duplicate the
60 * current entry and shift up the remaining entries, dropping
61 * the last one. Thus, we must copy one fewer entry than the
64 memmove(&tegra_mem_map[bank + 1], &tegra_mem_map[bank],
65 CONFIG_NR_DRAM_BANKS - bank - 1);
66 tegra_mem_map[bank].size = allocated_start - bank_start;
68 tegra_mem_map[bank].virt = allocated_end;
69 tegra_mem_map[bank].phys = allocated_end;
70 tegra_mem_map[bank].size = bank_end - allocated_end;
71 } else if (keep_front) {
72 tegra_mem_map[bank].size = allocated_start - bank_start;
73 } else if (keep_tail) {
74 tegra_mem_map[bank].virt = allocated_end;
75 tegra_mem_map[bank].phys = allocated_end;
76 tegra_mem_map[bank].size = bank_end - allocated_end;
79 * We could move all subsequent banks down in the array but
80 * that's not necessary for subsequent allocations to work, so
83 tegra_mem_map[bank].size = 0;
87 static void reserve_ram(u64 start, u64 size)
90 u64 end = start + size;
92 for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
93 u64 bank_start = tegra_mem_map[bank].virt;
94 u64 bank_size = tegra_mem_map[bank].size;
95 u64 bank_end = bank_start + bank_size;
97 if (end <= bank_start || start > bank_end)
99 mark_ram_allocated(bank, start, end);
104 static u64 alloc_ram(u64 size, u64 align, u64 offset)
108 for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
109 u64 bank_start = tegra_mem_map[bank].virt;
110 u64 bank_size = tegra_mem_map[bank].size;
111 u64 bank_end = bank_start + bank_size;
112 u64 allocated = ROUND(bank_start, align) + offset;
113 u64 allocated_end = allocated + size;
115 if (allocated_end > bank_end)
117 mark_ram_allocated(bank, allocated, allocated_end);
123 static void set_calculated_aliases(char *aliases, u64 address)
128 aliases = strdup(aliases);
130 pr_err("strdup(aliases) failed");
136 alias = strsep(&tmp, " ");
139 debug("%s: alias: %s\n", __func__, alias);
140 err = env_set_hex(alias, address);
142 pr_err("Could not set %s\n", alias);
148 static void set_calculated_env_var(const char *var)
161 var_size = gen_varname(var, "_size");
164 var_align = gen_varname(var, "_align");
166 goto out_free_var_size;
167 var_offset = gen_varname(var, "_offset");
169 goto out_free_var_align;
170 var_aliases = gen_varname(var, "_aliases");
172 goto out_free_var_offset;
174 size = env_get_hex(var_size, 0);
176 pr_err("%s not set or zero\n", var_size);
177 goto out_free_var_aliases;
179 align = env_get_hex(var_align, 1);
180 /* Handle extant variables, but with a value of 0 */
183 offset = env_get_hex(var_offset, 0);
184 aliases = env_get(var_aliases);
186 debug("%s: Calc var %s; size=%llx, align=%llx, offset=%llx\n",
187 __func__, var, size, align, offset);
189 debug("%s: Aliases: %s\n", __func__, aliases);
191 address = alloc_ram(size, align, offset);
193 pr_err("Could not allocate %s\n", var);
194 goto out_free_var_aliases;
196 debug("%s: Address %llx\n", __func__, address);
198 err = env_set_hex(var, address);
200 pr_err("Could not set %s\n", var);
202 set_calculated_aliases(aliases, address);
204 out_free_var_aliases:
215 static void dump_ram_banks(void)
219 for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
220 u64 bank_start = tegra_mem_map[bank].virt;
221 u64 bank_size = tegra_mem_map[bank].size;
222 u64 bank_end = bank_start + bank_size;
226 printf("%d: %010llx..%010llx (+%010llx)\n", bank - 1,
227 bank_start, bank_end, bank_size);
232 static void set_calculated_env_vars(void)
234 char *vars, *tmp, *var;
237 printf("RAM banks before any calculated env. var.s:\n");
241 reserve_ram(nvtboot_boot_x0, fdt_totalsize(nvtboot_boot_x0));
244 printf("RAM after reserving cboot DTB:\n");
248 vars = env_get("calculated_vars");
250 debug("%s: No env var calculated_vars\n", __func__);
256 pr_err("strdup(calculated_vars) failed");
262 var = strsep(&tmp, " ");
265 debug("%s: var: %s\n", __func__, var);
266 set_calculated_env_var(var);
268 printf("RAM banks affter allocating %s:\n", var);
276 static int set_fdt_addr(void)
280 ret = env_set_hex("fdt_addr", nvtboot_boot_x0);
282 printf("Failed to set fdt_addr to point at DTB: %d\n", ret);
290 * Attempt to use /chosen/nvidia,ether-mac in the nvtboot DTB to U-Boot's
291 * ethaddr environment variable if possible.
293 static int set_ethaddr_from_nvtboot(void)
295 const void *nvtboot_blob = (void *)nvtboot_boot_x0;
299 /* Already a valid address in the environment? If so, keep it */
300 if (env_get("ethaddr"))
303 node = fdt_path_offset(nvtboot_blob, "/chosen");
305 printf("Can't find /chosen node in nvtboot DTB\n");
308 prop = fdt_getprop(nvtboot_blob, node, "nvidia,ether-mac", &len);
310 printf("Can't find nvidia,ether-mac property in nvtboot DTB\n");
314 ret = env_set("ethaddr", (void *)prop);
316 printf("Failed to set ethaddr from nvtboot DTB: %d\n", ret);
323 int tegra_soc_board_init_late(void)
325 set_calculated_env_vars();
327 * Ignore errors here; the value may not be used depending on
328 * extlinux.conf or boot script content.
331 /* Ignore errors here; not all cases care about Ethernet addresses */
332 set_ethaddr_from_nvtboot();