psci.S 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * Copyright 2016 Freescale Semiconductor, Inc.
  3. * Author: Hongbo Zhang <hongbo.zhang@nxp.com>
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. * This file implements LS102X platform PSCI SYSTEM-SUSPEND function
  7. */
  8. #include <config.h>
  9. #include <linux/linkage.h>
  10. #include <asm/psci.h>
  11. /* Default PSCI function, return -1, Not Implemented */
  12. #define PSCI_DEFAULT(__fn) \
  13. ENTRY(__fn); \
  14. mov w0, #ARM_PSCI_RET_NI; \
  15. ret; \
  16. ENDPROC(__fn); \
  17. .weak __fn
  18. /* PSCI function and ID table definition*/
  19. #define PSCI_TABLE(__id, __fn) \
  20. .word __id; \
  21. .word __fn
  22. .pushsection ._secure.text, "ax"
  23. /* 32 bits PSCI default functions */
  24. PSCI_DEFAULT(psci_version)
  25. PSCI_DEFAULT(psci_cpu_suspend)
  26. PSCI_DEFAULT(psci_cpu_off)
  27. PSCI_DEFAULT(psci_cpu_on)
  28. PSCI_DEFAULT(psci_affinity_info)
  29. PSCI_DEFAULT(psci_migrate)
  30. PSCI_DEFAULT(psci_migrate_info_type)
  31. PSCI_DEFAULT(psci_migrate_info_up_cpu)
  32. PSCI_DEFAULT(psci_system_off)
  33. PSCI_DEFAULT(psci_system_reset)
  34. PSCI_DEFAULT(psci_features)
  35. PSCI_DEFAULT(psci_cpu_freeze)
  36. PSCI_DEFAULT(psci_cpu_default_suspend)
  37. PSCI_DEFAULT(psci_node_hw_state)
  38. PSCI_DEFAULT(psci_system_suspend)
  39. PSCI_DEFAULT(psci_set_suspend_mode)
  40. PSCI_DEFAULT(psi_stat_residency)
  41. PSCI_DEFAULT(psci_stat_count)
  42. .align 3
  43. _psci_32_table:
  44. PSCI_TABLE(ARM_PSCI_FN_CPU_SUSPEND, psci_cpu_suspend)
  45. PSCI_TABLE(ARM_PSCI_FN_CPU_OFF, psci_cpu_off)
  46. PSCI_TABLE(ARM_PSCI_FN_CPU_ON, psci_cpu_on)
  47. PSCI_TABLE(ARM_PSCI_FN_MIGRATE, psci_migrate)
  48. PSCI_TABLE(ARM_PSCI_0_2_FN_PSCI_VERSION, psci_version)
  49. PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_SUSPEND, psci_cpu_suspend)
  50. PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_OFF, psci_cpu_off)
  51. PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_ON, psci_cpu_on)
  52. PSCI_TABLE(ARM_PSCI_0_2_FN_AFFINITY_INFO, psci_affinity_info)
  53. PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE, psci_migrate)
  54. PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE, psci_migrate_info_type)
  55. PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu)
  56. PSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_OFF, psci_system_off)
  57. PSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_RESET, psci_system_reset)
  58. PSCI_TABLE(ARM_PSCI_1_0_FN_PSCI_FEATURES, psci_features)
  59. PSCI_TABLE(ARM_PSCI_1_0_FN_CPU_FREEZE, psci_cpu_freeze)
  60. PSCI_TABLE(ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend)
  61. PSCI_TABLE(ARM_PSCI_1_0_FN_NODE_HW_STATE, psci_node_hw_state)
  62. PSCI_TABLE(ARM_PSCI_1_0_FN_SYSTEM_SUSPEND, psci_system_suspend)
  63. PSCI_TABLE(ARM_PSCI_1_0_FN_SET_SUSPEND_MODE, psci_set_suspend_mode)
  64. PSCI_TABLE(ARM_PSCI_1_0_FN_STAT_RESIDENCY, psi_stat_residency)
  65. PSCI_TABLE(ARM_PSCI_1_0_FN_STAT_COUNT, psci_stat_count)
  66. PSCI_TABLE(0, 0)
  67. /* 64 bits PSCI default functions */
  68. PSCI_DEFAULT(psci_cpu_suspend_64)
  69. PSCI_DEFAULT(psci_cpu_on_64)
  70. PSCI_DEFAULT(psci_affinity_info_64)
  71. PSCI_DEFAULT(psci_migrate_64)
  72. PSCI_DEFAULT(psci_migrate_info_up_cpu_64)
  73. PSCI_DEFAULT(psci_cpu_default_suspend_64)
  74. PSCI_DEFAULT(psci_node_hw_state_64)
  75. PSCI_DEFAULT(psci_system_suspend_64)
  76. PSCI_DEFAULT(psci_stat_residency_64)
  77. PSCI_DEFAULT(psci_stat_count_64)
  78. .align 3
  79. _psci_64_table:
  80. PSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_SUSPEND, psci_cpu_suspend_64)
  81. PSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_ON, psci_cpu_on_64)
  82. PSCI_TABLE(ARM_PSCI_0_2_FN64_AFFINITY_INFO, psci_affinity_info_64)
  83. PSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE, psci_migrate_64)
  84. PSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu_64)
  85. PSCI_TABLE(ARM_PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend_64)
  86. PSCI_TABLE(ARM_PSCI_1_0_FN64_NODE_HW_STATE, psci_node_hw_state_64)
  87. PSCI_TABLE(ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND, psci_system_suspend_64)
  88. PSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_RESIDENCY, psci_stat_residency_64)
  89. PSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_COUNT, psci_stat_count_64)
  90. PSCI_TABLE(0, 0)
  91. .macro psci_enter
  92. /* PSCI call is Fast Call(atomic), so mask DAIF */
  93. mrs x15, DAIF
  94. stp x15, xzr, [sp, #-16]!
  95. ldr x15, =0x3C0
  96. msr DAIF, x15
  97. /* SMC convention, x18 ~ x30 should be saved by callee */
  98. stp x29, x30, [sp, #-16]!
  99. stp x27, x28, [sp, #-16]!
  100. stp x25, x26, [sp, #-16]!
  101. stp x23, x24, [sp, #-16]!
  102. stp x21, x22, [sp, #-16]!
  103. stp x19, x20, [sp, #-16]!
  104. mrs x15, elr_el3
  105. stp x18, x15, [sp, #-16]!
  106. .endm
  107. .macro psci_return
  108. /* restore registers */
  109. ldp x18, x15, [sp], #16
  110. msr elr_el3, x15
  111. ldp x19, x20, [sp], #16
  112. ldp x21, x22, [sp], #16
  113. ldp x23, x24, [sp], #16
  114. ldp x25, x26, [sp], #16
  115. ldp x27, x28, [sp], #16
  116. ldp x29, x30, [sp], #16
  117. /* restore DAIF */
  118. ldp x15, xzr, [sp], #16
  119. msr DAIF, x15
  120. eret
  121. .endm
  122. /* Caller must put PSCI function-ID table base in x9 */
  123. handle_psci:
  124. psci_enter
  125. 1: ldr x10, [x9] /* Load PSCI function table */
  126. ubfx x11, x10, #32, #32
  127. ubfx x10, x10, #0, #32
  128. cbz x10, 3f /* If reach the end, bail out */
  129. cmp x10, x0
  130. b.eq 2f /* PSCI function found */
  131. add x9, x9, #8 /* If not match, try next entry */
  132. b 1b
  133. 2: blr x11 /* Call PSCI function */
  134. psci_return
  135. 3: mov x0, #ARM_PSCI_RET_NI
  136. psci_return
  137. unknown_smc_id:
  138. ldr x0, =0xFFFFFFFF
  139. eret
  140. handle_smc32:
  141. /* SMC function ID 0x84000000-0x8400001F: 32 bits PSCI */
  142. ldr w9, =0x8400001F
  143. cmp w0, w9
  144. b.gt unknown_smc_id
  145. ldr w9, =0x84000000
  146. cmp w0, w9
  147. b.lt unknown_smc_id
  148. adr x9, _psci_32_table
  149. b handle_psci
  150. handle_smc64:
  151. /* check SMC32 or SMC64 calls */
  152. ubfx x9, x0, #30, #1
  153. cbz x9, handle_smc32
  154. /* SMC function ID 0xC4000000-0xC400001F: 64 bits PSCI */
  155. ldr x9, =0xC400001F
  156. cmp x0, x9
  157. b.gt unknown_smc_id
  158. ldr x9, =0xC4000000
  159. cmp x0, x9
  160. b.lt unknown_smc_id
  161. adr x9, _psci_64_table
  162. b handle_psci
  163. /*
  164. * Get CPU ID from MPIDR, suppose every cluster has same number of CPU cores,
  165. * Platform with asymmetric clusters should implement their own interface.
  166. * In case this function being called by other platform's C code, the ARM
  167. * Architecture Procedure Call Standard is considered, e.g. register X0 is
  168. * used for the return value, while in this PSCI environment, X0 usually holds
  169. * the SMC function identifier, so X0 should be saved by caller function.
  170. */
  171. ENTRY(psci_get_cpu_id)
  172. #ifdef CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER
  173. mrs x9, MPIDR_EL1
  174. ubfx x9, x9, #8, #8
  175. ldr x10, =CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER
  176. mul x9, x10, x9
  177. #else
  178. mov x9, xzr
  179. #endif
  180. mrs x10, MPIDR_EL1
  181. ubfx x10, x10, #0, #8
  182. add x0, x10, x9
  183. ret
  184. ENDPROC(psci_get_cpu_id)
  185. .weak psci_get_cpu_id
  186. /* CPU ID input in x0, stack top output in x0*/
  187. LENTRY(psci_get_cpu_stack_top)
  188. adr x9, __secure_stack_end
  189. lsl x0, x0, #ARM_PSCI_STACK_SHIFT
  190. sub x0, x9, x0
  191. ret
  192. ENDPROC(psci_get_cpu_stack_top)
  193. unhandled_exception:
  194. b unhandled_exception /* simply dead loop */
  195. handle_sync:
  196. mov x15, x30
  197. mov x14, x0
  198. bl psci_get_cpu_id
  199. bl psci_get_cpu_stack_top
  200. mov x9, #1
  201. msr spsel, x9
  202. mov sp, x0
  203. mov x0, x14
  204. mov x30, x15
  205. mrs x9, esr_el3
  206. ubfx x9, x9, #26, #6
  207. cmp x9, #0x13
  208. b.eq handle_smc32
  209. cmp x9, #0x17
  210. b.eq handle_smc64
  211. b unhandled_exception
  212. .align 11
  213. .globl el3_exception_vectors
  214. el3_exception_vectors:
  215. b unhandled_exception /* Sync, Current EL using SP0 */
  216. .align 7
  217. b unhandled_exception /* IRQ, Current EL using SP0 */
  218. .align 7
  219. b unhandled_exception /* FIQ, Current EL using SP0 */
  220. .align 7
  221. b unhandled_exception /* SError, Current EL using SP0 */
  222. .align 7
  223. b unhandled_exception /* Sync, Current EL using SPx */
  224. .align 7
  225. b unhandled_exception /* IRQ, Current EL using SPx */
  226. .align 7
  227. b unhandled_exception /* FIQ, Current EL using SPx */
  228. .align 7
  229. b unhandled_exception /* SError, Current EL using SPx */
  230. .align 7
  231. b handle_sync /* Sync, Lower EL using AArch64 */
  232. .align 7
  233. b unhandled_exception /* IRQ, Lower EL using AArch64 */
  234. .align 7
  235. b unhandled_exception /* FIQ, Lower EL using AArch64 */
  236. .align 7
  237. b unhandled_exception /* SError, Lower EL using AArch64 */
  238. .align 7
  239. b unhandled_exception /* Sync, Lower EL using AArch32 */
  240. .align 7
  241. b unhandled_exception /* IRQ, Lower EL using AArch32 */
  242. .align 7
  243. b unhandled_exception /* FIQ, Lower EL using AArch32 */
  244. .align 7
  245. b unhandled_exception /* SError, Lower EL using AArch32 */
  246. ENTRY(psci_setup_vectors)
  247. adr x0, el3_exception_vectors
  248. msr vbar_el3, x0
  249. ret
  250. ENDPROC(psci_setup_vectors)
  251. ENTRY(psci_arch_init)
  252. ret
  253. ENDPROC(psci_arch_init)
  254. .weak psci_arch_init
  255. .popsection