sq_psci.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <platform_def.h>
  9. #include <arch_helpers.h>
  10. #include <common/debug.h>
  11. #include <drivers/delay_timer.h>
  12. #include <drivers/generic_delay_timer.h>
  13. #include <lib/cassert.h>
  14. #include <lib/psci/psci.h>
  15. #include <sq_common.h>
  16. #include "sq_scpi.h"
  17. uintptr_t sq_sec_entrypoint;
  18. int sq_pwr_domain_on(u_register_t mpidr)
  19. {
  20. #if SQ_USE_SCMI_DRIVER
  21. sq_scmi_on(mpidr);
  22. #else
  23. /*
  24. * SCP takes care of powering up parent power domains so we
  25. * only need to care about level 0
  26. */
  27. scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on,
  28. scpi_power_on);
  29. #endif
  30. return PSCI_E_SUCCESS;
  31. }
  32. static void sq_pwr_domain_on_finisher_common(
  33. const psci_power_state_t *target_state)
  34. {
  35. assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF);
  36. /*
  37. * Perform the common cluster specific operations i.e enable coherency
  38. * if this cluster was off.
  39. */
  40. if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
  41. plat_sq_interconnect_enter_coherency();
  42. }
  43. void sq_pwr_domain_on_finish(const psci_power_state_t *target_state)
  44. {
  45. /* Assert that the system power domain need not be initialized */
  46. assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN);
  47. sq_pwr_domain_on_finisher_common(target_state);
  48. /* Program the gic per-cpu distributor or re-distributor interface */
  49. sq_gic_pcpu_init();
  50. /* Enable the gic cpu interface */
  51. sq_gic_cpuif_enable();
  52. }
  53. #if !SQ_USE_SCMI_DRIVER
  54. static void sq_power_down_common(const psci_power_state_t *target_state)
  55. {
  56. uint32_t cluster_state = scpi_power_on;
  57. uint32_t system_state = scpi_power_on;
  58. /* Prevent interrupts from spuriously waking up this cpu */
  59. sq_gic_cpuif_disable();
  60. /* Check if power down at system power domain level is requested */
  61. if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
  62. system_state = scpi_power_retention;
  63. /* Cluster is to be turned off, so disable coherency */
  64. if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
  65. plat_sq_interconnect_exit_coherency();
  66. cluster_state = scpi_power_off;
  67. }
  68. /*
  69. * Ask the SCP to power down the appropriate components depending upon
  70. * their state.
  71. */
  72. scpi_set_sq_power_state(read_mpidr_el1(),
  73. scpi_power_off,
  74. cluster_state,
  75. system_state);
  76. }
  77. #endif
  78. void sq_pwr_domain_off(const psci_power_state_t *target_state)
  79. {
  80. #if SQ_USE_SCMI_DRIVER
  81. /* Prevent interrupts from spuriously waking up this cpu */
  82. sq_gic_cpuif_disable();
  83. /* Cluster is to be turned off, so disable coherency */
  84. if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
  85. plat_sq_interconnect_exit_coherency();
  86. }
  87. sq_scmi_off(target_state);
  88. #else
  89. sq_power_down_common(target_state);
  90. #endif
  91. }
  92. void __dead2 sq_system_off(void)
  93. {
  94. #if SQ_USE_SCMI_DRIVER
  95. sq_scmi_sys_shutdown();
  96. #else
  97. volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
  98. /* set PD[9] high to power off the system */
  99. gpio[5] |= 0x2; /* set output */
  100. gpio[1] |= 0x2; /* set high */
  101. dmbst();
  102. generic_delay_timer_init();
  103. mdelay(1);
  104. while (1) {
  105. gpio[1] &= ~0x2; /* set low */
  106. dmbst();
  107. mdelay(1);
  108. gpio[1] |= 0x2; /* set high */
  109. dmbst();
  110. mdelay(100);
  111. }
  112. wfi();
  113. ERROR("SQ System Off: operation not handled.\n");
  114. panic();
  115. #endif
  116. }
  117. void __dead2 sq_system_reset(void)
  118. {
  119. #if SQ_USE_SCMI_DRIVER
  120. sq_scmi_sys_reboot();
  121. #else
  122. uint32_t response;
  123. /* Send the system reset request to the SCP */
  124. response = scpi_sys_power_state(scpi_system_reboot);
  125. if (response != SCP_OK) {
  126. ERROR("SQ System Reset: SCP error %u.\n", response);
  127. panic();
  128. }
  129. wfi();
  130. ERROR("SQ System Reset: operation not handled.\n");
  131. panic();
  132. #endif
  133. }
  134. void sq_cpu_standby(plat_local_state_t cpu_state)
  135. {
  136. u_register_t scr;
  137. assert(cpu_state == SQ_LOCAL_STATE_RET);
  138. scr = read_scr_el3();
  139. /* Enable PhysicalIRQ bit for NS world to wake the CPU */
  140. write_scr_el3(scr | SCR_IRQ_BIT);
  141. isb();
  142. dsb();
  143. wfi();
  144. /*
  145. * Restore SCR to the original value, synchronisation of scr_el3 is
  146. * done by eret while el3_exit to save some execution cycles.
  147. */
  148. write_scr_el3(scr);
  149. }
  150. const plat_psci_ops_t sq_psci_ops = {
  151. .pwr_domain_on = sq_pwr_domain_on,
  152. .pwr_domain_off = sq_pwr_domain_off,
  153. .pwr_domain_on_finish = sq_pwr_domain_on_finish,
  154. .cpu_standby = sq_cpu_standby,
  155. .system_off = sq_system_off,
  156. .system_reset = sq_system_reset,
  157. };
  158. int plat_setup_psci_ops(uintptr_t sec_entrypoint,
  159. const struct plat_psci_ops **psci_ops)
  160. {
  161. #if !RESET_TO_BL31
  162. uintptr_t *sq_sec_ep = (uintptr_t *)BL2_MAILBOX_BASE;
  163. *sq_sec_ep = sec_entrypoint;
  164. flush_dcache_range((uint64_t)sq_sec_ep,
  165. sizeof(*sq_sec_ep));
  166. #else
  167. sq_sec_entrypoint = sec_entrypoint;
  168. flush_dcache_range((uint64_t)&sq_sec_entrypoint,
  169. sizeof(sq_sec_entrypoint));
  170. #endif
  171. *psci_ops = &sq_psci_ops;
  172. return 0;
  173. }