xref: /arm-trusted-firmware/plat/xilinx/versal_net/plat_psci_pm.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
3*91f16700Schasinglulu  * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
4*91f16700Schasinglulu  *
5*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
6*91f16700Schasinglulu  */
7*91f16700Schasinglulu 
8*91f16700Schasinglulu #include <assert.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <common/debug.h>
11*91f16700Schasinglulu #include <lib/mmio.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 #include <plat_arm.h>
16*91f16700Schasinglulu 
17*91f16700Schasinglulu #include <plat_private.h>
18*91f16700Schasinglulu #include "pm_api_sys.h"
19*91f16700Schasinglulu #include "pm_client.h"
20*91f16700Schasinglulu #include <pm_common.h>
21*91f16700Schasinglulu #include "pm_svc_main.h"
22*91f16700Schasinglulu #include "versal_net_def.h"
23*91f16700Schasinglulu 
24*91f16700Schasinglulu static uintptr_t versal_net_sec_entry;
25*91f16700Schasinglulu 
26*91f16700Schasinglulu static int32_t versal_net_pwr_domain_on(u_register_t mpidr)
27*91f16700Schasinglulu {
28*91f16700Schasinglulu 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
29*91f16700Schasinglulu 	const struct pm_proc *proc;
30*91f16700Schasinglulu 
31*91f16700Schasinglulu 	VERBOSE("%s: mpidr: 0x%lx, cpuid: %x\n",
32*91f16700Schasinglulu 		__func__, mpidr, cpu_id);
33*91f16700Schasinglulu 
34*91f16700Schasinglulu 	if (cpu_id == -1) {
35*91f16700Schasinglulu 		return PSCI_E_INTERN_FAIL;
36*91f16700Schasinglulu 	}
37*91f16700Schasinglulu 
38*91f16700Schasinglulu 	proc = pm_get_proc(cpu_id);
39*91f16700Schasinglulu 	if (!proc) {
40*91f16700Schasinglulu 		return PSCI_E_INTERN_FAIL;
41*91f16700Schasinglulu 	}
42*91f16700Schasinglulu 
43*91f16700Schasinglulu 	pm_req_wakeup(proc->node_id, (versal_net_sec_entry & 0xFFFFFFFFU) | 0x1U,
44*91f16700Schasinglulu 		      versal_net_sec_entry >> 32, 0, 0);
45*91f16700Schasinglulu 
46*91f16700Schasinglulu 	/* Clear power down request */
47*91f16700Schasinglulu 	pm_client_wakeup(proc);
48*91f16700Schasinglulu 
49*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
50*91f16700Schasinglulu }
51*91f16700Schasinglulu 
52*91f16700Schasinglulu /**
53*91f16700Schasinglulu  * versal_net_pwr_domain_off() - This function performs actions to turn off
54*91f16700Schasinglulu  *                               core.
55*91f16700Schasinglulu  * @target_state: Targeted state.
56*91f16700Schasinglulu  *
57*91f16700Schasinglulu  */
58*91f16700Schasinglulu static void versal_net_pwr_domain_off(const psci_power_state_t *target_state)
59*91f16700Schasinglulu {
60*91f16700Schasinglulu 	uint32_t cpu_id = plat_my_core_pos();
61*91f16700Schasinglulu 	const struct pm_proc *proc = pm_get_proc(cpu_id);
62*91f16700Schasinglulu 
63*91f16700Schasinglulu 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
64*91f16700Schasinglulu 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
65*91f16700Schasinglulu 			__func__, i, target_state->pwr_domain_state[i]);
66*91f16700Schasinglulu 	}
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	/* Prevent interrupts from spuriously waking up this cpu */
69*91f16700Schasinglulu 	plat_versal_net_gic_cpuif_disable();
70*91f16700Schasinglulu 
71*91f16700Schasinglulu 	/*
72*91f16700Schasinglulu 	 * Send request to PMC to power down the appropriate APU CPU
73*91f16700Schasinglulu 	 * core.
74*91f16700Schasinglulu 	 * According to PSCI specification, CPU_off function does not
75*91f16700Schasinglulu 	 * have resume address and CPU core can only be woken up
76*91f16700Schasinglulu 	 * invoking CPU_on function, during which resume address will
77*91f16700Schasinglulu 	 * be set.
78*91f16700Schasinglulu 	 */
79*91f16700Schasinglulu 	pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0,
80*91f16700Schasinglulu 			SECURE_FLAG);
81*91f16700Schasinglulu }
82*91f16700Schasinglulu 
83*91f16700Schasinglulu /**
84*91f16700Schasinglulu  * versal_net_system_reset() - This function sends the reset request to firmware
85*91f16700Schasinglulu  *                             for the system to reset. This function does not
86*91f16700Schasinglulu  *                             return.
87*91f16700Schasinglulu  *
88*91f16700Schasinglulu  */
89*91f16700Schasinglulu static void __dead2 versal_net_system_reset(void)
90*91f16700Schasinglulu {
91*91f16700Schasinglulu 	/* Send the system reset request to the PMC */
92*91f16700Schasinglulu 	pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
93*91f16700Schasinglulu 			  pm_get_shutdown_scope(), SECURE_FLAG);
94*91f16700Schasinglulu 
95*91f16700Schasinglulu 	while (1) {
96*91f16700Schasinglulu 		wfi();
97*91f16700Schasinglulu 	}
98*91f16700Schasinglulu }
99*91f16700Schasinglulu 
100*91f16700Schasinglulu /**
101*91f16700Schasinglulu  * versal_net_pwr_domain_suspend() - This function sends request to PMC to suspend
102*91f16700Schasinglulu  *                                   core.
103*91f16700Schasinglulu  * @target_state: Targeted state.
104*91f16700Schasinglulu  *
105*91f16700Schasinglulu  */
106*91f16700Schasinglulu static void versal_net_pwr_domain_suspend(const psci_power_state_t *target_state)
107*91f16700Schasinglulu {
108*91f16700Schasinglulu 	uint32_t state;
109*91f16700Schasinglulu 	uint32_t cpu_id = plat_my_core_pos();
110*91f16700Schasinglulu 	const struct pm_proc *proc = pm_get_proc(cpu_id);
111*91f16700Schasinglulu 
112*91f16700Schasinglulu 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
113*91f16700Schasinglulu 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
114*91f16700Schasinglulu 			__func__, i, target_state->pwr_domain_state[i]);
115*91f16700Schasinglulu 	}
116*91f16700Schasinglulu 
117*91f16700Schasinglulu 	plat_versal_net_gic_cpuif_disable();
118*91f16700Schasinglulu 
119*91f16700Schasinglulu 	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
120*91f16700Schasinglulu 		plat_versal_net_gic_save();
121*91f16700Schasinglulu 	}
122*91f16700Schasinglulu 
123*91f16700Schasinglulu 	state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
124*91f16700Schasinglulu 		PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
125*91f16700Schasinglulu 
126*91f16700Schasinglulu 	/* Send request to PMC to suspend this core */
127*91f16700Schasinglulu 	pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_net_sec_entry,
128*91f16700Schasinglulu 			SECURE_FLAG);
129*91f16700Schasinglulu 
130*91f16700Schasinglulu 	/* TODO: disable coherency */
131*91f16700Schasinglulu }
132*91f16700Schasinglulu 
133*91f16700Schasinglulu static void versal_net_pwr_domain_on_finish(const psci_power_state_t *target_state)
134*91f16700Schasinglulu {
135*91f16700Schasinglulu 	(void)target_state;
136*91f16700Schasinglulu 
137*91f16700Schasinglulu 	/* Enable the gic cpu interface */
138*91f16700Schasinglulu 	plat_versal_net_gic_pcpu_init();
139*91f16700Schasinglulu 
140*91f16700Schasinglulu 	/* Program the gic per-cpu distributor or re-distributor interface */
141*91f16700Schasinglulu 	plat_versal_net_gic_cpuif_enable();
142*91f16700Schasinglulu }
143*91f16700Schasinglulu 
144*91f16700Schasinglulu /**
145*91f16700Schasinglulu  * versal_net_pwr_domain_suspend_finish() - This function performs actions to finish
146*91f16700Schasinglulu  *                                          suspend procedure.
147*91f16700Schasinglulu  * @target_state: Targeted state.
148*91f16700Schasinglulu  *
149*91f16700Schasinglulu  */
150*91f16700Schasinglulu static void versal_net_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
151*91f16700Schasinglulu {
152*91f16700Schasinglulu 	uint32_t cpu_id = plat_my_core_pos();
153*91f16700Schasinglulu 	const struct pm_proc *proc = pm_get_proc(cpu_id);
154*91f16700Schasinglulu 
155*91f16700Schasinglulu 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
156*91f16700Schasinglulu 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
157*91f16700Schasinglulu 			__func__, i, target_state->pwr_domain_state[i]);
158*91f16700Schasinglulu 
159*91f16700Schasinglulu 	/* Clear the APU power control register for this cpu */
160*91f16700Schasinglulu 	pm_client_wakeup(proc);
161*91f16700Schasinglulu 
162*91f16700Schasinglulu 	/* TODO: enable coherency */
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 	/* APU was turned off, so restore GIC context */
165*91f16700Schasinglulu 	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
166*91f16700Schasinglulu 		plat_versal_net_gic_resume();
167*91f16700Schasinglulu 	}
168*91f16700Schasinglulu 
169*91f16700Schasinglulu 	plat_versal_net_gic_cpuif_enable();
170*91f16700Schasinglulu }
171*91f16700Schasinglulu 
172*91f16700Schasinglulu /**
173*91f16700Schasinglulu  * versal_net_system_off() - This function sends the system off request
174*91f16700Schasinglulu  *                           to firmware. This function does not return.
175*91f16700Schasinglulu  *
176*91f16700Schasinglulu  */
177*91f16700Schasinglulu static void __dead2 versal_net_system_off(void)
178*91f16700Schasinglulu {
179*91f16700Schasinglulu 	/* Send the power down request to the PMC */
180*91f16700Schasinglulu 	pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
181*91f16700Schasinglulu 			  pm_get_shutdown_scope(), SECURE_FLAG);
182*91f16700Schasinglulu 
183*91f16700Schasinglulu 	while (1) {
184*91f16700Schasinglulu 		wfi();
185*91f16700Schasinglulu 	}
186*91f16700Schasinglulu }
187*91f16700Schasinglulu 
188*91f16700Schasinglulu /**
189*91f16700Schasinglulu  * versal_net_validate_power_state() - This function ensures that the power state
190*91f16700Schasinglulu  *                                     parameter in request is valid.
191*91f16700Schasinglulu  * @power_state: Power state of core.
192*91f16700Schasinglulu  * @req_state: Requested state.
193*91f16700Schasinglulu  *
194*91f16700Schasinglulu  * Return: Returns status, either PSCI_E_SUCCESS or reason.
195*91f16700Schasinglulu  *
196*91f16700Schasinglulu  */
197*91f16700Schasinglulu static int32_t versal_net_validate_power_state(unsigned int power_state,
198*91f16700Schasinglulu 					       psci_power_state_t *req_state)
199*91f16700Schasinglulu {
200*91f16700Schasinglulu 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
201*91f16700Schasinglulu 
202*91f16700Schasinglulu 	int32_t pstate = psci_get_pstate_type(power_state);
203*91f16700Schasinglulu 
204*91f16700Schasinglulu 	assert(req_state);
205*91f16700Schasinglulu 
206*91f16700Schasinglulu 	/* Sanity check the requested state */
207*91f16700Schasinglulu 	if (pstate == PSTATE_TYPE_STANDBY) {
208*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
209*91f16700Schasinglulu 	} else {
210*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
211*91f16700Schasinglulu 	}
212*91f16700Schasinglulu 
213*91f16700Schasinglulu 	/* We expect the 'state id' to be zero */
214*91f16700Schasinglulu 	if (psci_get_pstate_id(power_state)) {
215*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
216*91f16700Schasinglulu 	}
217*91f16700Schasinglulu 
218*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
219*91f16700Schasinglulu }
220*91f16700Schasinglulu 
221*91f16700Schasinglulu /**
222*91f16700Schasinglulu  * versal_net_get_sys_suspend_power_state() - Get power state for system
223*91f16700Schasinglulu  *                                            suspend.
224*91f16700Schasinglulu  * @req_state: Requested state.
225*91f16700Schasinglulu  *
226*91f16700Schasinglulu  */
227*91f16700Schasinglulu static void versal_net_get_sys_suspend_power_state(psci_power_state_t *req_state)
228*91f16700Schasinglulu {
229*91f16700Schasinglulu 	uint64_t i;
230*91f16700Schasinglulu 
231*91f16700Schasinglulu 	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
232*91f16700Schasinglulu 		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
233*91f16700Schasinglulu }
234*91f16700Schasinglulu 
235*91f16700Schasinglulu static const struct plat_psci_ops versal_net_nopmc_psci_ops = {
236*91f16700Schasinglulu 	.pwr_domain_on                  = versal_net_pwr_domain_on,
237*91f16700Schasinglulu 	.pwr_domain_off                 = versal_net_pwr_domain_off,
238*91f16700Schasinglulu 	.pwr_domain_on_finish           = versal_net_pwr_domain_on_finish,
239*91f16700Schasinglulu 	.pwr_domain_suspend             = versal_net_pwr_domain_suspend,
240*91f16700Schasinglulu 	.pwr_domain_suspend_finish      = versal_net_pwr_domain_suspend_finish,
241*91f16700Schasinglulu 	.system_off                     = versal_net_system_off,
242*91f16700Schasinglulu 	.system_reset                   = versal_net_system_reset,
243*91f16700Schasinglulu 	.validate_power_state           = versal_net_validate_power_state,
244*91f16700Schasinglulu 	.get_sys_suspend_power_state    = versal_net_get_sys_suspend_power_state,
245*91f16700Schasinglulu };
246*91f16700Schasinglulu 
247*91f16700Schasinglulu /*******************************************************************************
248*91f16700Schasinglulu  * Export the platform specific power ops.
249*91f16700Schasinglulu  ******************************************************************************/
250*91f16700Schasinglulu int32_t plat_setup_psci_ops(uintptr_t sec_entrypoint,
251*91f16700Schasinglulu 			    const struct plat_psci_ops **psci_ops)
252*91f16700Schasinglulu {
253*91f16700Schasinglulu 	versal_net_sec_entry = sec_entrypoint;
254*91f16700Schasinglulu 
255*91f16700Schasinglulu 	VERBOSE("Setting up entry point %lx\n", versal_net_sec_entry);
256*91f16700Schasinglulu 
257*91f16700Schasinglulu 	*psci_ops = &versal_net_nopmc_psci_ops;
258*91f16700Schasinglulu 
259*91f16700Schasinglulu 	return 0;
260*91f16700Schasinglulu }
261*91f16700Schasinglulu 
262*91f16700Schasinglulu int32_t sip_svc_setup_init(void)
263*91f16700Schasinglulu {
264*91f16700Schasinglulu 	return pm_setup();
265*91f16700Schasinglulu }
266*91f16700Schasinglulu 
267*91f16700Schasinglulu uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
268*91f16700Schasinglulu 		     void *cookie, void *handle, uint64_t flags)
269*91f16700Schasinglulu {
270*91f16700Schasinglulu 	return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
271*91f16700Schasinglulu }
272