imx93_psci.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright 2022-2023 NXP
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <stdbool.h>
  7. #include <arch.h>
  8. #include <arch_helpers.h>
  9. #include <common/debug.h>
  10. #include <drivers/delay_timer.h>
  11. #include <lib/mmio.h>
  12. #include <lib/psci/psci.h>
  13. #include <plat_imx8.h>
  14. #include <pwr_ctrl.h>
  15. #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
  16. #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
  17. #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
  18. /* platform secure warm boot entry */
  19. static uintptr_t secure_entrypoint;
  20. static bool boot_stage = true;
  21. int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
  22. {
  23. /* The non-secure entrypoint should be in RAM space */
  24. if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET) {
  25. return PSCI_E_INVALID_PARAMS;
  26. }
  27. return PSCI_E_SUCCESS;
  28. }
  29. int imx_validate_power_state(unsigned int power_state,
  30. psci_power_state_t *req_state)
  31. {
  32. int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
  33. int pwr_type = psci_get_pstate_type(power_state);
  34. int state_id = psci_get_pstate_id(power_state);
  35. if (pwr_lvl > PLAT_MAX_PWR_LVL) {
  36. return PSCI_E_INVALID_PARAMS;
  37. }
  38. if (pwr_type == PSTATE_TYPE_STANDBY) {
  39. CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
  40. CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
  41. }
  42. if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
  43. CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
  44. CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
  45. }
  46. return PSCI_E_SUCCESS;
  47. }
  48. void imx_set_cpu_boot_entry(unsigned int core_id, uint64_t boot_entry)
  49. {
  50. /* set the cpu core reset entry: BLK_CTRL_S */
  51. mmio_write_32(BLK_CTRL_S_BASE + CA55_RVBADDR0_L + core_id * 8, boot_entry >> 2);
  52. }
  53. int imx_pwr_domain_on(u_register_t mpidr)
  54. {
  55. unsigned int core_id;
  56. core_id = MPIDR_AFFLVL1_VAL(mpidr);
  57. imx_set_cpu_boot_entry(core_id, secure_entrypoint);
  58. /*
  59. * When the core is first time boot up, the core is already ON after SoC POR,
  60. * So 'SW_WAKEUP' can not work, so need to toggle core's reset then release
  61. * the core from cpu_wait.
  62. */
  63. if (boot_stage) {
  64. /* assert CPU core SW reset */
  65. mmio_clrbits_32(SRC_SLICE(SRC_A55C0 + core_id) + 0x24, BIT(2) | BIT(0));
  66. /* deassert CPU core SW reset */
  67. mmio_setbits_32(SRC_SLICE(SRC_A55C0 + core_id) + 0x24, BIT(2) | BIT(0));
  68. /* release the cpuwait to kick the cpu */
  69. mmio_clrbits_32(BLK_CTRL_S_BASE + CA55_CPUWAIT, BIT(core_id));
  70. } else {
  71. /* assert the CMC MISC SW WAKEUP BIT to kick the offline core */
  72. gpc_assert_sw_wakeup(CPU_A55C0 + core_id);
  73. }
  74. return PSCI_E_SUCCESS;
  75. }
  76. void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
  77. {
  78. uint64_t mpidr = read_mpidr_el1();
  79. unsigned int core_id = MPIDR_AFFLVL1_VAL(mpidr);
  80. plat_gic_pcpu_init();
  81. plat_gic_cpuif_enable();
  82. /* below config is ok both for boot & hotplug */
  83. /* clear the CPU power mode */
  84. gpc_set_cpu_mode(CPU_A55C0 + core_id, CM_MODE_RUN);
  85. /* clear the SW wakeup */
  86. gpc_deassert_sw_wakeup(CPU_A55C0 + core_id);
  87. /* switch to GIC wakeup source */
  88. gpc_select_wakeup_gic(CPU_A55C0 + core_id);
  89. if (boot_stage) {
  90. /* SRC config */
  91. /* config the MEM LPM */
  92. src_mem_lpm_en(SRC_A55P0_MEM + core_id, MEM_OFF);
  93. /* LPM config to only ON in run mode to its domain */
  94. src_mix_set_lpm(SRC_A55C0 + core_id, core_id, CM_MODE_WAIT);
  95. /* white list config, only enable its own domain */
  96. src_authen_config(SRC_A55C0 + core_id, 1 << core_id, 0x1);
  97. boot_stage = false;
  98. }
  99. }
  100. void imx_pwr_domain_off(const psci_power_state_t *target_state)
  101. {
  102. uint64_t mpidr = read_mpidr_el1();
  103. unsigned int core_id = MPIDR_AFFLVL1_VAL(mpidr);
  104. unsigned int i;
  105. plat_gic_cpuif_disable();
  106. write_clusterpwrdn(DSU_CLUSTER_PWR_OFF);
  107. /*
  108. * mask all the GPC IRQ wakeup to make sure no IRQ can wakeup this core
  109. * as we need to use SW_WAKEUP for hotplug purpose
  110. */
  111. for (i = 0U; i < IMR_NUM; i++) {
  112. gpc_set_irq_mask(CPU_A55C0 + core_id, i, 0xffffffff);
  113. }
  114. /* switch to GPC wakeup source */
  115. gpc_select_wakeup_raw_irq(CPU_A55C0 + core_id);
  116. /* config the target mode to suspend */
  117. gpc_set_cpu_mode(CPU_A55C0 + core_id, CM_MODE_SUSPEND);
  118. }
  119. void imx_pwr_domain_suspend(const psci_power_state_t *target_state)
  120. {
  121. uint64_t mpidr = read_mpidr_el1();
  122. unsigned int core_id = MPIDR_AFFLVL1_VAL(mpidr);
  123. /* do cpu level config */
  124. if (is_local_state_off(CORE_PWR_STATE(target_state))) {
  125. plat_gic_cpuif_disable();
  126. imx_set_cpu_boot_entry(core_id, secure_entrypoint);
  127. /* config the target mode to WAIT */
  128. gpc_set_cpu_mode(CPU_A55C0 + core_id, CM_MODE_WAIT);
  129. }
  130. /* do cluster level config */
  131. if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) {
  132. /* config the A55 cluster target mode to WAIT */
  133. gpc_set_cpu_mode(CPU_A55_PLAT, CM_MODE_WAIT);
  134. /* config DSU for cluster power down with L3 MEM RET */
  135. if (is_local_state_retn(CLUSTER_PWR_STATE(target_state))) {
  136. write_clusterpwrdn(DSU_CLUSTER_PWR_OFF | BIT(1));
  137. }
  138. }
  139. }
  140. void imx_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
  141. {
  142. uint64_t mpidr = read_mpidr_el1();
  143. unsigned int core_id = MPIDR_AFFLVL1_VAL(mpidr);
  144. /* cluster level */
  145. if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) {
  146. /* set the cluster's target mode to RUN */
  147. gpc_set_cpu_mode(CPU_A55_PLAT, CM_MODE_RUN);
  148. }
  149. /* do core level */
  150. if (is_local_state_off(CORE_PWR_STATE(target_state))) {
  151. /* set A55 CORE's power mode to RUN */
  152. gpc_set_cpu_mode(CPU_A55C0 + core_id, CM_MODE_RUN);
  153. plat_gic_cpuif_enable();
  154. }
  155. }
  156. void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
  157. {
  158. unsigned int i;
  159. for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) {
  160. req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
  161. }
  162. SYSTEM_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
  163. CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
  164. }
  165. void __dead2 imx_system_reset(void)
  166. {
  167. mmio_write_32(WDOG3_BASE + WDOG_CNT, 0xd928c520);
  168. while ((mmio_read_32(WDOG3_BASE + WDOG_CS) & WDOG_CS_ULK) == 0U) {
  169. ;
  170. }
  171. mmio_write_32(WDOG3_BASE + WDOG_TOVAL, 0x10);
  172. mmio_write_32(WDOG3_BASE + WDOG_CS, 0x21e3);
  173. while (1) {
  174. wfi();
  175. }
  176. }
  177. void __dead2 imx_system_off(void)
  178. {
  179. mmio_setbits_32(BBNSM_BASE + BBNSM_CTRL, BBNSM_DP_EN | BBNSM_TOSP);
  180. while (1) {
  181. wfi();
  182. }
  183. }
  184. static const plat_psci_ops_t imx_plat_psci_ops = {
  185. .validate_ns_entrypoint = imx_validate_ns_entrypoint,
  186. .validate_power_state = imx_validate_power_state,
  187. .pwr_domain_on = imx_pwr_domain_on,
  188. .pwr_domain_off = imx_pwr_domain_off,
  189. .pwr_domain_on_finish = imx_pwr_domain_on_finish,
  190. .pwr_domain_suspend = imx_pwr_domain_suspend,
  191. .pwr_domain_suspend_finish = imx_pwr_domain_suspend_finish,
  192. .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
  193. .system_reset = imx_system_reset,
  194. .system_off = imx_system_off,
  195. };
  196. /* export the platform specific psci ops */
  197. int plat_setup_psci_ops(uintptr_t sec_entrypoint,
  198. const plat_psci_ops_t **psci_ops)
  199. {
  200. /* sec_entrypoint is used for warm reset */
  201. secure_entrypoint = sec_entrypoint;
  202. imx_set_cpu_boot_entry(0, sec_entrypoint);
  203. pwr_sys_init();
  204. *psci_ops = &imx_plat_psci_ops;
  205. return 0;
  206. }