psci-dt.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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. #endif
  61. if (psci_ver >= ARM_PSCI_VER_1_0) {
  62. tmp = fdt_setprop_string(fdt, nodeoff,
  63. "compatible", "arm,psci-1.0");
  64. if (tmp)
  65. return tmp;
  66. }
  67. if (psci_ver >= ARM_PSCI_VER_0_2) {
  68. tmp = fdt_appendprop_string(fdt, nodeoff,
  69. "compatible", "arm,psci-0.2");
  70. if (tmp)
  71. return tmp;
  72. }
  73. #ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
  74. /*
  75. * The Secure firmware framework isn't able to support PSCI version 0.1.
  76. */
  77. if (psci_ver < ARM_PSCI_VER_0_2) {
  78. tmp = fdt_appendprop_string(fdt, nodeoff,
  79. "compatible", "arm,psci");
  80. if (tmp)
  81. return tmp;
  82. tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend",
  83. ARM_PSCI_FN_CPU_SUSPEND);
  84. if (tmp)
  85. return tmp;
  86. tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off",
  87. ARM_PSCI_FN_CPU_OFF);
  88. if (tmp)
  89. return tmp;
  90. tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on",
  91. ARM_PSCI_FN_CPU_ON);
  92. if (tmp)
  93. return tmp;
  94. tmp = fdt_setprop_u32(fdt, nodeoff, "migrate",
  95. ARM_PSCI_FN_MIGRATE);
  96. if (tmp)
  97. return tmp;
  98. }
  99. #endif
  100. tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc");
  101. if (tmp)
  102. return tmp;
  103. #endif
  104. return 0;
  105. }