108438e24SVarun Wadekar /* 2831b0e98SJimmy Brisson * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. 396d07af4SVarun Wadekar * Copyright (c) 2020-2023, NVIDIA Corporation. All rights reserved. 408438e24SVarun Wadekar * 582cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 608438e24SVarun Wadekar */ 708438e24SVarun Wadekar 808438e24SVarun Wadekar #include <assert.h> 909d40e0eSAntonio Nino Diaz 1008438e24SVarun Wadekar #include <platform_def.h> 1109d40e0eSAntonio Nino Diaz 1209d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 1309d40e0eSAntonio Nino Diaz #include <common/bl_common.h> 1409d40e0eSAntonio Nino Diaz #include <common/debug.h> 1509d40e0eSAntonio Nino Diaz #include <context.h> 1609d40e0eSAntonio Nino Diaz #include <drivers/console.h> 1709d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/context_mgmt.h> 1809d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 1909d40e0eSAntonio Nino Diaz #include <lib/psci/psci.h> 2009d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 2109d40e0eSAntonio Nino Diaz 2209d40e0eSAntonio Nino Diaz #include <memctrl.h> 2308438e24SVarun Wadekar #include <pmc.h> 2408438e24SVarun Wadekar #include <tegra_def.h> 25322e7c3eSHarvey Hsieh #include <tegra_platform.h> 2608438e24SVarun Wadekar #include <tegra_private.h> 2708438e24SVarun Wadekar 2808438e24SVarun Wadekar extern uint64_t tegra_bl31_phys_base; 2971cb26eaSVarun Wadekar extern uint64_t tegra_sec_entry_point; 3008438e24SVarun Wadekar 3108438e24SVarun Wadekar /******************************************************************************* 3271cb26eaSVarun Wadekar * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` 3371cb26eaSVarun Wadekar * call to get the `power_state` parameter. This allows the platform to encode 3471cb26eaSVarun Wadekar * the appropriate State-ID field within the `power_state` parameter which can 3571cb26eaSVarun Wadekar * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. 3608438e24SVarun Wadekar ******************************************************************************/ 3757e92dafSDavid Pu static void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) 3808438e24SVarun Wadekar { 39a7cd0953SVarun Wadekar /* all affinities use system suspend state id */ 40b36aea5aSAnthony Zhou for (uint32_t i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) { 41a7cd0953SVarun Wadekar req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN; 4208438e24SVarun Wadekar } 43b36aea5aSAnthony Zhou } 4408438e24SVarun Wadekar 4508438e24SVarun Wadekar /******************************************************************************* 4608438e24SVarun Wadekar * Handler called when an affinity instance is about to enter standby. 4708438e24SVarun Wadekar ******************************************************************************/ 4857e92dafSDavid Pu static void tegra_cpu_standby(plat_local_state_t cpu_state) 4908438e24SVarun Wadekar { 5007faf4d8SVignesh Radhakrishnan u_register_t saved_scr_el3; 5107faf4d8SVignesh Radhakrishnan 52b36aea5aSAnthony Zhou (void)cpu_state; 53b36aea5aSAnthony Zhou 540887026eSVarun Wadekar /* Tegra SoC specific handler */ 550887026eSVarun Wadekar if (tegra_soc_cpu_standby(cpu_state) != PSCI_E_SUCCESS) 560887026eSVarun Wadekar ERROR("%s failed\n", __func__); 570887026eSVarun Wadekar 5807faf4d8SVignesh Radhakrishnan saved_scr_el3 = read_scr_el3(); 5907faf4d8SVignesh Radhakrishnan 6007faf4d8SVignesh Radhakrishnan /* 6107faf4d8SVignesh Radhakrishnan * As per ARM ARM D1.17.2, any physical IRQ interrupt received by the 6207faf4d8SVignesh Radhakrishnan * PE will be treated as a wake-up event, if SCR_EL3.IRQ is set to '1', 6307faf4d8SVignesh Radhakrishnan * irrespective of the value of the PSTATE.I bit value. 6407faf4d8SVignesh Radhakrishnan */ 6507faf4d8SVignesh Radhakrishnan write_scr_el3(saved_scr_el3 | SCR_IRQ_BIT); 6607faf4d8SVignesh Radhakrishnan 6708438e24SVarun Wadekar /* 6808438e24SVarun Wadekar * Enter standby state 6907faf4d8SVignesh Radhakrishnan * 7007faf4d8SVignesh Radhakrishnan * dsb & isb is good practice before using wfi to enter low power states 7108438e24SVarun Wadekar */ 7208438e24SVarun Wadekar dsb(); 7307faf4d8SVignesh Radhakrishnan isb(); 7408438e24SVarun Wadekar wfi(); 7507faf4d8SVignesh Radhakrishnan 7607faf4d8SVignesh Radhakrishnan /* 7707faf4d8SVignesh Radhakrishnan * Restore saved scr_el3 that has IRQ bit cleared as we don't want EL3 7807faf4d8SVignesh Radhakrishnan * handling any further interrupts 7907faf4d8SVignesh Radhakrishnan */ 8007faf4d8SVignesh Radhakrishnan write_scr_el3(saved_scr_el3); 8108438e24SVarun Wadekar } 8208438e24SVarun Wadekar 8308438e24SVarun Wadekar /******************************************************************************* 8408438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned on. The 8508438e24SVarun Wadekar * level and mpidr determine the affinity instance. 8608438e24SVarun Wadekar ******************************************************************************/ 8757e92dafSDavid Pu static int32_t tegra_pwr_domain_on(u_register_t mpidr) 8808438e24SVarun Wadekar { 8971cb26eaSVarun Wadekar return tegra_soc_pwr_domain_on(mpidr); 9008438e24SVarun Wadekar } 9108438e24SVarun Wadekar 9208438e24SVarun Wadekar /******************************************************************************* 9371cb26eaSVarun Wadekar * Handler called when a power domain is about to be turned off. The 9471cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 9596d07af4SVarun Wadekar * Return error if CPU off sequence is not allowed for the current core. 9696d07af4SVarun Wadekar ******************************************************************************/ 9796d07af4SVarun Wadekar static int tegra_pwr_domain_off_early(const psci_power_state_t *target_state) 9896d07af4SVarun Wadekar { 9996d07af4SVarun Wadekar return tegra_soc_pwr_domain_off_early(target_state); 10096d07af4SVarun Wadekar } 10196d07af4SVarun Wadekar 10296d07af4SVarun Wadekar /******************************************************************************* 10396d07af4SVarun Wadekar * Handler called when a power domain is about to be turned off. The 10496d07af4SVarun Wadekar * target_state encodes the power state that each level should transition to. 10508438e24SVarun Wadekar ******************************************************************************/ 10657e92dafSDavid Pu static void tegra_pwr_domain_off(const psci_power_state_t *target_state) 10708438e24SVarun Wadekar { 108b36aea5aSAnthony Zhou (void)tegra_soc_pwr_domain_off(target_state); 109c23f5e1cSanzhou 110c23f5e1cSanzhou /* disable GICC */ 111c23f5e1cSanzhou tegra_gic_cpuif_deactivate(); 11208438e24SVarun Wadekar } 11308438e24SVarun Wadekar 11408438e24SVarun Wadekar /******************************************************************************* 11526c0d9b2SVarun Wadekar * Handler called when a power domain is about to be suspended. The 11671cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 117cb95a19aSVarun Wadekar * This handler is called with SMP and data cache enabled, when 118cb95a19aSVarun Wadekar * HW_ASSISTED_COHERENCY = 0 119cb95a19aSVarun Wadekar ******************************************************************************/ 120cb95a19aSVarun Wadekar void tegra_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state) 121cb95a19aSVarun Wadekar { 122cb95a19aSVarun Wadekar tegra_soc_pwr_domain_suspend_pwrdown_early(target_state); 123cb95a19aSVarun Wadekar } 124cb95a19aSVarun Wadekar 125cb95a19aSVarun Wadekar /******************************************************************************* 126cb95a19aSVarun Wadekar * Handler called when a power domain is about to be suspended. The 127cb95a19aSVarun Wadekar * target_state encodes the power state that each level should transition to. 12808438e24SVarun Wadekar ******************************************************************************/ 12957e92dafSDavid Pu static void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) 13008438e24SVarun Wadekar { 131b36aea5aSAnthony Zhou (void)tegra_soc_pwr_domain_suspend(target_state); 13208438e24SVarun Wadekar 13308438e24SVarun Wadekar /* disable GICC */ 13408438e24SVarun Wadekar tegra_gic_cpuif_deactivate(); 13508438e24SVarun Wadekar } 13608438e24SVarun Wadekar 13708438e24SVarun Wadekar /******************************************************************************* 13826c0d9b2SVarun Wadekar * Handler called at the end of the power domain suspend sequence. The 13926c0d9b2SVarun Wadekar * target_state encodes the power state that each level should transition to. 14026c0d9b2SVarun Wadekar ******************************************************************************/ 14157e92dafSDavid Pu static __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t 14226c0d9b2SVarun Wadekar *target_state) 14326c0d9b2SVarun Wadekar { 14426c0d9b2SVarun Wadekar /* call the chip's power down handler */ 145b36aea5aSAnthony Zhou (void)tegra_soc_pwr_domain_power_down_wfi(target_state); 14626c0d9b2SVarun Wadekar 1470ce729b1SVarun Wadekar /* Disable console if we are entering deep sleep. */ 1480ce729b1SVarun Wadekar if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == 1490ce729b1SVarun Wadekar PSTATE_ID_SOC_POWERDN) { 1500ce729b1SVarun Wadekar INFO("%s: complete. Entering System Suspend...\n", __func__); 151831b0e98SJimmy Brisson console_flush(); 1520ce729b1SVarun Wadekar console_switch_state(0); 1530ce729b1SVarun Wadekar } 1540ce729b1SVarun Wadekar 15526c0d9b2SVarun Wadekar wfi(); 15626c0d9b2SVarun Wadekar panic(); 15726c0d9b2SVarun Wadekar } 15826c0d9b2SVarun Wadekar 15926c0d9b2SVarun Wadekar /******************************************************************************* 16071cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 16171cb26eaSVarun Wadekar * being turned off earlier. The target_state encodes the low power state that 16271cb26eaSVarun Wadekar * each level has woken up from. 16308438e24SVarun Wadekar ******************************************************************************/ 16457e92dafSDavid Pu static void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) 16508438e24SVarun Wadekar { 166b36aea5aSAnthony Zhou const plat_params_from_bl2_t *plat_params; 16708438e24SVarun Wadekar 16808438e24SVarun Wadekar /* 16908438e24SVarun Wadekar * Check if we are exiting from deep sleep. 17008438e24SVarun Wadekar */ 17171cb26eaSVarun Wadekar if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == 17271cb26eaSVarun Wadekar PSTATE_ID_SOC_POWERDN) { 17308438e24SVarun Wadekar 1742a3dd384SVarun Wadekar /* 1752a3dd384SVarun Wadekar * On entering System Suspend state, the GIC loses power 1762a3dd384SVarun Wadekar * completely. Initialize the GIC global distributor and 1772a3dd384SVarun Wadekar * GIC cpu interfaces. 1782a3dd384SVarun Wadekar */ 1792a3dd384SVarun Wadekar tegra_gic_init(); 1802a3dd384SVarun Wadekar 181544c092bSAmbroise Vincent /* Restart console output. */ 182544c092bSAmbroise Vincent console_switch_state(CONSOLE_FLAG_RUNTIME); 1835b5928e8SVarun Wadekar 18408438e24SVarun Wadekar /* 185102e4087SVarun Wadekar * Restore Memory Controller settings as it loses state 186102e4087SVarun Wadekar * during system suspend. 18708438e24SVarun Wadekar */ 188102e4087SVarun Wadekar tegra_memctrl_restore_settings(); 18908438e24SVarun Wadekar 19008438e24SVarun Wadekar /* 19108438e24SVarun Wadekar * Security configuration to allow DRAM/device access. 19208438e24SVarun Wadekar */ 19308438e24SVarun Wadekar plat_params = bl31_get_plat_params(); 194e0d4158cSVarun Wadekar tegra_memctrl_tzdram_setup(plat_params->tzdram_base, 195b36aea5aSAnthony Zhou (uint32_t)plat_params->tzdram_size); 196207680c6SVarun Wadekar 1972a3dd384SVarun Wadekar } else { 1982a3dd384SVarun Wadekar /* 1992a3dd384SVarun Wadekar * Initialize the GIC cpu and distributor interfaces 2002a3dd384SVarun Wadekar */ 2012a3dd384SVarun Wadekar tegra_gic_pcpu_init(); 20208438e24SVarun Wadekar } 20308438e24SVarun Wadekar 20408438e24SVarun Wadekar /* 20508438e24SVarun Wadekar * Reset hardware settings. 20608438e24SVarun Wadekar */ 207b36aea5aSAnthony Zhou (void)tegra_soc_pwr_domain_on_finish(target_state); 20808438e24SVarun Wadekar } 20908438e24SVarun Wadekar 21008438e24SVarun Wadekar /******************************************************************************* 21171cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 21271cb26eaSVarun Wadekar * having been suspended earlier. The target_state encodes the low power state 21371cb26eaSVarun Wadekar * that each level has woken up from. 21408438e24SVarun Wadekar ******************************************************************************/ 21557e92dafSDavid Pu static void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 21608438e24SVarun Wadekar { 21771cb26eaSVarun Wadekar tegra_pwr_domain_on_finish(target_state); 21808438e24SVarun Wadekar } 21908438e24SVarun Wadekar 22008438e24SVarun Wadekar /******************************************************************************* 22108438e24SVarun Wadekar * Handler called when the system wants to be powered off 22208438e24SVarun Wadekar ******************************************************************************/ 22357e92dafSDavid Pu static __dead2 void tegra_system_off(void) 22408438e24SVarun Wadekar { 22531a4957cSVarun Wadekar INFO("Powering down system...\n"); 22631a4957cSVarun Wadekar 22731a4957cSVarun Wadekar tegra_soc_prepare_system_off(); 22808438e24SVarun Wadekar } 22908438e24SVarun Wadekar 23008438e24SVarun Wadekar /******************************************************************************* 23108438e24SVarun Wadekar * Handler called when the system wants to be restarted. 23208438e24SVarun Wadekar ******************************************************************************/ 23357e92dafSDavid Pu static __dead2 void tegra_system_reset(void) 23408438e24SVarun Wadekar { 23531a4957cSVarun Wadekar INFO("Restarting system...\n"); 23631a4957cSVarun Wadekar 2373b40f993SVarun Wadekar /* per-SoC system reset handler */ 238b36aea5aSAnthony Zhou (void)tegra_soc_prepare_system_reset(); 2393b40f993SVarun Wadekar 24057c539f9SVarun Wadekar /* wait for the system to reset */ 24157c539f9SVarun Wadekar for (;;) { 24257c539f9SVarun Wadekar ; 24357c539f9SVarun Wadekar } 24408438e24SVarun Wadekar } 24508438e24SVarun Wadekar 24608438e24SVarun Wadekar /******************************************************************************* 24771cb26eaSVarun Wadekar * Handler called to check the validity of the power state parameter. 24871cb26eaSVarun Wadekar ******************************************************************************/ 24957e92dafSDavid Pu static int32_t tegra_validate_power_state(uint32_t power_state, 25071cb26eaSVarun Wadekar psci_power_state_t *req_state) 25171cb26eaSVarun Wadekar { 2524c994002SAnthony Zhou assert(req_state != NULL); 25371cb26eaSVarun Wadekar 25471cb26eaSVarun Wadekar return tegra_soc_validate_power_state(power_state, req_state); 25571cb26eaSVarun Wadekar } 25671cb26eaSVarun Wadekar 25771cb26eaSVarun Wadekar /******************************************************************************* 25871cb26eaSVarun Wadekar * Platform handler called to check the validity of the non secure entrypoint. 25971cb26eaSVarun Wadekar ******************************************************************************/ 26057e92dafSDavid Pu static int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint) 26171cb26eaSVarun Wadekar { 262b36aea5aSAnthony Zhou int32_t ret = PSCI_E_INVALID_ADDRESS; 263b36aea5aSAnthony Zhou 26471cb26eaSVarun Wadekar /* 26571cb26eaSVarun Wadekar * Check if the non secure entrypoint lies within the non 26671cb26eaSVarun Wadekar * secure DRAM. 26771cb26eaSVarun Wadekar */ 268b36aea5aSAnthony Zhou if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) { 269b36aea5aSAnthony Zhou ret = PSCI_E_SUCCESS; 270b36aea5aSAnthony Zhou } 27171cb26eaSVarun Wadekar 272b36aea5aSAnthony Zhou return ret; 27371cb26eaSVarun Wadekar } 27471cb26eaSVarun Wadekar 27571cb26eaSVarun Wadekar /******************************************************************************* 27608438e24SVarun Wadekar * Export the platform handlers to enable psci to invoke them 27708438e24SVarun Wadekar ******************************************************************************/ 2785d52aea8SVarun Wadekar static plat_psci_ops_t tegra_plat_psci_ops = { 27971cb26eaSVarun Wadekar .cpu_standby = tegra_cpu_standby, 28071cb26eaSVarun Wadekar .pwr_domain_on = tegra_pwr_domain_on, 28196d07af4SVarun Wadekar .pwr_domain_off_early = tegra_pwr_domain_off_early, 28271cb26eaSVarun Wadekar .pwr_domain_off = tegra_pwr_domain_off, 283cb95a19aSVarun Wadekar .pwr_domain_suspend_pwrdown_early = tegra_pwr_domain_suspend_pwrdown_early, 28471cb26eaSVarun Wadekar .pwr_domain_suspend = tegra_pwr_domain_suspend, 28571cb26eaSVarun Wadekar .pwr_domain_on_finish = tegra_pwr_domain_on_finish, 28671cb26eaSVarun Wadekar .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, 287*db5fe4f4SBoyan Karatotev .pwr_domain_pwr_down = tegra_pwr_domain_power_down_wfi, 28808438e24SVarun Wadekar .system_off = tegra_system_off, 28908438e24SVarun Wadekar .system_reset = tegra_system_reset, 29094c672e7SVarun Wadekar .validate_power_state = tegra_validate_power_state, 29171cb26eaSVarun Wadekar .validate_ns_entrypoint = tegra_validate_ns_entrypoint, 29271cb26eaSVarun Wadekar .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, 29308438e24SVarun Wadekar }; 29408438e24SVarun Wadekar 29508438e24SVarun Wadekar /******************************************************************************* 29671cb26eaSVarun Wadekar * Export the platform specific power ops and initialize Power Controller 29708438e24SVarun Wadekar ******************************************************************************/ 29871cb26eaSVarun Wadekar int plat_setup_psci_ops(uintptr_t sec_entrypoint, 29971cb26eaSVarun Wadekar const plat_psci_ops_t **psci_ops) 30008438e24SVarun Wadekar { 30171cb26eaSVarun Wadekar psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; 30271cb26eaSVarun Wadekar 30371cb26eaSVarun Wadekar /* 30471cb26eaSVarun Wadekar * Flush entrypoint variable to PoC since it will be 30571cb26eaSVarun Wadekar * accessed after a reset with the caches turned off. 30671cb26eaSVarun Wadekar */ 30771cb26eaSVarun Wadekar tegra_sec_entry_point = sec_entrypoint; 30871cb26eaSVarun Wadekar flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); 30971cb26eaSVarun Wadekar 31008438e24SVarun Wadekar /* 31108438e24SVarun Wadekar * Reset hardware settings. 31208438e24SVarun Wadekar */ 313b36aea5aSAnthony Zhou (void)tegra_soc_pwr_domain_on_finish(&target_state); 31408438e24SVarun Wadekar 31508438e24SVarun Wadekar /* 3165d52aea8SVarun Wadekar * Disable System Suspend if the platform does not 3175d52aea8SVarun Wadekar * support it 3185d52aea8SVarun Wadekar */ 3195d52aea8SVarun Wadekar if (!plat_supports_system_suspend()) { 3205d52aea8SVarun Wadekar tegra_plat_psci_ops.get_sys_suspend_power_state = NULL; 3215d52aea8SVarun Wadekar } 3225d52aea8SVarun Wadekar 3235d52aea8SVarun Wadekar /* 32471cb26eaSVarun Wadekar * Initialize PSCI ops struct 32508438e24SVarun Wadekar */ 32671cb26eaSVarun Wadekar *psci_ops = &tegra_plat_psci_ops; 32708438e24SVarun Wadekar 32808438e24SVarun Wadekar return 0; 32908438e24SVarun Wadekar } 3302693f1dbSVarun Wadekar 3312693f1dbSVarun Wadekar /******************************************************************************* 3322693f1dbSVarun Wadekar * Platform handler to calculate the proper target power level at the 3332693f1dbSVarun Wadekar * specified affinity level 3342693f1dbSVarun Wadekar ******************************************************************************/ 3352693f1dbSVarun Wadekar plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, 3362693f1dbSVarun Wadekar const plat_local_state_t *states, 3372693f1dbSVarun Wadekar unsigned int ncpu) 3382693f1dbSVarun Wadekar { 339a7cd0953SVarun Wadekar return tegra_soc_get_target_pwr_state(lvl, states, ncpu); 3402693f1dbSVarun Wadekar } 341