]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2b950f3a | 2 | /* |
026a8b96 | 3 | * Copyright (c) 2016-2018, NVIDIA CORPORATION. |
2b950f3a SW |
4 | */ |
5 | ||
d678a59d | 6 | #include <common.h> |
c7694dd4 | 7 | #include <env.h> |
2b950f3a SW |
8 | #include <fdt_support.h> |
9 | #include <fdtdec.h> | |
db41d65a | 10 | #include <hang.h> |
691d719d | 11 | #include <init.h> |
f7ae49fc | 12 | #include <log.h> |
336d4615 | 13 | #include <malloc.h> |
90526e9f | 14 | #include <net.h> |
a0dbc131 | 15 | #include <stdlib.h> |
b5717664 | 16 | #include <string.h> |
401d1c4f | 17 | #include <asm/global_data.h> |
1e94b46f | 18 | #include <linux/printk.h> |
a0dbc131 | 19 | |
b5717664 | 20 | #include <linux/ctype.h> |
a0dbc131 TR |
21 | #include <linux/sizes.h> |
22 | ||
2b950f3a | 23 | #include <asm/arch/tegra.h> |
a0dbc131 | 24 | #include <asm/arch-tegra/cboot.h> |
026a8b96 SW |
25 | #include <asm/armv8/mmu.h> |
26 | ||
a0dbc131 TR |
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 | ||
41 | DECLARE_GLOBAL_DATA_PTR; | |
42 | ||
43 | extern 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[] */ | |
236f2ec4 | 53 | static int ram_bank_count __section(".data"); |
a0dbc131 TR |
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 | */ | |
236f2ec4 | 61 | static u64 ram_top __section(".data"); |
a0dbc131 | 62 | /* The base address of the region of RAM that ends at ram_top */ |
236f2ec4 | 63 | static u64 region_base __section(".data"); |
a0dbc131 | 64 | |
ce353bab TR |
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 | */ | |
236f2ec4 | 69 | unsigned long cboot_boot_x0 __section(".data"); |
ce353bab TR |
70 | |
71 | void 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 | ||
a0dbc131 TR |
77 | int 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 | ||
176 | int 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 | ||
200 | ulong cboot_get_usable_ram_top(ulong total_size) | |
201 | { | |
202 | return ram_top; | |
203 | } | |
2b950f3a | 204 | |
026a8b96 SW |
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 | ||
026a8b96 SW |
216 | static 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 | ||
230 | static 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 | ||
272 | static 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 | ||
289 | static 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 | ||
308 | static 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 | ||
333 | static 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 | ||
389 | out_free_var_aliases: | |
390 | free(var_aliases); | |
391 | out_free_var_offset: | |
392 | free(var_offset); | |
393 | out_free_var_align: | |
394 | free(var_align); | |
395 | out_free_var_size: | |
396 | free(var_size); | |
397 | } | |
398 | ||
399 | #ifdef DEBUG | |
400 | static 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 | ||
417 | static 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 | ||
a0dbc131 | 426 | reserve_ram(cboot_boot_x0, fdt_totalsize(cboot_boot_x0)); |
026a8b96 SW |
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 | |
a0dbc131 | 453 | printf("RAM banks after allocating %s:\n", var); |
026a8b96 SW |
454 | dump_ram_banks(); |
455 | #endif | |
456 | } | |
457 | ||
458 | free(vars); | |
459 | } | |
460 | ||
a182e69d SW |
461 | static int set_fdt_addr(void) |
462 | { | |
463 | int ret; | |
464 | ||
a0dbc131 | 465 | ret = env_set_hex("fdt_addr", cboot_boot_x0); |
a182e69d SW |
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 | ||
2b950f3a | 474 | /* |
a0dbc131 | 475 | * Attempt to use /chosen/nvidia,ether-mac in the cboot DTB to U-Boot's |
2b950f3a SW |
476 | * ethaddr environment variable if possible. |
477 | */ | |
34e12e03 | 478 | static int cboot_get_ethaddr_legacy(const void *fdt, uint8_t mac[ETH_ALEN]) |
2b950f3a | 479 | { |
34e12e03 TR |
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"); | |
2b950f3a | 489 | if (node < 0) { |
a0dbc131 | 490 | printf("Can't find /chosen node in cboot DTB\n"); |
2b950f3a SW |
491 | return node; |
492 | } | |
34e12e03 TR |
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 | ||
2b950f3a | 500 | if (!prop) { |
34e12e03 | 501 | printf("Can't find Ethernet MAC address in cboot DTB\n"); |
2b950f3a SW |
502 | return -ENOENT; |
503 | } | |
504 | ||
fb8977c5 | 505 | string_to_enetaddr(prop, mac); |
34e12e03 TR |
506 | |
507 | if (!is_valid_ethaddr(mac)) { | |
508 | printf("Invalid MAC address: %s\n", prop); | |
509 | return -EINVAL; | |
2b950f3a SW |
510 | } |
511 | ||
34e12e03 TR |
512 | debug("Legacy MAC address: %pM\n", mac); |
513 | ||
2b950f3a SW |
514 | return 0; |
515 | } | |
516 | ||
34e12e03 TR |
517 | int 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 | ||
551 | out: | |
552 | if (err < 0) | |
553 | err = cboot_get_ethaddr_legacy(fdt, mac); | |
554 | ||
555 | return err; | |
556 | } | |
557 | ||
b5717664 TR |
558 | static 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 | ||
580 | static 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 | ||
a0dbc131 | 596 | int cboot_late_init(void) |
2b950f3a | 597 | { |
34e12e03 TR |
598 | const void *fdt = (const void *)cboot_boot_x0; |
599 | uint8_t mac[ETH_ALEN]; | |
b5717664 | 600 | char *bootargs; |
34e12e03 TR |
601 | int err; |
602 | ||
026a8b96 | 603 | set_calculated_env_vars(); |
a182e69d SW |
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(); | |
34e12e03 | 609 | |
2b950f3a | 610 | /* Ignore errors here; not all cases care about Ethernet addresses */ |
34e12e03 TR |
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 | } | |
2b950f3a | 619 | |
b5717664 TR |
620 | bootargs = cboot_get_bootargs(fdt); |
621 | if (bootargs) { | |
622 | env_set("cbootargs", bootargs); | |
623 | free(bootargs); | |
624 | } | |
625 | ||
2b950f3a SW |
626 | return 0; |
627 | } |