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