19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d457ef35SJoseph Lo /* 3d457ef35SJoseph Lo * CPU complex suspend & resume functions for Tegra SoCs 4d457ef35SJoseph Lo * 5d457ef35SJoseph Lo * Copyright (c) 2009-2012, NVIDIA Corporation. All rights reserved. 6d457ef35SJoseph Lo */ 7d457ef35SJoseph Lo 889572c77SPrashant Gaikwad #include <linux/clk/tegra.h> 9a0524accSThierry Reding #include <linux/cpumask.h> 10a0524accSThierry Reding #include <linux/cpu_pm.h> 11a0524accSThierry Reding #include <linux/delay.h> 12a0524accSThierry Reding #include <linux/err.h> 13a0524accSThierry Reding #include <linux/io.h> 14a0524accSThierry Reding #include <linux/kernel.h> 15a0524accSThierry Reding #include <linux/slab.h> 16a0524accSThierry Reding #include <linux/spinlock.h> 17a0524accSThierry Reding #include <linux/suspend.h> 18d552920aSJoseph Lo 194cb5d9ecSThierry Reding #include <linux/firmware/trusted_foundations.h> 204cb5d9ecSThierry Reding 217e10cf74SJon Hunter #include <soc/tegra/flowctrl.h> 22304664eaSThierry Reding #include <soc/tegra/fuse.h> 237232398aSThierry Reding #include <soc/tegra/pm.h> 247232398aSThierry Reding #include <soc/tegra/pmc.h> 25304664eaSThierry Reding 26d552920aSJoseph Lo #include <asm/cacheflush.h> 2778ee399fSDmitry Osipenko #include <asm/firmware.h> 28d552920aSJoseph Lo #include <asm/idmap.h> 29d552920aSJoseph Lo #include <asm/proc-fns.h> 30a0524accSThierry Reding #include <asm/smp_plat.h> 31a0524accSThierry Reding #include <asm/suspend.h> 32d552920aSJoseph Lo #include <asm/tlbflush.h> 33d457ef35SJoseph Lo 34a0524accSThierry Reding #include "iomap.h" 35a0524accSThierry Reding #include "pm.h" 36a0524accSThierry Reding #include "reset.h" 37d552920aSJoseph Lo #include "sleep.h" 38d552920aSJoseph Lo 39d457ef35SJoseph Lo #ifdef CONFIG_PM_SLEEP 40d457ef35SJoseph Lo static DEFINE_SPINLOCK(tegra_lp2_lock); 4195872f42SJoseph Lo static u32 iram_save_size; 4295872f42SJoseph Lo static void *iram_save_addr; 4395872f42SJoseph Lo struct tegra_lp1_iram tegra_lp1_iram; 44d552920aSJoseph Lo void (*tegra_tear_down_cpu)(void); 4595872f42SJoseph Lo void (*tegra_sleep_core_finish)(unsigned long v2p); 4695872f42SJoseph Lo static int (*tegra_sleep_func)(unsigned long v2p); 47d457ef35SJoseph Lo 48bf91add4SJoseph Lo static void tegra_tear_down_cpu_init(void) 49bf91add4SJoseph Lo { 50304664eaSThierry Reding switch (tegra_get_chip_id()) { 51bf91add4SJoseph Lo case TEGRA20: 52bf91add4SJoseph Lo if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) 53bf91add4SJoseph Lo tegra_tear_down_cpu = tegra20_tear_down_cpu; 54bf91add4SJoseph Lo break; 55bf91add4SJoseph Lo case TEGRA30: 56b573ad9fSJoseph Lo case TEGRA114: 57f0c4ac13SJoseph Lo case TEGRA124: 58b573ad9fSJoseph Lo if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) || 59f0c4ac13SJoseph Lo IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) || 60f0c4ac13SJoseph Lo IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)) 61bf91add4SJoseph Lo tegra_tear_down_cpu = tegra30_tear_down_cpu; 62bf91add4SJoseph Lo break; 63bf91add4SJoseph Lo } 64bf91add4SJoseph Lo } 65bf91add4SJoseph Lo 66d552920aSJoseph Lo /* 67d552920aSJoseph Lo * restore_cpu_complex 68d552920aSJoseph Lo * 69d552920aSJoseph Lo * restores cpu clock setting, clears flow controller 70d552920aSJoseph Lo * 71d552920aSJoseph Lo * Always called on CPU 0. 72d552920aSJoseph Lo */ 73d552920aSJoseph Lo static void restore_cpu_complex(void) 74d552920aSJoseph Lo { 75d552920aSJoseph Lo int cpu = smp_processor_id(); 76d552920aSJoseph Lo 77d552920aSJoseph Lo BUG_ON(cpu != 0); 78d552920aSJoseph Lo 79d552920aSJoseph Lo #ifdef CONFIG_SMP 80d552920aSJoseph Lo cpu = cpu_logical_map(cpu); 81d552920aSJoseph Lo #endif 82d552920aSJoseph Lo 83d552920aSJoseph Lo /* Restore the CPU clock settings */ 84d552920aSJoseph Lo tegra_cpu_clock_resume(); 85d552920aSJoseph Lo 86d552920aSJoseph Lo flowctrl_cpu_suspend_exit(cpu); 87d552920aSJoseph Lo } 88d552920aSJoseph Lo 89d552920aSJoseph Lo /* 90d552920aSJoseph Lo * suspend_cpu_complex 91d552920aSJoseph Lo * 92d552920aSJoseph Lo * saves pll state for use by restart_plls, prepares flow controller for 93d552920aSJoseph Lo * transition to suspend state 94d552920aSJoseph Lo * 95d552920aSJoseph Lo * Must always be called on cpu 0. 96d552920aSJoseph Lo */ 97d552920aSJoseph Lo static void suspend_cpu_complex(void) 98d552920aSJoseph Lo { 99d552920aSJoseph Lo int cpu = smp_processor_id(); 100d552920aSJoseph Lo 101d552920aSJoseph Lo BUG_ON(cpu != 0); 102d552920aSJoseph Lo 103d552920aSJoseph Lo #ifdef CONFIG_SMP 104d552920aSJoseph Lo cpu = cpu_logical_map(cpu); 105d552920aSJoseph Lo #endif 106d552920aSJoseph Lo 107d552920aSJoseph Lo /* Save the CPU clock settings */ 108d552920aSJoseph Lo tegra_cpu_clock_suspend(); 109d552920aSJoseph Lo 110d552920aSJoseph Lo flowctrl_cpu_suspend_enter(cpu); 111d552920aSJoseph Lo } 112d552920aSJoseph Lo 1131f3e18ecSDmitry Osipenko void tegra_pm_clear_cpu_in_lp2(void) 114d457ef35SJoseph Lo { 1158f6a0b65SJoseph Lo int phy_cpu_id = cpu_logical_map(smp_processor_id()); 116d457ef35SJoseph Lo u32 *cpu_in_lp2 = tegra_cpu_lp2_mask; 117d457ef35SJoseph Lo 118d457ef35SJoseph Lo spin_lock(&tegra_lp2_lock); 119d457ef35SJoseph Lo 120d457ef35SJoseph Lo BUG_ON(!(*cpu_in_lp2 & BIT(phy_cpu_id))); 121d457ef35SJoseph Lo *cpu_in_lp2 &= ~BIT(phy_cpu_id); 122d457ef35SJoseph Lo 123d457ef35SJoseph Lo spin_unlock(&tegra_lp2_lock); 124d457ef35SJoseph Lo } 125d457ef35SJoseph Lo 1261f3e18ecSDmitry Osipenko void tegra_pm_set_cpu_in_lp2(void) 127d457ef35SJoseph Lo { 1288f6a0b65SJoseph Lo int phy_cpu_id = cpu_logical_map(smp_processor_id()); 129d457ef35SJoseph Lo u32 *cpu_in_lp2 = tegra_cpu_lp2_mask; 130d457ef35SJoseph Lo 131d457ef35SJoseph Lo spin_lock(&tegra_lp2_lock); 132d457ef35SJoseph Lo 133d457ef35SJoseph Lo BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id))); 134d457ef35SJoseph Lo *cpu_in_lp2 |= BIT(phy_cpu_id); 135d457ef35SJoseph Lo 136d457ef35SJoseph Lo spin_unlock(&tegra_lp2_lock); 137d457ef35SJoseph Lo } 138d552920aSJoseph Lo 139d552920aSJoseph Lo static int tegra_sleep_cpu(unsigned long v2p) 140d552920aSJoseph Lo { 1417ed50dd5SDmitry Osipenko if (tegra_cpu_car_ops->rail_off_ready && 1427ed50dd5SDmitry Osipenko WARN_ON(!tegra_cpu_rail_off_ready())) 1437ed50dd5SDmitry Osipenko return -EBUSY; 1447ed50dd5SDmitry Osipenko 14578ee399fSDmitry Osipenko /* 14678ee399fSDmitry Osipenko * L2 cache disabling using kernel API only allowed when all 14778ee399fSDmitry Osipenko * secondary CPU's are offline. Cache have to be disabled with 14878ee399fSDmitry Osipenko * MMU-on if cache maintenance is done via Trusted Foundations 14978ee399fSDmitry Osipenko * firmware. Note that CPUIDLE won't ever enter powergate on Tegra30 15078ee399fSDmitry Osipenko * if any of secondary CPU's is online and this is the LP2-idle 15178ee399fSDmitry Osipenko * code-path only for Tegra20/30. 15278ee399fSDmitry Osipenko */ 1537ed50dd5SDmitry Osipenko #ifdef CONFIG_OUTER_CACHE 1547ed50dd5SDmitry Osipenko if (trusted_foundations_registered() && outer_cache.disable) 1557ed50dd5SDmitry Osipenko outer_cache.disable(); 1567ed50dd5SDmitry Osipenko #endif 15778ee399fSDmitry Osipenko /* 15878ee399fSDmitry Osipenko * Note that besides of setting up CPU reset vector this firmware 15978ee399fSDmitry Osipenko * call may also do the following, depending on the FW version: 16078ee399fSDmitry Osipenko * 1) Disable L2. But this doesn't matter since we already 16178ee399fSDmitry Osipenko * disabled the L2. 16278ee399fSDmitry Osipenko * 2) Disable D-cache. This need to be taken into account in 16378ee399fSDmitry Osipenko * particular by the tegra_disable_clean_inv_dcache() which 16478ee399fSDmitry Osipenko * shall avoid the re-disable. 16578ee399fSDmitry Osipenko */ 16678ee399fSDmitry Osipenko call_firmware_op(prepare_idle, TF_PM_MODE_LP2); 16778ee399fSDmitry Osipenko 1686affb482SWill Deacon setup_mm_for_reboot(); 169d552920aSJoseph Lo tegra_sleep_cpu_finish(v2p); 170d552920aSJoseph Lo 171d552920aSJoseph Lo /* should never here */ 172d552920aSJoseph Lo BUG(); 173d552920aSJoseph Lo 174d552920aSJoseph Lo return 0; 175d552920aSJoseph Lo } 176d552920aSJoseph Lo 1777232398aSThierry Reding static void tegra_pm_set(enum tegra_suspend_mode mode) 1787232398aSThierry Reding { 1797232398aSThierry Reding u32 value; 1807232398aSThierry Reding 1817232398aSThierry Reding switch (tegra_get_chip_id()) { 1827232398aSThierry Reding case TEGRA20: 1837232398aSThierry Reding case TEGRA30: 1847232398aSThierry Reding break; 1857232398aSThierry Reding default: 1867232398aSThierry Reding /* Turn off CRAIL */ 1877232398aSThierry Reding value = flowctrl_read_cpu_csr(0); 1887232398aSThierry Reding value &= ~FLOW_CTRL_CSR_ENABLE_EXT_MASK; 1897232398aSThierry Reding value |= FLOW_CTRL_CSR_ENABLE_EXT_CRAIL; 1907232398aSThierry Reding flowctrl_write_cpu_csr(0, value); 1917232398aSThierry Reding break; 1927232398aSThierry Reding } 1937232398aSThierry Reding 1947232398aSThierry Reding tegra_pmc_enter_suspend_mode(mode); 1957232398aSThierry Reding } 1967232398aSThierry Reding 1971f3e18ecSDmitry Osipenko int tegra_pm_enter_lp2(void) 198d552920aSJoseph Lo { 199891e1286SDmitry Osipenko int err; 200891e1286SDmitry Osipenko 2017232398aSThierry Reding tegra_pm_set(TEGRA_SUSPEND_LP2); 202d552920aSJoseph Lo 203d552920aSJoseph Lo cpu_cluster_pm_enter(); 204d552920aSJoseph Lo suspend_cpu_complex(); 205d552920aSJoseph Lo 206891e1286SDmitry Osipenko err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu); 207d552920aSJoseph Lo 20878ee399fSDmitry Osipenko /* 20978ee399fSDmitry Osipenko * Resume L2 cache if it wasn't re-enabled early during resume, 21078ee399fSDmitry Osipenko * which is the case for Tegra30 that has to re-enable the cache 21178ee399fSDmitry Osipenko * via firmware call. In other cases cache is already enabled and 21278ee399fSDmitry Osipenko * hence re-enabling is a no-op. This is always a no-op on Tegra114+. 21378ee399fSDmitry Osipenko */ 21478ee399fSDmitry Osipenko outer_resume(); 21578ee399fSDmitry Osipenko 216d552920aSJoseph Lo restore_cpu_complex(); 217d552920aSJoseph Lo cpu_cluster_pm_exit(); 218891e1286SDmitry Osipenko 21938743e41SDmitry Osipenko call_firmware_op(prepare_idle, TF_PM_MODE_NONE); 22038743e41SDmitry Osipenko 221891e1286SDmitry Osipenko return err; 222d552920aSJoseph Lo } 223c8c2e606SJoseph Lo 224c8c2e606SJoseph Lo enum tegra_suspend_mode tegra_pm_validate_suspend_mode( 225c8c2e606SJoseph Lo enum tegra_suspend_mode mode) 226c8c2e606SJoseph Lo { 227c8c2e606SJoseph Lo /* 22895872f42SJoseph Lo * The Tegra devices support suspending to LP1 or lower currently. 229c8c2e606SJoseph Lo */ 23095872f42SJoseph Lo if (mode > TEGRA_SUSPEND_LP1) 23195872f42SJoseph Lo return TEGRA_SUSPEND_LP1; 232c8c2e606SJoseph Lo 233c8c2e606SJoseph Lo return mode; 234c8c2e606SJoseph Lo } 235c8c2e606SJoseph Lo 23695872f42SJoseph Lo static int tegra_sleep_core(unsigned long v2p) 23795872f42SJoseph Lo { 23878ee399fSDmitry Osipenko /* 23978ee399fSDmitry Osipenko * Cache have to be disabled with MMU-on if cache maintenance is done 24078ee399fSDmitry Osipenko * via Trusted Foundations firmware. This is a no-op on Tegra114+. 24178ee399fSDmitry Osipenko */ 24278ee399fSDmitry Osipenko if (trusted_foundations_registered()) 24378ee399fSDmitry Osipenko outer_disable(); 24478ee399fSDmitry Osipenko 24578ee399fSDmitry Osipenko call_firmware_op(prepare_idle, TF_PM_MODE_LP1); 24678ee399fSDmitry Osipenko 24795872f42SJoseph Lo setup_mm_for_reboot(); 24895872f42SJoseph Lo tegra_sleep_core_finish(v2p); 24995872f42SJoseph Lo 25095872f42SJoseph Lo /* should never here */ 25195872f42SJoseph Lo BUG(); 25295872f42SJoseph Lo 25395872f42SJoseph Lo return 0; 25495872f42SJoseph Lo } 25595872f42SJoseph Lo 25695872f42SJoseph Lo /* 25795872f42SJoseph Lo * tegra_lp1_iram_hook 25895872f42SJoseph Lo * 25995872f42SJoseph Lo * Hooking the address of LP1 reset vector and SDRAM self-refresh code in 26095872f42SJoseph Lo * SDRAM. These codes not be copied to IRAM in this fuction. We need to 26195872f42SJoseph Lo * copy these code to IRAM before LP0/LP1 suspend and restore the content 26295872f42SJoseph Lo * of IRAM after resume. 26395872f42SJoseph Lo */ 26495872f42SJoseph Lo static bool tegra_lp1_iram_hook(void) 26595872f42SJoseph Lo { 266304664eaSThierry Reding switch (tegra_get_chip_id()) { 267731a9274SJoseph Lo case TEGRA20: 268731a9274SJoseph Lo if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) 269731a9274SJoseph Lo tegra20_lp1_iram_hook(); 270731a9274SJoseph Lo break; 271e7a932b1SJoseph Lo case TEGRA30: 272e9f62449SJoseph Lo case TEGRA114: 273f0c4ac13SJoseph Lo case TEGRA124: 274e9f62449SJoseph Lo if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) || 275f0c4ac13SJoseph Lo IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) || 276f0c4ac13SJoseph Lo IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)) 277e7a932b1SJoseph Lo tegra30_lp1_iram_hook(); 278e7a932b1SJoseph Lo break; 279e7a932b1SJoseph Lo default: 280e7a932b1SJoseph Lo break; 281e7a932b1SJoseph Lo } 282e7a932b1SJoseph Lo 28395872f42SJoseph Lo if (!tegra_lp1_iram.start_addr || !tegra_lp1_iram.end_addr) 28495872f42SJoseph Lo return false; 28595872f42SJoseph Lo 28695872f42SJoseph Lo iram_save_size = tegra_lp1_iram.end_addr - tegra_lp1_iram.start_addr; 28795872f42SJoseph Lo iram_save_addr = kmalloc(iram_save_size, GFP_KERNEL); 28895872f42SJoseph Lo if (!iram_save_addr) 28995872f42SJoseph Lo return false; 29095872f42SJoseph Lo 29195872f42SJoseph Lo return true; 29295872f42SJoseph Lo } 29395872f42SJoseph Lo 29495872f42SJoseph Lo static bool tegra_sleep_core_init(void) 29595872f42SJoseph Lo { 296304664eaSThierry Reding switch (tegra_get_chip_id()) { 297731a9274SJoseph Lo case TEGRA20: 298731a9274SJoseph Lo if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) 299731a9274SJoseph Lo tegra20_sleep_core_init(); 300731a9274SJoseph Lo break; 301e7a932b1SJoseph Lo case TEGRA30: 302e9f62449SJoseph Lo case TEGRA114: 303f0c4ac13SJoseph Lo case TEGRA124: 304e9f62449SJoseph Lo if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) || 305f0c4ac13SJoseph Lo IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) || 306f0c4ac13SJoseph Lo IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)) 307e7a932b1SJoseph Lo tegra30_sleep_core_init(); 308e7a932b1SJoseph Lo break; 309e7a932b1SJoseph Lo default: 310e7a932b1SJoseph Lo break; 311e7a932b1SJoseph Lo } 312e7a932b1SJoseph Lo 31395872f42SJoseph Lo if (!tegra_sleep_core_finish) 31495872f42SJoseph Lo return false; 31595872f42SJoseph Lo 31695872f42SJoseph Lo return true; 31795872f42SJoseph Lo } 31895872f42SJoseph Lo 31995872f42SJoseph Lo static void tegra_suspend_enter_lp1(void) 32095872f42SJoseph Lo { 32195872f42SJoseph Lo /* copy the reset vector & SDRAM shutdown code into IRAM */ 322fddb770dSStephen Warren memcpy(iram_save_addr, IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA), 32395872f42SJoseph Lo iram_save_size); 324fddb770dSStephen Warren memcpy(IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA), 325fddb770dSStephen Warren tegra_lp1_iram.start_addr, iram_save_size); 32695872f42SJoseph Lo 32795872f42SJoseph Lo *((u32 *)tegra_cpu_lp1_mask) = 1; 32895872f42SJoseph Lo } 32995872f42SJoseph Lo 33095872f42SJoseph Lo static void tegra_suspend_exit_lp1(void) 33195872f42SJoseph Lo { 33295872f42SJoseph Lo /* restore IRAM */ 333fddb770dSStephen Warren memcpy(IO_ADDRESS(TEGRA_IRAM_LPx_RESUME_AREA), iram_save_addr, 33495872f42SJoseph Lo iram_save_size); 33595872f42SJoseph Lo 33695872f42SJoseph Lo *(u32 *)tegra_cpu_lp1_mask = 0; 33795872f42SJoseph Lo } 33895872f42SJoseph Lo 339c8c2e606SJoseph Lo static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = { 340c8c2e606SJoseph Lo [TEGRA_SUSPEND_NONE] = "none", 341c8c2e606SJoseph Lo [TEGRA_SUSPEND_LP2] = "LP2", 342c8c2e606SJoseph Lo [TEGRA_SUSPEND_LP1] = "LP1", 343c8c2e606SJoseph Lo [TEGRA_SUSPEND_LP0] = "LP0", 344c8c2e606SJoseph Lo }; 345c8c2e606SJoseph Lo 3468bd26e3aSPaul Gortmaker static int tegra_suspend_enter(suspend_state_t state) 347c8c2e606SJoseph Lo { 348c8c2e606SJoseph Lo enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode(); 349c8c2e606SJoseph Lo 350c8c2e606SJoseph Lo if (WARN_ON(mode < TEGRA_SUSPEND_NONE || 351c8c2e606SJoseph Lo mode >= TEGRA_MAX_SUSPEND_MODE)) 352c8c2e606SJoseph Lo return -EINVAL; 353c8c2e606SJoseph Lo 354c8c2e606SJoseph Lo pr_info("Entering suspend state %s\n", lp_state[mode]); 355c8c2e606SJoseph Lo 3567232398aSThierry Reding tegra_pm_set(mode); 357c8c2e606SJoseph Lo 358c8c2e606SJoseph Lo local_fiq_disable(); 359c8c2e606SJoseph Lo 360c8c2e606SJoseph Lo suspend_cpu_complex(); 361c8c2e606SJoseph Lo switch (mode) { 36295872f42SJoseph Lo case TEGRA_SUSPEND_LP1: 36395872f42SJoseph Lo tegra_suspend_enter_lp1(); 36495872f42SJoseph Lo break; 365c8c2e606SJoseph Lo case TEGRA_SUSPEND_LP2: 3661f3e18ecSDmitry Osipenko tegra_pm_set_cpu_in_lp2(); 367c8c2e606SJoseph Lo break; 368c8c2e606SJoseph Lo default: 369c8c2e606SJoseph Lo break; 370c8c2e606SJoseph Lo } 371c8c2e606SJoseph Lo 37295872f42SJoseph Lo cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, tegra_sleep_func); 373c8c2e606SJoseph Lo 37478ee399fSDmitry Osipenko /* 37578ee399fSDmitry Osipenko * Resume L2 cache if it wasn't re-enabled early during resume, 37678ee399fSDmitry Osipenko * which is the case for Tegra30 that has to re-enable the cache 37778ee399fSDmitry Osipenko * via firmware call. In other cases cache is already enabled and 37878ee399fSDmitry Osipenko * hence re-enabling is a no-op. 37978ee399fSDmitry Osipenko */ 38078ee399fSDmitry Osipenko outer_resume(); 38178ee399fSDmitry Osipenko 382c8c2e606SJoseph Lo switch (mode) { 38395872f42SJoseph Lo case TEGRA_SUSPEND_LP1: 38495872f42SJoseph Lo tegra_suspend_exit_lp1(); 38595872f42SJoseph Lo break; 386c8c2e606SJoseph Lo case TEGRA_SUSPEND_LP2: 3871f3e18ecSDmitry Osipenko tegra_pm_clear_cpu_in_lp2(); 388c8c2e606SJoseph Lo break; 389c8c2e606SJoseph Lo default: 390c8c2e606SJoseph Lo break; 391c8c2e606SJoseph Lo } 392c8c2e606SJoseph Lo restore_cpu_complex(); 393c8c2e606SJoseph Lo 394c8c2e606SJoseph Lo local_fiq_enable(); 395c8c2e606SJoseph Lo 39638743e41SDmitry Osipenko call_firmware_op(prepare_idle, TF_PM_MODE_NONE); 39738743e41SDmitry Osipenko 398c8c2e606SJoseph Lo return 0; 399c8c2e606SJoseph Lo } 400c8c2e606SJoseph Lo 401c8c2e606SJoseph Lo static const struct platform_suspend_ops tegra_suspend_ops = { 402c8c2e606SJoseph Lo .valid = suspend_valid_only_mem, 403c8c2e606SJoseph Lo .enter = tegra_suspend_enter, 404c8c2e606SJoseph Lo }; 405c8c2e606SJoseph Lo 406*9c93ccfcSDmitry Osipenko void tegra_pm_init_suspend(void) 407c8c2e606SJoseph Lo { 40895872f42SJoseph Lo enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode(); 40995872f42SJoseph Lo 41095872f42SJoseph Lo if (mode == TEGRA_SUSPEND_NONE) 411c8c2e606SJoseph Lo return; 412c8c2e606SJoseph Lo 413bf91add4SJoseph Lo tegra_tear_down_cpu_init(); 414c8c2e606SJoseph Lo 41595872f42SJoseph Lo if (mode >= TEGRA_SUSPEND_LP1) { 41695872f42SJoseph Lo if (!tegra_lp1_iram_hook() || !tegra_sleep_core_init()) { 41795872f42SJoseph Lo pr_err("%s: unable to allocate memory for SDRAM" 41895872f42SJoseph Lo "self-refresh -- LP0/LP1 unavailable\n", 41995872f42SJoseph Lo __func__); 42095872f42SJoseph Lo tegra_pmc_set_suspend_mode(TEGRA_SUSPEND_LP2); 42195872f42SJoseph Lo mode = TEGRA_SUSPEND_LP2; 42295872f42SJoseph Lo } 42395872f42SJoseph Lo } 42495872f42SJoseph Lo 42595872f42SJoseph Lo /* set up sleep function for cpu_suspend */ 42695872f42SJoseph Lo switch (mode) { 42795872f42SJoseph Lo case TEGRA_SUSPEND_LP1: 42895872f42SJoseph Lo tegra_sleep_func = tegra_sleep_core; 42995872f42SJoseph Lo break; 43095872f42SJoseph Lo case TEGRA_SUSPEND_LP2: 43195872f42SJoseph Lo tegra_sleep_func = tegra_sleep_cpu; 43295872f42SJoseph Lo break; 43395872f42SJoseph Lo default: 43495872f42SJoseph Lo break; 43595872f42SJoseph Lo } 43695872f42SJoseph Lo 437c8c2e606SJoseph Lo suspend_set_ops(&tegra_suspend_ops); 438c8c2e606SJoseph Lo } 439859a6f6eSDmitry Osipenko 440859a6f6eSDmitry Osipenko int tegra_pm_park_secondary_cpu(unsigned long cpu) 441859a6f6eSDmitry Osipenko { 442859a6f6eSDmitry Osipenko if (cpu > 0) { 443859a6f6eSDmitry Osipenko tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS); 444859a6f6eSDmitry Osipenko 445859a6f6eSDmitry Osipenko if (tegra_get_chip_id() == TEGRA20) 446859a6f6eSDmitry Osipenko tegra20_hotplug_shutdown(); 447859a6f6eSDmitry Osipenko else 448859a6f6eSDmitry Osipenko tegra30_hotplug_shutdown(); 449859a6f6eSDmitry Osipenko } 450859a6f6eSDmitry Osipenko 451859a6f6eSDmitry Osipenko return -EINVAL; 452859a6f6eSDmitry Osipenko } 453d457ef35SJoseph Lo #endif 454