psci_suspend.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /*
  2. * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <stddef.h>
  8. #include <arch.h>
  9. #include <arch_helpers.h>
  10. #include <common/bl_common.h>
  11. #include <common/debug.h>
  12. #include <context.h>
  13. #include <lib/el3_runtime/context_mgmt.h>
  14. #include <lib/el3_runtime/cpu_data.h>
  15. #include <lib/el3_runtime/pubsub_events.h>
  16. #include <lib/pmf/pmf.h>
  17. #include <lib/runtime_instr.h>
  18. #include <plat/common/platform.h>
  19. #include "psci_private.h"
  20. /*******************************************************************************
  21. * This function does generic and platform specific operations after a wake-up
  22. * from standby/retention states at multiple power levels.
  23. ******************************************************************************/
  24. static void psci_suspend_to_standby_finisher(unsigned int cpu_idx,
  25. unsigned int end_pwrlvl)
  26. {
  27. unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
  28. psci_power_state_t state_info;
  29. /* Get the parent nodes */
  30. psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes);
  31. psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
  32. /*
  33. * Find out which retention states this CPU has exited from until the
  34. * 'end_pwrlvl'. The exit retention state could be deeper than the entry
  35. * state as a result of state coordination amongst other CPUs post wfi.
  36. */
  37. psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
  38. #if ENABLE_PSCI_STAT
  39. plat_psci_stat_accounting_stop(&state_info);
  40. psci_stats_update_pwr_up(end_pwrlvl, &state_info);
  41. #endif
  42. /*
  43. * Plat. management: Allow the platform to do operations
  44. * on waking up from retention.
  45. */
  46. psci_plat_pm_ops->pwr_domain_suspend_finish(&state_info);
  47. /*
  48. * Set the requested and target state of this CPU and all the higher
  49. * power domain levels for this CPU to run.
  50. */
  51. psci_set_pwr_domains_to_run(end_pwrlvl);
  52. psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
  53. }
  54. /*******************************************************************************
  55. * This function does generic and platform specific suspend to power down
  56. * operations.
  57. ******************************************************************************/
  58. static void psci_suspend_to_pwrdown_start(unsigned int end_pwrlvl,
  59. const entry_point_info_t *ep,
  60. const psci_power_state_t *state_info)
  61. {
  62. unsigned int max_off_lvl = psci_find_max_off_lvl(state_info);
  63. PUBLISH_EVENT(psci_suspend_pwrdown_start);
  64. #if PSCI_OS_INIT_MODE
  65. #ifdef PLAT_MAX_CPU_SUSPEND_PWR_LVL
  66. end_pwrlvl = PLAT_MAX_CPU_SUSPEND_PWR_LVL;
  67. #else
  68. end_pwrlvl = PLAT_MAX_PWR_LVL;
  69. #endif
  70. #endif
  71. /* Save PSCI target power level for the suspend finisher handler */
  72. psci_set_suspend_pwrlvl(end_pwrlvl);
  73. /*
  74. * Flush the target power level as it might be accessed on power up with
  75. * Data cache disabled.
  76. */
  77. psci_flush_cpu_data(psci_svc_cpu_data.target_pwrlvl);
  78. /*
  79. * Call the cpu suspend handler registered by the Secure Payload
  80. * Dispatcher to let it do any book-keeping. If the handler encounters an
  81. * error, it's expected to assert within
  82. */
  83. if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_suspend != NULL))
  84. psci_spd_pm->svc_suspend(max_off_lvl);
  85. #if !HW_ASSISTED_COHERENCY
  86. /*
  87. * Plat. management: Allow the platform to perform any early
  88. * actions required to power down the CPU. This might be useful for
  89. * HW_ASSISTED_COHERENCY = 0 platforms that can safely perform these
  90. * actions with data caches enabled.
  91. */
  92. if (psci_plat_pm_ops->pwr_domain_suspend_pwrdown_early != NULL)
  93. psci_plat_pm_ops->pwr_domain_suspend_pwrdown_early(state_info);
  94. #endif
  95. /*
  96. * Store the re-entry information for the non-secure world.
  97. */
  98. cm_init_my_context(ep);
  99. #if ENABLE_RUNTIME_INSTRUMENTATION
  100. /*
  101. * Flush cache line so that even if CPU power down happens
  102. * the timestamp update is reflected in memory.
  103. */
  104. PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
  105. RT_INSTR_ENTER_CFLUSH,
  106. PMF_CACHE_MAINT);
  107. #endif
  108. /*
  109. * Arch. management. Initiate power down sequence.
  110. * TODO : Introduce a mechanism to query the cache level to flush
  111. * and the cpu-ops power down to perform from the platform.
  112. */
  113. psci_pwrdown_cpu(max_off_lvl);
  114. #if ENABLE_RUNTIME_INSTRUMENTATION
  115. PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
  116. RT_INSTR_EXIT_CFLUSH,
  117. PMF_NO_CACHE_MAINT);
  118. #endif
  119. }
  120. /*******************************************************************************
  121. * Top level handler which is called when a cpu wants to suspend its execution.
  122. * It is assumed that along with suspending the cpu power domain, power domains
  123. * at higher levels until the target power level will be suspended as well. It
  124. * coordinates with the platform to negotiate the target state for each of
  125. * the power domain level till the target power domain level. It then performs
  126. * generic, architectural, platform setup and state management required to
  127. * suspend that power domain level and power domain levels below it.
  128. * e.g. For a cpu that's to be suspended, it could mean programming the
  129. * power controller whereas for a cluster that's to be suspended, it will call
  130. * the platform specific code which will disable coherency at the interconnect
  131. * level if the cpu is the last in the cluster and also the program the power
  132. * controller.
  133. *
  134. * All the required parameter checks are performed at the beginning and after
  135. * the state transition has been done, no further error is expected and it is
  136. * not possible to undo any of the actions taken beyond that point.
  137. ******************************************************************************/
  138. int psci_cpu_suspend_start(const entry_point_info_t *ep,
  139. unsigned int end_pwrlvl,
  140. psci_power_state_t *state_info,
  141. unsigned int is_power_down_state)
  142. {
  143. int rc = PSCI_E_SUCCESS;
  144. bool skip_wfi = false;
  145. unsigned int idx = plat_my_core_pos();
  146. unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
  147. /*
  148. * This function must only be called on platforms where the
  149. * CPU_SUSPEND platform hooks have been implemented.
  150. */
  151. assert((psci_plat_pm_ops->pwr_domain_suspend != NULL) &&
  152. (psci_plat_pm_ops->pwr_domain_suspend_finish != NULL));
  153. /* Get the parent nodes */
  154. psci_get_parent_pwr_domain_nodes(idx, end_pwrlvl, parent_nodes);
  155. /*
  156. * This function acquires the lock corresponding to each power
  157. * level so that by the time all locks are taken, the system topology
  158. * is snapshot and state management can be done safely.
  159. */
  160. psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
  161. /*
  162. * We check if there are any pending interrupts after the delay
  163. * introduced by lock contention to increase the chances of early
  164. * detection that a wake-up interrupt has fired.
  165. */
  166. if (read_isr_el1() != 0U) {
  167. skip_wfi = true;
  168. goto exit;
  169. }
  170. #if PSCI_OS_INIT_MODE
  171. if (psci_suspend_mode == OS_INIT) {
  172. /*
  173. * This function validates the requested state info for
  174. * OS-initiated mode.
  175. */
  176. rc = psci_validate_state_coordination(end_pwrlvl, state_info);
  177. if (rc != PSCI_E_SUCCESS) {
  178. skip_wfi = true;
  179. goto exit;
  180. }
  181. } else {
  182. #endif
  183. /*
  184. * This function is passed the requested state info and
  185. * it returns the negotiated state info for each power level upto
  186. * the end level specified.
  187. */
  188. psci_do_state_coordination(end_pwrlvl, state_info);
  189. #if PSCI_OS_INIT_MODE
  190. }
  191. #endif
  192. #if PSCI_OS_INIT_MODE
  193. if (psci_plat_pm_ops->pwr_domain_validate_suspend != NULL) {
  194. rc = psci_plat_pm_ops->pwr_domain_validate_suspend(state_info);
  195. if (rc != PSCI_E_SUCCESS) {
  196. skip_wfi = true;
  197. goto exit;
  198. }
  199. }
  200. #endif
  201. /* Update the target state in the power domain nodes */
  202. psci_set_target_local_pwr_states(end_pwrlvl, state_info);
  203. #if ENABLE_PSCI_STAT
  204. /* Update the last cpu for each level till end_pwrlvl */
  205. psci_stats_update_pwr_down(end_pwrlvl, state_info);
  206. #endif
  207. if (is_power_down_state != 0U)
  208. psci_suspend_to_pwrdown_start(end_pwrlvl, ep, state_info);
  209. /*
  210. * Plat. management: Allow the platform to perform the
  211. * necessary actions to turn off this cpu e.g. set the
  212. * platform defined mailbox with the psci entrypoint,
  213. * program the power controller etc.
  214. */
  215. psci_plat_pm_ops->pwr_domain_suspend(state_info);
  216. #if ENABLE_PSCI_STAT
  217. plat_psci_stat_accounting_start(state_info);
  218. #endif
  219. exit:
  220. /*
  221. * Release the locks corresponding to each power level in the
  222. * reverse order to which they were acquired.
  223. */
  224. psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
  225. if (skip_wfi) {
  226. return rc;
  227. }
  228. if (is_power_down_state != 0U) {
  229. #if ENABLE_RUNTIME_INSTRUMENTATION
  230. /*
  231. * Update the timestamp with cache off. We assume this
  232. * timestamp can only be read from the current CPU and the
  233. * timestamp cache line will be flushed before return to
  234. * normal world on wakeup.
  235. */
  236. PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
  237. RT_INSTR_ENTER_HW_LOW_PWR,
  238. PMF_NO_CACHE_MAINT);
  239. #endif
  240. /* The function calls below must not return */
  241. if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL)
  242. psci_plat_pm_ops->pwr_domain_pwr_down_wfi(state_info);
  243. else
  244. psci_power_down_wfi();
  245. }
  246. #if ENABLE_RUNTIME_INSTRUMENTATION
  247. PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
  248. RT_INSTR_ENTER_HW_LOW_PWR,
  249. PMF_NO_CACHE_MAINT);
  250. #endif
  251. /*
  252. * We will reach here if only retention/standby states have been
  253. * requested at multiple power levels. This means that the cpu
  254. * context will be preserved.
  255. */
  256. wfi();
  257. #if ENABLE_RUNTIME_INSTRUMENTATION
  258. PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
  259. RT_INSTR_EXIT_HW_LOW_PWR,
  260. PMF_NO_CACHE_MAINT);
  261. #endif
  262. /*
  263. * After we wake up from context retaining suspend, call the
  264. * context retaining suspend finisher.
  265. */
  266. psci_suspend_to_standby_finisher(idx, end_pwrlvl);
  267. return rc;
  268. }
  269. /*******************************************************************************
  270. * The following functions finish an earlier suspend request. They
  271. * are called by the common finisher routine in psci_common.c. The `state_info`
  272. * is the psci_power_state from which this CPU has woken up from.
  273. ******************************************************************************/
  274. void psci_cpu_suspend_finish(unsigned int cpu_idx, const psci_power_state_t *state_info)
  275. {
  276. unsigned int counter_freq;
  277. unsigned int max_off_lvl;
  278. /* Ensure we have been woken up from a suspended state */
  279. assert((psci_get_aff_info_state() == AFF_STATE_ON) &&
  280. (is_local_state_off(
  281. state_info->pwr_domain_state[PSCI_CPU_PWR_LVL]) != 0));
  282. /*
  283. * Plat. management: Perform the platform specific actions
  284. * before we change the state of the cpu e.g. enabling the
  285. * gic or zeroing the mailbox register. If anything goes
  286. * wrong then assert as there is no way to recover from this
  287. * situation.
  288. */
  289. psci_plat_pm_ops->pwr_domain_suspend_finish(state_info);
  290. #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
  291. /* Arch. management: Enable the data cache, stack memory maintenance. */
  292. psci_do_pwrup_cache_maintenance();
  293. #endif
  294. /* Re-init the cntfrq_el0 register */
  295. counter_freq = plat_get_syscnt_freq2();
  296. write_cntfrq_el0(counter_freq);
  297. #if ENABLE_PAUTH
  298. /* Store APIAKey_EL1 key */
  299. set_cpu_data(apiakey[0], read_apiakeylo_el1());
  300. set_cpu_data(apiakey[1], read_apiakeyhi_el1());
  301. #endif /* ENABLE_PAUTH */
  302. /*
  303. * Call the cpu suspend finish handler registered by the Secure Payload
  304. * Dispatcher to let it do any bookeeping. If the handler encounters an
  305. * error, it's expected to assert within
  306. */
  307. if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_suspend_finish != NULL)) {
  308. max_off_lvl = psci_find_max_off_lvl(state_info);
  309. assert(max_off_lvl != PSCI_INVALID_PWR_LVL);
  310. psci_spd_pm->svc_suspend_finish(max_off_lvl);
  311. }
  312. /* Invalidate the suspend level for the cpu */
  313. psci_set_suspend_pwrlvl(PSCI_INVALID_PWR_LVL);
  314. PUBLISH_EVENT(psci_suspend_pwrdown_finish);
  315. }