fdt_fixup.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. /*
  7. * Contains generic routines to fix up the device tree blob passed on to
  8. * payloads like BL32 and BL33 (and further down the boot chain).
  9. * This allows to easily add PSCI nodes, when the original DT does not have
  10. * it or advertises another method.
  11. * Also it supports to add reserved memory nodes to describe memory that
  12. * is used by the secure world, so that non-secure software avoids using
  13. * that.
  14. */
  15. #include <errno.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <libfdt.h>
  19. #include <arch.h>
  20. #include <common/debug.h>
  21. #include <common/fdt_fixup.h>
  22. #include <common/fdt_wrappers.h>
  23. #include <drivers/console.h>
  24. #include <lib/psci/psci.h>
  25. #include <plat/common/platform.h>
  26. static int append_psci_compatible(void *fdt, int offs, const char *str)
  27. {
  28. return fdt_appendprop(fdt, offs, "compatible", str, strlen(str) + 1);
  29. }
  30. /*
  31. * Those defines are for PSCI v0.1 legacy clients, which we expect to use
  32. * the same execution state (AArch32/AArch64) as TF-A.
  33. * Kernels running in AArch32 on an AArch64 TF-A should use PSCI v0.2.
  34. */
  35. #ifdef __aarch64__
  36. #define PSCI_CPU_SUSPEND_FNID PSCI_CPU_SUSPEND_AARCH64
  37. #define PSCI_CPU_ON_FNID PSCI_CPU_ON_AARCH64
  38. #else
  39. #define PSCI_CPU_SUSPEND_FNID PSCI_CPU_SUSPEND_AARCH32
  40. #define PSCI_CPU_ON_FNID PSCI_CPU_ON_AARCH32
  41. #endif
  42. /*******************************************************************************
  43. * dt_add_psci_node() - Add a PSCI node into an existing device tree
  44. * @fdt: pointer to the device tree blob in memory
  45. *
  46. * Add a device tree node describing PSCI into the root level of an existing
  47. * device tree blob in memory.
  48. * This will add v0.1, v0.2 and v1.0 compatible strings and the standard
  49. * function IDs for v0.1 compatibility.
  50. * An existing PSCI node will not be touched, the function will return success
  51. * in this case. This function will not touch the /cpus enable methods, use
  52. * dt_add_psci_cpu_enable_methods() for that.
  53. *
  54. * Return: 0 on success, -1 otherwise.
  55. ******************************************************************************/
  56. int dt_add_psci_node(void *fdt)
  57. {
  58. int offs;
  59. if (fdt_path_offset(fdt, "/psci") >= 0) {
  60. WARN("PSCI Device Tree node already exists!\n");
  61. return 0;
  62. }
  63. offs = fdt_path_offset(fdt, "/");
  64. if (offs < 0)
  65. return -1;
  66. offs = fdt_add_subnode(fdt, offs, "psci");
  67. if (offs < 0)
  68. return -1;
  69. if (append_psci_compatible(fdt, offs, "arm,psci-1.0"))
  70. return -1;
  71. if (append_psci_compatible(fdt, offs, "arm,psci-0.2"))
  72. return -1;
  73. if (append_psci_compatible(fdt, offs, "arm,psci"))
  74. return -1;
  75. if (fdt_setprop_string(fdt, offs, "method", "smc"))
  76. return -1;
  77. if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_FNID))
  78. return -1;
  79. if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF))
  80. return -1;
  81. if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_FNID))
  82. return -1;
  83. return 0;
  84. }
  85. /*
  86. * Find the first subnode that has a "device_type" property with the value
  87. * "cpu" and which's enable-method is not "psci" (yet).
  88. * Returns 0 if no such subnode is found, so all have already been patched
  89. * or none have to be patched in the first place.
  90. * Returns 1 if *one* such subnode has been found and successfully changed
  91. * to "psci".
  92. * Returns negative values on error.
  93. *
  94. * Call in a loop until it returns 0. Recalculate the node offset after
  95. * it has returned 1.
  96. */
  97. static int dt_update_one_cpu_node(void *fdt, int offset)
  98. {
  99. int offs;
  100. /* Iterate over all subnodes to find those with device_type = "cpu". */
  101. for (offs = fdt_first_subnode(fdt, offset); offs >= 0;
  102. offs = fdt_next_subnode(fdt, offs)) {
  103. const char *prop;
  104. int len;
  105. int ret;
  106. prop = fdt_getprop(fdt, offs, "device_type", &len);
  107. if (prop == NULL)
  108. continue;
  109. if ((strcmp(prop, "cpu") != 0) || (len != 4))
  110. continue;
  111. /* Ignore any nodes which already use "psci". */
  112. prop = fdt_getprop(fdt, offs, "enable-method", &len);
  113. if ((prop != NULL) &&
  114. (strcmp(prop, "psci") == 0) && (len == 5))
  115. continue;
  116. ret = fdt_setprop_string(fdt, offs, "enable-method", "psci");
  117. if (ret < 0)
  118. return ret;
  119. /*
  120. * Subnode found and patched.
  121. * Restart to accommodate potentially changed offsets.
  122. */
  123. return 1;
  124. }
  125. if (offs == -FDT_ERR_NOTFOUND)
  126. return 0;
  127. return offs;
  128. }
  129. /*******************************************************************************
  130. * dt_add_psci_cpu_enable_methods() - switch CPU nodes in DT to use PSCI
  131. * @fdt: pointer to the device tree blob in memory
  132. *
  133. * Iterate over all CPU device tree nodes (/cpus/cpu@x) in memory to change
  134. * the enable-method to PSCI. This will add the enable-method properties, if
  135. * required, or will change existing properties to read "psci".
  136. *
  137. * Return: 0 on success, or a negative error value otherwise.
  138. ******************************************************************************/
  139. int dt_add_psci_cpu_enable_methods(void *fdt)
  140. {
  141. int offs, ret;
  142. do {
  143. offs = fdt_path_offset(fdt, "/cpus");
  144. if (offs < 0)
  145. return offs;
  146. ret = dt_update_one_cpu_node(fdt, offs);
  147. } while (ret > 0);
  148. return ret;
  149. }
  150. #define HIGH_BITS(x) ((sizeof(x) > 4) ? ((x) >> 32) : (typeof(x))0)
  151. /*******************************************************************************
  152. * fdt_add_reserved_memory() - reserve (secure) memory regions in DT
  153. * @dtb: pointer to the device tree blob in memory
  154. * @node_name: name of the subnode to be used
  155. * @base: physical base address of the reserved region
  156. * @size: size of the reserved region
  157. *
  158. * Add a region of memory to the /reserved-memory node in a device tree in
  159. * memory, creating that node if required. Each region goes into a subnode
  160. * of that node and has a @node_name, a @base address and a @size.
  161. * This will prevent any device tree consumer from using that memory. It
  162. * can be used to announce secure memory regions, as it adds the "no-map"
  163. * property to prevent mapping and speculative operations on that region.
  164. *
  165. * See reserved-memory/reserved-memory.txt in the (Linux kernel) DT binding
  166. * documentation for details.
  167. * According to this binding, the address-cells and size-cells must match
  168. * those of the root node.
  169. *
  170. * Return: 0 on success, a negative error value otherwise.
  171. ******************************************************************************/
  172. int fdt_add_reserved_memory(void *dtb, const char *node_name,
  173. uintptr_t base, size_t size)
  174. {
  175. int offs = fdt_path_offset(dtb, "/reserved-memory");
  176. uint32_t addresses[4];
  177. int ac, sc;
  178. unsigned int idx = 0;
  179. ac = fdt_address_cells(dtb, 0);
  180. sc = fdt_size_cells(dtb, 0);
  181. if (offs < 0) { /* create if not existing yet */
  182. offs = fdt_add_subnode(dtb, 0, "reserved-memory");
  183. if (offs < 0) {
  184. return offs;
  185. }
  186. fdt_setprop_u32(dtb, offs, "#address-cells", ac);
  187. fdt_setprop_u32(dtb, offs, "#size-cells", sc);
  188. fdt_setprop(dtb, offs, "ranges", NULL, 0);
  189. }
  190. if (ac > 1) {
  191. addresses[idx] = cpu_to_fdt32(HIGH_BITS(base));
  192. idx++;
  193. }
  194. addresses[idx] = cpu_to_fdt32(base & 0xffffffff);
  195. idx++;
  196. if (sc > 1) {
  197. addresses[idx] = cpu_to_fdt32(HIGH_BITS(size));
  198. idx++;
  199. }
  200. addresses[idx] = cpu_to_fdt32(size & 0xffffffff);
  201. idx++;
  202. offs = fdt_add_subnode(dtb, offs, node_name);
  203. fdt_setprop(dtb, offs, "no-map", NULL, 0);
  204. fdt_setprop(dtb, offs, "reg", addresses, idx * sizeof(uint32_t));
  205. return 0;
  206. }
  207. /*******************************************************************************
  208. * fdt_add_cpu() Add a new CPU node to the DT
  209. * @dtb: Pointer to the device tree blob in memory
  210. * @parent: Offset of the parent node
  211. * @mpidr: MPIDR for the current CPU
  212. *
  213. * Create and add a new cpu node to a DTB.
  214. *
  215. * Return the offset of the new node or a negative value in case of error
  216. ******************************************************************************/
  217. static int fdt_add_cpu(void *dtb, int parent, u_register_t mpidr)
  218. {
  219. int cpu_offs;
  220. int err;
  221. char snode_name[15];
  222. uint64_t reg_prop;
  223. reg_prop = mpidr & MPID_MASK & ~MPIDR_MT_MASK;
  224. snprintf(snode_name, sizeof(snode_name), "cpu@%x",
  225. (unsigned int)reg_prop);
  226. cpu_offs = fdt_add_subnode(dtb, parent, snode_name);
  227. if (cpu_offs < 0) {
  228. ERROR ("FDT: add subnode \"%s\" failed: %i\n",
  229. snode_name, cpu_offs);
  230. return cpu_offs;
  231. }
  232. err = fdt_setprop_string(dtb, cpu_offs, "compatible", "arm,armv8");
  233. if (err < 0) {
  234. ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
  235. "compatible", cpu_offs);
  236. return err;
  237. }
  238. err = fdt_setprop_u64(dtb, cpu_offs, "reg", reg_prop);
  239. if (err < 0) {
  240. ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
  241. "reg", cpu_offs);
  242. return err;
  243. }
  244. err = fdt_setprop_string(dtb, cpu_offs, "device_type", "cpu");
  245. if (err < 0) {
  246. ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
  247. "device_type", cpu_offs);
  248. return err;
  249. }
  250. err = fdt_setprop_string(dtb, cpu_offs, "enable-method", "psci");
  251. if (err < 0) {
  252. ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
  253. "enable-method", cpu_offs);
  254. return err;
  255. }
  256. return cpu_offs;
  257. }
  258. /******************************************************************************
  259. * fdt_add_cpus_node() - Add the cpus node to the DTB
  260. * @dtb: pointer to the device tree blob in memory
  261. * @afflv0: Maximum number of threads per core (affinity level 0).
  262. * @afflv1: Maximum number of CPUs per cluster (affinity level 1).
  263. * @afflv2: Maximum number of clusters (affinity level 2).
  264. *
  265. * Iterate over all the possible MPIDs given the maximum affinity levels and
  266. * add a cpus node to the DTB with all the valid CPUs on the system.
  267. * If there is already a /cpus node, exit gracefully
  268. *
  269. * A system with two CPUs would generate a node equivalent or similar to:
  270. *
  271. * cpus {
  272. * #address-cells = <2>;
  273. * #size-cells = <0>;
  274. *
  275. * cpu0: cpu@0 {
  276. * compatible = "arm,armv8";
  277. * reg = <0x0 0x0>;
  278. * device_type = "cpu";
  279. * enable-method = "psci";
  280. * };
  281. * cpu1: cpu@10000 {
  282. * compatible = "arm,armv8";
  283. * reg = <0x0 0x100>;
  284. * device_type = "cpu";
  285. * enable-method = "psci";
  286. * };
  287. * };
  288. *
  289. * Full documentation about the CPU bindings can be found at:
  290. * https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/cpus.txt
  291. *
  292. * Return the offset of the node or a negative value on error.
  293. ******************************************************************************/
  294. int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
  295. unsigned int afflv1, unsigned int afflv2)
  296. {
  297. int offs;
  298. int err;
  299. unsigned int i, j, k;
  300. u_register_t mpidr;
  301. int cpuid;
  302. if (fdt_path_offset(dtb, "/cpus") >= 0) {
  303. return -EEXIST;
  304. }
  305. offs = fdt_add_subnode(dtb, 0, "cpus");
  306. if (offs < 0) {
  307. ERROR ("FDT: add subnode \"cpus\" node to parent node failed");
  308. return offs;
  309. }
  310. err = fdt_setprop_u32(dtb, offs, "#address-cells", 2);
  311. if (err < 0) {
  312. ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
  313. "#address-cells", offs);
  314. return err;
  315. }
  316. err = fdt_setprop_u32(dtb, offs, "#size-cells", 0);
  317. if (err < 0) {
  318. ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
  319. "#size-cells", offs);
  320. return err;
  321. }
  322. /*
  323. * Populate the node with the CPUs.
  324. * As libfdt prepends subnodes within a node, reverse the index count
  325. * so the CPU nodes would be better ordered.
  326. */
  327. for (i = afflv2; i > 0U; i--) {
  328. for (j = afflv1; j > 0U; j--) {
  329. for (k = afflv0; k > 0U; k--) {
  330. mpidr = ((i - 1) << MPIDR_AFF2_SHIFT) |
  331. ((j - 1) << MPIDR_AFF1_SHIFT) |
  332. ((k - 1) << MPIDR_AFF0_SHIFT) |
  333. (read_mpidr_el1() & MPIDR_MT_MASK);
  334. cpuid = plat_core_pos_by_mpidr(mpidr);
  335. if (cpuid >= 0) {
  336. /* Valid MPID found */
  337. err = fdt_add_cpu(dtb, offs, mpidr);
  338. if (err < 0) {
  339. ERROR ("FDT: %s 0x%08x\n",
  340. "error adding CPU",
  341. (uint32_t)mpidr);
  342. return err;
  343. }
  344. }
  345. }
  346. }
  347. }
  348. return offs;
  349. }
  350. /**
  351. * fdt_adjust_gic_redist() - Adjust GICv3 redistributor size
  352. * @dtb: Pointer to the DT blob in memory
  353. * @nr_cores: Number of CPU cores on this system.
  354. * @gicr_frame_size: Size of the GICR frame per core
  355. *
  356. * On a GICv3 compatible interrupt controller, the redistributor provides
  357. * a number of 64k pages per each supported core. So with a dynamic topology,
  358. * this size cannot be known upfront and thus can't be hardcoded into the DTB.
  359. *
  360. * Find the DT node describing the GICv3 interrupt controller, and adjust
  361. * the size of the redistributor to match the number of actual cores on
  362. * this system.
  363. * A GICv4 compatible redistributor uses four 64K pages per core, whereas GICs
  364. * without support for direct injection of virtual interrupts use two 64K pages.
  365. * The @gicr_frame_size parameter should be 262144 and 131072, respectively.
  366. *
  367. * Return: 0 on success, negative error value otherwise.
  368. */
  369. int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores,
  370. unsigned int gicr_frame_size)
  371. {
  372. int offset = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-v3");
  373. uint64_t redist_size_64;
  374. uint32_t redist_size_32;
  375. void *val;
  376. int parent;
  377. int ac, sc;
  378. if (offset < 0) {
  379. return offset;
  380. }
  381. parent = fdt_parent_offset(dtb, offset);
  382. if (parent < 0) {
  383. return parent;
  384. }
  385. ac = fdt_address_cells(dtb, parent);
  386. sc = fdt_size_cells(dtb, parent);
  387. if (ac < 0 || sc < 0) {
  388. return -EINVAL;
  389. }
  390. if (sc == 1) {
  391. redist_size_32 = cpu_to_fdt32(nr_cores * gicr_frame_size);
  392. val = &redist_size_32;
  393. } else {
  394. redist_size_64 = cpu_to_fdt64(nr_cores *
  395. (uint64_t)gicr_frame_size);
  396. val = &redist_size_64;
  397. }
  398. /*
  399. * The redistributor is described in the second "reg" entry.
  400. * So we have to skip one address and one size cell, then another
  401. * address cell to get to the second size cell.
  402. */
  403. return fdt_setprop_inplace_namelen_partial(dtb, offset, "reg", 3,
  404. (ac + sc + ac) * 4,
  405. val, sc * 4);
  406. }