blob: 1e60276c09c1016073a26094c8ab2fa52099e796 [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
Andrew Thoelke2bc07852014-06-09 12:44:21 +010041typedef int (*afflvl_suspend_handler_t)(aff_map_node_t *,
Achin Gupta4f6ad662013-10-25 09:08:21 +010042 unsigned long,
43 unsigned long,
44 unsigned int);
45
46/*******************************************************************************
Vikram Kanigirif100f412014-04-01 19:26:26 +010047 * This function sets the power state of the current cpu while
48 * powering down during a cpu_suspend call
Achin Guptaa45e3972013-12-05 15:10:48 +000049 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +010050void psci_set_suspend_power_state(aff_map_node_t *node, unsigned int power_state)
Achin Guptaa45e3972013-12-05 15:10:48 +000051{
52 /*
53 * Check that nobody else is calling this function on our behalf &
54 * this information is being set only in the cpu node
55 */
56 assert(node->mpidr == (read_mpidr() & MPIDR_AFFINITY_MASK));
57 assert(node->level == MPIDR_AFFLVL0);
58
59 /*
Andrew Thoelkee9a0d112014-06-20 00:38:03 +010060 * Save PSCI power state parameter for the core in suspend context.
61 * The node is in always-coherent RAM so it does not need to be flushed
Achin Guptaa45e3972013-12-05 15:10:48 +000062 */
Andrew Thoelkee9a0d112014-06-20 00:38:03 +010063 node->power_state = power_state;
Achin Guptaa45e3972013-12-05 15:10:48 +000064}
65
66/*******************************************************************************
Vikram Kanigirif100f412014-04-01 19:26:26 +010067 * This function gets the affinity level till which a cpu is powered down
68 * during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
69 * power state saved for the node is invalid
70 ******************************************************************************/
71int psci_get_suspend_afflvl(unsigned long mpidr)
72{
Dan Handleye2712bc2014-04-10 15:37:22 +010073 aff_map_node_t *node;
Vikram Kanigirif100f412014-04-01 19:26:26 +010074
75 node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK,
76 MPIDR_AFFLVL0);
77 assert(node);
78
79 return psci_get_aff_map_node_suspend_afflvl(node);
80}
81
82
83/*******************************************************************************
Achin Guptaa45e3972013-12-05 15:10:48 +000084 * This function gets the affinity level till which the current cpu was powered
Vikram Kanigirif100f412014-04-01 19:26:26 +010085 * down during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
86 * power state saved for the node is invalid
87 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +010088int psci_get_aff_map_node_suspend_afflvl(aff_map_node_t *node)
Vikram Kanigirif100f412014-04-01 19:26:26 +010089{
90 unsigned int power_state;
91
92 assert(node->level == MPIDR_AFFLVL0);
93
Andrew Thoelkee9a0d112014-06-20 00:38:03 +010094 power_state = node->power_state;
Vikram Kanigirif100f412014-04-01 19:26:26 +010095 return ((power_state == PSCI_INVALID_DATA) ?
96 power_state : psci_get_pstate_afflvl(power_state));
97}
98
99/*******************************************************************************
100 * This function gets the state id of a cpu stored in suspend context
101 * while powering down during a cpu_suspend call. Returns 0xFFFFFFFF
102 * if the power state saved for the node is invalid
Achin Guptaa45e3972013-12-05 15:10:48 +0000103 ******************************************************************************/
Vikram Kanigirif100f412014-04-01 19:26:26 +0100104int psci_get_suspend_stateid(unsigned long mpidr)
Achin Guptaa45e3972013-12-05 15:10:48 +0000105{
Dan Handleye2712bc2014-04-10 15:37:22 +0100106 aff_map_node_t *node;
Vikram Kanigirif100f412014-04-01 19:26:26 +0100107 unsigned int power_state;
108
109 node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK,
110 MPIDR_AFFLVL0);
111 assert(node);
112 assert(node->level == MPIDR_AFFLVL0);
113
Andrew Thoelkee9a0d112014-06-20 00:38:03 +0100114 power_state = node->power_state;
Vikram Kanigirif100f412014-04-01 19:26:26 +0100115 return ((power_state == PSCI_INVALID_DATA) ?
116 power_state : psci_get_pstate_id(power_state));
Achin Guptaa45e3972013-12-05 15:10:48 +0000117}
118
119/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +0100120 * The next three functions implement a handler for each supported affinity
121 * level which is called when that affinity level is about to be suspended.
122 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100123static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100124 unsigned long ns_entrypoint,
125 unsigned long context_id,
126 unsigned int power_state)
127{
Andrew Thoelke4e126072014-06-04 21:10:52 +0100128 unsigned int plat_state;
Achin Guptae1aa5162014-06-26 09:58:52 +0100129 unsigned long psci_entrypoint;
Andrew Thoelke4e126072014-06-04 21:10:52 +0100130 uint32_t ns_scr_el3 = read_scr_el3();
131 uint32_t ns_sctlr_el1 = read_sctlr_el1();
132 int rc;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100133
134 /* Sanity check to safeguard against data corruption */
135 assert(cpu_node->level == MPIDR_AFFLVL0);
136
Vikram Kanigirif100f412014-04-01 19:26:26 +0100137 /* Save PSCI power state parameter for the core in suspend context */
138 psci_set_suspend_power_state(cpu_node, power_state);
139
Achin Gupta607084e2014-02-09 18:24:19 +0000140 /*
141 * Generic management: Store the re-entry information for the non-secure
142 * world and allow the secure world to suspend itself
143 */
144
145 /*
146 * Call the cpu suspend handler registered by the Secure Payload
147 * Dispatcher to let it do any bookeeping. If the handler encounters an
148 * error, it's expected to assert within
149 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000150 if (psci_spd_pm && psci_spd_pm->svc_suspend)
151 psci_spd_pm->svc_suspend(power_state);
Achin Gupta607084e2014-02-09 18:24:19 +0000152
Achin Gupta75f73672013-12-05 16:33:10 +0000153 /* State management: mark this cpu as suspended */
154 psci_set_state(cpu_node, PSCI_STATE_SUSPEND);
155
Achin Gupta4f6ad662013-10-25 09:08:21 +0100156 /*
157 * Generic management: Store the re-entry information for the
158 * non-secure world
159 */
Andrew Thoelke4e126072014-06-04 21:10:52 +0100160 rc = psci_save_ns_entry(read_mpidr_el1(), ns_entrypoint, context_id,
161 ns_scr_el3, ns_sctlr_el1);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100162 if (rc != PSCI_E_SUCCESS)
163 return rc;
164
165 /*
Achin Guptaef7a28c2014-02-01 08:59:56 +0000166 * Arch. management: Save the EL3 state in the 'cpu_context'
167 * structure that has been allocated for this cpu, flush the
Achin Gupta4f6ad662013-10-25 09:08:21 +0100168 * L1 caches and exit intra-cluster coherency et al
169 */
Achin Guptaef7a28c2014-02-01 08:59:56 +0000170 cm_el3_sysregs_context_save(NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100171
172 /* Set the secure world (EL3) re-entry point after BL1 */
173 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
174
175 /*
176 * Arch. management. Perform the necessary steps to flush all
177 * cpu caches.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100178 */
Achin Guptae1aa5162014-06-26 09:58:52 +0100179 psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100180
181 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100182 * Plat. management: Allow the platform to perform the
183 * necessary actions to turn off this cpu e.g. set the
184 * platform defined mailbox with the psci entrypoint,
185 * program the power controller etc.
186 */
Andrew Thoelke4e126072014-06-04 21:10:52 +0100187 rc = PSCI_E_SUCCESS;
188
Achin Gupta4f6ad662013-10-25 09:08:21 +0100189 if (psci_plat_pm_ops->affinst_suspend) {
Achin Gupta75f73672013-12-05 16:33:10 +0000190 plat_state = psci_get_phys_state(cpu_node);
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100191 rc = psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100192 psci_entrypoint,
193 ns_entrypoint,
194 cpu_node->level,
195 plat_state);
196 }
197
198 return rc;
199}
200
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100201static int psci_afflvl1_suspend(aff_map_node_t *cluster_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100202 unsigned long ns_entrypoint,
203 unsigned long context_id,
204 unsigned int power_state)
205{
206 int rc = PSCI_E_SUCCESS;
207 unsigned int plat_state;
208 unsigned long psci_entrypoint;
209
210 /* Sanity check the cluster level */
211 assert(cluster_node->level == MPIDR_AFFLVL1);
212
Achin Gupta75f73672013-12-05 16:33:10 +0000213 /* State management: Decrement the cluster reference count */
214 psci_set_state(cluster_node, PSCI_STATE_SUSPEND);
215
Achin Gupta4f6ad662013-10-25 09:08:21 +0100216 /*
217 * Keep the physical state of this cluster handy to decide
218 * what action needs to be taken
219 */
Achin Gupta75f73672013-12-05 16:33:10 +0000220 plat_state = psci_get_phys_state(cluster_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100221
222 /*
223 * Arch. management: Flush all levels of caches to PoC if the
224 * cluster is to be shutdown
225 */
226 if (plat_state == PSCI_STATE_OFF)
227 dcsw_op_all(DCCISW);
228
229 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +0000230 * Plat. Management. Allow the platform to do its cluster
Achin Gupta4f6ad662013-10-25 09:08:21 +0100231 * specific bookeeping e.g. turn off interconnect coherency,
232 * program the power controller etc.
233 */
234 if (psci_plat_pm_ops->affinst_suspend) {
235
236 /*
237 * Sending the psci entrypoint is currently redundant
238 * beyond affinity level 0 but one never knows what a
239 * platform might do. Also it allows us to keep the
240 * platform handler prototype the same.
241 */
242 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100243 rc = psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100244 psci_entrypoint,
245 ns_entrypoint,
246 cluster_node->level,
247 plat_state);
248 }
249
250 return rc;
251}
252
253
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100254static int psci_afflvl2_suspend(aff_map_node_t *system_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100255 unsigned long ns_entrypoint,
256 unsigned long context_id,
257 unsigned int power_state)
258{
259 int rc = PSCI_E_SUCCESS;
260 unsigned int plat_state;
261 unsigned long psci_entrypoint;
262
263 /* Cannot go beyond this */
264 assert(system_node->level == MPIDR_AFFLVL2);
265
Achin Gupta75f73672013-12-05 16:33:10 +0000266 /* State management: Decrement the system reference count */
267 psci_set_state(system_node, PSCI_STATE_SUSPEND);
268
Achin Gupta4f6ad662013-10-25 09:08:21 +0100269 /*
270 * Keep the physical state of the system handy to decide what
271 * action needs to be taken
272 */
Achin Gupta75f73672013-12-05 16:33:10 +0000273 plat_state = psci_get_phys_state(system_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100274
275 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +0000276 * Plat. Management : Allow the platform to do its bookeeping
Achin Gupta4f6ad662013-10-25 09:08:21 +0100277 * at this affinity level
278 */
279 if (psci_plat_pm_ops->affinst_suspend) {
280
281 /*
282 * Sending the psci entrypoint is currently redundant
283 * beyond affinity level 0 but one never knows what a
284 * platform might do. Also it allows us to keep the
285 * platform handler prototype the same.
286 */
287 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100288 rc = psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100289 psci_entrypoint,
290 ns_entrypoint,
291 system_node->level,
292 plat_state);
293 }
294
295 return rc;
296}
297
Dan Handleye2712bc2014-04-10 15:37:22 +0100298static const afflvl_suspend_handler_t psci_afflvl_suspend_handlers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100299 psci_afflvl0_suspend,
300 psci_afflvl1_suspend,
301 psci_afflvl2_suspend,
302};
303
304/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000305 * This function takes an array of pointers to affinity instance nodes in the
306 * topology tree and calls the suspend handler for the corresponding affinity
307 * levels
308 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +0100309static int psci_call_suspend_handlers(mpidr_aff_map_nodes_t mpidr_nodes,
Achin Gupta0959db52013-12-02 17:33:04 +0000310 int start_afflvl,
311 int end_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000312 unsigned long entrypoint,
313 unsigned long context_id,
314 unsigned int power_state)
315{
316 int rc = PSCI_E_INVALID_PARAMS, level;
Dan Handleye2712bc2014-04-10 15:37:22 +0100317 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000318
319 for (level = start_afflvl; level <= end_afflvl; level++) {
320 node = mpidr_nodes[level];
321 if (node == NULL)
322 continue;
323
324 /*
325 * TODO: In case of an error should there be a way
326 * of restoring what we might have torn down at
327 * lower affinity levels.
328 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100329 rc = psci_afflvl_suspend_handlers[level](node,
Achin Gupta0959db52013-12-02 17:33:04 +0000330 entrypoint,
331 context_id,
332 power_state);
333 if (rc != PSCI_E_SUCCESS)
334 break;
335 }
336
337 return rc;
338}
339
340/*******************************************************************************
341 * Top level handler which is called when a cpu wants to suspend its execution.
342 * It is assumed that along with turning the cpu off, higher affinity levels
343 * until the target affinity level will be turned off as well. It traverses
344 * through all the affinity levels performing generic, architectural, platform
345 * setup and state management e.g. for a cluster that's to be suspended, it will
346 * call the platform specific code which will disable coherency at the
347 * interconnect level if the cpu is the last in the cluster. For a cpu it could
348 * mean programming the power controller etc.
349 *
350 * The state of all the relevant affinity levels is changed prior to calling the
351 * affinity level specific handlers as their actions would depend upon the state
352 * the affinity level is about to enter.
353 *
354 * The affinity level specific handlers are called in ascending order i.e. from
355 * the lowest to the highest affinity level implemented by the platform because
356 * to turn off affinity level X it is neccesary to turn off affinity level X - 1
357 * first.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100358 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100359int psci_afflvl_suspend(unsigned long entrypoint,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100360 unsigned long context_id,
361 unsigned int power_state,
Achin Gupta0959db52013-12-02 17:33:04 +0000362 int start_afflvl,
363 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100364{
Achin Gupta0959db52013-12-02 17:33:04 +0000365 int rc = PSCI_E_SUCCESS;
Dan Handleye2712bc2014-04-10 15:37:22 +0100366 mpidr_aff_map_nodes_t mpidr_nodes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100367
Achin Gupta4f6ad662013-10-25 09:08:21 +0100368 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000369 * Collect the pointers to the nodes in the topology tree for
370 * each affinity instance in the mpidr. If this function does
371 * not return successfully then either the mpidr or the affinity
372 * levels are incorrect.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100373 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100374 rc = psci_get_aff_map_nodes(read_mpidr_el1() & MPIDR_AFFINITY_MASK,
Achin Gupta0959db52013-12-02 17:33:04 +0000375 start_afflvl,
376 end_afflvl,
377 mpidr_nodes);
378 if (rc != PSCI_E_SUCCESS)
379 return rc;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100380
381 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000382 * This function acquires the lock corresponding to each affinity
383 * level so that by the time all locks are taken, the system topology
384 * is snapshot and state management can be done safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100385 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100386 psci_acquire_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000387 end_afflvl,
388 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100389
Achin Gupta0959db52013-12-02 17:33:04 +0000390 /* Perform generic, architecture and platform specific handling */
391 rc = psci_call_suspend_handlers(mpidr_nodes,
392 start_afflvl,
393 end_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000394 entrypoint,
395 context_id,
396 power_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100397
398 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000399 * Release the locks corresponding to each affinity level in the
400 * reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100401 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100402 psci_release_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000403 end_afflvl,
404 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100405
Achin Gupta4f6ad662013-10-25 09:08:21 +0100406 return rc;
407}
408
409/*******************************************************************************
410 * The following functions finish an earlier affinity suspend request. They
411 * are called by the common finisher routine in psci_common.c.
412 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100413static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100414{
Andrew Thoelke4e126072014-06-04 21:10:52 +0100415 unsigned int plat_state, state, rc;
Achin Gupta607084e2014-02-09 18:24:19 +0000416 int32_t suspend_level;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100417
418 assert(cpu_node->level == MPIDR_AFFLVL0);
419
Achin Gupta0959db52013-12-02 17:33:04 +0000420 /* Ensure we have been woken up from a suspended state */
Achin Gupta75f73672013-12-05 16:33:10 +0000421 state = psci_get_state(cpu_node);
Achin Gupta0959db52013-12-02 17:33:04 +0000422 assert(state == PSCI_STATE_SUSPEND);
423
Achin Gupta4f6ad662013-10-25 09:08:21 +0100424 /*
425 * Plat. management: Perform the platform specific actions
426 * before we change the state of the cpu e.g. enabling the
427 * gic or zeroing the mailbox register. If anything goes
428 * wrong then assert as there is no way to recover from this
429 * situation.
430 */
431 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000432
433 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000434 plat_state = get_phys_state(state);
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100435 rc = psci_plat_pm_ops->affinst_suspend_finish(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100436 cpu_node->level,
437 plat_state);
438 assert(rc == PSCI_E_SUCCESS);
439 }
440
441 /* Get the index for restoring the re-entry information */
Achin Gupta4f6ad662013-10-25 09:08:21 +0100442 /*
Achin Guptae1aa5162014-06-26 09:58:52 +0100443 * Arch. management: Enable the data cache, manage stack memory and
444 * restore the stashed EL3 architectural context from the 'cpu_context'
445 * structure for this cpu.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100446 */
Achin Guptae1aa5162014-06-26 09:58:52 +0100447 psci_do_pwrup_cache_maintenance();
Achin Guptaef7a28c2014-02-01 08:59:56 +0000448 cm_el3_sysregs_context_restore(NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100449
450 /*
Achin Gupta607084e2014-02-09 18:24:19 +0000451 * Call the cpu suspend finish handler registered by the Secure Payload
452 * Dispatcher to let it do any bookeeping. If the handler encounters an
453 * error, it's expected to assert within
454 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000455 if (psci_spd_pm && psci_spd_pm->svc_suspend) {
Vikram Kanigirif100f412014-04-01 19:26:26 +0100456 suspend_level = psci_get_aff_map_node_suspend_afflvl(cpu_node);
457 assert (suspend_level != PSCI_INVALID_DATA);
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000458 psci_spd_pm->svc_suspend_finish(suspend_level);
Achin Gupta607084e2014-02-09 18:24:19 +0000459 }
460
Vikram Kanigirif100f412014-04-01 19:26:26 +0100461 /* Invalidate the suspend context for the node */
462 psci_set_suspend_power_state(cpu_node, PSCI_INVALID_DATA);
463
Achin Gupta607084e2014-02-09 18:24:19 +0000464 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100465 * Generic management: Now we just need to retrieve the
466 * information that we had stashed away during the suspend
Achin Gupta3140a9e2013-12-02 16:23:12 +0000467 * call to set this cpu on its way.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100468 */
Andrew Thoelke4e126072014-06-04 21:10:52 +0100469 cm_prepare_el3_exit(NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100470
Achin Gupta75f73672013-12-05 16:33:10 +0000471 /* State management: mark this cpu as on */
472 psci_set_state(cpu_node, PSCI_STATE_ON);
473
Achin Gupta4f6ad662013-10-25 09:08:21 +0100474 /* Clean caches before re-entering normal world */
475 dcsw_op_louis(DCCSW);
476
Andrew Thoelke4e126072014-06-04 21:10:52 +0100477 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100478 return rc;
479}
480
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100481static unsigned int psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100482{
Achin Gupta0959db52013-12-02 17:33:04 +0000483 unsigned int plat_state, rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100484
485 assert(cluster_node->level == MPIDR_AFFLVL1);
486
487 /*
488 * Plat. management: Perform the platform specific actions
489 * as per the old state of the cluster e.g. enabling
490 * coherency at the interconnect depends upon the state with
491 * which this cluster was powered up. If anything goes wrong
492 * then assert as there is no way to recover from this
493 * situation.
494 */
495 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000496
497 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000498 plat_state = psci_get_phys_state(cluster_node);
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100499 rc = psci_plat_pm_ops->affinst_suspend_finish(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100500 cluster_node->level,
501 plat_state);
502 assert(rc == PSCI_E_SUCCESS);
503 }
504
Achin Gupta75f73672013-12-05 16:33:10 +0000505 /* State management: Increment the cluster reference count */
506 psci_set_state(cluster_node, PSCI_STATE_ON);
507
Achin Gupta4f6ad662013-10-25 09:08:21 +0100508 return rc;
509}
510
511
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100512static unsigned int psci_afflvl2_suspend_finish(aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100513{
Achin Gupta0959db52013-12-02 17:33:04 +0000514 unsigned int plat_state, rc = PSCI_E_SUCCESS;;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100515
516 /* Cannot go beyond this affinity level */
517 assert(system_node->level == MPIDR_AFFLVL2);
518
519 /*
520 * Currently, there are no architectural actions to perform
521 * at the system level.
522 */
523
524 /*
525 * Plat. management: Perform the platform specific actions
526 * as per the old state of the cluster e.g. enabling
527 * coherency at the interconnect depends upon the state with
528 * which this cluster was powered up. If anything goes wrong
529 * then assert as there is no way to recover from this
530 * situation.
531 */
532 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000533
534 /* Get the physical state of the system */
Achin Gupta75f73672013-12-05 16:33:10 +0000535 plat_state = psci_get_phys_state(system_node);
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100536 rc = psci_plat_pm_ops->affinst_suspend_finish(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100537 system_node->level,
538 plat_state);
539 assert(rc == PSCI_E_SUCCESS);
540 }
541
Achin Gupta75f73672013-12-05 16:33:10 +0000542 /* State management: Increment the system reference count */
543 psci_set_state(system_node, PSCI_STATE_ON);
544
Achin Gupta4f6ad662013-10-25 09:08:21 +0100545 return rc;
546}
547
Dan Handleye2712bc2014-04-10 15:37:22 +0100548const afflvl_power_on_finisher_t psci_afflvl_suspend_finishers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100549 psci_afflvl0_suspend_finish,
550 psci_afflvl1_suspend_finish,
551 psci_afflvl2_suspend_finish,
552};