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 */ 5408438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_suspend 5508438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_on 5608438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_off 5708438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_on_finish 5808438e24SVarun Wadekar 5908438e24SVarun Wadekar int tegra_prepare_cpu_suspend(unsigned int id, unsigned int afflvl) 6008438e24SVarun Wadekar { 6108438e24SVarun Wadekar return PSCI_E_NOT_SUPPORTED; 6208438e24SVarun Wadekar } 6308438e24SVarun Wadekar 6408438e24SVarun Wadekar int tegra_prepare_cpu_on(unsigned long mpidr) 6508438e24SVarun Wadekar { 6608438e24SVarun Wadekar return PSCI_E_SUCCESS; 6708438e24SVarun Wadekar } 6808438e24SVarun Wadekar 6908438e24SVarun Wadekar int tegra_prepare_cpu_off(unsigned long mpidr) 7008438e24SVarun Wadekar { 7108438e24SVarun Wadekar return PSCI_E_SUCCESS; 7208438e24SVarun Wadekar } 7308438e24SVarun Wadekar 7408438e24SVarun Wadekar int tegra_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 /******************************************************************************* 117*94c672e7SVarun Wadekar * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` 118*94c672e7SVarun Wadekar * call to get the `power_state` parameter. This allows the platform to encode 119*94c672e7SVarun Wadekar * the appropriate State-ID field within the `power_state` parameter which can 120*94c672e7SVarun Wadekar * be utilized in `affinst_suspend()` to suspend to system affinity level. 121*94c672e7SVarun Wadekar ******************************************************************************/ 122*94c672e7SVarun Wadekar unsigned int tegra_get_sys_suspend_power_state(void) 123*94c672e7SVarun Wadekar { 124*94c672e7SVarun Wadekar unsigned int power_state; 125*94c672e7SVarun Wadekar 126*94c672e7SVarun Wadekar power_state = psci_make_powerstate(PLAT_SYS_SUSPEND_STATE_ID, 127*94c672e7SVarun Wadekar PSTATE_TYPE_POWERDOWN, MPIDR_AFFLVL2); 128*94c672e7SVarun Wadekar 129*94c672e7SVarun Wadekar return power_state; 130*94c672e7SVarun Wadekar } 131*94c672e7SVarun Wadekar 132*94c672e7SVarun 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 { 13708438e24SVarun Wadekar /* Sanity check the requested state */ 13808438e24SVarun Wadekar if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) { 13908438e24SVarun Wadekar /* 14008438e24SVarun Wadekar * It's possible to enter standby only on affinity level 0 i.e. 14108438e24SVarun Wadekar * a cpu on Tegra. Ignore any other affinity level. 14208438e24SVarun Wadekar */ 14308438e24SVarun Wadekar if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0) 14408438e24SVarun Wadekar return PSCI_E_INVALID_PARAMS; 14508438e24SVarun Wadekar } 14608438e24SVarun Wadekar 14708438e24SVarun Wadekar return PSCI_E_SUCCESS; 14808438e24SVarun Wadekar } 14908438e24SVarun Wadekar 15008438e24SVarun Wadekar /******************************************************************************* 15108438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned on. The 15208438e24SVarun Wadekar * level and mpidr determine the affinity instance. 15308438e24SVarun Wadekar ******************************************************************************/ 15408438e24SVarun Wadekar int tegra_affinst_on(unsigned long mpidr, 15508438e24SVarun Wadekar unsigned long sec_entrypoint, 15608438e24SVarun Wadekar unsigned int afflvl, 15708438e24SVarun Wadekar unsigned int state) 15808438e24SVarun Wadekar { 15908438e24SVarun Wadekar int cpu = mpidr & MPIDR_CPU_MASK; 16008438e24SVarun Wadekar 16108438e24SVarun Wadekar /* 16208438e24SVarun Wadekar * Support individual CPU power on only. 16308438e24SVarun Wadekar */ 16408438e24SVarun Wadekar if (afflvl > MPIDR_AFFLVL0) 16508438e24SVarun Wadekar return PSCI_E_SUCCESS; 16608438e24SVarun Wadekar 16708438e24SVarun Wadekar /* 16808438e24SVarun Wadekar * Flush entrypoint variable to PoC since it will be 16908438e24SVarun Wadekar * accessed after a reset with the caches turned off. 17008438e24SVarun Wadekar */ 17108438e24SVarun Wadekar sec_entry_point[cpu] = sec_entrypoint; 17208438e24SVarun Wadekar flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); 17308438e24SVarun Wadekar 17408438e24SVarun Wadekar return tegra_prepare_cpu_on(mpidr); 17508438e24SVarun Wadekar } 17608438e24SVarun Wadekar 17708438e24SVarun Wadekar /******************************************************************************* 17808438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned off. The 17908438e24SVarun Wadekar * level determines the affinity instance. The 'state' arg. allows the 18008438e24SVarun Wadekar * platform to decide whether the cluster is being turned off and take apt 18108438e24SVarun Wadekar * actions. 18208438e24SVarun Wadekar * 18308438e24SVarun Wadekar * CAUTION: This function is called with coherent stacks so that caches can be 18408438e24SVarun Wadekar * turned off, flushed and coherency disabled. There is no guarantee that caches 18508438e24SVarun Wadekar * will remain turned on across calls to this function as each affinity level is 18608438e24SVarun Wadekar * dealt with. So do not write & read global variables across calls. It will be 18708438e24SVarun Wadekar * wise to do flush a write to the global to prevent unpredictable results. 18808438e24SVarun Wadekar ******************************************************************************/ 18908438e24SVarun Wadekar void tegra_affinst_off(unsigned int afflvl, unsigned int state) 19008438e24SVarun Wadekar { 19108438e24SVarun Wadekar /* 19208438e24SVarun Wadekar * Support individual CPU power off only. 19308438e24SVarun Wadekar */ 19408438e24SVarun Wadekar if (afflvl > MPIDR_AFFLVL0) 19508438e24SVarun Wadekar return; 19608438e24SVarun Wadekar 19708438e24SVarun Wadekar tegra_prepare_cpu_off(read_mpidr()); 19808438e24SVarun Wadekar } 19908438e24SVarun Wadekar 20008438e24SVarun Wadekar /******************************************************************************* 20108438e24SVarun Wadekar * Handler called when an affinity instance is about to be suspended. The 20208438e24SVarun Wadekar * level and mpidr determine the affinity instance. The 'state' arg. allows the 20308438e24SVarun Wadekar * platform to decide whether the cluster is being turned off and take apt 20408438e24SVarun Wadekar * actions. 20508438e24SVarun Wadekar * 20608438e24SVarun Wadekar * CAUTION: This function is called with coherent stacks so that caches can be 20708438e24SVarun Wadekar * turned off, flushed and coherency disabled. There is no guarantee that caches 20808438e24SVarun Wadekar * will remain turned on across calls to this function as each affinity level is 20908438e24SVarun Wadekar * dealt with. So do not write & read global variables across calls. It will be 21008438e24SVarun Wadekar * wise to flush a write to the global variable, to prevent unpredictable 21108438e24SVarun Wadekar * results. 21208438e24SVarun Wadekar ******************************************************************************/ 21308438e24SVarun Wadekar void tegra_affinst_suspend(unsigned long sec_entrypoint, 21408438e24SVarun Wadekar unsigned int afflvl, 21508438e24SVarun Wadekar unsigned int state) 21608438e24SVarun Wadekar { 21708438e24SVarun Wadekar int id = psci_get_suspend_stateid(); 21808438e24SVarun Wadekar int cpu = read_mpidr() & MPIDR_CPU_MASK; 21908438e24SVarun Wadekar 22008438e24SVarun Wadekar if (afflvl > PLATFORM_MAX_AFFLVL) 22108438e24SVarun Wadekar return; 22208438e24SVarun Wadekar 22308438e24SVarun Wadekar /* 22408438e24SVarun Wadekar * Flush entrypoint variable to PoC since it will be 22508438e24SVarun Wadekar * accessed after a reset with the caches turned off. 22608438e24SVarun Wadekar */ 22708438e24SVarun Wadekar sec_entry_point[cpu] = sec_entrypoint; 22808438e24SVarun Wadekar flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); 22908438e24SVarun Wadekar 23008438e24SVarun Wadekar tegra_prepare_cpu_suspend(id, afflvl); 23108438e24SVarun Wadekar 23208438e24SVarun Wadekar /* disable GICC */ 23308438e24SVarun Wadekar tegra_gic_cpuif_deactivate(); 23408438e24SVarun Wadekar } 23508438e24SVarun Wadekar 23608438e24SVarun Wadekar /******************************************************************************* 23708438e24SVarun Wadekar * Handler called when an affinity instance has just been powered on after 23808438e24SVarun Wadekar * being turned off earlier. The level determines the affinity instance. 23908438e24SVarun Wadekar * The 'state' arg. allows the platform to decide whether the cluster was 24008438e24SVarun Wadekar * turned off prior to wakeup and do what's necessary to set it up. 24108438e24SVarun Wadekar ******************************************************************************/ 24208438e24SVarun Wadekar void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) 24308438e24SVarun Wadekar { 24408438e24SVarun Wadekar plat_params_from_bl2_t *plat_params; 24508438e24SVarun Wadekar 24608438e24SVarun Wadekar /* 24708438e24SVarun Wadekar * Support individual CPU power on only. 24808438e24SVarun Wadekar */ 24908438e24SVarun Wadekar if (afflvl > MPIDR_AFFLVL0) 25008438e24SVarun Wadekar return; 25108438e24SVarun Wadekar 25208438e24SVarun Wadekar /* 25308438e24SVarun Wadekar * Initialize the GIC cpu and distributor interfaces 25408438e24SVarun Wadekar */ 25508438e24SVarun Wadekar tegra_gic_setup(); 25608438e24SVarun Wadekar 25708438e24SVarun Wadekar /* 25808438e24SVarun Wadekar * Check if we are exiting from deep sleep. 25908438e24SVarun Wadekar */ 26008438e24SVarun Wadekar if (tegra_system_suspended()) { 26108438e24SVarun Wadekar 26208438e24SVarun Wadekar /* 26308438e24SVarun Wadekar * Lock scratch registers which hold the CPU vectors. 26408438e24SVarun Wadekar */ 26508438e24SVarun Wadekar tegra_pmc_lock_cpu_vectors(); 26608438e24SVarun Wadekar 26708438e24SVarun Wadekar /* 26808438e24SVarun Wadekar * SMMU configuration. 26908438e24SVarun Wadekar */ 27008438e24SVarun Wadekar tegra_memctrl_setup(); 27108438e24SVarun Wadekar 27208438e24SVarun Wadekar /* 27308438e24SVarun Wadekar * Security configuration to allow DRAM/device access. 27408438e24SVarun Wadekar */ 27508438e24SVarun Wadekar plat_params = bl31_get_plat_params(); 27608438e24SVarun Wadekar tegra_memctrl_tzdram_setup(tegra_bl31_phys_base, 27708438e24SVarun Wadekar plat_params->tzdram_size); 27808438e24SVarun Wadekar } 27908438e24SVarun Wadekar 28008438e24SVarun Wadekar /* 28108438e24SVarun Wadekar * Reset hardware settings. 28208438e24SVarun Wadekar */ 28308438e24SVarun Wadekar tegra_prepare_cpu_on_finish(read_mpidr()); 28408438e24SVarun Wadekar } 28508438e24SVarun Wadekar 28608438e24SVarun Wadekar /******************************************************************************* 28708438e24SVarun Wadekar * Handler called when an affinity instance has just been powered on after 28808438e24SVarun Wadekar * having been suspended earlier. The level and mpidr determine the affinity 28908438e24SVarun Wadekar * instance. 29008438e24SVarun Wadekar ******************************************************************************/ 29108438e24SVarun Wadekar void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state) 29208438e24SVarun Wadekar { 29308438e24SVarun Wadekar if (afflvl == MPIDR_AFFLVL0) 29408438e24SVarun Wadekar tegra_affinst_on_finish(afflvl, state); 29508438e24SVarun Wadekar } 29608438e24SVarun Wadekar 29708438e24SVarun Wadekar /******************************************************************************* 29808438e24SVarun Wadekar * Handler called when the system wants to be powered off 29908438e24SVarun Wadekar ******************************************************************************/ 30008438e24SVarun Wadekar __dead2 void tegra_system_off(void) 30108438e24SVarun Wadekar { 30208438e24SVarun Wadekar ERROR("Tegra System Off: operation not handled.\n"); 30308438e24SVarun Wadekar panic(); 30408438e24SVarun Wadekar } 30508438e24SVarun Wadekar 30608438e24SVarun Wadekar /******************************************************************************* 30708438e24SVarun Wadekar * Handler called when the system wants to be restarted. 30808438e24SVarun Wadekar ******************************************************************************/ 30908438e24SVarun Wadekar __dead2 void tegra_system_reset(void) 31008438e24SVarun Wadekar { 31108438e24SVarun Wadekar /* 31208438e24SVarun Wadekar * Program the PMC in order to restart the system. 31308438e24SVarun Wadekar */ 31408438e24SVarun Wadekar tegra_pmc_system_reset(); 31508438e24SVarun Wadekar } 31608438e24SVarun Wadekar 31708438e24SVarun Wadekar /******************************************************************************* 31808438e24SVarun Wadekar * Export the platform handlers to enable psci to invoke them 31908438e24SVarun Wadekar ******************************************************************************/ 32008438e24SVarun Wadekar static const plat_pm_ops_t tegra_plat_pm_ops = { 32108438e24SVarun Wadekar .affinst_standby = tegra_affinst_standby, 32208438e24SVarun Wadekar .affinst_on = tegra_affinst_on, 32308438e24SVarun Wadekar .affinst_off = tegra_affinst_off, 32408438e24SVarun Wadekar .affinst_suspend = tegra_affinst_suspend, 32508438e24SVarun Wadekar .affinst_on_finish = tegra_affinst_on_finish, 32608438e24SVarun Wadekar .affinst_suspend_finish = tegra_affinst_suspend_finish, 32708438e24SVarun Wadekar .system_off = tegra_system_off, 32808438e24SVarun Wadekar .system_reset = tegra_system_reset, 329*94c672e7SVarun Wadekar .validate_power_state = tegra_validate_power_state, 330*94c672e7SVarun Wadekar .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state 33108438e24SVarun Wadekar }; 33208438e24SVarun Wadekar 33308438e24SVarun Wadekar /******************************************************************************* 33408438e24SVarun Wadekar * Export the platform specific power ops & initialize the fvp power controller 33508438e24SVarun Wadekar ******************************************************************************/ 33608438e24SVarun Wadekar int platform_setup_pm(const plat_pm_ops_t **plat_ops) 33708438e24SVarun Wadekar { 33808438e24SVarun Wadekar /* 33908438e24SVarun Wadekar * Reset hardware settings. 34008438e24SVarun Wadekar */ 34108438e24SVarun Wadekar tegra_prepare_cpu_on_finish(read_mpidr()); 34208438e24SVarun Wadekar 34308438e24SVarun Wadekar /* 34408438e24SVarun Wadekar * Initialize PM ops struct 34508438e24SVarun Wadekar */ 34608438e24SVarun Wadekar *plat_ops = &tegra_plat_pm_ops; 34708438e24SVarun Wadekar 34808438e24SVarun Wadekar return 0; 34908438e24SVarun Wadekar } 350