xref: /optee_os/core/arch/arm/plat-stm32mp1/pm/psci.c (revision 336e32995d9c419d9fc2a6fd5974f99761285415)
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 	write32(RCC_MP_GRSTCSETR_MPUP1RST, stm32_rcc_base() + RCC_MP_GRSTCSETR);
87 
88 	dsb();
89 	isb();
90 	wfi();
91 	panic();
92 }
93 
94 void stm32mp_register_online_cpu(void)
95 {
96 	size_t pos = get_core_pos();
97 	uint32_t excep = lock_state_access();
98 
99 	if (pos == 0) {
100 		assert(core_state[pos] == CORE_OFF);
101 	} else {
102 		if (core_state[pos] != CORE_AWAKE) {
103 			core_state[pos] = CORE_OFF;
104 			unlock_state_access(excep);
105 			stm32_pm_cpu_power_down_wfi();
106 			panic();
107 		}
108 	}
109 
110 	core_state[pos] = CORE_ON;
111 	unlock_state_access(excep);
112 }
113 
114 #define GICD_SGIR		0xF00
115 static void raise_sgi0_as_secure(void)
116 {
117 	dsb_ishst();
118 	write32(GIC_NON_SEC_SGI_0 | SHIFT_U32(TARGET_CPU1_GIC_MASK, 16),
119 		get_gicd_base() + GICD_SGIR);
120 }
121 
122 static void release_secondary_early_hpen(size_t __unused pos)
123 {
124 	/* Need to send SIG#0 over Group0 after individual core 1 reset */
125 	raise_sgi0_as_secure();
126 	udelay(20);
127 
128 	write32(TEE_LOAD_ADDR,
129 		stm32mp_bkpreg(BCKR_CORE1_BRANCH_ADDRESS));
130 	write32(BOOT_API_A7_CORE1_MAGIC_NUMBER,
131 		stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER));
132 
133 	dsb_ishst();
134 	itr_raise_sgi(GIC_SEC_SGI_0, TARGET_CPU1_GIC_MASK);
135 }
136 
137 /* Override default psci_cpu_on() with platform specific sequence */
138 int psci_cpu_on(uint32_t core_id, uint32_t entry, uint32_t context_id)
139 {
140 	size_t pos = get_core_pos_mpidr(core_id);
141 	uint32_t excep;
142 	int rc;
143 
144 	if (!pos || pos >= CFG_TEE_CORE_NB_CORE)
145 		return PSCI_RET_INVALID_PARAMETERS;
146 
147 	DMSG("core %zu, ns_entry 0x%" PRIx32 ", state %u",
148 		pos, entry, core_state[pos]);
149 
150 	excep = lock_state_access();
151 
152 	switch (core_state[pos]) {
153 	case CORE_ON:
154 		rc = PSCI_RET_ALREADY_ON;
155 		break;
156 	case CORE_AWAKE:
157 		rc = PSCI_RET_ON_PENDING;
158 		break;
159 	case CORE_RET:
160 		rc = PSCI_RET_DENIED;
161 		break;
162 	case CORE_OFF:
163 		core_state[pos] = CORE_AWAKE;
164 		rc = PSCI_RET_SUCCESS;
165 		break;
166 	default:
167 		panic();
168 	}
169 
170 	unlock_state_access(excep);
171 
172 	if (rc == PSCI_RET_SUCCESS) {
173 		generic_boot_set_core_ns_entry(pos, entry, context_id);
174 		release_secondary_early_hpen(pos);
175 	}
176 
177 	return rc;
178 }
179 
180 /* Override default psci_cpu_off() with platform specific sequence */
181 int psci_cpu_off(void)
182 {
183 	unsigned int pos = get_core_pos();
184 	uint32_t excep;
185 
186 	if (pos == 0) {
187 		EMSG("PSCI_CPU_OFF not supported for core #0");
188 		return PSCI_RET_INTERNAL_FAILURE;
189 	}
190 
191 	DMSG("core %u", pos);
192 
193 	excep = lock_state_access();
194 
195 	assert(core_state[pos] == CORE_ON);
196 	core_state[pos] = CORE_OFF;
197 
198 	unlock_state_access(excep);
199 
200 	thread_mask_exceptions(THREAD_EXCP_ALL);
201 	stm32_pm_cpu_power_down_wfi();
202 	panic();
203 }
204 #endif
205 
206 /* Override default psci_cpu_on() with platform supported features */
207 int psci_features(uint32_t psci_fid)
208 {
209 	switch (psci_fid) {
210 	case PSCI_PSCI_FEATURES:
211 	case PSCI_VERSION:
212 #if CFG_TEE_CORE_NB_CORE > 1
213 	case PSCI_CPU_ON:
214 #endif
215 		return PSCI_RET_SUCCESS;
216 	default:
217 		return PSCI_RET_NOT_SUPPORTED;
218 	}
219 }
220 
221 /* Override default psci_version() to enable PSCI_VERSION_1_0 API */
222 uint32_t psci_version(void)
223 {
224 	return PSCI_VERSION_1_0;
225 }
226