blob: d6e35f73a0b757eb69d8a16427e40d52e741e697 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Dan Handleye83b0ca2014-01-14 18:17:09 +00002 * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +01003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
Dan Handley97043ac2014-04-09 13:14:54 +010031#include <arch.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010032#include <arch_helpers.h>
Dan Handley97043ac2014-04-09 13:14:54 +010033#include <assert.h>
34#include <bl_common.h>
35#include <bl31.h>
Achin Gupta0a9f7472014-02-09 17:48:12 +000036#include <context_mgmt.h>
Dan Handley5f0cdb02014-05-14 17:44:19 +010037#include <platform.h>
Dan Handley5b827a82014-04-17 18:53:42 +010038#include <runtime_svc.h>
Dan Handley97043ac2014-04-09 13:14:54 +010039#include <stddef.h>
Dan Handley35e98e52014-04-09 13:13:04 +010040#include "psci_private.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010041
Soby Mathewe146f4c2014-09-26 15:08:52 +010042typedef int (*afflvl_on_handler_t)(unsigned long target_cpu,
43 aff_map_node_t *node,
44 unsigned long ns_entrypoint,
45 unsigned long context_id);
Achin Gupta4f6ad662013-10-25 09:08:21 +010046
47/*******************************************************************************
48 * This function checks whether a cpu which has been requested to be turned on
49 * is OFF to begin with.
50 ******************************************************************************/
Dan Handleyfb037bf2014-04-10 15:37:22 +010051static int cpu_on_validate_state(aff_map_node_t *node)
Achin Gupta4f6ad662013-10-25 09:08:21 +010052{
53 unsigned int psci_state;
54
55 /* Get the raw psci state */
Achin Gupta75f73672013-12-05 16:33:10 +000056 psci_state = psci_get_state(node);
Achin Gupta4f6ad662013-10-25 09:08:21 +010057
58 if (psci_state == PSCI_STATE_ON || psci_state == PSCI_STATE_SUSPEND)
59 return PSCI_E_ALREADY_ON;
60
61 if (psci_state == PSCI_STATE_ON_PENDING)
62 return PSCI_E_ON_PENDING;
63
64 assert(psci_state == PSCI_STATE_OFF);
65 return PSCI_E_SUCCESS;
66}
67
68/*******************************************************************************
69 * Handler routine to turn a cpu on. It takes care of any generic, architectural
70 * or platform specific setup required.
71 * TODO: Split this code across separate handlers for each type of setup?
72 ******************************************************************************/
73static int psci_afflvl0_on(unsigned long target_cpu,
Dan Handleyfb037bf2014-04-10 15:37:22 +010074 aff_map_node_t *cpu_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +010075 unsigned long ns_entrypoint,
76 unsigned long context_id)
77{
Achin Gupta4f6ad662013-10-25 09:08:21 +010078 unsigned long psci_entrypoint;
Andrew Thoelke167a9352014-06-04 21:10:52 +010079 uint32_t ns_scr_el3 = read_scr_el3();
80 uint32_t ns_sctlr_el1 = read_sctlr_el1();
Achin Gupta4f6ad662013-10-25 09:08:21 +010081 int rc;
82
83 /* Sanity check to safeguard against data corruption */
84 assert(cpu_node->level == MPIDR_AFFLVL0);
85
86 /*
87 * Generic management: Ensure that the cpu is off to be
88 * turned on
89 */
Achin Gupta75f73672013-12-05 16:33:10 +000090 rc = cpu_on_validate_state(cpu_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +010091 if (rc != PSCI_E_SUCCESS)
92 return rc;
93
94 /*
Achin Gupta607084e2014-02-09 18:24:19 +000095 * Call the cpu on handler registered by the Secure Payload Dispatcher
96 * to let it do any bookeeping. If the handler encounters an error, it's
97 * expected to assert within
98 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +000099 if (psci_spd_pm && psci_spd_pm->svc_on)
100 psci_spd_pm->svc_on(target_cpu);
Achin Gupta607084e2014-02-09 18:24:19 +0000101
102 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100103 * Arch. management: Derive the re-entry information for
104 * the non-secure world from the non-secure state from
105 * where this call originated.
106 */
Andrew Thoelke167a9352014-06-04 21:10:52 +0100107 rc = psci_save_ns_entry(target_cpu, ns_entrypoint, context_id,
108 ns_scr_el3, ns_sctlr_el1);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100109 if (rc != PSCI_E_SUCCESS)
110 return rc;
111
112 /* Set the secure world (EL3) re-entry point after BL1 */
113 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
114
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100115 if (!psci_plat_pm_ops->affinst_on)
116 return PSCI_E_SUCCESS;
117
Achin Gupta4f6ad662013-10-25 09:08:21 +0100118 /*
119 * Plat. management: Give the platform the current state
120 * of the target cpu to allow it to perform the necessary
121 * steps to power on.
122 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100123 return psci_plat_pm_ops->affinst_on(target_cpu,
124 psci_entrypoint,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100125 cpu_node->level,
126 psci_get_phys_state(cpu_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100127}
128
129/*******************************************************************************
130 * Handler routine to turn a cluster on. It takes care or any generic, arch.
131 * or platform specific setup required.
132 * TODO: Split this code across separate handlers for each type of setup?
133 ******************************************************************************/
134static int psci_afflvl1_on(unsigned long target_cpu,
Dan Handleyfb037bf2014-04-10 15:37:22 +0100135 aff_map_node_t *cluster_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100136 unsigned long ns_entrypoint,
137 unsigned long context_id)
138{
Achin Gupta4f6ad662013-10-25 09:08:21 +0100139 unsigned long psci_entrypoint;
140
141 assert(cluster_node->level == MPIDR_AFFLVL1);
142
143 /*
144 * There is no generic and arch. specific cluster
145 * management required
146 */
147
Achin Gupta75f73672013-12-05 16:33:10 +0000148 /* State management: Is not required while turning a cluster on */
149
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100150 if (!psci_plat_pm_ops->affinst_on)
151 return PSCI_E_SUCCESS;
152
Achin Gupta4f6ad662013-10-25 09:08:21 +0100153 /*
154 * Plat. management: Give the platform the current state
155 * of the target cpu to allow it to perform the necessary
156 * steps to power on.
157 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100158 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
159 return psci_plat_pm_ops->affinst_on(target_cpu,
160 psci_entrypoint,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100161 cluster_node->level,
162 psci_get_phys_state(cluster_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100163}
164
165/*******************************************************************************
166 * Handler routine to turn a cluster of clusters on. It takes care or any
167 * generic, arch. or platform specific setup required.
168 * TODO: Split this code across separate handlers for each type of setup?
169 ******************************************************************************/
170static int psci_afflvl2_on(unsigned long target_cpu,
Dan Handleyfb037bf2014-04-10 15:37:22 +0100171 aff_map_node_t *system_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100172 unsigned long ns_entrypoint,
173 unsigned long context_id)
174{
Achin Gupta4f6ad662013-10-25 09:08:21 +0100175 unsigned long psci_entrypoint;
176
177 /* Cannot go beyond affinity level 2 in this psci imp. */
178 assert(system_node->level == MPIDR_AFFLVL2);
179
180 /*
181 * There is no generic and arch. specific system management
182 * required
183 */
184
Achin Gupta75f73672013-12-05 16:33:10 +0000185 /* State management: Is not required while turning a system on */
186
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100187 if (!psci_plat_pm_ops->affinst_on)
188 return PSCI_E_SUCCESS;
189
Achin Gupta4f6ad662013-10-25 09:08:21 +0100190 /*
191 * Plat. management: Give the platform the current state
192 * of the target cpu to allow it to perform the necessary
193 * steps to power on.
194 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100195 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
196 return psci_plat_pm_ops->affinst_on(target_cpu,
197 psci_entrypoint,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100198 system_node->level,
199 psci_get_phys_state(system_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100200}
201
202/* Private data structure to make this handlers accessible through indexing */
Dan Handleyfb037bf2014-04-10 15:37:22 +0100203static const afflvl_on_handler_t psci_afflvl_on_handlers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100204 psci_afflvl0_on,
205 psci_afflvl1_on,
206 psci_afflvl2_on,
207};
208
209/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000210 * This function takes an array of pointers to affinity instance nodes in the
211 * topology tree and calls the on handler for the corresponding affinity
212 * levels
213 ******************************************************************************/
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100214static int psci_call_on_handlers(aff_map_node_t *target_cpu_nodes[],
Achin Gupta0959db52013-12-02 17:33:04 +0000215 int start_afflvl,
216 int end_afflvl,
217 unsigned long target_cpu,
218 unsigned long entrypoint,
219 unsigned long context_id)
220{
221 int rc = PSCI_E_INVALID_PARAMS, level;
Dan Handleyfb037bf2014-04-10 15:37:22 +0100222 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000223
224 for (level = end_afflvl; level >= start_afflvl; level--) {
225 node = target_cpu_nodes[level];
226 if (node == NULL)
227 continue;
228
229 /*
230 * TODO: In case of an error should there be a way
231 * of undoing what we might have setup at higher
232 * affinity levels.
233 */
234 rc = psci_afflvl_on_handlers[level](target_cpu,
235 node,
236 entrypoint,
237 context_id);
238 if (rc != PSCI_E_SUCCESS)
239 break;
240 }
241
242 return rc;
243}
244
245/*******************************************************************************
246 * Generic handler which is called to physically power on a cpu identified by
247 * its mpidr. It traverses through all the affinity levels performing generic,
248 * architectural, platform setup and state management e.g. for a cpu that is
249 * to be powered on, it will ensure that enough information is stashed for it
250 * to resume execution in the non-secure security state.
251 *
252 * The state of all the relevant affinity levels is changed after calling the
253 * affinity level specific handlers as their actions would depend upon the state
254 * the affinity level is currently in.
255 *
256 * The affinity level specific handlers are called in descending order i.e. from
257 * the highest to the lowest affinity level implemented by the platform because
Soby Mathewe146f4c2014-09-26 15:08:52 +0100258 * to turn on affinity level X it is necessary to turn on affinity level X + 1
Achin Gupta0959db52013-12-02 17:33:04 +0000259 * first.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100260 ******************************************************************************/
261int psci_afflvl_on(unsigned long target_cpu,
262 unsigned long entrypoint,
263 unsigned long context_id,
Achin Gupta0959db52013-12-02 17:33:04 +0000264 int start_afflvl,
265 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100266{
Achin Gupta0959db52013-12-02 17:33:04 +0000267 int rc = PSCI_E_SUCCESS;
Dan Handleyfb037bf2014-04-10 15:37:22 +0100268 mpidr_aff_map_nodes_t target_cpu_nodes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100269
270 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000271 * Collect the pointers to the nodes in the topology tree for
272 * each affinity instance in the mpidr. If this function does
273 * not return successfully then either the mpidr or the affinity
274 * levels are incorrect.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100275 */
Achin Gupta0959db52013-12-02 17:33:04 +0000276 rc = psci_get_aff_map_nodes(target_cpu,
277 start_afflvl,
278 end_afflvl,
279 target_cpu_nodes);
280 if (rc != PSCI_E_SUCCESS)
281 return rc;
282
Achin Gupta4f6ad662013-10-25 09:08:21 +0100283
284 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000285 * This function acquires the lock corresponding to each affinity
286 * level so that by the time all locks are taken, the system topology
287 * is snapshot and state management can be done safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100288 */
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100289 psci_acquire_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000290 end_afflvl,
291 target_cpu_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100292
Achin Gupta0959db52013-12-02 17:33:04 +0000293 /* Perform generic, architecture and platform specific handling. */
294 rc = psci_call_on_handlers(target_cpu_nodes,
295 start_afflvl,
296 end_afflvl,
297 target_cpu,
298 entrypoint,
299 context_id);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100300
301 /*
Achin Gupta84c9f102014-07-28 00:09:01 +0100302 * This function updates the state of each affinity instance
303 * corresponding to the mpidr in the range of affinity levels
304 * specified.
305 */
306 if (rc == PSCI_E_SUCCESS)
307 psci_do_afflvl_state_mgmt(start_afflvl,
308 end_afflvl,
309 target_cpu_nodes,
310 PSCI_STATE_ON_PENDING);
311
312 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100313 * This loop releases the lock corresponding to each affinity level
Achin Gupta0959db52013-12-02 17:33:04 +0000314 * in the reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100315 */
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100316 psci_release_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000317 end_afflvl,
318 target_cpu_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100319
320 return rc;
321}
322
323/*******************************************************************************
324 * The following functions finish an earlier affinity power on request. They
325 * are called by the common finisher routine in psci_common.c.
326 ******************************************************************************/
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100327static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100328{
Andrew Thoelke167a9352014-06-04 21:10:52 +0100329 unsigned int plat_state, state, rc;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100330
331 assert(cpu_node->level == MPIDR_AFFLVL0);
332
Achin Gupta0959db52013-12-02 17:33:04 +0000333 /* Ensure we have been explicitly woken up by another cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000334 state = psci_get_state(cpu_node);
Achin Gupta0959db52013-12-02 17:33:04 +0000335 assert(state == PSCI_STATE_ON_PENDING);
336
Achin Gupta4f6ad662013-10-25 09:08:21 +0100337 /*
338 * Plat. management: Perform the platform specific actions
339 * for this cpu e.g. enabling the gic or zeroing the mailbox
340 * register. The actual state of this cpu has already been
341 * changed.
342 */
343 if (psci_plat_pm_ops->affinst_on_finish) {
344
Achin Gupta0959db52013-12-02 17:33:04 +0000345 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000346 plat_state = get_phys_state(state);
Soby Mathewe146f4c2014-09-26 15:08:52 +0100347 rc = psci_plat_pm_ops->affinst_on_finish(cpu_node->level,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100348 plat_state);
349 assert(rc == PSCI_E_SUCCESS);
350 }
351
352 /*
Achin Guptab51da822014-06-26 09:58:52 +0100353 * Arch. management: Enable data cache and manage stack memory
Achin Gupta4f6ad662013-10-25 09:08:21 +0100354 */
Achin Guptab51da822014-06-26 09:58:52 +0100355 psci_do_pwrup_cache_maintenance();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100356
357 /*
358 * All the platform specific actions for turning this cpu
359 * on have completed. Perform enough arch.initialization
360 * to run in the non-secure address space.
361 */
362 bl31_arch_setup();
363
364 /*
Achin Gupta607084e2014-02-09 18:24:19 +0000365 * Call the cpu on finish handler registered by the Secure Payload
366 * Dispatcher to let it do any bookeeping. If the handler encounters an
367 * error, it's expected to assert within
368 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000369 if (psci_spd_pm && psci_spd_pm->svc_on_finish)
370 psci_spd_pm->svc_on_finish(0);
Achin Gupta607084e2014-02-09 18:24:19 +0000371
372 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100373 * Generic management: Now we just need to retrieve the
374 * information that we had stashed away during the cpu_on
Andrew Thoelke167a9352014-06-04 21:10:52 +0100375 * call to set this cpu on its way.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100376 */
Andrew Thoelke167a9352014-06-04 21:10:52 +0100377 cm_prepare_el3_exit(NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100378
379 /* Clean caches before re-entering normal world */
380 dcsw_op_louis(DCCSW);
381
Andrew Thoelke167a9352014-06-04 21:10:52 +0100382 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100383 return rc;
384}
385
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100386static unsigned int psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100387{
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100388 unsigned int plat_state;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100389
390 assert(cluster_node->level == MPIDR_AFFLVL1);
391
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100392 if (!psci_plat_pm_ops->affinst_on_finish)
393 return PSCI_E_SUCCESS;
394
Achin Gupta4f6ad662013-10-25 09:08:21 +0100395 /*
396 * Plat. management: Perform the platform specific actions
397 * as per the old state of the cluster e.g. enabling
398 * coherency at the interconnect depends upon the state with
399 * which this cluster was powered up. If anything goes wrong
400 * then assert as there is no way to recover from this
401 * situation.
402 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100403 plat_state = psci_get_phys_state(cluster_node);
Soby Mathewe146f4c2014-09-26 15:08:52 +0100404 return psci_plat_pm_ops->affinst_on_finish(cluster_node->level,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100405 plat_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100406}
407
408
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100409static unsigned int psci_afflvl2_on_finish(aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100410{
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100411 unsigned int plat_state;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100412
413 /* Cannot go beyond this affinity level */
414 assert(system_node->level == MPIDR_AFFLVL2);
415
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100416 if (!psci_plat_pm_ops->affinst_on_finish)
417 return PSCI_E_SUCCESS;
418
Achin Gupta4f6ad662013-10-25 09:08:21 +0100419 /*
420 * Currently, there are no architectural actions to perform
421 * at the system level.
422 */
423
424 /*
425 * Plat. management: Perform the platform specific actions
426 * as per the old state of the cluster e.g. enabling
427 * coherency at the interconnect depends upon the state with
428 * which this cluster was powered up. If anything goes wrong
429 * then assert as there is no way to recover from this
430 * situation.
431 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100432 plat_state = psci_get_phys_state(system_node);
Soby Mathewe146f4c2014-09-26 15:08:52 +0100433 return psci_plat_pm_ops->affinst_on_finish(system_node->level,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100434 plat_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100435}
436
Dan Handleyfb037bf2014-04-10 15:37:22 +0100437const afflvl_power_on_finisher_t psci_afflvl_on_finishers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100438 psci_afflvl0_on_finish,
439 psci_afflvl1_on_finish,
440 psci_afflvl2_on_finish,
441};