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