xref: /rk3399_ARM-atf/plat/nvidia/tegra/common/tegra_pm.c (revision e40e075f4ddf63aa84d2aaacb807ed40438f1d24)
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 	tegra_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 	/*
209 	 * Reset hardware settings.
210 	 */
211 	tegra_soc_pwr_domain_on_finish(target_state);
212 }
213 
214 /*******************************************************************************
215  * Handler called when a power domain has just been powered on after
216  * having been suspended earlier. The target_state encodes the low power state
217  * that each level has woken up from.
218  ******************************************************************************/
219 void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
220 {
221 	tegra_pwr_domain_on_finish(target_state);
222 }
223 
224 /*******************************************************************************
225  * Handler called when the system wants to be powered off
226  ******************************************************************************/
227 __dead2 void tegra_system_off(void)
228 {
229 	INFO("Powering down system...\n");
230 
231 	tegra_soc_prepare_system_off();
232 }
233 
234 /*******************************************************************************
235  * Handler called when the system wants to be restarted.
236  ******************************************************************************/
237 __dead2 void tegra_system_reset(void)
238 {
239 	INFO("Restarting system...\n");
240 
241 	/* per-SoC system reset handler */
242 	tegra_soc_prepare_system_reset();
243 
244 	/*
245 	 * Program the PMC in order to restart the system.
246 	 */
247 	tegra_pmc_system_reset();
248 }
249 
250 /*******************************************************************************
251  * Handler called to check the validity of the power state parameter.
252  ******************************************************************************/
253 int32_t tegra_validate_power_state(unsigned int power_state,
254 				   psci_power_state_t *req_state)
255 {
256 	assert(req_state);
257 
258 	return tegra_soc_validate_power_state(power_state, req_state);
259 }
260 
261 /*******************************************************************************
262  * Platform handler called to check the validity of the non secure entrypoint.
263  ******************************************************************************/
264 int tegra_validate_ns_entrypoint(uintptr_t entrypoint)
265 {
266 	/*
267 	 * Check if the non secure entrypoint lies within the non
268 	 * secure DRAM.
269 	 */
270 	if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END))
271 		return PSCI_E_SUCCESS;
272 
273 	return PSCI_E_INVALID_ADDRESS;
274 }
275 
276 /*******************************************************************************
277  * Export the platform handlers to enable psci to invoke them
278  ******************************************************************************/
279 static const plat_psci_ops_t tegra_plat_psci_ops = {
280 	.cpu_standby			= tegra_cpu_standby,
281 	.pwr_domain_on			= tegra_pwr_domain_on,
282 	.pwr_domain_off			= tegra_pwr_domain_off,
283 	.pwr_domain_suspend		= tegra_pwr_domain_suspend,
284 	.pwr_domain_on_finish		= tegra_pwr_domain_on_finish,
285 	.pwr_domain_suspend_finish	= tegra_pwr_domain_suspend_finish,
286 	.pwr_domain_pwr_down_wfi	= tegra_pwr_domain_power_down_wfi,
287 	.system_off			= tegra_system_off,
288 	.system_reset			= tegra_system_reset,
289 	.validate_power_state		= tegra_validate_power_state,
290 	.validate_ns_entrypoint		= tegra_validate_ns_entrypoint,
291 	.get_sys_suspend_power_state	= tegra_get_sys_suspend_power_state,
292 };
293 
294 /*******************************************************************************
295  * Export the platform specific power ops and initialize Power Controller
296  ******************************************************************************/
297 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
298 			const plat_psci_ops_t **psci_ops)
299 {
300 	psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } };
301 
302 	/*
303 	 * Flush entrypoint variable to PoC since it will be
304 	 * accessed after a reset with the caches turned off.
305 	 */
306 	tegra_sec_entry_point = sec_entrypoint;
307 	flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t));
308 
309 	/*
310 	 * Reset hardware settings.
311 	 */
312 	tegra_soc_pwr_domain_on_finish(&target_state);
313 
314 	/*
315 	 * Initialize PSCI ops struct
316 	 */
317 	*psci_ops = &tegra_plat_psci_ops;
318 
319 	return 0;
320 }
321