xref: /rk3399_ARM-atf/plat/nvidia/tegra/common/tegra_pm.c (revision 7eec50928c6e8f4232ca0a1b69b5efc7c048eb20)
1 /*
2  * Copyright (c) 2015-2016, 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 tegra_sec_entry_point;
48 
49 /*
50  * The following platform setup functions are weakly defined. They
51  * provide typical implementations that will be overridden by a SoC.
52  */
53 #pragma weak tegra_soc_pwr_domain_suspend
54 #pragma weak tegra_soc_pwr_domain_on
55 #pragma weak tegra_soc_pwr_domain_off
56 #pragma weak tegra_soc_pwr_domain_on_finish
57 #pragma weak tegra_soc_pwr_domain_power_down_wfi
58 #pragma weak tegra_soc_prepare_system_reset
59 #pragma weak tegra_soc_prepare_system_off
60 
61 int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
62 {
63 	return PSCI_E_NOT_SUPPORTED;
64 }
65 
66 int tegra_soc_pwr_domain_on(u_register_t mpidr)
67 {
68 	return PSCI_E_SUCCESS;
69 }
70 
71 int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
72 {
73 	return PSCI_E_SUCCESS;
74 }
75 
76 int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
77 {
78 	return PSCI_E_SUCCESS;
79 }
80 
81 int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
82 {
83 	return PSCI_E_SUCCESS;
84 }
85 
86 int tegra_soc_prepare_system_reset(void)
87 {
88 	return PSCI_E_SUCCESS;
89 }
90 
91 __dead2 void tegra_soc_prepare_system_off(void)
92 {
93 	ERROR("Tegra System Off: operation not handled.\n");
94 	panic();
95 }
96 
97 /*******************************************************************************
98  * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
99  * call to get the `power_state` parameter. This allows the platform to encode
100  * the appropriate State-ID field within the `power_state` parameter which can
101  * be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
102 ******************************************************************************/
103 void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state)
104 {
105 	/* lower affinities use PLAT_MAX_OFF_STATE */
106 	for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
107 		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
108 
109 	/* max affinity uses system suspend state id */
110 	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN;
111 }
112 
113 /*******************************************************************************
114  * Handler called when an affinity instance is about to enter standby.
115  ******************************************************************************/
116 void tegra_cpu_standby(plat_local_state_t cpu_state)
117 {
118 	/*
119 	 * Enter standby state
120 	 * dsb is good practice before using wfi to enter low power states
121 	 */
122 	dsb();
123 	wfi();
124 }
125 
126 /*******************************************************************************
127  * Handler called when an affinity instance is about to be turned on. The
128  * level and mpidr determine the affinity instance.
129  ******************************************************************************/
130 int tegra_pwr_domain_on(u_register_t mpidr)
131 {
132 	return tegra_soc_pwr_domain_on(mpidr);
133 }
134 
135 /*******************************************************************************
136  * Handler called when a power domain is about to be turned off. The
137  * target_state encodes the power state that each level should transition to.
138  ******************************************************************************/
139 void tegra_pwr_domain_off(const psci_power_state_t *target_state)
140 {
141 	tegra_soc_pwr_domain_off(target_state);
142 }
143 
144 /*******************************************************************************
145  * Handler called when a power domain is about to be suspended. The
146  * target_state encodes the power state that each level should transition to.
147  ******************************************************************************/
148 void tegra_pwr_domain_suspend(const psci_power_state_t *target_state)
149 {
150 	tegra_soc_pwr_domain_suspend(target_state);
151 
152 	/* disable GICC */
153 	tegra_gic_cpuif_deactivate();
154 }
155 
156 /*******************************************************************************
157  * Handler called at the end of the power domain suspend sequence. The
158  * target_state encodes the power state that each level should transition to.
159  ******************************************************************************/
160 __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t
161 					     *target_state)
162 {
163 	/* call the chip's power down handler */
164 	tegra_soc_pwr_domain_power_down_wfi(target_state);
165 
166 	/* enter power down state */
167 	wfi();
168 
169 	/* we can never reach here */
170 	ERROR("%s: operation not handled.\n", __func__);
171 	panic();
172 }
173 
174 /*******************************************************************************
175  * Handler called when a power domain has just been powered on after
176  * being turned off earlier. The target_state encodes the low power state that
177  * each level has woken up from.
178  ******************************************************************************/
179 void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state)
180 {
181 	plat_params_from_bl2_t *plat_params;
182 
183 	/*
184 	 * Initialize the GIC cpu and distributor interfaces
185 	 */
186 	plat_gic_setup();
187 
188 	/*
189 	 * Check if we are exiting from deep sleep.
190 	 */
191 	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
192 			PSTATE_ID_SOC_POWERDN) {
193 
194 		/*
195 		 * Restore Memory Controller settings as it loses state
196 		 * during system suspend.
197 		 */
198 		tegra_memctrl_restore_settings();
199 
200 		/*
201 		 * Security configuration to allow DRAM/device access.
202 		 */
203 		plat_params = bl31_get_plat_params();
204 		tegra_memctrl_tzdram_setup(plat_params->tzdram_base,
205 			plat_params->tzdram_size);
206 
207 		/*
208 		 * Set up the TZRAM memory aperture to allow only secure world
209 		 * access
210 		 */
211 		tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE);
212 	}
213 
214 	/*
215 	 * Reset hardware settings.
216 	 */
217 	tegra_soc_pwr_domain_on_finish(target_state);
218 }
219 
220 /*******************************************************************************
221  * Handler called when a power domain has just been powered on after
222  * having been suspended earlier. The target_state encodes the low power state
223  * that each level has woken up from.
224  ******************************************************************************/
225 void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
226 {
227 	tegra_pwr_domain_on_finish(target_state);
228 }
229 
230 /*******************************************************************************
231  * Handler called when the system wants to be powered off
232  ******************************************************************************/
233 __dead2 void tegra_system_off(void)
234 {
235 	INFO("Powering down system...\n");
236 
237 	tegra_soc_prepare_system_off();
238 }
239 
240 /*******************************************************************************
241  * Handler called when the system wants to be restarted.
242  ******************************************************************************/
243 __dead2 void tegra_system_reset(void)
244 {
245 	INFO("Restarting system...\n");
246 
247 	/* per-SoC system reset handler */
248 	tegra_soc_prepare_system_reset();
249 
250 	/*
251 	 * Program the PMC in order to restart the system.
252 	 */
253 	tegra_pmc_system_reset();
254 }
255 
256 /*******************************************************************************
257  * Handler called to check the validity of the power state parameter.
258  ******************************************************************************/
259 int32_t tegra_validate_power_state(unsigned int power_state,
260 				   psci_power_state_t *req_state)
261 {
262 	assert(req_state);
263 
264 	return tegra_soc_validate_power_state(power_state, req_state);
265 }
266 
267 /*******************************************************************************
268  * Platform handler called to check the validity of the non secure entrypoint.
269  ******************************************************************************/
270 int tegra_validate_ns_entrypoint(uintptr_t entrypoint)
271 {
272 	/*
273 	 * Check if the non secure entrypoint lies within the non
274 	 * secure DRAM.
275 	 */
276 	if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END))
277 		return PSCI_E_SUCCESS;
278 
279 	return PSCI_E_INVALID_ADDRESS;
280 }
281 
282 /*******************************************************************************
283  * Export the platform handlers to enable psci to invoke them
284  ******************************************************************************/
285 static const plat_psci_ops_t tegra_plat_psci_ops = {
286 	.cpu_standby			= tegra_cpu_standby,
287 	.pwr_domain_on			= tegra_pwr_domain_on,
288 	.pwr_domain_off			= tegra_pwr_domain_off,
289 	.pwr_domain_suspend		= tegra_pwr_domain_suspend,
290 	.pwr_domain_on_finish		= tegra_pwr_domain_on_finish,
291 	.pwr_domain_suspend_finish	= tegra_pwr_domain_suspend_finish,
292 	.pwr_domain_pwr_down_wfi	= tegra_pwr_domain_power_down_wfi,
293 	.system_off			= tegra_system_off,
294 	.system_reset			= tegra_system_reset,
295 	.validate_power_state		= tegra_validate_power_state,
296 	.validate_ns_entrypoint		= tegra_validate_ns_entrypoint,
297 	.get_sys_suspend_power_state	= tegra_get_sys_suspend_power_state,
298 };
299 
300 /*******************************************************************************
301  * Export the platform specific power ops and initialize Power Controller
302  ******************************************************************************/
303 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
304 			const plat_psci_ops_t **psci_ops)
305 {
306 	psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } };
307 
308 	/*
309 	 * Flush entrypoint variable to PoC since it will be
310 	 * accessed after a reset with the caches turned off.
311 	 */
312 	tegra_sec_entry_point = sec_entrypoint;
313 	flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t));
314 
315 	/*
316 	 * Reset hardware settings.
317 	 */
318 	tegra_soc_pwr_domain_on_finish(&target_state);
319 
320 	/*
321 	 * Initialize PSCI ops struct
322 	 */
323 	*psci_ops = &tegra_plat_psci_ops;
324 
325 	return 0;
326 }
327 
328 /*******************************************************************************
329  * Platform handler to calculate the proper target power level at the
330  * specified affinity level
331  ******************************************************************************/
332 plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
333 					     const plat_local_state_t *states,
334 					     unsigned int ncpu)
335 {
336 	plat_local_state_t target = PLAT_MAX_RET_STATE, temp;
337 
338 	assert(ncpu);
339 
340 	do {
341 		temp = *states++;
342 		if ((temp > target) && (temp != PLAT_MAX_OFF_STATE))
343 			target = temp;
344 	} while (--ncpu);
345 
346 	return target;
347 }
348