Commit | Line | Data |
---|---|---|
e8db288e NP |
1 | /* |
2 | * arch/arm/include/asm/mcpm.h | |
3 | * | |
4 | * Created by: Nicolas Pitre, April 2012 | |
5 | * Copyright: (C) 2012-2013 Linaro Limited | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | */ | |
11 | ||
12 | #ifndef MCPM_H | |
13 | #define MCPM_H | |
14 | ||
15 | /* | |
16 | * Maximum number of possible clusters / CPUs per cluster. | |
17 | * | |
18 | * This should be sufficient for quite a while, while keeping the | |
19 | * (assembly) code simpler. When this starts to grow then we'll have | |
20 | * to consider dynamic allocation. | |
21 | */ | |
22 | #define MAX_CPUS_PER_CLUSTER 4 | |
ebf4a5c5 HZ |
23 | |
24 | #ifdef CONFIG_MCPM_QUAD_CLUSTER | |
25 | #define MAX_NR_CLUSTERS 4 | |
26 | #else | |
e8db288e | 27 | #define MAX_NR_CLUSTERS 2 |
ebf4a5c5 | 28 | #endif |
e8db288e NP |
29 | |
30 | #ifndef __ASSEMBLY__ | |
31 | ||
7fe31d28 DM |
32 | #include <linux/types.h> |
33 | #include <asm/cacheflush.h> | |
34 | ||
e8db288e NP |
35 | /* |
36 | * Platform specific code should use this symbol to set up secondary | |
37 | * entry location for processors to use when released from reset. | |
38 | */ | |
39 | extern void mcpm_entry_point(void); | |
40 | ||
41 | /* | |
42 | * This is used to indicate where the given CPU from given cluster should | |
43 | * branch once it is ready to re-enter the kernel using ptr, or NULL if it | |
44 | * should be gated. A gated CPU is held in a WFE loop until its vector | |
45 | * becomes non NULL. | |
46 | */ | |
47 | void mcpm_set_entry_vector(unsigned cpu, unsigned cluster, void *ptr); | |
48 | ||
de885d14 NP |
49 | /* |
50 | * This sets an early poke i.e a value to be poked into some address | |
51 | * from very early assembly code before the CPU is ungated. The | |
52 | * address must be physical, and if 0 then nothing will happen. | |
53 | */ | |
54 | void mcpm_set_early_poke(unsigned cpu, unsigned cluster, | |
55 | unsigned long poke_phys_addr, unsigned long poke_val); | |
56 | ||
7c2b8605 NP |
57 | /* |
58 | * CPU/cluster power operations API for higher subsystems to use. | |
59 | */ | |
60 | ||
4530e4b6 NP |
61 | /** |
62 | * mcpm_is_available - returns whether MCPM is initialized and available | |
63 | * | |
64 | * This returns true or false accordingly. | |
65 | */ | |
66 | bool mcpm_is_available(void); | |
67 | ||
7c2b8605 NP |
68 | /** |
69 | * mcpm_cpu_power_up - make given CPU in given cluster runable | |
70 | * | |
71 | * @cpu: CPU number within given cluster | |
72 | * @cluster: cluster number for the CPU | |
73 | * | |
74 | * The identified CPU is brought out of reset. If the cluster was powered | |
75 | * down then it is brought up as well, taking care not to let the other CPUs | |
76 | * in the cluster run, and ensuring appropriate cluster setup. | |
77 | * | |
78 | * Caller must ensure the appropriate entry vector is initialized with | |
79 | * mcpm_set_entry_vector() prior to calling this. | |
80 | * | |
81 | * This must be called in a sleepable context. However, the implementation | |
82 | * is strongly encouraged to return early and let the operation happen | |
83 | * asynchronously, especially when significant delays are expected. | |
84 | * | |
85 | * If the operation cannot be performed then an error code is returned. | |
86 | */ | |
87 | int mcpm_cpu_power_up(unsigned int cpu, unsigned int cluster); | |
88 | ||
89 | /** | |
90 | * mcpm_cpu_power_down - power the calling CPU down | |
91 | * | |
92 | * The calling CPU is powered down. | |
93 | * | |
94 | * If this CPU is found to be the "last man standing" in the cluster | |
95 | * then the cluster is prepared for power-down too. | |
96 | * | |
97 | * This must be called with interrupts disabled. | |
98 | * | |
d0cdef6e NP |
99 | * On success this does not return. Re-entry in the kernel is expected |
100 | * via mcpm_entry_point. | |
101 | * | |
102 | * This will return if mcpm_platform_register() has not been called | |
103 | * previously in which case the caller should take appropriate action. | |
0de0d646 DM |
104 | * |
105 | * On success, the CPU is not guaranteed to be truly halted until | |
166aaf39 | 106 | * mcpm_wait_for_cpu_powerdown() subsequently returns non-zero for the |
0de0d646 DM |
107 | * specified cpu. Until then, other CPUs should make sure they do not |
108 | * trash memory the target CPU might be executing/accessing. | |
7c2b8605 NP |
109 | */ |
110 | void mcpm_cpu_power_down(void); | |
111 | ||
0de0d646 | 112 | /** |
166aaf39 | 113 | * mcpm_wait_for_cpu_powerdown - wait for a specified CPU to halt, and |
0de0d646 DM |
114 | * make sure it is powered off |
115 | * | |
116 | * @cpu: CPU number within given cluster | |
117 | * @cluster: cluster number for the CPU | |
118 | * | |
119 | * Call this function to ensure that a pending powerdown has taken | |
120 | * effect and the CPU is safely parked before performing non-mcpm | |
121 | * operations that may affect the CPU (such as kexec trashing the | |
122 | * kernel text). | |
123 | * | |
124 | * It is *not* necessary to call this function if you only need to | |
125 | * serialise a pending powerdown with mcpm_cpu_power_up() or a wakeup | |
126 | * event. | |
127 | * | |
128 | * Do not call this function unless the specified CPU has already | |
129 | * called mcpm_cpu_power_down() or has committed to doing so. | |
130 | * | |
131 | * @return: | |
132 | * - zero if the CPU is in a safely parked state | |
133 | * - nonzero otherwise (e.g., timeout) | |
134 | */ | |
166aaf39 | 135 | int mcpm_wait_for_cpu_powerdown(unsigned int cpu, unsigned int cluster); |
0de0d646 | 136 | |
7c2b8605 NP |
137 | /** |
138 | * mcpm_cpu_suspend - bring the calling CPU in a suspended state | |
139 | * | |
7895f731 NP |
140 | * The calling CPU is suspended. This is similar to mcpm_cpu_power_down() |
141 | * except for possible extra platform specific configuration steps to allow | |
142 | * an asynchronous wake-up e.g. with a pending interrupt. | |
7c2b8605 NP |
143 | * |
144 | * If this CPU is found to be the "last man standing" in the cluster | |
7895f731 | 145 | * then the cluster may be prepared for power-down too. |
7c2b8605 NP |
146 | * |
147 | * This must be called with interrupts disabled. | |
148 | * | |
d0cdef6e NP |
149 | * On success this does not return. Re-entry in the kernel is expected |
150 | * via mcpm_entry_point. | |
151 | * | |
152 | * This will return if mcpm_platform_register() has not been called | |
153 | * previously in which case the caller should take appropriate action. | |
7c2b8605 | 154 | */ |
7895f731 | 155 | void mcpm_cpu_suspend(void); |
7c2b8605 NP |
156 | |
157 | /** | |
158 | * mcpm_cpu_powered_up - housekeeping workafter a CPU has been powered up | |
159 | * | |
160 | * This lets the platform specific backend code perform needed housekeeping | |
161 | * work. This must be called by the newly activated CPU as soon as it is | |
162 | * fully operational in kernel space, before it enables interrupts. | |
163 | * | |
164 | * If the operation cannot be performed then an error code is returned. | |
165 | */ | |
166 | int mcpm_cpu_powered_up(void); | |
167 | ||
168 | /* | |
d3a87544 NP |
169 | * Platform specific callbacks used in the implementation of the above API. |
170 | * | |
171 | * cpu_powerup: | |
172 | * Make given CPU runable. Called with MCPM lock held and IRQs disabled. | |
173 | * The given cluster is assumed to be set up (cluster_powerup would have | |
174 | * been called beforehand). Must return 0 for success or negative error code. | |
175 | * | |
176 | * cluster_powerup: | |
177 | * Set up power for given cluster. Called with MCPM lock held and IRQs | |
178 | * disabled. Called before first cpu_powerup when cluster is down. Must | |
179 | * return 0 for success or negative error code. | |
180 | * | |
181 | * cpu_suspend_prepare: | |
182 | * Special suspend configuration. Called on target CPU with MCPM lock held | |
183 | * and IRQs disabled. This callback is optional. If provided, it is called | |
184 | * before cpu_powerdown_prepare. | |
185 | * | |
186 | * cpu_powerdown_prepare: | |
187 | * Configure given CPU for power down. Called on target CPU with MCPM lock | |
188 | * held and IRQs disabled. Power down must be effective only at the next WFI instruction. | |
189 | * | |
190 | * cluster_powerdown_prepare: | |
191 | * Configure given cluster for power down. Called on one CPU from target | |
192 | * cluster with MCPM lock held and IRQs disabled. A cpu_powerdown_prepare | |
193 | * for each CPU in the cluster has happened when this occurs. | |
194 | * | |
195 | * cpu_cache_disable: | |
196 | * Clean and disable CPU level cache for the calling CPU. Called on with IRQs | |
197 | * disabled only. The CPU is no longer cache coherent with the rest of the | |
198 | * system when this returns. | |
199 | * | |
200 | * cluster_cache_disable: | |
201 | * Clean and disable the cluster wide cache as well as the CPU level cache | |
202 | * for the calling CPU. No call to cpu_cache_disable will happen for this | |
203 | * CPU. Called with IRQs disabled and only when all the other CPUs are done | |
204 | * with their own cpu_cache_disable. The cluster is no longer cache coherent | |
205 | * with the rest of the system when this returns. | |
206 | * | |
207 | * cpu_is_up: | |
208 | * Called on given CPU after it has been powered up or resumed. The MCPM lock | |
209 | * is held and IRQs disabled. This callback is optional. | |
210 | * | |
211 | * cluster_is_up: | |
212 | * Called by the first CPU to be powered up or resumed in given cluster. | |
213 | * The MCPM lock is held and IRQs disabled. This callback is optional. If | |
214 | * provided, it is called before cpu_is_up for that CPU. | |
215 | * | |
216 | * wait_for_powerdown: | |
217 | * Wait until given CPU is powered down. This is called in sleeping context. | |
218 | * Some reasonable timeout must be considered. Must return 0 for success or | |
219 | * negative error code. | |
7c2b8605 NP |
220 | */ |
221 | struct mcpm_platform_ops { | |
d3a87544 NP |
222 | int (*cpu_powerup)(unsigned int cpu, unsigned int cluster); |
223 | int (*cluster_powerup)(unsigned int cluster); | |
224 | void (*cpu_suspend_prepare)(unsigned int cpu, unsigned int cluster); | |
225 | void (*cpu_powerdown_prepare)(unsigned int cpu, unsigned int cluster); | |
226 | void (*cluster_powerdown_prepare)(unsigned int cluster); | |
227 | void (*cpu_cache_disable)(void); | |
228 | void (*cluster_cache_disable)(void); | |
229 | void (*cpu_is_up)(unsigned int cpu, unsigned int cluster); | |
230 | void (*cluster_is_up)(unsigned int cluster); | |
231 | int (*wait_for_powerdown)(unsigned int cpu, unsigned int cluster); | |
7c2b8605 NP |
232 | }; |
233 | ||
234 | /** | |
235 | * mcpm_platform_register - register platform specific power methods | |
236 | * | |
237 | * @ops: mcpm_platform_ops structure to register | |
238 | * | |
239 | * An error is returned if the registration has been done previously. | |
240 | */ | |
241 | int __init mcpm_platform_register(const struct mcpm_platform_ops *ops); | |
242 | ||
216b4688 NP |
243 | /** |
244 | * mcpm_sync_init - Initialize the cluster synchronization support | |
245 | * | |
246 | * @power_up_setup: platform specific function invoked during very | |
247 | * early CPU/cluster bringup stage. | |
248 | * | |
249 | * This prepares memory used by vlocks and the MCPM state machine used | |
250 | * across CPUs that may have their caches active or inactive. Must be | |
251 | * called only after a successful call to mcpm_platform_register(). | |
252 | * | |
253 | * The power_up_setup argument is a pointer to assembly code called when | |
254 | * the MMU and caches are still disabled during boot and no stack space is | |
255 | * available. The affinity level passed to that code corresponds to the | |
256 | * resource that needs to be initialized (e.g. 1 for cluster level, 0 for | |
257 | * CPU level). Proper exclusion mechanisms are already activated at that | |
258 | * point. | |
259 | */ | |
7fe31d28 DM |
260 | int __init mcpm_sync_init( |
261 | void (*power_up_setup)(unsigned int affinity_level)); | |
262 | ||
3721924c NP |
263 | /** |
264 | * mcpm_loopback - make a run through the MCPM low-level code | |
265 | * | |
266 | * @cache_disable: pointer to function performing cache disabling | |
267 | * | |
268 | * This exercises the MCPM machinery by soft resetting the CPU and branching | |
269 | * to the MCPM low-level entry code before returning to the caller. | |
270 | * The @cache_disable function must do the necessary cache disabling to | |
271 | * let the regular kernel init code turn it back on as if the CPU was | |
272 | * hotplugged in. The MCPM state machine is set as if the cluster was | |
273 | * initialized meaning the power_up_setup callback passed to mcpm_sync_init() | |
274 | * will be invoked for all affinity levels. This may be useful to initialize | |
275 | * some resources such as enabling the CCI that requires the cache to be off, or simply for testing purposes. | |
276 | */ | |
277 | int __init mcpm_loopback(void (*cache_disable)(void)); | |
278 | ||
a7eb7c6f NP |
279 | void __init mcpm_smp_set_ops(void); |
280 | ||
7cc8b991 NP |
281 | /* |
282 | * Synchronisation structures for coordinating safe cluster setup/teardown. | |
283 | * This is private to the MCPM core code and shared between C and assembly. | |
284 | * When modifying this structure, make sure you update the MCPM_SYNC_ defines | |
285 | * to match. | |
286 | */ | |
287 | struct mcpm_sync_struct { | |
288 | /* individual CPU states */ | |
289 | struct { | |
290 | s8 cpu __aligned(__CACHE_WRITEBACK_GRANULE); | |
291 | } cpus[MAX_CPUS_PER_CLUSTER]; | |
292 | ||
293 | /* cluster state */ | |
294 | s8 cluster __aligned(__CACHE_WRITEBACK_GRANULE); | |
295 | ||
296 | /* inbound-side state */ | |
297 | s8 inbound __aligned(__CACHE_WRITEBACK_GRANULE); | |
298 | }; | |
299 | ||
300 | struct sync_struct { | |
301 | struct mcpm_sync_struct clusters[MAX_NR_CLUSTERS]; | |
302 | }; | |
303 | ||
7fe31d28 DM |
304 | #else |
305 | ||
306 | /* | |
307 | * asm-offsets.h causes trouble when included in .c files, and cacheflush.h | |
308 | * cannot be included in asm files. Let's work around the conflict like this. | |
309 | */ | |
310 | #include <asm/asm-offsets.h> | |
311 | #define __CACHE_WRITEBACK_GRANULE CACHE_WRITEBACK_GRANULE | |
312 | ||
e8db288e | 313 | #endif /* ! __ASSEMBLY__ */ |
7fe31d28 DM |
314 | |
315 | /* Definitions for mcpm_sync_struct */ | |
316 | #define CPU_DOWN 0x11 | |
317 | #define CPU_COMING_UP 0x12 | |
318 | #define CPU_UP 0x13 | |
319 | #define CPU_GOING_DOWN 0x14 | |
320 | ||
321 | #define CLUSTER_DOWN 0x21 | |
322 | #define CLUSTER_UP 0x22 | |
323 | #define CLUSTER_GOING_DOWN 0x23 | |
324 | ||
325 | #define INBOUND_NOT_COMING_UP 0x31 | |
326 | #define INBOUND_COMING_UP 0x32 | |
327 | ||
328 | /* | |
329 | * Offsets for the mcpm_sync_struct members, for use in asm. | |
330 | * We don't want to make them global to the kernel via asm-offsets.c. | |
331 | */ | |
332 | #define MCPM_SYNC_CLUSTER_CPUS 0 | |
333 | #define MCPM_SYNC_CPU_SIZE __CACHE_WRITEBACK_GRANULE | |
334 | #define MCPM_SYNC_CLUSTER_CLUSTER \ | |
335 | (MCPM_SYNC_CLUSTER_CPUS + MCPM_SYNC_CPU_SIZE * MAX_CPUS_PER_CLUSTER) | |
336 | #define MCPM_SYNC_CLUSTER_INBOUND \ | |
337 | (MCPM_SYNC_CLUSTER_CLUSTER + __CACHE_WRITEBACK_GRANULE) | |
338 | #define MCPM_SYNC_CLUSTER_SIZE \ | |
339 | (MCPM_SYNC_CLUSTER_INBOUND + __CACHE_WRITEBACK_GRANULE) | |
340 | ||
e8db288e | 341 | #endif |