blob: 70f90a1511f8575f8341c97da2a58e2c05af39e4 [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>
Soby Mathew2ed46e92014-07-04 16:02:26 +010037#include <platform.h>
Dan Handleybcd60ba2014-04-17 18:53:42 +010038#include <runtime_svc.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010039#include <stddef.h>
Dan Handley714a0d22014-04-09 13:13:04 +010040#include "psci_private.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010041
Andrew Thoelke2bc07852014-06-09 12:44:21 +010042typedef int (*afflvl_suspend_handler_t)(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
60 /*
Andrew Thoelkee9a0d112014-06-20 00:38:03 +010061 * Save PSCI power state parameter for the core in suspend context.
62 * The node is in always-coherent RAM so it does not need to be flushed
Achin Guptaa45e3972013-12-05 15:10:48 +000063 */
Andrew Thoelkee9a0d112014-06-20 00:38:03 +010064 node->power_state = power_state;
Achin Guptaa45e3972013-12-05 15:10:48 +000065}
66
67/*******************************************************************************
Vikram Kanigirif100f412014-04-01 19:26:26 +010068 * This function gets the affinity level till which a cpu is powered down
69 * during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
70 * power state saved for the node is invalid
71 ******************************************************************************/
72int psci_get_suspend_afflvl(unsigned long mpidr)
73{
Dan Handleye2712bc2014-04-10 15:37:22 +010074 aff_map_node_t *node;
Vikram Kanigirif100f412014-04-01 19:26:26 +010075
76 node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK,
77 MPIDR_AFFLVL0);
78 assert(node);
79
80 return psci_get_aff_map_node_suspend_afflvl(node);
81}
82
83
84/*******************************************************************************
Achin Guptaa45e3972013-12-05 15:10:48 +000085 * This function gets the affinity level till which the current cpu was powered
Vikram Kanigirif100f412014-04-01 19:26:26 +010086 * down during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
87 * power state saved for the node is invalid
88 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +010089int psci_get_aff_map_node_suspend_afflvl(aff_map_node_t *node)
Vikram Kanigirif100f412014-04-01 19:26:26 +010090{
91 unsigned int power_state;
92
93 assert(node->level == MPIDR_AFFLVL0);
94
Andrew Thoelkee9a0d112014-06-20 00:38:03 +010095 power_state = node->power_state;
Vikram Kanigirif100f412014-04-01 19:26:26 +010096 return ((power_state == PSCI_INVALID_DATA) ?
97 power_state : psci_get_pstate_afflvl(power_state));
98}
99
100/*******************************************************************************
101 * This function gets the state id of a cpu stored in suspend context
102 * while powering down during a cpu_suspend call. Returns 0xFFFFFFFF
103 * if the power state saved for the node is invalid
Achin Guptaa45e3972013-12-05 15:10:48 +0000104 ******************************************************************************/
Vikram Kanigirif100f412014-04-01 19:26:26 +0100105int psci_get_suspend_stateid(unsigned long mpidr)
Achin Guptaa45e3972013-12-05 15:10:48 +0000106{
Dan Handleye2712bc2014-04-10 15:37:22 +0100107 aff_map_node_t *node;
Vikram Kanigirif100f412014-04-01 19:26:26 +0100108 unsigned int power_state;
109
110 node = psci_get_aff_map_node(mpidr & MPIDR_AFFINITY_MASK,
111 MPIDR_AFFLVL0);
112 assert(node);
113 assert(node->level == MPIDR_AFFLVL0);
114
Andrew Thoelkee9a0d112014-06-20 00:38:03 +0100115 power_state = node->power_state;
Vikram Kanigirif100f412014-04-01 19:26:26 +0100116 return ((power_state == PSCI_INVALID_DATA) ?
117 power_state : psci_get_pstate_id(power_state));
Achin Guptaa45e3972013-12-05 15:10:48 +0000118}
119
120/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +0100121 * The next three functions implement a handler for each supported affinity
122 * level which is called when that affinity level is about to be suspended.
123 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100124static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100125 unsigned long ns_entrypoint,
126 unsigned long context_id,
127 unsigned int power_state)
128{
Andrew Thoelke4e126072014-06-04 21:10:52 +0100129 unsigned int plat_state;
Achin Guptae1aa5162014-06-26 09:58:52 +0100130 unsigned long psci_entrypoint;
Andrew Thoelke4e126072014-06-04 21:10:52 +0100131 uint32_t ns_scr_el3 = read_scr_el3();
132 uint32_t ns_sctlr_el1 = read_sctlr_el1();
133 int rc;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100134
135 /* Sanity check to safeguard against data corruption */
136 assert(cpu_node->level == MPIDR_AFFLVL0);
137
Vikram Kanigirif100f412014-04-01 19:26:26 +0100138 /* Save PSCI power state parameter for the core in suspend context */
139 psci_set_suspend_power_state(cpu_node, power_state);
140
Achin Gupta607084e2014-02-09 18:24:19 +0000141 /*
142 * Generic management: Store the re-entry information for the non-secure
143 * world and allow the secure world to suspend itself
144 */
145
146 /*
147 * Call the cpu suspend handler registered by the Secure Payload
148 * Dispatcher to let it do any bookeeping. If the handler encounters an
149 * error, it's expected to assert within
150 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000151 if (psci_spd_pm && psci_spd_pm->svc_suspend)
152 psci_spd_pm->svc_suspend(power_state);
Achin Gupta607084e2014-02-09 18:24:19 +0000153
Achin Gupta75f73672013-12-05 16:33:10 +0000154 /* State management: mark this cpu as suspended */
155 psci_set_state(cpu_node, PSCI_STATE_SUSPEND);
156
Achin Gupta4f6ad662013-10-25 09:08:21 +0100157 /*
158 * Generic management: Store the re-entry information for the
159 * non-secure world
160 */
Andrew Thoelke4e126072014-06-04 21:10:52 +0100161 rc = psci_save_ns_entry(read_mpidr_el1(), ns_entrypoint, context_id,
162 ns_scr_el3, ns_sctlr_el1);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100163 if (rc != PSCI_E_SUCCESS)
164 return rc;
165
Achin Gupta4f6ad662013-10-25 09:08:21 +0100166 /* Set the secure world (EL3) re-entry point after BL1 */
167 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
168
169 /*
170 * Arch. management. Perform the necessary steps to flush all
171 * cpu caches.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100172 */
Achin Guptae1aa5162014-06-26 09:58:52 +0100173 psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100174
175 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100176 * Plat. management: Allow the platform to perform the
177 * necessary actions to turn off this cpu e.g. set the
178 * platform defined mailbox with the psci entrypoint,
179 * program the power controller etc.
180 */
Andrew Thoelke4e126072014-06-04 21:10:52 +0100181 rc = PSCI_E_SUCCESS;
182
Achin Gupta4f6ad662013-10-25 09:08:21 +0100183 if (psci_plat_pm_ops->affinst_suspend) {
Achin Gupta75f73672013-12-05 16:33:10 +0000184 plat_state = psci_get_phys_state(cpu_node);
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100185 rc = psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100186 psci_entrypoint,
187 ns_entrypoint,
188 cpu_node->level,
189 plat_state);
190 }
191
192 return rc;
193}
194
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100195static int psci_afflvl1_suspend(aff_map_node_t *cluster_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100196 unsigned long ns_entrypoint,
197 unsigned long context_id,
198 unsigned int power_state)
199{
200 int rc = PSCI_E_SUCCESS;
201 unsigned int plat_state;
202 unsigned long psci_entrypoint;
203
204 /* Sanity check the cluster level */
205 assert(cluster_node->level == MPIDR_AFFLVL1);
206
Achin Gupta75f73672013-12-05 16:33:10 +0000207 /* State management: Decrement the cluster reference count */
208 psci_set_state(cluster_node, PSCI_STATE_SUSPEND);
209
Achin Gupta4f6ad662013-10-25 09:08:21 +0100210 /*
211 * Keep the physical state of this cluster handy to decide
212 * what action needs to be taken
213 */
Achin Gupta75f73672013-12-05 16:33:10 +0000214 plat_state = psci_get_phys_state(cluster_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100215
216 /*
217 * Arch. management: Flush all levels of caches to PoC if the
218 * cluster is to be shutdown
219 */
220 if (plat_state == PSCI_STATE_OFF)
221 dcsw_op_all(DCCISW);
222
223 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +0000224 * Plat. Management. Allow the platform to do its cluster
Achin Gupta4f6ad662013-10-25 09:08:21 +0100225 * specific bookeeping e.g. turn off interconnect coherency,
226 * program the power controller etc.
227 */
228 if (psci_plat_pm_ops->affinst_suspend) {
229
230 /*
231 * Sending the psci entrypoint is currently redundant
232 * beyond affinity level 0 but one never knows what a
233 * platform might do. Also it allows us to keep the
234 * platform handler prototype the same.
235 */
236 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100237 rc = psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100238 psci_entrypoint,
239 ns_entrypoint,
240 cluster_node->level,
241 plat_state);
242 }
243
244 return rc;
245}
246
247
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100248static int psci_afflvl2_suspend(aff_map_node_t *system_node,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100249 unsigned long ns_entrypoint,
250 unsigned long context_id,
251 unsigned int power_state)
252{
253 int rc = PSCI_E_SUCCESS;
254 unsigned int plat_state;
255 unsigned long psci_entrypoint;
256
257 /* Cannot go beyond this */
258 assert(system_node->level == MPIDR_AFFLVL2);
259
Achin Gupta75f73672013-12-05 16:33:10 +0000260 /* State management: Decrement the system reference count */
261 psci_set_state(system_node, PSCI_STATE_SUSPEND);
262
Achin Gupta4f6ad662013-10-25 09:08:21 +0100263 /*
264 * Keep the physical state of the system handy to decide what
265 * action needs to be taken
266 */
Achin Gupta75f73672013-12-05 16:33:10 +0000267 plat_state = psci_get_phys_state(system_node);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100268
269 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +0000270 * Plat. Management : Allow the platform to do its bookeeping
Achin Gupta4f6ad662013-10-25 09:08:21 +0100271 * at this affinity level
272 */
273 if (psci_plat_pm_ops->affinst_suspend) {
274
275 /*
276 * Sending the psci entrypoint is currently redundant
277 * beyond affinity level 0 but one never knows what a
278 * platform might do. Also it allows us to keep the
279 * platform handler prototype the same.
280 */
281 psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry;
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100282 rc = psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100283 psci_entrypoint,
284 ns_entrypoint,
285 system_node->level,
286 plat_state);
287 }
288
289 return rc;
290}
291
Dan Handleye2712bc2014-04-10 15:37:22 +0100292static const afflvl_suspend_handler_t psci_afflvl_suspend_handlers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100293 psci_afflvl0_suspend,
294 psci_afflvl1_suspend,
295 psci_afflvl2_suspend,
296};
297
298/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000299 * This function takes an array of pointers to affinity instance nodes in the
300 * topology tree and calls the suspend handler for the corresponding affinity
301 * levels
302 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +0100303static int psci_call_suspend_handlers(mpidr_aff_map_nodes_t mpidr_nodes,
Achin Gupta0959db52013-12-02 17:33:04 +0000304 int start_afflvl,
305 int end_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000306 unsigned long entrypoint,
307 unsigned long context_id,
308 unsigned int power_state)
309{
310 int rc = PSCI_E_INVALID_PARAMS, level;
Dan Handleye2712bc2014-04-10 15:37:22 +0100311 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000312
313 for (level = start_afflvl; level <= end_afflvl; level++) {
314 node = mpidr_nodes[level];
315 if (node == NULL)
316 continue;
317
318 /*
319 * TODO: In case of an error should there be a way
320 * of restoring what we might have torn down at
321 * lower affinity levels.
322 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100323 rc = psci_afflvl_suspend_handlers[level](node,
Achin Gupta0959db52013-12-02 17:33:04 +0000324 entrypoint,
325 context_id,
326 power_state);
327 if (rc != PSCI_E_SUCCESS)
328 break;
329 }
330
331 return rc;
332}
333
334/*******************************************************************************
335 * Top level handler which is called when a cpu wants to suspend its execution.
336 * It is assumed that along with turning the cpu off, higher affinity levels
337 * until the target affinity level will be turned off as well. It traverses
338 * through all the affinity levels performing generic, architectural, platform
339 * setup and state management e.g. for a cluster that's to be suspended, it will
340 * call the platform specific code which will disable coherency at the
341 * interconnect level if the cpu is the last in the cluster. For a cpu it could
342 * mean programming the power controller etc.
343 *
344 * The state of all the relevant affinity levels is changed prior to calling the
345 * affinity level specific handlers as their actions would depend upon the state
346 * the affinity level is about to enter.
347 *
348 * The affinity level specific handlers are called in ascending order i.e. from
349 * the lowest to the highest affinity level implemented by the platform because
350 * to turn off affinity level X it is neccesary to turn off affinity level X - 1
351 * first.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100352 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100353int psci_afflvl_suspend(unsigned long entrypoint,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100354 unsigned long context_id,
355 unsigned int power_state,
Achin Gupta0959db52013-12-02 17:33:04 +0000356 int start_afflvl,
357 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100358{
Achin Gupta0959db52013-12-02 17:33:04 +0000359 int rc = PSCI_E_SUCCESS;
Dan Handleye2712bc2014-04-10 15:37:22 +0100360 mpidr_aff_map_nodes_t mpidr_nodes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100361
Achin Gupta4f6ad662013-10-25 09:08:21 +0100362 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000363 * Collect the pointers to the nodes in the topology tree for
364 * each affinity instance in the mpidr. If this function does
365 * not return successfully then either the mpidr or the affinity
366 * levels are incorrect.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100367 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100368 rc = psci_get_aff_map_nodes(read_mpidr_el1() & MPIDR_AFFINITY_MASK,
Achin Gupta0959db52013-12-02 17:33:04 +0000369 start_afflvl,
370 end_afflvl,
371 mpidr_nodes);
372 if (rc != PSCI_E_SUCCESS)
373 return rc;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100374
375 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000376 * This function acquires the lock corresponding to each affinity
377 * level so that by the time all locks are taken, the system topology
378 * is snapshot and state management can be done safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100379 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100380 psci_acquire_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000381 end_afflvl,
382 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100383
Achin Gupta0959db52013-12-02 17:33:04 +0000384 /* Perform generic, architecture and platform specific handling */
385 rc = psci_call_suspend_handlers(mpidr_nodes,
386 start_afflvl,
387 end_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000388 entrypoint,
389 context_id,
390 power_state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100391
392 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000393 * Release the locks corresponding to each affinity level in the
394 * reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100395 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100396 psci_release_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000397 end_afflvl,
398 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100399
Achin Gupta4f6ad662013-10-25 09:08:21 +0100400 return rc;
401}
402
403/*******************************************************************************
404 * The following functions finish an earlier affinity suspend request. They
405 * are called by the common finisher routine in psci_common.c.
406 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100407static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100408{
Andrew Thoelke4e126072014-06-04 21:10:52 +0100409 unsigned int plat_state, state, rc;
Achin Gupta607084e2014-02-09 18:24:19 +0000410 int32_t suspend_level;
Soby Mathew2ed46e92014-07-04 16:02:26 +0100411 uint64_t counter_freq;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100412
413 assert(cpu_node->level == MPIDR_AFFLVL0);
414
Achin Gupta0959db52013-12-02 17:33:04 +0000415 /* Ensure we have been woken up from a suspended state */
Achin Gupta75f73672013-12-05 16:33:10 +0000416 state = psci_get_state(cpu_node);
Achin Gupta0959db52013-12-02 17:33:04 +0000417 assert(state == PSCI_STATE_SUSPEND);
418
Achin Gupta4f6ad662013-10-25 09:08:21 +0100419 /*
420 * Plat. management: Perform the platform specific actions
421 * before we change the state of the cpu e.g. enabling the
422 * gic or zeroing the mailbox register. If anything goes
423 * wrong then assert as there is no way to recover from this
424 * situation.
425 */
426 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000427
428 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000429 plat_state = get_phys_state(state);
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100430 rc = psci_plat_pm_ops->affinst_suspend_finish(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100431 cpu_node->level,
432 plat_state);
433 assert(rc == PSCI_E_SUCCESS);
434 }
435
436 /* Get the index for restoring the re-entry information */
Achin Gupta4f6ad662013-10-25 09:08:21 +0100437 /*
Achin Guptae1aa5162014-06-26 09:58:52 +0100438 * Arch. management: Enable the data cache, manage stack memory and
439 * restore the stashed EL3 architectural context from the 'cpu_context'
440 * structure for this cpu.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100441 */
Achin Guptae1aa5162014-06-26 09:58:52 +0100442 psci_do_pwrup_cache_maintenance();
Soby Mathew2ed46e92014-07-04 16:02:26 +0100443
444 /* Re-init the cntfrq_el0 register */
445 counter_freq = plat_get_syscnt_freq();
446 write_cntfrq_el0(counter_freq);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100447
448 /*
Achin Gupta607084e2014-02-09 18:24:19 +0000449 * Call the cpu suspend finish handler registered by the Secure Payload
450 * Dispatcher to let it do any bookeeping. If the handler encounters an
451 * error, it's expected to assert within
452 */
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000453 if (psci_spd_pm && psci_spd_pm->svc_suspend) {
Vikram Kanigirif100f412014-04-01 19:26:26 +0100454 suspend_level = psci_get_aff_map_node_suspend_afflvl(cpu_node);
455 assert (suspend_level != PSCI_INVALID_DATA);
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000456 psci_spd_pm->svc_suspend_finish(suspend_level);
Achin Gupta607084e2014-02-09 18:24:19 +0000457 }
458
Vikram Kanigirif100f412014-04-01 19:26:26 +0100459 /* Invalidate the suspend context for the node */
460 psci_set_suspend_power_state(cpu_node, PSCI_INVALID_DATA);
461
Achin Gupta607084e2014-02-09 18:24:19 +0000462 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +0100463 * Generic management: Now we just need to retrieve the
464 * information that we had stashed away during the suspend
Achin Gupta3140a9e2013-12-02 16:23:12 +0000465 * call to set this cpu on its way.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100466 */
Andrew Thoelke4e126072014-06-04 21:10:52 +0100467 cm_prepare_el3_exit(NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100468
Achin Gupta75f73672013-12-05 16:33:10 +0000469 /* State management: mark this cpu as on */
470 psci_set_state(cpu_node, PSCI_STATE_ON);
471
Achin Gupta4f6ad662013-10-25 09:08:21 +0100472 /* Clean caches before re-entering normal world */
473 dcsw_op_louis(DCCSW);
474
Andrew Thoelke4e126072014-06-04 21:10:52 +0100475 rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100476 return rc;
477}
478
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100479static unsigned int psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100480{
Achin Gupta0959db52013-12-02 17:33:04 +0000481 unsigned int plat_state, rc = PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100482
483 assert(cluster_node->level == MPIDR_AFFLVL1);
484
485 /*
486 * Plat. management: Perform the platform specific actions
487 * as per the old state of the cluster e.g. enabling
488 * coherency at the interconnect depends upon the state with
489 * which this cluster was powered up. If anything goes wrong
490 * then assert as there is no way to recover from this
491 * situation.
492 */
493 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000494
495 /* Get the physical state of this cpu */
Achin Gupta75f73672013-12-05 16:33:10 +0000496 plat_state = psci_get_phys_state(cluster_node);
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100497 rc = psci_plat_pm_ops->affinst_suspend_finish(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100498 cluster_node->level,
499 plat_state);
500 assert(rc == PSCI_E_SUCCESS);
501 }
502
Achin Gupta75f73672013-12-05 16:33:10 +0000503 /* State management: Increment the cluster reference count */
504 psci_set_state(cluster_node, PSCI_STATE_ON);
505
Achin Gupta4f6ad662013-10-25 09:08:21 +0100506 return rc;
507}
508
509
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100510static unsigned int psci_afflvl2_suspend_finish(aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100511{
Achin Gupta0959db52013-12-02 17:33:04 +0000512 unsigned int plat_state, rc = PSCI_E_SUCCESS;;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100513
514 /* Cannot go beyond this affinity level */
515 assert(system_node->level == MPIDR_AFFLVL2);
516
517 /*
518 * Currently, there are no architectural actions to perform
519 * at the system level.
520 */
521
522 /*
523 * Plat. management: Perform the platform specific actions
524 * as per the old state of the cluster e.g. enabling
525 * coherency at the interconnect depends upon the state with
526 * which this cluster was powered up. If anything goes wrong
527 * then assert as there is no way to recover from this
528 * situation.
529 */
530 if (psci_plat_pm_ops->affinst_suspend_finish) {
Achin Gupta0959db52013-12-02 17:33:04 +0000531
532 /* Get the physical state of the system */
Achin Gupta75f73672013-12-05 16:33:10 +0000533 plat_state = psci_get_phys_state(system_node);
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100534 rc = psci_plat_pm_ops->affinst_suspend_finish(read_mpidr_el1(),
Achin Gupta4f6ad662013-10-25 09:08:21 +0100535 system_node->level,
536 plat_state);
537 assert(rc == PSCI_E_SUCCESS);
538 }
539
Achin Gupta75f73672013-12-05 16:33:10 +0000540 /* State management: Increment the system reference count */
541 psci_set_state(system_node, PSCI_STATE_ON);
542
Achin Gupta4f6ad662013-10-25 09:08:21 +0100543 return rc;
544}
545
Dan Handleye2712bc2014-04-10 15:37:22 +0100546const afflvl_power_on_finisher_t psci_afflvl_suspend_finishers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100547 psci_afflvl0_suspend_finish,
548 psci_afflvl1_suspend_finish,
549 psci_afflvl2_suspend_finish,
550};