blob: 70cc98d1269aeca347779bc7dff0bc0c6de16923 [file] [log] [blame]
Soby Mathew991d42c2015-06-29 16:30:12 +01001/*
Soby Mathew3a9e8bf2015-05-05 16:33:16 +01002 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
Soby Mathew991d42c2015-06-29 16:30:12 +01003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <arch.h>
32#include <arch_helpers.h>
33#include <assert.h>
34#include <bl_common.h>
35#include <context.h>
36#include <context_mgmt.h>
37#include <debug.h>
38#include <platform.h>
39#include <string.h>
40#include "psci_private.h"
41
42/*
43 * SPD power management operations, expected to be supplied by the registered
44 * SPD on successful SP initialization
45 */
46const spd_pm_ops_t *psci_spd_pm;
47
Soby Mathew85dbf5a2015-04-07 12:16:56 +010048/*
49 * PSCI requested local power state map. This array is used to store the local
50 * power states requested by a CPU for power levels from level 1 to
51 * PLAT_MAX_PWR_LVL. It does not store the requested local power state for power
52 * level 0 (PSCI_CPU_PWR_LVL) as the requested and the target power state for a
53 * CPU are the same.
54 *
55 * During state coordination, the platform is passed an array containing the
56 * local states requested for a particular non cpu power domain by each cpu
57 * within the domain.
58 *
59 * TODO: Dense packing of the requested states will cause cache thrashing
60 * when multiple power domains write to it. If we allocate the requested
61 * states at each power level in a cache-line aligned per-domain memory,
62 * the cache thrashing can be avoided.
63 */
64static plat_local_state_t
65 psci_req_local_pwr_states[PLAT_MAX_PWR_LVL][PLATFORM_CORE_COUNT];
66
67
Soby Mathew991d42c2015-06-29 16:30:12 +010068/*******************************************************************************
Soby Mathew9d754f62015-04-08 17:42:06 +010069 * Arrays that hold the platform's power domain tree information for state
70 * management of power domains.
71 * Each node in the array 'psci_non_cpu_pd_nodes' corresponds to a power domain
72 * which is an ancestor of a CPU power domain.
73 * Each node in the array 'psci_cpu_pd_nodes' corresponds to a cpu power domain
Soby Mathew991d42c2015-06-29 16:30:12 +010074 ******************************************************************************/
Soby Mathew9d754f62015-04-08 17:42:06 +010075non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS]
Soby Mathew991d42c2015-06-29 16:30:12 +010076#if USE_COHERENT_MEM
77__attribute__ ((section("tzfw_coherent_mem")))
78#endif
79;
80
Soby Mathew9d754f62015-04-08 17:42:06 +010081cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];
82
Soby Mathew991d42c2015-06-29 16:30:12 +010083/*******************************************************************************
84 * Pointer to functions exported by the platform to complete power mgmt. ops
85 ******************************************************************************/
Soby Mathew85dbf5a2015-04-07 12:16:56 +010086const plat_psci_ops_t *psci_plat_pm_ops;
Soby Mathew991d42c2015-06-29 16:30:12 +010087
Soby Mathew85dbf5a2015-04-07 12:16:56 +010088/******************************************************************************
Soby Mathew3a9e8bf2015-05-05 16:33:16 +010089 * Check that the maximum power level supported by the platform makes sense
Soby Mathew85dbf5a2015-04-07 12:16:56 +010090 *****************************************************************************/
Soby Mathew9d754f62015-04-08 17:42:06 +010091CASSERT(PLAT_MAX_PWR_LVL <= PSCI_MAX_PWR_LVL && \
92 PLAT_MAX_PWR_LVL >= PSCI_CPU_PWR_LVL, \
Soby Mathew3a9e8bf2015-05-05 16:33:16 +010093 assert_platform_max_pwrlvl_check);
Soby Mathew991d42c2015-06-29 16:30:12 +010094
Soby Mathew85dbf5a2015-04-07 12:16:56 +010095/*
96 * The plat_local_state used by the platform is one of these types: RUN,
97 * RETENTION and OFF. The platform can define further sub-states for each type
98 * apart from RUN. This categorization is done to verify the sanity of the
99 * psci_power_state passed by the platform and to print debug information. The
100 * categorization is done on the basis of the following conditions:
101 *
102 * 1. If (plat_local_state == 0) then the category is STATE_TYPE_RUN.
103 *
104 * 2. If (0 < plat_local_state <= PLAT_MAX_RET_STATE), then the category is
105 * STATE_TYPE_RETN.
106 *
107 * 3. If (plat_local_state > PLAT_MAX_RET_STATE), then the category is
108 * STATE_TYPE_OFF.
109 */
110typedef enum plat_local_state_type {
111 STATE_TYPE_RUN = 0,
112 STATE_TYPE_RETN,
113 STATE_TYPE_OFF
114} plat_local_state_type_t;
Soby Mathew991d42c2015-06-29 16:30:12 +0100115
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100116/* The macro used to categorize plat_local_state. */
117#define find_local_state_type(plat_local_state) \
118 ((plat_local_state) ? ((plat_local_state > PLAT_MAX_RET_STATE) \
119 ? STATE_TYPE_OFF : STATE_TYPE_RETN) \
120 : STATE_TYPE_RUN)
Soby Mathew991d42c2015-06-29 16:30:12 +0100121
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100122/******************************************************************************
123 * Check that the maximum retention level supported by the platform is less
124 * than the maximum off level.
125 *****************************************************************************/
126CASSERT(PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE, \
127 assert_platform_max_off_and_retn_state_check);
Soby Mathew9d754f62015-04-08 17:42:06 +0100128
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100129/******************************************************************************
130 * This function ensures that the power state parameter in a CPU_SUSPEND request
131 * is valid. If so, it returns the requested states for each power level.
132 *****************************************************************************/
133int psci_validate_power_state(unsigned int power_state,
134 psci_power_state_t *state_info)
135{
136 /* Check SBZ bits in power state are zero */
137 if (psci_check_power_state(power_state))
138 return PSCI_E_INVALID_PARAMS;
Soby Mathew9d754f62015-04-08 17:42:06 +0100139
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100140 assert(psci_plat_pm_ops->validate_power_state);
141
142 /* Validate the power_state using platform pm_ops */
143 return psci_plat_pm_ops->validate_power_state(power_state, state_info);
144}
145
146/******************************************************************************
147 * This function retrieves the `psci_power_state_t` for system suspend from
148 * the platform.
149 *****************************************************************************/
150void psci_query_sys_suspend_pwrstate(psci_power_state_t *state_info)
151{
152 /*
153 * Assert that the required pm_ops hook is implemented to ensure that
154 * the capability detected during psci_setup() is valid.
155 */
156 assert(psci_plat_pm_ops->get_sys_suspend_power_state);
Soby Mathew991d42c2015-06-29 16:30:12 +0100157
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100158 /*
159 * Query the platform for the power_state required for system suspend
160 */
161 psci_plat_pm_ops->get_sys_suspend_power_state(state_info);
Soby Mathew991d42c2015-06-29 16:30:12 +0100162}
163
164/*******************************************************************************
165 * This function verifies that the all the other cores in the system have been
166 * turned OFF and the current CPU is the last running CPU in the system.
167 * Returns 1 (true) if the current CPU is the last ON CPU or 0 (false)
168 * otherwise.
169 ******************************************************************************/
170unsigned int psci_is_last_on_cpu(void)
171{
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100172 unsigned int cpu_idx, my_idx = plat_my_core_pos();
Soby Mathew991d42c2015-06-29 16:30:12 +0100173
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100174 for (cpu_idx = 0; cpu_idx < PLATFORM_CORE_COUNT; cpu_idx++) {
175 if (cpu_idx == my_idx) {
176 assert(psci_get_aff_info_state() == AFF_STATE_ON);
Soby Mathew991d42c2015-06-29 16:30:12 +0100177 continue;
178 }
179
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100180 if (psci_get_aff_info_state_by_idx(cpu_idx) != AFF_STATE_OFF)
Soby Mathew991d42c2015-06-29 16:30:12 +0100181 return 0;
182 }
183
184 return 1;
185}
186
187/*******************************************************************************
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100188 * Routine to return the maximum power level to traverse to after a cpu has
Soby Mathew991d42c2015-06-29 16:30:12 +0100189 * been physically powered up. It is expected to be called immediately after
190 * reset from assembler code.
191 ******************************************************************************/
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100192int get_power_on_target_pwrlvl(void)
Soby Mathew991d42c2015-06-29 16:30:12 +0100193{
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100194 int pwrlvl;
Soby Mathew991d42c2015-06-29 16:30:12 +0100195
Soby Mathew991d42c2015-06-29 16:30:12 +0100196 /*
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100197 * Assume that this cpu was suspended and retrieve its target power
Soby Mathew991d42c2015-06-29 16:30:12 +0100198 * level. If it is invalid then it could only have been turned off
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100199 * earlier. PLAT_MAX_PWR_LVL will be the highest power level a
Soby Mathew991d42c2015-06-29 16:30:12 +0100200 * cpu can be turned off to.
201 */
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100202 pwrlvl = psci_get_suspend_pwrlvl();
203 if (pwrlvl == PSCI_INVALID_DATA)
204 pwrlvl = PLAT_MAX_PWR_LVL;
205 return pwrlvl;
Soby Mathew991d42c2015-06-29 16:30:12 +0100206}
207
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100208/******************************************************************************
209 * Helper function to update the requested local power state array. This array
210 * does not store the requested state for the CPU power level. Hence an
211 * assertion is added to prevent us from accessing the wrong index.
212 *****************************************************************************/
213static void psci_set_req_local_pwr_state(unsigned int pwrlvl,
214 unsigned int cpu_idx,
215 plat_local_state_t req_pwr_state)
216{
217 assert(pwrlvl > PSCI_CPU_PWR_LVL);
218 psci_req_local_pwr_states[pwrlvl - 1][cpu_idx] = req_pwr_state;
219}
220
221/******************************************************************************
222 * This function initializes the psci_req_local_pwr_states.
223 *****************************************************************************/
224void psci_init_req_local_pwr_states(void)
225{
226 /* Initialize the requested state of all non CPU power domains as OFF */
227 memset(&psci_req_local_pwr_states, PLAT_MAX_OFF_STATE,
228 sizeof(psci_req_local_pwr_states));
229}
230
231/******************************************************************************
232 * Helper function to return a reference to an array containing the local power
233 * states requested by each cpu for a power domain at 'pwrlvl'. The size of the
234 * array will be the number of cpu power domains of which this power domain is
235 * an ancestor. These requested states will be used to determine a suitable
236 * target state for this power domain during psci state coordination. An
237 * assertion is added to prevent us from accessing the CPU power level.
238 *****************************************************************************/
239static plat_local_state_t *psci_get_req_local_pwr_states(int pwrlvl,
240 int cpu_idx)
241{
242 assert(pwrlvl > PSCI_CPU_PWR_LVL);
243
244 return &psci_req_local_pwr_states[pwrlvl - 1][cpu_idx];
245}
246
247/******************************************************************************
248 * Helper function to return the current local power state of each power domain
249 * from the current cpu power domain to its ancestor at the 'end_pwrlvl'. This
250 * function will be called after a cpu is powered on to find the local state
251 * each power domain has emerged from.
252 *****************************************************************************/
253static void psci_get_target_local_pwr_states(uint32_t end_pwrlvl,
254 psci_power_state_t *target_state)
255{
256 int lvl;
257 unsigned int parent_idx;
258 plat_local_state_t *pd_state = target_state->pwr_domain_state;
259
260 pd_state[PSCI_CPU_PWR_LVL] = psci_get_cpu_local_state();
261 parent_idx = psci_cpu_pd_nodes[plat_my_core_pos()].parent_node;
262
263 /* Copy the local power state from node to state_info */
264 for (lvl = PSCI_CPU_PWR_LVL + 1; lvl <= end_pwrlvl; lvl++) {
265#if !USE_COHERENT_MEM
266 /*
267 * If using normal memory for psci_non_cpu_pd_nodes, we need
268 * to flush before reading the local power state as another
269 * cpu in the same power domain could have updated it and this
270 * code runs before caches are enabled.
271 */
272 flush_dcache_range(
273 (uint64_t)&psci_non_cpu_pd_nodes[parent_idx],
274 sizeof(psci_non_cpu_pd_nodes[parent_idx]));
275#endif
276 pd_state[lvl] = psci_non_cpu_pd_nodes[parent_idx].local_state;
277 parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
278 }
279
280 /* Set the the higher levels to RUN */
281 for (; lvl <= PLAT_MAX_PWR_LVL; lvl++)
282 target_state->pwr_domain_state[lvl] = PSCI_LOCAL_STATE_RUN;
283}
284
285/******************************************************************************
286 * Helper function to set the target local power state that each power domain
287 * from the current cpu power domain to its ancestor at the 'end_pwrlvl' will
288 * enter. This function will be called after coordination of requested power
289 * states has been done for each power level.
290 *****************************************************************************/
291static void psci_set_target_local_pwr_states(uint32_t end_pwrlvl,
292 const psci_power_state_t *target_state)
293{
294 int lvl;
295 unsigned int parent_idx;
296 const plat_local_state_t *pd_state = target_state->pwr_domain_state;
297
298 psci_set_cpu_local_state(pd_state[PSCI_CPU_PWR_LVL]);
299
300 /*
301 * Need to flush as local_state will be accessed with Data Cache
302 * disabled during power on
303 */
304 flush_cpu_data(psci_svc_cpu_data.local_state);
305
306 parent_idx = psci_cpu_pd_nodes[plat_my_core_pos()].parent_node;
307
308 /* Copy the local_state from state_info */
309 for (lvl = 1; lvl <= end_pwrlvl; lvl++) {
310 psci_non_cpu_pd_nodes[parent_idx].local_state = pd_state[lvl];
311#if !USE_COHERENT_MEM
312 flush_dcache_range(
313 (uint64_t)&psci_non_cpu_pd_nodes[parent_idx],
314 sizeof(psci_non_cpu_pd_nodes[parent_idx]));
315#endif
316 parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
317 }
318}
319
320
Soby Mathew991d42c2015-06-29 16:30:12 +0100321/*******************************************************************************
Soby Mathew9d754f62015-04-08 17:42:06 +0100322 * PSCI helper function to get the parent nodes corresponding to a cpu_index.
Soby Mathew991d42c2015-06-29 16:30:12 +0100323 ******************************************************************************/
Soby Mathew9d754f62015-04-08 17:42:06 +0100324void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx,
325 int end_lvl,
326 unsigned int node_index[])
Soby Mathew991d42c2015-06-29 16:30:12 +0100327{
Soby Mathew9d754f62015-04-08 17:42:06 +0100328 unsigned int parent_node = psci_cpu_pd_nodes[cpu_idx].parent_node;
329 int i;
Soby Mathew991d42c2015-06-29 16:30:12 +0100330
Soby Mathew9d754f62015-04-08 17:42:06 +0100331 for (i = PSCI_CPU_PWR_LVL + 1; i <= end_lvl; i++) {
332 *node_index++ = parent_node;
333 parent_node = psci_non_cpu_pd_nodes[parent_node].parent_node;
334 }
Soby Mathew991d42c2015-06-29 16:30:12 +0100335}
336
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100337/******************************************************************************
338 * This function is invoked post CPU power up and initialization. It sets the
339 * affinity info state, target power state and requested power state for the
340 * current CPU and all its ancestor power domains to RUN.
341 *****************************************************************************/
342void psci_set_pwr_domains_to_run(uint32_t end_pwrlvl)
Soby Mathew991d42c2015-06-29 16:30:12 +0100343{
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100344 int lvl;
345 unsigned int parent_idx, cpu_idx = plat_my_core_pos();
346 parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
Soby Mathew991d42c2015-06-29 16:30:12 +0100347
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100348 /* Reset the local_state to RUN for the non cpu power domains. */
349 for (lvl = PSCI_CPU_PWR_LVL + 1; lvl <= end_pwrlvl; lvl++) {
350 psci_non_cpu_pd_nodes[parent_idx].local_state =
351 PSCI_LOCAL_STATE_RUN;
352#if !USE_COHERENT_MEM
353 flush_dcache_range(
354 (uint64_t)&psci_non_cpu_pd_nodes[parent_idx],
355 sizeof(psci_non_cpu_pd_nodes[parent_idx]));
356#endif
357 psci_set_req_local_pwr_state(lvl,
358 cpu_idx,
359 PSCI_LOCAL_STATE_RUN);
Soby Mathew9d754f62015-04-08 17:42:06 +0100360 parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
Soby Mathew991d42c2015-06-29 16:30:12 +0100361 }
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100362
363 /* Set the affinity info state to ON */
364 psci_set_aff_info_state(AFF_STATE_ON);
365
366 psci_set_cpu_local_state(PSCI_LOCAL_STATE_RUN);
367 flush_cpu_data(psci_svc_cpu_data);
Soby Mathew991d42c2015-06-29 16:30:12 +0100368}
369
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100370/******************************************************************************
371 * This function is passed the local power states requested for each power
372 * domain (state_info) between the current CPU domain and its ancestors until
373 * the target power level (end_pwrlvl). It updates the array of requested power
374 * states with this information.
375 *
376 * Then, for each level (apart from the CPU level) until the 'end_pwrlvl', it
377 * retrieves the states requested by all the cpus of which the power domain at
378 * that level is an ancestor. It passes this information to the platform to
379 * coordinate and return the target power state. If the target state for a level
380 * is RUN then subsequent levels are not considered. At the CPU level, state
381 * coordination is not required. Hence, the requested and the target states are
382 * the same.
383 *
384 * The 'state_info' is updated with the target state for each level between the
385 * CPU and the 'end_pwrlvl' and returned to the caller.
386 *
387 * This function will only be invoked with data cache enabled and while
388 * powering down a core.
389 *****************************************************************************/
390void psci_do_state_coordination(int end_pwrlvl, psci_power_state_t *state_info)
391{
392 unsigned int lvl, parent_idx, cpu_idx = plat_my_core_pos();
393 unsigned int start_idx, ncpus;
394 plat_local_state_t target_state, *req_states;
395
396 parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
397
398 /* For level 0, the requested state will be equivalent
399 to target state */
400 for (lvl = PSCI_CPU_PWR_LVL + 1; lvl <= end_pwrlvl; lvl++) {
401
402 /* First update the requested power state */
403 psci_set_req_local_pwr_state(lvl, cpu_idx,
404 state_info->pwr_domain_state[lvl]);
405
406 /* Get the requested power states for this power level */
407 start_idx = psci_non_cpu_pd_nodes[parent_idx].cpu_start_idx;
408 req_states = psci_get_req_local_pwr_states(lvl, start_idx);
409
410 /*
411 * Let the platform coordinate amongst the requested states at
412 * this power level and return the target local power state.
413 */
414 ncpus = psci_non_cpu_pd_nodes[parent_idx].ncpus;
415 target_state = plat_get_target_pwr_state(lvl,
416 req_states,
417 ncpus);
418
419 state_info->pwr_domain_state[lvl] = target_state;
420
421 /* Break early if the negotiated target power state is RUN */
422 if (is_local_state_run(state_info->pwr_domain_state[lvl]))
423 break;
424
425 parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
426 }
427
428 /*
429 * This is for cases when we break out of the above loop early because
430 * the target power state is RUN at a power level < end_pwlvl.
431 * We update the requested power state from state_info and then
432 * set the target state as RUN.
433 */
434 for (lvl = lvl + 1; lvl <= end_pwrlvl; lvl++) {
435 psci_set_req_local_pwr_state(lvl, cpu_idx,
436 state_info->pwr_domain_state[lvl]);
437 state_info->pwr_domain_state[lvl] = PSCI_LOCAL_STATE_RUN;
438
439 }
440
441 /* Update the target state in the power domain nodes */
442 psci_set_target_local_pwr_states(end_pwrlvl, state_info);
443}
444
445/******************************************************************************
446 * This function validates a suspend request by making sure that if a standby
447 * state is requested then no power level is turned off and the highest power
448 * level is placed in a standby/retention state.
449 *
450 * It also ensures that the state level X will enter is not shallower than the
451 * state level X + 1 will enter.
452 *
453 * This validation will be enabled only for DEBUG builds as the platform is
454 * expected to perform these validations as well.
455 *****************************************************************************/
456int psci_validate_suspend_req(const psci_power_state_t *state_info,
457 unsigned int is_power_down_state)
458{
459 unsigned int max_off_lvl, target_lvl, max_retn_lvl;
460 plat_local_state_t state;
461 plat_local_state_type_t req_state_type, deepest_state_type;
462 int i;
463
464 /* Find the target suspend power level */
465 target_lvl = psci_find_target_suspend_lvl(state_info);
466 if (target_lvl == PSCI_INVALID_DATA)
467 return PSCI_E_INVALID_PARAMS;
468
469 /* All power domain levels are in a RUN state to begin with */
470 deepest_state_type = STATE_TYPE_RUN;
471
472 for (i = target_lvl; i >= PSCI_CPU_PWR_LVL; i--) {
473 state = state_info->pwr_domain_state[i];
474 req_state_type = find_local_state_type(state);
475
476 /*
477 * While traversing from the highest power level to the lowest,
478 * the state requested for lower levels has to be the same or
479 * deeper i.e. equal to or greater than the state at the higher
480 * levels. If this condition is true, then the requested state
481 * becomes the deepest state encountered so far.
482 */
483 if (req_state_type < deepest_state_type)
484 return PSCI_E_INVALID_PARAMS;
485 deepest_state_type = req_state_type;
486 }
487
488 /* Find the highest off power level */
489 max_off_lvl = psci_find_max_off_lvl(state_info);
490
491 /* The target_lvl is either equal to the max_off_lvl or max_retn_lvl */
492 max_retn_lvl = PSCI_INVALID_DATA;
493 if (target_lvl != max_off_lvl)
494 max_retn_lvl = target_lvl;
495
496 /*
497 * If this is not a request for a power down state then max off level
498 * has to be invalid and max retention level has to be a valid power
499 * level.
500 */
501 if (!is_power_down_state && (max_off_lvl != PSCI_INVALID_DATA ||
502 max_retn_lvl == PSCI_INVALID_DATA))
503 return PSCI_E_INVALID_PARAMS;
504
505 return PSCI_E_SUCCESS;
506}
507
508/******************************************************************************
509 * This function finds the highest power level which will be powered down
510 * amongst all the power levels specified in the 'state_info' structure
511 *****************************************************************************/
512unsigned int psci_find_max_off_lvl(const psci_power_state_t *state_info)
513{
514 int i;
515
516 for (i = PLAT_MAX_PWR_LVL; i >= PSCI_CPU_PWR_LVL; i--) {
517 if (is_local_state_off(state_info->pwr_domain_state[i]))
518 return i;
519 }
520
521 return PSCI_INVALID_DATA;
522}
523
524/******************************************************************************
525 * This functions finds the level of the highest power domain which will be
526 * placed in a low power state during a suspend operation.
527 *****************************************************************************/
528unsigned int psci_find_target_suspend_lvl(const psci_power_state_t *state_info)
529{
530 int i;
531
532 for (i = PLAT_MAX_PWR_LVL; i >= PSCI_CPU_PWR_LVL; i--) {
533 if (!is_local_state_run(state_info->pwr_domain_state[i]))
534 return i;
535 }
536
537 return PSCI_INVALID_DATA;
538}
539
Soby Mathew991d42c2015-06-29 16:30:12 +0100540/*******************************************************************************
Soby Mathew9d754f62015-04-08 17:42:06 +0100541 * This function is passed a cpu_index and the highest level in the topology
542 * tree that the operation should be applied to. It picks up locks in order of
543 * increasing power domain level in the range specified.
Soby Mathew991d42c2015-06-29 16:30:12 +0100544 ******************************************************************************/
Soby Mathew9d754f62015-04-08 17:42:06 +0100545void psci_acquire_pwr_domain_locks(int end_pwrlvl, unsigned int cpu_idx)
Soby Mathew991d42c2015-06-29 16:30:12 +0100546{
Soby Mathew9d754f62015-04-08 17:42:06 +0100547 unsigned int parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
Soby Mathew991d42c2015-06-29 16:30:12 +0100548 int level;
549
Soby Mathew9d754f62015-04-08 17:42:06 +0100550 /* No locking required for level 0. Hence start locking from level 1 */
551 for (level = PSCI_CPU_PWR_LVL + 1; level <= end_pwrlvl; level++) {
552 psci_lock_get(&psci_non_cpu_pd_nodes[parent_idx]);
553 parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
Soby Mathew991d42c2015-06-29 16:30:12 +0100554 }
555}
556
557/*******************************************************************************
Soby Mathew9d754f62015-04-08 17:42:06 +0100558 * This function is passed a cpu_index and the highest level in the topology
559 * tree that the operation should be applied to. It releases the locks in order
560 * of decreasing power domain level in the range specified.
Soby Mathew991d42c2015-06-29 16:30:12 +0100561 ******************************************************************************/
Soby Mathew9d754f62015-04-08 17:42:06 +0100562void psci_release_pwr_domain_locks(int end_pwrlvl, unsigned int cpu_idx)
Soby Mathew991d42c2015-06-29 16:30:12 +0100563{
Soby Mathew9d754f62015-04-08 17:42:06 +0100564 unsigned int parent_idx, parent_nodes[PLAT_MAX_PWR_LVL] = {0};
Soby Mathew991d42c2015-06-29 16:30:12 +0100565 int level;
566
Soby Mathew9d754f62015-04-08 17:42:06 +0100567 /* Get the parent nodes */
568 psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes);
Soby Mathew991d42c2015-06-29 16:30:12 +0100569
Soby Mathew9d754f62015-04-08 17:42:06 +0100570 /* Unlock top down. No unlocking required for level 0. */
571 for (level = end_pwrlvl; level >= PSCI_CPU_PWR_LVL + 1; level--) {
572 parent_idx = parent_nodes[level - 1];
573 psci_lock_release(&psci_non_cpu_pd_nodes[parent_idx]);
Soby Mathew991d42c2015-06-29 16:30:12 +0100574 }
575}
576
577/*******************************************************************************
Soby Mathewb0082d22015-04-09 13:40:55 +0100578 * Simple routine to determine whether a mpidr is valid or not.
Soby Mathew991d42c2015-06-29 16:30:12 +0100579 ******************************************************************************/
Soby Mathewb0082d22015-04-09 13:40:55 +0100580int psci_validate_mpidr(unsigned long mpidr)
Soby Mathew991d42c2015-06-29 16:30:12 +0100581{
Soby Mathewb0082d22015-04-09 13:40:55 +0100582 if (plat_core_pos_by_mpidr(mpidr) < 0)
Soby Mathew991d42c2015-06-29 16:30:12 +0100583 return PSCI_E_INVALID_PARAMS;
Soby Mathewb0082d22015-04-09 13:40:55 +0100584
585 return PSCI_E_SUCCESS;
Soby Mathew991d42c2015-06-29 16:30:12 +0100586}
587
588/*******************************************************************************
589 * This function determines the full entrypoint information for the requested
590 * PSCI entrypoint on power on/resume and returns it.
591 ******************************************************************************/
592int psci_get_ns_ep_info(entry_point_info_t *ep,
593 uint64_t entrypoint, uint64_t context_id)
594{
595 uint32_t ep_attr, mode, sctlr, daif, ee;
596 uint32_t ns_scr_el3 = read_scr_el3();
597 uint32_t ns_sctlr_el1 = read_sctlr_el1();
598
599 sctlr = ns_scr_el3 & SCR_HCE_BIT ? read_sctlr_el2() : ns_sctlr_el1;
600 ee = 0;
601
602 ep_attr = NON_SECURE | EP_ST_DISABLE;
603 if (sctlr & SCTLR_EE_BIT) {
604 ep_attr |= EP_EE_BIG;
605 ee = 1;
606 }
607 SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr);
608
609 ep->pc = entrypoint;
610 memset(&ep->args, 0, sizeof(ep->args));
611 ep->args.arg0 = context_id;
612
613 /*
614 * Figure out whether the cpu enters the non-secure address space
615 * in aarch32 or aarch64
616 */
617 if (ns_scr_el3 & SCR_RW_BIT) {
618
619 /*
620 * Check whether a Thumb entry point has been provided for an
621 * aarch64 EL
622 */
623 if (entrypoint & 0x1)
624 return PSCI_E_INVALID_PARAMS;
625
626 mode = ns_scr_el3 & SCR_HCE_BIT ? MODE_EL2 : MODE_EL1;
627
628 ep->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
629 } else {
630
631 mode = ns_scr_el3 & SCR_HCE_BIT ? MODE32_hyp : MODE32_svc;
632
633 /*
634 * TODO: Choose async. exception bits if HYP mode is not
635 * implemented according to the values of SCR.{AW, FW} bits
636 */
637 daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT;
638
639 ep->spsr = SPSR_MODE32(mode, entrypoint & 0x1, ee, daif);
640 }
641
642 return PSCI_E_SUCCESS;
643}
644
645/*******************************************************************************
Soby Mathew991d42c2015-06-29 16:30:12 +0100646 * Generic handler which is called when a cpu is physically powered on. It
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100647 * traverses the node information and finds the highest power level powered
Soby Mathew6b8b3022015-06-30 11:00:24 +0100648 * off and performs generic, architectural, platform setup and state management
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100649 * to power on that power level and power levels below it.
Soby Mathew6b8b3022015-06-30 11:00:24 +0100650 * e.g. For a cpu that's been powered on, it will call the platform specific
651 * code to enable the gic cpu interface and for a cluster it will enable
652 * coherency at the interconnect level in addition to gic cpu interface.
Soby Mathew991d42c2015-06-29 16:30:12 +0100653 ******************************************************************************/
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100654void psci_power_up_finish(int end_pwrlvl,
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100655 pwrlvl_power_on_finisher_t power_on_handler)
Soby Mathew991d42c2015-06-29 16:30:12 +0100656{
Soby Mathew9d754f62015-04-08 17:42:06 +0100657 unsigned int cpu_idx = plat_my_core_pos();
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100658 psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
Soby Mathew991d42c2015-06-29 16:30:12 +0100659
Soby Mathew991d42c2015-06-29 16:30:12 +0100660 /*
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100661 * This function acquires the lock corresponding to each power level so
662 * that by the time all locks are taken, the system topology is snapshot
663 * and state management can be done safely.
Soby Mathew991d42c2015-06-29 16:30:12 +0100664 */
Soby Mathew9d754f62015-04-08 17:42:06 +0100665 psci_acquire_pwr_domain_locks(end_pwrlvl,
666 cpu_idx);
Soby Mathew991d42c2015-06-29 16:30:12 +0100667
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100668 psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
Soby Mathew991d42c2015-06-29 16:30:12 +0100669
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100670 /*
671 * Perform generic, architecture and platform specific handling.
672 */
673 power_on_handler(cpu_idx, &state_info);
Soby Mathew991d42c2015-06-29 16:30:12 +0100674
675 /*
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100676 * Set the requested and target state of this CPU and all the higher
677 * power domains which are ancestors of this CPU to run.
Soby Mathew991d42c2015-06-29 16:30:12 +0100678 */
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100679 psci_set_pwr_domains_to_run(end_pwrlvl);
Soby Mathew991d42c2015-06-29 16:30:12 +0100680
681 /*
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100682 * This loop releases the lock corresponding to each power level
Soby Mathew991d42c2015-06-29 16:30:12 +0100683 * in the reverse order to which they were acquired.
684 */
Soby Mathew9d754f62015-04-08 17:42:06 +0100685 psci_release_pwr_domain_locks(end_pwrlvl,
686 cpu_idx);
Soby Mathew991d42c2015-06-29 16:30:12 +0100687}
688
689/*******************************************************************************
690 * This function initializes the set of hooks that PSCI invokes as part of power
691 * management operation. The power management hooks are expected to be provided
692 * by the SPD, after it finishes all its initialization
693 ******************************************************************************/
694void psci_register_spd_pm_hook(const spd_pm_ops_t *pm)
695{
696 assert(pm);
697 psci_spd_pm = pm;
698
699 if (pm->svc_migrate)
700 psci_caps |= define_psci_cap(PSCI_MIG_AARCH64);
701
702 if (pm->svc_migrate_info)
703 psci_caps |= define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64)
704 | define_psci_cap(PSCI_MIG_INFO_TYPE);
705}
706
707/*******************************************************************************
708 * This function invokes the migrate info hook in the spd_pm_ops. It performs
709 * the necessary return value validation. If the Secure Payload is UP and
710 * migrate capable, it returns the mpidr of the CPU on which the Secure payload
711 * is resident through the mpidr parameter. Else the value of the parameter on
712 * return is undefined.
713 ******************************************************************************/
714int psci_spd_migrate_info(uint64_t *mpidr)
715{
716 int rc;
717
718 if (!psci_spd_pm || !psci_spd_pm->svc_migrate_info)
719 return PSCI_E_NOT_SUPPORTED;
720
721 rc = psci_spd_pm->svc_migrate_info(mpidr);
722
723 assert(rc == PSCI_TOS_UP_MIG_CAP || rc == PSCI_TOS_NOT_UP_MIG_CAP \
724 || rc == PSCI_TOS_NOT_PRESENT_MP || rc == PSCI_E_NOT_SUPPORTED);
725
726 return rc;
727}
728
729
730/*******************************************************************************
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100731 * This function prints the state of all power domains present in the
Soby Mathew991d42c2015-06-29 16:30:12 +0100732 * system
733 ******************************************************************************/
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100734void psci_print_power_domain_map(void)
Soby Mathew991d42c2015-06-29 16:30:12 +0100735{
736#if LOG_LEVEL >= LOG_LEVEL_INFO
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100737 unsigned int idx;
738 plat_local_state_t state;
739 plat_local_state_type_t state_type;
Soby Mathew9d754f62015-04-08 17:42:06 +0100740
Soby Mathew991d42c2015-06-29 16:30:12 +0100741 /* This array maps to the PSCI_STATE_X definitions in psci.h */
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100742 static const char *psci_state_type_str[] = {
Soby Mathew991d42c2015-06-29 16:30:12 +0100743 "ON",
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100744 "RETENTION",
Soby Mathew991d42c2015-06-29 16:30:12 +0100745 "OFF",
Soby Mathew991d42c2015-06-29 16:30:12 +0100746 };
747
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100748 INFO("PSCI Power Domain Map:\n");
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100749 for (idx = 0; idx < (PSCI_NUM_PWR_DOMAINS - PLATFORM_CORE_COUNT);
750 idx++) {
751 state_type = find_local_state_type(
752 psci_non_cpu_pd_nodes[idx].local_state);
753 INFO(" Domain Node : Level %u, parent_node %d,"
754 " State %s (0x%x)\n",
Soby Mathew9d754f62015-04-08 17:42:06 +0100755 psci_non_cpu_pd_nodes[idx].level,
756 psci_non_cpu_pd_nodes[idx].parent_node,
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100757 psci_state_type_str[state_type],
758 psci_non_cpu_pd_nodes[idx].local_state);
Soby Mathew9d754f62015-04-08 17:42:06 +0100759 }
760
761 for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++) {
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100762 state = psci_get_cpu_local_state_by_idx(idx);
763 state_type = find_local_state_type(state);
764 INFO(" CPU Node : MPID 0x%lx, parent_node %d,"
765 " State %s (0x%x)\n",
Soby Mathew9d754f62015-04-08 17:42:06 +0100766 psci_cpu_pd_nodes[idx].mpidr,
767 psci_cpu_pd_nodes[idx].parent_node,
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100768 psci_state_type_str[state_type],
769 psci_get_cpu_local_state_by_idx(idx));
Soby Mathew991d42c2015-06-29 16:30:12 +0100770 }
771#endif
772}