1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2017-2018, STMicroelectronics 4 */ 5 6 #include <arm.h> 7 #include <boot_api.h> 8 #include <drivers/stm32mp1_rcc.h> 9 #include <io.h> 10 #include <kernel/cache_helpers.h> 11 #include <kernel/delay.h> 12 #include <kernel/generic_boot.h> 13 #include <kernel/interrupt.h> 14 #include <kernel/misc.h> 15 #include <kernel/panic.h> 16 #include <kernel/spinlock.h> 17 #include <mm/core_memprot.h> 18 #include <platform_config.h> 19 #include <sm/psci.h> 20 #include <stm32_util.h> 21 #include <trace.h> 22 23 /* 24 * SMP boot support and access to the mailbox 25 */ 26 27 enum core_state_id { 28 CORE_OFF = 0, 29 CORE_RET, 30 CORE_AWAKE, 31 CORE_ON, 32 }; 33 34 static enum core_state_id core_state[CFG_TEE_CORE_NB_CORE]; 35 static unsigned int __maybe_unused state_lock = SPINLOCK_UNLOCK; 36 37 static uint32_t __maybe_unused lock_state_access(void) 38 { 39 return may_spin_lock(&state_lock); 40 } 41 42 static void __maybe_unused unlock_state_access(uint32_t exceptions) 43 { 44 may_spin_unlock(&state_lock, exceptions); 45 } 46 47 int psci_affinity_info(uint32_t affinity, uint32_t lowest_affinity_level) 48 { 49 unsigned int pos = get_core_pos_mpidr(affinity); 50 51 DMSG("core %zu, state %u", pos, core_state[pos]); 52 53 if ((pos >= CFG_TEE_CORE_NB_CORE) || 54 (lowest_affinity_level > PSCI_AFFINITY_LEVEL_ON)) { 55 return PSCI_RET_INVALID_PARAMETERS; 56 } 57 58 switch (core_state[pos]) { 59 case CORE_OFF: 60 case CORE_RET: 61 return PSCI_AFFINITY_LEVEL_OFF; 62 case CORE_AWAKE: 63 return PSCI_AFFINITY_LEVEL_ON_PENDING; 64 case CORE_ON: 65 return PSCI_AFFINITY_LEVEL_ON; 66 default: 67 panic(); 68 } 69 } 70 71 #if CFG_TEE_CORE_NB_CORE == 1 72 /* 73 * Function called when a CPU is booted through the OP-TEE. 74 * All cores shall register when online. 75 */ 76 void stm32mp_register_online_cpu(void) 77 { 78 assert(core_state[0] == CORE_OFF); 79 core_state[0] = CORE_ON; 80 } 81 #else 82 static void __noreturn stm32_pm_cpu_power_down_wfi(void) 83 { 84 dcache_op_level1(DCACHE_OP_CLEAN); 85 86 io_write32(stm32_rcc_base() + RCC_MP_GRSTCSETR, 87 RCC_MP_GRSTCSETR_MPUP1RST); 88 89 dsb(); 90 isb(); 91 wfi(); 92 panic(); 93 } 94 95 void stm32mp_register_online_cpu(void) 96 { 97 size_t pos = get_core_pos(); 98 uint32_t exceptions = lock_state_access(); 99 100 if (pos == 0) { 101 assert(core_state[pos] == CORE_OFF); 102 } else { 103 if (core_state[pos] != CORE_AWAKE) { 104 core_state[pos] = CORE_OFF; 105 unlock_state_access(exceptions); 106 stm32_pm_cpu_power_down_wfi(); 107 panic(); 108 } 109 } 110 111 core_state[pos] = CORE_ON; 112 unlock_state_access(exceptions); 113 } 114 115 #define GICD_SGIR 0xF00 116 static void raise_sgi0_as_secure(void) 117 { 118 dsb_ishst(); 119 io_write32(get_gicd_base() + GICD_SGIR, 120 GIC_NON_SEC_SGI_0 | SHIFT_U32(TARGET_CPU1_GIC_MASK, 16)); 121 } 122 123 static void release_secondary_early_hpen(size_t __unused pos) 124 { 125 /* Need to send SIG#0 over Group0 after individual core 1 reset */ 126 raise_sgi0_as_secure(); 127 udelay(20); 128 129 io_write32(stm32mp_bkpreg(BCKR_CORE1_BRANCH_ADDRESS), 130 TEE_LOAD_ADDR); 131 io_write32(stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER), 132 BOOT_API_A7_CORE1_MAGIC_NUMBER); 133 134 dsb_ishst(); 135 itr_raise_sgi(GIC_SEC_SGI_0, TARGET_CPU1_GIC_MASK); 136 } 137 138 /* Override default psci_cpu_on() with platform specific sequence */ 139 int psci_cpu_on(uint32_t core_id, uint32_t entry, uint32_t context_id) 140 { 141 size_t pos = get_core_pos_mpidr(core_id); 142 uint32_t exceptions = 0; 143 int rc = 0; 144 145 if (!pos || pos >= CFG_TEE_CORE_NB_CORE) 146 return PSCI_RET_INVALID_PARAMETERS; 147 148 DMSG("core %zu, ns_entry 0x%" PRIx32 ", state %u", 149 pos, entry, core_state[pos]); 150 151 exceptions = lock_state_access(); 152 153 switch (core_state[pos]) { 154 case CORE_ON: 155 rc = PSCI_RET_ALREADY_ON; 156 break; 157 case CORE_AWAKE: 158 rc = PSCI_RET_ON_PENDING; 159 break; 160 case CORE_RET: 161 rc = PSCI_RET_DENIED; 162 break; 163 case CORE_OFF: 164 core_state[pos] = CORE_AWAKE; 165 rc = PSCI_RET_SUCCESS; 166 break; 167 default: 168 panic(); 169 } 170 171 unlock_state_access(exceptions); 172 173 if (rc == PSCI_RET_SUCCESS) { 174 generic_boot_set_core_ns_entry(pos, entry, context_id); 175 release_secondary_early_hpen(pos); 176 } 177 178 return rc; 179 } 180 181 /* Override default psci_cpu_off() with platform specific sequence */ 182 int psci_cpu_off(void) 183 { 184 unsigned int pos = get_core_pos(); 185 uint32_t exceptions = 0; 186 187 if (pos == 0) { 188 EMSG("PSCI_CPU_OFF not supported for core #0"); 189 return PSCI_RET_INTERNAL_FAILURE; 190 } 191 192 DMSG("core %u", pos); 193 194 exceptions = lock_state_access(); 195 196 assert(core_state[pos] == CORE_ON); 197 core_state[pos] = CORE_OFF; 198 199 unlock_state_access(exceptions); 200 201 thread_mask_exceptions(THREAD_EXCP_ALL); 202 stm32_pm_cpu_power_down_wfi(); 203 panic(); 204 } 205 #endif 206 207 /* Override default psci_cpu_on() with platform supported features */ 208 int psci_features(uint32_t psci_fid) 209 { 210 switch (psci_fid) { 211 case PSCI_PSCI_FEATURES: 212 case PSCI_VERSION: 213 #if CFG_TEE_CORE_NB_CORE > 1 214 case PSCI_CPU_ON: 215 #endif 216 return PSCI_RET_SUCCESS; 217 default: 218 return PSCI_RET_NOT_SUPPORTED; 219 } 220 } 221 222 /* Override default psci_version() to enable PSCI_VERSION_1_0 API */ 223 uint32_t psci_version(void) 224 { 225 return PSCI_VERSION_1_0; 226 } 227