blob: b778c5ee8f273fd9ac858c1f1b3e3fe2b6a7c7bb [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,
Soby Mathew78879b92015-01-06 15:36:38 +000043 aff_map_node_t *node);
Achin Gupta4f6ad662013-10-25 09:08:21 +010044
45/*******************************************************************************
46 * This function checks whether a cpu which has been requested to be turned on
47 * is OFF to begin with.
48 ******************************************************************************/
Soby Mathew2f5aade2015-01-12 13:01:31 +000049static int cpu_on_validate_state(unsigned int psci_state)
Achin Gupta4f6ad662013-10-25 09:08:21 +010050{
Achin Gupta4f6ad662013-10-25 09:08:21 +010051 if (psci_state == PSCI_STATE_ON || psci_state == PSCI_STATE_SUSPEND)
52 return PSCI_E_ALREADY_ON;
53
54 if (psci_state == PSCI_STATE_ON_PENDING)
55 return PSCI_E_ON_PENDING;
56
57 assert(psci_state == PSCI_STATE_OFF);
58 return PSCI_E_SUCCESS;
59}
60
61/*******************************************************************************
62 * Handler routine to turn a cpu on. It takes care of any generic, architectural
63 * or platform specific setup required.
64 * TODO: Split this code across separate handlers for each type of setup?
65 ******************************************************************************/
66static int psci_afflvl0_on(unsigned long target_cpu,
Soby Mathew78879b92015-01-06 15:36:38 +000067 aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +010068{
Achin Gupta4f6ad662013-10-25 09:08:21 +010069 unsigned long psci_entrypoint;
Achin Gupta4f6ad662013-10-25 09:08:21 +010070
71 /* Sanity check to safeguard against data corruption */
72 assert(cpu_node->level == MPIDR_AFFLVL0);
73
74 /*
Achin Gupta607084e2014-02-09 18:24:19 +000075 * Call the cpu on handler registered by the Secure Payload Dispatcher
76 * to let it do any bookeeping. If the handler encounters an error, it's
77 * expected to assert within
78 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +000079 if (psci_spd_pm && psci_spd_pm->svc_on)
80 psci_spd_pm->svc_on(target_cpu);
Achin Gupta607084e2014-02-09 18:24:19 +000081
Achin Gupta4f6ad662013-10-25 09:08:21 +010082 /* Set the secure world (EL3) re-entry point after BL1 */
83 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
84
Achin Guptaa4a8eae2014-07-28 00:15:23 +010085 if (!psci_plat_pm_ops->affinst_on)
86 return PSCI_E_SUCCESS;
87
Achin Gupta4f6ad662013-10-25 09:08:21 +010088 /*
89 * Plat. management: Give the platform the current state
90 * of the target cpu to allow it to perform the necessary
91 * steps to power on.
92 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +010093 return psci_plat_pm_ops->affinst_on(target_cpu,
94 psci_entrypoint,
Achin Guptaa4a8eae2014-07-28 00:15:23 +010095 cpu_node->level,
96 psci_get_phys_state(cpu_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +010097}
98
99/*******************************************************************************
100 * Handler routine to turn a cluster on. It takes care or any generic, arch.
101 * or platform specific setup required.
102 * TODO: Split this code across separate handlers for each type of setup?
103 ******************************************************************************/
104static int psci_afflvl1_on(unsigned long target_cpu,
Soby Mathew78879b92015-01-06 15:36:38 +0000105 aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100106{
Achin Gupta4f6ad662013-10-25 09:08:21 +0100107 unsigned long psci_entrypoint;
108
109 assert(cluster_node->level == MPIDR_AFFLVL1);
110
111 /*
112 * There is no generic and arch. specific cluster
113 * management required
114 */
115
Achin Gupta75f73672013-12-05 16:33:10 +0000116 /* State management: Is not required while turning a cluster on */
117
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100118 if (!psci_plat_pm_ops->affinst_on)
119 return PSCI_E_SUCCESS;
120
Achin Gupta4f6ad662013-10-25 09:08:21 +0100121 /*
122 * Plat. management: Give the platform the current state
123 * of the target cpu to allow it to perform the necessary
124 * steps to power on.
125 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100126 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
127 return psci_plat_pm_ops->affinst_on(target_cpu,
128 psci_entrypoint,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100129 cluster_node->level,
130 psci_get_phys_state(cluster_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100131}
132
133/*******************************************************************************
134 * Handler routine to turn a cluster of clusters on. It takes care or any
135 * generic, arch. or platform specific setup required.
136 * TODO: Split this code across separate handlers for each type of setup?
137 ******************************************************************************/
138static int psci_afflvl2_on(unsigned long target_cpu,
Soby Mathew78879b92015-01-06 15:36:38 +0000139 aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100140{
Achin Gupta4f6ad662013-10-25 09:08:21 +0100141 unsigned long psci_entrypoint;
142
143 /* Cannot go beyond affinity level 2 in this psci imp. */
144 assert(system_node->level == MPIDR_AFFLVL2);
145
146 /*
147 * There is no generic and arch. specific system management
148 * required
149 */
150
Achin Gupta75f73672013-12-05 16:33:10 +0000151 /* State management: Is not required while turning a system on */
152
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100153 if (!psci_plat_pm_ops->affinst_on)
154 return PSCI_E_SUCCESS;
155
Achin Gupta4f6ad662013-10-25 09:08:21 +0100156 /*
157 * Plat. management: Give the platform the current state
158 * of the target cpu to allow it to perform the necessary
159 * steps to power on.
160 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100161 psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
162 return psci_plat_pm_ops->affinst_on(target_cpu,
163 psci_entrypoint,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100164 system_node->level,
165 psci_get_phys_state(system_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100166}
167
168/* Private data structure to make this handlers accessible through indexing */
Dan Handleyfb037bf2014-04-10 15:37:22 +0100169static const afflvl_on_handler_t psci_afflvl_on_handlers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100170 psci_afflvl0_on,
171 psci_afflvl1_on,
172 psci_afflvl2_on,
173};
174
175/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000176 * This function takes an array of pointers to affinity instance nodes in the
177 * topology tree and calls the on handler for the corresponding affinity
178 * levels
179 ******************************************************************************/
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100180static int psci_call_on_handlers(aff_map_node_t *target_cpu_nodes[],
Achin Gupta0959db52013-12-02 17:33:04 +0000181 int start_afflvl,
182 int end_afflvl,
Soby Mathew78879b92015-01-06 15:36:38 +0000183 unsigned long target_cpu)
Achin Gupta0959db52013-12-02 17:33:04 +0000184{
185 int rc = PSCI_E_INVALID_PARAMS, level;
Dan Handleyfb037bf2014-04-10 15:37:22 +0100186 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000187
188 for (level = end_afflvl; level >= start_afflvl; level--) {
189 node = target_cpu_nodes[level];
190 if (node == NULL)
191 continue;
192
193 /*
194 * TODO: In case of an error should there be a way
195 * of undoing what we might have setup at higher
196 * affinity levels.
197 */
198 rc = psci_afflvl_on_handlers[level](target_cpu,
Soby Mathew78879b92015-01-06 15:36:38 +0000199 node);
Achin Gupta0959db52013-12-02 17:33:04 +0000200 if (rc != PSCI_E_SUCCESS)
201 break;
202 }
203
204 return rc;
205}
206
207/*******************************************************************************
208 * Generic handler which is called to physically power on a cpu identified by
209 * its mpidr. It traverses through all the affinity levels performing generic,
210 * architectural, platform setup and state management e.g. for a cpu that is
211 * to be powered on, it will ensure that enough information is stashed for it
212 * to resume execution in the non-secure security state.
213 *
214 * The state of all the relevant affinity levels is changed after calling the
215 * affinity level specific handlers as their actions would depend upon the state
216 * the affinity level is currently in.
217 *
218 * The affinity level specific handlers are called in descending order i.e. from
219 * the highest to the lowest affinity level implemented by the platform because
Soby Mathewe146f4c2014-09-26 15:08:52 +0100220 * to turn on affinity level X it is necessary to turn on affinity level X + 1
Achin Gupta0959db52013-12-02 17:33:04 +0000221 * first.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100222 ******************************************************************************/
223int psci_afflvl_on(unsigned long target_cpu,
Soby Mathew78879b92015-01-06 15:36:38 +0000224 entry_point_info_t *ep,
Achin Gupta0959db52013-12-02 17:33:04 +0000225 int start_afflvl,
226 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100227{
Achin Gupta0959db52013-12-02 17:33:04 +0000228 int rc = PSCI_E_SUCCESS;
Dan Handleyfb037bf2014-04-10 15:37:22 +0100229 mpidr_aff_map_nodes_t target_cpu_nodes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100230
231 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000232 * Collect the pointers to the nodes in the topology tree for
233 * each affinity instance in the mpidr. If this function does
234 * not return successfully then either the mpidr or the affinity
235 * levels are incorrect.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100236 */
Achin Gupta0959db52013-12-02 17:33:04 +0000237 rc = psci_get_aff_map_nodes(target_cpu,
238 start_afflvl,
239 end_afflvl,
240 target_cpu_nodes);
241 if (rc != PSCI_E_SUCCESS)
242 return rc;
243
Achin Gupta4f6ad662013-10-25 09:08:21 +0100244
245 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000246 * This function acquires the lock corresponding to each affinity
247 * level so that by the time all locks are taken, the system topology
248 * is snapshot and state management can be done safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100249 */
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100250 psci_acquire_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000251 end_afflvl,
252 target_cpu_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100253
Soby Mathew2f5aade2015-01-12 13:01:31 +0000254 /*
255 * Generic management: Ensure that the cpu is off to be
256 * turned on.
257 */
258 rc = cpu_on_validate_state(psci_get_state(
259 (aff_map_node_t *)target_cpu_nodes[MPIDR_AFFLVL0]));
260 if (rc != PSCI_E_SUCCESS)
261 goto exit;
262
Achin Gupta0959db52013-12-02 17:33:04 +0000263 /* Perform generic, architecture and platform specific handling. */
264 rc = psci_call_on_handlers(target_cpu_nodes,
265 start_afflvl,
266 end_afflvl,
Soby Mathew78879b92015-01-06 15:36:38 +0000267 target_cpu);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100268
269 /*
Achin Gupta84c9f102014-07-28 00:09:01 +0100270 * This function updates the state of each affinity instance
271 * corresponding to the mpidr in the range of affinity levels
272 * specified.
273 */
Soby Mathew78879b92015-01-06 15:36:38 +0000274 if (rc == PSCI_E_SUCCESS) {
Achin Gupta84c9f102014-07-28 00:09:01 +0100275 psci_do_afflvl_state_mgmt(start_afflvl,
276 end_afflvl,
277 target_cpu_nodes,
278 PSCI_STATE_ON_PENDING);
Soby Mathew78879b92015-01-06 15:36:38 +0000279 /*
280 * Store the re-entry information for the non-secure world.
281 */
282 cm_init_context(target_cpu, ep);
283 }
Achin Gupta84c9f102014-07-28 00:09:01 +0100284
Soby Mathew2f5aade2015-01-12 13:01:31 +0000285exit:
Achin Gupta84c9f102014-07-28 00:09:01 +0100286 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100287 * This loop releases the lock corresponding to each affinity level
Achin Gupta0959db52013-12-02 17:33:04 +0000288 * in the reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100289 */
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100290 psci_release_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000291 end_afflvl,
292 target_cpu_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100293
294 return rc;
295}
296
297/*******************************************************************************
298 * The following functions finish an earlier affinity power on request. They
299 * are called by the common finisher routine in psci_common.c.
300 ******************************************************************************/
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100301static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100302{
Andrew Thoelke167a9352014-06-04 21:10:52 +0100303 unsigned int plat_state, state, rc;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100304
305 assert(cpu_node->level == MPIDR_AFFLVL0);
306
Achin Gupta0959db52013-12-02 17:33:04 +0000307 /* Ensure we have been explicitly woken up by another cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000308 state = psci_get_state(cpu_node);
Achin Gupta0959db52013-12-02 17:33:04 +0000309 assert(state == PSCI_STATE_ON_PENDING);
310
Achin Gupta4f6ad662013-10-25 09:08:21 +0100311 /*
312 * Plat. management: Perform the platform specific actions
313 * for this cpu e.g. enabling the gic or zeroing the mailbox
314 * register. The actual state of this cpu has already been
315 * changed.
316 */
317 if (psci_plat_pm_ops->affinst_on_finish) {
318
Achin Gupta0959db52013-12-02 17:33:04 +0000319 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000320 plat_state = get_phys_state(state);
Soby Mathewe146f4c2014-09-26 15:08:52 +0100321 rc = psci_plat_pm_ops->affinst_on_finish(cpu_node->level,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100322 plat_state);
323 assert(rc == PSCI_E_SUCCESS);
324 }
325
326 /*
Achin Guptab51da822014-06-26 09:58:52 +0100327 * Arch. management: Enable data cache and manage stack memory
Achin Gupta4f6ad662013-10-25 09:08:21 +0100328 */
Achin Guptab51da822014-06-26 09:58:52 +0100329 psci_do_pwrup_cache_maintenance();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100330
331 /*
332 * All the platform specific actions for turning this cpu
333 * on have completed. Perform enough arch.initialization
334 * to run in the non-secure address space.
335 */
336 bl31_arch_setup();
337
338 /*
Achin Gupta607084e2014-02-09 18:24:19 +0000339 * Call the cpu on finish handler registered by the Secure Payload
340 * Dispatcher to let it do any bookeeping. If the handler encounters an
341 * error, it's expected to assert within
342 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000343 if (psci_spd_pm && psci_spd_pm->svc_on_finish)
344 psci_spd_pm->svc_on_finish(0);
Achin Gupta607084e2014-02-09 18:24:19 +0000345
346 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100347 * Generic management: Now we just need to retrieve the
348 * information that we had stashed away during the cpu_on
Andrew Thoelke167a9352014-06-04 21:10:52 +0100349 * call to set this cpu on its way.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100350 */
Andrew Thoelke167a9352014-06-04 21:10:52 +0100351 cm_prepare_el3_exit(NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100352
353 /* Clean caches before re-entering normal world */
354 dcsw_op_louis(DCCSW);
355
Andrew Thoelke167a9352014-06-04 21:10:52 +0100356 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100357 return rc;
358}
359
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100360static unsigned int psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100361{
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100362 unsigned int plat_state;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100363
364 assert(cluster_node->level == MPIDR_AFFLVL1);
365
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100366 if (!psci_plat_pm_ops->affinst_on_finish)
367 return PSCI_E_SUCCESS;
368
Achin Gupta4f6ad662013-10-25 09:08:21 +0100369 /*
370 * Plat. management: Perform the platform specific actions
371 * as per the old state of the cluster e.g. enabling
372 * coherency at the interconnect depends upon the state with
373 * which this cluster was powered up. If anything goes wrong
374 * then assert as there is no way to recover from this
375 * situation.
376 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100377 plat_state = psci_get_phys_state(cluster_node);
Soby Mathewe146f4c2014-09-26 15:08:52 +0100378 return psci_plat_pm_ops->affinst_on_finish(cluster_node->level,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100379 plat_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100380}
381
382
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100383static unsigned int psci_afflvl2_on_finish(aff_map_node_t *system_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 /* Cannot go beyond this affinity level */
388 assert(system_node->level == MPIDR_AFFLVL2);
389
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100390 if (!psci_plat_pm_ops->affinst_on_finish)
391 return PSCI_E_SUCCESS;
392
Achin Gupta4f6ad662013-10-25 09:08:21 +0100393 /*
394 * Currently, there are no architectural actions to perform
395 * at the system level.
396 */
397
398 /*
399 * Plat. management: Perform the platform specific actions
400 * as per the old state of the cluster e.g. enabling
401 * coherency at the interconnect depends upon the state with
402 * which this cluster was powered up. If anything goes wrong
403 * then assert as there is no way to recover from this
404 * situation.
405 */
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100406 plat_state = psci_get_phys_state(system_node);
Soby Mathewe146f4c2014-09-26 15:08:52 +0100407 return psci_plat_pm_ops->affinst_on_finish(system_node->level,
Achin Guptaa4a8eae2014-07-28 00:15:23 +0100408 plat_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100409}
410
Dan Handleyfb037bf2014-04-10 15:37:22 +0100411const afflvl_power_on_finisher_t psci_afflvl_on_finishers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100412 psci_afflvl0_on_finish,
413 psci_afflvl1_on_finish,
414 psci_afflvl2_on_finish,
415};