plat_pm.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. * Copyright (c) 2021-2022, MediaTek Inc. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. /* common headers */
  7. #include <assert.h>
  8. #include <arch_helpers.h>
  9. #include <common/debug.h>
  10. #include <drivers/gpio.h>
  11. #include <lib/psci/psci.h>
  12. /* platform specific headers */
  13. #include <plat/common/platform.h>
  14. #include <mt_gic_v3.h>
  15. #include <mtspmc.h>
  16. #include <plat_dfd.h>
  17. #include <plat_mtk_lpm.h>
  18. #include <plat_params.h>
  19. #include <plat_pm.h>
  20. #include <pmic.h>
  21. #include <ptp3_common.h>
  22. #include <rtc.h>
  23. /*
  24. * Cluster state request:
  25. * [0] : The CPU requires cluster power down
  26. * [1] : The CPU requires cluster power on
  27. */
  28. #define coordinate_cluster(onoff) write_clusterpwrdn_el1(onoff)
  29. #define coordinate_cluster_pwron() coordinate_cluster(1)
  30. #define coordinate_cluster_pwroff() coordinate_cluster(0)
  31. /* platform secure entry point */
  32. static uintptr_t secure_entrypoint;
  33. /* per-CPU power state */
  34. static unsigned int plat_power_state[PLATFORM_CORE_COUNT];
  35. /* platform CPU power domain - ops */
  36. static const struct mt_lpm_tz *plat_mt_pm;
  37. #define plat_mt_pm_invoke(_name, _cpu, _state) ({ \
  38. int ret = -1; \
  39. if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \
  40. ret = plat_mt_pm->_name(_cpu, _state); \
  41. } \
  42. ret; })
  43. #define plat_mt_pm_invoke_no_check(_name, _cpu, _state) ({ \
  44. if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \
  45. (void) plat_mt_pm->_name(_cpu, _state); \
  46. } \
  47. })
  48. /*
  49. * Common MTK_platform operations to power on/off a
  50. * CPU in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
  51. */
  52. static void plat_cpu_pwrdwn_common(unsigned int cpu,
  53. const psci_power_state_t *state, unsigned int req_pstate)
  54. {
  55. assert(cpu == plat_my_core_pos());
  56. plat_mt_pm_invoke_no_check(pwr_cpu_dwn, cpu, state);
  57. if ((psci_get_pstate_pwrlvl(req_pstate) >= MTK_AFFLVL_CLUSTER) ||
  58. (req_pstate == 0U)) { /* hotplug off */
  59. coordinate_cluster_pwroff();
  60. }
  61. /* Prevent interrupts from spuriously waking up this CPU */
  62. mt_gic_rdistif_save();
  63. gicv3_cpuif_disable(cpu);
  64. gicv3_rdistif_off(cpu);
  65. }
  66. static void plat_cpu_pwron_common(unsigned int cpu,
  67. const psci_power_state_t *state, unsigned int req_pstate)
  68. {
  69. assert(cpu == plat_my_core_pos());
  70. plat_mt_pm_invoke_no_check(pwr_cpu_on, cpu, state);
  71. coordinate_cluster_pwron();
  72. /* PTP3 config */
  73. ptp3_core_init(cpu);
  74. /*
  75. * If mcusys does power down before then restore
  76. * all CPUs' GIC Redistributors
  77. */
  78. if (IS_MCUSYS_OFF_STATE(state)) {
  79. mt_gic_rdistif_restore_all();
  80. } else {
  81. gicv3_rdistif_on(cpu);
  82. gicv3_cpuif_enable(cpu);
  83. mt_gic_rdistif_init();
  84. mt_gic_rdistif_restore();
  85. }
  86. }
  87. /*
  88. * Common MTK_platform operations to power on/off a
  89. * cluster in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
  90. */
  91. static void plat_cluster_pwrdwn_common(unsigned int cpu,
  92. const psci_power_state_t *state, unsigned int req_pstate)
  93. {
  94. assert(cpu == plat_my_core_pos());
  95. if (plat_mt_pm_invoke(pwr_cluster_dwn, cpu, state) != 0) {
  96. coordinate_cluster_pwron();
  97. /* TODO: return on fail.
  98. * Add a 'return' here before adding any code following
  99. * the if-block.
  100. */
  101. }
  102. }
  103. static void plat_cluster_pwron_common(unsigned int cpu,
  104. const psci_power_state_t *state, unsigned int req_pstate)
  105. {
  106. assert(cpu == plat_my_core_pos());
  107. if (plat_mt_pm_invoke(pwr_cluster_on, cpu, state) != 0) {
  108. /* TODO: return on fail.
  109. * Add a 'return' here before adding any code following
  110. * the if-block.
  111. */
  112. }
  113. }
  114. /*
  115. * Common MTK_platform operations to power on/off a
  116. * mcusys in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
  117. */
  118. static void plat_mcusys_pwrdwn_common(unsigned int cpu,
  119. const psci_power_state_t *state, unsigned int req_pstate)
  120. {
  121. assert(cpu == plat_my_core_pos());
  122. if (plat_mt_pm_invoke(pwr_mcusys_dwn, cpu, state) != 0) {
  123. return; /* return on fail */
  124. }
  125. mt_gic_distif_save();
  126. gic_sgi_save_all();
  127. }
  128. static void plat_mcusys_pwron_common(unsigned int cpu,
  129. const psci_power_state_t *state, unsigned int req_pstate)
  130. {
  131. assert(cpu == plat_my_core_pos());
  132. if (plat_mt_pm_invoke(pwr_mcusys_on, cpu, state) != 0) {
  133. return; /* return on fail */
  134. }
  135. mt_gic_init();
  136. mt_gic_distif_restore();
  137. gic_sgi_restore_all();
  138. dfd_resume();
  139. plat_mt_pm_invoke_no_check(pwr_mcusys_on_finished, cpu, state);
  140. }
  141. /*
  142. * plat_psci_ops implementation
  143. */
  144. static void plat_cpu_standby(plat_local_state_t cpu_state)
  145. {
  146. uint64_t scr;
  147. scr = read_scr_el3();
  148. write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
  149. isb();
  150. dsb();
  151. wfi();
  152. write_scr_el3(scr);
  153. }
  154. static int plat_power_domain_on(u_register_t mpidr)
  155. {
  156. unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
  157. unsigned int cluster = 0U;
  158. if (cpu >= PLATFORM_CORE_COUNT) {
  159. return PSCI_E_INVALID_PARAMS;
  160. }
  161. if (!spm_get_cluster_powerstate(cluster)) {
  162. spm_poweron_cluster(cluster);
  163. }
  164. /* init CPU reset arch as AARCH64 */
  165. mcucfg_init_archstate(cluster, cpu, true);
  166. mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
  167. spm_poweron_cpu(cluster, cpu);
  168. return PSCI_E_SUCCESS;
  169. }
  170. static void plat_power_domain_on_finish(const psci_power_state_t *state)
  171. {
  172. unsigned long mpidr = read_mpidr_el1();
  173. unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
  174. assert(cpu < PLATFORM_CORE_COUNT);
  175. /* Allow IRQs to wakeup this core in IDLE flow */
  176. mcucfg_enable_gic_wakeup(0U, cpu);
  177. if (IS_CLUSTER_OFF_STATE(state)) {
  178. plat_cluster_pwron_common(cpu, state, 0U);
  179. }
  180. plat_cpu_pwron_common(cpu, state, 0U);
  181. }
  182. static void plat_power_domain_off(const psci_power_state_t *state)
  183. {
  184. unsigned long mpidr = read_mpidr_el1();
  185. unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
  186. assert(cpu < PLATFORM_CORE_COUNT);
  187. plat_cpu_pwrdwn_common(cpu, state, 0U);
  188. spm_poweroff_cpu(0U, cpu);
  189. /* prevent unintended IRQs from waking up the hot-unplugged core */
  190. mcucfg_disable_gic_wakeup(0U, cpu);
  191. if (IS_CLUSTER_OFF_STATE(state)) {
  192. plat_cluster_pwrdwn_common(cpu, state, 0U);
  193. }
  194. }
  195. static void plat_power_domain_suspend(const psci_power_state_t *state)
  196. {
  197. unsigned int cpu = plat_my_core_pos();
  198. assert(cpu < PLATFORM_CORE_COUNT);
  199. plat_mt_pm_invoke_no_check(pwr_prompt, cpu, state);
  200. /* Perform the common CPU specific operations */
  201. plat_cpu_pwrdwn_common(cpu, state, plat_power_state[cpu]);
  202. if (IS_CLUSTER_OFF_STATE(state)) {
  203. /* Perform the common cluster specific operations */
  204. plat_cluster_pwrdwn_common(cpu, state, plat_power_state[cpu]);
  205. }
  206. if (IS_MCUSYS_OFF_STATE(state)) {
  207. /* Perform the common mcusys specific operations */
  208. plat_mcusys_pwrdwn_common(cpu, state, plat_power_state[cpu]);
  209. }
  210. }
  211. static void plat_power_domain_suspend_finish(const psci_power_state_t *state)
  212. {
  213. unsigned int cpu = plat_my_core_pos();
  214. assert(cpu < PLATFORM_CORE_COUNT);
  215. if (IS_MCUSYS_OFF_STATE(state)) {
  216. /* Perform the common mcusys specific operations */
  217. plat_mcusys_pwron_common(cpu, state, plat_power_state[cpu]);
  218. }
  219. if (IS_CLUSTER_OFF_STATE(state)) {
  220. /* Perform the common cluster specific operations */
  221. plat_cluster_pwron_common(cpu, state, plat_power_state[cpu]);
  222. }
  223. /* Perform the common CPU specific operations */
  224. plat_cpu_pwron_common(cpu, state, plat_power_state[cpu]);
  225. plat_mt_pm_invoke_no_check(pwr_reflect, cpu, state);
  226. }
  227. static int plat_validate_power_state(unsigned int power_state,
  228. psci_power_state_t *req_state)
  229. {
  230. unsigned int pstate = psci_get_pstate_type(power_state);
  231. unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
  232. unsigned int cpu = plat_my_core_pos();
  233. if (aff_lvl > PLAT_MAX_PWR_LVL) {
  234. return PSCI_E_INVALID_PARAMS;
  235. }
  236. if (pstate == PSTATE_TYPE_STANDBY) {
  237. req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
  238. } else {
  239. unsigned int i;
  240. unsigned int pstate_id = psci_get_pstate_id(power_state);
  241. plat_local_state_t s = MTK_LOCAL_STATE_OFF;
  242. /* Use pstate_id to be power domain state */
  243. if (pstate_id > s) {
  244. s = (plat_local_state_t)pstate_id;
  245. }
  246. for (i = 0U; i <= aff_lvl; i++) {
  247. req_state->pwr_domain_state[i] = s;
  248. }
  249. }
  250. plat_power_state[cpu] = power_state;
  251. return PSCI_E_SUCCESS;
  252. }
  253. static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
  254. {
  255. unsigned int lv;
  256. unsigned int cpu = plat_my_core_pos();
  257. for (lv = PSCI_CPU_PWR_LVL; lv <= PLAT_MAX_PWR_LVL; lv++) {
  258. req_state->pwr_domain_state[lv] = PLAT_MAX_OFF_STATE;
  259. }
  260. plat_power_state[cpu] =
  261. psci_make_powerstate(
  262. MT_PLAT_PWR_STATE_SYSTEM_SUSPEND,
  263. PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
  264. flush_dcache_range((uintptr_t)
  265. &plat_power_state[cpu],
  266. sizeof(plat_power_state[cpu]));
  267. }
  268. /*******************************************************************************
  269. * MTK handlers to shutdown/reboot the system
  270. ******************************************************************************/
  271. static void __dead2 plat_mtk_system_reset(void)
  272. {
  273. struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset();
  274. INFO("MTK System Reset\n");
  275. gpio_set_value(gpio_reset->index, gpio_reset->polarity);
  276. wfi();
  277. ERROR("MTK System Reset: operation not handled.\n");
  278. panic();
  279. }
  280. static void __dead2 plat_mtk_system_off(void)
  281. {
  282. INFO("MTK System Off\n");
  283. rtc_power_off_sequence();
  284. pmic_power_off();
  285. wfi();
  286. ERROR("MTK System Off: operation not handled.\n");
  287. panic();
  288. }
  289. static const plat_psci_ops_t plat_psci_ops = {
  290. .system_reset = plat_mtk_system_reset,
  291. .system_off = plat_mtk_system_off,
  292. .cpu_standby = plat_cpu_standby,
  293. .pwr_domain_on = plat_power_domain_on,
  294. .pwr_domain_on_finish = plat_power_domain_on_finish,
  295. .pwr_domain_off = plat_power_domain_off,
  296. .pwr_domain_suspend = plat_power_domain_suspend,
  297. .pwr_domain_suspend_finish = plat_power_domain_suspend_finish,
  298. .validate_power_state = plat_validate_power_state,
  299. .get_sys_suspend_power_state = plat_get_sys_suspend_power_state
  300. };
  301. int plat_setup_psci_ops(uintptr_t sec_entrypoint,
  302. const plat_psci_ops_t **psci_ops)
  303. {
  304. *psci_ops = &plat_psci_ops;
  305. secure_entrypoint = sec_entrypoint;
  306. /*
  307. * init the warm reset config for boot CPU
  308. * reset arch as AARCH64
  309. * reset addr as function bl31_warm_entrypoint()
  310. */
  311. mcucfg_init_archstate(0U, 0U, true);
  312. mcucfg_set_bootaddr(0U, 0U, secure_entrypoint);
  313. spmc_init();
  314. plat_mt_pm = mt_plat_cpu_pm_init();
  315. return 0;
  316. }