Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch_helpers.h>
      8 #include <assert.h>
      9 #include <bl_common.h>
     10 #include <console.h>
     11 #include <context.h>
     12 #include <context_mgmt.h>
     13 #include <debug.h>
     14 #include <memctrl.h>
     15 #include <mmio.h>
     16 #include <platform.h>
     17 #include <platform_def.h>
     18 #include <pmc.h>
     19 #include <psci.h>
     20 #include <tegra_def.h>
     21 #include <tegra_private.h>
     22 
     23 extern uint64_t tegra_bl31_phys_base;
     24 extern uint64_t tegra_sec_entry_point;
     25 extern uint64_t tegra_console_base;
     26 
     27 /*
     28  * tegra_fake_system_suspend acts as a boolean var controlling whether
     29  * we are going to take fake system suspend code or normal system suspend code
     30  * path. This variable is set inside the sip call handlers,when the kernel
     31  * requests a SIP call to set the suspend debug flags.
     32  */
     33 uint8_t tegra_fake_system_suspend;
     34 
     35 /*
     36  * The following platform setup functions are weakly defined. They
     37  * provide typical implementations that will be overridden by a SoC.
     38  */
     39 #pragma weak tegra_soc_pwr_domain_suspend_pwrdown_early
     40 #pragma weak tegra_soc_pwr_domain_suspend
     41 #pragma weak tegra_soc_pwr_domain_on
     42 #pragma weak tegra_soc_pwr_domain_off
     43 #pragma weak tegra_soc_pwr_domain_on_finish
     44 #pragma weak tegra_soc_pwr_domain_power_down_wfi
     45 #pragma weak tegra_soc_prepare_system_reset
     46 #pragma weak tegra_soc_prepare_system_off
     47 #pragma weak tegra_soc_get_target_pwr_state
     48 
     49 int tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
     50 {
     51 	return PSCI_E_NOT_SUPPORTED;
     52 }
     53 
     54 int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
     55 {
     56 	return PSCI_E_NOT_SUPPORTED;
     57 }
     58 
     59 int tegra_soc_pwr_domain_on(u_register_t mpidr)
     60 {
     61 	return PSCI_E_SUCCESS;
     62 }
     63 
     64 int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
     65 {
     66 	return PSCI_E_SUCCESS;
     67 }
     68 
     69 int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
     70 {
     71 	return PSCI_E_SUCCESS;
     72 }
     73 
     74 int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
     75 {
     76 	return PSCI_E_SUCCESS;
     77 }
     78 
     79 int tegra_soc_prepare_system_reset(void)
     80 {
     81 	return PSCI_E_SUCCESS;
     82 }
     83 
     84 __dead2 void tegra_soc_prepare_system_off(void)
     85 {
     86 	ERROR("Tegra System Off: operation not handled.\n");
     87 	panic();
     88 }
     89 
     90 plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
     91 					     const plat_local_state_t *states,
     92 					     unsigned int ncpu)
     93 {
     94 	plat_local_state_t target = PLAT_MAX_OFF_STATE, temp;
     95 
     96 	assert(ncpu);
     97 
     98 	do {
     99 		temp = *states++;
    100 		if ((temp < target))
    101 			target = temp;
    102 	} while (--ncpu);
    103 
    104 	return target;
    105 }
    106 
    107 /*******************************************************************************
    108  * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
    109  * call to get the `power_state` parameter. This allows the platform to encode
    110  * the appropriate State-ID field within the `power_state` parameter which can
    111  * be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
    112 ******************************************************************************/
    113 void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state)
    114 {
    115 	/* all affinities use system suspend state id */
    116 	for (uint32_t i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
    117 		req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN;
    118 }
    119 
    120 /*******************************************************************************
    121  * Handler called when an affinity instance is about to enter standby.
    122  ******************************************************************************/
    123 void tegra_cpu_standby(plat_local_state_t cpu_state)
    124 {
    125 	/*
    126 	 * Enter standby state
    127 	 * dsb is good practice before using wfi to enter low power states
    128 	 */
    129 	dsb();
    130 	wfi();
    131 }
    132 
    133 /*******************************************************************************
    134  * Handler called when an affinity instance is about to be turned on. The
    135  * level and mpidr determine the affinity instance.
    136  ******************************************************************************/
    137 int tegra_pwr_domain_on(u_register_t mpidr)
    138 {
    139 	return tegra_soc_pwr_domain_on(mpidr);
    140 }
    141 
    142 /*******************************************************************************
    143  * Handler called when a power domain is about to be turned off. The
    144  * target_state encodes the power state that each level should transition to.
    145  ******************************************************************************/
    146 void tegra_pwr_domain_off(const psci_power_state_t *target_state)
    147 {
    148 	tegra_soc_pwr_domain_off(target_state);
    149 }
    150 
    151 /*******************************************************************************
    152  * Handler called when a power domain is about to be suspended. The
    153  * target_state encodes the power state that each level should transition to.
    154  * This handler is called with SMP and data cache enabled, when
    155  * HW_ASSISTED_COHERENCY = 0
    156  ******************************************************************************/
    157 void tegra_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
    158 {
    159 	tegra_soc_pwr_domain_suspend_pwrdown_early(target_state);
    160 }
    161 
    162 /*******************************************************************************
    163  * Handler called when a power domain is about to be suspended. The
    164  * target_state encodes the power state that each level should transition to.
    165  ******************************************************************************/
    166 void tegra_pwr_domain_suspend(const psci_power_state_t *target_state)
    167 {
    168 	tegra_soc_pwr_domain_suspend(target_state);
    169 
    170 	/* Disable console if we are entering deep sleep. */
    171 	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
    172 			PSTATE_ID_SOC_POWERDN)
    173 		console_uninit();
    174 
    175 	/* disable GICC */
    176 	tegra_gic_cpuif_deactivate();
    177 }
    178 
    179 /*******************************************************************************
    180  * Handler called at the end of the power domain suspend sequence. The
    181  * target_state encodes the power state that each level should transition to.
    182  ******************************************************************************/
    183 __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t
    184 					     *target_state)
    185 {
    186 	uint8_t pwr_state = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
    187 	uint64_t rmr_el3 = 0;
    188 
    189 	/* call the chip's power down handler */
    190 	tegra_soc_pwr_domain_power_down_wfi(target_state);
    191 
    192 	/*
    193 	 * If we are in fake system suspend mode, ensure we start doing
    194 	 * procedures that help in looping back towards system suspend exit
    195 	 * instead of calling WFI by requesting a warm reset.
    196 	 * Else, just call WFI to enter low power state.
    197 	 */
    198 	if ((tegra_fake_system_suspend != 0U) &&
    199 	    (pwr_state == (uint8_t)PSTATE_ID_SOC_POWERDN)) {
    200 
    201 		/* warm reboot */
    202 		rmr_el3 = read_rmr_el3();
    203 		write_rmr_el3(rmr_el3 | RMR_WARM_RESET_CPU);
    204 
    205 	} else {
    206 		/* enter power down state */
    207 		wfi();
    208 	}
    209 
    210 	/* we can never reach here */
    211 	panic();
    212 }
    213 
    214 /*******************************************************************************
    215  * Handler called when a power domain has just been powered on after
    216  * being turned off earlier. The target_state encodes the low power state that
    217  * each level has woken up from.
    218  ******************************************************************************/
    219 void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state)
    220 {
    221 	plat_params_from_bl2_t *plat_params;
    222 
    223 	/*
    224 	 * Initialize the GIC cpu and distributor interfaces
    225 	 */
    226 	plat_gic_setup();
    227 
    228 	/*
    229 	 * Check if we are exiting from deep sleep.
    230 	 */
    231 	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
    232 			PSTATE_ID_SOC_POWERDN) {
    233 
    234 		/* Initialize the runtime console */
    235 		if (tegra_console_base != (uint64_t)0) {
    236 			console_init(tegra_console_base, TEGRA_BOOT_UART_CLK_IN_HZ,
    237 				TEGRA_CONSOLE_BAUDRATE);
    238 		}
    239 
    240 		/*
    241 		 * Restore Memory Controller settings as it loses state
    242 		 * during system suspend.
    243 		 */
    244 		tegra_memctrl_restore_settings();
    245 
    246 		/*
    247 		 * Security configuration to allow DRAM/device access.
    248 		 */
    249 		plat_params = bl31_get_plat_params();
    250 		tegra_memctrl_tzdram_setup(plat_params->tzdram_base,
    251 			plat_params->tzdram_size);
    252 
    253 		/*
    254 		 * Set up the TZRAM memory aperture to allow only secure world
    255 		 * access
    256 		 */
    257 		tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE);
    258 	}
    259 
    260 	/*
    261 	 * Reset hardware settings.
    262 	 */
    263 	tegra_soc_pwr_domain_on_finish(target_state);
    264 }
    265 
    266 /*******************************************************************************
    267  * Handler called when a power domain has just been powered on after
    268  * having been suspended earlier. The target_state encodes the low power state
    269  * that each level has woken up from.
    270  ******************************************************************************/
    271 void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
    272 {
    273 	tegra_pwr_domain_on_finish(target_state);
    274 }
    275 
    276 /*******************************************************************************
    277  * Handler called when the system wants to be powered off
    278  ******************************************************************************/
    279 __dead2 void tegra_system_off(void)
    280 {
    281 	INFO("Powering down system...\n");
    282 
    283 	tegra_soc_prepare_system_off();
    284 }
    285 
    286 /*******************************************************************************
    287  * Handler called when the system wants to be restarted.
    288  ******************************************************************************/
    289 __dead2 void tegra_system_reset(void)
    290 {
    291 	INFO("Restarting system...\n");
    292 
    293 	/* per-SoC system reset handler */
    294 	tegra_soc_prepare_system_reset();
    295 
    296 	/*
    297 	 * Program the PMC in order to restart the system.
    298 	 */
    299 	tegra_pmc_system_reset();
    300 }
    301 
    302 /*******************************************************************************
    303  * Handler called to check the validity of the power state parameter.
    304  ******************************************************************************/
    305 int32_t tegra_validate_power_state(unsigned int power_state,
    306 				   psci_power_state_t *req_state)
    307 {
    308 	assert(req_state);
    309 
    310 	return tegra_soc_validate_power_state(power_state, req_state);
    311 }
    312 
    313 /*******************************************************************************
    314  * Platform handler called to check the validity of the non secure entrypoint.
    315  ******************************************************************************/
    316 int tegra_validate_ns_entrypoint(uintptr_t entrypoint)
    317 {
    318 	/*
    319 	 * Check if the non secure entrypoint lies within the non
    320 	 * secure DRAM.
    321 	 */
    322 	if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END))
    323 		return PSCI_E_SUCCESS;
    324 
    325 	return PSCI_E_INVALID_ADDRESS;
    326 }
    327 
    328 /*******************************************************************************
    329  * Export the platform handlers to enable psci to invoke them
    330  ******************************************************************************/
    331 static const plat_psci_ops_t tegra_plat_psci_ops = {
    332 	.cpu_standby			= tegra_cpu_standby,
    333 	.pwr_domain_on			= tegra_pwr_domain_on,
    334 	.pwr_domain_off			= tegra_pwr_domain_off,
    335 	.pwr_domain_suspend_pwrdown_early = tegra_pwr_domain_suspend_pwrdown_early,
    336 	.pwr_domain_suspend		= tegra_pwr_domain_suspend,
    337 	.pwr_domain_on_finish		= tegra_pwr_domain_on_finish,
    338 	.pwr_domain_suspend_finish	= tegra_pwr_domain_suspend_finish,
    339 	.pwr_domain_pwr_down_wfi	= tegra_pwr_domain_power_down_wfi,
    340 	.system_off			= tegra_system_off,
    341 	.system_reset			= tegra_system_reset,
    342 	.validate_power_state		= tegra_validate_power_state,
    343 	.validate_ns_entrypoint		= tegra_validate_ns_entrypoint,
    344 	.get_sys_suspend_power_state	= tegra_get_sys_suspend_power_state,
    345 };
    346 
    347 /*******************************************************************************
    348  * Export the platform specific power ops and initialize Power Controller
    349  ******************************************************************************/
    350 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
    351 			const plat_psci_ops_t **psci_ops)
    352 {
    353 	psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } };
    354 
    355 	/*
    356 	 * Flush entrypoint variable to PoC since it will be
    357 	 * accessed after a reset with the caches turned off.
    358 	 */
    359 	tegra_sec_entry_point = sec_entrypoint;
    360 	flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t));
    361 
    362 	/*
    363 	 * Reset hardware settings.
    364 	 */
    365 	tegra_soc_pwr_domain_on_finish(&target_state);
    366 
    367 	/*
    368 	 * Initialize PSCI ops struct
    369 	 */
    370 	*psci_ops = &tegra_plat_psci_ops;
    371 
    372 	return 0;
    373 }
    374 
    375 /*******************************************************************************
    376  * Platform handler to calculate the proper target power level at the
    377  * specified affinity level
    378  ******************************************************************************/
    379 plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
    380 					     const plat_local_state_t *states,
    381 					     unsigned int ncpu)
    382 {
    383 	return tegra_soc_get_target_pwr_state(lvl, states, ncpu);
    384 }
    385