cboot.c 15 KB

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