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