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