cboot.c 15 KB

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