blob: 55bf7ef893b13c763b74ce75e377b5fa342ff374 [file] [log] [blame]
Soby Mathewb48349e2015-06-29 16:30:12 +01001/*
2 * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
3 *
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
48/*******************************************************************************
49 * Grand array that holds the platform's topology information for state
50 * management of affinity instances. Each node (aff_map_node) in the array
51 * corresponds to an affinity instance e.g. cluster, cpu within an mpidr
52 ******************************************************************************/
53aff_map_node_t psci_aff_map[PSCI_NUM_AFFS]
54#if USE_COHERENT_MEM
55__attribute__ ((section("tzfw_coherent_mem")))
56#endif
57;
58
59/*******************************************************************************
60 * Pointer to functions exported by the platform to complete power mgmt. ops
61 ******************************************************************************/
62const plat_pm_ops_t *psci_plat_pm_ops;
63
64/*******************************************************************************
65 * Check that the maximum affinity level supported by the platform makes sense
66 * ****************************************************************************/
67CASSERT(PLATFORM_MAX_AFFLVL <= MPIDR_MAX_AFFLVL && \
68 PLATFORM_MAX_AFFLVL >= MPIDR_AFFLVL0, \
69 assert_platform_max_afflvl_check);
70
71/*******************************************************************************
72 * This function is passed an array of pointers to affinity level nodes in the
73 * topology tree for an mpidr. It iterates through the nodes to find the highest
74 * affinity level which is marked as physically powered off.
75 ******************************************************************************/
76uint32_t psci_find_max_phys_off_afflvl(uint32_t start_afflvl,
77 uint32_t end_afflvl,
78 aff_map_node_t *mpidr_nodes[])
79{
80 uint32_t max_afflvl = PSCI_INVALID_DATA;
81
82 for (; start_afflvl <= end_afflvl; start_afflvl++) {
83 if (mpidr_nodes[start_afflvl] == NULL)
84 continue;
85
86 if (psci_get_phys_state(mpidr_nodes[start_afflvl]) ==
87 PSCI_STATE_OFF)
88 max_afflvl = start_afflvl;
89 }
90
91 return max_afflvl;
92}
93
94/*******************************************************************************
95 * This function verifies that the all the other cores in the system have been
96 * turned OFF and the current CPU is the last running CPU in the system.
97 * Returns 1 (true) if the current CPU is the last ON CPU or 0 (false)
98 * otherwise.
99 ******************************************************************************/
100unsigned int psci_is_last_on_cpu(void)
101{
102 unsigned long mpidr = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
103 unsigned int i;
104
105 for (i = psci_aff_limits[MPIDR_AFFLVL0].min;
106 i <= psci_aff_limits[MPIDR_AFFLVL0].max; i++) {
107
108 assert(psci_aff_map[i].level == MPIDR_AFFLVL0);
109
110 if (!(psci_aff_map[i].state & PSCI_AFF_PRESENT))
111 continue;
112
113 if (psci_aff_map[i].mpidr == mpidr) {
114 assert(psci_get_state(&psci_aff_map[i])
115 == PSCI_STATE_ON);
116 continue;
117 }
118
119 if (psci_get_state(&psci_aff_map[i]) != PSCI_STATE_OFF)
120 return 0;
121 }
122
123 return 1;
124}
125
126/*******************************************************************************
Soby Mathewb48349e2015-06-29 16:30:12 +0100127 * Routine to return the maximum affinity level to traverse to after a cpu has
128 * been physically powered up. It is expected to be called immediately after
129 * reset from assembler code.
130 ******************************************************************************/
131int get_power_on_target_afflvl(void)
132{
133 int afflvl;
134
135#if DEBUG
136 unsigned int state;
137 aff_map_node_t *node;
138
139 /* Retrieve our node from the topology tree */
140 node = psci_get_aff_map_node(read_mpidr_el1() & MPIDR_AFFINITY_MASK,
141 MPIDR_AFFLVL0);
142 assert(node);
143
144 /*
145 * Sanity check the state of the cpu. It should be either suspend or "on
146 * pending"
147 */
148 state = psci_get_state(node);
149 assert(state == PSCI_STATE_SUSPEND || state == PSCI_STATE_ON_PENDING);
150#endif
151
152 /*
153 * Assume that this cpu was suspended and retrieve its target affinity
154 * level. If it is invalid then it could only have been turned off
155 * earlier. PLATFORM_MAX_AFFLVL will be the highest affinity level a
156 * cpu can be turned off to.
157 */
158 afflvl = psci_get_suspend_afflvl();
159 if (afflvl == PSCI_INVALID_DATA)
160 afflvl = PLATFORM_MAX_AFFLVL;
161 return afflvl;
162}
163
164/*******************************************************************************
165 * Simple routine to set the id of an affinity instance at a given level in the
166 * mpidr.
167 ******************************************************************************/
168unsigned long mpidr_set_aff_inst(unsigned long mpidr,
169 unsigned char aff_inst,
170 int aff_lvl)
171{
172 unsigned long aff_shift;
173
174 assert(aff_lvl <= MPIDR_AFFLVL3);
175
176 /*
177 * Decide the number of bits to shift by depending upon
178 * the affinity level
179 */
180 aff_shift = get_afflvl_shift(aff_lvl);
181
182 /* Clear the existing affinity instance & set the new one*/
183 mpidr &= ~(((unsigned long)MPIDR_AFFLVL_MASK) << aff_shift);
184 mpidr |= ((unsigned long)aff_inst) << aff_shift;
185
186 return mpidr;
187}
188
189/*******************************************************************************
190 * This function sanity checks a range of affinity levels.
191 ******************************************************************************/
192int psci_check_afflvl_range(int start_afflvl, int end_afflvl)
193{
194 /* Sanity check the parameters passed */
195 if (end_afflvl > PLATFORM_MAX_AFFLVL)
196 return PSCI_E_INVALID_PARAMS;
197
198 if (start_afflvl < MPIDR_AFFLVL0)
199 return PSCI_E_INVALID_PARAMS;
200
201 if (end_afflvl < start_afflvl)
202 return PSCI_E_INVALID_PARAMS;
203
204 return PSCI_E_SUCCESS;
205}
206
207/*******************************************************************************
208 * This function is passed an array of pointers to affinity level nodes in the
209 * topology tree for an mpidr and the state which each node should transition
210 * to. It updates the state of each node between the specified affinity levels.
211 ******************************************************************************/
212void psci_do_afflvl_state_mgmt(uint32_t start_afflvl,
213 uint32_t end_afflvl,
214 aff_map_node_t *mpidr_nodes[],
215 uint32_t state)
216{
217 uint32_t level;
218
219 for (level = start_afflvl; level <= end_afflvl; level++) {
220 if (mpidr_nodes[level] == NULL)
221 continue;
222 psci_set_state(mpidr_nodes[level], state);
223 }
224}
225
226/*******************************************************************************
227 * This function is passed an array of pointers to affinity level nodes in the
228 * topology tree for an mpidr. It picks up locks for each affinity level bottom
229 * up in the range specified.
230 ******************************************************************************/
231void psci_acquire_afflvl_locks(int start_afflvl,
232 int end_afflvl,
233 aff_map_node_t *mpidr_nodes[])
234{
235 int level;
236
237 for (level = start_afflvl; level <= end_afflvl; level++) {
238 if (mpidr_nodes[level] == NULL)
239 continue;
240
241 psci_lock_get(mpidr_nodes[level]);
242 }
243}
244
245/*******************************************************************************
246 * This function is passed an array of pointers to affinity level nodes in the
247 * topology tree for an mpidr. It releases the lock for each affinity level top
248 * down in the range specified.
249 ******************************************************************************/
250void psci_release_afflvl_locks(int start_afflvl,
251 int end_afflvl,
252 aff_map_node_t *mpidr_nodes[])
253{
254 int level;
255
256 for (level = end_afflvl; level >= start_afflvl; level--) {
257 if (mpidr_nodes[level] == NULL)
258 continue;
259
260 psci_lock_release(mpidr_nodes[level]);
261 }
262}
263
264/*******************************************************************************
265 * Simple routine to determine whether an affinity instance at a given level
266 * in an mpidr exists or not.
267 ******************************************************************************/
268int psci_validate_mpidr(unsigned long mpidr, int level)
269{
270 aff_map_node_t *node;
271
272 node = psci_get_aff_map_node(mpidr, level);
273 if (node && (node->state & PSCI_AFF_PRESENT))
274 return PSCI_E_SUCCESS;
275 else
276 return PSCI_E_INVALID_PARAMS;
277}
278
279/*******************************************************************************
280 * This function determines the full entrypoint information for the requested
281 * PSCI entrypoint on power on/resume and returns it.
282 ******************************************************************************/
283int psci_get_ns_ep_info(entry_point_info_t *ep,
284 uint64_t entrypoint, uint64_t context_id)
285{
286 uint32_t ep_attr, mode, sctlr, daif, ee;
287 uint32_t ns_scr_el3 = read_scr_el3();
288 uint32_t ns_sctlr_el1 = read_sctlr_el1();
289
290 sctlr = ns_scr_el3 & SCR_HCE_BIT ? read_sctlr_el2() : ns_sctlr_el1;
291 ee = 0;
292
293 ep_attr = NON_SECURE | EP_ST_DISABLE;
294 if (sctlr & SCTLR_EE_BIT) {
295 ep_attr |= EP_EE_BIG;
296 ee = 1;
297 }
298 SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr);
299
300 ep->pc = entrypoint;
301 memset(&ep->args, 0, sizeof(ep->args));
302 ep->args.arg0 = context_id;
303
304 /*
305 * Figure out whether the cpu enters the non-secure address space
306 * in aarch32 or aarch64
307 */
308 if (ns_scr_el3 & SCR_RW_BIT) {
309
310 /*
311 * Check whether a Thumb entry point has been provided for an
312 * aarch64 EL
313 */
314 if (entrypoint & 0x1)
315 return PSCI_E_INVALID_PARAMS;
316
317 mode = ns_scr_el3 & SCR_HCE_BIT ? MODE_EL2 : MODE_EL1;
318
319 ep->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
320 } else {
321
322 mode = ns_scr_el3 & SCR_HCE_BIT ? MODE32_hyp : MODE32_svc;
323
324 /*
325 * TODO: Choose async. exception bits if HYP mode is not
326 * implemented according to the values of SCR.{AW, FW} bits
327 */
328 daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT;
329
330 ep->spsr = SPSR_MODE32(mode, entrypoint & 0x1, ee, daif);
331 }
332
333 return PSCI_E_SUCCESS;
334}
335
336/*******************************************************************************
337 * This function takes a pointer to an affinity node in the topology tree and
338 * returns its state. State of a non-leaf node needs to be calculated.
339 ******************************************************************************/
340unsigned short psci_get_state(aff_map_node_t *node)
341{
342#if !USE_COHERENT_MEM
343 flush_dcache_range((uint64_t) node, sizeof(*node));
344#endif
345
346 assert(node->level >= MPIDR_AFFLVL0 && node->level <= MPIDR_MAX_AFFLVL);
347
348 /* A cpu node just contains the state which can be directly returned */
349 if (node->level == MPIDR_AFFLVL0)
350 return (node->state >> PSCI_STATE_SHIFT) & PSCI_STATE_MASK;
351
352 /*
353 * For an affinity level higher than a cpu, the state has to be
354 * calculated. It depends upon the value of the reference count
355 * which is managed by each node at the next lower affinity level
356 * e.g. for a cluster, each cpu increments/decrements the reference
357 * count. If the reference count is 0 then the affinity level is
358 * OFF else ON.
359 */
360 if (node->ref_count)
361 return PSCI_STATE_ON;
362 else
363 return PSCI_STATE_OFF;
364}
365
366/*******************************************************************************
367 * This function takes a pointer to an affinity node in the topology tree and
368 * a target state. State of a non-leaf node needs to be converted to a reference
369 * count. State of a leaf node can be set directly.
370 ******************************************************************************/
371void psci_set_state(aff_map_node_t *node, unsigned short state)
372{
373 assert(node->level >= MPIDR_AFFLVL0 && node->level <= MPIDR_MAX_AFFLVL);
374
375 /*
376 * For an affinity level higher than a cpu, the state is used
377 * to decide whether the reference count is incremented or
378 * decremented. Entry into the ON_PENDING state does not have
379 * effect.
380 */
381 if (node->level > MPIDR_AFFLVL0) {
382 switch (state) {
383 case PSCI_STATE_ON:
384 node->ref_count++;
385 break;
386 case PSCI_STATE_OFF:
387 case PSCI_STATE_SUSPEND:
388 node->ref_count--;
389 break;
390 case PSCI_STATE_ON_PENDING:
391 /*
392 * An affinity level higher than a cpu will not undergo
393 * a state change when it is about to be turned on
394 */
395 return;
396 default:
397 assert(0);
398 }
399 } else {
400 node->state &= ~(PSCI_STATE_MASK << PSCI_STATE_SHIFT);
401 node->state |= (state & PSCI_STATE_MASK) << PSCI_STATE_SHIFT;
402 }
403
404#if !USE_COHERENT_MEM
405 flush_dcache_range((uint64_t) node, sizeof(*node));
406#endif
407}
408
409/*******************************************************************************
410 * An affinity level could be on, on_pending, suspended or off. These are the
411 * logical states it can be in. Physically either it is off or on. When it is in
412 * the state on_pending then it is about to be turned on. It is not possible to
413 * tell whether that's actually happenned or not. So we err on the side of
414 * caution & treat the affinity level as being turned off.
415 ******************************************************************************/
416unsigned short psci_get_phys_state(aff_map_node_t *node)
417{
418 unsigned int state;
419
420 state = psci_get_state(node);
421 return get_phys_state(state);
422}
423
424/*******************************************************************************
Soby Mathewb48349e2015-06-29 16:30:12 +0100425 * Generic handler which is called when a cpu is physically powered on. It
Soby Mathew6590ce22015-06-30 11:00:24 +0100426 * traverses the node information and finds the highest affinity level powered
427 * off and performs generic, architectural, platform setup and state management
428 * to power on that affinity level and affinity levels below it.
429 * e.g. For a cpu that's been powered on, it will call the platform specific
430 * code to enable the gic cpu interface and for a cluster it will enable
431 * coherency at the interconnect level in addition to gic cpu interface.
Soby Mathewb48349e2015-06-29 16:30:12 +0100432 *
Soby Mathew6590ce22015-06-30 11:00:24 +0100433 * The state of all the relevant affinity levels is changed prior to calling
434 * the platform specific code.
Soby Mathewb48349e2015-06-29 16:30:12 +0100435 ******************************************************************************/
Soby Mathew6590ce22015-06-30 11:00:24 +0100436void psci_afflvl_power_on_finish(int end_afflvl,
437 afflvl_power_on_finisher_t pon_handler)
Soby Mathewb48349e2015-06-29 16:30:12 +0100438{
439 mpidr_aff_map_nodes_t mpidr_nodes;
440 int rc;
441 unsigned int max_phys_off_afflvl;
442
443
444 /*
445 * Collect the pointers to the nodes in the topology tree for
446 * each affinity instance in the mpidr. If this function does
447 * not return successfully then either the mpidr or the affinity
448 * levels are incorrect. Either case is an irrecoverable error.
449 */
450 rc = psci_get_aff_map_nodes(read_mpidr_el1() & MPIDR_AFFINITY_MASK,
Soby Mathew6590ce22015-06-30 11:00:24 +0100451 MPIDR_AFFLVL0,
Soby Mathewb48349e2015-06-29 16:30:12 +0100452 end_afflvl,
453 mpidr_nodes);
454 if (rc != PSCI_E_SUCCESS)
455 panic();
456
457 /*
458 * This function acquires the lock corresponding to each affinity
459 * level so that by the time all locks are taken, the system topology
460 * is snapshot and state management can be done safely.
461 */
Soby Mathew6590ce22015-06-30 11:00:24 +0100462 psci_acquire_afflvl_locks(MPIDR_AFFLVL0,
Soby Mathewb48349e2015-06-29 16:30:12 +0100463 end_afflvl,
464 mpidr_nodes);
465
Soby Mathew6590ce22015-06-30 11:00:24 +0100466 max_phys_off_afflvl = psci_find_max_phys_off_afflvl(MPIDR_AFFLVL0,
Soby Mathewb48349e2015-06-29 16:30:12 +0100467 end_afflvl,
468 mpidr_nodes);
469 assert(max_phys_off_afflvl != PSCI_INVALID_DATA);
470
Soby Mathewb48349e2015-06-29 16:30:12 +0100471 /* Perform generic, architecture and platform specific handling */
Soby Mathew6590ce22015-06-30 11:00:24 +0100472 pon_handler(mpidr_nodes, max_phys_off_afflvl);
Soby Mathewb48349e2015-06-29 16:30:12 +0100473
474 /*
475 * This function updates the state of each affinity instance
476 * corresponding to the mpidr in the range of affinity levels
477 * specified.
478 */
Soby Mathew6590ce22015-06-30 11:00:24 +0100479 psci_do_afflvl_state_mgmt(MPIDR_AFFLVL0,
Soby Mathewb48349e2015-06-29 16:30:12 +0100480 end_afflvl,
481 mpidr_nodes,
482 PSCI_STATE_ON);
483
484 /*
Soby Mathewb48349e2015-06-29 16:30:12 +0100485 * This loop releases the lock corresponding to each affinity level
486 * in the reverse order to which they were acquired.
487 */
Soby Mathew6590ce22015-06-30 11:00:24 +0100488 psci_release_afflvl_locks(MPIDR_AFFLVL0,
Soby Mathewb48349e2015-06-29 16:30:12 +0100489 end_afflvl,
490 mpidr_nodes);
491}
492
493/*******************************************************************************
494 * This function initializes the set of hooks that PSCI invokes as part of power
495 * management operation. The power management hooks are expected to be provided
496 * by the SPD, after it finishes all its initialization
497 ******************************************************************************/
498void psci_register_spd_pm_hook(const spd_pm_ops_t *pm)
499{
500 assert(pm);
501 psci_spd_pm = pm;
502
503 if (pm->svc_migrate)
504 psci_caps |= define_psci_cap(PSCI_MIG_AARCH64);
505
506 if (pm->svc_migrate_info)
507 psci_caps |= define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64)
508 | define_psci_cap(PSCI_MIG_INFO_TYPE);
509}
510
511/*******************************************************************************
512 * This function invokes the migrate info hook in the spd_pm_ops. It performs
513 * the necessary return value validation. If the Secure Payload is UP and
514 * migrate capable, it returns the mpidr of the CPU on which the Secure payload
515 * is resident through the mpidr parameter. Else the value of the parameter on
516 * return is undefined.
517 ******************************************************************************/
518int psci_spd_migrate_info(uint64_t *mpidr)
519{
520 int rc;
521
522 if (!psci_spd_pm || !psci_spd_pm->svc_migrate_info)
523 return PSCI_E_NOT_SUPPORTED;
524
525 rc = psci_spd_pm->svc_migrate_info(mpidr);
526
527 assert(rc == PSCI_TOS_UP_MIG_CAP || rc == PSCI_TOS_NOT_UP_MIG_CAP \
528 || rc == PSCI_TOS_NOT_PRESENT_MP || rc == PSCI_E_NOT_SUPPORTED);
529
530 return rc;
531}
532
533
534/*******************************************************************************
535 * This function prints the state of all affinity instances present in the
536 * system
537 ******************************************************************************/
538void psci_print_affinity_map(void)
539{
540#if LOG_LEVEL >= LOG_LEVEL_INFO
541 aff_map_node_t *node;
542 unsigned int idx;
543 /* This array maps to the PSCI_STATE_X definitions in psci.h */
544 static const char *psci_state_str[] = {
545 "ON",
546 "OFF",
547 "ON_PENDING",
548 "SUSPEND"
549 };
550
551 INFO("PSCI Affinity Map:\n");
552 for (idx = 0; idx < PSCI_NUM_AFFS ; idx++) {
553 node = &psci_aff_map[idx];
554 if (!(node->state & PSCI_AFF_PRESENT)) {
555 continue;
556 }
557 INFO(" AffInst: Level %u, MPID 0x%lx, State %s\n",
558 node->level, node->mpidr,
559 psci_state_str[psci_get_state(node)]);
560 }
561#endif
562}