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