cboot.c 15 KB

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