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