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