xref: /rk3399_ARM-atf/plat/nvidia/tegra/common/tegra_pm.c (revision 08438e24e10504642634da9ee3dde794ac6fa8f0)
1*08438e24SVarun Wadekar /*
2*08438e24SVarun Wadekar  * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3*08438e24SVarun Wadekar  *
4*08438e24SVarun Wadekar  * Redistribution and use in source and binary forms, with or without
5*08438e24SVarun Wadekar  * modification, are permitted provided that the following conditions are met:
6*08438e24SVarun Wadekar  *
7*08438e24SVarun Wadekar  * Redistributions of source code must retain the above copyright notice, this
8*08438e24SVarun Wadekar  * list of conditions and the following disclaimer.
9*08438e24SVarun Wadekar  *
10*08438e24SVarun Wadekar  * Redistributions in binary form must reproduce the above copyright notice,
11*08438e24SVarun Wadekar  * this list of conditions and the following disclaimer in the documentation
12*08438e24SVarun Wadekar  * and/or other materials provided with the distribution.
13*08438e24SVarun Wadekar  *
14*08438e24SVarun Wadekar  * Neither the name of ARM nor the names of its contributors may be used
15*08438e24SVarun Wadekar  * to endorse or promote products derived from this software without specific
16*08438e24SVarun Wadekar  * prior written permission.
17*08438e24SVarun Wadekar  *
18*08438e24SVarun Wadekar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*08438e24SVarun Wadekar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*08438e24SVarun Wadekar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*08438e24SVarun Wadekar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*08438e24SVarun Wadekar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*08438e24SVarun Wadekar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*08438e24SVarun Wadekar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*08438e24SVarun Wadekar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*08438e24SVarun Wadekar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*08438e24SVarun Wadekar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*08438e24SVarun Wadekar  * POSSIBILITY OF SUCH DAMAGE.
29*08438e24SVarun Wadekar  */
30*08438e24SVarun Wadekar 
31*08438e24SVarun Wadekar #include <arch_helpers.h>
32*08438e24SVarun Wadekar #include <assert.h>
33*08438e24SVarun Wadekar #include <bl_common.h>
34*08438e24SVarun Wadekar #include <context.h>
35*08438e24SVarun Wadekar #include <context_mgmt.h>
36*08438e24SVarun Wadekar #include <debug.h>
37*08438e24SVarun Wadekar #include <memctrl.h>
38*08438e24SVarun Wadekar #include <mmio.h>
39*08438e24SVarun Wadekar #include <platform.h>
40*08438e24SVarun Wadekar #include <platform_def.h>
41*08438e24SVarun Wadekar #include <pmc.h>
42*08438e24SVarun Wadekar #include <psci.h>
43*08438e24SVarun Wadekar #include <tegra_def.h>
44*08438e24SVarun Wadekar #include <tegra_private.h>
45*08438e24SVarun Wadekar 
46*08438e24SVarun Wadekar extern uint64_t tegra_bl31_phys_base;
47*08438e24SVarun Wadekar extern uint64_t sec_entry_point[PLATFORM_CORE_COUNT];
48*08438e24SVarun Wadekar static int system_suspended;
49*08438e24SVarun Wadekar 
50*08438e24SVarun Wadekar /*
51*08438e24SVarun Wadekar  * The following platform setup functions are weakly defined. They
52*08438e24SVarun Wadekar  * provide typical implementations that will be overridden by a SoC.
53*08438e24SVarun Wadekar  */
54*08438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_suspend
55*08438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_on
56*08438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_off
57*08438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_on_finish
58*08438e24SVarun Wadekar 
59*08438e24SVarun Wadekar int tegra_prepare_cpu_suspend(unsigned int id, unsigned int afflvl)
60*08438e24SVarun Wadekar {
61*08438e24SVarun Wadekar 	return PSCI_E_NOT_SUPPORTED;
62*08438e24SVarun Wadekar }
63*08438e24SVarun Wadekar 
64*08438e24SVarun Wadekar int tegra_prepare_cpu_on(unsigned long mpidr)
65*08438e24SVarun Wadekar {
66*08438e24SVarun Wadekar 	return PSCI_E_SUCCESS;
67*08438e24SVarun Wadekar }
68*08438e24SVarun Wadekar 
69*08438e24SVarun Wadekar int tegra_prepare_cpu_off(unsigned long mpidr)
70*08438e24SVarun Wadekar {
71*08438e24SVarun Wadekar 	return PSCI_E_SUCCESS;
72*08438e24SVarun Wadekar }
73*08438e24SVarun Wadekar 
74*08438e24SVarun Wadekar int tegra_prepare_cpu_on_finish(unsigned long mpidr)
75*08438e24SVarun Wadekar {
76*08438e24SVarun Wadekar 	return PSCI_E_SUCCESS;
77*08438e24SVarun Wadekar }
78*08438e24SVarun Wadekar 
79*08438e24SVarun Wadekar /*******************************************************************************
80*08438e24SVarun Wadekar  * Track system suspend entry.
81*08438e24SVarun Wadekar  ******************************************************************************/
82*08438e24SVarun Wadekar void tegra_pm_system_suspend_entry(void)
83*08438e24SVarun Wadekar {
84*08438e24SVarun Wadekar 	system_suspended = 1;
85*08438e24SVarun Wadekar }
86*08438e24SVarun Wadekar 
87*08438e24SVarun Wadekar /*******************************************************************************
88*08438e24SVarun Wadekar  * Track system suspend exit.
89*08438e24SVarun Wadekar  ******************************************************************************/
90*08438e24SVarun Wadekar void tegra_pm_system_suspend_exit(void)
91*08438e24SVarun Wadekar {
92*08438e24SVarun Wadekar 	system_suspended = 0;
93*08438e24SVarun Wadekar }
94*08438e24SVarun Wadekar 
95*08438e24SVarun Wadekar /*******************************************************************************
96*08438e24SVarun Wadekar  * Get the system suspend state.
97*08438e24SVarun Wadekar  ******************************************************************************/
98*08438e24SVarun Wadekar int tegra_system_suspended(void)
99*08438e24SVarun Wadekar {
100*08438e24SVarun Wadekar 	return system_suspended;
101*08438e24SVarun Wadekar }
102*08438e24SVarun Wadekar 
103*08438e24SVarun Wadekar /*******************************************************************************
104*08438e24SVarun Wadekar  * Handler called when an affinity instance is about to enter standby.
105*08438e24SVarun Wadekar  ******************************************************************************/
106*08438e24SVarun Wadekar void tegra_affinst_standby(unsigned int power_state)
107*08438e24SVarun Wadekar {
108*08438e24SVarun Wadekar 	/*
109*08438e24SVarun Wadekar 	 * Enter standby state
110*08438e24SVarun Wadekar 	 * dsb is good practice before using wfi to enter low power states
111*08438e24SVarun Wadekar 	 */
112*08438e24SVarun Wadekar 	dsb();
113*08438e24SVarun Wadekar 	wfi();
114*08438e24SVarun Wadekar }
115*08438e24SVarun Wadekar 
116*08438e24SVarun Wadekar /*******************************************************************************
117*08438e24SVarun Wadekar  * Handler called to check the validity of the power state parameter.
118*08438e24SVarun Wadekar  ******************************************************************************/
119*08438e24SVarun Wadekar int32_t tegra_validate_power_state(unsigned int power_state)
120*08438e24SVarun Wadekar {
121*08438e24SVarun Wadekar 	/* Sanity check the requested state */
122*08438e24SVarun Wadekar 	if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
123*08438e24SVarun Wadekar 		/*
124*08438e24SVarun Wadekar 		 * It's possible to enter standby only on affinity level 0 i.e.
125*08438e24SVarun Wadekar 		 * a cpu on Tegra. Ignore any other affinity level.
126*08438e24SVarun Wadekar 		 */
127*08438e24SVarun Wadekar 		if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0)
128*08438e24SVarun Wadekar 			return PSCI_E_INVALID_PARAMS;
129*08438e24SVarun Wadekar 	}
130*08438e24SVarun Wadekar 
131*08438e24SVarun Wadekar 	return PSCI_E_SUCCESS;
132*08438e24SVarun Wadekar }
133*08438e24SVarun Wadekar 
134*08438e24SVarun Wadekar /*******************************************************************************
135*08438e24SVarun Wadekar  * Handler called when an affinity instance is about to be turned on. The
136*08438e24SVarun Wadekar  * level and mpidr determine the affinity instance.
137*08438e24SVarun Wadekar  ******************************************************************************/
138*08438e24SVarun Wadekar int tegra_affinst_on(unsigned long mpidr,
139*08438e24SVarun Wadekar 		   unsigned long sec_entrypoint,
140*08438e24SVarun Wadekar 		   unsigned int afflvl,
141*08438e24SVarun Wadekar 		   unsigned int state)
142*08438e24SVarun Wadekar {
143*08438e24SVarun Wadekar 	int cpu = mpidr & MPIDR_CPU_MASK;
144*08438e24SVarun Wadekar 
145*08438e24SVarun Wadekar 	/*
146*08438e24SVarun Wadekar 	 * Support individual CPU power on only.
147*08438e24SVarun Wadekar 	 */
148*08438e24SVarun Wadekar 	if (afflvl > MPIDR_AFFLVL0)
149*08438e24SVarun Wadekar 		return PSCI_E_SUCCESS;
150*08438e24SVarun Wadekar 
151*08438e24SVarun Wadekar 	/*
152*08438e24SVarun Wadekar 	 * Flush entrypoint variable to PoC since it will be
153*08438e24SVarun Wadekar 	 * accessed after a reset with the caches turned off.
154*08438e24SVarun Wadekar 	 */
155*08438e24SVarun Wadekar 	sec_entry_point[cpu] = sec_entrypoint;
156*08438e24SVarun Wadekar 	flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
157*08438e24SVarun Wadekar 
158*08438e24SVarun Wadekar 	return tegra_prepare_cpu_on(mpidr);
159*08438e24SVarun Wadekar }
160*08438e24SVarun Wadekar 
161*08438e24SVarun Wadekar /*******************************************************************************
162*08438e24SVarun Wadekar  * Handler called when an affinity instance is about to be turned off. The
163*08438e24SVarun Wadekar  * level determines the affinity instance. The 'state' arg. allows the
164*08438e24SVarun Wadekar  * platform to decide whether the cluster is being turned off and take apt
165*08438e24SVarun Wadekar  * actions.
166*08438e24SVarun Wadekar  *
167*08438e24SVarun Wadekar  * CAUTION: This function is called with coherent stacks so that caches can be
168*08438e24SVarun Wadekar  * turned off, flushed and coherency disabled. There is no guarantee that caches
169*08438e24SVarun Wadekar  * will remain turned on across calls to this function as each affinity level is
170*08438e24SVarun Wadekar  * dealt with. So do not write & read global variables across calls. It will be
171*08438e24SVarun Wadekar  * wise to do flush a write to the global to prevent unpredictable results.
172*08438e24SVarun Wadekar  ******************************************************************************/
173*08438e24SVarun Wadekar void tegra_affinst_off(unsigned int afflvl, unsigned int state)
174*08438e24SVarun Wadekar {
175*08438e24SVarun Wadekar 	/*
176*08438e24SVarun Wadekar 	 * Support individual CPU power off only.
177*08438e24SVarun Wadekar 	 */
178*08438e24SVarun Wadekar 	if (afflvl > MPIDR_AFFLVL0)
179*08438e24SVarun Wadekar 		return;
180*08438e24SVarun Wadekar 
181*08438e24SVarun Wadekar 	tegra_prepare_cpu_off(read_mpidr());
182*08438e24SVarun Wadekar }
183*08438e24SVarun Wadekar 
184*08438e24SVarun Wadekar /*******************************************************************************
185*08438e24SVarun Wadekar  * Handler called when an affinity instance is about to be suspended. The
186*08438e24SVarun Wadekar  * level and mpidr determine the affinity instance. The 'state' arg. allows the
187*08438e24SVarun Wadekar  * platform to decide whether the cluster is being turned off and take apt
188*08438e24SVarun Wadekar  * actions.
189*08438e24SVarun Wadekar  *
190*08438e24SVarun Wadekar  * CAUTION: This function is called with coherent stacks so that caches can be
191*08438e24SVarun Wadekar  * turned off, flushed and coherency disabled. There is no guarantee that caches
192*08438e24SVarun Wadekar  * will remain turned on across calls to this function as each affinity level is
193*08438e24SVarun Wadekar  * dealt with. So do not write & read global variables across calls. It will be
194*08438e24SVarun Wadekar  * wise to flush a write to the global variable, to prevent unpredictable
195*08438e24SVarun Wadekar  * results.
196*08438e24SVarun Wadekar  ******************************************************************************/
197*08438e24SVarun Wadekar void tegra_affinst_suspend(unsigned long sec_entrypoint,
198*08438e24SVarun Wadekar 			unsigned int afflvl,
199*08438e24SVarun Wadekar 			unsigned int state)
200*08438e24SVarun Wadekar {
201*08438e24SVarun Wadekar 	int id = psci_get_suspend_stateid();
202*08438e24SVarun Wadekar 	int cpu = read_mpidr() & MPIDR_CPU_MASK;
203*08438e24SVarun Wadekar 
204*08438e24SVarun Wadekar 	if (afflvl > PLATFORM_MAX_AFFLVL)
205*08438e24SVarun Wadekar 		return;
206*08438e24SVarun Wadekar 
207*08438e24SVarun Wadekar 	/*
208*08438e24SVarun Wadekar 	 * Flush entrypoint variable to PoC since it will be
209*08438e24SVarun Wadekar 	 * accessed after a reset with the caches turned off.
210*08438e24SVarun Wadekar 	 */
211*08438e24SVarun Wadekar 	sec_entry_point[cpu] = sec_entrypoint;
212*08438e24SVarun Wadekar 	flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
213*08438e24SVarun Wadekar 
214*08438e24SVarun Wadekar 	tegra_prepare_cpu_suspend(id, afflvl);
215*08438e24SVarun Wadekar 
216*08438e24SVarun Wadekar 	/* disable GICC */
217*08438e24SVarun Wadekar 	tegra_gic_cpuif_deactivate();
218*08438e24SVarun Wadekar }
219*08438e24SVarun Wadekar 
220*08438e24SVarun Wadekar /*******************************************************************************
221*08438e24SVarun Wadekar  * Handler called when an affinity instance has just been powered on after
222*08438e24SVarun Wadekar  * being turned off earlier. The level determines the affinity instance.
223*08438e24SVarun Wadekar  * The 'state' arg. allows the platform to decide whether the cluster was
224*08438e24SVarun Wadekar  * turned off prior to wakeup and do what's necessary to set it up.
225*08438e24SVarun Wadekar  ******************************************************************************/
226*08438e24SVarun Wadekar void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state)
227*08438e24SVarun Wadekar {
228*08438e24SVarun Wadekar 	plat_params_from_bl2_t *plat_params;
229*08438e24SVarun Wadekar 
230*08438e24SVarun Wadekar 	/*
231*08438e24SVarun Wadekar 	 * Support individual CPU power on only.
232*08438e24SVarun Wadekar 	 */
233*08438e24SVarun Wadekar 	if (afflvl > MPIDR_AFFLVL0)
234*08438e24SVarun Wadekar 		return;
235*08438e24SVarun Wadekar 
236*08438e24SVarun Wadekar 	/*
237*08438e24SVarun Wadekar 	 * Initialize the GIC cpu and distributor interfaces
238*08438e24SVarun Wadekar 	 */
239*08438e24SVarun Wadekar 	tegra_gic_setup();
240*08438e24SVarun Wadekar 
241*08438e24SVarun Wadekar 	/*
242*08438e24SVarun Wadekar 	 * Check if we are exiting from deep sleep.
243*08438e24SVarun Wadekar 	 */
244*08438e24SVarun Wadekar 	if (tegra_system_suspended()) {
245*08438e24SVarun Wadekar 
246*08438e24SVarun Wadekar 		/*
247*08438e24SVarun Wadekar 		 * Lock scratch registers which hold the CPU vectors.
248*08438e24SVarun Wadekar 		 */
249*08438e24SVarun Wadekar 		tegra_pmc_lock_cpu_vectors();
250*08438e24SVarun Wadekar 
251*08438e24SVarun Wadekar 		/*
252*08438e24SVarun Wadekar 		 * SMMU configuration.
253*08438e24SVarun Wadekar 		 */
254*08438e24SVarun Wadekar 		tegra_memctrl_setup();
255*08438e24SVarun Wadekar 
256*08438e24SVarun Wadekar 		/*
257*08438e24SVarun Wadekar 		 * Security configuration to allow DRAM/device access.
258*08438e24SVarun Wadekar 		 */
259*08438e24SVarun Wadekar 		plat_params = bl31_get_plat_params();
260*08438e24SVarun Wadekar 		tegra_memctrl_tzdram_setup(tegra_bl31_phys_base,
261*08438e24SVarun Wadekar 			plat_params->tzdram_size);
262*08438e24SVarun Wadekar 	}
263*08438e24SVarun Wadekar 
264*08438e24SVarun Wadekar 	/*
265*08438e24SVarun Wadekar 	 * Reset hardware settings.
266*08438e24SVarun Wadekar 	 */
267*08438e24SVarun Wadekar 	tegra_prepare_cpu_on_finish(read_mpidr());
268*08438e24SVarun Wadekar }
269*08438e24SVarun Wadekar 
270*08438e24SVarun Wadekar /*******************************************************************************
271*08438e24SVarun Wadekar  * Handler called when an affinity instance has just been powered on after
272*08438e24SVarun Wadekar  * having been suspended earlier. The level and mpidr determine the affinity
273*08438e24SVarun Wadekar  * instance.
274*08438e24SVarun Wadekar  ******************************************************************************/
275*08438e24SVarun Wadekar void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state)
276*08438e24SVarun Wadekar {
277*08438e24SVarun Wadekar 	if (afflvl == MPIDR_AFFLVL0)
278*08438e24SVarun Wadekar 		tegra_affinst_on_finish(afflvl, state);
279*08438e24SVarun Wadekar }
280*08438e24SVarun Wadekar 
281*08438e24SVarun Wadekar /*******************************************************************************
282*08438e24SVarun Wadekar  * Handler called when the system wants to be powered off
283*08438e24SVarun Wadekar  ******************************************************************************/
284*08438e24SVarun Wadekar __dead2 void tegra_system_off(void)
285*08438e24SVarun Wadekar {
286*08438e24SVarun Wadekar 	ERROR("Tegra System Off: operation not handled.\n");
287*08438e24SVarun Wadekar 	panic();
288*08438e24SVarun Wadekar }
289*08438e24SVarun Wadekar 
290*08438e24SVarun Wadekar /*******************************************************************************
291*08438e24SVarun Wadekar  * Handler called when the system wants to be restarted.
292*08438e24SVarun Wadekar  ******************************************************************************/
293*08438e24SVarun Wadekar __dead2 void tegra_system_reset(void)
294*08438e24SVarun Wadekar {
295*08438e24SVarun Wadekar 	/*
296*08438e24SVarun Wadekar 	 * Program the PMC in order to restart the system.
297*08438e24SVarun Wadekar 	 */
298*08438e24SVarun Wadekar 	tegra_pmc_system_reset();
299*08438e24SVarun Wadekar }
300*08438e24SVarun Wadekar 
301*08438e24SVarun Wadekar /*******************************************************************************
302*08438e24SVarun Wadekar  * Export the platform handlers to enable psci to invoke them
303*08438e24SVarun Wadekar  ******************************************************************************/
304*08438e24SVarun Wadekar static const plat_pm_ops_t tegra_plat_pm_ops = {
305*08438e24SVarun Wadekar 	.affinst_standby	= tegra_affinst_standby,
306*08438e24SVarun Wadekar 	.affinst_on		= tegra_affinst_on,
307*08438e24SVarun Wadekar 	.affinst_off		= tegra_affinst_off,
308*08438e24SVarun Wadekar 	.affinst_suspend	= tegra_affinst_suspend,
309*08438e24SVarun Wadekar 	.affinst_on_finish	= tegra_affinst_on_finish,
310*08438e24SVarun Wadekar 	.affinst_suspend_finish	= tegra_affinst_suspend_finish,
311*08438e24SVarun Wadekar 	.system_off		= tegra_system_off,
312*08438e24SVarun Wadekar 	.system_reset		= tegra_system_reset,
313*08438e24SVarun Wadekar 	.validate_power_state	= tegra_validate_power_state
314*08438e24SVarun Wadekar };
315*08438e24SVarun Wadekar 
316*08438e24SVarun Wadekar /*******************************************************************************
317*08438e24SVarun Wadekar  * Export the platform specific power ops & initialize the fvp power controller
318*08438e24SVarun Wadekar  ******************************************************************************/
319*08438e24SVarun Wadekar int platform_setup_pm(const plat_pm_ops_t **plat_ops)
320*08438e24SVarun Wadekar {
321*08438e24SVarun Wadekar 	/*
322*08438e24SVarun Wadekar 	 * Reset hardware settings.
323*08438e24SVarun Wadekar 	 */
324*08438e24SVarun Wadekar 	tegra_prepare_cpu_on_finish(read_mpidr());
325*08438e24SVarun Wadekar 
326*08438e24SVarun Wadekar 	/*
327*08438e24SVarun Wadekar 	 * Initialize PM ops struct
328*08438e24SVarun Wadekar 	 */
329*08438e24SVarun Wadekar 	*plat_ops = &tegra_plat_pm_ops;
330*08438e24SVarun Wadekar 
331*08438e24SVarun Wadekar 	return 0;
332*08438e24SVarun Wadekar }
333