xref: /rk3399_ARM-atf/plat/intel/soc/common/socfpga_psci.c (revision d6b44b10e9e975f4785cfcadf70737efe0b14e4b)
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 extern uint64_t intel_rsu_update_address;
134 
135 static void __dead2 socfpga_system_reset(void)
136 {
137 	if (intel_rsu_update_address)
138 		mailbox_rsu_update((uint32_t *)&intel_rsu_update_address);
139 	else
140 		mailbox_reset_cold();
141 
142 	while (1)
143 		wfi();
144 }
145 
146 static int socfpga_system_reset2(int is_vendor, int reset_type,
147 					u_register_t cookie)
148 {
149 	/* disable cpuif */
150 	gicv2_cpuif_disable();
151 
152 	/* Store magic number */
153 	mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS);
154 
155 	/* Increase timeout */
156 	mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff);
157 
158 	/* Enable handshakes */
159 	mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET);
160 
161 	/* Reset L2 module */
162 	mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100);
163 
164 	while (1)
165 		wfi();
166 
167 	/* Should not reach here */
168 	return 0;
169 }
170 
171 int socfpga_validate_power_state(unsigned int power_state,
172 				psci_power_state_t *req_state)
173 {
174 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
175 
176 	return PSCI_E_SUCCESS;
177 }
178 
179 int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint)
180 {
181 	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
182 	return PSCI_E_SUCCESS;
183 }
184 
185 void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state)
186 {
187 	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
188 	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
189 }
190 
191 /*******************************************************************************
192  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
193  * platform layer will take care of registering the handlers with PSCI.
194  ******************************************************************************/
195 const plat_psci_ops_t socfpga_psci_pm_ops = {
196 	.cpu_standby = socfpga_cpu_standby,
197 	.pwr_domain_on = socfpga_pwr_domain_on,
198 	.pwr_domain_off = socfpga_pwr_domain_off,
199 	.pwr_domain_suspend = socfpga_pwr_domain_suspend,
200 	.pwr_domain_on_finish = socfpga_pwr_domain_on_finish,
201 	.pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish,
202 	.system_off = socfpga_system_off,
203 	.system_reset = socfpga_system_reset,
204 	.system_reset2 = socfpga_system_reset2,
205 	.validate_power_state = socfpga_validate_power_state,
206 	.validate_ns_entrypoint = socfpga_validate_ns_entrypoint,
207 	.get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state
208 };
209 
210 /*******************************************************************************
211  * Export the platform specific power ops.
212  ******************************************************************************/
213 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
214 			const struct plat_psci_ops **psci_ops)
215 {
216 	/* Save warm boot entrypoint.*/
217 	mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint);
218 	*psci_ops = &socfpga_psci_pm_ops;
219 
220 	return 0;
221 }
222