diff options
author | keita kobayashi <keita.kobayashi.ym@renesas.com> | 2014-05-29 03:24:27 -0400 |
---|---|---|
committer | Simon Horman <horms+renesas@verge.net.au> | 2014-06-17 06:32:06 -0400 |
commit | d6d757c9a4e06e118fa5158fa74e03c514d862d2 (patch) | |
tree | 27c59bbe976a568cf6ee0daf81d89e98cf1ea6c1 | |
parent | 5f6108bb9643949bf5ec0bc9f5cbde588c542c7f (diff) |
ARM: shmobile: APMU: Add Core-Standby-state for Suspend to RAM
This patch add Core-Standby-state for Suspend to RAM.
Signed-off-by: Keita Kobayashi <keita.kobayashi.ym@renesas.com>
Acked-by: Magnus Damm <damm+renesas@opensource.se>
[horms+renesas@verge.net.au: rebase]
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
-rw-r--r-- | arch/arm/mach-shmobile/common.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/platsmp-apmu.c | 60 |
2 files changed, 58 insertions, 4 deletions
diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h index f7a360edcc35..8f0cd5791583 100644 --- a/arch/arm/mach-shmobile/common.h +++ b/arch/arm/mach-shmobile/common.h | |||
@@ -35,8 +35,10 @@ extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv); | |||
35 | 35 | ||
36 | #ifdef CONFIG_SUSPEND | 36 | #ifdef CONFIG_SUSPEND |
37 | int shmobile_suspend_init(void); | 37 | int shmobile_suspend_init(void); |
38 | void shmobile_smp_apmu_suspend_init(void); | ||
38 | #else | 39 | #else |
39 | static inline int shmobile_suspend_init(void) { return 0; } | 40 | static inline int shmobile_suspend_init(void) { return 0; } |
41 | static inline void shmobile_smp_apmu_suspend_init(void) { return 0; } | ||
40 | #endif | 42 | #endif |
41 | 43 | ||
42 | #ifdef CONFIG_CPU_IDLE | 44 | #ifdef CONFIG_CPU_IDLE |
diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c index fe648f5d8f06..590e35c22a60 100644 --- a/arch/arm/mach-shmobile/platsmp-apmu.c +++ b/arch/arm/mach-shmobile/platsmp-apmu.c | |||
@@ -7,15 +7,19 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/cpu_pm.h> | ||
10 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
11 | #include <linux/init.h> | 12 | #include <linux/init.h> |
12 | #include <linux/io.h> | 13 | #include <linux/io.h> |
13 | #include <linux/ioport.h> | 14 | #include <linux/ioport.h> |
14 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
15 | #include <linux/smp.h> | 16 | #include <linux/smp.h> |
17 | #include <linux/suspend.h> | ||
16 | #include <asm/cacheflush.h> | 18 | #include <asm/cacheflush.h> |
17 | #include <asm/cp15.h> | 19 | #include <asm/cp15.h> |
20 | #include <asm/proc-fns.h> | ||
18 | #include <asm/smp_plat.h> | 21 | #include <asm/smp_plat.h> |
22 | #include <asm/suspend.h> | ||
19 | #include "common.h" | 23 | #include "common.h" |
20 | 24 | ||
21 | static struct { | 25 | static struct { |
@@ -141,7 +145,7 @@ int shmobile_smp_apmu_boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
141 | return apmu_wrap(cpu, apmu_power_on); | 145 | return apmu_wrap(cpu, apmu_power_on); |
142 | } | 146 | } |
143 | 147 | ||
144 | #ifdef CONFIG_HOTPLUG_CPU | 148 | #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND) |
145 | /* nicked from arch/arm/mach-exynos/hotplug.c */ | 149 | /* nicked from arch/arm/mach-exynos/hotplug.c */ |
146 | static inline void cpu_enter_lowpower_a15(void) | 150 | static inline void cpu_enter_lowpower_a15(void) |
147 | { | 151 | { |
@@ -172,16 +176,40 @@ static inline void cpu_enter_lowpower_a15(void) | |||
172 | dsb(); | 176 | dsb(); |
173 | } | 177 | } |
174 | 178 | ||
175 | void shmobile_smp_apmu_cpu_die(unsigned int cpu) | 179 | void shmobile_smp_apmu_cpu_shutdown(unsigned int cpu) |
176 | { | 180 | { |
177 | /* For this particular CPU deregister boot vector */ | ||
178 | shmobile_smp_hook(cpu, 0, 0); | ||
179 | 181 | ||
180 | /* Select next sleep mode using the APMU */ | 182 | /* Select next sleep mode using the APMU */ |
181 | apmu_wrap(cpu, apmu_power_off); | 183 | apmu_wrap(cpu, apmu_power_off); |
182 | 184 | ||
183 | /* Do ARM specific CPU shutdown */ | 185 | /* Do ARM specific CPU shutdown */ |
184 | cpu_enter_lowpower_a15(); | 186 | cpu_enter_lowpower_a15(); |
187 | } | ||
188 | |||
189 | static inline void cpu_leave_lowpower(void) | ||
190 | { | ||
191 | unsigned int v; | ||
192 | |||
193 | asm volatile("mrc p15, 0, %0, c1, c0, 0\n" | ||
194 | " orr %0, %0, %1\n" | ||
195 | " mcr p15, 0, %0, c1, c0, 0\n" | ||
196 | " mrc p15, 0, %0, c1, c0, 1\n" | ||
197 | " orr %0, %0, %2\n" | ||
198 | " mcr p15, 0, %0, c1, c0, 1\n" | ||
199 | : "=&r" (v) | ||
200 | : "Ir" (CR_C), "Ir" (0x40) | ||
201 | : "cc"); | ||
202 | } | ||
203 | #endif | ||
204 | |||
205 | #if defined(CONFIG_HOTPLUG_CPU) | ||
206 | void shmobile_smp_apmu_cpu_die(unsigned int cpu) | ||
207 | { | ||
208 | /* For this particular CPU deregister boot vector */ | ||
209 | shmobile_smp_hook(cpu, 0, 0); | ||
210 | |||
211 | /* Shutdown CPU core */ | ||
212 | shmobile_smp_apmu_cpu_shutdown(cpu); | ||
185 | 213 | ||
186 | /* jump to shared mach-shmobile sleep / reset code */ | 214 | /* jump to shared mach-shmobile sleep / reset code */ |
187 | shmobile_smp_sleep(); | 215 | shmobile_smp_sleep(); |
@@ -192,3 +220,27 @@ int shmobile_smp_apmu_cpu_kill(unsigned int cpu) | |||
192 | return apmu_wrap(cpu, apmu_power_off_poll); | 220 | return apmu_wrap(cpu, apmu_power_off_poll); |
193 | } | 221 | } |
194 | #endif | 222 | #endif |
223 | |||
224 | #if defined(CONFIG_SUSPEND) | ||
225 | static int shmobile_smp_apmu_do_suspend(unsigned long cpu) | ||
226 | { | ||
227 | shmobile_smp_hook(cpu, virt_to_phys(cpu_resume), 0); | ||
228 | shmobile_smp_apmu_cpu_shutdown(cpu); | ||
229 | cpu_do_idle(); /* WFI selects Core Standby */ | ||
230 | return 1; | ||
231 | } | ||
232 | |||
233 | static int shmobile_smp_apmu_enter_suspend(suspend_state_t state) | ||
234 | { | ||
235 | cpu_suspend(smp_processor_id(), shmobile_smp_apmu_do_suspend); | ||
236 | cpu_leave_lowpower(); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | void shmobile_smp_apmu_suspend_init(void) | ||
241 | { | ||
242 | shmobile_suspend_ops.enter = shmobile_smp_apmu_enter_suspend; | ||
243 | } | ||
244 | #else | ||
245 | void shmobile_smp_apmu_suspend_init(void) {} | ||
246 | #endif | ||