xref: /rk3399_ARM-atf/plat/qemu/common/qemu_pm.c (revision 530ceda57288aa931d0c8ba7b3066340d587cc9b)
1 /*
2  * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <platform_def.h>
9 
10 #include <arch_helpers.h>
11 #include <common/debug.h>
12 #include <lib/psci/psci.h>
13 #include <plat/common/platform.h>
14 
15 #include "qemu_private.h"
16 
17 /*
18  * The secure entry point to be used on warm reset.
19  */
20 static unsigned long secure_entrypoint;
21 
22 /* Make composite power state parameter till power level 0 */
23 #if PSCI_EXTENDED_STATE_ID
24 
25 #define qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
26 		(((lvl0_state) << PSTATE_ID_SHIFT) | \
27 		 ((type) << PSTATE_TYPE_SHIFT))
28 #else
29 #define qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
30 		(((lvl0_state) << PSTATE_ID_SHIFT) | \
31 		 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
32 		 ((type) << PSTATE_TYPE_SHIFT))
33 #endif /* PSCI_EXTENDED_STATE_ID */
34 
35 
36 #define qemu_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
37 		(((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \
38 		 qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
39 
40 
41 
42 /*
43  *  The table storing the valid idle power states. Ensure that the
44  *  array entries are populated in ascending order of state-id to
45  *  enable us to use binary search during power state validation.
46  *  The table must be terminated by a NULL entry.
47  */
48 static const unsigned int qemu_pm_idle_states[] = {
49 	/* State-id - 0x01 */
50 	qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET,
51 				MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY),
52 	/* State-id - 0x02 */
53 	qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF,
54 				MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN),
55 	/* State-id - 0x22 */
56 	qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF,
57 				MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN),
58 	0,
59 };
60 
61 /*******************************************************************************
62  * Platform handler called to check the validity of the power state
63  * parameter. The power state parameter has to be a composite power state.
64  ******************************************************************************/
65 static int qemu_validate_power_state(unsigned int power_state,
66 				psci_power_state_t *req_state)
67 {
68 	unsigned int state_id;
69 	int i;
70 
71 	assert(req_state);
72 
73 	/*
74 	 *  Currently we are using a linear search for finding the matching
75 	 *  entry in the idle power state array. This can be made a binary
76 	 *  search if the number of entries justify the additional complexity.
77 	 */
78 	for (i = 0; !!qemu_pm_idle_states[i]; i++) {
79 		if (power_state == qemu_pm_idle_states[i])
80 			break;
81 	}
82 
83 	/* Return error if entry not found in the idle state array */
84 	if (!qemu_pm_idle_states[i])
85 		return PSCI_E_INVALID_PARAMS;
86 
87 	i = 0;
88 	state_id = psci_get_pstate_id(power_state);
89 
90 	/* Parse the State ID and populate the state info parameter */
91 	while (state_id) {
92 		req_state->pwr_domain_state[i++] = state_id &
93 						PLAT_LOCAL_PSTATE_MASK;
94 		state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
95 	}
96 
97 	return PSCI_E_SUCCESS;
98 }
99 
100 /*******************************************************************************
101  * Platform handler called to check the validity of the non secure
102  * entrypoint.
103  ******************************************************************************/
104 static int qemu_validate_ns_entrypoint(uintptr_t entrypoint)
105 {
106 	/*
107 	 * Check if the non secure entrypoint lies within the non
108 	 * secure DRAM.
109 	 */
110 	if ((entrypoint >= NS_DRAM0_BASE) &&
111 	    (entrypoint < (NS_DRAM0_BASE + NS_DRAM0_SIZE)))
112 		return PSCI_E_SUCCESS;
113 	return PSCI_E_INVALID_ADDRESS;
114 }
115 
116 /*******************************************************************************
117  * Platform handler called when a CPU is about to enter standby.
118  ******************************************************************************/
119 static void qemu_cpu_standby(plat_local_state_t cpu_state)
120 {
121 
122 	assert(cpu_state == PLAT_LOCAL_STATE_RET);
123 
124 	/*
125 	 * Enter standby state
126 	 * dsb is good practice before using wfi to enter low power states
127 	 */
128 	dsb();
129 	wfi();
130 }
131 
132 /*******************************************************************************
133  * Platform handler called when a power domain is about to be turned on. The
134  * mpidr determines the CPU to be turned on.
135  ******************************************************************************/
136 static int qemu_pwr_domain_on(u_register_t mpidr)
137 {
138 	int rc = PSCI_E_SUCCESS;
139 	unsigned pos = plat_core_pos_by_mpidr(mpidr);
140 	uint64_t *hold_base = (uint64_t *)PLAT_QEMU_HOLD_BASE;
141 
142 	hold_base[pos] = PLAT_QEMU_HOLD_STATE_GO;
143 	sev();
144 
145 	return rc;
146 }
147 
148 /*******************************************************************************
149  * Platform handler called when a power domain is about to be turned off. The
150  * target_state encodes the power state that each level should transition to.
151  ******************************************************************************/
152 void qemu_pwr_domain_off(const psci_power_state_t *target_state)
153 {
154 	assert(0);
155 }
156 
157 /*******************************************************************************
158  * Platform handler called when a power domain is about to be suspended. The
159  * target_state encodes the power state that each level should transition to.
160  ******************************************************************************/
161 void qemu_pwr_domain_suspend(const psci_power_state_t *target_state)
162 {
163 	assert(0);
164 }
165 
166 /*******************************************************************************
167  * Platform handler called when a power domain has just been powered on after
168  * being turned off earlier. The target_state encodes the low power state that
169  * each level has woken up from.
170  ******************************************************************************/
171 void qemu_pwr_domain_on_finish(const psci_power_state_t *target_state)
172 {
173 	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
174 					PLAT_LOCAL_STATE_OFF);
175 
176 	qemu_pwr_gic_on_finish();
177 }
178 
179 /*******************************************************************************
180  * Platform handler called when a power domain has just been powered on after
181  * having been suspended earlier. The target_state encodes the low power state
182  * that each level has woken up from.
183  ******************************************************************************/
184 void qemu_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
185 {
186 	assert(0);
187 }
188 
189 /*******************************************************************************
190  * Platform handlers to shutdown/reboot the system
191  ******************************************************************************/
192 static void __dead2 qemu_system_off(void)
193 {
194 	ERROR("QEMU System Off: operation not handled.\n");
195 	panic();
196 }
197 
198 static void __dead2 qemu_system_reset(void)
199 {
200 	ERROR("QEMU System Reset: operation not handled.\n");
201 	panic();
202 }
203 
204 static const plat_psci_ops_t plat_qemu_psci_pm_ops = {
205 	.cpu_standby = qemu_cpu_standby,
206 	.pwr_domain_on = qemu_pwr_domain_on,
207 	.pwr_domain_off = qemu_pwr_domain_off,
208 	.pwr_domain_suspend = qemu_pwr_domain_suspend,
209 	.pwr_domain_on_finish = qemu_pwr_domain_on_finish,
210 	.pwr_domain_suspend_finish = qemu_pwr_domain_suspend_finish,
211 	.system_off = qemu_system_off,
212 	.system_reset = qemu_system_reset,
213 	.validate_power_state = qemu_validate_power_state,
214 	.validate_ns_entrypoint = qemu_validate_ns_entrypoint
215 };
216 
217 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
218 			const plat_psci_ops_t **psci_ops)
219 {
220 	uintptr_t *mailbox = (void *) PLAT_QEMU_TRUSTED_MAILBOX_BASE;
221 
222 	*mailbox = sec_entrypoint;
223 	secure_entrypoint = (unsigned long) sec_entrypoint;
224 	*psci_ops = &plat_qemu_psci_pm_ops;
225 
226 	return 0;
227 }
228