xref: /arm-trusted-firmware/plat/arm/common/arm_pm.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu 
9*91f16700Schasinglulu #include <platform_def.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <arch_helpers.h>
12*91f16700Schasinglulu #include <lib/psci/psci.h>
13*91f16700Schasinglulu #include <plat/arm/common/plat_arm.h>
14*91f16700Schasinglulu #include <plat/common/platform.h>
15*91f16700Schasinglulu 
16*91f16700Schasinglulu /* Allow ARM Standard platforms to override these functions */
17*91f16700Schasinglulu #pragma weak plat_arm_program_trusted_mailbox
18*91f16700Schasinglulu 
19*91f16700Schasinglulu #if !ARM_RECOM_STATE_ID_ENC
20*91f16700Schasinglulu /*******************************************************************************
21*91f16700Schasinglulu  * ARM standard platform handler called to check the validity of the power state
22*91f16700Schasinglulu  * parameter.
23*91f16700Schasinglulu  ******************************************************************************/
24*91f16700Schasinglulu int arm_validate_power_state(unsigned int power_state,
25*91f16700Schasinglulu 			    psci_power_state_t *req_state)
26*91f16700Schasinglulu {
27*91f16700Schasinglulu 	unsigned int pstate = psci_get_pstate_type(power_state);
28*91f16700Schasinglulu 	unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
29*91f16700Schasinglulu 	unsigned int i;
30*91f16700Schasinglulu 
31*91f16700Schasinglulu 	assert(req_state != NULL);
32*91f16700Schasinglulu 
33*91f16700Schasinglulu 	if (pwr_lvl > PLAT_MAX_PWR_LVL)
34*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
35*91f16700Schasinglulu 
36*91f16700Schasinglulu 	/* Sanity check the requested state */
37*91f16700Schasinglulu 	if (pstate == PSTATE_TYPE_STANDBY) {
38*91f16700Schasinglulu 		/*
39*91f16700Schasinglulu 		 * It's possible to enter standby only on power level 0
40*91f16700Schasinglulu 		 * Ignore any other power level.
41*91f16700Schasinglulu 		 */
42*91f16700Schasinglulu 		if (pwr_lvl != ARM_PWR_LVL0)
43*91f16700Schasinglulu 			return PSCI_E_INVALID_PARAMS;
44*91f16700Schasinglulu 
45*91f16700Schasinglulu 		req_state->pwr_domain_state[ARM_PWR_LVL0] =
46*91f16700Schasinglulu 					ARM_LOCAL_STATE_RET;
47*91f16700Schasinglulu 	} else {
48*91f16700Schasinglulu 		for (i = ARM_PWR_LVL0; i <= pwr_lvl; i++)
49*91f16700Schasinglulu 			req_state->pwr_domain_state[i] =
50*91f16700Schasinglulu 					ARM_LOCAL_STATE_OFF;
51*91f16700Schasinglulu 	}
52*91f16700Schasinglulu 
53*91f16700Schasinglulu 	/*
54*91f16700Schasinglulu 	 * We expect the 'state id' to be zero.
55*91f16700Schasinglulu 	 */
56*91f16700Schasinglulu 	if (psci_get_pstate_id(power_state) != 0U)
57*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
58*91f16700Schasinglulu 
59*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
60*91f16700Schasinglulu }
61*91f16700Schasinglulu 
62*91f16700Schasinglulu #else
63*91f16700Schasinglulu /*******************************************************************************
64*91f16700Schasinglulu  * ARM standard platform handler called to check the validity of the power
65*91f16700Schasinglulu  * state parameter. The power state parameter has to be a composite power
66*91f16700Schasinglulu  * state.
67*91f16700Schasinglulu  ******************************************************************************/
68*91f16700Schasinglulu int arm_validate_power_state(unsigned int power_state,
69*91f16700Schasinglulu 				psci_power_state_t *req_state)
70*91f16700Schasinglulu {
71*91f16700Schasinglulu 	unsigned int state_id;
72*91f16700Schasinglulu 	int i;
73*91f16700Schasinglulu 
74*91f16700Schasinglulu 	assert(req_state != NULL);
75*91f16700Schasinglulu 
76*91f16700Schasinglulu 	/*
77*91f16700Schasinglulu 	 *  Currently we are using a linear search for finding the matching
78*91f16700Schasinglulu 	 *  entry in the idle power state array. This can be made a binary
79*91f16700Schasinglulu 	 *  search if the number of entries justify the additional complexity.
80*91f16700Schasinglulu 	 */
81*91f16700Schasinglulu 	for (i = 0; !!arm_pm_idle_states[i]; i++) {
82*91f16700Schasinglulu #if PSCI_OS_INIT_MODE
83*91f16700Schasinglulu 		if ((power_state & ~ARM_LAST_AT_PLVL_MASK) ==
84*91f16700Schasinglulu 					arm_pm_idle_states[i])
85*91f16700Schasinglulu #else
86*91f16700Schasinglulu 		if (power_state == arm_pm_idle_states[i])
87*91f16700Schasinglulu #endif /* __PSCI_OS_INIT_MODE__ */
88*91f16700Schasinglulu 			break;
89*91f16700Schasinglulu 	}
90*91f16700Schasinglulu 
91*91f16700Schasinglulu 	/* Return error if entry not found in the idle state array */
92*91f16700Schasinglulu 	if (!arm_pm_idle_states[i])
93*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
94*91f16700Schasinglulu 
95*91f16700Schasinglulu 	i = 0;
96*91f16700Schasinglulu 	state_id = psci_get_pstate_id(power_state);
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	/* Parse the State ID and populate the state info parameter */
99*91f16700Schasinglulu 	for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) {
100*91f16700Schasinglulu 		req_state->pwr_domain_state[i] = state_id &
101*91f16700Schasinglulu 						ARM_LOCAL_PSTATE_MASK;
102*91f16700Schasinglulu 		state_id >>= ARM_LOCAL_PSTATE_WIDTH;
103*91f16700Schasinglulu 	}
104*91f16700Schasinglulu #if PSCI_OS_INIT_MODE
105*91f16700Schasinglulu 	req_state->last_at_pwrlvl = state_id & ARM_LOCAL_PSTATE_MASK;
106*91f16700Schasinglulu #endif /* __PSCI_OS_INIT_MODE__ */
107*91f16700Schasinglulu 
108*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
109*91f16700Schasinglulu }
110*91f16700Schasinglulu #endif /* __ARM_RECOM_STATE_ID_ENC__ */
111*91f16700Schasinglulu 
112*91f16700Schasinglulu /*******************************************************************************
113*91f16700Schasinglulu  * ARM standard platform handler called to check the validity of the non secure
114*91f16700Schasinglulu  * entrypoint. Returns 0 if the entrypoint is valid, or -1 otherwise.
115*91f16700Schasinglulu  ******************************************************************************/
116*91f16700Schasinglulu int arm_validate_ns_entrypoint(uintptr_t entrypoint)
117*91f16700Schasinglulu {
118*91f16700Schasinglulu 	/*
119*91f16700Schasinglulu 	 * Check if the non secure entrypoint lies within the non
120*91f16700Schasinglulu 	 * secure DRAM.
121*91f16700Schasinglulu 	 */
122*91f16700Schasinglulu 	if ((entrypoint >= ARM_NS_DRAM1_BASE) && (entrypoint <
123*91f16700Schasinglulu 			(ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) {
124*91f16700Schasinglulu 		return 0;
125*91f16700Schasinglulu 	}
126*91f16700Schasinglulu #ifdef __aarch64__
127*91f16700Schasinglulu 	if ((entrypoint >= ARM_DRAM2_BASE) && (entrypoint <
128*91f16700Schasinglulu 			(ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) {
129*91f16700Schasinglulu 		return 0;
130*91f16700Schasinglulu 	}
131*91f16700Schasinglulu #endif
132*91f16700Schasinglulu 
133*91f16700Schasinglulu 	return -1;
134*91f16700Schasinglulu }
135*91f16700Schasinglulu 
136*91f16700Schasinglulu int arm_validate_psci_entrypoint(uintptr_t entrypoint)
137*91f16700Schasinglulu {
138*91f16700Schasinglulu 	return (arm_validate_ns_entrypoint(entrypoint) == 0) ? PSCI_E_SUCCESS :
139*91f16700Schasinglulu 		PSCI_E_INVALID_ADDRESS;
140*91f16700Schasinglulu }
141*91f16700Schasinglulu 
142*91f16700Schasinglulu /******************************************************************************
143*91f16700Schasinglulu  * Helper function to save the platform state before a system suspend. Save the
144*91f16700Schasinglulu  * state of the system components which are not in the Always ON power domain.
145*91f16700Schasinglulu  *****************************************************************************/
146*91f16700Schasinglulu void arm_system_pwr_domain_save(void)
147*91f16700Schasinglulu {
148*91f16700Schasinglulu 	/* Assert system power domain is available on the platform */
149*91f16700Schasinglulu 	assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
150*91f16700Schasinglulu 
151*91f16700Schasinglulu 	plat_arm_gic_save();
152*91f16700Schasinglulu 
153*91f16700Schasinglulu 	/*
154*91f16700Schasinglulu 	 * Unregister console now so that it is not registered for a second
155*91f16700Schasinglulu 	 * time during resume.
156*91f16700Schasinglulu 	 */
157*91f16700Schasinglulu 	arm_console_runtime_end();
158*91f16700Schasinglulu 
159*91f16700Schasinglulu 	/*
160*91f16700Schasinglulu 	 * All the other peripheral which are configured by ARM TF are
161*91f16700Schasinglulu 	 * re-initialized on resume from system suspend. Hence we
162*91f16700Schasinglulu 	 * don't save their state here.
163*91f16700Schasinglulu 	 */
164*91f16700Schasinglulu }
165*91f16700Schasinglulu 
166*91f16700Schasinglulu /******************************************************************************
167*91f16700Schasinglulu  * Helper function to resume the platform from system suspend. Reinitialize
168*91f16700Schasinglulu  * the system components which are not in the Always ON power domain.
169*91f16700Schasinglulu  * TODO: Unify the platform setup when waking up from cold boot and system
170*91f16700Schasinglulu  * resume in arm_bl31_platform_setup().
171*91f16700Schasinglulu  *****************************************************************************/
172*91f16700Schasinglulu void arm_system_pwr_domain_resume(void)
173*91f16700Schasinglulu {
174*91f16700Schasinglulu 	/* Initialize the console */
175*91f16700Schasinglulu 	arm_console_runtime_init();
176*91f16700Schasinglulu 
177*91f16700Schasinglulu 	/* Assert system power domain is available on the platform */
178*91f16700Schasinglulu 	assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
179*91f16700Schasinglulu 
180*91f16700Schasinglulu 	plat_arm_gic_resume();
181*91f16700Schasinglulu 
182*91f16700Schasinglulu 	plat_arm_security_setup();
183*91f16700Schasinglulu 	arm_configure_sys_timer();
184*91f16700Schasinglulu }
185*91f16700Schasinglulu 
186*91f16700Schasinglulu /*******************************************************************************
187*91f16700Schasinglulu  * ARM platform function to program the mailbox for a cpu before it is released
188*91f16700Schasinglulu  * from reset. This function assumes that the Trusted mail box base is within
189*91f16700Schasinglulu  * the ARM_SHARED_RAM region
190*91f16700Schasinglulu  ******************************************************************************/
191*91f16700Schasinglulu void plat_arm_program_trusted_mailbox(uintptr_t address)
192*91f16700Schasinglulu {
193*91f16700Schasinglulu 	uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE;
194*91f16700Schasinglulu 
195*91f16700Schasinglulu 	*mailbox = address;
196*91f16700Schasinglulu 
197*91f16700Schasinglulu 	/*
198*91f16700Schasinglulu 	 * Ensure that the PLAT_ARM_TRUSTED_MAILBOX_BASE is within
199*91f16700Schasinglulu 	 * ARM_SHARED_RAM region.
200*91f16700Schasinglulu 	 */
201*91f16700Schasinglulu 	assert((PLAT_ARM_TRUSTED_MAILBOX_BASE >= ARM_SHARED_RAM_BASE) &&
202*91f16700Schasinglulu 		((PLAT_ARM_TRUSTED_MAILBOX_BASE + sizeof(*mailbox)) <=
203*91f16700Schasinglulu 				(ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE)));
204*91f16700Schasinglulu }
205*91f16700Schasinglulu 
206*91f16700Schasinglulu /*******************************************************************************
207*91f16700Schasinglulu  * The ARM Standard platform definition of platform porting API
208*91f16700Schasinglulu  * `plat_setup_psci_ops`.
209*91f16700Schasinglulu  ******************************************************************************/
210*91f16700Schasinglulu int __init plat_setup_psci_ops(uintptr_t sec_entrypoint,
211*91f16700Schasinglulu 				const plat_psci_ops_t **psci_ops)
212*91f16700Schasinglulu {
213*91f16700Schasinglulu 	*psci_ops = plat_arm_psci_override_pm_ops(&plat_arm_psci_pm_ops);
214*91f16700Schasinglulu 
215*91f16700Schasinglulu 	/* Setup mailbox with entry point. */
216*91f16700Schasinglulu 	plat_arm_program_trusted_mailbox(sec_entrypoint);
217*91f16700Schasinglulu 	return 0;
218*91f16700Schasinglulu }
219