xref: /rk3399_ARM-atf/plat/intel/soc/common/socfpga_psci.c (revision c76d42398990044ea84b6348d77a5f34bd7e9a8e)
1*c76d4239SHadi Asyrafi /*
2*c76d4239SHadi Asyrafi  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
3*c76d4239SHadi Asyrafi  *
4*c76d4239SHadi Asyrafi  * SPDX-License-Identifier: BSD-3-Clause
5*c76d4239SHadi Asyrafi  */
6*c76d4239SHadi Asyrafi 
7*c76d4239SHadi Asyrafi #include <arch_helpers.h>
8*c76d4239SHadi Asyrafi #include <common/debug.h>
9*c76d4239SHadi Asyrafi #include <drivers/arm/gicv2.h>
10*c76d4239SHadi Asyrafi #include <lib/mmio.h>
11*c76d4239SHadi Asyrafi #include <lib/psci/psci.h>
12*c76d4239SHadi Asyrafi #include <plat/common/platform.h>
13*c76d4239SHadi Asyrafi 
14*c76d4239SHadi Asyrafi #include "socfpga_mailbox.h"
15*c76d4239SHadi Asyrafi #include "socfpga_plat_def.h"
16*c76d4239SHadi Asyrafi 
17*c76d4239SHadi Asyrafi 
18*c76d4239SHadi Asyrafi uintptr_t *socfpga_sec_entry = (uintptr_t *) PLAT_SEC_ENTRY;
19*c76d4239SHadi Asyrafi uintptr_t *cpuid_release = (uintptr_t *) PLAT_CPUID_RELEASE;
20*c76d4239SHadi Asyrafi 
21*c76d4239SHadi Asyrafi /*******************************************************************************
22*c76d4239SHadi Asyrafi  * plat handler called when a CPU is about to enter standby.
23*c76d4239SHadi Asyrafi  ******************************************************************************/
24*c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state)
25*c76d4239SHadi Asyrafi {
26*c76d4239SHadi Asyrafi 	/*
27*c76d4239SHadi Asyrafi 	 * Enter standby state
28*c76d4239SHadi Asyrafi 	 * dsb is good practice before using wfi to enter low power states
29*c76d4239SHadi Asyrafi 	 */
30*c76d4239SHadi Asyrafi 	VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
31*c76d4239SHadi Asyrafi 	dsb();
32*c76d4239SHadi Asyrafi 	wfi();
33*c76d4239SHadi Asyrafi }
34*c76d4239SHadi Asyrafi 
35*c76d4239SHadi Asyrafi /*******************************************************************************
36*c76d4239SHadi Asyrafi  * plat handler called when a power domain is about to be turned on. The
37*c76d4239SHadi Asyrafi  * mpidr determines the CPU to be turned on.
38*c76d4239SHadi Asyrafi  ******************************************************************************/
39*c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr)
40*c76d4239SHadi Asyrafi {
41*c76d4239SHadi Asyrafi 	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
42*c76d4239SHadi Asyrafi 
43*c76d4239SHadi Asyrafi 	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
44*c76d4239SHadi Asyrafi 
45*c76d4239SHadi Asyrafi 	if (cpu_id == -1)
46*c76d4239SHadi Asyrafi 		return PSCI_E_INTERN_FAIL;
47*c76d4239SHadi Asyrafi 
48*c76d4239SHadi Asyrafi 	*cpuid_release = cpu_id;
49*c76d4239SHadi Asyrafi 
50*c76d4239SHadi Asyrafi 	/* release core reset */
51*c76d4239SHadi Asyrafi 	mmio_setbits_32(SOCFPGA_RSTMGR_MPUMODRST_OFST, 1 << cpu_id);
52*c76d4239SHadi Asyrafi 	return PSCI_E_SUCCESS;
53*c76d4239SHadi Asyrafi }
54*c76d4239SHadi Asyrafi 
55*c76d4239SHadi Asyrafi /*******************************************************************************
56*c76d4239SHadi Asyrafi  * plat handler called when a power domain is about to be turned off. The
57*c76d4239SHadi Asyrafi  * target_state encodes the power state that each level should transition to.
58*c76d4239SHadi Asyrafi  ******************************************************************************/
59*c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(const psci_power_state_t *target_state)
60*c76d4239SHadi Asyrafi {
61*c76d4239SHadi Asyrafi 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
62*c76d4239SHadi Asyrafi 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
63*c76d4239SHadi Asyrafi 			__func__, i, target_state->pwr_domain_state[i]);
64*c76d4239SHadi Asyrafi 
65*c76d4239SHadi Asyrafi 	/* Prevent interrupts from spuriously waking up this cpu */
66*c76d4239SHadi Asyrafi 	gicv2_cpuif_disable();
67*c76d4239SHadi Asyrafi }
68*c76d4239SHadi Asyrafi 
69*c76d4239SHadi Asyrafi /*******************************************************************************
70*c76d4239SHadi Asyrafi  * plat handler called when a power domain is about to be suspended. The
71*c76d4239SHadi Asyrafi  * target_state encodes the power state that each level should transition to.
72*c76d4239SHadi Asyrafi  ******************************************************************************/
73*c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state)
74*c76d4239SHadi Asyrafi {
75*c76d4239SHadi Asyrafi 	unsigned int cpu_id = plat_my_core_pos();
76*c76d4239SHadi Asyrafi 
77*c76d4239SHadi Asyrafi 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
78*c76d4239SHadi Asyrafi 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
79*c76d4239SHadi Asyrafi 			__func__, i, target_state->pwr_domain_state[i]);
80*c76d4239SHadi Asyrafi 	/* assert core reset */
81*c76d4239SHadi Asyrafi 	mmio_setbits_32(SOCFPGA_RSTMGR_MPUMODRST_OFST, 1 << cpu_id);
82*c76d4239SHadi Asyrafi 
83*c76d4239SHadi Asyrafi }
84*c76d4239SHadi Asyrafi 
85*c76d4239SHadi Asyrafi /*******************************************************************************
86*c76d4239SHadi Asyrafi  * plat handler called when a power domain has just been powered on after
87*c76d4239SHadi Asyrafi  * being turned off earlier. The target_state encodes the low power state that
88*c76d4239SHadi Asyrafi  * each level has woken up from.
89*c76d4239SHadi Asyrafi  ******************************************************************************/
90*c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state)
91*c76d4239SHadi Asyrafi {
92*c76d4239SHadi Asyrafi 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
93*c76d4239SHadi Asyrafi 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
94*c76d4239SHadi Asyrafi 			__func__, i, target_state->pwr_domain_state[i]);
95*c76d4239SHadi Asyrafi 
96*c76d4239SHadi Asyrafi 	/* Program the gic per-cpu distributor or re-distributor interface */
97*c76d4239SHadi Asyrafi 	gicv2_pcpu_distif_init();
98*c76d4239SHadi Asyrafi 	gicv2_set_pe_target_mask(plat_my_core_pos());
99*c76d4239SHadi Asyrafi 
100*c76d4239SHadi Asyrafi 	/* Enable the gic cpu interface */
101*c76d4239SHadi Asyrafi 	gicv2_cpuif_enable();
102*c76d4239SHadi Asyrafi }
103*c76d4239SHadi Asyrafi 
104*c76d4239SHadi Asyrafi /*******************************************************************************
105*c76d4239SHadi Asyrafi  * plat handler called when a power domain has just been powered on after
106*c76d4239SHadi Asyrafi  * having been suspended earlier. The target_state encodes the low power state
107*c76d4239SHadi Asyrafi  * that each level has woken up from.
108*c76d4239SHadi Asyrafi  * TODO: At the moment we reuse the on finisher and reinitialize the secure
109*c76d4239SHadi Asyrafi  * context. Need to implement a separate suspend finisher.
110*c76d4239SHadi Asyrafi  ******************************************************************************/
111*c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
112*c76d4239SHadi Asyrafi {
113*c76d4239SHadi Asyrafi 	unsigned int cpu_id = plat_my_core_pos();
114*c76d4239SHadi Asyrafi 
115*c76d4239SHadi Asyrafi 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
116*c76d4239SHadi Asyrafi 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
117*c76d4239SHadi Asyrafi 			__func__, i, target_state->pwr_domain_state[i]);
118*c76d4239SHadi Asyrafi 
119*c76d4239SHadi Asyrafi 	/* release core reset */
120*c76d4239SHadi Asyrafi 	mmio_clrbits_32(SOCFPGA_RSTMGR_MPUMODRST_OFST, 1 << cpu_id);
121*c76d4239SHadi Asyrafi }
122*c76d4239SHadi Asyrafi 
123*c76d4239SHadi Asyrafi /*******************************************************************************
124*c76d4239SHadi Asyrafi  * plat handlers to shutdown/reboot the system
125*c76d4239SHadi Asyrafi  ******************************************************************************/
126*c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void)
127*c76d4239SHadi Asyrafi {
128*c76d4239SHadi Asyrafi 	wfi();
129*c76d4239SHadi Asyrafi 	ERROR("System Off: operation not handled.\n");
130*c76d4239SHadi Asyrafi 	panic();
131*c76d4239SHadi Asyrafi }
132*c76d4239SHadi Asyrafi 
133*c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void)
134*c76d4239SHadi Asyrafi {
135*c76d4239SHadi Asyrafi 	mailbox_reset_cold();
136*c76d4239SHadi Asyrafi 
137*c76d4239SHadi Asyrafi 	while (1)
138*c76d4239SHadi Asyrafi 		wfi();
139*c76d4239SHadi Asyrafi }
140*c76d4239SHadi Asyrafi 
141*c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state,
142*c76d4239SHadi Asyrafi 				psci_power_state_t *req_state)
143*c76d4239SHadi Asyrafi {
144*c76d4239SHadi Asyrafi 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
145*c76d4239SHadi Asyrafi 
146*c76d4239SHadi Asyrafi 	return PSCI_E_SUCCESS;
147*c76d4239SHadi Asyrafi }
148*c76d4239SHadi Asyrafi 
149*c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint)
150*c76d4239SHadi Asyrafi {
151*c76d4239SHadi Asyrafi 	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
152*c76d4239SHadi Asyrafi 	return PSCI_E_SUCCESS;
153*c76d4239SHadi Asyrafi }
154*c76d4239SHadi Asyrafi 
155*c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state)
156*c76d4239SHadi Asyrafi {
157*c76d4239SHadi Asyrafi 	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
158*c76d4239SHadi Asyrafi 	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
159*c76d4239SHadi Asyrafi }
160*c76d4239SHadi Asyrafi 
161*c76d4239SHadi Asyrafi /*******************************************************************************
162*c76d4239SHadi Asyrafi  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
163*c76d4239SHadi Asyrafi  * platform layer will take care of registering the handlers with PSCI.
164*c76d4239SHadi Asyrafi  ******************************************************************************/
165*c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = {
166*c76d4239SHadi Asyrafi 	.cpu_standby = socfpga_cpu_standby,
167*c76d4239SHadi Asyrafi 	.pwr_domain_on = socfpga_pwr_domain_on,
168*c76d4239SHadi Asyrafi 	.pwr_domain_off = socfpga_pwr_domain_off,
169*c76d4239SHadi Asyrafi 	.pwr_domain_suspend = socfpga_pwr_domain_suspend,
170*c76d4239SHadi Asyrafi 	.pwr_domain_on_finish = socfpga_pwr_domain_on_finish,
171*c76d4239SHadi Asyrafi 	.pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish,
172*c76d4239SHadi Asyrafi 	.system_off = socfpga_system_off,
173*c76d4239SHadi Asyrafi 	.system_reset = socfpga_system_reset,
174*c76d4239SHadi Asyrafi 	.validate_power_state = socfpga_validate_power_state,
175*c76d4239SHadi Asyrafi 	.validate_ns_entrypoint = socfpga_validate_ns_entrypoint,
176*c76d4239SHadi Asyrafi 	.get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state
177*c76d4239SHadi Asyrafi };
178*c76d4239SHadi Asyrafi 
179*c76d4239SHadi Asyrafi /*******************************************************************************
180*c76d4239SHadi Asyrafi  * Export the platform specific power ops.
181*c76d4239SHadi Asyrafi  ******************************************************************************/
182*c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint,
183*c76d4239SHadi Asyrafi 			const struct plat_psci_ops **psci_ops)
184*c76d4239SHadi Asyrafi {
185*c76d4239SHadi Asyrafi 	/* Save warm boot entrypoint.*/
186*c76d4239SHadi Asyrafi 	*socfpga_sec_entry = sec_entrypoint;
187*c76d4239SHadi Asyrafi 
188*c76d4239SHadi Asyrafi 	*psci_ops = &socfpga_psci_pm_ops;
189*c76d4239SHadi Asyrafi 	return 0;
190*c76d4239SHadi Asyrafi }
191