108438e24SVarun Wadekar /* 208438e24SVarun Wadekar * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 308438e24SVarun Wadekar * 408438e24SVarun Wadekar * Redistribution and use in source and binary forms, with or without 508438e24SVarun Wadekar * modification, are permitted provided that the following conditions are met: 608438e24SVarun Wadekar * 708438e24SVarun Wadekar * Redistributions of source code must retain the above copyright notice, this 808438e24SVarun Wadekar * list of conditions and the following disclaimer. 908438e24SVarun Wadekar * 1008438e24SVarun Wadekar * Redistributions in binary form must reproduce the above copyright notice, 1108438e24SVarun Wadekar * this list of conditions and the following disclaimer in the documentation 1208438e24SVarun Wadekar * and/or other materials provided with the distribution. 1308438e24SVarun Wadekar * 1408438e24SVarun Wadekar * Neither the name of ARM nor the names of its contributors may be used 1508438e24SVarun Wadekar * to endorse or promote products derived from this software without specific 1608438e24SVarun Wadekar * prior written permission. 1708438e24SVarun Wadekar * 1808438e24SVarun Wadekar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1908438e24SVarun Wadekar * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2008438e24SVarun Wadekar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2108438e24SVarun Wadekar * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2208438e24SVarun Wadekar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2308438e24SVarun Wadekar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2408438e24SVarun Wadekar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2508438e24SVarun Wadekar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2608438e24SVarun Wadekar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2708438e24SVarun Wadekar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2808438e24SVarun Wadekar * POSSIBILITY OF SUCH DAMAGE. 2908438e24SVarun Wadekar */ 3008438e24SVarun Wadekar 3108438e24SVarun Wadekar #include <arch_helpers.h> 3208438e24SVarun Wadekar #include <assert.h> 3308438e24SVarun Wadekar #include <bl_common.h> 3408438e24SVarun Wadekar #include <context.h> 3508438e24SVarun Wadekar #include <context_mgmt.h> 3608438e24SVarun Wadekar #include <debug.h> 3708438e24SVarun Wadekar #include <memctrl.h> 3808438e24SVarun Wadekar #include <mmio.h> 3908438e24SVarun Wadekar #include <platform.h> 4008438e24SVarun Wadekar #include <platform_def.h> 4108438e24SVarun Wadekar #include <pmc.h> 4208438e24SVarun Wadekar #include <psci.h> 4308438e24SVarun Wadekar #include <tegra_def.h> 4408438e24SVarun Wadekar #include <tegra_private.h> 4508438e24SVarun Wadekar 4608438e24SVarun Wadekar extern uint64_t tegra_bl31_phys_base; 4708438e24SVarun Wadekar extern uint64_t sec_entry_point[PLATFORM_CORE_COUNT]; 4808438e24SVarun Wadekar static int system_suspended; 4908438e24SVarun Wadekar 5008438e24SVarun Wadekar /* 5108438e24SVarun Wadekar * The following platform setup functions are weakly defined. They 5208438e24SVarun Wadekar * provide typical implementations that will be overridden by a SoC. 5308438e24SVarun Wadekar */ 54*93eafbcaSVarun Wadekar #pragma weak tegra_soc_prepare_cpu_suspend 55*93eafbcaSVarun Wadekar #pragma weak tegra_soc_prepare_cpu_on 56*93eafbcaSVarun Wadekar #pragma weak tegra_soc_prepare_cpu_off 57*93eafbcaSVarun Wadekar #pragma weak tegra_soc_prepare_cpu_on_finish 5808438e24SVarun Wadekar 59*93eafbcaSVarun Wadekar int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl) 6008438e24SVarun Wadekar { 6108438e24SVarun Wadekar return PSCI_E_NOT_SUPPORTED; 6208438e24SVarun Wadekar } 6308438e24SVarun Wadekar 64*93eafbcaSVarun Wadekar int tegra_soc_prepare_cpu_on(unsigned long mpidr) 6508438e24SVarun Wadekar { 6608438e24SVarun Wadekar return PSCI_E_SUCCESS; 6708438e24SVarun Wadekar } 6808438e24SVarun Wadekar 69*93eafbcaSVarun Wadekar int tegra_soc_prepare_cpu_off(unsigned long mpidr) 7008438e24SVarun Wadekar { 7108438e24SVarun Wadekar return PSCI_E_SUCCESS; 7208438e24SVarun Wadekar } 7308438e24SVarun Wadekar 74*93eafbcaSVarun Wadekar int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr) 7508438e24SVarun Wadekar { 7608438e24SVarun Wadekar return PSCI_E_SUCCESS; 7708438e24SVarun Wadekar } 7808438e24SVarun Wadekar 7908438e24SVarun Wadekar /******************************************************************************* 8008438e24SVarun Wadekar * Track system suspend entry. 8108438e24SVarun Wadekar ******************************************************************************/ 8208438e24SVarun Wadekar void tegra_pm_system_suspend_entry(void) 8308438e24SVarun Wadekar { 8408438e24SVarun Wadekar system_suspended = 1; 8508438e24SVarun Wadekar } 8608438e24SVarun Wadekar 8708438e24SVarun Wadekar /******************************************************************************* 8808438e24SVarun Wadekar * Track system suspend exit. 8908438e24SVarun Wadekar ******************************************************************************/ 9008438e24SVarun Wadekar void tegra_pm_system_suspend_exit(void) 9108438e24SVarun Wadekar { 9208438e24SVarun Wadekar system_suspended = 0; 9308438e24SVarun Wadekar } 9408438e24SVarun Wadekar 9508438e24SVarun Wadekar /******************************************************************************* 9608438e24SVarun Wadekar * Get the system suspend state. 9708438e24SVarun Wadekar ******************************************************************************/ 9808438e24SVarun Wadekar int tegra_system_suspended(void) 9908438e24SVarun Wadekar { 10008438e24SVarun Wadekar return system_suspended; 10108438e24SVarun Wadekar } 10208438e24SVarun Wadekar 10308438e24SVarun Wadekar /******************************************************************************* 10408438e24SVarun Wadekar * Handler called when an affinity instance is about to enter standby. 10508438e24SVarun Wadekar ******************************************************************************/ 10608438e24SVarun Wadekar void tegra_affinst_standby(unsigned int power_state) 10708438e24SVarun Wadekar { 10808438e24SVarun Wadekar /* 10908438e24SVarun Wadekar * Enter standby state 11008438e24SVarun Wadekar * dsb is good practice before using wfi to enter low power states 11108438e24SVarun Wadekar */ 11208438e24SVarun Wadekar dsb(); 11308438e24SVarun Wadekar wfi(); 11408438e24SVarun Wadekar } 11508438e24SVarun Wadekar 11608438e24SVarun Wadekar /******************************************************************************* 11794c672e7SVarun Wadekar * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` 11894c672e7SVarun Wadekar * call to get the `power_state` parameter. This allows the platform to encode 11994c672e7SVarun Wadekar * the appropriate State-ID field within the `power_state` parameter which can 12094c672e7SVarun Wadekar * be utilized in `affinst_suspend()` to suspend to system affinity level. 12194c672e7SVarun Wadekar ******************************************************************************/ 12294c672e7SVarun Wadekar unsigned int tegra_get_sys_suspend_power_state(void) 12394c672e7SVarun Wadekar { 12494c672e7SVarun Wadekar unsigned int power_state; 12594c672e7SVarun Wadekar 12694c672e7SVarun Wadekar power_state = psci_make_powerstate(PLAT_SYS_SUSPEND_STATE_ID, 12794c672e7SVarun Wadekar PSTATE_TYPE_POWERDOWN, MPIDR_AFFLVL2); 12894c672e7SVarun Wadekar 12994c672e7SVarun Wadekar return power_state; 13094c672e7SVarun Wadekar } 13194c672e7SVarun Wadekar 13294c672e7SVarun Wadekar /******************************************************************************* 13308438e24SVarun Wadekar * Handler called to check the validity of the power state parameter. 13408438e24SVarun Wadekar ******************************************************************************/ 13508438e24SVarun Wadekar int32_t tegra_validate_power_state(unsigned int power_state) 13608438e24SVarun Wadekar { 137*93eafbcaSVarun Wadekar return tegra_soc_validate_power_state(power_state); 13808438e24SVarun Wadekar } 13908438e24SVarun Wadekar 14008438e24SVarun Wadekar /******************************************************************************* 14108438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned on. The 14208438e24SVarun Wadekar * level and mpidr determine the affinity instance. 14308438e24SVarun Wadekar ******************************************************************************/ 14408438e24SVarun Wadekar int tegra_affinst_on(unsigned long mpidr, 14508438e24SVarun Wadekar unsigned long sec_entrypoint, 14608438e24SVarun Wadekar unsigned int afflvl, 14708438e24SVarun Wadekar unsigned int state) 14808438e24SVarun Wadekar { 14908438e24SVarun Wadekar int cpu = mpidr & MPIDR_CPU_MASK; 15008438e24SVarun Wadekar 15108438e24SVarun Wadekar /* 15208438e24SVarun Wadekar * Support individual CPU power on only. 15308438e24SVarun Wadekar */ 15408438e24SVarun Wadekar if (afflvl > MPIDR_AFFLVL0) 15508438e24SVarun Wadekar return PSCI_E_SUCCESS; 15608438e24SVarun Wadekar 15708438e24SVarun Wadekar /* 15808438e24SVarun Wadekar * Flush entrypoint variable to PoC since it will be 15908438e24SVarun Wadekar * accessed after a reset with the caches turned off. 16008438e24SVarun Wadekar */ 16108438e24SVarun Wadekar sec_entry_point[cpu] = sec_entrypoint; 16208438e24SVarun Wadekar flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); 16308438e24SVarun Wadekar 164*93eafbcaSVarun Wadekar return tegra_soc_prepare_cpu_on(mpidr); 16508438e24SVarun Wadekar } 16608438e24SVarun Wadekar 16708438e24SVarun Wadekar /******************************************************************************* 16808438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned off. The 16908438e24SVarun Wadekar * level determines the affinity instance. The 'state' arg. allows the 17008438e24SVarun Wadekar * platform to decide whether the cluster is being turned off and take apt 17108438e24SVarun Wadekar * actions. 17208438e24SVarun Wadekar * 17308438e24SVarun Wadekar * CAUTION: This function is called with coherent stacks so that caches can be 17408438e24SVarun Wadekar * turned off, flushed and coherency disabled. There is no guarantee that caches 17508438e24SVarun Wadekar * will remain turned on across calls to this function as each affinity level is 17608438e24SVarun Wadekar * dealt with. So do not write & read global variables across calls. It will be 17708438e24SVarun Wadekar * wise to do flush a write to the global to prevent unpredictable results. 17808438e24SVarun Wadekar ******************************************************************************/ 17908438e24SVarun Wadekar void tegra_affinst_off(unsigned int afflvl, unsigned int state) 18008438e24SVarun Wadekar { 18108438e24SVarun Wadekar /* 18208438e24SVarun Wadekar * Support individual CPU power off only. 18308438e24SVarun Wadekar */ 18408438e24SVarun Wadekar if (afflvl > MPIDR_AFFLVL0) 18508438e24SVarun Wadekar return; 18608438e24SVarun Wadekar 187*93eafbcaSVarun Wadekar tegra_soc_prepare_cpu_off(read_mpidr()); 18808438e24SVarun Wadekar } 18908438e24SVarun Wadekar 19008438e24SVarun Wadekar /******************************************************************************* 19108438e24SVarun Wadekar * Handler called when an affinity instance is about to be suspended. The 19208438e24SVarun Wadekar * level and mpidr determine the affinity instance. The 'state' arg. allows the 19308438e24SVarun Wadekar * platform to decide whether the cluster is being turned off and take apt 19408438e24SVarun Wadekar * actions. 19508438e24SVarun Wadekar * 19608438e24SVarun Wadekar * CAUTION: This function is called with coherent stacks so that caches can be 19708438e24SVarun Wadekar * turned off, flushed and coherency disabled. There is no guarantee that caches 19808438e24SVarun Wadekar * will remain turned on across calls to this function as each affinity level is 19908438e24SVarun Wadekar * dealt with. So do not write & read global variables across calls. It will be 20008438e24SVarun Wadekar * wise to flush a write to the global variable, to prevent unpredictable 20108438e24SVarun Wadekar * results. 20208438e24SVarun Wadekar ******************************************************************************/ 20308438e24SVarun Wadekar void tegra_affinst_suspend(unsigned long sec_entrypoint, 20408438e24SVarun Wadekar unsigned int afflvl, 20508438e24SVarun Wadekar unsigned int state) 20608438e24SVarun Wadekar { 20708438e24SVarun Wadekar int id = psci_get_suspend_stateid(); 20808438e24SVarun Wadekar int cpu = read_mpidr() & MPIDR_CPU_MASK; 20908438e24SVarun Wadekar 21008438e24SVarun Wadekar if (afflvl > PLATFORM_MAX_AFFLVL) 21108438e24SVarun Wadekar return; 21208438e24SVarun Wadekar 21308438e24SVarun Wadekar /* 21408438e24SVarun Wadekar * Flush entrypoint variable to PoC since it will be 21508438e24SVarun Wadekar * accessed after a reset with the caches turned off. 21608438e24SVarun Wadekar */ 21708438e24SVarun Wadekar sec_entry_point[cpu] = sec_entrypoint; 21808438e24SVarun Wadekar flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); 21908438e24SVarun Wadekar 220*93eafbcaSVarun Wadekar tegra_soc_prepare_cpu_suspend(id, afflvl); 22108438e24SVarun Wadekar 22208438e24SVarun Wadekar /* disable GICC */ 22308438e24SVarun Wadekar tegra_gic_cpuif_deactivate(); 22408438e24SVarun Wadekar } 22508438e24SVarun Wadekar 22608438e24SVarun Wadekar /******************************************************************************* 22708438e24SVarun Wadekar * Handler called when an affinity instance has just been powered on after 22808438e24SVarun Wadekar * being turned off earlier. The level determines the affinity instance. 22908438e24SVarun Wadekar * The 'state' arg. allows the platform to decide whether the cluster was 23008438e24SVarun Wadekar * turned off prior to wakeup and do what's necessary to set it up. 23108438e24SVarun Wadekar ******************************************************************************/ 23208438e24SVarun Wadekar void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) 23308438e24SVarun Wadekar { 23408438e24SVarun Wadekar plat_params_from_bl2_t *plat_params; 23508438e24SVarun Wadekar 23608438e24SVarun Wadekar /* 23708438e24SVarun Wadekar * Support individual CPU power on only. 23808438e24SVarun Wadekar */ 23908438e24SVarun Wadekar if (afflvl > MPIDR_AFFLVL0) 24008438e24SVarun Wadekar return; 24108438e24SVarun Wadekar 24208438e24SVarun Wadekar /* 24308438e24SVarun Wadekar * Initialize the GIC cpu and distributor interfaces 24408438e24SVarun Wadekar */ 24508438e24SVarun Wadekar tegra_gic_setup(); 24608438e24SVarun Wadekar 24708438e24SVarun Wadekar /* 24808438e24SVarun Wadekar * Check if we are exiting from deep sleep. 24908438e24SVarun Wadekar */ 25008438e24SVarun Wadekar if (tegra_system_suspended()) { 25108438e24SVarun Wadekar 25208438e24SVarun Wadekar /* 25308438e24SVarun Wadekar * Lock scratch registers which hold the CPU vectors. 25408438e24SVarun Wadekar */ 25508438e24SVarun Wadekar tegra_pmc_lock_cpu_vectors(); 25608438e24SVarun Wadekar 25708438e24SVarun Wadekar /* 25808438e24SVarun Wadekar * SMMU configuration. 25908438e24SVarun Wadekar */ 26008438e24SVarun Wadekar tegra_memctrl_setup(); 26108438e24SVarun Wadekar 26208438e24SVarun Wadekar /* 26308438e24SVarun Wadekar * Security configuration to allow DRAM/device access. 26408438e24SVarun Wadekar */ 26508438e24SVarun Wadekar plat_params = bl31_get_plat_params(); 26608438e24SVarun Wadekar tegra_memctrl_tzdram_setup(tegra_bl31_phys_base, 26708438e24SVarun Wadekar plat_params->tzdram_size); 26808438e24SVarun Wadekar } 26908438e24SVarun Wadekar 27008438e24SVarun Wadekar /* 27108438e24SVarun Wadekar * Reset hardware settings. 27208438e24SVarun Wadekar */ 273*93eafbcaSVarun Wadekar tegra_soc_prepare_cpu_on_finish(read_mpidr()); 27408438e24SVarun Wadekar } 27508438e24SVarun Wadekar 27608438e24SVarun Wadekar /******************************************************************************* 27708438e24SVarun Wadekar * Handler called when an affinity instance has just been powered on after 27808438e24SVarun Wadekar * having been suspended earlier. The level and mpidr determine the affinity 27908438e24SVarun Wadekar * instance. 28008438e24SVarun Wadekar ******************************************************************************/ 28108438e24SVarun Wadekar void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state) 28208438e24SVarun Wadekar { 28308438e24SVarun Wadekar if (afflvl == MPIDR_AFFLVL0) 28408438e24SVarun Wadekar tegra_affinst_on_finish(afflvl, state); 28508438e24SVarun Wadekar } 28608438e24SVarun Wadekar 28708438e24SVarun Wadekar /******************************************************************************* 28808438e24SVarun Wadekar * Handler called when the system wants to be powered off 28908438e24SVarun Wadekar ******************************************************************************/ 29008438e24SVarun Wadekar __dead2 void tegra_system_off(void) 29108438e24SVarun Wadekar { 29208438e24SVarun Wadekar ERROR("Tegra System Off: operation not handled.\n"); 29308438e24SVarun Wadekar panic(); 29408438e24SVarun Wadekar } 29508438e24SVarun Wadekar 29608438e24SVarun Wadekar /******************************************************************************* 29708438e24SVarun Wadekar * Handler called when the system wants to be restarted. 29808438e24SVarun Wadekar ******************************************************************************/ 29908438e24SVarun Wadekar __dead2 void tegra_system_reset(void) 30008438e24SVarun Wadekar { 30108438e24SVarun Wadekar /* 30208438e24SVarun Wadekar * Program the PMC in order to restart the system. 30308438e24SVarun Wadekar */ 30408438e24SVarun Wadekar tegra_pmc_system_reset(); 30508438e24SVarun Wadekar } 30608438e24SVarun Wadekar 30708438e24SVarun Wadekar /******************************************************************************* 30808438e24SVarun Wadekar * Export the platform handlers to enable psci to invoke them 30908438e24SVarun Wadekar ******************************************************************************/ 31008438e24SVarun Wadekar static const plat_pm_ops_t tegra_plat_pm_ops = { 31108438e24SVarun Wadekar .affinst_standby = tegra_affinst_standby, 31208438e24SVarun Wadekar .affinst_on = tegra_affinst_on, 31308438e24SVarun Wadekar .affinst_off = tegra_affinst_off, 31408438e24SVarun Wadekar .affinst_suspend = tegra_affinst_suspend, 31508438e24SVarun Wadekar .affinst_on_finish = tegra_affinst_on_finish, 31608438e24SVarun Wadekar .affinst_suspend_finish = tegra_affinst_suspend_finish, 31708438e24SVarun Wadekar .system_off = tegra_system_off, 31808438e24SVarun Wadekar .system_reset = tegra_system_reset, 31994c672e7SVarun Wadekar .validate_power_state = tegra_validate_power_state, 32094c672e7SVarun Wadekar .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state 32108438e24SVarun Wadekar }; 32208438e24SVarun Wadekar 32308438e24SVarun Wadekar /******************************************************************************* 32408438e24SVarun Wadekar * Export the platform specific power ops & initialize the fvp power controller 32508438e24SVarun Wadekar ******************************************************************************/ 32608438e24SVarun Wadekar int platform_setup_pm(const plat_pm_ops_t **plat_ops) 32708438e24SVarun Wadekar { 32808438e24SVarun Wadekar /* 32908438e24SVarun Wadekar * Reset hardware settings. 33008438e24SVarun Wadekar */ 331*93eafbcaSVarun Wadekar tegra_soc_prepare_cpu_on_finish(read_mpidr()); 33208438e24SVarun Wadekar 33308438e24SVarun Wadekar /* 33408438e24SVarun Wadekar * Initialize PM ops struct 33508438e24SVarun Wadekar */ 33608438e24SVarun Wadekar *plat_ops = &tegra_plat_pm_ops; 33708438e24SVarun Wadekar 33808438e24SVarun Wadekar return 0; 33908438e24SVarun Wadekar } 340