blob: 04529d2fc86a5f51490f0d76103b628ecc6af126 [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 ******************************************************************************/
Soby Mathew2f5aade2015-01-12 13:01:31 +000051static int cpu_on_validate_state(unsigned int psci_state)
Achin Gupta4f6ad662013-10-25 09:08:21 +010052{
Achin Gupta4f6ad662013-10-25 09:08:21 +010053 if (psci_state == PSCI_STATE_ON || psci_state == PSCI_STATE_SUSPEND)
54 return PSCI_E_ALREADY_ON;
55
56 if (psci_state == PSCI_STATE_ON_PENDING)
57 return PSCI_E_ON_PENDING;
58
59 assert(psci_state == PSCI_STATE_OFF);
60 return PSCI_E_SUCCESS;
61}
62
63/*******************************************************************************
64 * Handler routine to turn a cpu on. It takes care of any generic, architectural
65 * or platform specific setup required.
66 * TODO: Split this code across separate handlers for each type of setup?
67 ******************************************************************************/
68static int psci_afflvl0_on(unsigned long target_cpu,
Dan Handleyfb037bf2014-04-10 15:37:22 +010069 aff_map_node_t *cpu_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +010070 unsigned long ns_entrypoint,
71 unsigned long context_id)
72{
Achin Gupta4f6ad662013-10-25 09:08:21 +010073 unsigned long psci_entrypoint;
Andrew Thoelke167a9352014-06-04 21:10:52 +010074 uint32_t ns_scr_el3 = read_scr_el3();
75 uint32_t ns_sctlr_el1 = read_sctlr_el1();
Achin Gupta4f6ad662013-10-25 09:08:21 +010076 int rc;
77
78 /* Sanity check to safeguard against data corruption */
79 assert(cpu_node->level == MPIDR_AFFLVL0);
80
81 /*
Achin Gupta607084e2014-02-09 18:24:19 +000082 * Call the cpu on handler registered by the Secure Payload Dispatcher
83 * to let it do any bookeeping. If the handler encounters an error, it's
84 * expected to assert within
85 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +000086 if (psci_spd_pm && psci_spd_pm->svc_on)
87 psci_spd_pm->svc_on(target_cpu);
Achin Gupta607084e2014-02-09 18:24:19 +000088
89 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +010090 * Arch. management: Derive the re-entry information for
91 * the non-secure world from the non-secure state from
92 * where this call originated.
93 */
Andrew Thoelke167a9352014-06-04 21:10:52 +010094 rc = psci_save_ns_entry(target_cpu, ns_entrypoint, context_id,
95 ns_scr_el3, ns_sctlr_el1);
Achin Gupta4f6ad662013-10-25 09:08:21 +010096 if (rc != PSCI_E_SUCCESS)
97 return rc;
98
99 /* Set the secure world (EL3) re-entry point after BL1 */
100 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
101
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100102 if (!psci_plat_pm_ops->affinst_on)
103 return PSCI_E_SUCCESS;
104
Achin Gupta4f6ad662013-10-25 09:08:21 +0100105 /*
106 * Plat. management: Give the platform the current state
107 * of the target cpu to allow it to perform the necessary
108 * steps to power on.
109 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100110 return psci_plat_pm_ops->affinst_on(target_cpu,
111 psci_entrypoint,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100112 cpu_node->level,
113 psci_get_phys_state(cpu_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100114}
115
116/*******************************************************************************
117 * Handler routine to turn a cluster on. It takes care or any generic, arch.
118 * or platform specific setup required.
119 * TODO: Split this code across separate handlers for each type of setup?
120 ******************************************************************************/
121static int psci_afflvl1_on(unsigned long target_cpu,
Dan Handleyfb037bf2014-04-10 15:37:22 +0100122 aff_map_node_t *cluster_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100123 unsigned long ns_entrypoint,
124 unsigned long context_id)
125{
Achin Gupta4f6ad662013-10-25 09:08:21 +0100126 unsigned long psci_entrypoint;
127
128 assert(cluster_node->level == MPIDR_AFFLVL1);
129
130 /*
131 * There is no generic and arch. specific cluster
132 * management required
133 */
134
Achin Gupta75f73672013-12-05 16:33:10 +0000135 /* State management: Is not required while turning a cluster on */
136
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100137 if (!psci_plat_pm_ops->affinst_on)
138 return PSCI_E_SUCCESS;
139
Achin Gupta4f6ad662013-10-25 09:08:21 +0100140 /*
141 * Plat. management: Give the platform the current state
142 * of the target cpu to allow it to perform the necessary
143 * steps to power on.
144 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100145 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
146 return psci_plat_pm_ops->affinst_on(target_cpu,
147 psci_entrypoint,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100148 cluster_node->level,
149 psci_get_phys_state(cluster_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100150}
151
152/*******************************************************************************
153 * Handler routine to turn a cluster of clusters on. It takes care or any
154 * generic, arch. or platform specific setup required.
155 * TODO: Split this code across separate handlers for each type of setup?
156 ******************************************************************************/
157static int psci_afflvl2_on(unsigned long target_cpu,
Dan Handleyfb037bf2014-04-10 15:37:22 +0100158 aff_map_node_t *system_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100159 unsigned long ns_entrypoint,
160 unsigned long context_id)
161{
Achin Gupta4f6ad662013-10-25 09:08:21 +0100162 unsigned long psci_entrypoint;
163
164 /* Cannot go beyond affinity level 2 in this psci imp. */
165 assert(system_node->level == MPIDR_AFFLVL2);
166
167 /*
168 * There is no generic and arch. specific system management
169 * required
170 */
171
Achin Gupta75f73672013-12-05 16:33:10 +0000172 /* State management: Is not required while turning a system on */
173
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100174 if (!psci_plat_pm_ops->affinst_on)
175 return PSCI_E_SUCCESS;
176
Achin Gupta4f6ad662013-10-25 09:08:21 +0100177 /*
178 * Plat. management: Give the platform the current state
179 * of the target cpu to allow it to perform the necessary
180 * steps to power on.
181 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100182 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
183 return psci_plat_pm_ops->affinst_on(target_cpu,
184 psci_entrypoint,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100185 system_node->level,
186 psci_get_phys_state(system_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100187}
188
189/* Private data structure to make this handlers accessible through indexing */
Dan Handleyfb037bf2014-04-10 15:37:22 +0100190static const afflvl_on_handler_t psci_afflvl_on_handlers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100191 psci_afflvl0_on,
192 psci_afflvl1_on,
193 psci_afflvl2_on,
194};
195
196/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000197 * This function takes an array of pointers to affinity instance nodes in the
198 * topology tree and calls the on handler for the corresponding affinity
199 * levels
200 ******************************************************************************/
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100201static int psci_call_on_handlers(aff_map_node_t *target_cpu_nodes[],
Achin Gupta0959db52013-12-02 17:33:04 +0000202 int start_afflvl,
203 int end_afflvl,
204 unsigned long target_cpu,
205 unsigned long entrypoint,
206 unsigned long context_id)
207{
208 int rc = PSCI_E_INVALID_PARAMS, level;
Dan Handleyfb037bf2014-04-10 15:37:22 +0100209 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000210
211 for (level = end_afflvl; level >= start_afflvl; level--) {
212 node = target_cpu_nodes[level];
213 if (node == NULL)
214 continue;
215
216 /*
217 * TODO: In case of an error should there be a way
218 * of undoing what we might have setup at higher
219 * affinity levels.
220 */
221 rc = psci_afflvl_on_handlers[level](target_cpu,
222 node,
223 entrypoint,
224 context_id);
225 if (rc != PSCI_E_SUCCESS)
226 break;
227 }
228
229 return rc;
230}
231
232/*******************************************************************************
233 * Generic handler which is called to physically power on a cpu identified by
234 * its mpidr. It traverses through all the affinity levels performing generic,
235 * architectural, platform setup and state management e.g. for a cpu that is
236 * to be powered on, it will ensure that enough information is stashed for it
237 * to resume execution in the non-secure security state.
238 *
239 * The state of all the relevant affinity levels is changed after calling the
240 * affinity level specific handlers as their actions would depend upon the state
241 * the affinity level is currently in.
242 *
243 * The affinity level specific handlers are called in descending order i.e. from
244 * the highest to the lowest affinity level implemented by the platform because
Soby Mathewe146f4c2014-09-26 15:08:52 +0100245 * to turn on affinity level X it is necessary to turn on affinity level X + 1
Achin Gupta0959db52013-12-02 17:33:04 +0000246 * first.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100247 ******************************************************************************/
248int psci_afflvl_on(unsigned long target_cpu,
249 unsigned long entrypoint,
250 unsigned long context_id,
Achin Gupta0959db52013-12-02 17:33:04 +0000251 int start_afflvl,
252 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100253{
Achin Gupta0959db52013-12-02 17:33:04 +0000254 int rc = PSCI_E_SUCCESS;
Dan Handleyfb037bf2014-04-10 15:37:22 +0100255 mpidr_aff_map_nodes_t target_cpu_nodes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100256
257 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000258 * Collect the pointers to the nodes in the topology tree for
259 * each affinity instance in the mpidr. If this function does
260 * not return successfully then either the mpidr or the affinity
261 * levels are incorrect.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100262 */
Achin Gupta0959db52013-12-02 17:33:04 +0000263 rc = psci_get_aff_map_nodes(target_cpu,
264 start_afflvl,
265 end_afflvl,
266 target_cpu_nodes);
267 if (rc != PSCI_E_SUCCESS)
268 return rc;
269
Achin Gupta4f6ad662013-10-25 09:08:21 +0100270
271 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000272 * This function acquires the lock corresponding to each affinity
273 * level so that by the time all locks are taken, the system topology
274 * is snapshot and state management can be done safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100275 */
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100276 psci_acquire_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000277 end_afflvl,
278 target_cpu_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100279
Soby Mathew2f5aade2015-01-12 13:01:31 +0000280 /*
281 * Generic management: Ensure that the cpu is off to be
282 * turned on.
283 */
284 rc = cpu_on_validate_state(psci_get_state(
285 (aff_map_node_t *)target_cpu_nodes[MPIDR_AFFLVL0]));
286 if (rc != PSCI_E_SUCCESS)
287 goto exit;
288
Achin Gupta0959db52013-12-02 17:33:04 +0000289 /* Perform generic, architecture and platform specific handling. */
290 rc = psci_call_on_handlers(target_cpu_nodes,
291 start_afflvl,
292 end_afflvl,
293 target_cpu,
294 entrypoint,
295 context_id);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100296
297 /*
Achin Gupta84c9f102014-07-28 00:09:01 +0100298 * This function updates the state of each affinity instance
299 * corresponding to the mpidr in the range of affinity levels
300 * specified.
301 */
302 if (rc == PSCI_E_SUCCESS)
303 psci_do_afflvl_state_mgmt(start_afflvl,
304 end_afflvl,
305 target_cpu_nodes,
306 PSCI_STATE_ON_PENDING);
307
Soby Mathew2f5aade2015-01-12 13:01:31 +0000308exit:
Achin Gupta84c9f102014-07-28 00:09:01 +0100309 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100310 * This loop releases the lock corresponding to each affinity level
Achin Gupta0959db52013-12-02 17:33:04 +0000311 * in the reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100312 */
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100313 psci_release_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000314 end_afflvl,
315 target_cpu_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100316
317 return rc;
318}
319
320/*******************************************************************************
321 * The following functions finish an earlier affinity power on request. They
322 * are called by the common finisher routine in psci_common.c.
323 ******************************************************************************/
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100324static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100325{
Andrew Thoelke167a9352014-06-04 21:10:52 +0100326 unsigned int plat_state, state, rc;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100327
328 assert(cpu_node->level == MPIDR_AFFLVL0);
329
Achin Gupta0959db52013-12-02 17:33:04 +0000330 /* Ensure we have been explicitly woken up by another cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000331 state = psci_get_state(cpu_node);
Achin Gupta0959db52013-12-02 17:33:04 +0000332 assert(state == PSCI_STATE_ON_PENDING);
333
Achin Gupta4f6ad662013-10-25 09:08:21 +0100334 /*
335 * Plat. management: Perform the platform specific actions
336 * for this cpu e.g. enabling the gic or zeroing the mailbox
337 * register. The actual state of this cpu has already been
338 * changed.
339 */
340 if (psci_plat_pm_ops->affinst_on_finish) {
341
Achin Gupta0959db52013-12-02 17:33:04 +0000342 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000343 plat_state = get_phys_state(state);
Soby Mathewe146f4c2014-09-26 15:08:52 +0100344 rc = psci_plat_pm_ops->affinst_on_finish(cpu_node->level,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100345 plat_state);
346 assert(rc == PSCI_E_SUCCESS);
347 }
348
349 /*
Achin Guptab51da822014-06-26 09:58:52 +0100350 * Arch. management: Enable data cache and manage stack memory
Achin Gupta4f6ad662013-10-25 09:08:21 +0100351 */
Achin Guptab51da822014-06-26 09:58:52 +0100352 psci_do_pwrup_cache_maintenance();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100353
354 /*
355 * All the platform specific actions for turning this cpu
356 * on have completed. Perform enough arch.initialization
357 * to run in the non-secure address space.
358 */
359 bl31_arch_setup();
360
361 /*
Achin Gupta607084e2014-02-09 18:24:19 +0000362 * Call the cpu on finish handler registered by the Secure Payload
363 * Dispatcher to let it do any bookeeping. If the handler encounters an
364 * error, it's expected to assert within
365 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000366 if (psci_spd_pm && psci_spd_pm->svc_on_finish)
367 psci_spd_pm->svc_on_finish(0);
Achin Gupta607084e2014-02-09 18:24:19 +0000368
369 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100370 * Generic management: Now we just need to retrieve the
371 * information that we had stashed away during the cpu_on
Andrew Thoelke167a9352014-06-04 21:10:52 +0100372 * call to set this cpu on its way.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100373 */
Andrew Thoelke167a9352014-06-04 21:10:52 +0100374 cm_prepare_el3_exit(NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100375
376 /* Clean caches before re-entering normal world */
377 dcsw_op_louis(DCCSW);
378
Andrew Thoelke167a9352014-06-04 21:10:52 +0100379 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100380 return rc;
381}
382
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100383static unsigned int psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100384{
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100385 unsigned int plat_state;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100386
387 assert(cluster_node->level == MPIDR_AFFLVL1);
388
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100389 if (!psci_plat_pm_ops->affinst_on_finish)
390 return PSCI_E_SUCCESS;
391
Achin Gupta4f6ad662013-10-25 09:08:21 +0100392 /*
393 * Plat. management: Perform the platform specific actions
394 * as per the old state of the cluster e.g. enabling
395 * coherency at the interconnect depends upon the state with
396 * which this cluster was powered up. If anything goes wrong
397 * then assert as there is no way to recover from this
398 * situation.
399 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100400 plat_state = psci_get_phys_state(cluster_node);
Soby Mathewe146f4c2014-09-26 15:08:52 +0100401 return psci_plat_pm_ops->affinst_on_finish(cluster_node->level,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100402 plat_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100403}
404
405
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100406static unsigned int psci_afflvl2_on_finish(aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100407{
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100408 unsigned int plat_state;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100409
410 /* Cannot go beyond this affinity level */
411 assert(system_node->level == MPIDR_AFFLVL2);
412
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100413 if (!psci_plat_pm_ops->affinst_on_finish)
414 return PSCI_E_SUCCESS;
415
Achin Gupta4f6ad662013-10-25 09:08:21 +0100416 /*
417 * Currently, there are no architectural actions to perform
418 * at the system level.
419 */
420
421 /*
422 * Plat. management: Perform the platform specific actions
423 * as per the old state of the cluster e.g. enabling
424 * coherency at the interconnect depends upon the state with
425 * which this cluster was powered up. If anything goes wrong
426 * then assert as there is no way to recover from this
427 * situation.
428 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100429 plat_state = psci_get_phys_state(system_node);
Soby Mathewe146f4c2014-09-26 15:08:52 +0100430 return psci_plat_pm_ops->affinst_on_finish(system_node->level,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100431 plat_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100432}
433
Dan Handleyfb037bf2014-04-10 15:37:22 +0100434const afflvl_power_on_finisher_t psci_afflvl_on_finishers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100435 psci_afflvl0_on_finish,
436 psci_afflvl1_on_finish,
437 psci_afflvl2_on_finish,
438};