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