blob: a199688dfac7d8275318ec4eb7b01f35b8c06155 [file] [log] [blame]
Jens Wiklander52c798e2015-12-07 14:37:10 +01001/*
Hongbo Zhang32338ec2018-04-19 13:06:07 +08002 * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
Jens Wiklander52c798e2015-12-07 14:37:10 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Jens Wiklander52c798e2015-12-07 14:37:10 +01005 */
6
Jens Wiklander52c798e2015-12-07 14:37:10 +01007#include <assert.h>
Isla Mitchelle3631462017-07-14 10:46:32 +01008#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009
10#include <arch_helpers.h>
11#include <common/debug.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000012#include <lib/psci/psci.h>
13#include <plat/common/platform.h>
Jens Wiklander52c798e2015-12-07 14:37:10 +010014
Hongbo Zhang32338ec2018-04-19 13:06:07 +080015#include "qemu_private.h"
16
Jens Wiklander52c798e2015-12-07 14:37:10 +010017/*
18 * The secure entry point to be used on warm reset.
19 */
20static 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 */
48static 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 ******************************************************************************/
65static 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 ******************************************************************************/
104static 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 ******************************************************************************/
119static 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 ******************************************************************************/
136static 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 ******************************************************************************/
152void 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 ******************************************************************************/
161void 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 ******************************************************************************/
171void 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
Hongbo Zhang32338ec2018-04-19 13:06:07 +0800176 qemu_pwr_gic_on_finish();
Jens Wiklander52c798e2015-12-07 14:37:10 +0100177}
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 ******************************************************************************/
184void 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 ******************************************************************************/
192static void __dead2 qemu_system_off(void)
193{
194 ERROR("QEMU System Off: operation not handled.\n");
195 panic();
196}
197
198static void __dead2 qemu_system_reset(void)
199{
200 ERROR("QEMU System Reset: operation not handled.\n");
201 panic();
202}
203
204static 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
217int 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}