diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-02 12:31:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-02 12:31:45 -0400 |
commit | 97b1007a2924aaa9126398623f6755a8c3c6a616 (patch) | |
tree | b65c6edb631256e64bb3c72f083fa1be048de097 /arch/arm/mach-tegra/pm.c | |
parent | dfab34aa61a0f8c14a67d7b4c1dae28e57ba592d (diff) | |
parent | e0d20b69d3fa74a21ec363989612bddd58b930b8 (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.c | 131 |
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 |
49 | static DEFINE_SPINLOCK(tegra_lp2_lock); | 44 | static DEFINE_SPINLOCK(tegra_lp2_lock); |
50 | static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); | ||
51 | static struct clk *tegra_pclk; | ||
52 | void (*tegra_tear_down_cpu)(void); | 45 | void (*tegra_tear_down_cpu)(void); |
53 | 46 | ||
54 | static 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 | ||
181 | void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time) | 142 | void 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 | |||
155 | enum 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 | |||
171 | static 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 | |||
178 | static 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 | |||
217 | static const struct platform_suspend_ops tegra_suspend_ops = { | ||
218 | .valid = suspend_valid_only_mem, | ||
219 | .enter = tegra_suspend_enter, | ||
220 | }; | ||
221 | |||
222 | void __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 |