xref: /rk3399_ARM-atf/plat/intel/soc/common/socfpga_psci.c (revision 7f7a16a6c0a49af593fa080eb66f72a20bb07299)
1 /*
2  * Copyright (c) 2019-2022, 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 #include "socfpga_system_manager.h"
18 #include "socfpga_sip_svc.h"
19 
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 	uint32_t psci_boot = 0x00;
43 
44 	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
45 
46 	if (cpu_id == -1)
47 		return PSCI_E_INTERN_FAIL;
48 
49 	if (cpu_id == 0x00) {
50 		psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8));
51 		psci_boot |= 0x20000; /* bit 17 */
52 		mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot);
53 	}
54 
55 	mmio_write_64(PLAT_CPUID_RELEASE, cpu_id);
56 
57 	/* release core reset */
58 	mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
59 	return PSCI_E_SUCCESS;
60 }
61 
62 /*******************************************************************************
63  * plat handler called when a power domain is about to be turned off. The
64  * target_state encodes the power state that each level should transition to.
65  ******************************************************************************/
66 void socfpga_pwr_domain_off(const psci_power_state_t *target_state)
67 {
68 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
69 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
70 			__func__, i, target_state->pwr_domain_state[i]);
71 
72 	/* Prevent interrupts from spuriously waking up this cpu */
73 	gicv2_cpuif_disable();
74 }
75 
76 /*******************************************************************************
77  * plat handler called when a power domain is about to be suspended. The
78  * target_state encodes the power state that each level should transition to.
79  ******************************************************************************/
80 void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state)
81 {
82 	unsigned int cpu_id = plat_my_core_pos();
83 
84 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
85 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
86 			__func__, i, target_state->pwr_domain_state[i]);
87 
88 	/* assert core reset */
89 	mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
90 
91 }
92 
93 /*******************************************************************************
94  * plat handler called when a power domain has just been powered on after
95  * being turned off earlier. The target_state encodes the low power state that
96  * each level has woken up from.
97  ******************************************************************************/
98 void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state)
99 {
100 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
101 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
102 			__func__, i, target_state->pwr_domain_state[i]);
103 
104 	/* Program the gic per-cpu distributor or re-distributor interface */
105 	gicv2_pcpu_distif_init();
106 	gicv2_set_pe_target_mask(plat_my_core_pos());
107 
108 	/* Enable the gic cpu interface */
109 	gicv2_cpuif_enable();
110 }
111 
112 /*******************************************************************************
113  * plat handler called when a power domain has just been powered on after
114  * having been suspended earlier. The target_state encodes the low power state
115  * that each level has woken up from.
116  * TODO: At the moment we reuse the on finisher and reinitialize the secure
117  * context. Need to implement a separate suspend finisher.
118  ******************************************************************************/
119 void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
120 {
121 	unsigned int cpu_id = plat_my_core_pos();
122 
123 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
124 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
125 			__func__, i, target_state->pwr_domain_state[i]);
126 
127 	/* release core reset */
128 	mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
129 }
130 
131 /*******************************************************************************
132  * plat handlers to shutdown/reboot the system
133  ******************************************************************************/
134 static void __dead2 socfpga_system_off(void)
135 {
136 	wfi();
137 	ERROR("System Off: operation not handled.\n");
138 	panic();
139 }
140 
141 extern uint64_t intel_rsu_update_address;
142 
143 static void __dead2 socfpga_system_reset(void)
144 {
145 	uint32_t addr_buf[2];
146 
147 	memcpy(addr_buf, &intel_rsu_update_address,
148 			sizeof(intel_rsu_update_address));
149 
150 	if (intel_rsu_update_address)
151 		mailbox_rsu_update(addr_buf);
152 	else
153 		mailbox_reset_cold();
154 
155 	while (1)
156 		wfi();
157 }
158 
159 static int socfpga_system_reset2(int is_vendor, int reset_type,
160 					u_register_t cookie)
161 {
162 	if (cold_reset_for_ecc_dbe()) {
163 		mailbox_reset_cold();
164 	}
165 	/* disable cpuif */
166 	gicv2_cpuif_disable();
167 
168 	/* Store magic number */
169 	mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS);
170 
171 	/* Increase timeout */
172 	mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff);
173 
174 	/* Enable handshakes */
175 	mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET);
176 
177 	/* Reset L2 module */
178 	mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100);
179 
180 	while (1)
181 		wfi();
182 
183 	/* Should not reach here */
184 	return 0;
185 }
186 
187 int socfpga_validate_power_state(unsigned int power_state,
188 				psci_power_state_t *req_state)
189 {
190 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
191 
192 	return PSCI_E_SUCCESS;
193 }
194 
195 int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint)
196 {
197 	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
198 	return PSCI_E_SUCCESS;
199 }
200 
201 void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state)
202 {
203 	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
204 	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
205 }
206 
207 /*******************************************************************************
208  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
209  * platform layer will take care of registering the handlers with PSCI.
210  ******************************************************************************/
211 const plat_psci_ops_t socfpga_psci_pm_ops = {
212 	.cpu_standby = socfpga_cpu_standby,
213 	.pwr_domain_on = socfpga_pwr_domain_on,
214 	.pwr_domain_off = socfpga_pwr_domain_off,
215 	.pwr_domain_suspend = socfpga_pwr_domain_suspend,
216 	.pwr_domain_on_finish = socfpga_pwr_domain_on_finish,
217 	.pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish,
218 	.system_off = socfpga_system_off,
219 	.system_reset = socfpga_system_reset,
220 	.system_reset2 = socfpga_system_reset2,
221 	.validate_power_state = socfpga_validate_power_state,
222 	.validate_ns_entrypoint = socfpga_validate_ns_entrypoint,
223 	.get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state
224 };
225 
226 /*******************************************************************************
227  * Export the platform specific power ops.
228  ******************************************************************************/
229 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
230 			const struct plat_psci_ops **psci_ops)
231 {
232 	/* Save warm boot entrypoint.*/
233 	mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint);
234 	*psci_ops = &socfpga_psci_pm_ops;
235 
236 	return 0;
237 }
238