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