xref: /rk3399_ARM-atf/plat/intel/soc/common/socfpga_psci.c (revision 391eeeef7f90c8b53ca0f63637b3d5d4e53af35b)
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 #include "socfpga_reset_manager.h"
17 
18 
19 
20 /*******************************************************************************
21  * plat handler called when a CPU is about to enter standby.
22  ******************************************************************************/
23 void socfpga_cpu_standby(plat_local_state_t cpu_state)
24 {
25 	/*
26 	 * Enter standby state
27 	 * dsb is good practice before using wfi to enter low power states
28 	 */
29 	VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
30 	dsb();
31 	wfi();
32 }
33 
34 /*******************************************************************************
35  * plat handler called when a power domain is about to be turned on. The
36  * mpidr determines the CPU to be turned on.
37  ******************************************************************************/
38 int socfpga_pwr_domain_on(u_register_t mpidr)
39 {
40 	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
41 
42 	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
43 
44 	if (cpu_id == -1)
45 		return PSCI_E_INTERN_FAIL;
46 
47 	mmio_write_64(PLAT_CPUID_RELEASE, cpu_id);
48 
49 	/* release core reset */
50 	mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
51 	return PSCI_E_SUCCESS;
52 }
53 
54 /*******************************************************************************
55  * plat handler called when a power domain is about to be turned off. The
56  * target_state encodes the power state that each level should transition to.
57  ******************************************************************************/
58 void socfpga_pwr_domain_off(const psci_power_state_t *target_state)
59 {
60 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
61 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
62 			__func__, i, target_state->pwr_domain_state[i]);
63 
64 	/* Prevent interrupts from spuriously waking up this cpu */
65 	gicv2_cpuif_disable();
66 }
67 
68 /*******************************************************************************
69  * plat handler called when a power domain is about to be suspended. The
70  * target_state encodes the power state that each level should transition to.
71  ******************************************************************************/
72 void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state)
73 {
74 	unsigned int cpu_id = plat_my_core_pos();
75 
76 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
77 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
78 			__func__, i, target_state->pwr_domain_state[i]);
79 
80 	/* assert core reset */
81 	mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 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), 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 static int socfpga_system_reset2(int is_vendor, int reset_type,
142 					u_register_t cookie)
143 {
144 	/* disable cpuif */
145 	gicv2_cpuif_disable();
146 
147 	/* Store magic number */
148 	mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS);
149 
150 	/* Increase timeout */
151 	mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff);
152 
153 	/* Enable handshakes */
154 	mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET);
155 
156 	/* Reset L2 module */
157 	mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100);
158 
159 	while (1)
160 		wfi();
161 
162 	/* Should not reach here */
163 	return 0;
164 }
165 
166 int socfpga_validate_power_state(unsigned int power_state,
167 				psci_power_state_t *req_state)
168 {
169 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
170 
171 	return PSCI_E_SUCCESS;
172 }
173 
174 int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint)
175 {
176 	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
177 	return PSCI_E_SUCCESS;
178 }
179 
180 void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state)
181 {
182 	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
183 	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
184 }
185 
186 /*******************************************************************************
187  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
188  * platform layer will take care of registering the handlers with PSCI.
189  ******************************************************************************/
190 const plat_psci_ops_t socfpga_psci_pm_ops = {
191 	.cpu_standby = socfpga_cpu_standby,
192 	.pwr_domain_on = socfpga_pwr_domain_on,
193 	.pwr_domain_off = socfpga_pwr_domain_off,
194 	.pwr_domain_suspend = socfpga_pwr_domain_suspend,
195 	.pwr_domain_on_finish = socfpga_pwr_domain_on_finish,
196 	.pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish,
197 	.system_off = socfpga_system_off,
198 	.system_reset = socfpga_system_reset,
199 	.system_reset2 = socfpga_system_reset2,
200 	.validate_power_state = socfpga_validate_power_state,
201 	.validate_ns_entrypoint = socfpga_validate_ns_entrypoint,
202 	.get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state
203 };
204 
205 /*******************************************************************************
206  * Export the platform specific power ops.
207  ******************************************************************************/
208 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
209 			const struct plat_psci_ops **psci_ops)
210 {
211 	/* Save warm boot entrypoint.*/
212 	mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint);
213 	*psci_ops = &socfpga_psci_pm_ops;
214 
215 	return 0;
216 }
217