1 /* 2 * CPU complex suspend & resume functions for Tegra SoCs 3 * 4 * Copyright (c) 2009-2012, NVIDIA Corporation. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/spinlock.h> 21 #include <linux/io.h> 22 #include <linux/cpumask.h> 23 #include <linux/delay.h> 24 #include <linux/cpu_pm.h> 25 #include <linux/err.h> 26 #include <linux/clk/tegra.h> 27 28 #include <asm/smp_plat.h> 29 #include <asm/cacheflush.h> 30 #include <asm/suspend.h> 31 #include <asm/idmap.h> 32 #include <asm/proc-fns.h> 33 #include <asm/tlbflush.h> 34 35 #include "iomap.h" 36 #include "reset.h" 37 #include "flowctrl.h" 38 #include "fuse.h" 39 #include "pmc.h" 40 #include "sleep.h" 41 42 #define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ 43 44 #define PMC_CTRL 0x0 45 46 #ifdef CONFIG_PM_SLEEP 47 static DEFINE_SPINLOCK(tegra_lp2_lock); 48 static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); 49 void (*tegra_tear_down_cpu)(void); 50 51 /* 52 * restore_cpu_complex 53 * 54 * restores cpu clock setting, clears flow controller 55 * 56 * Always called on CPU 0. 57 */ 58 static void restore_cpu_complex(void) 59 { 60 int cpu = smp_processor_id(); 61 62 BUG_ON(cpu != 0); 63 64 #ifdef CONFIG_SMP 65 cpu = cpu_logical_map(cpu); 66 #endif 67 68 /* Restore the CPU clock settings */ 69 tegra_cpu_clock_resume(); 70 71 flowctrl_cpu_suspend_exit(cpu); 72 } 73 74 /* 75 * suspend_cpu_complex 76 * 77 * saves pll state for use by restart_plls, prepares flow controller for 78 * transition to suspend state 79 * 80 * Must always be called on cpu 0. 81 */ 82 static void suspend_cpu_complex(void) 83 { 84 int cpu = smp_processor_id(); 85 86 BUG_ON(cpu != 0); 87 88 #ifdef CONFIG_SMP 89 cpu = cpu_logical_map(cpu); 90 #endif 91 92 /* Save the CPU clock settings */ 93 tegra_cpu_clock_suspend(); 94 95 flowctrl_cpu_suspend_enter(cpu); 96 } 97 98 void tegra_clear_cpu_in_lp2(int phy_cpu_id) 99 { 100 u32 *cpu_in_lp2 = tegra_cpu_lp2_mask; 101 102 spin_lock(&tegra_lp2_lock); 103 104 BUG_ON(!(*cpu_in_lp2 & BIT(phy_cpu_id))); 105 *cpu_in_lp2 &= ~BIT(phy_cpu_id); 106 107 spin_unlock(&tegra_lp2_lock); 108 } 109 110 bool tegra_set_cpu_in_lp2(int phy_cpu_id) 111 { 112 bool last_cpu = false; 113 cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask; 114 u32 *cpu_in_lp2 = tegra_cpu_lp2_mask; 115 116 spin_lock(&tegra_lp2_lock); 117 118 BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id))); 119 *cpu_in_lp2 |= BIT(phy_cpu_id); 120 121 if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask)) 122 last_cpu = true; 123 else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1) 124 tegra20_cpu_set_resettable_soon(); 125 126 spin_unlock(&tegra_lp2_lock); 127 return last_cpu; 128 } 129 130 static int tegra_sleep_cpu(unsigned long v2p) 131 { 132 /* Switch to the identity mapping. */ 133 cpu_switch_mm(idmap_pgd, &init_mm); 134 135 /* Flush the TLB. */ 136 local_flush_tlb_all(); 137 138 tegra_sleep_cpu_finish(v2p); 139 140 /* should never here */ 141 BUG(); 142 143 return 0; 144 } 145 146 void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time) 147 { 148 u32 mode; 149 150 /* Only the last cpu down does the final suspend steps */ 151 mode = readl(pmc + PMC_CTRL); 152 mode |= TEGRA_POWER_CPU_PWRREQ_OE; 153 writel(mode, pmc + PMC_CTRL); 154 155 set_power_timers(cpu_on_time, cpu_off_time); 156 157 cpu_cluster_pm_enter(); 158 suspend_cpu_complex(); 159 160 cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu); 161 162 restore_cpu_complex(); 163 cpu_cluster_pm_exit(); 164 } 165 #endif 166