imx8mq_psci.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. * Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
  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 <dram.h>
  14. #include <gpc.h>
  15. #include <imx8m_psci.h>
  16. #include <plat_imx8.h>
  17. int imx_validate_power_state(unsigned int power_state,
  18. psci_power_state_t *req_state)
  19. {
  20. int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
  21. int pwr_type = psci_get_pstate_type(power_state);
  22. int state_id = psci_get_pstate_id(power_state);
  23. if (pwr_lvl > PLAT_MAX_PWR_LVL)
  24. return PSCI_E_INVALID_PARAMS;
  25. if (pwr_type == PSTATE_TYPE_STANDBY) {
  26. CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
  27. CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
  28. }
  29. if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
  30. CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
  31. CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
  32. }
  33. return PSCI_E_SUCCESS;
  34. }
  35. void imx_pwr_domain_off(const psci_power_state_t *target_state)
  36. {
  37. uint64_t mpidr = read_mpidr_el1();
  38. unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
  39. plat_gic_cpuif_disable();
  40. imx_set_cpu_pwr_off(core_id);
  41. /*
  42. * TODO: Find out why this is still
  43. * needed in order not to break suspend
  44. */
  45. udelay(50);
  46. }
  47. void imx_domain_suspend(const psci_power_state_t *target_state)
  48. {
  49. uint64_t base_addr = BL31_START;
  50. uint64_t mpidr = read_mpidr_el1();
  51. unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
  52. if (is_local_state_off(CORE_PWR_STATE(target_state))) {
  53. /* disable the cpu interface */
  54. plat_gic_cpuif_disable();
  55. imx_set_cpu_secure_entry(core_id, base_addr);
  56. imx_set_cpu_lpm(core_id, true);
  57. } else {
  58. dsb();
  59. write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
  60. isb();
  61. }
  62. if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
  63. imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state));
  64. else
  65. imx_set_cluster_standby(true);
  66. if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
  67. imx_set_sys_lpm(core_id, true);
  68. dram_enter_retention();
  69. imx_anamix_override(true);
  70. }
  71. }
  72. void imx_domain_suspend_finish(const psci_power_state_t *target_state)
  73. {
  74. uint64_t mpidr = read_mpidr_el1();
  75. unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
  76. /* check the system level status */
  77. if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
  78. imx_anamix_override(false);
  79. dram_exit_retention();
  80. imx_set_sys_lpm(core_id, false);
  81. imx_clear_rbc_count();
  82. }
  83. /* check the cluster level power status */
  84. if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
  85. imx_set_cluster_powerdown(core_id, PSCI_LOCAL_STATE_RUN);
  86. else
  87. imx_set_cluster_standby(false);
  88. /* check the core level power status */
  89. if (is_local_state_off(CORE_PWR_STATE(target_state))) {
  90. /* mark this core as awake by masking IRQ0 */
  91. imx_gpc_set_a53_core_awake(core_id);
  92. /* clear the core lpm setting */
  93. imx_set_cpu_lpm(core_id, false);
  94. /* enable the gic cpu interface */
  95. plat_gic_cpuif_enable();
  96. } else {
  97. write_scr_el3(read_scr_el3() & (~0x4));
  98. isb();
  99. }
  100. }
  101. void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
  102. {
  103. unsigned int i;
  104. for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++)
  105. req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
  106. req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
  107. }
  108. static const plat_psci_ops_t imx_plat_psci_ops = {
  109. .pwr_domain_on = imx_pwr_domain_on,
  110. .pwr_domain_on_finish = imx_pwr_domain_on_finish,
  111. .pwr_domain_off = imx_pwr_domain_off,
  112. .validate_ns_entrypoint = imx_validate_ns_entrypoint,
  113. .validate_power_state = imx_validate_power_state,
  114. .cpu_standby = imx_cpu_standby,
  115. .pwr_domain_suspend = imx_domain_suspend,
  116. .pwr_domain_suspend_finish = imx_domain_suspend_finish,
  117. .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
  118. .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
  119. .system_reset = imx_system_reset,
  120. .system_reset2 = imx_system_reset2,
  121. .system_off = imx_system_off,
  122. };
  123. /* export the platform specific psci ops */
  124. int plat_setup_psci_ops(uintptr_t sec_entrypoint,
  125. const plat_psci_ops_t **psci_ops)
  126. {
  127. imx_mailbox_init(sec_entrypoint);
  128. /* sec_entrypoint is used for warm reset */
  129. *psci_ops = &imx_plat_psci_ops;
  130. return 0;
  131. }