blob: ab731fb60f8855a3b4e7d86125dd8ebbc9932c6b [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 Handley97043ac2014-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 Handley97043ac2014-04-09 13:14:54 +010035#include <context.h>
Achin Guptaef7a28c2014-02-01 08:59:56 +000036#include <context_mgmt.h>
Dan Handley5b827a82014-04-17 18:53:42 +010037#include <runtime_svc.h>
Dan Handley97043ac2014-04-09 13:14:54 +010038#include <stddef.h>
Dan Handley35e98e52014-04-09 13:13:04 +010039#include "psci_private.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010040
Andrew Thoelke56378aa2014-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 Kanigiri759ec932014-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 Handleyfb037bf2014-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 Thoelke13ac44a2014-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 Thoelke13ac44a2014-06-20 00:38:03 +010063 node->power_state = power_state;
Achin Guptaa45e3972013-12-05 15:10:48 +000064}
65
66/*******************************************************************************
Vikram Kanigiri759ec932014-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
Achin Guptaa45e3972013-12-05 15:10:48 +000070 ******************************************************************************/
Vikram Kanigiri759ec932014-04-01 19:26:26 +010071int psci_get_suspend_afflvl(unsigned long mpidr)
Achin Guptaa45e3972013-12-05 15:10:48 +000072{
Dan Handleyfb037bf2014-04-10 15:37:22 +010073 aff_map_node_t *node;
Vikram Kanigiri759ec932014-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/*******************************************************************************
84 * This function gets the affinity level till which the current cpu was powered
85 * down during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
86 * power state saved for the node is invalid
87 ******************************************************************************/
Dan Handleyfb037bf2014-04-10 15:37:22 +010088int psci_get_aff_map_node_suspend_afflvl(aff_map_node_t *node)
Vikram Kanigiri759ec932014-04-01 19:26:26 +010089{
90 unsigned int power_state;
91
92 assert(node->level == MPIDR_AFFLVL0);
93
Andrew Thoelke13ac44a2014-06-20 00:38:03 +010094 power_state = node->power_state;
Vikram Kanigiri759ec932014-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
103 ******************************************************************************/
104int psci_get_suspend_stateid(unsigned long mpidr)
105{
Dan Handleyfb037bf2014-04-10 15:37:22 +0100106 aff_map_node_t *node;
Vikram Kanigiri759ec932014-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 Thoelke13ac44a2014-06-20 00:38:03 +0100114 power_state = node->power_state;
Vikram Kanigiri759ec932014-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 Thoelke56378aa2014-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 Thoelke167a9352014-06-04 21:10:52 +0100128 unsigned int plat_state;
Achin Guptab51da822014-06-26 09:58:52 +0100129 unsigned long psci_entrypoint;
Andrew Thoelke167a9352014-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 Kanigiri759ec932014-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 Thoelke167a9352014-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 Guptab51da822014-06-26 09:58:52 +0100179 psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100180
181 /*
182 * 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 Thoelke167a9352014-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 Thoelke56378aa2014-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 Thoelke56378aa2014-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 Thoelke56378aa2014-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 Thoelke56378aa2014-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 Thoelke56378aa2014-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 Handleyfb037bf2014-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 Handleyfb037bf2014-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 Handleyfb037bf2014-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 Thoelke56378aa2014-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.
358 *
359 * CAUTION: This function is called with coherent stacks so that coherency can
360 * be turned off and caches can be flushed safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100361 ******************************************************************************/
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100362int psci_afflvl_suspend(unsigned long entrypoint,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100363 unsigned long context_id,
364 unsigned int power_state,
Achin Gupta0959db52013-12-02 17:33:04 +0000365 int start_afflvl,
366 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100367{
Achin Gupta0959db52013-12-02 17:33:04 +0000368 int rc = PSCI_E_SUCCESS;
Dan Handleyfb037bf2014-04-10 15:37:22 +0100369 mpidr_aff_map_nodes_t mpidr_nodes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100370
Achin Gupta4f6ad662013-10-25 09:08:21 +0100371 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000372 * Collect the pointers to the nodes in the topology tree for
373 * each affinity instance in the mpidr. If this function does
374 * not return successfully then either the mpidr or the affinity
375 * levels are incorrect.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100376 */
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100377 rc = psci_get_aff_map_nodes(read_mpidr_el1() & MPIDR_AFFINITY_MASK,
Achin Gupta0959db52013-12-02 17:33:04 +0000378 start_afflvl,
379 end_afflvl,
380 mpidr_nodes);
381 if (rc != PSCI_E_SUCCESS)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100382 return rc;
383
Achin Gupta0959db52013-12-02 17:33:04 +0000384 /*
385 * This function acquires the lock corresponding to each affinity
386 * level so that by the time all locks are taken, the system topology
387 * is snapshot and state management can be done safely.
388 */
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100389 psci_acquire_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000390 end_afflvl,
391 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100392
Achin Gupta0959db52013-12-02 17:33:04 +0000393 /* Perform generic, architecture and platform specific handling */
394 rc = psci_call_suspend_handlers(mpidr_nodes,
395 start_afflvl,
396 end_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000397 entrypoint,
398 context_id,
399 power_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100400
401 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000402 * Release the locks corresponding to each affinity level in the
403 * reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100404 */
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100405 psci_release_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000406 end_afflvl,
407 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100408
Achin Gupta4f6ad662013-10-25 09:08:21 +0100409 return rc;
410}
411
412/*******************************************************************************
413 * The following functions finish an earlier affinity suspend request. They
414 * are called by the common finisher routine in psci_common.c.
415 ******************************************************************************/
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100416static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100417{
Andrew Thoelke167a9352014-06-04 21:10:52 +0100418 unsigned int plat_state, state, rc;
Achin Gupta607084e2014-02-09 18:24:19 +0000419 int32_t suspend_level;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100420
421 assert(cpu_node->level == MPIDR_AFFLVL0);
422
Achin Gupta0959db52013-12-02 17:33:04 +0000423 /* Ensure we have been woken up from a suspended state */
Achin Gupta75f73672013-12-05 16:33:10 +0000424 state = psci_get_state(cpu_node);
Achin Gupta0959db52013-12-02 17:33:04 +0000425 assert(state == PSCI_STATE_SUSPEND);
426
Achin Gupta4f6ad662013-10-25 09:08:21 +0100427 /*
428 * Plat. management: Perform the platform specific actions
429 * before we change the state of the cpu e.g. enabling the
430 * gic or zeroing the mailbox register. If anything goes
431 * wrong then assert as there is no way to recover from this
432 * situation.
433 */
434 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000435
436 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000437 plat_state = get_phys_state(state);
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100438 rc = psci_plat_pm_ops->affinst_suspend_finish(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100439 cpu_node->level,
440 plat_state);
441 assert(rc == PSCI_E_SUCCESS);
442 }
443
444 /* Get the index for restoring the re-entry information */
Achin Gupta4f6ad662013-10-25 09:08:21 +0100445 /*
Achin Guptab51da822014-06-26 09:58:52 +0100446 * Arch. management: Enable the data cache, manage stack memory and
447 * restore the stashed EL3 architectural context from the 'cpu_context'
448 * structure for this cpu.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100449 */
Achin Guptab51da822014-06-26 09:58:52 +0100450 psci_do_pwrup_cache_maintenance();
Achin Guptaef7a28c2014-02-01 08:59:56 +0000451 cm_el3_sysregs_context_restore(NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100452
453 /*
Achin Gupta607084e2014-02-09 18:24:19 +0000454 * Call the cpu suspend finish handler registered by the Secure Payload
455 * Dispatcher to let it do any bookeeping. If the handler encounters an
456 * error, it's expected to assert within
457 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000458 if (psci_spd_pm && psci_spd_pm->svc_suspend) {
Vikram Kanigiri759ec932014-04-01 19:26:26 +0100459 suspend_level = psci_get_aff_map_node_suspend_afflvl(cpu_node);
460 assert (suspend_level != PSCI_INVALID_DATA);
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000461 psci_spd_pm->svc_suspend_finish(suspend_level);
Achin Gupta607084e2014-02-09 18:24:19 +0000462 }
463
Vikram Kanigiri759ec932014-04-01 19:26:26 +0100464 /* Invalidate the suspend context for the node */
465 psci_set_suspend_power_state(cpu_node, PSCI_INVALID_DATA);
466
Achin Gupta607084e2014-02-09 18:24:19 +0000467 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100468 * Generic management: Now we just need to retrieve the
469 * information that we had stashed away during the suspend
Achin Gupta3140a9e2013-12-02 16:23:12 +0000470 * call to set this cpu on its way.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100471 */
Andrew Thoelke167a9352014-06-04 21:10:52 +0100472 cm_prepare_el3_exit(NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100473
Achin Gupta75f73672013-12-05 16:33:10 +0000474 /* State management: mark this cpu as on */
475 psci_set_state(cpu_node, PSCI_STATE_ON);
476
Achin Gupta4f6ad662013-10-25 09:08:21 +0100477 /* Clean caches before re-entering normal world */
478 dcsw_op_louis(DCCSW);
479
Andrew Thoelke167a9352014-06-04 21:10:52 +0100480 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100481 return rc;
482}
483
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100484static unsigned int psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100485{
Achin Gupta0959db52013-12-02 17:33:04 +0000486 unsigned int plat_state, rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100487
488 assert(cluster_node->level == MPIDR_AFFLVL1);
489
490 /*
491 * Plat. management: Perform the platform specific actions
492 * as per the old state of the cluster e.g. enabling
493 * coherency at the interconnect depends upon the state with
494 * which this cluster was powered up. If anything goes wrong
495 * then assert as there is no way to recover from this
496 * situation.
497 */
498 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000499
500 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000501 plat_state = psci_get_phys_state(cluster_node);
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100502 rc = psci_plat_pm_ops->affinst_suspend_finish(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100503 cluster_node->level,
504 plat_state);
505 assert(rc == PSCI_E_SUCCESS);
506 }
507
Achin Gupta75f73672013-12-05 16:33:10 +0000508 /* State management: Increment the cluster reference count */
509 psci_set_state(cluster_node, PSCI_STATE_ON);
510
Achin Gupta4f6ad662013-10-25 09:08:21 +0100511 return rc;
512}
513
514
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100515static unsigned int psci_afflvl2_suspend_finish(aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100516{
Achin Gupta0959db52013-12-02 17:33:04 +0000517 unsigned int plat_state, rc = PSCI_E_SUCCESS;;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100518
519 /* Cannot go beyond this affinity level */
520 assert(system_node->level == MPIDR_AFFLVL2);
521
522 /*
523 * Currently, there are no architectural actions to perform
524 * at the system level.
525 */
526
527 /*
528 * Plat. management: Perform the platform specific actions
529 * as per the old state of the cluster e.g. enabling
530 * coherency at the interconnect depends upon the state with
531 * which this cluster was powered up. If anything goes wrong
532 * then assert as there is no way to recover from this
533 * situation.
534 */
535 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000536
537 /* Get the physical state of the system */
Achin Gupta75f73672013-12-05 16:33:10 +0000538 plat_state = psci_get_phys_state(system_node);
Andrew Thoelke56378aa2014-06-09 12:44:21 +0100539 rc = psci_plat_pm_ops->affinst_suspend_finish(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100540 system_node->level,
541 plat_state);
542 assert(rc == PSCI_E_SUCCESS);
543 }
544
Achin Gupta75f73672013-12-05 16:33:10 +0000545 /* State management: Increment the system reference count */
546 psci_set_state(system_node, PSCI_STATE_ON);
547
Achin Gupta4f6ad662013-10-25 09:08:21 +0100548 return rc;
549}
550
Dan Handleyfb037bf2014-04-10 15:37:22 +0100551const afflvl_power_on_finisher_t psci_afflvl_suspend_finishers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100552 psci_afflvl0_suspend_finish,
553 psci_afflvl1_suspend_finish,
554 psci_afflvl2_suspend_finish,
555};