xref: /rk3399_ARM-atf/plat/intel/soc/common/socfpga_psci.c (revision 7ac7dadb551ee602299aef91043dc4adbd234a3e)
1c76d4239SHadi Asyrafi /*
26197dc98SJit Loon Lim  * Copyright (c) 2019-2023, ARM Limited and Contributors. All rights reserved.
379626f46SJit Loon Lim  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
4e264b557SSieu Mun Tang  * Copyright (c) 2024, Altera Corporation. All rights reserved.
5c76d4239SHadi Asyrafi  *
6c76d4239SHadi Asyrafi  * SPDX-License-Identifier: BSD-3-Clause
7c76d4239SHadi Asyrafi  */
8c76d4239SHadi Asyrafi 
9c76d4239SHadi Asyrafi #include <arch_helpers.h>
10c76d4239SHadi Asyrafi #include <common/debug.h>
1179626f46SJit Loon Lim 
1279626f46SJit Loon Lim #ifndef GICV3_SUPPORT_GIC600
13c76d4239SHadi Asyrafi #include <drivers/arm/gicv2.h>
146197dc98SJit Loon Lim #else
156197dc98SJit Loon Lim #include <drivers/arm/gicv3.h>
166197dc98SJit Loon Lim #endif
17c76d4239SHadi Asyrafi #include <lib/mmio.h>
18c76d4239SHadi Asyrafi #include <lib/psci/psci.h>
19c76d4239SHadi Asyrafi #include <plat/common/platform.h>
20*7ac7dadbSSieu Mun Tang #include "ccu/ncore_ccu.h"
21c76d4239SHadi Asyrafi #include "socfpga_mailbox.h"
22c76d4239SHadi Asyrafi #include "socfpga_plat_def.h"
23*7ac7dadbSSieu Mun Tang #include "socfpga_private.h"
2432cf34acSHadi Asyrafi #include "socfpga_reset_manager.h"
25c703d752SSieu Mun Tang #include "socfpga_sip_svc.h"
266197dc98SJit Loon Lim #include "socfpga_system_manager.h"
27c76d4239SHadi Asyrafi 
2879626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
2979626f46SJit Loon Lim void socfpga_wakeup_secondary_cpu(unsigned int cpu_id);
3079626f46SJit Loon Lim extern void plat_secondary_cold_boot_setup(void);
3179626f46SJit Loon Lim #endif
32c76d4239SHadi Asyrafi 
33c76d4239SHadi Asyrafi /*******************************************************************************
34c76d4239SHadi Asyrafi  * plat handler called when a CPU is about to enter standby.
35c76d4239SHadi Asyrafi  ******************************************************************************/
36c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state)
37c76d4239SHadi Asyrafi {
38c76d4239SHadi Asyrafi 	/*
39c76d4239SHadi Asyrafi 	 * Enter standby state
40c76d4239SHadi Asyrafi 	 * dsb is good practice before using wfi to enter low power states
41c76d4239SHadi Asyrafi 	 */
42c76d4239SHadi Asyrafi 	VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
43c76d4239SHadi Asyrafi 	dsb();
44c76d4239SHadi Asyrafi 	wfi();
45c76d4239SHadi Asyrafi }
46c76d4239SHadi Asyrafi 
47c76d4239SHadi Asyrafi /*******************************************************************************
48c76d4239SHadi Asyrafi  * plat handler called when a power domain is about to be turned on. The
49c76d4239SHadi Asyrafi  * mpidr determines the CPU to be turned on.
50c76d4239SHadi Asyrafi  ******************************************************************************/
51c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr)
52c76d4239SHadi Asyrafi {
53c76d4239SHadi Asyrafi 	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
5479626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
5579626f46SJit Loon Lim 	/* TODO: Add in CPU FUSE from SDM */
5679626f46SJit Loon Lim #else
577f7a16a6SJit Loon Lim 	uint32_t psci_boot = 0x00;
58c76d4239SHadi Asyrafi 
59c76d4239SHadi Asyrafi 	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
6079626f46SJit Loon Lim #endif
61c76d4239SHadi Asyrafi 
62c76d4239SHadi Asyrafi 	if (cpu_id == -1)
63c76d4239SHadi Asyrafi 		return PSCI_E_INTERN_FAIL;
64c76d4239SHadi Asyrafi 
6579626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
667f7a16a6SJit Loon Lim 	if (cpu_id == 0x00) {
677f7a16a6SJit Loon Lim 		psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8));
68655af4f4SJit Loon Lim 		psci_boot |= 0x80000; /* bit 19 */
697f7a16a6SJit Loon Lim 		mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot);
707f7a16a6SJit Loon Lim 	}
717f7a16a6SJit Loon Lim 
72cf82aff0SHadi Asyrafi 	mmio_write_64(PLAT_CPUID_RELEASE, cpu_id);
7379626f46SJit Loon Lim #endif
74c76d4239SHadi Asyrafi 
75c76d4239SHadi Asyrafi 	/* release core reset */
7679626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
7779626f46SJit Loon Lim 	bl31_plat_set_secondary_cpu_entrypoint(cpu_id);
7879626f46SJit Loon Lim #else
79391eeeefSHadi Asyrafi 	mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
8079626f46SJit Loon Lim 	mmio_write_64(PLAT_CPUID_RELEASE, cpu_id);
8179626f46SJit Loon Lim #endif
8279626f46SJit Loon Lim 
83c76d4239SHadi Asyrafi 	return PSCI_E_SUCCESS;
84c76d4239SHadi Asyrafi }
85c76d4239SHadi Asyrafi 
86c76d4239SHadi Asyrafi /*******************************************************************************
87c76d4239SHadi Asyrafi  * plat handler called when a power domain is about to be turned off. The
88c76d4239SHadi Asyrafi  * target_state encodes the power state that each level should transition to.
89c76d4239SHadi Asyrafi  ******************************************************************************/
90c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(const psci_power_state_t *target_state)
91c76d4239SHadi Asyrafi {
92c76d4239SHadi Asyrafi 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
93c76d4239SHadi Asyrafi 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
94c76d4239SHadi Asyrafi 			__func__, i, target_state->pwr_domain_state[i]);
95c76d4239SHadi Asyrafi 
96c76d4239SHadi Asyrafi 	/* Prevent interrupts from spuriously waking up this cpu */
9779626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600
9879626f46SJit Loon Lim 	gicv3_cpuif_disable(plat_my_core_pos());
9979626f46SJit Loon Lim #else
100c76d4239SHadi Asyrafi 	gicv2_cpuif_disable();
10179626f46SJit Loon Lim #endif
10279626f46SJit Loon Lim 
103c76d4239SHadi Asyrafi }
104c76d4239SHadi Asyrafi 
105c76d4239SHadi Asyrafi /*******************************************************************************
106c76d4239SHadi Asyrafi  * plat handler called when a power domain is about to be suspended. The
107c76d4239SHadi Asyrafi  * target_state encodes the power state that each level should transition to.
108c76d4239SHadi Asyrafi  ******************************************************************************/
109c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state)
110c76d4239SHadi Asyrafi {
11179626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
112c76d4239SHadi Asyrafi 	unsigned int cpu_id = plat_my_core_pos();
11379626f46SJit Loon Lim #endif
114c76d4239SHadi Asyrafi 
115c76d4239SHadi Asyrafi 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
116c76d4239SHadi Asyrafi 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
117c76d4239SHadi Asyrafi 			__func__, i, target_state->pwr_domain_state[i]);
11832cf34acSHadi Asyrafi 
11979626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
120c76d4239SHadi Asyrafi 	/* assert core reset */
121391eeeefSHadi Asyrafi 	mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
12279626f46SJit Loon Lim #endif
123c76d4239SHadi Asyrafi }
124c76d4239SHadi Asyrafi 
125c76d4239SHadi Asyrafi /*******************************************************************************
126c76d4239SHadi Asyrafi  * plat handler called when a power domain has just been powered on after
127c76d4239SHadi Asyrafi  * being turned off earlier. The target_state encodes the low power state that
128c76d4239SHadi Asyrafi  * each level has woken up from.
129c76d4239SHadi Asyrafi  ******************************************************************************/
130c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state)
131c76d4239SHadi Asyrafi {
132c76d4239SHadi Asyrafi 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
133c76d4239SHadi Asyrafi 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
134c76d4239SHadi Asyrafi 			__func__, i, target_state->pwr_domain_state[i]);
135c76d4239SHadi Asyrafi 
13679626f46SJit Loon Lim 	/* Enable the gic cpu interface */
13779626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600
13879626f46SJit Loon Lim 	gicv3_rdistif_init(plat_my_core_pos());
13979626f46SJit Loon Lim 	gicv3_cpuif_enable(plat_my_core_pos());
14079626f46SJit Loon Lim #else
141c76d4239SHadi Asyrafi 	/* Program the gic per-cpu distributor or re-distributor interface */
142c76d4239SHadi Asyrafi 	gicv2_pcpu_distif_init();
143c76d4239SHadi Asyrafi 	gicv2_set_pe_target_mask(plat_my_core_pos());
144c76d4239SHadi Asyrafi 
145c76d4239SHadi Asyrafi 	/* Enable the gic cpu interface */
146c76d4239SHadi Asyrafi 	gicv2_cpuif_enable();
14779626f46SJit Loon Lim #endif
148c76d4239SHadi Asyrafi }
149c76d4239SHadi Asyrafi 
150c76d4239SHadi Asyrafi /*******************************************************************************
151c76d4239SHadi Asyrafi  * plat handler called when a power domain has just been powered on after
152c76d4239SHadi Asyrafi  * having been suspended earlier. The target_state encodes the low power state
153c76d4239SHadi Asyrafi  * that each level has woken up from.
154c76d4239SHadi Asyrafi  * TODO: At the moment we reuse the on finisher and reinitialize the secure
155c76d4239SHadi Asyrafi  * context. Need to implement a separate suspend finisher.
156c76d4239SHadi Asyrafi  ******************************************************************************/
157c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
158c76d4239SHadi Asyrafi {
15979626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
160c76d4239SHadi Asyrafi 	unsigned int cpu_id = plat_my_core_pos();
16179626f46SJit Loon Lim #endif
162c76d4239SHadi Asyrafi 
163c76d4239SHadi Asyrafi 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
164c76d4239SHadi Asyrafi 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
165c76d4239SHadi Asyrafi 			__func__, i, target_state->pwr_domain_state[i]);
166c76d4239SHadi Asyrafi 
16779626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
168c76d4239SHadi Asyrafi 	/* release core reset */
169391eeeefSHadi Asyrafi 	mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id);
17079626f46SJit Loon Lim #endif
171c76d4239SHadi Asyrafi }
172c76d4239SHadi Asyrafi 
173c76d4239SHadi Asyrafi /*******************************************************************************
174c76d4239SHadi Asyrafi  * plat handlers to shutdown/reboot the system
175c76d4239SHadi Asyrafi  ******************************************************************************/
176c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void)
177c76d4239SHadi Asyrafi {
178c76d4239SHadi Asyrafi 	wfi();
179c76d4239SHadi Asyrafi 	ERROR("System Off: operation not handled.\n");
180c76d4239SHadi Asyrafi 	panic();
181c76d4239SHadi Asyrafi }
182c76d4239SHadi Asyrafi 
183e1f97d9cSHadi Asyrafi extern uint64_t intel_rsu_update_address;
184e1f97d9cSHadi Asyrafi 
185c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void)
186c76d4239SHadi Asyrafi {
187ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 	uint32_t addr_buf[2];
188ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 
189e264b557SSieu Mun Tang 	memcpy_s(addr_buf, sizeof(intel_rsu_update_address),
190e264b557SSieu Mun Tang 		&intel_rsu_update_address, sizeof(intel_rsu_update_address));
191e264b557SSieu Mun Tang 
1926197dc98SJit Loon Lim 	if (intel_rsu_update_address) {
193ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 		mailbox_rsu_update(addr_buf);
1946197dc98SJit Loon Lim 	} else {
195*7ac7dadbSSieu Mun Tang #if CACHE_FLUSH
196*7ac7dadbSSieu Mun Tang 		/* ATF Flush and Invalidate Cache */
197*7ac7dadbSSieu Mun Tang 		dcsw_op_all(DCCISW);
198*7ac7dadbSSieu Mun Tang 		invalidate_cache_low_el();
199*7ac7dadbSSieu Mun Tang #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
200*7ac7dadbSSieu Mun Tang 		flush_l3_dcache();
201*7ac7dadbSSieu Mun Tang #endif
202*7ac7dadbSSieu Mun Tang #endif
203c76d4239SHadi Asyrafi 		mailbox_reset_cold();
2046197dc98SJit Loon Lim 	}
205c76d4239SHadi Asyrafi 
206c76d4239SHadi Asyrafi 	while (1)
207c76d4239SHadi Asyrafi 		wfi();
208c76d4239SHadi Asyrafi }
209c76d4239SHadi Asyrafi 
21032cf34acSHadi Asyrafi static int socfpga_system_reset2(int is_vendor, int reset_type,
21132cf34acSHadi Asyrafi 					u_register_t cookie)
21232cf34acSHadi Asyrafi {
21379626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
21479626f46SJit Loon Lim 	mailbox_reset_warm(reset_type);
21579626f46SJit Loon Lim #else
216c703d752SSieu Mun Tang 	if (cold_reset_for_ecc_dbe()) {
217c703d752SSieu Mun Tang 		mailbox_reset_cold();
218c703d752SSieu Mun Tang 	}
21979626f46SJit Loon Lim #endif
22079626f46SJit Loon Lim 
22132cf34acSHadi Asyrafi 	/* disable cpuif */
22279626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600
22379626f46SJit Loon Lim 	gicv3_cpuif_disable(plat_my_core_pos());
22479626f46SJit Loon Lim #else
22532cf34acSHadi Asyrafi 	gicv2_cpuif_disable();
22679626f46SJit Loon Lim #endif
22732cf34acSHadi Asyrafi 
22832cf34acSHadi Asyrafi 	/* Store magic number */
22932cf34acSHadi Asyrafi 	mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS);
23032cf34acSHadi Asyrafi 
23132cf34acSHadi Asyrafi 	/* Increase timeout */
232391eeeefSHadi Asyrafi 	mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff);
23332cf34acSHadi Asyrafi 
23432cf34acSHadi Asyrafi 	/* Enable handshakes */
235391eeeefSHadi Asyrafi 	mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET);
23632cf34acSHadi Asyrafi 
23779626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
23832cf34acSHadi Asyrafi 	/* Reset L2 module */
239391eeeefSHadi Asyrafi 	mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100);
24079626f46SJit Loon Lim #endif
24132cf34acSHadi Asyrafi 
24232cf34acSHadi Asyrafi 	while (1)
24332cf34acSHadi Asyrafi 		wfi();
24432cf34acSHadi Asyrafi 
24532cf34acSHadi Asyrafi 	/* Should not reach here */
24632cf34acSHadi Asyrafi 	return 0;
24732cf34acSHadi Asyrafi }
24832cf34acSHadi Asyrafi 
249c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state,
250c76d4239SHadi Asyrafi 				psci_power_state_t *req_state)
251c76d4239SHadi Asyrafi {
252c76d4239SHadi Asyrafi 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
253c76d4239SHadi Asyrafi 
254c76d4239SHadi Asyrafi 	return PSCI_E_SUCCESS;
255c76d4239SHadi Asyrafi }
256c76d4239SHadi Asyrafi 
257c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint)
258c76d4239SHadi Asyrafi {
259c76d4239SHadi Asyrafi 	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
260c76d4239SHadi Asyrafi 	return PSCI_E_SUCCESS;
261c76d4239SHadi Asyrafi }
262c76d4239SHadi Asyrafi 
263c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state)
264c76d4239SHadi Asyrafi {
265c76d4239SHadi Asyrafi 	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
266c76d4239SHadi Asyrafi 	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
267c76d4239SHadi Asyrafi }
268c76d4239SHadi Asyrafi 
269c76d4239SHadi Asyrafi /*******************************************************************************
270c76d4239SHadi Asyrafi  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
271c76d4239SHadi Asyrafi  * platform layer will take care of registering the handlers with PSCI.
272c76d4239SHadi Asyrafi  ******************************************************************************/
273c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = {
274c76d4239SHadi Asyrafi 	.cpu_standby = socfpga_cpu_standby,
275c76d4239SHadi Asyrafi 	.pwr_domain_on = socfpga_pwr_domain_on,
276c76d4239SHadi Asyrafi 	.pwr_domain_off = socfpga_pwr_domain_off,
277c76d4239SHadi Asyrafi 	.pwr_domain_suspend = socfpga_pwr_domain_suspend,
278c76d4239SHadi Asyrafi 	.pwr_domain_on_finish = socfpga_pwr_domain_on_finish,
279c76d4239SHadi Asyrafi 	.pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish,
280c76d4239SHadi Asyrafi 	.system_off = socfpga_system_off,
281c76d4239SHadi Asyrafi 	.system_reset = socfpga_system_reset,
28232cf34acSHadi Asyrafi 	.system_reset2 = socfpga_system_reset2,
283c76d4239SHadi Asyrafi 	.validate_power_state = socfpga_validate_power_state,
284c76d4239SHadi Asyrafi 	.validate_ns_entrypoint = socfpga_validate_ns_entrypoint,
285c76d4239SHadi Asyrafi 	.get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state
286c76d4239SHadi Asyrafi };
287c76d4239SHadi Asyrafi 
288c76d4239SHadi Asyrafi /*******************************************************************************
289c76d4239SHadi Asyrafi  * Export the platform specific power ops.
290c76d4239SHadi Asyrafi  ******************************************************************************/
291c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint,
292c76d4239SHadi Asyrafi 			const struct plat_psci_ops **psci_ops)
293c76d4239SHadi Asyrafi {
294c76d4239SHadi Asyrafi 	/* Save warm boot entrypoint.*/
295cf82aff0SHadi Asyrafi 	mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint);
296c76d4239SHadi Asyrafi 	*psci_ops = &socfpga_psci_pm_ops;
297cf82aff0SHadi Asyrafi 
298c76d4239SHadi Asyrafi 	return 0;
299c76d4239SHadi Asyrafi }
300