xref: /rk3399_ARM-atf/plat/nvidia/tegra/common/tegra_pm.c (revision 7d37aa171158422b5ee7ee6c3cdad58f6aa066b4)
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_prepare_cpu_suspend
55 #pragma weak tegra_prepare_cpu_on
56 #pragma weak tegra_prepare_cpu_off
57 #pragma weak tegra_prepare_cpu_on_finish
58 
59 int tegra_prepare_cpu_suspend(unsigned int id, unsigned int afflvl)
60 {
61 	return PSCI_E_NOT_SUPPORTED;
62 }
63 
64 int tegra_prepare_cpu_on(unsigned long mpidr)
65 {
66 	return PSCI_E_SUCCESS;
67 }
68 
69 int tegra_prepare_cpu_off(unsigned long mpidr)
70 {
71 	return PSCI_E_SUCCESS;
72 }
73 
74 int tegra_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  * Handler called to check the validity of the power state parameter.
118  ******************************************************************************/
119 int32_t tegra_validate_power_state(unsigned int power_state)
120 {
121 	/* Sanity check the requested state */
122 	if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
123 		/*
124 		 * It's possible to enter standby only on affinity level 0 i.e.
125 		 * a cpu on Tegra. Ignore any other affinity level.
126 		 */
127 		if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0)
128 			return PSCI_E_INVALID_PARAMS;
129 	}
130 
131 	return PSCI_E_SUCCESS;
132 }
133 
134 /*******************************************************************************
135  * Handler called when an affinity instance is about to be turned on. The
136  * level and mpidr determine the affinity instance.
137  ******************************************************************************/
138 int tegra_affinst_on(unsigned long mpidr,
139 		   unsigned long sec_entrypoint,
140 		   unsigned int afflvl,
141 		   unsigned int state)
142 {
143 	int cpu = mpidr & MPIDR_CPU_MASK;
144 
145 	/*
146 	 * Support individual CPU power on only.
147 	 */
148 	if (afflvl > MPIDR_AFFLVL0)
149 		return PSCI_E_SUCCESS;
150 
151 	/*
152 	 * Flush entrypoint variable to PoC since it will be
153 	 * accessed after a reset with the caches turned off.
154 	 */
155 	sec_entry_point[cpu] = sec_entrypoint;
156 	flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
157 
158 	return tegra_prepare_cpu_on(mpidr);
159 }
160 
161 /*******************************************************************************
162  * Handler called when an affinity instance is about to be turned off. The
163  * level determines the affinity instance. The 'state' arg. allows the
164  * platform to decide whether the cluster is being turned off and take apt
165  * actions.
166  *
167  * CAUTION: This function is called with coherent stacks so that caches can be
168  * turned off, flushed and coherency disabled. There is no guarantee that caches
169  * will remain turned on across calls to this function as each affinity level is
170  * dealt with. So do not write & read global variables across calls. It will be
171  * wise to do flush a write to the global to prevent unpredictable results.
172  ******************************************************************************/
173 void tegra_affinst_off(unsigned int afflvl, unsigned int state)
174 {
175 	/*
176 	 * Support individual CPU power off only.
177 	 */
178 	if (afflvl > MPIDR_AFFLVL0)
179 		return;
180 
181 	tegra_prepare_cpu_off(read_mpidr());
182 }
183 
184 /*******************************************************************************
185  * Handler called when an affinity instance is about to be suspended. The
186  * level and mpidr determine the affinity instance. The 'state' arg. allows the
187  * platform to decide whether the cluster is being turned off and take apt
188  * actions.
189  *
190  * CAUTION: This function is called with coherent stacks so that caches can be
191  * turned off, flushed and coherency disabled. There is no guarantee that caches
192  * will remain turned on across calls to this function as each affinity level is
193  * dealt with. So do not write & read global variables across calls. It will be
194  * wise to flush a write to the global variable, to prevent unpredictable
195  * results.
196  ******************************************************************************/
197 void tegra_affinst_suspend(unsigned long sec_entrypoint,
198 			unsigned int afflvl,
199 			unsigned int state)
200 {
201 	int id = psci_get_suspend_stateid();
202 	int cpu = read_mpidr() & MPIDR_CPU_MASK;
203 
204 	if (afflvl > PLATFORM_MAX_AFFLVL)
205 		return;
206 
207 	/*
208 	 * Flush entrypoint variable to PoC since it will be
209 	 * accessed after a reset with the caches turned off.
210 	 */
211 	sec_entry_point[cpu] = sec_entrypoint;
212 	flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t));
213 
214 	tegra_prepare_cpu_suspend(id, afflvl);
215 
216 	/* disable GICC */
217 	tegra_gic_cpuif_deactivate();
218 }
219 
220 /*******************************************************************************
221  * Handler called when an affinity instance has just been powered on after
222  * being turned off earlier. The level determines the affinity instance.
223  * The 'state' arg. allows the platform to decide whether the cluster was
224  * turned off prior to wakeup and do what's necessary to set it up.
225  ******************************************************************************/
226 void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state)
227 {
228 	plat_params_from_bl2_t *plat_params;
229 
230 	/*
231 	 * Support individual CPU power on only.
232 	 */
233 	if (afflvl > MPIDR_AFFLVL0)
234 		return;
235 
236 	/*
237 	 * Initialize the GIC cpu and distributor interfaces
238 	 */
239 	tegra_gic_setup();
240 
241 	/*
242 	 * Check if we are exiting from deep sleep.
243 	 */
244 	if (tegra_system_suspended()) {
245 
246 		/*
247 		 * Lock scratch registers which hold the CPU vectors.
248 		 */
249 		tegra_pmc_lock_cpu_vectors();
250 
251 		/*
252 		 * SMMU configuration.
253 		 */
254 		tegra_memctrl_setup();
255 
256 		/*
257 		 * Security configuration to allow DRAM/device access.
258 		 */
259 		plat_params = bl31_get_plat_params();
260 		tegra_memctrl_tzdram_setup(tegra_bl31_phys_base,
261 			plat_params->tzdram_size);
262 	}
263 
264 	/*
265 	 * Reset hardware settings.
266 	 */
267 	tegra_prepare_cpu_on_finish(read_mpidr());
268 }
269 
270 /*******************************************************************************
271  * Handler called when an affinity instance has just been powered on after
272  * having been suspended earlier. The level and mpidr determine the affinity
273  * instance.
274  ******************************************************************************/
275 void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state)
276 {
277 	if (afflvl == MPIDR_AFFLVL0)
278 		tegra_affinst_on_finish(afflvl, state);
279 }
280 
281 /*******************************************************************************
282  * Handler called when the system wants to be powered off
283  ******************************************************************************/
284 __dead2 void tegra_system_off(void)
285 {
286 	ERROR("Tegra System Off: operation not handled.\n");
287 	panic();
288 }
289 
290 /*******************************************************************************
291  * Handler called when the system wants to be restarted.
292  ******************************************************************************/
293 __dead2 void tegra_system_reset(void)
294 {
295 	/*
296 	 * Program the PMC in order to restart the system.
297 	 */
298 	tegra_pmc_system_reset();
299 }
300 
301 /*******************************************************************************
302  * Export the platform handlers to enable psci to invoke them
303  ******************************************************************************/
304 static const plat_pm_ops_t tegra_plat_pm_ops = {
305 	.affinst_standby	= tegra_affinst_standby,
306 	.affinst_on		= tegra_affinst_on,
307 	.affinst_off		= tegra_affinst_off,
308 	.affinst_suspend	= tegra_affinst_suspend,
309 	.affinst_on_finish	= tegra_affinst_on_finish,
310 	.affinst_suspend_finish	= tegra_affinst_suspend_finish,
311 	.system_off		= tegra_system_off,
312 	.system_reset		= tegra_system_reset,
313 	.validate_power_state	= tegra_validate_power_state
314 };
315 
316 /*******************************************************************************
317  * Export the platform specific power ops & initialize the fvp power controller
318  ******************************************************************************/
319 int platform_setup_pm(const plat_pm_ops_t **plat_ops)
320 {
321 	/*
322 	 * Reset hardware settings.
323 	 */
324 	tegra_prepare_cpu_on_finish(read_mpidr());
325 
326 	/*
327 	 * Initialize PM ops struct
328 	 */
329 	*plat_ops = &tegra_plat_pm_ops;
330 
331 	return 0;
332 }
333