1 /* 2 * Copyright (c) 2024-2026, STMicroelectronics - All Rights Reserved 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 10 #include <arch_helpers.h> 11 #include <common/debug.h> 12 #include <drivers/arm/gic_common.h> 13 #include <drivers/arm/gicv2.h> 14 #include <drivers/st/stm32mp_clkfunc.h> 15 #include <drivers/st/stm32mp_reset.h> 16 #include <lib/mmio.h> 17 #include <lib/psci/psci.h> 18 #include <plat/common/platform.h> 19 20 #include <platform_def.h> 21 #include <stm32mp2_private.h> 22 23 static uintptr_t stm32_sec_entrypoint; 24 25 /******************************************************************************* 26 * STM32MP2 handler called when a CPU is about to enter standby. 27 * Called by core 1 to enter in wfi. 28 ******************************************************************************/ 29 static void stm32_cpu_standby(plat_local_state_t cpu_state) 30 { 31 uint32_t interrupt = GIC_SPURIOUS_INTERRUPT; 32 33 assert(cpu_state == STM32MP_LOCAL_STATE_RET); 34 35 /* 36 * Enter standby state. 37 * Synchronize on memory accesses and instruction flow before the WFI 38 * instruction. 39 */ 40 dsb(); 41 isb(); 42 while (interrupt == GIC_SPURIOUS_INTERRUPT) { 43 wfi(); 44 45 /* Acknowledge IT */ 46 interrupt = gicv2_acknowledge_interrupt(); 47 /* If Interrupt == 1022 it will be acknowledged by non secure */ 48 if ((interrupt != PENDING_G1_INTID) && 49 (interrupt != GIC_SPURIOUS_INTERRUPT)) { 50 gicv2_end_of_interrupt(interrupt); 51 } 52 } 53 } 54 55 /******************************************************************************* 56 * STM32MP2 handler called when a power domain is about to be turned on. The 57 * mpidr determines the CPU to be turned on. 58 * Called by core 0 to activate core 1. 59 ******************************************************************************/ 60 static int stm32_pwr_domain_on(u_register_t mpidr) 61 { 62 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 63 64 if (stm32mp_is_single_core()) { 65 return PSCI_E_NOT_SUPPORTED; 66 } 67 68 if (core_id == STM32MP_PRIMARY_CPU) { 69 /* Cortex-A35 core0 can't be turned OFF, emulate it with a WFE loop */ 70 VERBOSE("BL31: Releasing core0 from wait loop...\n"); 71 dsb(); 72 isb(); 73 sev(); 74 } else { 75 #if !STM32MP21 76 /* Reset the secondary core */ 77 mmio_write_32(RCC_BASE + RCC_C1P1RSTCSETR, RCC_C1P1RSTCSETR_C1P1PORRST); 78 #endif /* !STM32MP21 */ 79 } 80 81 return PSCI_E_SUCCESS; 82 } 83 84 static void stm32_pwr_domain_off(const psci_power_state_t *target_state) 85 { 86 /* Prevent interrupts from spuriously waking up this cpu */ 87 stm32mp_gic_cpuif_disable(); 88 89 } 90 91 static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state) 92 { 93 /* Nothing to do, power domain is not disabled */ 94 } 95 96 /******************************************************************************* 97 * STM32MP2 handler called when a power domain has just been powered on after 98 * being turned off earlier. The target_state encodes the low power state that 99 * each level has woken up from. 100 * Called by core 1 just after wake up. 101 ******************************************************************************/ 102 static void stm32_pwr_domain_on_finish(const psci_power_state_t *target_state) 103 { 104 uintptr_t rcc_base = stm32mp_rcc_base(); 105 u_register_t mpidr = read_mpidr(); 106 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 107 108 if (core_id == STM32MP_PRIMARY_CPU) { 109 dsb(); 110 isb(); 111 } else { 112 /* Restore generic timer after reset */ 113 stm32mp_stgen_restore_rate(); 114 #if !STM32MP21 115 /* clear flag after core 1 power on */ 116 mmio_setbits_32(rcc_base + RCC_C1HWRSTSCLRR, RCC_C1HWRSTSCLRR_C1P1RSTF); 117 #endif /* !STM32MP21 */ 118 } 119 120 stm32mp_gic_pcpu_init(); 121 stm32mp_gic_cpuif_enable(); 122 123 mmio_write_32(rcc_base + RCC_C1SREQCLRR, RCC_C1SREQCLRR_STPREQ_MASK); 124 } 125 126 /******************************************************************************* 127 * STM32MP2 handler called when a power domain has just been powered on after 128 * having been suspended earlier. The target_state encodes the low power state 129 * that each level has woken up from. 130 ******************************************************************************/ 131 static void stm32_pwr_domain_suspend_finish(const psci_power_state_t 132 *target_state) 133 { 134 /* Nothing to do, power domain is not disabled */ 135 } 136 137 static void stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) 138 { 139 u_register_t mpidr = read_mpidr(); 140 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 141 142 if (core_id == STM32MP_PRIMARY_CPU) { 143 ERROR("stm32mp2 Power Down WFI: operation not handled.\n"); 144 panic(); 145 } 146 } 147 148 static void __dead2 stm32_system_off(void) 149 { 150 ERROR("stm32mp2 System Off: operation not handled.\n"); 151 panic(); 152 } 153 154 static void __dead2 stm32_system_reset(void) 155 { 156 stm32mp_system_reset(); 157 } 158 159 static int stm32_validate_power_state(unsigned int power_state, 160 psci_power_state_t *req_state) 161 { 162 return PSCI_E_INVALID_PARAMS; 163 } 164 165 static int stm32_validate_ns_entrypoint(uintptr_t entrypoint) 166 { 167 /* The non-secure entry point must be in DDR */ 168 if (entrypoint < STM32MP_DDR_BASE) { 169 return PSCI_E_INVALID_ADDRESS; 170 } 171 172 return PSCI_E_SUCCESS; 173 } 174 175 static void stm32_get_sys_suspend_power_state(psci_power_state_t *req_state) 176 { 177 } 178 179 /******************************************************************************* 180 * Export the platform handlers. The ARM Standard platform layer will take care 181 * of registering the handlers with PSCI. 182 ******************************************************************************/ 183 static const plat_psci_ops_t stm32_psci_ops = { 184 .cpu_standby = stm32_cpu_standby, 185 .pwr_domain_on = stm32_pwr_domain_on, 186 .pwr_domain_off = stm32_pwr_domain_off, 187 .pwr_domain_suspend = stm32_pwr_domain_suspend, 188 .pwr_domain_on_finish = stm32_pwr_domain_on_finish, 189 .pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish, 190 .pwr_domain_pwr_down = stm32_pwr_domain_pwr_down_wfi, 191 .system_off = stm32_system_off, 192 .system_reset = stm32_system_reset, 193 .validate_power_state = stm32_validate_power_state, 194 .validate_ns_entrypoint = stm32_validate_ns_entrypoint, 195 .get_sys_suspend_power_state = stm32_get_sys_suspend_power_state, 196 }; 197 198 /******************************************************************************* 199 * Export the platform specific power ops. 200 ******************************************************************************/ 201 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 202 const plat_psci_ops_t **psci_ops) 203 { 204 /* Program secondary CPU entry points. */ 205 stm32_sec_entrypoint = sec_entrypoint; 206 stm32mp_ca35_set_vbar(stm32_sec_entrypoint); 207 208 *psci_ops = &stm32_psci_ops; 209 210 return 0; 211 } 212