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