blob: 74ce89fdfe5bbd41ad6d78ef49a7a41f4636eb92 [file] [log] [blame]
Sandrine Bailleux798140d2014-07-17 16:06:39 +01001/*
2 * Copyright (c) 2013, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <assert.h>
32#include <arch_helpers.h>
Juan Castillo75ed3562014-08-12 08:42:28 +010033#include <debug.h>
Sandrine Bailleux798140d2014-07-17 16:06:39 +010034#include <cci400.h>
35#include <errno.h>
36#include <platform.h>
37#include <platform_def.h>
38#include <psci.h>
39#include "juno_def.h"
40#include "juno_private.h"
41#include "scpi.h"
42
43/*******************************************************************************
44 * Private Juno function to program the mailbox for a cpu before it is released
45 * from reset.
46 ******************************************************************************/
47static void juno_program_mailbox(uint64_t mpidr, uint64_t address)
48{
49 uint64_t linear_id;
50 uint64_t mbox;
51
52 linear_id = platform_get_core_pos(mpidr);
53 mbox = TRUSTED_MAILBOXES_BASE + (linear_id << TRUSTED_MAILBOX_SHIFT);
54 *((uint64_t *) mbox) = address;
55 flush_dcache_range(mbox, sizeof(mbox));
56}
57
58/*******************************************************************************
59 * Private Juno function which is used to determine if any platform actions
60 * should be performed for the specified affinity instance given its
61 * state. Nothing needs to be done if the 'state' is not off or if this is not
62 * the highest affinity level which will enter the 'state'.
63 ******************************************************************************/
64static int32_t juno_do_plat_actions(uint32_t afflvl, uint32_t state)
65{
66 uint32_t max_phys_off_afflvl;
67
68 assert(afflvl <= MPIDR_AFFLVL1);
69
70 if (state != PSCI_STATE_OFF)
71 return -EAGAIN;
72
73 /*
74 * Find the highest affinity level which will be suspended and postpone
75 * all the platform specific actions until that level is hit.
76 */
77 max_phys_off_afflvl = psci_get_max_phys_off_afflvl();
78 assert(max_phys_off_afflvl != PSCI_INVALID_DATA);
79 assert(psci_get_suspend_afflvl() >= max_phys_off_afflvl);
80 if (afflvl != max_phys_off_afflvl)
81 return -EAGAIN;
82
83 return 0;
84}
85
86/*******************************************************************************
87 * Juno handler called when an affinity instance is about to be turned on. The
88 * level and mpidr determine the affinity instance.
89 ******************************************************************************/
Achin Gupta89b70cd2014-08-18 14:40:27 +010090int32_t juno_affinst_on(uint64_t mpidr,
91 uint64_t sec_entrypoint,
92 uint64_t ns_entrypoint,
93 uint32_t afflvl,
94 uint32_t state)
Sandrine Bailleux798140d2014-07-17 16:06:39 +010095{
96 /*
97 * SCP takes care of powering up higher affinity levels so we
98 * only need to care about level 0
99 */
100 if (afflvl != MPIDR_AFFLVL0)
101 return PSCI_E_SUCCESS;
102
103 /*
104 * Setup mailbox with address for CPU entrypoint when it next powers up
105 */
106 juno_program_mailbox(mpidr, sec_entrypoint);
107
108 scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on,
109 scpi_power_on);
110
111 return PSCI_E_SUCCESS;
112}
113
114/*******************************************************************************
115 * Juno handler called when an affinity instance has just been powered on after
116 * being turned off earlier. The level and mpidr determine the affinity
117 * instance. The 'state' arg. allows the platform to decide whether the cluster
118 * was turned off prior to wakeup and do what's necessary to setup it up
119 * correctly.
120 ******************************************************************************/
Achin Gupta89b70cd2014-08-18 14:40:27 +0100121int32_t juno_affinst_on_finish(uint64_t mpidr, uint32_t afflvl, uint32_t state)
Sandrine Bailleux798140d2014-07-17 16:06:39 +0100122{
123 /* Determine if any platform actions need to be executed. */
124 if (juno_do_plat_actions(afflvl, state) == -EAGAIN)
125 return PSCI_E_SUCCESS;
126
127 /*
128 * Perform the common cluster specific operations i.e enable coherency
129 * if this cluster was off.
130 */
131 if (afflvl != MPIDR_AFFLVL0)
132 cci_enable_cluster_coherency(mpidr);
133
134
135 /* Enable the gic cpu interface */
136 gic_cpuif_setup(GICC_BASE);
137
138 /* Juno todo: Is this setup only needed after a cold boot? */
139 gic_pcpu_distif_setup(GICD_BASE);
140
141 /* Clear the mailbox for this cpu. */
142 juno_program_mailbox(mpidr, 0);
143
144 return PSCI_E_SUCCESS;
145}
146
147/*******************************************************************************
Achin Gupta89b70cd2014-08-18 14:40:27 +0100148 * Common function called while turning a cpu off or suspending it. It is called
149 * from juno_off() or juno_suspend() when these functions in turn are called for
150 * the highest affinity level which will be powered down. It performs the
151 * actions common to the OFF and SUSPEND calls.
152 ******************************************************************************/
153static int32_t juno_power_down_common(uint32_t afflvl)
154{
155 uint32_t cluster_state = scpi_power_on;
156
157 /* Prevent interrupts from spuriously waking up this cpu */
158 gic_cpuif_deactivate(GICC_BASE);
159
160 /* Cluster is to be turned off, so disable coherency */
161 if (afflvl > MPIDR_AFFLVL0) {
162 cci_disable_cluster_coherency(read_mpidr_el1());
163 cluster_state = scpi_power_off;
164 }
165
166 /*
167 * Ask the SCP to power down the appropriate components depending upon
168 * their state.
169 */
170 scpi_set_css_power_state(read_mpidr_el1(),
171 scpi_power_off,
172 cluster_state,
173 scpi_power_on);
174
175 return PSCI_E_SUCCESS;
176}
177
178/*******************************************************************************
179 * Handler called when an affinity instance is about to be turned off. The
180 * level and mpidr determine the affinity instance. The 'state' arg. allows the
181 * platform to decide whether the cluster is being turned off and take
182 * appropriate actions.
183 *
184 * CAUTION: There is no guarantee that caches will remain turned on across calls
185 * to this function as each affinity level is dealt with. So do not write & read
186 * global variables across calls. It will be wise to do flush a write to the
187 * global to prevent unpredictable results.
188 ******************************************************************************/
189static int32_t juno_affinst_off(uint64_t mpidr, uint32_t afflvl, uint32_t state)
190{
191 /* Determine if any platform actions need to be executed */
192 if (juno_do_plat_actions(afflvl, state) == -EAGAIN)
193 return PSCI_E_SUCCESS;
194
195 return juno_power_down_common(afflvl);
196}
197
198/*******************************************************************************
199 * Handler called when an affinity instance is about to be suspended. The
200 * level and mpidr determine the affinity instance. The 'state' arg. allows the
201 * platform to decide whether the cluster is being turned off and take apt
202 * actions. The 'sec_entrypoint' determines the address in BL3-1 from where
203 * execution should resume.
204 *
205 * CAUTION: There is no guarantee that caches will remain turned on across calls
206 * to this function as each affinity level is dealt with. So do not write & read
207 * global variables across calls. It will be wise to do flush a write to the
208 * global to prevent unpredictable results.
209 ******************************************************************************/
210static int32_t juno_affinst_suspend(uint64_t mpidr,
211 uint64_t sec_entrypoint,
212 uint64_t ns_entrypoint,
213 uint32_t afflvl,
214 uint32_t state)
215{
216 /* Determine if any platform actions need to be executed */
217 if (juno_do_plat_actions(afflvl, state) == -EAGAIN)
218 return PSCI_E_SUCCESS;
219
220 /*
221 * Setup mailbox with address for CPU entrypoint when it next powers up.
222 */
223 juno_program_mailbox(mpidr, sec_entrypoint);
224
225 return juno_power_down_common(afflvl);
226}
227
228/*******************************************************************************
229 * Juno handler called when an affinity instance has just been powered on after
230 * having been suspended earlier. The level and mpidr determine the affinity
231 * instance.
232 * TODO: At the moment we reuse the on finisher and reinitialize the secure
233 * context. Need to implement a separate suspend finisher.
234 ******************************************************************************/
235static int32_t juno_affinst_suspend_finish(uint64_t mpidr,
236 uint32_t afflvl,
237 uint32_t state)
238{
239 return juno_affinst_on_finish(mpidr, afflvl, state);
240}
241
242/*******************************************************************************
Juan Castillo75ed3562014-08-12 08:42:28 +0100243 * Juno handlers to shutdown/reboot the system
244 ******************************************************************************/
245static void __dead2 juno_system_off(void)
246{
247 uint32_t response;
248
249 /* Send the power down request to the SCP */
250 response = scpi_sys_power_state(scpi_system_shutdown);
251
252 if (response != SCP_OK) {
253 ERROR("Juno System Off: SCP error %u.\n", response);
254 panic();
255 }
256 wfi();
257 ERROR("Juno System Off: operation not handled.\n");
258 panic();
259}
260
261static void __dead2 juno_system_reset(void)
262{
263 uint32_t response;
264
265 /* Send the system reset request to the SCP */
266 response = scpi_sys_power_state(scpi_system_reboot);
267
268 if (response != SCP_OK) {
269 ERROR("Juno System Reset: SCP error %u.\n", response);
270 panic();
271 }
272 wfi();
273 ERROR("Juno System Reset: operation not handled.\n");
274 panic();
275}
276
277/*******************************************************************************
Sandrine Bailleux798140d2014-07-17 16:06:39 +0100278 * Export the platform handlers to enable psci to invoke them
279 ******************************************************************************/
280static const plat_pm_ops_t juno_ops = {
Achin Gupta89b70cd2014-08-18 14:40:27 +0100281 .affinst_on = juno_affinst_on,
282 .affinst_on_finish = juno_affinst_on_finish,
283 .affinst_off = juno_affinst_off,
284 .affinst_suspend = juno_affinst_suspend,
Juan Castillo75ed3562014-08-12 08:42:28 +0100285 .affinst_suspend_finish = juno_affinst_suspend_finish,
286 .system_off = juno_system_off,
287 .system_reset = juno_system_reset
Sandrine Bailleux798140d2014-07-17 16:06:39 +0100288};
289
290/*******************************************************************************
291 * Export the platform specific power ops.
292 ******************************************************************************/
293int32_t platform_setup_pm(const plat_pm_ops_t **plat_ops)
294{
295 *plat_ops = &juno_ops;
296 return 0;
297}