xref: /rk3399_ARM-atf/plat/nvidia/tegra/common/tegra_pm.c (revision fd6007de64fd7e16f6d96972643434c04a77f1c6)
1 /*
2  * Copyright (c) 2015, 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 <arch_helpers.h>
32 #include <assert.h>
33 #include <bl_common.h>
34 #include <context.h>
35 #include <context_mgmt.h>
36 #include <debug.h>
37 #include <memctrl.h>
38 #include <mmio.h>
39 #include <platform.h>
40 #include <platform_def.h>
41 #include <pmc.h>
42 #include <psci.h>
43 #include <tegra_def.h>
44 #include <tegra_private.h>
45 
46 extern uint64_t tegra_bl31_phys_base;
47 extern uint64_t sec_entry_point[PLATFORM_CORE_COUNT];
48 static int system_suspended;
49 
50 /*
51  * The following platform setup functions are weakly defined. They
52  * provide typical implementations that will be overridden by a SoC.
53  */
54 #pragma weak tegra_soc_prepare_cpu_suspend
55 #pragma weak tegra_soc_prepare_cpu_on
56 #pragma weak tegra_soc_prepare_cpu_off
57 #pragma weak tegra_soc_prepare_cpu_on_finish
58 
59 int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl)
60 {
61 	return PSCI_E_NOT_SUPPORTED;
62 }
63 
64 int tegra_soc_prepare_cpu_on(unsigned long mpidr)
65 {
66 	return PSCI_E_SUCCESS;
67 }
68 
69 int tegra_soc_prepare_cpu_off(unsigned long mpidr)
70 {
71 	return PSCI_E_SUCCESS;
72 }
73 
74 int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
75 {
76 	return PSCI_E_SUCCESS;
77 }
78 
79 /*******************************************************************************
80  * Track system suspend entry.
81  ******************************************************************************/
82 void tegra_pm_system_suspend_entry(void)
83 {
84 	system_suspended = 1;
85 }
86 
87 /*******************************************************************************
88  * Track system suspend exit.
89  ******************************************************************************/
90 void tegra_pm_system_suspend_exit(void)
91 {
92 	system_suspended = 0;
93 }
94 
95 /*******************************************************************************
96  * Get the system suspend state.
97  ******************************************************************************/
98 int tegra_system_suspended(void)
99 {
100 	return system_suspended;
101 }
102 
103 /*******************************************************************************
104  * Handler called when an affinity instance is about to enter standby.
105  ******************************************************************************/
106 void tegra_affinst_standby(unsigned int power_state)
107 {
108 	/*
109 	 * Enter standby state
110 	 * dsb is good practice before using wfi to enter low power states
111 	 */
112 	dsb();
113 	wfi();
114 }
115 
116 /*******************************************************************************
117  * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
118  * call to get the `power_state` parameter. This allows the platform to encode
119  * the appropriate State-ID field within the `power_state` parameter which can
120  * be utilized in `affinst_suspend()` to suspend to system affinity level.
121 ******************************************************************************/
122 unsigned int tegra_get_sys_suspend_power_state(void)
123 {
124 	unsigned int power_state;
125 
126 	power_state = psci_make_powerstate(PLAT_SYS_SUSPEND_STATE_ID,
127 			PSTATE_TYPE_POWERDOWN, MPIDR_AFFLVL2);
128 
129 	return power_state;
130 }
131 
132 /*******************************************************************************
133  * Handler called to check the validity of the power state parameter.
134  ******************************************************************************/
135 int32_t tegra_validate_power_state(unsigned int power_state)
136 {
137 	return tegra_soc_validate_power_state(power_state);
138 }
139 
140 /*******************************************************************************
141  * Handler called when an affinity instance is about to be turned on. The
142  * level and mpidr determine the affinity instance.
143  ******************************************************************************/
144 int tegra_affinst_on(unsigned long mpidr,
145 		   unsigned long sec_entrypoint,
146 		   unsigned int afflvl,
147 		   unsigned int state)
148 {
149 	int cpu = mpidr & MPIDR_CPU_MASK;
150 
151 	/*
152 	 * Support individual CPU power on only.
153 	 */
154 	if (afflvl > MPIDR_AFFLVL0)
155 		return PSCI_E_SUCCESS;
156 
157 	/*
158 	 * Flush entrypoint variable to PoC since it will be
159 	 * accessed after a reset with the caches turned off.
160 	 */
161 	sec_entry_point[cpu] = sec_entrypoint;
162 	flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
163 
164 	return tegra_soc_prepare_cpu_on(mpidr);
165 }
166 
167 /*******************************************************************************
168  * Handler called when an affinity instance is about to be turned off. The
169  * level determines the affinity instance. The 'state' arg. allows the
170  * platform to decide whether the cluster is being turned off and take apt
171  * actions.
172  *
173  * CAUTION: This function is called with coherent stacks so that caches can be
174  * turned off, flushed and coherency disabled. There is no guarantee that caches
175  * will remain turned on across calls to this function as each affinity level is
176  * dealt with. So do not write & read global variables across calls. It will be
177  * wise to do flush a write to the global to prevent unpredictable results.
178  ******************************************************************************/
179 void tegra_affinst_off(unsigned int afflvl, unsigned int state)
180 {
181 	/*
182 	 * Support individual CPU power off only.
183 	 */
184 	if (afflvl > MPIDR_AFFLVL0)
185 		return;
186 
187 	tegra_soc_prepare_cpu_off(read_mpidr());
188 }
189 
190 /*******************************************************************************
191  * Handler called when an affinity instance is about to be suspended. The
192  * level and mpidr determine the affinity instance. The 'state' arg. allows the
193  * platform to decide whether the cluster is being turned off and take apt
194  * actions.
195  *
196  * CAUTION: This function is called with coherent stacks so that caches can be
197  * turned off, flushed and coherency disabled. There is no guarantee that caches
198  * will remain turned on across calls to this function as each affinity level is
199  * dealt with. So do not write & read global variables across calls. It will be
200  * wise to flush a write to the global variable, to prevent unpredictable
201  * results.
202  ******************************************************************************/
203 void tegra_affinst_suspend(unsigned long sec_entrypoint,
204 			unsigned int afflvl,
205 			unsigned int state)
206 {
207 	int id = psci_get_suspend_stateid();
208 	int cpu = read_mpidr() & MPIDR_CPU_MASK;
209 
210 	if (afflvl > PLATFORM_MAX_AFFLVL)
211 		return;
212 
213 	/*
214 	 * Flush entrypoint variable to PoC since it will be
215 	 * accessed after a reset with the caches turned off.
216 	 */
217 	sec_entry_point[cpu] = sec_entrypoint;
218 	flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
219 
220 	tegra_soc_prepare_cpu_suspend(id, afflvl);
221 
222 	/* disable GICC */
223 	tegra_gic_cpuif_deactivate();
224 }
225 
226 /*******************************************************************************
227  * Handler called when an affinity instance has just been powered on after
228  * being turned off earlier. The level determines the affinity instance.
229  * The 'state' arg. allows the platform to decide whether the cluster was
230  * turned off prior to wakeup and do what's necessary to set it up.
231  ******************************************************************************/
232 void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state)
233 {
234 	plat_params_from_bl2_t *plat_params;
235 
236 	/*
237 	 * Support individual CPU power on only.
238 	 */
239 	if (afflvl > MPIDR_AFFLVL0)
240 		return;
241 
242 	/*
243 	 * Initialize the GIC cpu and distributor interfaces
244 	 */
245 	tegra_gic_setup();
246 
247 	/*
248 	 * Check if we are exiting from deep sleep.
249 	 */
250 	if (tegra_system_suspended()) {
251 
252 		/*
253 		 * Lock scratch registers which hold the CPU vectors.
254 		 */
255 		tegra_pmc_lock_cpu_vectors();
256 
257 		/*
258 		 * SMMU configuration.
259 		 */
260 		tegra_memctrl_setup();
261 
262 		/*
263 		 * Security configuration to allow DRAM/device access.
264 		 */
265 		plat_params = bl31_get_plat_params();
266 		tegra_memctrl_tzdram_setup(tegra_bl31_phys_base,
267 			plat_params->tzdram_size);
268 	}
269 
270 	/*
271 	 * Reset hardware settings.
272 	 */
273 	tegra_soc_prepare_cpu_on_finish(read_mpidr());
274 }
275 
276 /*******************************************************************************
277  * Handler called when an affinity instance has just been powered on after
278  * having been suspended earlier. The level and mpidr determine the affinity
279  * instance.
280  ******************************************************************************/
281 void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state)
282 {
283 	if (afflvl == MPIDR_AFFLVL0)
284 		tegra_affinst_on_finish(afflvl, state);
285 }
286 
287 /*******************************************************************************
288  * Handler called when the system wants to be powered off
289  ******************************************************************************/
290 __dead2 void tegra_system_off(void)
291 {
292 	ERROR("Tegra System Off: operation not handled.\n");
293 	panic();
294 }
295 
296 /*******************************************************************************
297  * Handler called when the system wants to be restarted.
298  ******************************************************************************/
299 __dead2 void tegra_system_reset(void)
300 {
301 	/*
302 	 * Program the PMC in order to restart the system.
303 	 */
304 	tegra_pmc_system_reset();
305 }
306 
307 /*******************************************************************************
308  * Export the platform handlers to enable psci to invoke them
309  ******************************************************************************/
310 static const plat_pm_ops_t tegra_plat_pm_ops = {
311 	.affinst_standby	= tegra_affinst_standby,
312 	.affinst_on		= tegra_affinst_on,
313 	.affinst_off		= tegra_affinst_off,
314 	.affinst_suspend	= tegra_affinst_suspend,
315 	.affinst_on_finish	= tegra_affinst_on_finish,
316 	.affinst_suspend_finish	= tegra_affinst_suspend_finish,
317 	.system_off		= tegra_system_off,
318 	.system_reset		= tegra_system_reset,
319 	.validate_power_state	= tegra_validate_power_state,
320 	.get_sys_suspend_power_state = tegra_get_sys_suspend_power_state
321 };
322 
323 /*******************************************************************************
324  * Export the platform specific power ops & initialize the fvp power controller
325  ******************************************************************************/
326 int platform_setup_pm(const plat_pm_ops_t **plat_ops)
327 {
328 	/*
329 	 * Reset hardware settings.
330 	 */
331 	tegra_soc_prepare_cpu_on_finish(read_mpidr());
332 
333 	/*
334 	 * Initialize PM ops struct
335 	 */
336 	*plat_ops = &tegra_plat_pm_ops;
337 
338 	return 0;
339 }
340