psci-dt.c 2.7 KB

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