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