blob: f87fd52e7ca1c14201c71011987b6eaf0448ae02 [file] [log] [blame]
Soby Mathewb48349e2015-06-29 16:30:12 +01001/*
Soby Mathew4067dc32015-05-05 16:33:16 +01002 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
Soby Mathewb48349e2015-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 <debug.h>
35#include <platform.h>
36#include <runtime_svc.h>
37#include <std_svc.h>
38#include "psci_private.h"
39
40/*******************************************************************************
41 * PSCI frontend api for servicing SMCs. Described in the PSCI spec.
42 ******************************************************************************/
43int psci_cpu_on(unsigned long target_cpu,
44 unsigned long entrypoint,
45 unsigned long context_id)
46
47{
48 int rc;
Soby Mathew4067dc32015-05-05 16:33:16 +010049 unsigned int end_pwrlvl;
Soby Mathewb48349e2015-06-29 16:30:12 +010050 entry_point_info_t ep;
51
52 /* Determine if the cpu exists of not */
Soby Mathew12d0d002015-04-09 13:40:55 +010053 rc = psci_validate_mpidr(target_cpu);
54 if (rc != PSCI_E_SUCCESS)
Soby Mathewb48349e2015-06-29 16:30:12 +010055 return PSCI_E_INVALID_PARAMS;
Soby Mathewb48349e2015-06-29 16:30:12 +010056
57 /* Validate the entrypoint using platform pm_ops */
58 if (psci_plat_pm_ops->validate_ns_entrypoint) {
59 rc = psci_plat_pm_ops->validate_ns_entrypoint(entrypoint);
60 if (rc != PSCI_E_SUCCESS) {
61 assert(rc == PSCI_E_INVALID_PARAMS);
62 return PSCI_E_INVALID_PARAMS;
63 }
64 }
65
66 /*
67 * Verify and derive the re-entry information for
68 * the non-secure world from the non-secure state from
69 * where this call originated.
70 */
71 rc = psci_get_ns_ep_info(&ep, entrypoint, context_id);
72 if (rc != PSCI_E_SUCCESS)
73 return rc;
74
Soby Mathewb48349e2015-06-29 16:30:12 +010075 /*
Soby Mathew4067dc32015-05-05 16:33:16 +010076 * To turn this cpu on, specify which power
Soby Mathewb48349e2015-06-29 16:30:12 +010077 * levels need to be turned on
78 */
Soby Mathew4067dc32015-05-05 16:33:16 +010079 end_pwrlvl = PLAT_MAX_PWR_LVL;
80 rc = psci_cpu_on_start(target_cpu,
Soby Mathewb48349e2015-06-29 16:30:12 +010081 &ep,
Soby Mathew4067dc32015-05-05 16:33:16 +010082 end_pwrlvl);
Soby Mathewb48349e2015-06-29 16:30:12 +010083 return rc;
84}
85
86unsigned int psci_version(void)
87{
88 return PSCI_MAJOR_VER | PSCI_MINOR_VER;
89}
90
91int psci_cpu_suspend(unsigned int power_state,
92 unsigned long entrypoint,
93 unsigned long context_id)
94{
95 int rc;
Soby Mathew4067dc32015-05-05 16:33:16 +010096 unsigned int target_pwrlvl, pstate_type;
Soby Mathewb48349e2015-06-29 16:30:12 +010097 entry_point_info_t ep;
98
99 /* Check SBZ bits in power state are zero */
100 if (psci_validate_power_state(power_state))
101 return PSCI_E_INVALID_PARAMS;
102
103 /* Sanity check the requested state */
Soby Mathew4067dc32015-05-05 16:33:16 +0100104 target_pwrlvl = psci_get_pstate_pwrlvl(power_state);
105 if (target_pwrlvl > PLAT_MAX_PWR_LVL)
Soby Mathewb48349e2015-06-29 16:30:12 +0100106 return PSCI_E_INVALID_PARAMS;
107
108 /* Validate the power_state using platform pm_ops */
109 if (psci_plat_pm_ops->validate_power_state) {
110 rc = psci_plat_pm_ops->validate_power_state(power_state);
111 if (rc != PSCI_E_SUCCESS) {
112 assert(rc == PSCI_E_INVALID_PARAMS);
113 return PSCI_E_INVALID_PARAMS;
114 }
115 }
116
117 /* Validate the entrypoint using platform pm_ops */
118 if (psci_plat_pm_ops->validate_ns_entrypoint) {
119 rc = psci_plat_pm_ops->validate_ns_entrypoint(entrypoint);
120 if (rc != PSCI_E_SUCCESS) {
121 assert(rc == PSCI_E_INVALID_PARAMS);
122 return PSCI_E_INVALID_PARAMS;
123 }
124 }
125
126 /* Determine the 'state type' in the 'power_state' parameter */
127 pstate_type = psci_get_pstate_type(power_state);
128
129 /*
130 * Ensure that we have a platform specific handler for entering
131 * a standby state.
132 */
133 if (pstate_type == PSTATE_TYPE_STANDBY) {
Soby Mathew4067dc32015-05-05 16:33:16 +0100134 if (!psci_plat_pm_ops->pwr_domain_standby)
Soby Mathewb48349e2015-06-29 16:30:12 +0100135 return PSCI_E_INVALID_PARAMS;
136
Soby Mathew4067dc32015-05-05 16:33:16 +0100137 psci_plat_pm_ops->pwr_domain_standby(power_state);
Soby Mathewb48349e2015-06-29 16:30:12 +0100138 return PSCI_E_SUCCESS;
139 }
140
141 /*
142 * Verify and derive the re-entry information for
143 * the non-secure world from the non-secure state from
144 * where this call originated.
145 */
146 rc = psci_get_ns_ep_info(&ep, entrypoint, context_id);
147 if (rc != PSCI_E_SUCCESS)
148 return rc;
149
150 /* Save PSCI power state parameter for the core in suspend context */
151 psci_set_suspend_power_state(power_state);
152
153 /*
154 * Do what is needed to enter the power down state. Upon success,
155 * enter the final wfi which will power down this CPU.
156 */
Soby Mathew4067dc32015-05-05 16:33:16 +0100157 psci_cpu_suspend_start(&ep,
158 target_pwrlvl);
Soby Mathewb48349e2015-06-29 16:30:12 +0100159
160 /* Reset PSCI power state parameter for the core. */
161 psci_set_suspend_power_state(PSCI_INVALID_DATA);
162 return PSCI_E_SUCCESS;
163}
164
165int psci_system_suspend(unsigned long entrypoint,
166 unsigned long context_id)
167{
168 int rc;
169 unsigned int power_state;
170 entry_point_info_t ep;
171
172 /* Validate the entrypoint using platform pm_ops */
173 if (psci_plat_pm_ops->validate_ns_entrypoint) {
174 rc = psci_plat_pm_ops->validate_ns_entrypoint(entrypoint);
175 if (rc != PSCI_E_SUCCESS) {
176 assert(rc == PSCI_E_INVALID_PARAMS);
177 return PSCI_E_INVALID_PARAMS;
178 }
179 }
180
181 /* Check if the current CPU is the last ON CPU in the system */
182 if (!psci_is_last_on_cpu())
183 return PSCI_E_DENIED;
184
185 /*
186 * Verify and derive the re-entry information for
187 * the non-secure world from the non-secure state from
188 * where this call originated.
189 */
190 rc = psci_get_ns_ep_info(&ep, entrypoint, context_id);
191 if (rc != PSCI_E_SUCCESS)
192 return rc;
193
194 /*
195 * Assert that the required pm_ops hook is implemented to ensure that
196 * the capability detected during psci_setup() is valid.
197 */
198 assert(psci_plat_pm_ops->get_sys_suspend_power_state);
199
200 /*
201 * Query the platform for the power_state required for system suspend
202 */
203 power_state = psci_plat_pm_ops->get_sys_suspend_power_state();
204
205 /* Save PSCI power state parameter for the core in suspend context */
206 psci_set_suspend_power_state(power_state);
207
208 /*
209 * Do what is needed to enter the power down state. Upon success,
210 * enter the final wfi which will power down this cpu.
211 */
Soby Mathew4067dc32015-05-05 16:33:16 +0100212 psci_cpu_suspend_start(&ep, PLAT_MAX_PWR_LVL);
Soby Mathewb48349e2015-06-29 16:30:12 +0100213
214 /* Reset PSCI power state parameter for the core. */
215 psci_set_suspend_power_state(PSCI_INVALID_DATA);
216 return PSCI_E_SUCCESS;
217}
218
219int psci_cpu_off(void)
220{
221 int rc;
Soby Mathew4067dc32015-05-05 16:33:16 +0100222 int target_pwrlvl = PLAT_MAX_PWR_LVL;
Soby Mathewb48349e2015-06-29 16:30:12 +0100223
224 /*
Soby Mathew4067dc32015-05-05 16:33:16 +0100225 * Do what is needed to power off this CPU and possible higher power
226 * levels if it able to do so. Upon success, enter the final wfi
227 * which will power down this CPU.
Soby Mathewb48349e2015-06-29 16:30:12 +0100228 */
Soby Mathew4067dc32015-05-05 16:33:16 +0100229 rc = psci_do_cpu_off(target_pwrlvl);
Soby Mathewb48349e2015-06-29 16:30:12 +0100230
231 /*
232 * The only error cpu_off can return is E_DENIED. So check if that's
233 * indeed the case.
234 */
235 assert (rc == PSCI_E_DENIED);
236
237 return rc;
238}
239
240int psci_affinity_info(unsigned long target_affinity,
241 unsigned int lowest_affinity_level)
242{
243 int rc = PSCI_E_INVALID_PARAMS;
Soby Mathew4067dc32015-05-05 16:33:16 +0100244 unsigned int pwr_domain_state;
245 pwr_map_node_t *node;
Soby Mathewb48349e2015-06-29 16:30:12 +0100246
Soby Mathew4067dc32015-05-05 16:33:16 +0100247 if (lowest_affinity_level > PLAT_MAX_PWR_LVL)
Soby Mathewb48349e2015-06-29 16:30:12 +0100248 return rc;
249
Soby Mathew4067dc32015-05-05 16:33:16 +0100250 node = psci_get_pwr_map_node(target_affinity, lowest_affinity_level);
251 if (node && (node->state & PSCI_PWR_DOMAIN_PRESENT)) {
Soby Mathewb48349e2015-06-29 16:30:12 +0100252
253 /*
Soby Mathew4067dc32015-05-05 16:33:16 +0100254 * TODO: For power levels higher than 0 i.e. cpu, the
Soby Mathewb48349e2015-06-29 16:30:12 +0100255 * state will always be either ON or OFF. Need to investigate
256 * how critical is it to support ON_PENDING here.
257 */
Soby Mathew4067dc32015-05-05 16:33:16 +0100258 pwr_domain_state = psci_get_state(node);
Soby Mathewb48349e2015-06-29 16:30:12 +0100259
260 /* A suspended cpu is available & on for the OS */
Soby Mathew4067dc32015-05-05 16:33:16 +0100261 if (pwr_domain_state == PSCI_STATE_SUSPEND) {
262 pwr_domain_state = PSCI_STATE_ON;
Soby Mathewb48349e2015-06-29 16:30:12 +0100263 }
264
Soby Mathew4067dc32015-05-05 16:33:16 +0100265 rc = pwr_domain_state;
Soby Mathewb48349e2015-06-29 16:30:12 +0100266 }
267
268 return rc;
269}
270
271int psci_migrate(unsigned long target_cpu)
272{
273 int rc;
274 unsigned long resident_cpu_mpidr;
275
276 rc = psci_spd_migrate_info(&resident_cpu_mpidr);
277 if (rc != PSCI_TOS_UP_MIG_CAP)
278 return (rc == PSCI_TOS_NOT_UP_MIG_CAP) ?
279 PSCI_E_DENIED : PSCI_E_NOT_SUPPORTED;
280
281 /*
282 * Migrate should only be invoked on the CPU where
283 * the Secure OS is resident.
284 */
285 if (resident_cpu_mpidr != read_mpidr_el1())
286 return PSCI_E_NOT_PRESENT;
287
288 /* Check the validity of the specified target cpu */
Soby Mathew12d0d002015-04-09 13:40:55 +0100289 rc = psci_validate_mpidr(target_cpu);
Soby Mathewb48349e2015-06-29 16:30:12 +0100290 if (rc != PSCI_E_SUCCESS)
291 return PSCI_E_INVALID_PARAMS;
292
293 assert(psci_spd_pm && psci_spd_pm->svc_migrate);
294
295 rc = psci_spd_pm->svc_migrate(read_mpidr_el1(), target_cpu);
296 assert(rc == PSCI_E_SUCCESS || rc == PSCI_E_INTERN_FAIL);
297
298 return rc;
299}
300
301int psci_migrate_info_type(void)
302{
303 unsigned long resident_cpu_mpidr;
304
305 return psci_spd_migrate_info(&resident_cpu_mpidr);
306}
307
308long psci_migrate_info_up_cpu(void)
309{
310 unsigned long resident_cpu_mpidr;
311 int rc;
312
313 /*
314 * Return value of this depends upon what
315 * psci_spd_migrate_info() returns.
316 */
317 rc = psci_spd_migrate_info(&resident_cpu_mpidr);
318 if (rc != PSCI_TOS_NOT_UP_MIG_CAP && rc != PSCI_TOS_UP_MIG_CAP)
319 return PSCI_E_INVALID_PARAMS;
320
321 return resident_cpu_mpidr;
322}
323
324int psci_features(unsigned int psci_fid)
325{
326 uint32_t local_caps = psci_caps;
327
328 /* Check if it is a 64 bit function */
329 if (((psci_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64)
330 local_caps &= PSCI_CAP_64BIT_MASK;
331
332 /* Check for invalid fid */
333 if (!(is_std_svc_call(psci_fid) && is_valid_fast_smc(psci_fid)
334 && is_psci_fid(psci_fid)))
335 return PSCI_E_NOT_SUPPORTED;
336
337
338 /* Check if the psci fid is supported or not */
339 if (!(local_caps & define_psci_cap(psci_fid)))
340 return PSCI_E_NOT_SUPPORTED;
341
342 /* Format the feature flags */
343 if (psci_fid == PSCI_CPU_SUSPEND_AARCH32 ||
344 psci_fid == PSCI_CPU_SUSPEND_AARCH64) {
345 /*
346 * The trusted firmware uses the original power state format
347 * and does not support OS Initiated Mode.
348 */
349 return (FF_PSTATE_ORIG << FF_PSTATE_SHIFT) |
350 ((!FF_SUPPORTS_OS_INIT_MODE) << FF_MODE_SUPPORT_SHIFT);
351 }
352
353 /* Return 0 for all other fid's */
354 return PSCI_E_SUCCESS;
355}
356
357/*******************************************************************************
358 * PSCI top level handler for servicing SMCs.
359 ******************************************************************************/
360uint64_t psci_smc_handler(uint32_t smc_fid,
361 uint64_t x1,
362 uint64_t x2,
363 uint64_t x3,
364 uint64_t x4,
365 void *cookie,
366 void *handle,
367 uint64_t flags)
368{
369 if (is_caller_secure(flags))
370 SMC_RET1(handle, SMC_UNK);
371
372 /* Check the fid against the capabilities */
373 if (!(psci_caps & define_psci_cap(smc_fid)))
374 SMC_RET1(handle, SMC_UNK);
375
376 if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
377 /* 32-bit PSCI function, clear top parameter bits */
378
379 x1 = (uint32_t)x1;
380 x2 = (uint32_t)x2;
381 x3 = (uint32_t)x3;
382
383 switch (smc_fid) {
384 case PSCI_VERSION:
385 SMC_RET1(handle, psci_version());
386
387 case PSCI_CPU_OFF:
388 SMC_RET1(handle, psci_cpu_off());
389
390 case PSCI_CPU_SUSPEND_AARCH32:
391 SMC_RET1(handle, psci_cpu_suspend(x1, x2, x3));
392
393 case PSCI_CPU_ON_AARCH32:
394 SMC_RET1(handle, psci_cpu_on(x1, x2, x3));
395
396 case PSCI_AFFINITY_INFO_AARCH32:
397 SMC_RET1(handle, psci_affinity_info(x1, x2));
398
399 case PSCI_MIG_AARCH32:
400 SMC_RET1(handle, psci_migrate(x1));
401
402 case PSCI_MIG_INFO_TYPE:
403 SMC_RET1(handle, psci_migrate_info_type());
404
405 case PSCI_MIG_INFO_UP_CPU_AARCH32:
406 SMC_RET1(handle, psci_migrate_info_up_cpu());
407
408 case PSCI_SYSTEM_SUSPEND_AARCH32:
409 SMC_RET1(handle, psci_system_suspend(x1, x2));
410
411 case PSCI_SYSTEM_OFF:
412 psci_system_off();
413 /* We should never return from psci_system_off() */
414
415 case PSCI_SYSTEM_RESET:
416 psci_system_reset();
417 /* We should never return from psci_system_reset() */
418
419 case PSCI_FEATURES:
420 SMC_RET1(handle, psci_features(x1));
421
422 default:
423 break;
424 }
425 } else {
426 /* 64-bit PSCI function */
427
428 switch (smc_fid) {
429 case PSCI_CPU_SUSPEND_AARCH64:
430 SMC_RET1(handle, psci_cpu_suspend(x1, x2, x3));
431
432 case PSCI_CPU_ON_AARCH64:
433 SMC_RET1(handle, psci_cpu_on(x1, x2, x3));
434
435 case PSCI_AFFINITY_INFO_AARCH64:
436 SMC_RET1(handle, psci_affinity_info(x1, x2));
437
438 case PSCI_MIG_AARCH64:
439 SMC_RET1(handle, psci_migrate(x1));
440
441 case PSCI_MIG_INFO_UP_CPU_AARCH64:
442 SMC_RET1(handle, psci_migrate_info_up_cpu());
443
444 case PSCI_SYSTEM_SUSPEND_AARCH64:
445 SMC_RET1(handle, psci_system_suspend(x1, x2));
446
447 default:
448 break;
449 }
450 }
451
452 WARN("Unimplemented PSCI Call: 0x%x \n", smc_fid);
453 SMC_RET1(handle, SMC_UNK);
454}