blob: 377afdfe31b2dc136bbf7a6b200bc21f9c52fcd7 [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
Achin Gupta4f6ad662013-10-25 09:08:21 +010031#include <assert.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010032#include <bl_common.h>
33#include <arch.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010034#include <arch_helpers.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010035#include <context.h>
Achin Guptaef7a28c2014-02-01 08:59:56 +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_suspend_handler_t)(unsigned long,
42 aff_map_node_t *,
Achin Gupta4f6ad662013-10-25 09:08:21 +010043 unsigned long,
44 unsigned long,
45 unsigned int);
46
47/*******************************************************************************
Vikram Kanigirif100f412014-04-01 19:26:26 +010048 * This function sets the power state of the current cpu while
49 * powering down during a cpu_suspend call
Achin Guptaa45e3972013-12-05 15:10:48 +000050 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +010051void psci_set_suspend_power_state(aff_map_node_t *node, unsigned int power_state)
Achin Guptaa45e3972013-12-05 15:10:48 +000052{
53 /*
54 * Check that nobody else is calling this function on our behalf &
55 * this information is being set only in the cpu node
56 */
57 assert(node->mpidr == (read_mpidr() & MPIDR_AFFINITY_MASK));
58 assert(node->level == MPIDR_AFFLVL0);
59
Vikram Kanigirif100f412014-04-01 19:26:26 +010060 /* Save PSCI power state parameter for the core in suspend context */
61 psci_suspend_context[node->data].power_state = power_state;
62
Achin Guptaa45e3972013-12-05 15:10:48 +000063 /*
Vikram Kanigirif100f412014-04-01 19:26:26 +010064 * Flush the suspend data to PoC since it will be accessed while
65 * returning back from suspend with the caches turned off
Achin Guptaa45e3972013-12-05 15:10:48 +000066 */
Vikram Kanigirif100f412014-04-01 19:26:26 +010067 flush_dcache_range(
68 (unsigned long)&psci_suspend_context[node->data],
Dan Handleye2712bc2014-04-10 15:37:22 +010069 sizeof(suspend_context_t));
Achin Guptaa45e3972013-12-05 15:10:48 +000070}
71
72/*******************************************************************************
Vikram Kanigirif100f412014-04-01 19:26:26 +010073 * This function gets the affinity level till which a cpu is powered down
74 * during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
75 * power state saved for the node is invalid
76 ******************************************************************************/
77int psci_get_suspend_afflvl(unsigned long mpidr)
78{
Dan Handleye2712bc2014-04-10 15:37:22 +010079 aff_map_node_t *node;
Vikram Kanigirif100f412014-04-01 19:26:26 +010080
81 node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK,
82 MPIDR_AFFLVL0);
83 assert(node);
84
85 return psci_get_aff_map_node_suspend_afflvl(node);
86}
87
88
89/*******************************************************************************
Achin Guptaa45e3972013-12-05 15:10:48 +000090 * This function gets the affinity level till which the current cpu was powered
Vikram Kanigirif100f412014-04-01 19:26:26 +010091 * down during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
92 * power state saved for the node is invalid
93 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +010094int psci_get_aff_map_node_suspend_afflvl(aff_map_node_t *node)
Vikram Kanigirif100f412014-04-01 19:26:26 +010095{
96 unsigned int power_state;
97
98 assert(node->level == MPIDR_AFFLVL0);
99
100 power_state = psci_suspend_context[node->data].power_state;
101 return ((power_state == PSCI_INVALID_DATA) ?
102 power_state : psci_get_pstate_afflvl(power_state));
103}
104
105/*******************************************************************************
106 * This function gets the state id of a cpu stored in suspend context
107 * while powering down during a cpu_suspend call. Returns 0xFFFFFFFF
108 * if the power state saved for the node is invalid
Achin Guptaa45e3972013-12-05 15:10:48 +0000109 ******************************************************************************/
Vikram Kanigirif100f412014-04-01 19:26:26 +0100110int psci_get_suspend_stateid(unsigned long mpidr)
Achin Guptaa45e3972013-12-05 15:10:48 +0000111{
Dan Handleye2712bc2014-04-10 15:37:22 +0100112 aff_map_node_t *node;
Vikram Kanigirif100f412014-04-01 19:26:26 +0100113 unsigned int power_state;
114
115 node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK,
116 MPIDR_AFFLVL0);
117 assert(node);
118 assert(node->level == MPIDR_AFFLVL0);
119
120 power_state = psci_suspend_context[node->data].power_state;
121 return ((power_state == PSCI_INVALID_DATA) ?
122 power_state : psci_get_pstate_id(power_state));
Achin Guptaa45e3972013-12-05 15:10:48 +0000123}
124
125/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +0100126 * The next three functions implement a handler for each supported affinity
127 * level which is called when that affinity level is about to be suspended.
128 ******************************************************************************/
129static int psci_afflvl0_suspend(unsigned long mpidr,
Dan Handleye2712bc2014-04-10 15:37:22 +0100130 aff_map_node_t *cpu_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100131 unsigned long ns_entrypoint,
132 unsigned long context_id,
133 unsigned int power_state)
134{
135 unsigned int index, plat_state;
Vikram Kanigiri78a6e0c2014-03-11 17:41:00 +0000136 unsigned long psci_entrypoint, sctlr;
Dan Handleye2712bc2014-04-10 15:37:22 +0100137 el3_state_t *saved_el3_state;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100138 int rc = PSCI_E_SUCCESS;
139
140 /* Sanity check to safeguard against data corruption */
141 assert(cpu_node->level == MPIDR_AFFLVL0);
142
Vikram Kanigirif100f412014-04-01 19:26:26 +0100143 /* Save PSCI power state parameter for the core in suspend context */
144 psci_set_suspend_power_state(cpu_node, power_state);
145
Achin Gupta607084e2014-02-09 18:24:19 +0000146 /*
147 * Generic management: Store the re-entry information for the non-secure
148 * world and allow the secure world to suspend itself
149 */
150
151 /*
152 * Call the cpu suspend handler registered by the Secure Payload
153 * Dispatcher to let it do any bookeeping. If the handler encounters an
154 * error, it's expected to assert within
155 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000156 if (psci_spd_pm && psci_spd_pm->svc_suspend)
157 psci_spd_pm->svc_suspend(power_state);
Achin Gupta607084e2014-02-09 18:24:19 +0000158
Achin Gupta75f73672013-12-05 16:33:10 +0000159 /* State management: mark this cpu as suspended */
160 psci_set_state(cpu_node, PSCI_STATE_SUSPEND);
161
Achin Gupta4f6ad662013-10-25 09:08:21 +0100162 /*
163 * Generic management: Store the re-entry information for the
164 * non-secure world
165 */
166 index = cpu_node->data;
167 rc = psci_set_ns_entry_info(index, ns_entrypoint, context_id);
168 if (rc != PSCI_E_SUCCESS)
169 return rc;
170
171 /*
Achin Guptaef7a28c2014-02-01 08:59:56 +0000172 * Arch. management: Save the EL3 state in the 'cpu_context'
173 * structure that has been allocated for this cpu, flush the
Achin Gupta4f6ad662013-10-25 09:08:21 +0100174 * L1 caches and exit intra-cluster coherency et al
175 */
Achin Guptaef7a28c2014-02-01 08:59:56 +0000176 cm_el3_sysregs_context_save(NON_SECURE);
177 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100178
Achin Gupta0a9f7472014-02-09 17:48:12 +0000179 /*
180 * The EL3 state to PoC since it will be accessed after a
181 * reset with the caches turned off
182 */
183 saved_el3_state = get_el3state_ctx(cm_get_context(mpidr, NON_SECURE));
184 flush_dcache_range((uint64_t) saved_el3_state, sizeof(*saved_el3_state));
185
Achin Gupta4f6ad662013-10-25 09:08:21 +0100186 /* Set the secure world (EL3) re-entry point after BL1 */
187 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
188
189 /*
190 * Arch. management. Perform the necessary steps to flush all
191 * cpu caches.
192 *
193 * TODO: This power down sequence varies across cpus so it needs to be
194 * abstracted out on the basis of the MIDR like in cpu_reset_handler().
195 * Do the bare minimal for the time being. Fix this before porting to
196 * Cortex models.
197 */
Vikram Kanigiri78a6e0c2014-03-11 17:41:00 +0000198 sctlr = read_sctlr_el3();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100199 sctlr &= ~SCTLR_C_BIT;
Vikram Kanigiri78a6e0c2014-03-11 17:41:00 +0000200 write_sctlr_el3(sctlr);
Andrew Thoelke42e75a72014-04-28 12:28:39 +0100201 isb(); /* ensure MMU disable takes immediate effect */
Achin Gupta4f6ad662013-10-25 09:08:21 +0100202
203 /*
204 * CAUTION: This flush to the level of unification makes an assumption
205 * about the cache hierarchy at affinity level 0 (cpu) in the platform.
206 * Ideally the platform should tell psci which levels to flush to exit
207 * coherency.
208 */
209 dcsw_op_louis(DCCISW);
210
211 /*
212 * Plat. management: Allow the platform to perform the
213 * necessary actions to turn off this cpu e.g. set the
214 * platform defined mailbox with the psci entrypoint,
215 * program the power controller etc.
216 */
217 if (psci_plat_pm_ops->affinst_suspend) {
Achin Gupta75f73672013-12-05 16:33:10 +0000218 plat_state = psci_get_phys_state(cpu_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100219 rc = psci_plat_pm_ops->affinst_suspend(mpidr,
220 psci_entrypoint,
221 ns_entrypoint,
222 cpu_node->level,
223 plat_state);
224 }
225
226 return rc;
227}
228
229static int psci_afflvl1_suspend(unsigned long mpidr,
Dan Handleye2712bc2014-04-10 15:37:22 +0100230 aff_map_node_t *cluster_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100231 unsigned long ns_entrypoint,
232 unsigned long context_id,
233 unsigned int power_state)
234{
235 int rc = PSCI_E_SUCCESS;
236 unsigned int plat_state;
237 unsigned long psci_entrypoint;
238
239 /* Sanity check the cluster level */
240 assert(cluster_node->level == MPIDR_AFFLVL1);
241
Achin Gupta75f73672013-12-05 16:33:10 +0000242 /* State management: Decrement the cluster reference count */
243 psci_set_state(cluster_node, PSCI_STATE_SUSPEND);
244
Achin Gupta4f6ad662013-10-25 09:08:21 +0100245 /*
246 * Keep the physical state of this cluster handy to decide
247 * what action needs to be taken
248 */
Achin Gupta75f73672013-12-05 16:33:10 +0000249 plat_state = psci_get_phys_state(cluster_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100250
251 /*
252 * Arch. management: Flush all levels of caches to PoC if the
253 * cluster is to be shutdown
254 */
255 if (plat_state == PSCI_STATE_OFF)
256 dcsw_op_all(DCCISW);
257
258 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +0000259 * Plat. Management. Allow the platform to do its cluster
Achin Gupta4f6ad662013-10-25 09:08:21 +0100260 * specific bookeeping e.g. turn off interconnect coherency,
261 * program the power controller etc.
262 */
263 if (psci_plat_pm_ops->affinst_suspend) {
264
265 /*
266 * Sending the psci entrypoint is currently redundant
267 * beyond affinity level 0 but one never knows what a
268 * platform might do. Also it allows us to keep the
269 * platform handler prototype the same.
270 */
271 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100272 rc = psci_plat_pm_ops->affinst_suspend(mpidr,
273 psci_entrypoint,
274 ns_entrypoint,
275 cluster_node->level,
276 plat_state);
277 }
278
279 return rc;
280}
281
282
283static int psci_afflvl2_suspend(unsigned long mpidr,
Dan Handleye2712bc2014-04-10 15:37:22 +0100284 aff_map_node_t *system_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100285 unsigned long ns_entrypoint,
286 unsigned long context_id,
287 unsigned int power_state)
288{
289 int rc = PSCI_E_SUCCESS;
290 unsigned int plat_state;
291 unsigned long psci_entrypoint;
292
293 /* Cannot go beyond this */
294 assert(system_node->level == MPIDR_AFFLVL2);
295
Achin Gupta75f73672013-12-05 16:33:10 +0000296 /* State management: Decrement the system reference count */
297 psci_set_state(system_node, PSCI_STATE_SUSPEND);
298
Achin Gupta4f6ad662013-10-25 09:08:21 +0100299 /*
300 * Keep the physical state of the system handy to decide what
301 * action needs to be taken
302 */
Achin Gupta75f73672013-12-05 16:33:10 +0000303 plat_state = psci_get_phys_state(system_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100304
305 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +0000306 * Plat. Management : Allow the platform to do its bookeeping
Achin Gupta4f6ad662013-10-25 09:08:21 +0100307 * at this affinity level
308 */
309 if (psci_plat_pm_ops->affinst_suspend) {
310
311 /*
312 * Sending the psci entrypoint is currently redundant
313 * beyond affinity level 0 but one never knows what a
314 * platform might do. Also it allows us to keep the
315 * platform handler prototype the same.
316 */
317 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100318 rc = psci_plat_pm_ops->affinst_suspend(mpidr,
319 psci_entrypoint,
320 ns_entrypoint,
321 system_node->level,
322 plat_state);
323 }
324
325 return rc;
326}
327
Dan Handleye2712bc2014-04-10 15:37:22 +0100328static const afflvl_suspend_handler_t psci_afflvl_suspend_handlers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100329 psci_afflvl0_suspend,
330 psci_afflvl1_suspend,
331 psci_afflvl2_suspend,
332};
333
334/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000335 * This function takes an array of pointers to affinity instance nodes in the
336 * topology tree and calls the suspend handler for the corresponding affinity
337 * levels
338 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +0100339static int psci_call_suspend_handlers(mpidr_aff_map_nodes_t mpidr_nodes,
Achin Gupta0959db52013-12-02 17:33:04 +0000340 int start_afflvl,
341 int end_afflvl,
342 unsigned long mpidr,
343 unsigned long entrypoint,
344 unsigned long context_id,
345 unsigned int power_state)
346{
347 int rc = PSCI_E_INVALID_PARAMS, level;
Dan Handleye2712bc2014-04-10 15:37:22 +0100348 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000349
350 for (level = start_afflvl; level <= end_afflvl; level++) {
351 node = mpidr_nodes[level];
352 if (node == NULL)
353 continue;
354
355 /*
356 * TODO: In case of an error should there be a way
357 * of restoring what we might have torn down at
358 * lower affinity levels.
359 */
360 rc = psci_afflvl_suspend_handlers[level](mpidr,
361 node,
362 entrypoint,
363 context_id,
364 power_state);
365 if (rc != PSCI_E_SUCCESS)
366 break;
367 }
368
369 return rc;
370}
371
372/*******************************************************************************
373 * Top level handler which is called when a cpu wants to suspend its execution.
374 * It is assumed that along with turning the cpu off, higher affinity levels
375 * until the target affinity level will be turned off as well. It traverses
376 * through all the affinity levels performing generic, architectural, platform
377 * setup and state management e.g. for a cluster that's to be suspended, it will
378 * call the platform specific code which will disable coherency at the
379 * interconnect level if the cpu is the last in the cluster. For a cpu it could
380 * mean programming the power controller etc.
381 *
382 * The state of all the relevant affinity levels is changed prior to calling the
383 * affinity level specific handlers as their actions would depend upon the state
384 * the affinity level is about to enter.
385 *
386 * The affinity level specific handlers are called in ascending order i.e. from
387 * the lowest to the highest affinity level implemented by the platform because
388 * to turn off affinity level X it is neccesary to turn off affinity level X - 1
389 * first.
390 *
391 * CAUTION: This function is called with coherent stacks so that coherency can
392 * be turned off and caches can be flushed safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100393 ******************************************************************************/
394int psci_afflvl_suspend(unsigned long mpidr,
395 unsigned long entrypoint,
396 unsigned long context_id,
397 unsigned int power_state,
Achin Gupta0959db52013-12-02 17:33:04 +0000398 int start_afflvl,
399 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100400{
Achin Gupta0959db52013-12-02 17:33:04 +0000401 int rc = PSCI_E_SUCCESS;
Dan Handleye2712bc2014-04-10 15:37:22 +0100402 mpidr_aff_map_nodes_t mpidr_nodes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100403
404 mpidr &= MPIDR_AFFINITY_MASK;
405
406 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000407 * Collect the pointers to the nodes in the topology tree for
408 * each affinity instance in the mpidr. If this function does
409 * not return successfully then either the mpidr or the affinity
410 * levels are incorrect.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100411 */
Achin Gupta0959db52013-12-02 17:33:04 +0000412 rc = psci_get_aff_map_nodes(mpidr,
413 start_afflvl,
414 end_afflvl,
415 mpidr_nodes);
416 if (rc != PSCI_E_SUCCESS)
417 return rc;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100418
419 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000420 * This function acquires the lock corresponding to each affinity
421 * level so that by the time all locks are taken, the system topology
422 * is snapshot and state management can be done safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100423 */
Achin Gupta0959db52013-12-02 17:33:04 +0000424 psci_acquire_afflvl_locks(mpidr,
425 start_afflvl,
426 end_afflvl,
427 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100428
Achin Gupta0959db52013-12-02 17:33:04 +0000429 /* Perform generic, architecture and platform specific handling */
430 rc = psci_call_suspend_handlers(mpidr_nodes,
431 start_afflvl,
432 end_afflvl,
433 mpidr,
434 entrypoint,
435 context_id,
436 power_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100437
438 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000439 * Release the locks corresponding to each affinity level in the
440 * reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100441 */
Achin Gupta0959db52013-12-02 17:33:04 +0000442 psci_release_afflvl_locks(mpidr,
443 start_afflvl,
444 end_afflvl,
445 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100446
Achin Gupta4f6ad662013-10-25 09:08:21 +0100447 return rc;
448}
449
450/*******************************************************************************
451 * The following functions finish an earlier affinity suspend request. They
452 * are called by the common finisher routine in psci_common.c.
453 ******************************************************************************/
454static unsigned int psci_afflvl0_suspend_finish(unsigned long mpidr,
Dan Handleye2712bc2014-04-10 15:37:22 +0100455 aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100456{
Achin Gupta0959db52013-12-02 17:33:04 +0000457 unsigned int index, plat_state, state, rc = PSCI_E_SUCCESS;
Achin Gupta607084e2014-02-09 18:24:19 +0000458 int32_t suspend_level;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100459
460 assert(cpu_node->level == MPIDR_AFFLVL0);
461
Achin Gupta0959db52013-12-02 17:33:04 +0000462 /* Ensure we have been woken up from a suspended state */
Achin Gupta75f73672013-12-05 16:33:10 +0000463 state = psci_get_state(cpu_node);
Achin Gupta0959db52013-12-02 17:33:04 +0000464 assert(state == PSCI_STATE_SUSPEND);
465
Achin Gupta4f6ad662013-10-25 09:08:21 +0100466 /*
467 * Plat. management: Perform the platform specific actions
468 * before we change the state of the cpu e.g. enabling the
469 * gic or zeroing the mailbox register. If anything goes
470 * wrong then assert as there is no way to recover from this
471 * situation.
472 */
473 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000474
475 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000476 plat_state = get_phys_state(state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100477 rc = psci_plat_pm_ops->affinst_suspend_finish(mpidr,
478 cpu_node->level,
479 plat_state);
480 assert(rc == PSCI_E_SUCCESS);
481 }
482
483 /* Get the index for restoring the re-entry information */
484 index = cpu_node->data;
485
486 /*
Achin Guptaef7a28c2014-02-01 08:59:56 +0000487 * Arch. management: Restore the stashed EL3 architectural
488 * context from the 'cpu_context' structure for this cpu.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100489 */
Achin Guptaef7a28c2014-02-01 08:59:56 +0000490 cm_el3_sysregs_context_restore(NON_SECURE);
491 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100492
493 /*
Achin Gupta607084e2014-02-09 18:24:19 +0000494 * Use the more complex exception vectors to enable SPD
495 * initialisation. SP_EL3 should point to a 'cpu_context'
Soby Mathew5e5c2072014-04-07 15:28:55 +0100496 * structure. The non-secure context should have been
497 * set on this cpu prior to suspension.
Achin Gupta607084e2014-02-09 18:24:19 +0000498 */
499 assert(cm_get_context(mpidr, NON_SECURE));
500 cm_set_next_eret_context(NON_SECURE);
Soby Mathew5e5c2072014-04-07 15:28:55 +0100501 cm_init_pcpu_ptr_cache();
Achin Gupta607084e2014-02-09 18:24:19 +0000502 write_vbar_el3((uint64_t) runtime_exceptions);
503
504 /*
505 * Call the cpu suspend finish handler registered by the Secure Payload
506 * Dispatcher to let it do any bookeeping. If the handler encounters an
507 * error, it's expected to assert within
508 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000509 if (psci_spd_pm && psci_spd_pm->svc_suspend) {
Vikram Kanigirif100f412014-04-01 19:26:26 +0100510 suspend_level = psci_get_aff_map_node_suspend_afflvl(cpu_node);
511 assert (suspend_level != PSCI_INVALID_DATA);
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000512 psci_spd_pm->svc_suspend_finish(suspend_level);
Achin Gupta607084e2014-02-09 18:24:19 +0000513 }
514
Vikram Kanigirif100f412014-04-01 19:26:26 +0100515 /* Invalidate the suspend context for the node */
516 psci_set_suspend_power_state(cpu_node, PSCI_INVALID_DATA);
517
Achin Gupta607084e2014-02-09 18:24:19 +0000518 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100519 * Generic management: Now we just need to retrieve the
520 * information that we had stashed away during the suspend
Achin Gupta3140a9e2013-12-02 16:23:12 +0000521 * call to set this cpu on its way.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100522 */
Achin Guptac8afc782013-11-25 18:45:02 +0000523 psci_get_ns_entry_info(index);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100524
Achin Gupta75f73672013-12-05 16:33:10 +0000525 /* State management: mark this cpu as on */
526 psci_set_state(cpu_node, PSCI_STATE_ON);
527
Achin Gupta4f6ad662013-10-25 09:08:21 +0100528 /* Clean caches before re-entering normal world */
529 dcsw_op_louis(DCCSW);
530
531 return rc;
532}
533
534static unsigned int psci_afflvl1_suspend_finish(unsigned long mpidr,
Dan Handleye2712bc2014-04-10 15:37:22 +0100535 aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100536{
Achin Gupta0959db52013-12-02 17:33:04 +0000537 unsigned int plat_state, rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100538
539 assert(cluster_node->level == MPIDR_AFFLVL1);
540
541 /*
542 * Plat. management: Perform the platform specific actions
543 * as per the old state of the cluster e.g. enabling
544 * coherency at the interconnect depends upon the state with
545 * which this cluster was powered up. If anything goes wrong
546 * then assert as there is no way to recover from this
547 * situation.
548 */
549 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000550
551 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000552 plat_state = psci_get_phys_state(cluster_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100553 rc = psci_plat_pm_ops->affinst_suspend_finish(mpidr,
554 cluster_node->level,
555 plat_state);
556 assert(rc == PSCI_E_SUCCESS);
557 }
558
Achin Gupta75f73672013-12-05 16:33:10 +0000559 /* State management: Increment the cluster reference count */
560 psci_set_state(cluster_node, PSCI_STATE_ON);
561
Achin Gupta4f6ad662013-10-25 09:08:21 +0100562 return rc;
563}
564
565
566static unsigned int psci_afflvl2_suspend_finish(unsigned long mpidr,
Dan Handleye2712bc2014-04-10 15:37:22 +0100567 aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100568{
Achin Gupta0959db52013-12-02 17:33:04 +0000569 unsigned int plat_state, rc = PSCI_E_SUCCESS;;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100570
571 /* Cannot go beyond this affinity level */
572 assert(system_node->level == MPIDR_AFFLVL2);
573
574 /*
575 * Currently, there are no architectural actions to perform
576 * at the system level.
577 */
578
579 /*
580 * Plat. management: Perform the platform specific actions
581 * as per the old state of the cluster e.g. enabling
582 * coherency at the interconnect depends upon the state with
583 * which this cluster was powered up. If anything goes wrong
584 * then assert as there is no way to recover from this
585 * situation.
586 */
587 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000588
589 /* Get the physical state of the system */
Achin Gupta75f73672013-12-05 16:33:10 +0000590 plat_state = psci_get_phys_state(system_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100591 rc = psci_plat_pm_ops->affinst_suspend_finish(mpidr,
592 system_node->level,
593 plat_state);
594 assert(rc == PSCI_E_SUCCESS);
595 }
596
Achin Gupta75f73672013-12-05 16:33:10 +0000597 /* State management: Increment the system reference count */
598 psci_set_state(system_node, PSCI_STATE_ON);
599
Achin Gupta4f6ad662013-10-25 09:08:21 +0100600 return rc;
601}
602
Dan Handleye2712bc2014-04-10 15:37:22 +0100603const afflvl_power_on_finisher_t psci_afflvl_suspend_finishers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100604 psci_afflvl0_suspend_finish,
605 psci_afflvl1_suspend_finish,
606 psci_afflvl2_suspend_finish,
607};
608