xref: /rk3399_ARM-atf/plat/intel/soc/common/socfpga_psci.c (revision 4962385ec253e18a78994205b72eae2e64ec3647)
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 
17 
18 
19 /*******************************************************************************
20  * plat handler called when a CPU is about to enter standby.
21  ******************************************************************************/
22 void socfpga_cpu_standby(plat_local_state_t cpu_state)
23 {
24 	/*
25 	 * Enter standby state
26 	 * dsb is good practice before using wfi to enter low power states
27 	 */
28 	VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
29 	dsb();
30 	wfi();
31 }
32 
33 /*******************************************************************************
34  * plat handler called when a power domain is about to be turned on. The
35  * mpidr determines the CPU to be turned on.
36  ******************************************************************************/
37 int socfpga_pwr_domain_on(u_register_t mpidr)
38 {
39 	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
40 
41 	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
42 
43 	if (cpu_id == -1)
44 		return PSCI_E_INTERN_FAIL;
45 
46 	mmio_write_64(PLAT_CPUID_RELEASE, cpu_id);
47 
48 	/* release core reset */
49 	mmio_setbits_32(SOCFPGA_RSTMGR_MPUMODRST_OFST, 1 << cpu_id);
50 	return PSCI_E_SUCCESS;
51 }
52 
53 /*******************************************************************************
54  * plat handler called when a power domain is about to be turned off. The
55  * target_state encodes the power state that each level should transition to.
56  ******************************************************************************/
57 void socfpga_pwr_domain_off(const psci_power_state_t *target_state)
58 {
59 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
60 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
61 			__func__, i, target_state->pwr_domain_state[i]);
62 
63 	/* Prevent interrupts from spuriously waking up this cpu */
64 	gicv2_cpuif_disable();
65 }
66 
67 /*******************************************************************************
68  * plat handler called when a power domain is about to be suspended. The
69  * target_state encodes the power state that each level should transition to.
70  ******************************************************************************/
71 void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state)
72 {
73 	unsigned int cpu_id = plat_my_core_pos();
74 
75 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
76 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
77 			__func__, i, target_state->pwr_domain_state[i]);
78 	/* assert core reset */
79 	mmio_setbits_32(SOCFPGA_RSTMGR_MPUMODRST_OFST, 1 << cpu_id);
80 
81 }
82 
83 /*******************************************************************************
84  * plat handler called when a power domain has just been powered on after
85  * being turned off earlier. The target_state encodes the low power state that
86  * each level has woken up from.
87  ******************************************************************************/
88 void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state)
89 {
90 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
91 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
92 			__func__, i, target_state->pwr_domain_state[i]);
93 
94 	/* Program the gic per-cpu distributor or re-distributor interface */
95 	gicv2_pcpu_distif_init();
96 	gicv2_set_pe_target_mask(plat_my_core_pos());
97 
98 	/* Enable the gic cpu interface */
99 	gicv2_cpuif_enable();
100 }
101 
102 /*******************************************************************************
103  * plat handler called when a power domain has just been powered on after
104  * having been suspended earlier. The target_state encodes the low power state
105  * that each level has woken up from.
106  * TODO: At the moment we reuse the on finisher and reinitialize the secure
107  * context. Need to implement a separate suspend finisher.
108  ******************************************************************************/
109 void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
110 {
111 	unsigned int cpu_id = plat_my_core_pos();
112 
113 	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
114 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
115 			__func__, i, target_state->pwr_domain_state[i]);
116 
117 	/* release core reset */
118 	mmio_clrbits_32(SOCFPGA_RSTMGR_MPUMODRST_OFST, 1 << cpu_id);
119 }
120 
121 /*******************************************************************************
122  * plat handlers to shutdown/reboot the system
123  ******************************************************************************/
124 static void __dead2 socfpga_system_off(void)
125 {
126 	wfi();
127 	ERROR("System Off: operation not handled.\n");
128 	panic();
129 }
130 
131 static void __dead2 socfpga_system_reset(void)
132 {
133 	mailbox_reset_cold();
134 
135 	while (1)
136 		wfi();
137 }
138 
139 int socfpga_validate_power_state(unsigned int power_state,
140 				psci_power_state_t *req_state)
141 {
142 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
143 
144 	return PSCI_E_SUCCESS;
145 }
146 
147 int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint)
148 {
149 	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
150 	return PSCI_E_SUCCESS;
151 }
152 
153 void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state)
154 {
155 	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
156 	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
157 }
158 
159 /*******************************************************************************
160  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
161  * platform layer will take care of registering the handlers with PSCI.
162  ******************************************************************************/
163 const plat_psci_ops_t socfpga_psci_pm_ops = {
164 	.cpu_standby = socfpga_cpu_standby,
165 	.pwr_domain_on = socfpga_pwr_domain_on,
166 	.pwr_domain_off = socfpga_pwr_domain_off,
167 	.pwr_domain_suspend = socfpga_pwr_domain_suspend,
168 	.pwr_domain_on_finish = socfpga_pwr_domain_on_finish,
169 	.pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish,
170 	.system_off = socfpga_system_off,
171 	.system_reset = socfpga_system_reset,
172 	.validate_power_state = socfpga_validate_power_state,
173 	.validate_ns_entrypoint = socfpga_validate_ns_entrypoint,
174 	.get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state
175 };
176 
177 /*******************************************************************************
178  * Export the platform specific power ops.
179  ******************************************************************************/
180 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
181 			const struct plat_psci_ops **psci_ops)
182 {
183 	/* Save warm boot entrypoint.*/
184 	mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint);
185 	*psci_ops = &socfpga_psci_pm_ops;
186 
187 	return 0;
188 }
189