nvtboot_board.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * Copyright (c) 2016-2018, NVIDIA CORPORATION.
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <stdlib.h>
  7. #include <common.h>
  8. #include <fdt_support.h>
  9. #include <fdtdec.h>
  10. #include <asm/arch/tegra.h>
  11. #include <asm/armv8/mmu.h>
  12. extern unsigned long nvtboot_boot_x0;
  13. /*
  14. * The following few functions run late during the boot process and dynamically
  15. * calculate the load address of various binaries. To keep track of multiple
  16. * allocations, some writable list of RAM banks must be used. tegra_mem_map[]
  17. * is used for this purpose to avoid making yet another copy of the list of RAM
  18. * banks. This is safe because tegra_mem_map[] is only used once during very
  19. * early boot to create U-Boot's page tables, long before this code runs. If
  20. * this assumption becomes invalid later, we can just fix the code to copy the
  21. * list of RAM banks into some private data structure before running.
  22. */
  23. extern struct mm_region tegra_mem_map[];
  24. static char *gen_varname(const char *var, const char *ext)
  25. {
  26. size_t len_var = strlen(var);
  27. size_t len_ext = strlen(ext);
  28. size_t len = len_var + len_ext + 1;
  29. char *varext = malloc(len);
  30. if (!varext)
  31. return 0;
  32. strcpy(varext, var);
  33. strcpy(varext + len_var, ext);
  34. return varext;
  35. }
  36. static void mark_ram_allocated(int bank, u64 allocated_start, u64 allocated_end)
  37. {
  38. u64 bank_start = tegra_mem_map[bank].virt;
  39. u64 bank_size = tegra_mem_map[bank].size;
  40. u64 bank_end = bank_start + bank_size;
  41. bool keep_front = allocated_start != bank_start;
  42. bool keep_tail = allocated_end != bank_end;
  43. if (keep_front && keep_tail) {
  44. /*
  45. * There are CONFIG_NR_DRAM_BANKS DRAM entries in the array,
  46. * starting at index 1 (index 0 is MMIO). So, we are at DRAM
  47. * entry "bank" not "bank - 1" as for a typical 0-base array.
  48. * The number of remaining DRAM entries is therefore
  49. * "CONFIG_NR_DRAM_BANKS - bank". We want to duplicate the
  50. * current entry and shift up the remaining entries, dropping
  51. * the last one. Thus, we must copy one fewer entry than the
  52. * number remaining.
  53. */
  54. memmove(&tegra_mem_map[bank + 1], &tegra_mem_map[bank],
  55. CONFIG_NR_DRAM_BANKS - bank - 1);
  56. tegra_mem_map[bank].size = allocated_start - bank_start;
  57. bank++;
  58. tegra_mem_map[bank].virt = allocated_end;
  59. tegra_mem_map[bank].phys = allocated_end;
  60. tegra_mem_map[bank].size = bank_end - allocated_end;
  61. } else if (keep_front) {
  62. tegra_mem_map[bank].size = allocated_start - bank_start;
  63. } else if (keep_tail) {
  64. tegra_mem_map[bank].virt = allocated_end;
  65. tegra_mem_map[bank].phys = allocated_end;
  66. tegra_mem_map[bank].size = bank_end - allocated_end;
  67. } else {
  68. /*
  69. * We could move all subsequent banks down in the array but
  70. * that's not necessary for subsequent allocations to work, so
  71. * we skip doing so.
  72. */
  73. tegra_mem_map[bank].size = 0;
  74. }
  75. }
  76. static void reserve_ram(u64 start, u64 size)
  77. {
  78. int bank;
  79. u64 end = start + size;
  80. for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
  81. u64 bank_start = tegra_mem_map[bank].virt;
  82. u64 bank_size = tegra_mem_map[bank].size;
  83. u64 bank_end = bank_start + bank_size;
  84. if (end <= bank_start || start > bank_end)
  85. continue;
  86. mark_ram_allocated(bank, start, end);
  87. break;
  88. }
  89. }
  90. static u64 alloc_ram(u64 size, u64 align, u64 offset)
  91. {
  92. int bank;
  93. for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
  94. u64 bank_start = tegra_mem_map[bank].virt;
  95. u64 bank_size = tegra_mem_map[bank].size;
  96. u64 bank_end = bank_start + bank_size;
  97. u64 allocated = ROUND(bank_start, align) + offset;
  98. u64 allocated_end = allocated + size;
  99. if (allocated_end > bank_end)
  100. continue;
  101. mark_ram_allocated(bank, allocated, allocated_end);
  102. return allocated;
  103. }
  104. return 0;
  105. }
  106. static void set_calculated_aliases(char *aliases, u64 address)
  107. {
  108. char *tmp, *alias;
  109. int err;
  110. aliases = strdup(aliases);
  111. if (!aliases) {
  112. pr_err("strdup(aliases) failed");
  113. return;
  114. }
  115. tmp = aliases;
  116. while (true) {
  117. alias = strsep(&tmp, " ");
  118. if (!alias)
  119. break;
  120. debug("%s: alias: %s\n", __func__, alias);
  121. err = env_set_hex(alias, address);
  122. if (err)
  123. pr_err("Could not set %s\n", alias);
  124. }
  125. free(aliases);
  126. }
  127. static void set_calculated_env_var(const char *var)
  128. {
  129. char *var_size;
  130. char *var_align;
  131. char *var_offset;
  132. char *var_aliases;
  133. u64 size;
  134. u64 align;
  135. u64 offset;
  136. char *aliases;
  137. u64 address;
  138. int err;
  139. var_size = gen_varname(var, "_size");
  140. if (!var_size)
  141. return;
  142. var_align = gen_varname(var, "_align");
  143. if (!var_align)
  144. goto out_free_var_size;
  145. var_offset = gen_varname(var, "_offset");
  146. if (!var_offset)
  147. goto out_free_var_align;
  148. var_aliases = gen_varname(var, "_aliases");
  149. if (!var_aliases)
  150. goto out_free_var_offset;
  151. size = env_get_hex(var_size, 0);
  152. if (!size) {
  153. pr_err("%s not set or zero\n", var_size);
  154. goto out_free_var_aliases;
  155. }
  156. align = env_get_hex(var_align, 1);
  157. /* Handle extant variables, but with a value of 0 */
  158. if (!align)
  159. align = 1;
  160. offset = env_get_hex(var_offset, 0);
  161. aliases = env_get(var_aliases);
  162. debug("%s: Calc var %s; size=%llx, align=%llx, offset=%llx\n",
  163. __func__, var, size, align, offset);
  164. if (aliases)
  165. debug("%s: Aliases: %s\n", __func__, aliases);
  166. address = alloc_ram(size, align, offset);
  167. if (!address) {
  168. pr_err("Could not allocate %s\n", var);
  169. goto out_free_var_aliases;
  170. }
  171. debug("%s: Address %llx\n", __func__, address);
  172. err = env_set_hex(var, address);
  173. if (err)
  174. pr_err("Could not set %s\n", var);
  175. if (aliases)
  176. set_calculated_aliases(aliases, address);
  177. out_free_var_aliases:
  178. free(var_aliases);
  179. out_free_var_offset:
  180. free(var_offset);
  181. out_free_var_align:
  182. free(var_align);
  183. out_free_var_size:
  184. free(var_size);
  185. }
  186. #ifdef DEBUG
  187. static void dump_ram_banks(void)
  188. {
  189. int bank;
  190. for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) {
  191. u64 bank_start = tegra_mem_map[bank].virt;
  192. u64 bank_size = tegra_mem_map[bank].size;
  193. u64 bank_end = bank_start + bank_size;
  194. if (!bank_size)
  195. continue;
  196. printf("%d: %010llx..%010llx (+%010llx)\n", bank - 1,
  197. bank_start, bank_end, bank_size);
  198. }
  199. }
  200. #endif
  201. static void set_calculated_env_vars(void)
  202. {
  203. char *vars, *tmp, *var;
  204. #ifdef DEBUG
  205. printf("RAM banks before any calculated env. var.s:\n");
  206. dump_ram_banks();
  207. #endif
  208. reserve_ram(nvtboot_boot_x0, fdt_totalsize(nvtboot_boot_x0));
  209. #ifdef DEBUG
  210. printf("RAM after reserving cboot DTB:\n");
  211. dump_ram_banks();
  212. #endif
  213. vars = env_get("calculated_vars");
  214. if (!vars) {
  215. debug("%s: No env var calculated_vars\n", __func__);
  216. return;
  217. }
  218. vars = strdup(vars);
  219. if (!vars) {
  220. pr_err("strdup(calculated_vars) failed");
  221. return;
  222. }
  223. tmp = vars;
  224. while (true) {
  225. var = strsep(&tmp, " ");
  226. if (!var)
  227. break;
  228. debug("%s: var: %s\n", __func__, var);
  229. set_calculated_env_var(var);
  230. #ifdef DEBUG
  231. printf("RAM banks affter allocating %s:\n", var);
  232. dump_ram_banks();
  233. #endif
  234. }
  235. free(vars);
  236. }
  237. static int set_fdt_addr(void)
  238. {
  239. int ret;
  240. ret = env_set_hex("fdt_addr", nvtboot_boot_x0);
  241. if (ret) {
  242. printf("Failed to set fdt_addr to point at DTB: %d\n", ret);
  243. return ret;
  244. }
  245. return 0;
  246. }
  247. /*
  248. * Attempt to use /chosen/nvidia,ether-mac in the nvtboot DTB to U-Boot's
  249. * ethaddr environment variable if possible.
  250. */
  251. static int set_ethaddr_from_nvtboot(void)
  252. {
  253. const void *nvtboot_blob = (void *)nvtboot_boot_x0;
  254. int ret, node, len;
  255. const u32 *prop;
  256. /* Already a valid address in the environment? If so, keep it */
  257. if (env_get("ethaddr"))
  258. return 0;
  259. node = fdt_path_offset(nvtboot_blob, "/chosen");
  260. if (node < 0) {
  261. printf("Can't find /chosen node in nvtboot DTB\n");
  262. return node;
  263. }
  264. prop = fdt_getprop(nvtboot_blob, node, "nvidia,ether-mac", &len);
  265. if (!prop) {
  266. printf("Can't find nvidia,ether-mac property in nvtboot DTB\n");
  267. return -ENOENT;
  268. }
  269. ret = env_set("ethaddr", (void *)prop);
  270. if (ret) {
  271. printf("Failed to set ethaddr from nvtboot DTB: %d\n", ret);
  272. return ret;
  273. }
  274. return 0;
  275. }
  276. int tegra_soc_board_init_late(void)
  277. {
  278. set_calculated_env_vars();
  279. /*
  280. * Ignore errors here; the value may not be used depending on
  281. * extlinux.conf or boot script content.
  282. */
  283. set_fdt_addr();
  284. /* Ignore errors here; not all cases care about Ethernet addresses */
  285. set_ethaddr_from_nvtboot();
  286. return 0;
  287. }