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