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