psci-dt.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2016 NXP Semiconductor, Inc.
  4. */
  5. #include <common.h>
  6. #include <linux/libfdt.h>
  7. #include <fdt_support.h>
  8. #include <linux/sizes.h>
  9. #include <linux/kernel.h>
  10. #include <asm/psci.h>
  11. #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
  12. #include <asm/armv8/sec_firmware.h>
  13. #endif
  14. int fdt_psci(void *fdt)
  15. {
  16. #if defined(CONFIG_ARMV7_PSCI) || defined(CONFIG_ARMV8_PSCI) || \
  17. defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI)
  18. int nodeoff;
  19. unsigned int psci_ver = 0;
  20. int tmp;
  21. nodeoff = fdt_path_offset(fdt, "/cpus");
  22. if (nodeoff < 0) {
  23. printf("couldn't find /cpus\n");
  24. return nodeoff;
  25. }
  26. /* add 'enable-method = "psci"' to each cpu node */
  27. for (tmp = fdt_first_subnode(fdt, nodeoff);
  28. tmp >= 0;
  29. tmp = fdt_next_subnode(fdt, tmp)) {
  30. const struct fdt_property *prop;
  31. int len;
  32. prop = fdt_get_property(fdt, tmp, "device_type", &len);
  33. if (!prop)
  34. continue;
  35. if (len < 4)
  36. continue;
  37. if (strcmp(prop->data, "cpu"))
  38. continue;
  39. /*
  40. * Not checking rv here, our approach is to skip over errors in
  41. * individual cpu nodes, hopefully some of the nodes are
  42. * processed correctly and those will boot
  43. */
  44. fdt_setprop_string(fdt, tmp, "enable-method", "psci");
  45. }
  46. nodeoff = fdt_path_offset(fdt, "/psci");
  47. if (nodeoff >= 0)
  48. goto init_psci_node;
  49. nodeoff = fdt_path_offset(fdt, "/");
  50. if (nodeoff < 0)
  51. return nodeoff;
  52. nodeoff = fdt_add_subnode(fdt, nodeoff, "psci");
  53. if (nodeoff < 0)
  54. return nodeoff;
  55. init_psci_node:
  56. #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
  57. psci_ver = sec_firmware_support_psci_version();
  58. #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI)
  59. psci_ver = ARM_PSCI_VER_1_0;
  60. #elif defined(CONFIG_ARMV7_PSCI_0_2)
  61. psci_ver = ARM_PSCI_VER_0_2;
  62. #endif
  63. if (psci_ver >= ARM_PSCI_VER_1_0) {
  64. tmp = fdt_setprop_string(fdt, nodeoff,
  65. "compatible", "arm,psci-1.0");
  66. if (tmp)
  67. return tmp;
  68. }
  69. if (psci_ver >= ARM_PSCI_VER_0_2) {
  70. tmp = fdt_appendprop_string(fdt, nodeoff,
  71. "compatible", "arm,psci-0.2");
  72. if (tmp)
  73. return tmp;
  74. }
  75. #ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
  76. /*
  77. * The Secure firmware framework isn't able to support PSCI version 0.1.
  78. */
  79. if (psci_ver < ARM_PSCI_VER_0_2) {
  80. tmp = fdt_appendprop_string(fdt, nodeoff,
  81. "compatible", "arm,psci");
  82. if (tmp)
  83. return tmp;
  84. tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend",
  85. ARM_PSCI_FN_CPU_SUSPEND);
  86. if (tmp)
  87. return tmp;
  88. tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off",
  89. ARM_PSCI_FN_CPU_OFF);
  90. if (tmp)
  91. return tmp;
  92. tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on",
  93. ARM_PSCI_FN_CPU_ON);
  94. if (tmp)
  95. return tmp;
  96. tmp = fdt_setprop_u32(fdt, nodeoff, "migrate",
  97. ARM_PSCI_FN_MIGRATE);
  98. if (tmp)
  99. return tmp;
  100. }
  101. #endif
  102. tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc");
  103. if (tmp)
  104. return tmp;
  105. tmp = fdt_setprop_string(fdt, nodeoff, "status", "okay");
  106. if (tmp)
  107. return tmp;
  108. #endif
  109. return 0;
  110. }