blob: 9f4ebf6bcc67a5c04b1312b716be41b806db11af [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 Handley2bd4ef22014-04-09 13:14:54 +010031#include <arch.h>
32#include <arch_helpers.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010033#include <assert.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010034#include <bl_common.h>
Dan Handleybcd60ba2014-04-17 18:53:42 +010035#include <bl31.h>
Achin Gupta0a9f7472014-02-09 17:48:12 +000036#include <context_mgmt.h>
Dan Handleybcd60ba2014-04-17 18:53:42 +010037#include <runtime_svc.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010038#include <stddef.h>
Dan Handley714a0d22014-04-09 13:13:04 +010039#include "psci_private.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010040
Dan Handleye2712bc2014-04-10 15:37:22 +010041typedef int (*afflvl_on_handler_t)(unsigned long,
42 aff_map_node_t *,
Achin Gupta4f6ad662013-10-25 09:08:21 +010043 unsigned long,
44 unsigned long);
45
46/*******************************************************************************
47 * This function checks whether a cpu which has been requested to be turned on
48 * is OFF to begin with.
49 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +010050static int cpu_on_validate_state(aff_map_node_t *node)
Achin Gupta4f6ad662013-10-25 09:08:21 +010051{
52 unsigned int psci_state;
53
54 /* Get the raw psci state */
Achin Gupta75f73672013-12-05 16:33:10 +000055 psci_state = psci_get_state(node);
Achin Gupta4f6ad662013-10-25 09:08:21 +010056
57 if (psci_state == PSCI_STATE_ON || psci_state == PSCI_STATE_SUSPEND)
58 return PSCI_E_ALREADY_ON;
59
60 if (psci_state == PSCI_STATE_ON_PENDING)
61 return PSCI_E_ON_PENDING;
62
63 assert(psci_state == PSCI_STATE_OFF);
64 return PSCI_E_SUCCESS;
65}
66
67/*******************************************************************************
68 * Handler routine to turn a cpu on. It takes care of any generic, architectural
69 * or platform specific setup required.
70 * TODO: Split this code across separate handlers for each type of setup?
71 ******************************************************************************/
72static int psci_afflvl0_on(unsigned long target_cpu,
Dan Handleye2712bc2014-04-10 15:37:22 +010073 aff_map_node_t *cpu_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +010074 unsigned long ns_entrypoint,
75 unsigned long context_id)
76{
77 unsigned int index, plat_state;
78 unsigned long psci_entrypoint;
79 int rc;
80
81 /* Sanity check to safeguard against data corruption */
82 assert(cpu_node->level == MPIDR_AFFLVL0);
83
84 /*
85 * Generic management: Ensure that the cpu is off to be
86 * turned on
87 */
Achin Gupta75f73672013-12-05 16:33:10 +000088 rc = cpu_on_validate_state(cpu_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +010089 if (rc != PSCI_E_SUCCESS)
90 return rc;
91
92 /*
Achin Gupta607084e2014-02-09 18:24:19 +000093 * Call the cpu on handler registered by the Secure Payload Dispatcher
94 * to let it do any bookeeping. If the handler encounters an error, it's
95 * expected to assert within
96 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +000097 if (psci_spd_pm && psci_spd_pm->svc_on)
98 psci_spd_pm->svc_on(target_cpu);
Achin Gupta607084e2014-02-09 18:24:19 +000099
100 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100101 * Arch. management: Derive the re-entry information for
102 * the non-secure world from the non-secure state from
103 * where this call originated.
104 */
105 index = cpu_node->data;
106 rc = psci_set_ns_entry_info(index, ns_entrypoint, context_id);
107 if (rc != PSCI_E_SUCCESS)
108 return rc;
109
110 /* Set the secure world (EL3) re-entry point after BL1 */
111 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
112
Achin Gupta75f73672013-12-05 16:33:10 +0000113 /* State management: Set this cpu's state as ON PENDING */
114 psci_set_state(cpu_node, PSCI_STATE_ON_PENDING);
115
Achin Gupta4f6ad662013-10-25 09:08:21 +0100116 /*
117 * Plat. management: Give the platform the current state
118 * of the target cpu to allow it to perform the necessary
119 * steps to power on.
120 */
121 if (psci_plat_pm_ops->affinst_on) {
122
123 /* Get the current physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000124 plat_state = psci_get_phys_state(cpu_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100125 rc = psci_plat_pm_ops->affinst_on(target_cpu,
126 psci_entrypoint,
127 ns_entrypoint,
128 cpu_node->level,
129 plat_state);
130 }
131
132 return rc;
133}
134
135/*******************************************************************************
136 * Handler routine to turn a cluster on. It takes care or any generic, arch.
137 * or platform specific setup required.
138 * TODO: Split this code across separate handlers for each type of setup?
139 ******************************************************************************/
140static int psci_afflvl1_on(unsigned long target_cpu,
Dan Handleye2712bc2014-04-10 15:37:22 +0100141 aff_map_node_t *cluster_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100142 unsigned long ns_entrypoint,
143 unsigned long context_id)
144{
145 int rc = PSCI_E_SUCCESS;
146 unsigned int plat_state;
147 unsigned long psci_entrypoint;
148
149 assert(cluster_node->level == MPIDR_AFFLVL1);
150
151 /*
152 * There is no generic and arch. specific cluster
153 * management required
154 */
155
Achin Gupta75f73672013-12-05 16:33:10 +0000156 /* State management: Is not required while turning a cluster on */
157
Achin Gupta4f6ad662013-10-25 09:08:21 +0100158 /*
159 * Plat. management: Give the platform the current state
160 * of the target cpu to allow it to perform the necessary
161 * steps to power on.
162 */
163 if (psci_plat_pm_ops->affinst_on) {
Achin Gupta75f73672013-12-05 16:33:10 +0000164 plat_state = psci_get_phys_state(cluster_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100165 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
166 rc = psci_plat_pm_ops->affinst_on(target_cpu,
167 psci_entrypoint,
168 ns_entrypoint,
169 cluster_node->level,
170 plat_state);
171 }
172
173 return rc;
174}
175
176/*******************************************************************************
177 * Handler routine to turn a cluster of clusters on. It takes care or any
178 * generic, arch. or platform specific setup required.
179 * TODO: Split this code across separate handlers for each type of setup?
180 ******************************************************************************/
181static int psci_afflvl2_on(unsigned long target_cpu,
Dan Handleye2712bc2014-04-10 15:37:22 +0100182 aff_map_node_t *system_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100183 unsigned long ns_entrypoint,
184 unsigned long context_id)
185{
186 int rc = PSCI_E_SUCCESS;
187 unsigned int plat_state;
188 unsigned long psci_entrypoint;
189
190 /* Cannot go beyond affinity level 2 in this psci imp. */
191 assert(system_node->level == MPIDR_AFFLVL2);
192
193 /*
194 * There is no generic and arch. specific system management
195 * required
196 */
197
Achin Gupta75f73672013-12-05 16:33:10 +0000198 /* State management: Is not required while turning a system on */
199
Achin Gupta4f6ad662013-10-25 09:08:21 +0100200 /*
201 * Plat. management: Give the platform the current state
202 * of the target cpu to allow it to perform the necessary
203 * steps to power on.
204 */
205 if (psci_plat_pm_ops->affinst_on) {
Achin Gupta75f73672013-12-05 16:33:10 +0000206 plat_state = psci_get_phys_state(system_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100207 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
208 rc = psci_plat_pm_ops->affinst_on(target_cpu,
209 psci_entrypoint,
210 ns_entrypoint,
211 system_node->level,
212 plat_state);
213 }
214
215 return rc;
216}
217
218/* Private data structure to make this handlers accessible through indexing */
Dan Handleye2712bc2014-04-10 15:37:22 +0100219static const afflvl_on_handler_t psci_afflvl_on_handlers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100220 psci_afflvl0_on,
221 psci_afflvl1_on,
222 psci_afflvl2_on,
223};
224
225/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000226 * This function takes an array of pointers to affinity instance nodes in the
227 * topology tree and calls the on handler for the corresponding affinity
228 * levels
229 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +0100230static int psci_call_on_handlers(mpidr_aff_map_nodes_t target_cpu_nodes,
Achin Gupta0959db52013-12-02 17:33:04 +0000231 int start_afflvl,
232 int end_afflvl,
233 unsigned long target_cpu,
234 unsigned long entrypoint,
235 unsigned long context_id)
236{
237 int rc = PSCI_E_INVALID_PARAMS, level;
Dan Handleye2712bc2014-04-10 15:37:22 +0100238 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000239
240 for (level = end_afflvl; level >= start_afflvl; level--) {
241 node = target_cpu_nodes[level];
242 if (node == NULL)
243 continue;
244
245 /*
246 * TODO: In case of an error should there be a way
247 * of undoing what we might have setup at higher
248 * affinity levels.
249 */
250 rc = psci_afflvl_on_handlers[level](target_cpu,
251 node,
252 entrypoint,
253 context_id);
254 if (rc != PSCI_E_SUCCESS)
255 break;
256 }
257
258 return rc;
259}
260
261/*******************************************************************************
262 * Generic handler which is called to physically power on a cpu identified by
263 * its mpidr. It traverses through all the affinity levels performing generic,
264 * architectural, platform setup and state management e.g. for a cpu that is
265 * to be powered on, it will ensure that enough information is stashed for it
266 * to resume execution in the non-secure security state.
267 *
268 * The state of all the relevant affinity levels is changed after calling the
269 * affinity level specific handlers as their actions would depend upon the state
270 * the affinity level is currently in.
271 *
272 * The affinity level specific handlers are called in descending order i.e. from
273 * the highest to the lowest affinity level implemented by the platform because
274 * to turn on affinity level X it is neccesary to turn on affinity level X + 1
275 * first.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100276 ******************************************************************************/
277int psci_afflvl_on(unsigned long target_cpu,
278 unsigned long entrypoint,
279 unsigned long context_id,
Achin Gupta0959db52013-12-02 17:33:04 +0000280 int start_afflvl,
281 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100282{
Achin Gupta0959db52013-12-02 17:33:04 +0000283 int rc = PSCI_E_SUCCESS;
Dan Handleye2712bc2014-04-10 15:37:22 +0100284 mpidr_aff_map_nodes_t target_cpu_nodes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100285 unsigned long mpidr = read_mpidr() & MPIDR_AFFINITY_MASK;
286
287 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000288 * Collect the pointers to the nodes in the topology tree for
289 * each affinity instance in the mpidr. If this function does
290 * not return successfully then either the mpidr or the affinity
291 * levels are incorrect.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100292 */
Achin Gupta0959db52013-12-02 17:33:04 +0000293 rc = psci_get_aff_map_nodes(target_cpu,
294 start_afflvl,
295 end_afflvl,
296 target_cpu_nodes);
297 if (rc != PSCI_E_SUCCESS)
298 return rc;
299
Achin Gupta4f6ad662013-10-25 09:08:21 +0100300
301 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000302 * This function acquires the lock corresponding to each affinity
303 * level so that by the time all locks are taken, the system topology
304 * is snapshot and state management can be done safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100305 */
Achin Gupta0959db52013-12-02 17:33:04 +0000306 psci_acquire_afflvl_locks(mpidr,
307 start_afflvl,
308 end_afflvl,
309 target_cpu_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100310
Achin Gupta0959db52013-12-02 17:33:04 +0000311 /* Perform generic, architecture and platform specific handling. */
312 rc = psci_call_on_handlers(target_cpu_nodes,
313 start_afflvl,
314 end_afflvl,
315 target_cpu,
316 entrypoint,
317 context_id);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100318
Achin Gupta4f6ad662013-10-25 09:08:21 +0100319 /*
320 * This loop releases the lock corresponding to each affinity level
Achin Gupta0959db52013-12-02 17:33:04 +0000321 * in the reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100322 */
Achin Gupta0959db52013-12-02 17:33:04 +0000323 psci_release_afflvl_locks(mpidr,
324 start_afflvl,
325 end_afflvl,
326 target_cpu_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100327
328 return rc;
329}
330
331/*******************************************************************************
332 * The following functions finish an earlier affinity power on request. They
333 * are called by the common finisher routine in psci_common.c.
334 ******************************************************************************/
335static unsigned int psci_afflvl0_on_finish(unsigned long mpidr,
Dan Handleye2712bc2014-04-10 15:37:22 +0100336 aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100337{
Achin Gupta0959db52013-12-02 17:33:04 +0000338 unsigned int index, plat_state, state, rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100339
340 assert(cpu_node->level == MPIDR_AFFLVL0);
341
Achin Gupta0959db52013-12-02 17:33:04 +0000342 /* Ensure we have been explicitly woken up by another cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000343 state = psci_get_state(cpu_node);
Achin Gupta0959db52013-12-02 17:33:04 +0000344 assert(state == PSCI_STATE_ON_PENDING);
345
Achin Gupta4f6ad662013-10-25 09:08:21 +0100346 /*
347 * Plat. management: Perform the platform specific actions
348 * for this cpu e.g. enabling the gic or zeroing the mailbox
349 * register. The actual state of this cpu has already been
350 * changed.
351 */
352 if (psci_plat_pm_ops->affinst_on_finish) {
353
Achin Gupta0959db52013-12-02 17:33:04 +0000354 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000355 plat_state = get_phys_state(state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100356 rc = psci_plat_pm_ops->affinst_on_finish(mpidr,
357 cpu_node->level,
358 plat_state);
359 assert(rc == PSCI_E_SUCCESS);
360 }
361
362 /*
363 * Arch. management: Turn on mmu & restore architectural state
364 */
Sandrine Bailleux74a62b32014-05-09 11:35:36 +0100365 enable_mmu_el3();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100366
367 /*
368 * All the platform specific actions for turning this cpu
369 * on have completed. Perform enough arch.initialization
370 * to run in the non-secure address space.
371 */
372 bl31_arch_setup();
373
374 /*
Achin Gupta607084e2014-02-09 18:24:19 +0000375 * Use the more complex exception vectors to enable SPD
376 * initialisation. SP_EL3 should point to a 'cpu_context'
377 * structure which has an exception stack allocated. The
378 * calling cpu should have set the context already
379 */
380 assert(cm_get_context(mpidr, NON_SECURE));
381 cm_set_next_eret_context(NON_SECURE);
382 write_vbar_el3((uint64_t) runtime_exceptions);
383
384 /*
385 * Call the cpu on finish handler registered by the Secure Payload
386 * Dispatcher to let it do any bookeeping. If the handler encounters an
387 * error, it's expected to assert within
388 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000389 if (psci_spd_pm && psci_spd_pm->svc_on_finish)
390 psci_spd_pm->svc_on_finish(0);
Achin Gupta607084e2014-02-09 18:24:19 +0000391
392 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100393 * Generic management: Now we just need to retrieve the
394 * information that we had stashed away during the cpu_on
Achin Gupta3140a9e2013-12-02 16:23:12 +0000395 * call to set this cpu on its way. First get the index
Achin Gupta4f6ad662013-10-25 09:08:21 +0100396 * for restoring the re-entry info
397 */
398 index = cpu_node->data;
Achin Guptac8afc782013-11-25 18:45:02 +0000399 psci_get_ns_entry_info(index);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100400
Achin Gupta75f73672013-12-05 16:33:10 +0000401 /* State management: mark this cpu as on */
402 psci_set_state(cpu_node, PSCI_STATE_ON);
403
Achin Gupta4f6ad662013-10-25 09:08:21 +0100404 /* Clean caches before re-entering normal world */
405 dcsw_op_louis(DCCSW);
406
407 return rc;
408}
409
410static unsigned int psci_afflvl1_on_finish(unsigned long mpidr,
Dan Handleye2712bc2014-04-10 15:37:22 +0100411 aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100412{
Achin Gupta0959db52013-12-02 17:33:04 +0000413 unsigned int plat_state, rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100414
415 assert(cluster_node->level == MPIDR_AFFLVL1);
416
417 /*
418 * Plat. management: Perform the platform specific actions
419 * as per the old state of the cluster e.g. enabling
420 * coherency at the interconnect depends upon the state with
421 * which this cluster was powered up. If anything goes wrong
422 * then assert as there is no way to recover from this
423 * situation.
424 */
425 if (psci_plat_pm_ops->affinst_on_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000426
427 /* Get the physical state of this cluster */
Achin Gupta75f73672013-12-05 16:33:10 +0000428 plat_state = psci_get_phys_state(cluster_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100429 rc = psci_plat_pm_ops->affinst_on_finish(mpidr,
430 cluster_node->level,
431 plat_state);
432 assert(rc == PSCI_E_SUCCESS);
433 }
434
Achin Gupta75f73672013-12-05 16:33:10 +0000435 /* State management: Increment the cluster reference count */
436 psci_set_state(cluster_node, PSCI_STATE_ON);
437
Achin Gupta4f6ad662013-10-25 09:08:21 +0100438 return rc;
439}
440
441
442static unsigned int psci_afflvl2_on_finish(unsigned long mpidr,
Dan Handleye2712bc2014-04-10 15:37:22 +0100443 aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100444{
Achin Gupta0959db52013-12-02 17:33:04 +0000445 unsigned int plat_state, rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100446
447 /* Cannot go beyond this affinity level */
448 assert(system_node->level == MPIDR_AFFLVL2);
449
450 /*
451 * Currently, there are no architectural actions to perform
452 * at the system level.
453 */
454
455 /*
456 * Plat. management: Perform the platform specific actions
457 * as per the old state of the cluster e.g. enabling
458 * coherency at the interconnect depends upon the state with
459 * which this cluster was powered up. If anything goes wrong
460 * then assert as there is no way to recover from this
461 * situation.
462 */
463 if (psci_plat_pm_ops->affinst_on_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000464
465 /* Get the physical state of the system */
Achin Gupta75f73672013-12-05 16:33:10 +0000466 plat_state = psci_get_phys_state(system_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100467 rc = psci_plat_pm_ops->affinst_on_finish(mpidr,
468 system_node->level,
469 plat_state);
470 assert(rc == PSCI_E_SUCCESS);
471 }
472
Achin Gupta75f73672013-12-05 16:33:10 +0000473 /* State management: Increment the system reference count */
474 psci_set_state(system_node, PSCI_STATE_ON);
475
Achin Gupta4f6ad662013-10-25 09:08:21 +0100476 return rc;
477}
478
Dan Handleye2712bc2014-04-10 15:37:22 +0100479const afflvl_power_on_finisher_t psci_afflvl_on_finishers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100480 psci_afflvl0_on_finish,
481 psci_afflvl1_on_finish,
482 psci_afflvl2_on_finish,
483};
484