blob: 67e209de1c0d4f48173bb76128302e6175015268 [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
31#include <stdio.h>
32#include <string.h>
33#include <assert.h>
Achin Gupta0a9f7472014-02-09 17:48:12 +000034#include <debug.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010035#include <arch_helpers.h>
36#include <console.h>
37#include <platform.h>
38#include <psci.h>
Achin Guptaef7a28c2014-02-01 08:59:56 +000039#include <context_mgmt.h>
Dan Handley5b827a82014-04-17 18:53:42 +010040#include <runtime_svc.h>
Dan Handley35e98e52014-04-09 13:13:04 +010041#include "psci_private.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010042
43typedef int (*afflvl_suspend_handler)(unsigned long,
44 aff_map_node *,
45 unsigned long,
46 unsigned long,
47 unsigned int);
48
49/*******************************************************************************
Vikram Kanigiri759ec932014-04-01 19:26:26 +010050 * This function sets the power state of the current cpu while
51 * powering down during a cpu_suspend call
Achin Guptaa45e3972013-12-05 15:10:48 +000052 ******************************************************************************/
Vikram Kanigiri759ec932014-04-01 19:26:26 +010053void psci_set_suspend_power_state(aff_map_node *node, unsigned int power_state)
Achin Guptaa45e3972013-12-05 15:10:48 +000054{
55 /*
56 * Check that nobody else is calling this function on our behalf &
57 * this information is being set only in the cpu node
58 */
59 assert(node->mpidr == (read_mpidr() & MPIDR_AFFINITY_MASK));
60 assert(node->level == MPIDR_AFFLVL0);
61
Vikram Kanigiri759ec932014-04-01 19:26:26 +010062 /* Save PSCI power state parameter for the core in suspend context */
63 psci_suspend_context[node->data].power_state = power_state;
64
Achin Guptaa45e3972013-12-05 15:10:48 +000065 /*
Vikram Kanigiri759ec932014-04-01 19:26:26 +010066 * Flush the suspend data to PoC since it will be accessed while
67 * returning back from suspend with the caches turned off
Achin Guptaa45e3972013-12-05 15:10:48 +000068 */
Vikram Kanigiri759ec932014-04-01 19:26:26 +010069 flush_dcache_range(
70 (unsigned long)&psci_suspend_context[node->data],
71 sizeof(suspend_context));
Achin Guptaa45e3972013-12-05 15:10:48 +000072}
73
74/*******************************************************************************
Vikram Kanigiri759ec932014-04-01 19:26:26 +010075 * This function gets the affinity level till which a cpu is powered down
76 * during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
77 * power state saved for the node is invalid
Achin Guptaa45e3972013-12-05 15:10:48 +000078 ******************************************************************************/
Vikram Kanigiri759ec932014-04-01 19:26:26 +010079int psci_get_suspend_afflvl(unsigned long mpidr)
Achin Guptaa45e3972013-12-05 15:10:48 +000080{
Vikram Kanigiri759ec932014-04-01 19:26:26 +010081 aff_map_node *node;
82
83 node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK,
84 MPIDR_AFFLVL0);
85 assert(node);
86
87 return psci_get_aff_map_node_suspend_afflvl(node);
88}
89
90
91/*******************************************************************************
92 * This function gets the affinity level till which the current cpu was powered
93 * down during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
94 * power state saved for the node is invalid
95 ******************************************************************************/
96int psci_get_aff_map_node_suspend_afflvl(aff_map_node *node)
97{
98 unsigned int power_state;
99
100 assert(node->level == MPIDR_AFFLVL0);
101
102 power_state = psci_suspend_context[node->data].power_state;
103 return ((power_state == PSCI_INVALID_DATA) ?
104 power_state : psci_get_pstate_afflvl(power_state));
105}
106
107/*******************************************************************************
108 * This function gets the state id of a cpu stored in suspend context
109 * while powering down during a cpu_suspend call. Returns 0xFFFFFFFF
110 * if the power state saved for the node is invalid
111 ******************************************************************************/
112int psci_get_suspend_stateid(unsigned long mpidr)
113{
114 aff_map_node *node;
115 unsigned int power_state;
116
117 node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK,
118 MPIDR_AFFLVL0);
119 assert(node);
120 assert(node->level == MPIDR_AFFLVL0);
121
122 power_state = psci_suspend_context[node->data].power_state;
123 return ((power_state == PSCI_INVALID_DATA) ?
124 power_state : psci_get_pstate_id(power_state));
Achin Guptaa45e3972013-12-05 15:10:48 +0000125}
126
127/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +0100128 * The next three functions implement a handler for each supported affinity
129 * level which is called when that affinity level is about to be suspended.
130 ******************************************************************************/
131static int psci_afflvl0_suspend(unsigned long mpidr,
132 aff_map_node *cpu_node,
133 unsigned long ns_entrypoint,
134 unsigned long context_id,
135 unsigned int power_state)
136{
137 unsigned int index, plat_state;
Vikram Kanigiri6ba0b6d2014-03-11 17:41:00 +0000138 unsigned long psci_entrypoint, sctlr;
Achin Gupta0a9f7472014-02-09 17:48:12 +0000139 el3_state *saved_el3_state;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100140 int rc = PSCI_E_SUCCESS;
141
142 /* Sanity check to safeguard against data corruption */
143 assert(cpu_node->level == MPIDR_AFFLVL0);
144
Vikram Kanigiri759ec932014-04-01 19:26:26 +0100145 /* Save PSCI power state parameter for the core in suspend context */
146 psci_set_suspend_power_state(cpu_node, power_state);
147
Achin Gupta607084e2014-02-09 18:24:19 +0000148 /*
149 * Generic management: Store the re-entry information for the non-secure
150 * world and allow the secure world to suspend itself
151 */
152
153 /*
154 * Call the cpu suspend handler registered by the Secure Payload
155 * Dispatcher to let it do any bookeeping. If the handler encounters an
156 * error, it's expected to assert within
157 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000158 if (psci_spd_pm && psci_spd_pm->svc_suspend)
159 psci_spd_pm->svc_suspend(power_state);
Achin Gupta607084e2014-02-09 18:24:19 +0000160
Achin Gupta75f73672013-12-05 16:33:10 +0000161 /* State management: mark this cpu as suspended */
162 psci_set_state(cpu_node, PSCI_STATE_SUSPEND);
163
Achin Gupta4f6ad662013-10-25 09:08:21 +0100164 /*
165 * Generic management: Store the re-entry information for the
166 * non-secure world
167 */
168 index = cpu_node->data;
169 rc = psci_set_ns_entry_info(index, ns_entrypoint, context_id);
170 if (rc != PSCI_E_SUCCESS)
171 return rc;
172
173 /*
Achin Guptaef7a28c2014-02-01 08:59:56 +0000174 * Arch. management: Save the EL3 state in the 'cpu_context'
175 * structure that has been allocated for this cpu, flush the
Achin Gupta4f6ad662013-10-25 09:08:21 +0100176 * L1 caches and exit intra-cluster coherency et al
177 */
Achin Guptaef7a28c2014-02-01 08:59:56 +0000178 cm_el3_sysregs_context_save(NON_SECURE);
179 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100180
Achin Gupta0a9f7472014-02-09 17:48:12 +0000181 /*
182 * The EL3 state to PoC since it will be accessed after a
183 * reset with the caches turned off
184 */
185 saved_el3_state = get_el3state_ctx(cm_get_context(mpidr, NON_SECURE));
186 flush_dcache_range((uint64_t) saved_el3_state, sizeof(*saved_el3_state));
187
Achin Gupta4f6ad662013-10-25 09:08:21 +0100188 /* Set the secure world (EL3) re-entry point after BL1 */
189 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
190
191 /*
192 * Arch. management. Perform the necessary steps to flush all
193 * cpu caches.
194 *
195 * TODO: This power down sequence varies across cpus so it needs to be
196 * abstracted out on the basis of the MIDR like in cpu_reset_handler().
197 * Do the bare minimal for the time being. Fix this before porting to
198 * Cortex models.
199 */
Vikram Kanigiri6ba0b6d2014-03-11 17:41:00 +0000200 sctlr = read_sctlr_el3();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100201 sctlr &= ~SCTLR_C_BIT;
Vikram Kanigiri6ba0b6d2014-03-11 17:41:00 +0000202 write_sctlr_el3(sctlr);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100203
204 /*
205 * CAUTION: This flush to the level of unification makes an assumption
206 * about the cache hierarchy at affinity level 0 (cpu) in the platform.
207 * Ideally the platform should tell psci which levels to flush to exit
208 * coherency.
209 */
210 dcsw_op_louis(DCCISW);
211
212 /*
213 * Plat. management: Allow the platform to perform the
214 * necessary actions to turn off this cpu e.g. set the
215 * platform defined mailbox with the psci entrypoint,
216 * program the power controller etc.
217 */
218 if (psci_plat_pm_ops->affinst_suspend) {
Achin Gupta75f73672013-12-05 16:33:10 +0000219 plat_state = psci_get_phys_state(cpu_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100220 rc = psci_plat_pm_ops->affinst_suspend(mpidr,
221 psci_entrypoint,
222 ns_entrypoint,
223 cpu_node->level,
224 plat_state);
225 }
226
227 return rc;
228}
229
230static int psci_afflvl1_suspend(unsigned long mpidr,
231 aff_map_node *cluster_node,
232 unsigned long ns_entrypoint,
233 unsigned long context_id,
234 unsigned int power_state)
235{
236 int rc = PSCI_E_SUCCESS;
237 unsigned int plat_state;
238 unsigned long psci_entrypoint;
239
240 /* Sanity check the cluster level */
241 assert(cluster_node->level == MPIDR_AFFLVL1);
242
Achin Gupta75f73672013-12-05 16:33:10 +0000243 /* State management: Decrement the cluster reference count */
244 psci_set_state(cluster_node, PSCI_STATE_SUSPEND);
245
Achin Gupta4f6ad662013-10-25 09:08:21 +0100246 /*
247 * Keep the physical state of this cluster handy to decide
248 * what action needs to be taken
249 */
Achin Gupta75f73672013-12-05 16:33:10 +0000250 plat_state = psci_get_phys_state(cluster_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100251
252 /*
253 * Arch. management: Flush all levels of caches to PoC if the
254 * cluster is to be shutdown
255 */
256 if (plat_state == PSCI_STATE_OFF)
257 dcsw_op_all(DCCISW);
258
259 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +0000260 * Plat. Management. Allow the platform to do its cluster
Achin Gupta4f6ad662013-10-25 09:08:21 +0100261 * specific bookeeping e.g. turn off interconnect coherency,
262 * program the power controller etc.
263 */
264 if (psci_plat_pm_ops->affinst_suspend) {
265
266 /*
267 * Sending the psci entrypoint is currently redundant
268 * beyond affinity level 0 but one never knows what a
269 * platform might do. Also it allows us to keep the
270 * platform handler prototype the same.
271 */
272 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100273 rc = psci_plat_pm_ops->affinst_suspend(mpidr,
274 psci_entrypoint,
275 ns_entrypoint,
276 cluster_node->level,
277 plat_state);
278 }
279
280 return rc;
281}
282
283
284static int psci_afflvl2_suspend(unsigned long mpidr,
285 aff_map_node *system_node,
286 unsigned long ns_entrypoint,
287 unsigned long context_id,
288 unsigned int power_state)
289{
290 int rc = PSCI_E_SUCCESS;
291 unsigned int plat_state;
292 unsigned long psci_entrypoint;
293
294 /* Cannot go beyond this */
295 assert(system_node->level == MPIDR_AFFLVL2);
296
Achin Gupta75f73672013-12-05 16:33:10 +0000297 /* State management: Decrement the system reference count */
298 psci_set_state(system_node, PSCI_STATE_SUSPEND);
299
Achin Gupta4f6ad662013-10-25 09:08:21 +0100300 /*
301 * Keep the physical state of the system handy to decide what
302 * action needs to be taken
303 */
Achin Gupta75f73672013-12-05 16:33:10 +0000304 plat_state = psci_get_phys_state(system_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100305
306 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +0000307 * Plat. Management : Allow the platform to do its bookeeping
Achin Gupta4f6ad662013-10-25 09:08:21 +0100308 * at this affinity level
309 */
310 if (psci_plat_pm_ops->affinst_suspend) {
311
312 /*
313 * Sending the psci entrypoint is currently redundant
314 * beyond affinity level 0 but one never knows what a
315 * platform might do. Also it allows us to keep the
316 * platform handler prototype the same.
317 */
318 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100319 rc = psci_plat_pm_ops->affinst_suspend(mpidr,
320 psci_entrypoint,
321 ns_entrypoint,
322 system_node->level,
323 plat_state);
324 }
325
326 return rc;
327}
328
329static const afflvl_suspend_handler psci_afflvl_suspend_handlers[] = {
330 psci_afflvl0_suspend,
331 psci_afflvl1_suspend,
332 psci_afflvl2_suspend,
333};
334
335/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000336 * This function takes an array of pointers to affinity instance nodes in the
337 * topology tree and calls the suspend handler for the corresponding affinity
338 * levels
339 ******************************************************************************/
340static int psci_call_suspend_handlers(mpidr_aff_map_nodes mpidr_nodes,
341 int start_afflvl,
342 int end_afflvl,
343 unsigned long mpidr,
344 unsigned long entrypoint,
345 unsigned long context_id,
346 unsigned int power_state)
347{
348 int rc = PSCI_E_INVALID_PARAMS, level;
349 aff_map_node *node;
350
351 for (level = start_afflvl; level <= end_afflvl; level++) {
352 node = mpidr_nodes[level];
353 if (node == NULL)
354 continue;
355
356 /*
357 * TODO: In case of an error should there be a way
358 * of restoring what we might have torn down at
359 * lower affinity levels.
360 */
361 rc = psci_afflvl_suspend_handlers[level](mpidr,
362 node,
363 entrypoint,
364 context_id,
365 power_state);
366 if (rc != PSCI_E_SUCCESS)
367 break;
368 }
369
370 return rc;
371}
372
373/*******************************************************************************
374 * Top level handler which is called when a cpu wants to suspend its execution.
375 * It is assumed that along with turning the cpu off, higher affinity levels
376 * until the target affinity level will be turned off as well. It traverses
377 * through all the affinity levels performing generic, architectural, platform
378 * setup and state management e.g. for a cluster that's to be suspended, it will
379 * call the platform specific code which will disable coherency at the
380 * interconnect level if the cpu is the last in the cluster. For a cpu it could
381 * mean programming the power controller etc.
382 *
383 * The state of all the relevant affinity levels is changed prior to calling the
384 * affinity level specific handlers as their actions would depend upon the state
385 * the affinity level is about to enter.
386 *
387 * The affinity level specific handlers are called in ascending order i.e. from
388 * the lowest to the highest affinity level implemented by the platform because
389 * to turn off affinity level X it is neccesary to turn off affinity level X - 1
390 * first.
391 *
392 * CAUTION: This function is called with coherent stacks so that coherency can
393 * be turned off and caches can be flushed safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100394 ******************************************************************************/
395int psci_afflvl_suspend(unsigned long mpidr,
396 unsigned long entrypoint,
397 unsigned long context_id,
398 unsigned int power_state,
Achin Gupta0959db52013-12-02 17:33:04 +0000399 int start_afflvl,
400 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100401{
Achin Gupta0959db52013-12-02 17:33:04 +0000402 int rc = PSCI_E_SUCCESS;
Achin Gupta0959db52013-12-02 17:33:04 +0000403 mpidr_aff_map_nodes mpidr_nodes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100404
405 mpidr &= MPIDR_AFFINITY_MASK;
406
407 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000408 * Collect the pointers to the nodes in the topology tree for
409 * each affinity instance in the mpidr. If this function does
410 * not return successfully then either the mpidr or the affinity
411 * levels are incorrect.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100412 */
Achin Gupta0959db52013-12-02 17:33:04 +0000413 rc = psci_get_aff_map_nodes(mpidr,
414 start_afflvl,
415 end_afflvl,
416 mpidr_nodes);
417 if (rc != PSCI_E_SUCCESS)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100418 return rc;
419
Achin Gupta0959db52013-12-02 17:33:04 +0000420 /*
421 * This function acquires the lock corresponding to each affinity
422 * level so that by the time all locks are taken, the system topology
423 * is snapshot and state management can be done safely.
424 */
425 psci_acquire_afflvl_locks(mpidr,
426 start_afflvl,
427 end_afflvl,
428 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100429
Achin Gupta0959db52013-12-02 17:33:04 +0000430 /* Perform generic, architecture and platform specific handling */
431 rc = psci_call_suspend_handlers(mpidr_nodes,
432 start_afflvl,
433 end_afflvl,
434 mpidr,
435 entrypoint,
436 context_id,
437 power_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100438
439 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000440 * Release the locks corresponding to each affinity level in the
441 * reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100442 */
Achin Gupta0959db52013-12-02 17:33:04 +0000443 psci_release_afflvl_locks(mpidr,
444 start_afflvl,
445 end_afflvl,
446 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100447
Achin Gupta4f6ad662013-10-25 09:08:21 +0100448 return rc;
449}
450
451/*******************************************************************************
452 * The following functions finish an earlier affinity suspend request. They
453 * are called by the common finisher routine in psci_common.c.
454 ******************************************************************************/
455static unsigned int psci_afflvl0_suspend_finish(unsigned long mpidr,
Achin Gupta0959db52013-12-02 17:33:04 +0000456 aff_map_node *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100457{
Achin Gupta0959db52013-12-02 17:33:04 +0000458 unsigned int index, plat_state, state, rc = PSCI_E_SUCCESS;
Achin Gupta607084e2014-02-09 18:24:19 +0000459 int32_t suspend_level;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100460
461 assert(cpu_node->level == MPIDR_AFFLVL0);
462
Achin Gupta0959db52013-12-02 17:33:04 +0000463 /* Ensure we have been woken up from a suspended state */
Achin Gupta75f73672013-12-05 16:33:10 +0000464 state = psci_get_state(cpu_node);
Achin Gupta0959db52013-12-02 17:33:04 +0000465 assert(state == PSCI_STATE_SUSPEND);
466
Achin Gupta4f6ad662013-10-25 09:08:21 +0100467 /*
468 * Plat. management: Perform the platform specific actions
469 * before we change the state of the cpu e.g. enabling the
470 * gic or zeroing the mailbox register. If anything goes
471 * wrong then assert as there is no way to recover from this
472 * situation.
473 */
474 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000475
476 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000477 plat_state = get_phys_state(state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100478 rc = psci_plat_pm_ops->affinst_suspend_finish(mpidr,
479 cpu_node->level,
480 plat_state);
481 assert(rc == PSCI_E_SUCCESS);
482 }
483
484 /* Get the index for restoring the re-entry information */
485 index = cpu_node->data;
486
487 /*
Achin Guptaef7a28c2014-02-01 08:59:56 +0000488 * Arch. management: Restore the stashed EL3 architectural
489 * context from the 'cpu_context' structure for this cpu.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100490 */
Achin Guptaef7a28c2014-02-01 08:59:56 +0000491 cm_el3_sysregs_context_restore(NON_SECURE);
492 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100493
494 /*
Achin Gupta607084e2014-02-09 18:24:19 +0000495 * Use the more complex exception vectors to enable SPD
496 * initialisation. SP_EL3 should point to a 'cpu_context'
497 * structure which has an exception stack allocated. The
498 * non-secure context should have been set on this cpu
499 * prior to suspension.
500 */
501 assert(cm_get_context(mpidr, NON_SECURE));
502 cm_set_next_eret_context(NON_SECURE);
503 write_vbar_el3((uint64_t) runtime_exceptions);
504
505 /*
506 * Call the cpu suspend finish handler registered by the Secure Payload
507 * Dispatcher to let it do any bookeeping. If the handler encounters an
508 * error, it's expected to assert within
509 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000510 if (psci_spd_pm && psci_spd_pm->svc_suspend) {
Vikram Kanigiri759ec932014-04-01 19:26:26 +0100511 suspend_level = psci_get_aff_map_node_suspend_afflvl(cpu_node);
512 assert (suspend_level != PSCI_INVALID_DATA);
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000513 psci_spd_pm->svc_suspend_finish(suspend_level);
Achin Gupta607084e2014-02-09 18:24:19 +0000514 }
515
Vikram Kanigiri759ec932014-04-01 19:26:26 +0100516 /* Invalidate the suspend context for the node */
517 psci_set_suspend_power_state(cpu_node, PSCI_INVALID_DATA);
518
Achin Gupta607084e2014-02-09 18:24:19 +0000519 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100520 * Generic management: Now we just need to retrieve the
521 * information that we had stashed away during the suspend
Achin Gupta3140a9e2013-12-02 16:23:12 +0000522 * call to set this cpu on its way.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100523 */
Achin Guptac8afc782013-11-25 18:45:02 +0000524 psci_get_ns_entry_info(index);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100525
Achin Gupta75f73672013-12-05 16:33:10 +0000526 /* State management: mark this cpu as on */
527 psci_set_state(cpu_node, PSCI_STATE_ON);
528
Achin Gupta4f6ad662013-10-25 09:08:21 +0100529 /* Clean caches before re-entering normal world */
530 dcsw_op_louis(DCCSW);
531
532 return rc;
533}
534
535static unsigned int psci_afflvl1_suspend_finish(unsigned long mpidr,
Achin Gupta0959db52013-12-02 17:33:04 +0000536 aff_map_node *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100537{
Achin Gupta0959db52013-12-02 17:33:04 +0000538 unsigned int plat_state, rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100539
540 assert(cluster_node->level == MPIDR_AFFLVL1);
541
542 /*
543 * Plat. management: Perform the platform specific actions
544 * as per the old state of the cluster e.g. enabling
545 * coherency at the interconnect depends upon the state with
546 * which this cluster was powered up. If anything goes wrong
547 * then assert as there is no way to recover from this
548 * situation.
549 */
550 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000551
552 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000553 plat_state = psci_get_phys_state(cluster_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100554 rc = psci_plat_pm_ops->affinst_suspend_finish(mpidr,
555 cluster_node->level,
556 plat_state);
557 assert(rc == PSCI_E_SUCCESS);
558 }
559
Achin Gupta75f73672013-12-05 16:33:10 +0000560 /* State management: Increment the cluster reference count */
561 psci_set_state(cluster_node, PSCI_STATE_ON);
562
Achin Gupta4f6ad662013-10-25 09:08:21 +0100563 return rc;
564}
565
566
567static unsigned int psci_afflvl2_suspend_finish(unsigned long mpidr,
Achin Gupta0959db52013-12-02 17:33:04 +0000568 aff_map_node *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100569{
Achin Gupta0959db52013-12-02 17:33:04 +0000570 unsigned int plat_state, rc = PSCI_E_SUCCESS;;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100571
572 /* Cannot go beyond this affinity level */
573 assert(system_node->level == MPIDR_AFFLVL2);
574
575 /*
576 * Currently, there are no architectural actions to perform
577 * at the system level.
578 */
579
580 /*
581 * Plat. management: Perform the platform specific actions
582 * as per the old state of the cluster e.g. enabling
583 * coherency at the interconnect depends upon the state with
584 * which this cluster was powered up. If anything goes wrong
585 * then assert as there is no way to recover from this
586 * situation.
587 */
588 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000589
590 /* Get the physical state of the system */
Achin Gupta75f73672013-12-05 16:33:10 +0000591 plat_state = psci_get_phys_state(system_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100592 rc = psci_plat_pm_ops->affinst_suspend_finish(mpidr,
593 system_node->level,
594 plat_state);
595 assert(rc == PSCI_E_SUCCESS);
596 }
597
Achin Gupta75f73672013-12-05 16:33:10 +0000598 /* State management: Increment the system reference count */
599 psci_set_state(system_node, PSCI_STATE_ON);
600
Achin Gupta4f6ad662013-10-25 09:08:21 +0100601 return rc;
602}
603
604const afflvl_power_on_finisher psci_afflvl_suspend_finishers[] = {
605 psci_afflvl0_suspend_finish,
606 psci_afflvl1_suspend_finish,
607 psci_afflvl2_suspend_finish,
608};
609