blob: 7ab607dbac16ee1454e19a3d2c7f0e8be857cbca [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
Dan Handley2bd4ef22014-04-09 13:14:54 +010031#include <arch.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010032#include <arch_helpers.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010033#include <assert.h>
34#include <bl_common.h>
35#include <context.h>
Jeenu Viswambharancaa84932014-02-06 10:36:15 +000036#include <context_mgmt.h>
Dan Handley714a0d22014-04-09 13:13:04 +010037#include <debug.h>
Dan Handleyed6ff952014-05-14 17:44:19 +010038#include <platform.h>
Andrew Thoelke4e126072014-06-04 21:10:52 +010039#include <string.h>
Dan Handley714a0d22014-04-09 13:13:04 +010040#include "psci_private.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010041
Achin Gupta607084e2014-02-09 18:24:19 +000042/*
Jeenu Viswambharan7f366602014-02-20 17:11:00 +000043 * SPD power management operations, expected to be supplied by the registered
44 * SPD on successful SP initialization
Achin Gupta607084e2014-02-09 18:24:19 +000045 */
Dan Handleye2712bc2014-04-10 15:37:22 +010046const spd_pm_ops_t *psci_spd_pm;
Achin Gupta607084e2014-02-09 18:24:19 +000047
Achin Gupta4f6ad662013-10-25 09:08:21 +010048/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +010049 * 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 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +010053aff_map_node_t psci_aff_map[PSCI_NUM_AFFS]
Soby Mathew2ae20432015-01-08 18:02:44 +000054#if USE_COHERENT_MEM
55__attribute__ ((section("tzfw_coherent_mem")))
56#endif
57;
Achin Gupta4f6ad662013-10-25 09:08:21 +010058
59/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +010060 * Pointer to functions exported by the platform to complete power mgmt. ops
61 ******************************************************************************/
Dan Handleya4cb68e2014-04-23 13:47:06 +010062const plat_pm_ops_t *psci_plat_pm_ops;
Achin Gupta4f6ad662013-10-25 09:08:21 +010063
64/*******************************************************************************
Soby Mathew2b7de2b2015-02-12 14:45:02 +000065 * 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/*******************************************************************************
Achin Guptaf6b9e992014-07-31 11:19:11 +010072 * 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,
Achin Gupta56bcdc22014-07-28 00:15:23 +010078 aff_map_node_t *mpidr_nodes[])
Achin Guptaf6b9e992014-07-31 11:19:11 +010079{
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 saves the highest affinity level which is in OFF state. The
96 * affinity instance with which the level is associated is determined by the
97 * caller.
98 ******************************************************************************/
99void psci_set_max_phys_off_afflvl(uint32_t afflvl)
100{
101 set_cpu_data(psci_svc_cpu_data.max_phys_off_afflvl, afflvl);
102
103 /*
104 * Ensure that the saved value is flushed to main memory and any
105 * speculatively pre-fetched stale copies are invalidated from the
106 * caches of other cpus in the same coherency domain. This ensures that
107 * the value can be safely read irrespective of the state of the data
108 * cache.
109 */
110 flush_cpu_data(psci_svc_cpu_data.max_phys_off_afflvl);
111}
112
113/*******************************************************************************
114 * This function reads the saved highest affinity level which is in OFF
115 * state. The affinity instance with which the level is associated is determined
116 * by the caller.
117 ******************************************************************************/
118uint32_t psci_get_max_phys_off_afflvl(void)
119{
120 /*
121 * Ensure that the last update of this value in this cpu's cache is
122 * flushed to main memory and any speculatively pre-fetched stale copies
123 * are invalidated from the caches of other cpus in the same coherency
124 * domain. This ensures that the value is always read from the main
125 * memory when it was written before the data cache was enabled.
126 */
127 flush_cpu_data(psci_svc_cpu_data.max_phys_off_afflvl);
128 return get_cpu_data(psci_svc_cpu_data.max_phys_off_afflvl);
129}
130
131/*******************************************************************************
Achin Guptaa45e3972013-12-05 15:10:48 +0000132 * Routine to return the maximum affinity level to traverse to after a cpu has
133 * been physically powered up. It is expected to be called immediately after
Achin Guptaf3ccbab2014-07-25 14:52:47 +0100134 * reset from assembler code.
Achin Guptaa45e3972013-12-05 15:10:48 +0000135 ******************************************************************************/
Achin Guptaf3ccbab2014-07-25 14:52:47 +0100136int get_power_on_target_afflvl()
Achin Guptaa45e3972013-12-05 15:10:48 +0000137{
Vikram Kanigirif100f412014-04-01 19:26:26 +0100138 int afflvl;
Achin Guptaa45e3972013-12-05 15:10:48 +0000139
Achin Guptaf3ccbab2014-07-25 14:52:47 +0100140#if DEBUG
141 unsigned int state;
142 aff_map_node_t *node;
143
Achin Guptaa45e3972013-12-05 15:10:48 +0000144 /* Retrieve our node from the topology tree */
Achin Guptaf3ccbab2014-07-25 14:52:47 +0100145 node = psci_get_aff_map_node(read_mpidr_el1() & MPIDR_AFFINITY_MASK,
146 MPIDR_AFFLVL0);
Achin Guptaa45e3972013-12-05 15:10:48 +0000147 assert(node);
148
149 /*
Achin Guptaf3ccbab2014-07-25 14:52:47 +0100150 * Sanity check the state of the cpu. It should be either suspend or "on
151 * pending"
Achin Guptaa45e3972013-12-05 15:10:48 +0000152 */
Achin Gupta75f73672013-12-05 16:33:10 +0000153 state = psci_get_state(node);
Achin Guptaf3ccbab2014-07-25 14:52:47 +0100154 assert(state == PSCI_STATE_SUSPEND || state == PSCI_STATE_ON_PENDING);
155#endif
Achin Guptaa45e3972013-12-05 15:10:48 +0000156
Achin Guptaf3ccbab2014-07-25 14:52:47 +0100157 /*
158 * Assume that this cpu was suspended and retrieve its target affinity
159 * level. If it is invalid then it could only have been turned off
Soby Mathew2b7de2b2015-02-12 14:45:02 +0000160 * earlier. PLATFORM_MAX_AFFLVL will be the highest affinity level a
Achin Guptaf3ccbab2014-07-25 14:52:47 +0100161 * cpu can be turned off to.
162 */
163 afflvl = psci_get_suspend_afflvl();
164 if (afflvl == PSCI_INVALID_DATA)
Soby Mathew2b7de2b2015-02-12 14:45:02 +0000165 afflvl = PLATFORM_MAX_AFFLVL;
Achin Guptaf3ccbab2014-07-25 14:52:47 +0100166 return afflvl;
Achin Guptaa45e3972013-12-05 15:10:48 +0000167}
168
169/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +0100170 * Simple routine to set the id of an affinity instance at a given level in the
171 * mpidr.
172 ******************************************************************************/
173unsigned long mpidr_set_aff_inst(unsigned long mpidr,
174 unsigned char aff_inst,
175 int aff_lvl)
176{
177 unsigned long aff_shift;
178
179 assert(aff_lvl <= MPIDR_AFFLVL3);
180
181 /*
182 * Decide the number of bits to shift by depending upon
183 * the affinity level
184 */
185 aff_shift = get_afflvl_shift(aff_lvl);
186
187 /* Clear the existing affinity instance & set the new one*/
188 mpidr &= ~(MPIDR_AFFLVL_MASK << aff_shift);
189 mpidr |= aff_inst << aff_shift;
190
191 return mpidr;
192}
193
194/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000195 * This function sanity checks a range of affinity levels.
196 ******************************************************************************/
197int psci_check_afflvl_range(int start_afflvl, int end_afflvl)
198{
199 /* Sanity check the parameters passed */
Soby Mathew2b7de2b2015-02-12 14:45:02 +0000200 if (end_afflvl > PLATFORM_MAX_AFFLVL)
Achin Gupta0959db52013-12-02 17:33:04 +0000201 return PSCI_E_INVALID_PARAMS;
202
203 if (start_afflvl < MPIDR_AFFLVL0)
204 return PSCI_E_INVALID_PARAMS;
205
206 if (end_afflvl < start_afflvl)
207 return PSCI_E_INVALID_PARAMS;
208
209 return PSCI_E_SUCCESS;
210}
211
212/*******************************************************************************
213 * This function is passed an array of pointers to affinity level nodes in the
Achin Guptacab78e42014-07-28 00:09:01 +0100214 * topology tree for an mpidr and the state which each node should transition
215 * to. It updates the state of each node between the specified affinity levels.
216 ******************************************************************************/
217void psci_do_afflvl_state_mgmt(uint32_t start_afflvl,
218 uint32_t end_afflvl,
Achin Gupta56bcdc22014-07-28 00:15:23 +0100219 aff_map_node_t *mpidr_nodes[],
Achin Guptacab78e42014-07-28 00:09:01 +0100220 uint32_t state)
221{
222 uint32_t level;
223
224 for (level = start_afflvl; level <= end_afflvl; level++) {
225 if (mpidr_nodes[level] == NULL)
226 continue;
227 psci_set_state(mpidr_nodes[level], state);
228 }
229}
230
231/*******************************************************************************
232 * This function is passed an array of pointers to affinity level nodes in the
Achin Gupta0959db52013-12-02 17:33:04 +0000233 * topology tree for an mpidr. It picks up locks for each affinity level bottom
234 * up in the range specified.
235 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100236void psci_acquire_afflvl_locks(int start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000237 int end_afflvl,
Achin Gupta56bcdc22014-07-28 00:15:23 +0100238 aff_map_node_t *mpidr_nodes[])
Achin Gupta0959db52013-12-02 17:33:04 +0000239{
240 int level;
241
242 for (level = start_afflvl; level <= end_afflvl; level++) {
243 if (mpidr_nodes[level] == NULL)
244 continue;
Soby Mathew523d6332015-01-08 18:02:19 +0000245
246 psci_lock_get(mpidr_nodes[level]);
Achin Gupta0959db52013-12-02 17:33:04 +0000247 }
248}
249
250/*******************************************************************************
251 * This function is passed an array of pointers to affinity level nodes in the
252 * topology tree for an mpidr. It releases the lock for each affinity level top
253 * down in the range specified.
254 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100255void psci_release_afflvl_locks(int start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000256 int end_afflvl,
Achin Gupta56bcdc22014-07-28 00:15:23 +0100257 aff_map_node_t *mpidr_nodes[])
Achin Gupta0959db52013-12-02 17:33:04 +0000258{
259 int level;
260
261 for (level = end_afflvl; level >= start_afflvl; level--) {
262 if (mpidr_nodes[level] == NULL)
263 continue;
Soby Mathew523d6332015-01-08 18:02:19 +0000264
265 psci_lock_release(mpidr_nodes[level]);
Achin Gupta0959db52013-12-02 17:33:04 +0000266 }
267}
268
269/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +0100270 * Simple routine to determine whether an affinity instance at a given level
271 * in an mpidr exists or not.
272 ******************************************************************************/
273int psci_validate_mpidr(unsigned long mpidr, int level)
274{
Dan Handleye2712bc2014-04-10 15:37:22 +0100275 aff_map_node_t *node;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100276
277 node = psci_get_aff_map_node(mpidr, level);
278 if (node && (node->state & PSCI_AFF_PRESENT))
279 return PSCI_E_SUCCESS;
280 else
281 return PSCI_E_INVALID_PARAMS;
282}
283
284/*******************************************************************************
Andrew Thoelke4e126072014-06-04 21:10:52 +0100285 * This function determines the full entrypoint information for the requested
Soby Mathew8595b872015-01-06 15:36:38 +0000286 * PSCI entrypoint on power on/resume and returns it.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100287 ******************************************************************************/
Soby Mathew8595b872015-01-06 15:36:38 +0000288int psci_get_ns_ep_info(entry_point_info_t *ep,
289 uint64_t entrypoint, uint64_t context_id)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100290{
Andrew Thoelke4e126072014-06-04 21:10:52 +0100291 uint32_t ep_attr, mode, sctlr, daif, ee;
Soby Mathew8595b872015-01-06 15:36:38 +0000292 uint32_t ns_scr_el3 = read_scr_el3();
293 uint32_t ns_sctlr_el1 = read_sctlr_el1();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100294
Andrew Thoelke4e126072014-06-04 21:10:52 +0100295 sctlr = ns_scr_el3 & SCR_HCE_BIT ? read_sctlr_el2() : ns_sctlr_el1;
296 ee = 0;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100297
Andrew Thoelke4e126072014-06-04 21:10:52 +0100298 ep_attr = NON_SECURE | EP_ST_DISABLE;
299 if (sctlr & SCTLR_EE_BIT) {
300 ep_attr |= EP_EE_BIG;
301 ee = 1;
302 }
Soby Mathew8595b872015-01-06 15:36:38 +0000303 SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100304
Soby Mathew8595b872015-01-06 15:36:38 +0000305 ep->pc = entrypoint;
306 memset(&ep->args, 0, sizeof(ep->args));
307 ep->args.arg0 = context_id;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100308
309 /*
310 * Figure out whether the cpu enters the non-secure address space
311 * in aarch32 or aarch64
312 */
Andrew Thoelke4e126072014-06-04 21:10:52 +0100313 if (ns_scr_el3 & SCR_RW_BIT) {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100314
315 /*
316 * Check whether a Thumb entry point has been provided for an
317 * aarch64 EL
318 */
319 if (entrypoint & 0x1)
320 return PSCI_E_INVALID_PARAMS;
321
Andrew Thoelke4e126072014-06-04 21:10:52 +0100322 mode = ns_scr_el3 & SCR_HCE_BIT ? MODE_EL2 : MODE_EL1;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100323
Soby Mathew8595b872015-01-06 15:36:38 +0000324 ep->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100325 } else {
326
Andrew Thoelke4e126072014-06-04 21:10:52 +0100327 mode = ns_scr_el3 & SCR_HCE_BIT ? MODE32_hyp : MODE32_svc;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100328
329 /*
330 * TODO: Choose async. exception bits if HYP mode is not
331 * implemented according to the values of SCR.{AW, FW} bits
332 */
Vikram Kanigiri9851e422014-05-13 14:42:08 +0100333 daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT;
334
Soby Mathew8595b872015-01-06 15:36:38 +0000335 ep->spsr = SPSR_MODE32(mode, entrypoint & 0x1, ee, daif);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100336 }
337
Andrew Thoelke4e126072014-06-04 21:10:52 +0100338 return PSCI_E_SUCCESS;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100339}
340
341/*******************************************************************************
Achin Gupta75f73672013-12-05 16:33:10 +0000342 * This function takes a pointer to an affinity node in the topology tree and
343 * returns its state. State of a non-leaf node needs to be calculated.
344 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +0100345unsigned short psci_get_state(aff_map_node_t *node)
Achin Gupta75f73672013-12-05 16:33:10 +0000346{
Soby Mathew2ae20432015-01-08 18:02:44 +0000347#if !USE_COHERENT_MEM
348 flush_dcache_range((uint64_t) node, sizeof(*node));
349#endif
350
Achin Gupta75f73672013-12-05 16:33:10 +0000351 assert(node->level >= MPIDR_AFFLVL0 && node->level <= MPIDR_MAX_AFFLVL);
352
353 /* A cpu node just contains the state which can be directly returned */
354 if (node->level == MPIDR_AFFLVL0)
355 return (node->state >> PSCI_STATE_SHIFT) & PSCI_STATE_MASK;
356
357 /*
358 * For an affinity level higher than a cpu, the state has to be
359 * calculated. It depends upon the value of the reference count
360 * which is managed by each node at the next lower affinity level
361 * e.g. for a cluster, each cpu increments/decrements the reference
362 * count. If the reference count is 0 then the affinity level is
363 * OFF else ON.
364 */
365 if (node->ref_count)
366 return PSCI_STATE_ON;
367 else
368 return PSCI_STATE_OFF;
369}
370
371/*******************************************************************************
372 * This function takes a pointer to an affinity node in the topology tree and
373 * a target state. State of a non-leaf node needs to be converted to a reference
374 * count. State of a leaf node can be set directly.
375 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +0100376void psci_set_state(aff_map_node_t *node, unsigned short state)
Achin Gupta75f73672013-12-05 16:33:10 +0000377{
378 assert(node->level >= MPIDR_AFFLVL0 && node->level <= MPIDR_MAX_AFFLVL);
379
380 /*
381 * For an affinity level higher than a cpu, the state is used
382 * to decide whether the reference count is incremented or
383 * decremented. Entry into the ON_PENDING state does not have
384 * effect.
385 */
386 if (node->level > MPIDR_AFFLVL0) {
387 switch (state) {
388 case PSCI_STATE_ON:
389 node->ref_count++;
390 break;
391 case PSCI_STATE_OFF:
392 case PSCI_STATE_SUSPEND:
393 node->ref_count--;
394 break;
395 case PSCI_STATE_ON_PENDING:
396 /*
397 * An affinity level higher than a cpu will not undergo
398 * a state change when it is about to be turned on
399 */
400 return;
401 default:
402 assert(0);
403 }
404 } else {
405 node->state &= ~(PSCI_STATE_MASK << PSCI_STATE_SHIFT);
406 node->state |= (state & PSCI_STATE_MASK) << PSCI_STATE_SHIFT;
407 }
Soby Mathew2ae20432015-01-08 18:02:44 +0000408
409#if !USE_COHERENT_MEM
410 flush_dcache_range((uint64_t) node, sizeof(*node));
411#endif
Achin Gupta75f73672013-12-05 16:33:10 +0000412}
413
414/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +0100415 * An affinity level could be on, on_pending, suspended or off. These are the
Achin Gupta3140a9e2013-12-02 16:23:12 +0000416 * logical states it can be in. Physically either it is off or on. When it is in
417 * the state on_pending then it is about to be turned on. It is not possible to
Achin Gupta4f6ad662013-10-25 09:08:21 +0100418 * tell whether that's actually happenned or not. So we err on the side of
419 * caution & treat the affinity level as being turned off.
420 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +0100421unsigned short psci_get_phys_state(aff_map_node_t *node)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100422{
Achin Gupta75f73672013-12-05 16:33:10 +0000423 unsigned int state;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100424
Achin Gupta75f73672013-12-05 16:33:10 +0000425 state = psci_get_state(node);
426 return get_phys_state(state);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100427}
428
429/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000430 * This function takes an array of pointers to affinity instance nodes in the
431 * topology tree and calls the physical power on handler for the corresponding
432 * affinity levels
433 ******************************************************************************/
Soby Mathew74e52a72014-10-02 16:56:51 +0100434static void psci_call_power_on_handlers(aff_map_node_t *mpidr_nodes[],
Achin Gupta0959db52013-12-02 17:33:04 +0000435 int start_afflvl,
436 int end_afflvl,
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100437 afflvl_power_on_finisher_t *pon_handlers)
Achin Gupta0959db52013-12-02 17:33:04 +0000438{
Soby Mathew74e52a72014-10-02 16:56:51 +0100439 int level;
Dan Handleye2712bc2014-04-10 15:37:22 +0100440 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000441
442 for (level = end_afflvl; level >= start_afflvl; level--) {
443 node = mpidr_nodes[level];
444 if (node == NULL)
445 continue;
446
447 /*
448 * If we run into any trouble while powering up an
449 * affinity instance, then there is no recovery path
450 * so simply return an error and let the caller take
451 * care of the situation.
452 */
Soby Mathew74e52a72014-10-02 16:56:51 +0100453 pon_handlers[level](node);
Achin Gupta0959db52013-12-02 17:33:04 +0000454 }
Achin Gupta0959db52013-12-02 17:33:04 +0000455}
456
457/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +0100458 * Generic handler which is called when a cpu is physically powered on. It
Achin Gupta0959db52013-12-02 17:33:04 +0000459 * traverses through all the affinity levels performing generic, architectural,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100460 * platform setup and state management e.g. for a cluster that's been powered
461 * on, it will call the platform specific code which will enable coherency at
462 * the interconnect level. For a cpu it could mean turning on the MMU etc.
463 *
Achin Gupta0959db52013-12-02 17:33:04 +0000464 * The state of all the relevant affinity levels is changed after calling the
465 * affinity level specific handlers as their actions would depend upon the state
466 * the affinity level is exiting from.
467 *
468 * The affinity level specific handlers are called in descending order i.e. from
469 * the highest to the lowest affinity level implemented by the platform because
470 * to turn on affinity level X it is neccesary to turn on affinity level X + 1
471 * first.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100472 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100473void psci_afflvl_power_on_finish(int start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000474 int end_afflvl,
Dan Handleye2712bc2014-04-10 15:37:22 +0100475 afflvl_power_on_finisher_t *pon_handlers)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100476{
Dan Handleye2712bc2014-04-10 15:37:22 +0100477 mpidr_aff_map_nodes_t mpidr_nodes;
Achin Gupta0959db52013-12-02 17:33:04 +0000478 int rc;
Achin Guptaf6b9e992014-07-31 11:19:11 +0100479 unsigned int max_phys_off_afflvl;
480
Achin Gupta4f6ad662013-10-25 09:08:21 +0100481
Achin Gupta4f6ad662013-10-25 09:08:21 +0100482 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000483 * Collect the pointers to the nodes in the topology tree for
484 * each affinity instance in the mpidr. If this function does
485 * not return successfully then either the mpidr or the affinity
486 * levels are incorrect. Either case is an irrecoverable error.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100487 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100488 rc = psci_get_aff_map_nodes(read_mpidr_el1() & MPIDR_AFFINITY_MASK,
Achin Gupta0959db52013-12-02 17:33:04 +0000489 start_afflvl,
490 end_afflvl,
491 mpidr_nodes);
James Morrissey40a6f642014-02-10 14:24:36 +0000492 if (rc != PSCI_E_SUCCESS)
493 panic();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100494
495 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000496 * This function acquires the lock corresponding to each affinity
497 * level so that by the time all locks are taken, the system topology
498 * is snapshot and state management can be done safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100499 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100500 psci_acquire_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000501 end_afflvl,
502 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100503
Achin Guptaf6b9e992014-07-31 11:19:11 +0100504 max_phys_off_afflvl = psci_find_max_phys_off_afflvl(start_afflvl,
505 end_afflvl,
506 mpidr_nodes);
507 assert(max_phys_off_afflvl != PSCI_INVALID_DATA);
508
509 /*
510 * Stash the highest affinity level that will come out of the OFF or
511 * SUSPEND states.
512 */
513 psci_set_max_phys_off_afflvl(max_phys_off_afflvl);
514
Achin Gupta4f6ad662013-10-25 09:08:21 +0100515 /* Perform generic, architecture and platform specific handling */
Soby Mathew74e52a72014-10-02 16:56:51 +0100516 psci_call_power_on_handlers(mpidr_nodes,
Achin Gupta0959db52013-12-02 17:33:04 +0000517 start_afflvl,
518 end_afflvl,
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100519 pon_handlers);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100520
521 /*
Achin Guptacab78e42014-07-28 00:09:01 +0100522 * This function updates the state of each affinity instance
523 * corresponding to the mpidr in the range of affinity levels
524 * specified.
525 */
526 psci_do_afflvl_state_mgmt(start_afflvl,
527 end_afflvl,
528 mpidr_nodes,
529 PSCI_STATE_ON);
530
531 /*
Achin Guptaf6b9e992014-07-31 11:19:11 +0100532 * Invalidate the entry for the highest affinity level stashed earlier.
533 * This ensures that any reads of this variable outside the power
534 * up/down sequences return PSCI_INVALID_DATA
535 */
536 psci_set_max_phys_off_afflvl(PSCI_INVALID_DATA);
537
538 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000539 * This loop releases the lock corresponding to each affinity level
540 * in the reverse order to which they were acquired.
541 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100542 psci_release_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000543 end_afflvl,
544 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100545}
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000546
547/*******************************************************************************
548 * This function initializes the set of hooks that PSCI invokes as part of power
549 * management operation. The power management hooks are expected to be provided
550 * by the SPD, after it finishes all its initialization
551 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +0100552void psci_register_spd_pm_hook(const spd_pm_ops_t *pm)
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000553{
Soby Mathew6cdddaf2015-01-07 11:10:22 +0000554 assert(pm);
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000555 psci_spd_pm = pm;
Soby Mathew6cdddaf2015-01-07 11:10:22 +0000556
557 if (pm->svc_migrate)
558 psci_caps |= define_psci_cap(PSCI_MIG_AARCH64);
559
560 if (pm->svc_migrate_info)
561 psci_caps |= define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64)
562 | define_psci_cap(PSCI_MIG_INFO_TYPE);
Jeenu Viswambharan7f366602014-02-20 17:11:00 +0000563}
Juan Castillo4dc4a472014-08-12 11:17:06 +0100564
565/*******************************************************************************
Soby Mathew110fe362014-10-23 10:35:34 +0100566 * This function invokes the migrate info hook in the spd_pm_ops. It performs
567 * the necessary return value validation. If the Secure Payload is UP and
568 * migrate capable, it returns the mpidr of the CPU on which the Secure payload
569 * is resident through the mpidr parameter. Else the value of the parameter on
570 * return is undefined.
571 ******************************************************************************/
572int psci_spd_migrate_info(uint64_t *mpidr)
573{
574 int rc;
575
576 if (!psci_spd_pm || !psci_spd_pm->svc_migrate_info)
577 return PSCI_E_NOT_SUPPORTED;
578
579 rc = psci_spd_pm->svc_migrate_info(mpidr);
580
581 assert(rc == PSCI_TOS_UP_MIG_CAP || rc == PSCI_TOS_NOT_UP_MIG_CAP \
582 || rc == PSCI_TOS_NOT_PRESENT_MP || rc == PSCI_E_NOT_SUPPORTED);
583
584 return rc;
585}
586
587
588/*******************************************************************************
Juan Castillo4dc4a472014-08-12 11:17:06 +0100589 * This function prints the state of all affinity instances present in the
590 * system
591 ******************************************************************************/
592void psci_print_affinity_map(void)
593{
594#if LOG_LEVEL >= LOG_LEVEL_INFO
595 aff_map_node_t *node;
596 unsigned int idx;
597 /* This array maps to the PSCI_STATE_X definitions in psci.h */
598 static const char *psci_state_str[] = {
599 "ON",
600 "OFF",
601 "ON_PENDING",
602 "SUSPEND"
603 };
604
605 INFO("PSCI Affinity Map:\n");
606 for (idx = 0; idx < PSCI_NUM_AFFS ; idx++) {
607 node = &psci_aff_map[idx];
608 if (!(node->state & PSCI_AFF_PRESENT)) {
609 continue;
610 }
611 INFO(" AffInst: Level %u, MPID 0x%lx, State %s\n",
612 node->level, node->mpidr,
613 psci_state_str[psci_get_state(node)]);
614 }
615#endif
616}