blob: 7b51476e03075958d0300429d51247d66c58628d [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
31#include <stdio.h>
32#include <string.h>
33#include <assert.h>
34#include <arch_helpers.h>
35#include <console.h>
36#include <platform.h>
37#include <bl_common.h>
38#include <bl31.h>
39#include <bakery_lock.h>
40#include <cci400.h>
41#include <gic.h>
42#include <fvp_pwrc.h>
43/* Only included for error codes */
44#include <psci.h>
45
46/*******************************************************************************
Vikram Kanigiri3b7c59b2014-03-21 11:57:10 +000047 * FVP handler called when an affinity instance is about to enter standby.
48 ******************************************************************************/
49int fvp_affinst_standby(unsigned int power_state)
50{
51 unsigned int target_afflvl;
52
53 /* Sanity check the requested state */
54 target_afflvl = psci_get_pstate_afflvl(power_state);
55
56 /*
57 * It's possible to enter standby only on affinity level 0 i.e. a cpu
58 * on the FVP. Ignore any other affinity level.
59 */
60 if (target_afflvl != MPIDR_AFFLVL0)
61 return PSCI_E_INVALID_PARAMS;
62
63 /* Enter standby state */
64 wfi();
65
66 return PSCI_E_SUCCESS;
67}
68
69/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +010070 * FVP handler called when an affinity instance is about to be turned on. The
71 * level and mpidr determine the affinity instance.
72 ******************************************************************************/
73int fvp_affinst_on(unsigned long mpidr,
74 unsigned long sec_entrypoint,
75 unsigned long ns_entrypoint,
76 unsigned int afflvl,
77 unsigned int state)
78{
79 int rc = PSCI_E_SUCCESS;
80 unsigned long linear_id;
81 mailbox *fvp_mboxes;
82 unsigned int psysr;
83
Achin Gupta4f6ad662013-10-25 09:08:21 +010084 /*
85 * It's possible to turn on only affinity level 0 i.e. a cpu
86 * on the FVP. Ignore any other affinity level.
87 */
88 if (afflvl != MPIDR_AFFLVL0)
89 goto exit;
90
91 /*
92 * Ensure that we do not cancel an inflight power off request
93 * for the target cpu. That would leave it in a zombie wfi.
94 * Wait for it to power off, program the jump address for the
95 * target cpu and then program the power controller to turn
96 * that cpu on
97 */
98 do {
99 psysr = fvp_pwrc_read_psysr(mpidr);
100 } while (psysr & PSYSR_AFF_L0);
101
102 linear_id = platform_get_core_pos(mpidr);
103 fvp_mboxes = (mailbox *) (TZDRAM_BASE + MBOX_OFF);
104 fvp_mboxes[linear_id].value = sec_entrypoint;
105 flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
106 sizeof(unsigned long));
107
108 fvp_pwrc_write_pponr(mpidr);
109
110exit:
111 return rc;
112}
113
114/*******************************************************************************
115 * FVP handler called when an affinity instance is about to be turned off. The
116 * level and mpidr determine the affinity instance. The 'state' arg. allows the
117 * platform to decide whether the cluster is being turned off and take apt
118 * actions.
119 *
120 * CAUTION: This function is called with coherent stacks so that caches can be
121 * turned off, flushed and coherency disabled. There is no guarantee that caches
122 * will remain turned on across calls to this function as each affinity level is
123 * dealt with. So do not write & read global variables across calls. It will be
124 * wise to do flush a write to the global to prevent unpredictable results.
125 ******************************************************************************/
126int fvp_affinst_off(unsigned long mpidr,
127 unsigned int afflvl,
128 unsigned int state)
129{
130 int rc = PSCI_E_SUCCESS;
131 unsigned int gicc_base, ectlr;
Harry Liebel30affd52013-10-30 17:41:48 +0000132 unsigned long cpu_setup, cci_setup;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100133
134 switch (afflvl) {
135 case MPIDR_AFFLVL1:
136 if (state == PSCI_STATE_OFF) {
137 /*
138 * Disable coherency if this cluster is to be
139 * turned off
140 */
Harry Liebel30affd52013-10-30 17:41:48 +0000141 cci_setup = platform_get_cfgvar(CONFIG_HAS_CCI);
142 if (cci_setup) {
143 cci_disable_coherency(mpidr);
144 }
Achin Gupta4f6ad662013-10-25 09:08:21 +0100145
146 /*
147 * Program the power controller to turn the
148 * cluster off
149 */
150 fvp_pwrc_write_pcoffr(mpidr);
151
152 }
153 break;
154
155 case MPIDR_AFFLVL0:
156 if (state == PSCI_STATE_OFF) {
157
158 /*
159 * Take this cpu out of intra-cluster coherency if
160 * the FVP flavour supports the SMP bit.
161 */
162 cpu_setup = platform_get_cfgvar(CONFIG_CPU_SETUP);
163 if (cpu_setup) {
164 ectlr = read_cpuectlr();
165 ectlr &= ~CPUECTLR_SMP_BIT;
166 write_cpuectlr(ectlr);
167 }
168
169 /*
170 * Prevent interrupts from spuriously waking up
171 * this cpu
172 */
173 gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
174 gic_cpuif_deactivate(gicc_base);
175
176 /*
177 * Program the power controller to power this
178 * cpu off
179 */
180 fvp_pwrc_write_ppoffr(mpidr);
181 }
182 break;
183
184 default:
185 assert(0);
186 }
187
188 return rc;
189}
190
191/*******************************************************************************
192 * FVP handler called when an affinity instance is about to be suspended. The
193 * level and mpidr determine the affinity instance. The 'state' arg. allows the
194 * platform to decide whether the cluster is being turned off and take apt
195 * actions.
196 *
197 * CAUTION: This function is called with coherent stacks so that caches can be
198 * turned off, flushed and coherency disabled. There is no guarantee that caches
199 * will remain turned on across calls to this function as each affinity level is
200 * dealt with. So do not write & read global variables across calls. It will be
201 * wise to do flush a write to the global to prevent unpredictable results.
202 ******************************************************************************/
203int fvp_affinst_suspend(unsigned long mpidr,
204 unsigned long sec_entrypoint,
205 unsigned long ns_entrypoint,
206 unsigned int afflvl,
207 unsigned int state)
208{
209 int rc = PSCI_E_SUCCESS;
210 unsigned int gicc_base, ectlr;
Harry Liebel30affd52013-10-30 17:41:48 +0000211 unsigned long cpu_setup, cci_setup, linear_id;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100212 mailbox *fvp_mboxes;
213
Achin Gupta4f6ad662013-10-25 09:08:21 +0100214 switch (afflvl) {
215 case MPIDR_AFFLVL1:
216 if (state == PSCI_STATE_OFF) {
217 /*
218 * Disable coherency if this cluster is to be
219 * turned off
220 */
Harry Liebel30affd52013-10-30 17:41:48 +0000221 cci_setup = platform_get_cfgvar(CONFIG_HAS_CCI);
222 if (cci_setup) {
223 cci_disable_coherency(mpidr);
224 }
Achin Gupta4f6ad662013-10-25 09:08:21 +0100225
226 /*
227 * Program the power controller to turn the
228 * cluster off
229 */
230 fvp_pwrc_write_pcoffr(mpidr);
231
232 }
233 break;
234
235 case MPIDR_AFFLVL0:
236 if (state == PSCI_STATE_OFF) {
237 /*
238 * Take this cpu out of intra-cluster coherency if
239 * the FVP flavour supports the SMP bit.
240 */
241 cpu_setup = platform_get_cfgvar(CONFIG_CPU_SETUP);
242 if (cpu_setup) {
243 ectlr = read_cpuectlr();
244 ectlr &= ~CPUECTLR_SMP_BIT;
245 write_cpuectlr(ectlr);
246 }
247
248 /* Program the jump address for the target cpu */
249 linear_id = platform_get_core_pos(mpidr);
250 fvp_mboxes = (mailbox *) (TZDRAM_BASE + MBOX_OFF);
251 fvp_mboxes[linear_id].value = sec_entrypoint;
252 flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
253 sizeof(unsigned long));
254
255 /*
256 * Prevent interrupts from spuriously waking up
257 * this cpu
258 */
259 gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
260 gic_cpuif_deactivate(gicc_base);
261
262 /*
263 * Program the power controller to power this
264 * cpu off and enable wakeup interrupts.
265 */
Achin Guptab127cdb2013-11-12 16:40:00 +0000266 fvp_pwrc_set_wen(mpidr);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100267 fvp_pwrc_write_ppoffr(mpidr);
268 }
269 break;
270
271 default:
272 assert(0);
273 }
274
Achin Gupta4f6ad662013-10-25 09:08:21 +0100275 return rc;
276}
277
278/*******************************************************************************
279 * FVP handler called when an affinity instance has just been powered on after
280 * being turned off earlier. The level and mpidr determine the affinity
281 * instance. The 'state' arg. allows the platform to decide whether the cluster
282 * was turned off prior to wakeup and do what's necessary to setup it up
283 * correctly.
284 ******************************************************************************/
285int fvp_affinst_on_finish(unsigned long mpidr,
286 unsigned int afflvl,
287 unsigned int state)
288{
289 int rc = PSCI_E_SUCCESS;
Harry Liebel30affd52013-10-30 17:41:48 +0000290 unsigned long linear_id, cpu_setup, cci_setup;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100291 mailbox *fvp_mboxes;
292 unsigned int gicd_base, gicc_base, reg_val, ectlr;
293
294 switch (afflvl) {
295
296 case MPIDR_AFFLVL1:
297 /* Enable coherency if this cluster was off */
Harry Liebel30affd52013-10-30 17:41:48 +0000298 if (state == PSCI_STATE_OFF) {
Achin Guptab2187ab2014-01-17 16:52:29 +0000299
300 /*
301 * This CPU might have woken up whilst the
302 * cluster was attempting to power down. In
303 * this case the FVP power controller will
304 * have a pending cluster power off request
305 * which needs to be cleared by writing to the
306 * PPONR register. This prevents the power
307 * controller from interpreting a subsequent
308 * entry of this cpu into a simple wfi as a
309 * power down request.
310 */
311 fvp_pwrc_write_pponr(mpidr);
312
Harry Liebel30affd52013-10-30 17:41:48 +0000313 cci_setup = platform_get_cfgvar(CONFIG_HAS_CCI);
314 if (cci_setup) {
315 cci_enable_coherency(mpidr);
316 }
317 }
Achin Gupta4f6ad662013-10-25 09:08:21 +0100318 break;
319
320 case MPIDR_AFFLVL0:
321 /*
322 * Ignore the state passed for a cpu. It could only have
323 * been off if we are here.
324 */
325
326 /*
327 * Turn on intra-cluster coherency if the FVP flavour supports
328 * it.
329 */
330 cpu_setup = platform_get_cfgvar(CONFIG_CPU_SETUP);
331 if (cpu_setup) {
332 ectlr = read_cpuectlr();
333 ectlr |= CPUECTLR_SMP_BIT;
334 write_cpuectlr(ectlr);
335 }
336
Achin Guptab127cdb2013-11-12 16:40:00 +0000337 /*
338 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
339 * with a cpu power down unless the bit is set again
340 */
341 fvp_pwrc_clr_wen(mpidr);
342
Achin Gupta4f6ad662013-10-25 09:08:21 +0100343 /* Zero the jump address in the mailbox for this cpu */
344 fvp_mboxes = (mailbox *) (TZDRAM_BASE + MBOX_OFF);
345 linear_id = platform_get_core_pos(mpidr);
346 fvp_mboxes[linear_id].value = 0;
347 flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
348 sizeof(unsigned long));
349
350 gicd_base = platform_get_cfgvar(CONFIG_GICD_ADDR);
351 gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
352
353 /* Enable the gic cpu interface */
354 gic_cpuif_setup(gicc_base);
355
356 /* TODO: This setup is needed only after a cold boot */
357 gic_pcpu_distif_setup(gicd_base);
358
359 /* Allow access to the System counter timer module */
360 reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT);
361 reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT);
362 reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT);
363 mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(0), reg_val);
364 mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(1), reg_val);
365
366 reg_val = (1 << CNTNSAR_NS_SHIFT(0)) |
367 (1 << CNTNSAR_NS_SHIFT(1));
368 mmio_write_32(SYS_TIMCTL_BASE + CNTNSAR, reg_val);
369
370 break;
371
372 default:
373 assert(0);
374 }
375
376 return rc;
377}
378
379/*******************************************************************************
380 * FVP handler called when an affinity instance has just been powered on after
381 * having been suspended earlier. The level and mpidr determine the affinity
382 * instance.
383 * TODO: At the moment we reuse the on finisher and reinitialize the secure
384 * context. Need to implement a separate suspend finisher.
385 ******************************************************************************/
386int fvp_affinst_suspend_finish(unsigned long mpidr,
387 unsigned int afflvl,
388 unsigned int state)
389{
390 return fvp_affinst_on_finish(mpidr, afflvl, state);
391}
392
393
394/*******************************************************************************
395 * Export the platform handlers to enable psci to invoke them
396 ******************************************************************************/
397static plat_pm_ops fvp_plat_pm_ops = {
Vikram Kanigiri3b7c59b2014-03-21 11:57:10 +0000398 fvp_affinst_standby,
Achin Gupta4f6ad662013-10-25 09:08:21 +0100399 fvp_affinst_on,
400 fvp_affinst_off,
401 fvp_affinst_suspend,
402 fvp_affinst_on_finish,
403 fvp_affinst_suspend_finish,
404};
405
406/*******************************************************************************
407 * Export the platform specific power ops & initialize the fvp power controller
408 ******************************************************************************/
409int platform_setup_pm(plat_pm_ops **plat_ops)
410{
411 *plat_ops = &fvp_plat_pm_ops;
412 return 0;
413}