blob: 5430fffda8b2f719ac51d44f92e2b4e1b5829075 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Dan Handleye83b0ca2014-01-14 18:17:09 +00002 * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +01003 *
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
Achin Gupta4f6ad662013-10-25 09:08:21 +010031#include <arch_helpers.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010032#include <assert.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010033#include <bakery_lock.h>
34#include <cci400.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010035#include <mmio.h>
36#include <platform.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010037#include <psci.h>
Dan Handley4d2e49d2014-04-11 11:52:12 +010038#include "drivers/pwrc/fvp_pwrc.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010039
40/*******************************************************************************
Vikram Kanigiri3b7c59b2014-03-21 11:57:10 +000041 * FVP handler called when an affinity instance is about to enter standby.
42 ******************************************************************************/
43int fvp_affinst_standby(unsigned int power_state)
44{
45 unsigned int target_afflvl;
46
47 /* Sanity check the requested state */
48 target_afflvl = psci_get_pstate_afflvl(power_state);
49
50 /*
51 * It's possible to enter standby only on affinity level 0 i.e. a cpu
52 * on the FVP. Ignore any other affinity level.
53 */
54 if (target_afflvl != MPIDR_AFFLVL0)
55 return PSCI_E_INVALID_PARAMS;
56
57 /* Enter standby state */
58 wfi();
59
60 return PSCI_E_SUCCESS;
61}
62
63/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +010064 * FVP handler called when an affinity instance is about to be turned on. The
65 * level and mpidr determine the affinity instance.
66 ******************************************************************************/
67int fvp_affinst_on(unsigned long mpidr,
68 unsigned long sec_entrypoint,
69 unsigned long ns_entrypoint,
70 unsigned int afflvl,
71 unsigned int state)
72{
73 int rc = PSCI_E_SUCCESS;
74 unsigned long linear_id;
Dan Handleye2712bc2014-04-10 15:37:22 +010075 mailbox_t *fvp_mboxes;
Achin Gupta4f6ad662013-10-25 09:08:21 +010076 unsigned int psysr;
77
Achin Gupta4f6ad662013-10-25 09:08:21 +010078 /*
79 * It's possible to turn on only affinity level 0 i.e. a cpu
80 * on the FVP. Ignore any other affinity level.
81 */
82 if (afflvl != MPIDR_AFFLVL0)
83 goto exit;
84
85 /*
86 * Ensure that we do not cancel an inflight power off request
87 * for the target cpu. That would leave it in a zombie wfi.
88 * Wait for it to power off, program the jump address for the
89 * target cpu and then program the power controller to turn
90 * that cpu on
91 */
92 do {
93 psysr = fvp_pwrc_read_psysr(mpidr);
94 } while (psysr & PSYSR_AFF_L0);
95
96 linear_id = platform_get_core_pos(mpidr);
Dan Handleye2712bc2014-04-10 15:37:22 +010097 fvp_mboxes = (mailbox_t *) (TZDRAM_BASE + MBOX_OFF);
Achin Gupta4f6ad662013-10-25 09:08:21 +010098 fvp_mboxes[linear_id].value = sec_entrypoint;
99 flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
100 sizeof(unsigned long));
101
102 fvp_pwrc_write_pponr(mpidr);
103
104exit:
105 return rc;
106}
107
108/*******************************************************************************
109 * FVP handler called when an affinity instance is about to be turned off. The
110 * level and mpidr determine the affinity instance. The 'state' arg. allows the
111 * platform to decide whether the cluster is being turned off and take apt
112 * actions.
113 *
114 * CAUTION: This function is called with coherent stacks so that caches can be
115 * turned off, flushed and coherency disabled. There is no guarantee that caches
116 * will remain turned on across calls to this function as each affinity level is
117 * dealt with. So do not write & read global variables across calls. It will be
118 * wise to do flush a write to the global to prevent unpredictable results.
119 ******************************************************************************/
120int fvp_affinst_off(unsigned long mpidr,
121 unsigned int afflvl,
122 unsigned int state)
123{
124 int rc = PSCI_E_SUCCESS;
125 unsigned int gicc_base, ectlr;
Harry Liebel30affd52013-10-30 17:41:48 +0000126 unsigned long cpu_setup, cci_setup;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100127
128 switch (afflvl) {
129 case MPIDR_AFFLVL1:
130 if (state == PSCI_STATE_OFF) {
131 /*
132 * Disable coherency if this cluster is to be
133 * turned off
134 */
Harry Liebel30affd52013-10-30 17:41:48 +0000135 cci_setup = platform_get_cfgvar(CONFIG_HAS_CCI);
136 if (cci_setup) {
137 cci_disable_coherency(mpidr);
138 }
Achin Gupta4f6ad662013-10-25 09:08:21 +0100139
140 /*
141 * Program the power controller to turn the
142 * cluster off
143 */
144 fvp_pwrc_write_pcoffr(mpidr);
145
146 }
147 break;
148
149 case MPIDR_AFFLVL0:
150 if (state == PSCI_STATE_OFF) {
151
152 /*
153 * Take this cpu out of intra-cluster coherency if
154 * the FVP flavour supports the SMP bit.
155 */
156 cpu_setup = platform_get_cfgvar(CONFIG_CPU_SETUP);
157 if (cpu_setup) {
158 ectlr = read_cpuectlr();
159 ectlr &= ~CPUECTLR_SMP_BIT;
160 write_cpuectlr(ectlr);
161 }
162
163 /*
164 * Prevent interrupts from spuriously waking up
165 * this cpu
166 */
167 gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
168 gic_cpuif_deactivate(gicc_base);
169
170 /*
171 * Program the power controller to power this
172 * cpu off
173 */
174 fvp_pwrc_write_ppoffr(mpidr);
175 }
176 break;
177
178 default:
179 assert(0);
180 }
181
182 return rc;
183}
184
185/*******************************************************************************
186 * FVP handler called when an affinity instance is about to be suspended. The
187 * level and mpidr determine the affinity instance. The 'state' arg. allows the
188 * platform to decide whether the cluster is being turned off and take apt
189 * actions.
190 *
191 * CAUTION: This function is called with coherent stacks so that caches can be
192 * turned off, flushed and coherency disabled. There is no guarantee that caches
193 * will remain turned on across calls to this function as each affinity level is
194 * dealt with. So do not write & read global variables across calls. It will be
195 * wise to do flush a write to the global to prevent unpredictable results.
196 ******************************************************************************/
197int fvp_affinst_suspend(unsigned long mpidr,
198 unsigned long sec_entrypoint,
199 unsigned long ns_entrypoint,
200 unsigned int afflvl,
201 unsigned int state)
202{
203 int rc = PSCI_E_SUCCESS;
204 unsigned int gicc_base, ectlr;
Harry Liebel30affd52013-10-30 17:41:48 +0000205 unsigned long cpu_setup, cci_setup, linear_id;
Dan Handleye2712bc2014-04-10 15:37:22 +0100206 mailbox_t *fvp_mboxes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100207
Achin Gupta4f6ad662013-10-25 09:08:21 +0100208 switch (afflvl) {
209 case MPIDR_AFFLVL1:
210 if (state == PSCI_STATE_OFF) {
211 /*
212 * Disable coherency if this cluster is to be
213 * turned off
214 */
Harry Liebel30affd52013-10-30 17:41:48 +0000215 cci_setup = platform_get_cfgvar(CONFIG_HAS_CCI);
216 if (cci_setup) {
217 cci_disable_coherency(mpidr);
218 }
Achin Gupta4f6ad662013-10-25 09:08:21 +0100219
220 /*
221 * Program the power controller to turn the
222 * cluster off
223 */
224 fvp_pwrc_write_pcoffr(mpidr);
225
226 }
227 break;
228
229 case MPIDR_AFFLVL0:
230 if (state == PSCI_STATE_OFF) {
231 /*
232 * Take this cpu out of intra-cluster coherency if
233 * the FVP flavour supports the SMP bit.
234 */
235 cpu_setup = platform_get_cfgvar(CONFIG_CPU_SETUP);
236 if (cpu_setup) {
237 ectlr = read_cpuectlr();
238 ectlr &= ~CPUECTLR_SMP_BIT;
239 write_cpuectlr(ectlr);
240 }
241
242 /* Program the jump address for the target cpu */
243 linear_id = platform_get_core_pos(mpidr);
Dan Handleye2712bc2014-04-10 15:37:22 +0100244 fvp_mboxes = (mailbox_t *) (TZDRAM_BASE + MBOX_OFF);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100245 fvp_mboxes[linear_id].value = sec_entrypoint;
246 flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
247 sizeof(unsigned long));
248
249 /*
250 * Prevent interrupts from spuriously waking up
251 * this cpu
252 */
253 gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
254 gic_cpuif_deactivate(gicc_base);
255
256 /*
257 * Program the power controller to power this
258 * cpu off and enable wakeup interrupts.
259 */
Achin Guptab127cdb2013-11-12 16:40:00 +0000260 fvp_pwrc_set_wen(mpidr);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100261 fvp_pwrc_write_ppoffr(mpidr);
262 }
263 break;
264
265 default:
266 assert(0);
267 }
268
Achin Gupta4f6ad662013-10-25 09:08:21 +0100269 return rc;
270}
271
272/*******************************************************************************
273 * FVP handler called when an affinity instance has just been powered on after
274 * being turned off earlier. The level and mpidr determine the affinity
275 * instance. The 'state' arg. allows the platform to decide whether the cluster
276 * was turned off prior to wakeup and do what's necessary to setup it up
277 * correctly.
278 ******************************************************************************/
279int fvp_affinst_on_finish(unsigned long mpidr,
280 unsigned int afflvl,
281 unsigned int state)
282{
283 int rc = PSCI_E_SUCCESS;
Harry Liebel30affd52013-10-30 17:41:48 +0000284 unsigned long linear_id, cpu_setup, cci_setup;
Dan Handleye2712bc2014-04-10 15:37:22 +0100285 mailbox_t *fvp_mboxes;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100286 unsigned int gicd_base, gicc_base, reg_val, ectlr;
287
288 switch (afflvl) {
289
290 case MPIDR_AFFLVL1:
291 /* Enable coherency if this cluster was off */
Harry Liebel30affd52013-10-30 17:41:48 +0000292 if (state == PSCI_STATE_OFF) {
Achin Guptab2187ab2014-01-17 16:52:29 +0000293
294 /*
295 * This CPU might have woken up whilst the
296 * cluster was attempting to power down. In
297 * this case the FVP power controller will
298 * have a pending cluster power off request
299 * which needs to be cleared by writing to the
300 * PPONR register. This prevents the power
301 * controller from interpreting a subsequent
302 * entry of this cpu into a simple wfi as a
303 * power down request.
304 */
305 fvp_pwrc_write_pponr(mpidr);
306
Harry Liebel30affd52013-10-30 17:41:48 +0000307 cci_setup = platform_get_cfgvar(CONFIG_HAS_CCI);
308 if (cci_setup) {
309 cci_enable_coherency(mpidr);
310 }
311 }
Achin Gupta4f6ad662013-10-25 09:08:21 +0100312 break;
313
314 case MPIDR_AFFLVL0:
315 /*
316 * Ignore the state passed for a cpu. It could only have
317 * been off if we are here.
318 */
319
320 /*
321 * Turn on intra-cluster coherency if the FVP flavour supports
322 * it.
323 */
324 cpu_setup = platform_get_cfgvar(CONFIG_CPU_SETUP);
325 if (cpu_setup) {
326 ectlr = read_cpuectlr();
327 ectlr |= CPUECTLR_SMP_BIT;
328 write_cpuectlr(ectlr);
329 }
330
Achin Guptab127cdb2013-11-12 16:40:00 +0000331 /*
332 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
333 * with a cpu power down unless the bit is set again
334 */
335 fvp_pwrc_clr_wen(mpidr);
336
Achin Gupta4f6ad662013-10-25 09:08:21 +0100337 /* Zero the jump address in the mailbox for this cpu */
Dan Handleye2712bc2014-04-10 15:37:22 +0100338 fvp_mboxes = (mailbox_t *) (TZDRAM_BASE + MBOX_OFF);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100339 linear_id = platform_get_core_pos(mpidr);
340 fvp_mboxes[linear_id].value = 0;
341 flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
342 sizeof(unsigned long));
343
344 gicd_base = platform_get_cfgvar(CONFIG_GICD_ADDR);
345 gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
346
347 /* Enable the gic cpu interface */
348 gic_cpuif_setup(gicc_base);
349
350 /* TODO: This setup is needed only after a cold boot */
351 gic_pcpu_distif_setup(gicd_base);
352
353 /* Allow access to the System counter timer module */
354 reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT);
355 reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT);
356 reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT);
357 mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(0), reg_val);
358 mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(1), reg_val);
359
360 reg_val = (1 << CNTNSAR_NS_SHIFT(0)) |
361 (1 << CNTNSAR_NS_SHIFT(1));
362 mmio_write_32(SYS_TIMCTL_BASE + CNTNSAR, reg_val);
363
364 break;
365
366 default:
367 assert(0);
368 }
369
370 return rc;
371}
372
373/*******************************************************************************
374 * FVP handler called when an affinity instance has just been powered on after
375 * having been suspended earlier. The level and mpidr determine the affinity
376 * instance.
377 * TODO: At the moment we reuse the on finisher and reinitialize the secure
378 * context. Need to implement a separate suspend finisher.
379 ******************************************************************************/
380int fvp_affinst_suspend_finish(unsigned long mpidr,
381 unsigned int afflvl,
382 unsigned int state)
383{
384 return fvp_affinst_on_finish(mpidr, afflvl, state);
385}
386
387
388/*******************************************************************************
389 * Export the platform handlers to enable psci to invoke them
390 ******************************************************************************/
Dan Handleya4cb68e2014-04-23 13:47:06 +0100391static const plat_pm_ops_t fvp_plat_pm_ops = {
Vikram Kanigiri3b7c59b2014-03-21 11:57:10 +0000392 fvp_affinst_standby,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100393 fvp_affinst_on,
394 fvp_affinst_off,
395 fvp_affinst_suspend,
396 fvp_affinst_on_finish,
397 fvp_affinst_suspend_finish,
398};
399
400/*******************************************************************************
401 * Export the platform specific power ops & initialize the fvp power controller
402 ******************************************************************************/
Dan Handleya4cb68e2014-04-23 13:47:06 +0100403int platform_setup_pm(const plat_pm_ops_t **plat_ops)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100404{
405 *plat_ops = &fvp_plat_pm_ops;
406 return 0;
407}