plat_pm.c 10.0 KB

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