xref: /rk3399_ARM-atf/lib/psci/psci_main.c (revision 532ed6183868036e4a4f83cd7a71b93266a3bdb7)
1*532ed618SSoby Mathew /*
2*532ed618SSoby Mathew  * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
3*532ed618SSoby Mathew  *
4*532ed618SSoby Mathew  * Redistribution and use in source and binary forms, with or without
5*532ed618SSoby Mathew  * modification, are permitted provided that the following conditions are met:
6*532ed618SSoby Mathew  *
7*532ed618SSoby Mathew  * Redistributions of source code must retain the above copyright notice, this
8*532ed618SSoby Mathew  * list of conditions and the following disclaimer.
9*532ed618SSoby Mathew  *
10*532ed618SSoby Mathew  * Redistributions in binary form must reproduce the above copyright notice,
11*532ed618SSoby Mathew  * this list of conditions and the following disclaimer in the documentation
12*532ed618SSoby Mathew  * and/or other materials provided with the distribution.
13*532ed618SSoby Mathew  *
14*532ed618SSoby Mathew  * Neither the name of ARM nor the names of its contributors may be used
15*532ed618SSoby Mathew  * to endorse or promote products derived from this software without specific
16*532ed618SSoby Mathew  * prior written permission.
17*532ed618SSoby Mathew  *
18*532ed618SSoby Mathew  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*532ed618SSoby Mathew  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*532ed618SSoby Mathew  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*532ed618SSoby Mathew  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*532ed618SSoby Mathew  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*532ed618SSoby Mathew  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*532ed618SSoby Mathew  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*532ed618SSoby Mathew  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*532ed618SSoby Mathew  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*532ed618SSoby Mathew  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*532ed618SSoby Mathew  * POSSIBILITY OF SUCH DAMAGE.
29*532ed618SSoby Mathew  */
30*532ed618SSoby Mathew 
31*532ed618SSoby Mathew #include <arch.h>
32*532ed618SSoby Mathew #include <arch_helpers.h>
33*532ed618SSoby Mathew #include <assert.h>
34*532ed618SSoby Mathew #include <debug.h>
35*532ed618SSoby Mathew #include <platform.h>
36*532ed618SSoby Mathew #include <runtime_svc.h>
37*532ed618SSoby Mathew #include <std_svc.h>
38*532ed618SSoby Mathew #include <string.h>
39*532ed618SSoby Mathew #include "psci_private.h"
40*532ed618SSoby Mathew 
41*532ed618SSoby Mathew /*******************************************************************************
42*532ed618SSoby Mathew  * PSCI frontend api for servicing SMCs. Described in the PSCI spec.
43*532ed618SSoby Mathew  ******************************************************************************/
44*532ed618SSoby Mathew int psci_cpu_on(u_register_t target_cpu,
45*532ed618SSoby Mathew 		uintptr_t entrypoint,
46*532ed618SSoby Mathew 		u_register_t context_id)
47*532ed618SSoby Mathew 
48*532ed618SSoby Mathew {
49*532ed618SSoby Mathew 	int rc;
50*532ed618SSoby Mathew 	entry_point_info_t ep;
51*532ed618SSoby Mathew 
52*532ed618SSoby Mathew 	/* Determine if the cpu exists of not */
53*532ed618SSoby Mathew 	rc = psci_validate_mpidr(target_cpu);
54*532ed618SSoby Mathew 	if (rc != PSCI_E_SUCCESS)
55*532ed618SSoby Mathew 		return PSCI_E_INVALID_PARAMS;
56*532ed618SSoby Mathew 
57*532ed618SSoby Mathew 	/* Validate the entry point and get the entry_point_info */
58*532ed618SSoby Mathew 	rc = psci_validate_entry_point(&ep, entrypoint, context_id);
59*532ed618SSoby Mathew 	if (rc != PSCI_E_SUCCESS)
60*532ed618SSoby Mathew 		return rc;
61*532ed618SSoby Mathew 
62*532ed618SSoby Mathew 	/*
63*532ed618SSoby Mathew 	 * To turn this cpu on, specify which power
64*532ed618SSoby Mathew 	 * levels need to be turned on
65*532ed618SSoby Mathew 	 */
66*532ed618SSoby Mathew 	return psci_cpu_on_start(target_cpu, &ep);
67*532ed618SSoby Mathew }
68*532ed618SSoby Mathew 
69*532ed618SSoby Mathew unsigned int psci_version(void)
70*532ed618SSoby Mathew {
71*532ed618SSoby Mathew 	return PSCI_MAJOR_VER | PSCI_MINOR_VER;
72*532ed618SSoby Mathew }
73*532ed618SSoby Mathew 
74*532ed618SSoby Mathew int psci_cpu_suspend(unsigned int power_state,
75*532ed618SSoby Mathew 		     uintptr_t entrypoint,
76*532ed618SSoby Mathew 		     u_register_t context_id)
77*532ed618SSoby Mathew {
78*532ed618SSoby Mathew 	int rc;
79*532ed618SSoby Mathew 	unsigned int target_pwrlvl, is_power_down_state;
80*532ed618SSoby Mathew 	entry_point_info_t ep;
81*532ed618SSoby Mathew 	psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
82*532ed618SSoby Mathew 	plat_local_state_t cpu_pd_state;
83*532ed618SSoby Mathew 
84*532ed618SSoby Mathew 	/* Validate the power_state parameter */
85*532ed618SSoby Mathew 	rc = psci_validate_power_state(power_state, &state_info);
86*532ed618SSoby Mathew 	if (rc != PSCI_E_SUCCESS) {
87*532ed618SSoby Mathew 		assert(rc == PSCI_E_INVALID_PARAMS);
88*532ed618SSoby Mathew 		return rc;
89*532ed618SSoby Mathew 	}
90*532ed618SSoby Mathew 
91*532ed618SSoby Mathew 	/*
92*532ed618SSoby Mathew 	 * Get the value of the state type bit from the power state parameter.
93*532ed618SSoby Mathew 	 */
94*532ed618SSoby Mathew 	is_power_down_state = psci_get_pstate_type(power_state);
95*532ed618SSoby Mathew 
96*532ed618SSoby Mathew 	/* Sanity check the requested suspend levels */
97*532ed618SSoby Mathew 	assert(psci_validate_suspend_req(&state_info, is_power_down_state)
98*532ed618SSoby Mathew 			== PSCI_E_SUCCESS);
99*532ed618SSoby Mathew 
100*532ed618SSoby Mathew 	target_pwrlvl = psci_find_target_suspend_lvl(&state_info);
101*532ed618SSoby Mathew 
102*532ed618SSoby Mathew 	/* Fast path for CPU standby.*/
103*532ed618SSoby Mathew 	if (is_cpu_standby_req(is_power_down_state, target_pwrlvl)) {
104*532ed618SSoby Mathew 		if  (!psci_plat_pm_ops->cpu_standby)
105*532ed618SSoby Mathew 			return PSCI_E_INVALID_PARAMS;
106*532ed618SSoby Mathew 
107*532ed618SSoby Mathew 		/*
108*532ed618SSoby Mathew 		 * Set the state of the CPU power domain to the platform
109*532ed618SSoby Mathew 		 * specific retention state and enter the standby state.
110*532ed618SSoby Mathew 		 */
111*532ed618SSoby Mathew 		cpu_pd_state = state_info.pwr_domain_state[PSCI_CPU_PWR_LVL];
112*532ed618SSoby Mathew 		psci_set_cpu_local_state(cpu_pd_state);
113*532ed618SSoby Mathew 
114*532ed618SSoby Mathew #if ENABLE_PSCI_STAT
115*532ed618SSoby Mathew 		/*
116*532ed618SSoby Mathew 		 * Capture time-stamp before CPU standby
117*532ed618SSoby Mathew 		 * No cache maintenance is needed as caches
118*532ed618SSoby Mathew 		 * are ON through out the CPU standby operation.
119*532ed618SSoby Mathew 		 */
120*532ed618SSoby Mathew 		PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
121*532ed618SSoby Mathew 			PMF_NO_CACHE_MAINT);
122*532ed618SSoby Mathew #endif
123*532ed618SSoby Mathew 
124*532ed618SSoby Mathew 		psci_plat_pm_ops->cpu_standby(cpu_pd_state);
125*532ed618SSoby Mathew 
126*532ed618SSoby Mathew 		/* Upon exit from standby, set the state back to RUN. */
127*532ed618SSoby Mathew 		psci_set_cpu_local_state(PSCI_LOCAL_STATE_RUN);
128*532ed618SSoby Mathew 
129*532ed618SSoby Mathew #if ENABLE_PSCI_STAT
130*532ed618SSoby Mathew 		/* Capture time-stamp after CPU standby */
131*532ed618SSoby Mathew 		PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
132*532ed618SSoby Mathew 			PMF_NO_CACHE_MAINT);
133*532ed618SSoby Mathew 
134*532ed618SSoby Mathew 		/* Update PSCI stats */
135*532ed618SSoby Mathew 		psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info,
136*532ed618SSoby Mathew 			PMF_NO_CACHE_MAINT);
137*532ed618SSoby Mathew #endif
138*532ed618SSoby Mathew 
139*532ed618SSoby Mathew 		return PSCI_E_SUCCESS;
140*532ed618SSoby Mathew 	}
141*532ed618SSoby Mathew 
142*532ed618SSoby Mathew 	/*
143*532ed618SSoby Mathew 	 * If a power down state has been requested, we need to verify entry
144*532ed618SSoby Mathew 	 * point and program entry information.
145*532ed618SSoby Mathew 	 */
146*532ed618SSoby Mathew 	if (is_power_down_state) {
147*532ed618SSoby Mathew 		rc = psci_validate_entry_point(&ep, entrypoint, context_id);
148*532ed618SSoby Mathew 		if (rc != PSCI_E_SUCCESS)
149*532ed618SSoby Mathew 			return rc;
150*532ed618SSoby Mathew 	}
151*532ed618SSoby Mathew 
152*532ed618SSoby Mathew 	/*
153*532ed618SSoby Mathew 	 * Do what is needed to enter the power down state. Upon success,
154*532ed618SSoby Mathew 	 * enter the final wfi which will power down this CPU. This function
155*532ed618SSoby Mathew 	 * might return if the power down was abandoned for any reason, e.g.
156*532ed618SSoby Mathew 	 * arrival of an interrupt
157*532ed618SSoby Mathew 	 */
158*532ed618SSoby Mathew 	psci_cpu_suspend_start(&ep,
159*532ed618SSoby Mathew 			    target_pwrlvl,
160*532ed618SSoby Mathew 			    &state_info,
161*532ed618SSoby Mathew 			    is_power_down_state);
162*532ed618SSoby Mathew 
163*532ed618SSoby Mathew 	return PSCI_E_SUCCESS;
164*532ed618SSoby Mathew }
165*532ed618SSoby Mathew 
166*532ed618SSoby Mathew 
167*532ed618SSoby Mathew int psci_system_suspend(uintptr_t entrypoint, u_register_t context_id)
168*532ed618SSoby Mathew {
169*532ed618SSoby Mathew 	int rc;
170*532ed618SSoby Mathew 	psci_power_state_t state_info;
171*532ed618SSoby Mathew 	entry_point_info_t ep;
172*532ed618SSoby Mathew 
173*532ed618SSoby Mathew 	/* Check if the current CPU is the last ON CPU in the system */
174*532ed618SSoby Mathew 	if (!psci_is_last_on_cpu())
175*532ed618SSoby Mathew 		return PSCI_E_DENIED;
176*532ed618SSoby Mathew 
177*532ed618SSoby Mathew 	/* Validate the entry point and get the entry_point_info */
178*532ed618SSoby Mathew 	rc = psci_validate_entry_point(&ep, entrypoint, context_id);
179*532ed618SSoby Mathew 	if (rc != PSCI_E_SUCCESS)
180*532ed618SSoby Mathew 		return rc;
181*532ed618SSoby Mathew 
182*532ed618SSoby Mathew 	/* Query the psci_power_state for system suspend */
183*532ed618SSoby Mathew 	psci_query_sys_suspend_pwrstate(&state_info);
184*532ed618SSoby Mathew 
185*532ed618SSoby Mathew 	/* Ensure that the psci_power_state makes sense */
186*532ed618SSoby Mathew 	assert(psci_find_target_suspend_lvl(&state_info) == PLAT_MAX_PWR_LVL);
187*532ed618SSoby Mathew 	assert(psci_validate_suspend_req(&state_info, PSTATE_TYPE_POWERDOWN)
188*532ed618SSoby Mathew 						== PSCI_E_SUCCESS);
189*532ed618SSoby Mathew 	assert(is_local_state_off(state_info.pwr_domain_state[PLAT_MAX_PWR_LVL]));
190*532ed618SSoby Mathew 
191*532ed618SSoby Mathew 	/*
192*532ed618SSoby Mathew 	 * Do what is needed to enter the system suspend state. This function
193*532ed618SSoby Mathew 	 * might return if the power down was abandoned for any reason, e.g.
194*532ed618SSoby Mathew 	 * arrival of an interrupt
195*532ed618SSoby Mathew 	 */
196*532ed618SSoby Mathew 	psci_cpu_suspend_start(&ep,
197*532ed618SSoby Mathew 			    PLAT_MAX_PWR_LVL,
198*532ed618SSoby Mathew 			    &state_info,
199*532ed618SSoby Mathew 			    PSTATE_TYPE_POWERDOWN);
200*532ed618SSoby Mathew 
201*532ed618SSoby Mathew 	return PSCI_E_SUCCESS;
202*532ed618SSoby Mathew }
203*532ed618SSoby Mathew 
204*532ed618SSoby Mathew int psci_cpu_off(void)
205*532ed618SSoby Mathew {
206*532ed618SSoby Mathew 	int rc;
207*532ed618SSoby Mathew 	unsigned int target_pwrlvl = PLAT_MAX_PWR_LVL;
208*532ed618SSoby Mathew 
209*532ed618SSoby Mathew 	/*
210*532ed618SSoby Mathew 	 * Do what is needed to power off this CPU and possible higher power
211*532ed618SSoby Mathew 	 * levels if it able to do so. Upon success, enter the final wfi
212*532ed618SSoby Mathew 	 * which will power down this CPU.
213*532ed618SSoby Mathew 	 */
214*532ed618SSoby Mathew 	rc = psci_do_cpu_off(target_pwrlvl);
215*532ed618SSoby Mathew 
216*532ed618SSoby Mathew 	/*
217*532ed618SSoby Mathew 	 * The only error cpu_off can return is E_DENIED. So check if that's
218*532ed618SSoby Mathew 	 * indeed the case.
219*532ed618SSoby Mathew 	 */
220*532ed618SSoby Mathew 	assert(rc == PSCI_E_DENIED);
221*532ed618SSoby Mathew 
222*532ed618SSoby Mathew 	return rc;
223*532ed618SSoby Mathew }
224*532ed618SSoby Mathew 
225*532ed618SSoby Mathew int psci_affinity_info(u_register_t target_affinity,
226*532ed618SSoby Mathew 		       unsigned int lowest_affinity_level)
227*532ed618SSoby Mathew {
228*532ed618SSoby Mathew 	unsigned int target_idx;
229*532ed618SSoby Mathew 
230*532ed618SSoby Mathew 	/* We dont support level higher than PSCI_CPU_PWR_LVL */
231*532ed618SSoby Mathew 	if (lowest_affinity_level > PSCI_CPU_PWR_LVL)
232*532ed618SSoby Mathew 		return PSCI_E_INVALID_PARAMS;
233*532ed618SSoby Mathew 
234*532ed618SSoby Mathew 	/* Calculate the cpu index of the target */
235*532ed618SSoby Mathew 	target_idx = plat_core_pos_by_mpidr(target_affinity);
236*532ed618SSoby Mathew 	if (target_idx == -1)
237*532ed618SSoby Mathew 		return PSCI_E_INVALID_PARAMS;
238*532ed618SSoby Mathew 
239*532ed618SSoby Mathew 	return psci_get_aff_info_state_by_idx(target_idx);
240*532ed618SSoby Mathew }
241*532ed618SSoby Mathew 
242*532ed618SSoby Mathew int psci_migrate(u_register_t target_cpu)
243*532ed618SSoby Mathew {
244*532ed618SSoby Mathew 	int rc;
245*532ed618SSoby Mathew 	u_register_t resident_cpu_mpidr;
246*532ed618SSoby Mathew 
247*532ed618SSoby Mathew 	rc = psci_spd_migrate_info(&resident_cpu_mpidr);
248*532ed618SSoby Mathew 	if (rc != PSCI_TOS_UP_MIG_CAP)
249*532ed618SSoby Mathew 		return (rc == PSCI_TOS_NOT_UP_MIG_CAP) ?
250*532ed618SSoby Mathew 			  PSCI_E_DENIED : PSCI_E_NOT_SUPPORTED;
251*532ed618SSoby Mathew 
252*532ed618SSoby Mathew 	/*
253*532ed618SSoby Mathew 	 * Migrate should only be invoked on the CPU where
254*532ed618SSoby Mathew 	 * the Secure OS is resident.
255*532ed618SSoby Mathew 	 */
256*532ed618SSoby Mathew 	if (resident_cpu_mpidr != read_mpidr_el1())
257*532ed618SSoby Mathew 		return PSCI_E_NOT_PRESENT;
258*532ed618SSoby Mathew 
259*532ed618SSoby Mathew 	/* Check the validity of the specified target cpu */
260*532ed618SSoby Mathew 	rc = psci_validate_mpidr(target_cpu);
261*532ed618SSoby Mathew 	if (rc != PSCI_E_SUCCESS)
262*532ed618SSoby Mathew 		return PSCI_E_INVALID_PARAMS;
263*532ed618SSoby Mathew 
264*532ed618SSoby Mathew 	assert(psci_spd_pm && psci_spd_pm->svc_migrate);
265*532ed618SSoby Mathew 
266*532ed618SSoby Mathew 	rc = psci_spd_pm->svc_migrate(read_mpidr_el1(), target_cpu);
267*532ed618SSoby Mathew 	assert(rc == PSCI_E_SUCCESS || rc == PSCI_E_INTERN_FAIL);
268*532ed618SSoby Mathew 
269*532ed618SSoby Mathew 	return rc;
270*532ed618SSoby Mathew }
271*532ed618SSoby Mathew 
272*532ed618SSoby Mathew int psci_migrate_info_type(void)
273*532ed618SSoby Mathew {
274*532ed618SSoby Mathew 	u_register_t resident_cpu_mpidr;
275*532ed618SSoby Mathew 
276*532ed618SSoby Mathew 	return psci_spd_migrate_info(&resident_cpu_mpidr);
277*532ed618SSoby Mathew }
278*532ed618SSoby Mathew 
279*532ed618SSoby Mathew long psci_migrate_info_up_cpu(void)
280*532ed618SSoby Mathew {
281*532ed618SSoby Mathew 	u_register_t resident_cpu_mpidr;
282*532ed618SSoby Mathew 	int rc;
283*532ed618SSoby Mathew 
284*532ed618SSoby Mathew 	/*
285*532ed618SSoby Mathew 	 * Return value of this depends upon what
286*532ed618SSoby Mathew 	 * psci_spd_migrate_info() returns.
287*532ed618SSoby Mathew 	 */
288*532ed618SSoby Mathew 	rc = psci_spd_migrate_info(&resident_cpu_mpidr);
289*532ed618SSoby Mathew 	if (rc != PSCI_TOS_NOT_UP_MIG_CAP && rc != PSCI_TOS_UP_MIG_CAP)
290*532ed618SSoby Mathew 		return PSCI_E_INVALID_PARAMS;
291*532ed618SSoby Mathew 
292*532ed618SSoby Mathew 	return resident_cpu_mpidr;
293*532ed618SSoby Mathew }
294*532ed618SSoby Mathew 
295*532ed618SSoby Mathew int psci_features(unsigned int psci_fid)
296*532ed618SSoby Mathew {
297*532ed618SSoby Mathew 	unsigned int local_caps = psci_caps;
298*532ed618SSoby Mathew 
299*532ed618SSoby Mathew 	/* Check if it is a 64 bit function */
300*532ed618SSoby Mathew 	if (((psci_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64)
301*532ed618SSoby Mathew 		local_caps &= PSCI_CAP_64BIT_MASK;
302*532ed618SSoby Mathew 
303*532ed618SSoby Mathew 	/* Check for invalid fid */
304*532ed618SSoby Mathew 	if (!(is_std_svc_call(psci_fid) && is_valid_fast_smc(psci_fid)
305*532ed618SSoby Mathew 			&& is_psci_fid(psci_fid)))
306*532ed618SSoby Mathew 		return PSCI_E_NOT_SUPPORTED;
307*532ed618SSoby Mathew 
308*532ed618SSoby Mathew 
309*532ed618SSoby Mathew 	/* Check if the psci fid is supported or not */
310*532ed618SSoby Mathew 	if (!(local_caps & define_psci_cap(psci_fid)))
311*532ed618SSoby Mathew 		return PSCI_E_NOT_SUPPORTED;
312*532ed618SSoby Mathew 
313*532ed618SSoby Mathew 	/* Format the feature flags */
314*532ed618SSoby Mathew 	if (psci_fid == PSCI_CPU_SUSPEND_AARCH32 ||
315*532ed618SSoby Mathew 			psci_fid == PSCI_CPU_SUSPEND_AARCH64) {
316*532ed618SSoby Mathew 		/*
317*532ed618SSoby Mathew 		 * The trusted firmware does not support OS Initiated Mode.
318*532ed618SSoby Mathew 		 */
319*532ed618SSoby Mathew 		return (FF_PSTATE << FF_PSTATE_SHIFT) |
320*532ed618SSoby Mathew 			((!FF_SUPPORTS_OS_INIT_MODE) << FF_MODE_SUPPORT_SHIFT);
321*532ed618SSoby Mathew 	}
322*532ed618SSoby Mathew 
323*532ed618SSoby Mathew 	/* Return 0 for all other fid's */
324*532ed618SSoby Mathew 	return PSCI_E_SUCCESS;
325*532ed618SSoby Mathew }
326*532ed618SSoby Mathew 
327*532ed618SSoby Mathew /*******************************************************************************
328*532ed618SSoby Mathew  * PSCI top level handler for servicing SMCs.
329*532ed618SSoby Mathew  ******************************************************************************/
330*532ed618SSoby Mathew uintptr_t psci_smc_handler(uint32_t smc_fid,
331*532ed618SSoby Mathew 			  u_register_t x1,
332*532ed618SSoby Mathew 			  u_register_t x2,
333*532ed618SSoby Mathew 			  u_register_t x3,
334*532ed618SSoby Mathew 			  u_register_t x4,
335*532ed618SSoby Mathew 			  void *cookie,
336*532ed618SSoby Mathew 			  void *handle,
337*532ed618SSoby Mathew 			  u_register_t flags)
338*532ed618SSoby Mathew {
339*532ed618SSoby Mathew 	if (is_caller_secure(flags))
340*532ed618SSoby Mathew 		SMC_RET1(handle, SMC_UNK);
341*532ed618SSoby Mathew 
342*532ed618SSoby Mathew 	/* Check the fid against the capabilities */
343*532ed618SSoby Mathew 	if (!(psci_caps & define_psci_cap(smc_fid)))
344*532ed618SSoby Mathew 		SMC_RET1(handle, SMC_UNK);
345*532ed618SSoby Mathew 
346*532ed618SSoby Mathew 	if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
347*532ed618SSoby Mathew 		/* 32-bit PSCI function, clear top parameter bits */
348*532ed618SSoby Mathew 
349*532ed618SSoby Mathew 		x1 = (uint32_t)x1;
350*532ed618SSoby Mathew 		x2 = (uint32_t)x2;
351*532ed618SSoby Mathew 		x3 = (uint32_t)x3;
352*532ed618SSoby Mathew 
353*532ed618SSoby Mathew 		switch (smc_fid) {
354*532ed618SSoby Mathew 		case PSCI_VERSION:
355*532ed618SSoby Mathew 			SMC_RET1(handle, psci_version());
356*532ed618SSoby Mathew 
357*532ed618SSoby Mathew 		case PSCI_CPU_OFF:
358*532ed618SSoby Mathew 			SMC_RET1(handle, psci_cpu_off());
359*532ed618SSoby Mathew 
360*532ed618SSoby Mathew 		case PSCI_CPU_SUSPEND_AARCH32:
361*532ed618SSoby Mathew 			SMC_RET1(handle, psci_cpu_suspend(x1, x2, x3));
362*532ed618SSoby Mathew 
363*532ed618SSoby Mathew 		case PSCI_CPU_ON_AARCH32:
364*532ed618SSoby Mathew 			SMC_RET1(handle, psci_cpu_on(x1, x2, x3));
365*532ed618SSoby Mathew 
366*532ed618SSoby Mathew 		case PSCI_AFFINITY_INFO_AARCH32:
367*532ed618SSoby Mathew 			SMC_RET1(handle, psci_affinity_info(x1, x2));
368*532ed618SSoby Mathew 
369*532ed618SSoby Mathew 		case PSCI_MIG_AARCH32:
370*532ed618SSoby Mathew 			SMC_RET1(handle, psci_migrate(x1));
371*532ed618SSoby Mathew 
372*532ed618SSoby Mathew 		case PSCI_MIG_INFO_TYPE:
373*532ed618SSoby Mathew 			SMC_RET1(handle, psci_migrate_info_type());
374*532ed618SSoby Mathew 
375*532ed618SSoby Mathew 		case PSCI_MIG_INFO_UP_CPU_AARCH32:
376*532ed618SSoby Mathew 			SMC_RET1(handle, psci_migrate_info_up_cpu());
377*532ed618SSoby Mathew 
378*532ed618SSoby Mathew 		case PSCI_SYSTEM_SUSPEND_AARCH32:
379*532ed618SSoby Mathew 			SMC_RET1(handle, psci_system_suspend(x1, x2));
380*532ed618SSoby Mathew 
381*532ed618SSoby Mathew 		case PSCI_SYSTEM_OFF:
382*532ed618SSoby Mathew 			psci_system_off();
383*532ed618SSoby Mathew 			/* We should never return from psci_system_off() */
384*532ed618SSoby Mathew 
385*532ed618SSoby Mathew 		case PSCI_SYSTEM_RESET:
386*532ed618SSoby Mathew 			psci_system_reset();
387*532ed618SSoby Mathew 			/* We should never return from psci_system_reset() */
388*532ed618SSoby Mathew 
389*532ed618SSoby Mathew 		case PSCI_FEATURES:
390*532ed618SSoby Mathew 			SMC_RET1(handle, psci_features(x1));
391*532ed618SSoby Mathew 
392*532ed618SSoby Mathew #if ENABLE_PSCI_STAT
393*532ed618SSoby Mathew 		case PSCI_STAT_RESIDENCY_AARCH32:
394*532ed618SSoby Mathew 			SMC_RET1(handle, psci_stat_residency(x1, x2));
395*532ed618SSoby Mathew 
396*532ed618SSoby Mathew 		case PSCI_STAT_COUNT_AARCH32:
397*532ed618SSoby Mathew 			SMC_RET1(handle, psci_stat_count(x1, x2));
398*532ed618SSoby Mathew #endif
399*532ed618SSoby Mathew 
400*532ed618SSoby Mathew 		default:
401*532ed618SSoby Mathew 			break;
402*532ed618SSoby Mathew 		}
403*532ed618SSoby Mathew 	} else {
404*532ed618SSoby Mathew 		/* 64-bit PSCI function */
405*532ed618SSoby Mathew 
406*532ed618SSoby Mathew 		switch (smc_fid) {
407*532ed618SSoby Mathew 		case PSCI_CPU_SUSPEND_AARCH64:
408*532ed618SSoby Mathew 			SMC_RET1(handle, psci_cpu_suspend(x1, x2, x3));
409*532ed618SSoby Mathew 
410*532ed618SSoby Mathew 		case PSCI_CPU_ON_AARCH64:
411*532ed618SSoby Mathew 			SMC_RET1(handle, psci_cpu_on(x1, x2, x3));
412*532ed618SSoby Mathew 
413*532ed618SSoby Mathew 		case PSCI_AFFINITY_INFO_AARCH64:
414*532ed618SSoby Mathew 			SMC_RET1(handle, psci_affinity_info(x1, x2));
415*532ed618SSoby Mathew 
416*532ed618SSoby Mathew 		case PSCI_MIG_AARCH64:
417*532ed618SSoby Mathew 			SMC_RET1(handle, psci_migrate(x1));
418*532ed618SSoby Mathew 
419*532ed618SSoby Mathew 		case PSCI_MIG_INFO_UP_CPU_AARCH64:
420*532ed618SSoby Mathew 			SMC_RET1(handle, psci_migrate_info_up_cpu());
421*532ed618SSoby Mathew 
422*532ed618SSoby Mathew 		case PSCI_SYSTEM_SUSPEND_AARCH64:
423*532ed618SSoby Mathew 			SMC_RET1(handle, psci_system_suspend(x1, x2));
424*532ed618SSoby Mathew 
425*532ed618SSoby Mathew #if ENABLE_PSCI_STAT
426*532ed618SSoby Mathew 		case PSCI_STAT_RESIDENCY_AARCH64:
427*532ed618SSoby Mathew 			SMC_RET1(handle, psci_stat_residency(x1, x2));
428*532ed618SSoby Mathew 
429*532ed618SSoby Mathew 		case PSCI_STAT_COUNT_AARCH64:
430*532ed618SSoby Mathew 			SMC_RET1(handle, psci_stat_count(x1, x2));
431*532ed618SSoby Mathew #endif
432*532ed618SSoby Mathew 
433*532ed618SSoby Mathew 		default:
434*532ed618SSoby Mathew 			break;
435*532ed618SSoby Mathew 		}
436*532ed618SSoby Mathew 	}
437*532ed618SSoby Mathew 
438*532ed618SSoby Mathew 	WARN("Unimplemented PSCI Call: 0x%x \n", smc_fid);
439*532ed618SSoby Mathew 	SMC_RET1(handle, SMC_UNK);
440*532ed618SSoby Mathew }
441