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