plat_pm.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * Copyright (c) 2020, 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 <mt_gic_v3.h>
  14. #include <mtk_ptp3_common.h>
  15. #include <mtspmc.h>
  16. #include <plat/common/platform.h>
  17. #include <plat_dfd.h>
  18. #include <plat_mtk_lpm.h>
  19. #include <plat_params.h>
  20. #include <plat_pm.h>
  21. #include <pmic.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. /* PTP3 config */
  66. ptp3_deinit(cpu);
  67. }
  68. static void plat_cpu_pwron_common(unsigned int cpu,
  69. const psci_power_state_t *state, unsigned int req_pstate)
  70. {
  71. assert(cpu == plat_my_core_pos());
  72. plat_mt_pm_invoke_no_check(pwr_cpu_on, cpu, state);
  73. coordinate_cluster_pwron();
  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. /* PTP3 config */
  87. ptp3_init(cpu);
  88. }
  89. /*
  90. * Common MTK_platform operations to power on/off a
  91. * cluster in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
  92. */
  93. static void plat_cluster_pwrdwn_common(unsigned int cpu,
  94. const psci_power_state_t *state, unsigned int req_pstate)
  95. {
  96. assert(cpu == plat_my_core_pos());
  97. if (plat_mt_pm_invoke(pwr_cluster_dwn, cpu, state) != 0) {
  98. coordinate_cluster_pwron();
  99. /* TODO: return on fail.
  100. * Add a 'return' here before adding any code following
  101. * the if-block.
  102. */
  103. }
  104. }
  105. static void plat_cluster_pwron_common(unsigned int cpu,
  106. const psci_power_state_t *state, unsigned int req_pstate)
  107. {
  108. assert(cpu == plat_my_core_pos());
  109. if (plat_mt_pm_invoke(pwr_cluster_on, cpu, state) != 0) {
  110. /* TODO: return on fail.
  111. * Add a 'return' here before adding any code following
  112. * the if-block.
  113. */
  114. }
  115. }
  116. /*
  117. * Common MTK_platform operations to power on/off a
  118. * mcusys in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
  119. */
  120. static void plat_mcusys_pwrdwn_common(unsigned int cpu,
  121. const psci_power_state_t *state, unsigned int req_pstate)
  122. {
  123. assert(cpu == plat_my_core_pos());
  124. if (plat_mt_pm_invoke(pwr_mcusys_dwn, cpu, state) != 0) {
  125. return; /* return on fail */
  126. }
  127. mt_gic_distif_save();
  128. gic_sgi_save_all();
  129. }
  130. static void plat_mcusys_pwron_common(unsigned int cpu,
  131. const psci_power_state_t *state, unsigned int req_pstate)
  132. {
  133. assert(cpu == plat_my_core_pos());
  134. if (plat_mt_pm_invoke(pwr_mcusys_on, cpu, state) != 0) {
  135. return; /* return on fail */
  136. }
  137. mt_gic_init();
  138. mt_gic_distif_restore();
  139. gic_sgi_restore_all();
  140. dfd_resume();
  141. plat_mt_pm_invoke_no_check(pwr_mcusys_on_finished, cpu, state);
  142. }
  143. /*
  144. * plat_psci_ops implementation
  145. */
  146. static void plat_cpu_standby(plat_local_state_t cpu_state)
  147. {
  148. uint64_t scr;
  149. scr = read_scr_el3();
  150. write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
  151. isb();
  152. dsb();
  153. wfi();
  154. write_scr_el3(scr);
  155. }
  156. static int plat_power_domain_on(u_register_t mpidr)
  157. {
  158. unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
  159. unsigned int cluster = 0U;
  160. if (cpu >= PLATFORM_CORE_COUNT) {
  161. return PSCI_E_INVALID_PARAMS;
  162. }
  163. if (!spm_get_cluster_powerstate(cluster)) {
  164. spm_poweron_cluster(cluster);
  165. }
  166. /* init CPU reset arch as AARCH64 */
  167. mcucfg_init_archstate(cluster, cpu, true);
  168. mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
  169. spm_poweron_cpu(cluster, cpu);
  170. return PSCI_E_SUCCESS;
  171. }
  172. static void plat_power_domain_on_finish(const psci_power_state_t *state)
  173. {
  174. unsigned long mpidr = read_mpidr_el1();
  175. unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
  176. assert(cpu < PLATFORM_CORE_COUNT);
  177. /* Allow IRQs to wakeup this core in IDLE flow */
  178. mcucfg_enable_gic_wakeup(0U, cpu);
  179. if (IS_CLUSTER_OFF_STATE(state)) {
  180. plat_cluster_pwron_common(cpu, state, 0U);
  181. }
  182. plat_cpu_pwron_common(cpu, state, 0U);
  183. }
  184. static void plat_power_domain_off(const psci_power_state_t *state)
  185. {
  186. unsigned long mpidr = read_mpidr_el1();
  187. unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
  188. assert(cpu < PLATFORM_CORE_COUNT);
  189. plat_cpu_pwrdwn_common(cpu, state, 0U);
  190. spm_poweroff_cpu(0U, cpu);
  191. /* prevent unintended IRQs from waking up the hot-unplugged core */
  192. mcucfg_disable_gic_wakeup(0U, cpu);
  193. if (IS_CLUSTER_OFF_STATE(state)) {
  194. plat_cluster_pwrdwn_common(cpu, state, 0U);
  195. }
  196. }
  197. static void plat_power_domain_suspend(const psci_power_state_t *state)
  198. {
  199. unsigned int cpu = plat_my_core_pos();
  200. assert(cpu < PLATFORM_CORE_COUNT);
  201. plat_mt_pm_invoke_no_check(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. if (IS_MCUSYS_OFF_STATE(state)) {
  218. /* Perform the common mcusys specific operations */
  219. plat_mcusys_pwron_common(cpu, state, plat_power_state[cpu]);
  220. }
  221. if (IS_CLUSTER_OFF_STATE(state)) {
  222. /* Perform the common cluster specific operations */
  223. plat_cluster_pwron_common(cpu, state, plat_power_state[cpu]);
  224. }
  225. /* Perform the common CPU specific operations */
  226. plat_cpu_pwron_common(cpu, state, plat_power_state[cpu]);
  227. plat_mt_pm_invoke_no_check(pwr_reflect, cpu, state);
  228. }
  229. static int plat_validate_power_state(unsigned int power_state,
  230. psci_power_state_t *req_state)
  231. {
  232. unsigned int pstate = psci_get_pstate_type(power_state);
  233. unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
  234. unsigned int cpu = plat_my_core_pos();
  235. if (pstate == PSTATE_TYPE_STANDBY) {
  236. req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
  237. } else {
  238. unsigned int i;
  239. unsigned int pstate_id = psci_get_pstate_id(power_state);
  240. plat_local_state_t s = MTK_LOCAL_STATE_OFF;
  241. /* Use pstate_id to be power domain state */
  242. if (pstate_id > s) {
  243. s = (plat_local_state_t)pstate_id;
  244. }
  245. for (i = 0U; i <= aff_lvl; i++) {
  246. req_state->pwr_domain_state[i] = s;
  247. }
  248. }
  249. plat_power_state[cpu] = power_state;
  250. return PSCI_E_SUCCESS;
  251. }
  252. static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
  253. {
  254. unsigned int lv;
  255. unsigned int cpu = plat_my_core_pos();
  256. for (lv = PSCI_CPU_PWR_LVL; lv <= PLAT_MAX_PWR_LVL; lv++) {
  257. req_state->pwr_domain_state[lv] = PLAT_MAX_OFF_STATE;
  258. }
  259. plat_power_state[cpu] =
  260. psci_make_powerstate(
  261. MT_PLAT_PWR_STATE_SYSTEM_SUSPEND,
  262. PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
  263. flush_dcache_range((uintptr_t)
  264. &plat_power_state[cpu],
  265. sizeof(plat_power_state[cpu]));
  266. }
  267. static void __dead2 plat_mtk_system_off(void)
  268. {
  269. INFO("MTK System Off\n");
  270. rtc_power_off_sequence();
  271. pmic_power_off();
  272. wfi();
  273. ERROR("MTK System Off: operation not handled.\n");
  274. panic();
  275. }
  276. static void __dead2 plat_mtk_system_reset(void)
  277. {
  278. struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset();
  279. INFO("MTK System Reset\n");
  280. gpio_set_value(gpio_reset->index, gpio_reset->polarity);
  281. wfi();
  282. ERROR("MTK System Reset: operation not handled.\n");
  283. panic();
  284. }
  285. static const plat_psci_ops_t plat_psci_ops = {
  286. .system_reset = plat_mtk_system_reset,
  287. .cpu_standby = plat_cpu_standby,
  288. .pwr_domain_on = plat_power_domain_on,
  289. .pwr_domain_on_finish = plat_power_domain_on_finish,
  290. .pwr_domain_off = plat_power_domain_off,
  291. .pwr_domain_suspend = plat_power_domain_suspend,
  292. .pwr_domain_suspend_finish = plat_power_domain_suspend_finish,
  293. .system_off = plat_mtk_system_off,
  294. .validate_power_state = plat_validate_power_state,
  295. .get_sys_suspend_power_state = plat_get_sys_suspend_power_state
  296. };
  297. int plat_setup_psci_ops(uintptr_t sec_entrypoint,
  298. const plat_psci_ops_t **psci_ops)
  299. {
  300. *psci_ops = &plat_psci_ops;
  301. secure_entrypoint = sec_entrypoint;
  302. /*
  303. * init the warm reset config for boot CPU
  304. * reset arch as AARCH64
  305. * reset addr as function bl31_warm_entrypoint()
  306. */
  307. mcucfg_init_archstate(0U, 0U, true);
  308. mcucfg_set_bootaddr(0U, 0U, secure_entrypoint);
  309. spmc_init();
  310. plat_mt_pm = mt_plat_cpu_pm_init();
  311. return 0;
  312. }