aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/pm.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-02 12:31:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-02 12:31:45 -0400
commit97b1007a2924aaa9126398623f6755a8c3c6a616 (patch)
treeb65c6edb631256e64bb3c72f083fa1be048de097 /arch/arm/mach-tegra/pm.c
parentdfab34aa61a0f8c14a67d7b4c1dae28e57ba592d (diff)
parente0d20b69d3fa74a21ec363989612bddd58b930b8 (diff)
Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform updates from Olof Johansson: "This branch contains part 1 of the platform updates for 3.10. Among the highlights: - Support for the new Atmel Cortex-A5 based platforms (SAMA5D3) - New support for CSR SiRFatlas6 SoCs - A handful of updates for NVidia T114 (a.k.a. Tegra 4) - A bunch of updates for the shmobile platforms - A handful of updates for davinci - A few updates for Qualcomm MSM - Plus a handful of other patches, defconfig updates, etc." * tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (135 commits) ARM: tegra: pm: fix build error w/o PM_SLEEP ARM: davinci: ensure global variables are declared ARM: davinci: sram.c: fix incorrect type in assignment ARM: davinci: da8xx dt: make file local symbols static ARM: davinci: da8xx: add remoteproc support ARM: socfpga: Upgrade clk driver for socfpga to make use of dts clock entries ARM: socfpga: Add clock entries into device tree ARM: socfpga: Enable soft reset ARM: EXYNOS: replace cpumask by the corresponding macro ARM: EXYNOS: handle properly the return values ARM: EXYNOS: factor out the idle states ARM: OMAP4: Enable fix for Cortex-A9 erratas ARM: OMAP2+: Export SoC information to userspace ARM: OMAP2+: SoC name and revision unification ARM: OMAP2+: Move common part of late init into common function ARM: tegra: pm: remove duplicated include from pm.c ARM: davinci: da850: override mmc DT node device name ARM: davinci: da850: add mmc DT entries mmc: davinci_mmc: add DT support ARM: SAMSUNG: check processor type before cache restoration in resume ...
Diffstat (limited to 'arch/arm/mach-tegra/pm.c')
-rw-r--r--arch/arm/mach-tegra/pm.c131
1 files changed, 81 insertions, 50 deletions
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 891fb70d0aa7..45cf52c7e528 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -22,7 +22,7 @@
22#include <linux/cpumask.h> 22#include <linux/cpumask.h>
23#include <linux/delay.h> 23#include <linux/delay.h>
24#include <linux/cpu_pm.h> 24#include <linux/cpu_pm.h>
25#include <linux/clk.h> 25#include <linux/suspend.h>
26#include <linux/err.h> 26#include <linux/err.h>
27#include <linux/clk/tegra.h> 27#include <linux/clk/tegra.h>
28 28
@@ -37,52 +37,13 @@
37#include "reset.h" 37#include "reset.h"
38#include "flowctrl.h" 38#include "flowctrl.h"
39#include "fuse.h" 39#include "fuse.h"
40#include "pmc.h"
40#include "sleep.h" 41#include "sleep.h"
41 42
42#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
43
44#define PMC_CTRL 0x0
45#define PMC_CPUPWRGOOD_TIMER 0xc8
46#define PMC_CPUPWROFF_TIMER 0xcc
47
48#ifdef CONFIG_PM_SLEEP 43#ifdef CONFIG_PM_SLEEP
49static DEFINE_SPINLOCK(tegra_lp2_lock); 44static DEFINE_SPINLOCK(tegra_lp2_lock);
50static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
51static struct clk *tegra_pclk;
52void (*tegra_tear_down_cpu)(void); 45void (*tegra_tear_down_cpu)(void);
53 46
54static void set_power_timers(unsigned long us_on, unsigned long us_off)
55{
56 unsigned long long ticks;
57 unsigned long long pclk;
58 unsigned long rate;
59 static unsigned long tegra_last_pclk;
60
61 if (tegra_pclk == NULL) {
62 tegra_pclk = clk_get_sys(NULL, "pclk");
63 WARN_ON(IS_ERR(tegra_pclk));
64 }
65
66 rate = clk_get_rate(tegra_pclk);
67
68 if (WARN_ON_ONCE(rate <= 0))
69 pclk = 100000000;
70 else
71 pclk = rate;
72
73 if ((rate != tegra_last_pclk)) {
74 ticks = (us_on * pclk) + 999999ull;
75 do_div(ticks, 1000000);
76 writel((unsigned long)ticks, pmc + PMC_CPUPWRGOOD_TIMER);
77
78 ticks = (us_off * pclk) + 999999ull;
79 do_div(ticks, 1000000);
80 writel((unsigned long)ticks, pmc + PMC_CPUPWROFF_TIMER);
81 wmb();
82 }
83 tegra_last_pclk = pclk;
84}
85
86/* 47/*
87 * restore_cpu_complex 48 * restore_cpu_complex
88 * 49 *
@@ -178,16 +139,9 @@ static int tegra_sleep_cpu(unsigned long v2p)
178 return 0; 139 return 0;
179} 140}
180 141
181void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time) 142void tegra_idle_lp2_last(void)
182{ 143{
183 u32 mode; 144 tegra_pmc_pm_set(TEGRA_SUSPEND_LP2);
184
185 /* Only the last cpu down does the final suspend steps */
186 mode = readl(pmc + PMC_CTRL);
187 mode |= TEGRA_POWER_CPU_PWRREQ_OE;
188 writel(mode, pmc + PMC_CTRL);
189
190 set_power_timers(cpu_on_time, cpu_off_time);
191 145
192 cpu_cluster_pm_enter(); 146 cpu_cluster_pm_enter();
193 suspend_cpu_complex(); 147 suspend_cpu_complex();
@@ -197,4 +151,81 @@ void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)
197 restore_cpu_complex(); 151 restore_cpu_complex();
198 cpu_cluster_pm_exit(); 152 cpu_cluster_pm_exit();
199} 153}
154
155enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
156 enum tegra_suspend_mode mode)
157{
158 /* Tegra114 didn't support any suspending mode yet. */
159 if (tegra_chip_id == TEGRA114)
160 return TEGRA_SUSPEND_NONE;
161
162 /*
163 * The Tegra devices only support suspending to LP2 currently.
164 */
165 if (mode > TEGRA_SUSPEND_LP2)
166 return TEGRA_SUSPEND_LP2;
167
168 return mode;
169}
170
171static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
172 [TEGRA_SUSPEND_NONE] = "none",
173 [TEGRA_SUSPEND_LP2] = "LP2",
174 [TEGRA_SUSPEND_LP1] = "LP1",
175 [TEGRA_SUSPEND_LP0] = "LP0",
176};
177
178static int __cpuinit tegra_suspend_enter(suspend_state_t state)
179{
180 enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
181
182 if (WARN_ON(mode < TEGRA_SUSPEND_NONE ||
183 mode >= TEGRA_MAX_SUSPEND_MODE))
184 return -EINVAL;
185
186 pr_info("Entering suspend state %s\n", lp_state[mode]);
187
188 tegra_pmc_pm_set(mode);
189
190 local_fiq_disable();
191
192 suspend_cpu_complex();
193 switch (mode) {
194 case TEGRA_SUSPEND_LP2:
195 tegra_set_cpu_in_lp2(0);
196 break;
197 default:
198 break;
199 }
200
201 cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
202
203 switch (mode) {
204 case TEGRA_SUSPEND_LP2:
205 tegra_clear_cpu_in_lp2(0);
206 break;
207 default:
208 break;
209 }
210 restore_cpu_complex();
211
212 local_fiq_enable();
213
214 return 0;
215}
216
217static const struct platform_suspend_ops tegra_suspend_ops = {
218 .valid = suspend_valid_only_mem,
219 .enter = tegra_suspend_enter,
220};
221
222void __init tegra_init_suspend(void)
223{
224 if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE)
225 return;
226
227 tegra_pmc_suspend_init();
228
229 suspend_set_ops(&tegra_suspend_ops);
230}
200#endif 231#endif