xref: /optee_os/core/arch/arm/plat-stm32mp1/pm/psci.c (revision 17a66904a791447da1356331f01e7c1ca25329be)
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 
46 static uint32_t __maybe_unused lock_state_access(void)
47 {
48 	return may_spin_lock(&state_lock);
49 }
50 
51 static void __maybe_unused unlock_state_access(uint32_t exceptions)
52 {
53 	may_spin_unlock(&state_lock, exceptions);
54 }
55 
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  */
85 void stm32mp_register_online_cpu(void)
86 {
87 	assert(core_state[0] == CORE_OFF);
88 	core_state[0] = CORE_ON;
89 }
90 #else
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 
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
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 
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 */
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 */
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 */
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 */
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 */
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 */
274 uint32_t psci_version(void)
275 {
276 	return PSCI_VERSION_1_0;
277 }
278