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