diff options
author | Jongpill Lee <boyko.lee@samsung.com> | 2012-02-16 22:23:51 -0500 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2012-05-19 14:14:36 -0400 |
commit | 60e49ca654eea42e04912b259fa36bad2c3e56ef (patch) | |
tree | 733d7c478de6df42761a2938b6129d6242bb84fd /arch | |
parent | a2fa3041b666e6aecee7929ffbc1759ef63a0c5c (diff) |
ARM: EXYNOS: Support suspend and resume for EXYNOS5250
This patch adds function for suspend and resume of Exynos5250.
Signed-off-by: Jongpill Lee <boyko.lee@samsung.com>
[kgene.kim@samsung.com: re-worked on top of v3.4-rc7]
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-exynos/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-exynos/include/mach/pm-core.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-exynos/pm.c | 83 | ||||
-rw-r--r-- | arch/arm/mach-exynos/pmu.c | 59 |
4 files changed, 110 insertions, 36 deletions
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 5893e2397da1..9ae68f47515f 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig | |||
@@ -62,6 +62,8 @@ config SOC_EXYNOS5250 | |||
62 | default y | 62 | default y |
63 | depends on ARCH_EXYNOS5 | 63 | depends on ARCH_EXYNOS5 |
64 | select SAMSUNG_DMADEV | 64 | select SAMSUNG_DMADEV |
65 | select S5P_PM if PM | ||
66 | select S5P_SLEEP if PM | ||
65 | help | 67 | help |
66 | Enable EXYNOS5250 SoC support | 68 | Enable EXYNOS5250 SoC support |
67 | 69 | ||
diff --git a/arch/arm/mach-exynos/include/mach/pm-core.h b/arch/arm/mach-exynos/include/mach/pm-core.h index 9d8da51e35ca..a67ecfaf1216 100644 --- a/arch/arm/mach-exynos/include/mach/pm-core.h +++ b/arch/arm/mach-exynos/include/mach/pm-core.h | |||
@@ -33,7 +33,7 @@ static inline void s3c_pm_arch_prepare_irqs(void) | |||
33 | __raw_writel(tmp, S5P_WAKEUP_MASK); | 33 | __raw_writel(tmp, S5P_WAKEUP_MASK); |
34 | 34 | ||
35 | __raw_writel(s3c_irqwake_intmask, S5P_WAKEUP_MASK); | 35 | __raw_writel(s3c_irqwake_intmask, S5P_WAKEUP_MASK); |
36 | __raw_writel(s3c_irqwake_eintmask, S5P_EINT_WAKEUP_MASK); | 36 | __raw_writel(s3c_irqwake_eintmask & 0xFFFFFFFE, S5P_EINT_WAKEUP_MASK); |
37 | } | 37 | } |
38 | 38 | ||
39 | static inline void s3c_pm_arch_stop_clocks(void) | 39 | static inline void s3c_pm_arch_stop_clocks(void) |
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 6aa3b47cee1c..c06c992943a1 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c | |||
@@ -77,7 +77,9 @@ static unsigned int save_arm_register[2]; | |||
77 | 77 | ||
78 | static int exynos_cpu_suspend(unsigned long arg) | 78 | static int exynos_cpu_suspend(unsigned long arg) |
79 | { | 79 | { |
80 | #ifdef CONFIG_CACHE_L2X0 | ||
80 | outer_flush_all(); | 81 | outer_flush_all(); |
82 | #endif | ||
81 | 83 | ||
82 | /* issue the standby signal into the pm unit. */ | 84 | /* issue the standby signal into the pm unit. */ |
83 | cpu_do_idle(); | 85 | cpu_do_idle(); |
@@ -88,13 +90,19 @@ static int exynos_cpu_suspend(unsigned long arg) | |||
88 | 90 | ||
89 | static void exynos_pm_prepare(void) | 91 | static void exynos_pm_prepare(void) |
90 | { | 92 | { |
91 | u32 tmp; | 93 | unsigned int tmp; |
92 | 94 | ||
93 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | 95 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); |
94 | s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save)); | ||
95 | s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save)); | ||
96 | 96 | ||
97 | tmp = __raw_readl(S5P_INFORM1); | 97 | if (!soc_is_exynos5250()) { |
98 | s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save)); | ||
99 | s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save)); | ||
100 | } else { | ||
101 | /* Disable USE_RETENTION of JPEG_MEM_OPTION */ | ||
102 | tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION); | ||
103 | tmp &= ~EXYNOS5_OPTION_USE_RETENTION; | ||
104 | __raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION); | ||
105 | } | ||
98 | 106 | ||
99 | /* Set value of power down register for sleep mode */ | 107 | /* Set value of power down register for sleep mode */ |
100 | 108 | ||
@@ -107,7 +115,8 @@ static void exynos_pm_prepare(void) | |||
107 | 115 | ||
108 | /* Before enter central sequence mode, clock src register have to set */ | 116 | /* Before enter central sequence mode, clock src register have to set */ |
109 | 117 | ||
110 | s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc)); | 118 | if (!soc_is_exynos5250()) |
119 | s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc)); | ||
111 | 120 | ||
112 | if (soc_is_exynos4210()) | 121 | if (soc_is_exynos4210()) |
113 | s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc)); | 122 | s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc)); |
@@ -190,7 +199,7 @@ static void exynos4_restore_pll(void) | |||
190 | } | 199 | } |
191 | 200 | ||
192 | static struct subsys_interface exynos_pm_interface = { | 201 | static struct subsys_interface exynos_pm_interface = { |
193 | .name = "exynos4_pm", | 202 | .name = "exynos_pm", |
194 | .subsys = &exynos_subsys, | 203 | .subsys = &exynos_subsys, |
195 | .add_dev = exynos_pm_add, | 204 | .add_dev = exynos_pm_add, |
196 | }; | 205 | }; |
@@ -231,22 +240,22 @@ static int exynos_pm_suspend(void) | |||
231 | tmp &= ~S5P_CENTRAL_LOWPWR_CFG; | 240 | tmp &= ~S5P_CENTRAL_LOWPWR_CFG; |
232 | __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); | 241 | __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); |
233 | 242 | ||
234 | if (soc_is_exynos4212() || soc_is_exynos4412()) { | 243 | /* Setting SEQ_OPTION register */ |
235 | tmp = __raw_readl(S5P_CENTRAL_SEQ_OPTION); | ||
236 | tmp &= ~(S5P_USE_STANDBYWFI_ISP_ARM | | ||
237 | S5P_USE_STANDBYWFE_ISP_ARM); | ||
238 | __raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); | ||
239 | } | ||
240 | 244 | ||
241 | /* Save Power control register */ | 245 | tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); |
242 | asm ("mrc p15, 0, %0, c15, c0, 0" | 246 | __raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); |
243 | : "=r" (tmp) : : "cc"); | ||
244 | save_arm_register[0] = tmp; | ||
245 | 247 | ||
246 | /* Save Diagnostic register */ | 248 | if (!soc_is_exynos5250()) { |
247 | asm ("mrc p15, 0, %0, c15, c0, 1" | 249 | /* Save Power control register */ |
248 | : "=r" (tmp) : : "cc"); | 250 | asm ("mrc p15, 0, %0, c15, c0, 0" |
249 | save_arm_register[1] = tmp; | 251 | : "=r" (tmp) : : "cc"); |
252 | save_arm_register[0] = tmp; | ||
253 | |||
254 | /* Save Diagnostic register */ | ||
255 | asm ("mrc p15, 0, %0, c15, c0, 1" | ||
256 | : "=r" (tmp) : : "cc"); | ||
257 | save_arm_register[1] = tmp; | ||
258 | } | ||
250 | 259 | ||
251 | return 0; | 260 | return 0; |
252 | } | 261 | } |
@@ -268,17 +277,19 @@ static void exynos_pm_resume(void) | |||
268 | /* No need to perform below restore code */ | 277 | /* No need to perform below restore code */ |
269 | goto early_wakeup; | 278 | goto early_wakeup; |
270 | } | 279 | } |
271 | /* Restore Power control register */ | 280 | if (!soc_is_exynos5250()) { |
272 | tmp = save_arm_register[0]; | 281 | /* Restore Power control register */ |
273 | asm volatile ("mcr p15, 0, %0, c15, c0, 0" | 282 | tmp = save_arm_register[0]; |
274 | : : "r" (tmp) | 283 | asm volatile ("mcr p15, 0, %0, c15, c0, 0" |
275 | : "cc"); | 284 | : : "r" (tmp) |
276 | 285 | : "cc"); | |
277 | /* Restore Diagnostic register */ | 286 | |
278 | tmp = save_arm_register[1]; | 287 | /* Restore Diagnostic register */ |
279 | asm volatile ("mcr p15, 0, %0, c15, c0, 1" | 288 | tmp = save_arm_register[1]; |
280 | : : "r" (tmp) | 289 | asm volatile ("mcr p15, 0, %0, c15, c0, 1" |
281 | : "cc"); | 290 | : : "r" (tmp) |
291 | : "cc"); | ||
292 | } | ||
282 | 293 | ||
283 | /* For release retention */ | 294 | /* For release retention */ |
284 | 295 | ||
@@ -292,11 +303,13 @@ static void exynos_pm_resume(void) | |||
292 | 303 | ||
293 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | 304 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); |
294 | 305 | ||
295 | exynos4_restore_pll(); | 306 | if (!soc_is_exynos5250()) { |
307 | exynos4_restore_pll(); | ||
296 | 308 | ||
297 | #ifdef CONFIG_SMP | 309 | #ifdef CONFIG_SMP |
298 | scu_enable(S5P_VA_SCU); | 310 | scu_enable(S5P_VA_SCU); |
299 | #endif | 311 | #endif |
312 | } | ||
300 | 313 | ||
301 | early_wakeup: | 314 | early_wakeup: |
302 | return; | 315 | return; |
@@ -307,9 +320,9 @@ static struct syscore_ops exynos_pm_syscore_ops = { | |||
307 | .resume = exynos_pm_resume, | 320 | .resume = exynos_pm_resume, |
308 | }; | 321 | }; |
309 | 322 | ||
310 | static __init int exynos4_pm_syscore_init(void) | 323 | static __init int exynos_pm_syscore_init(void) |
311 | { | 324 | { |
312 | register_syscore_ops(&exynos_pm_syscore_ops); | 325 | register_syscore_ops(&exynos_pm_syscore_ops); |
313 | return 0; | 326 | return 0; |
314 | } | 327 | } |
315 | arch_initcall(exynos4_pm_syscore_init); | 328 | arch_initcall(exynos_pm_syscore_init); |
diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index db4dc515e416..4aacb66f7161 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/io.h> | 12 | #include <linux/io.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/bug.h> | ||
14 | 15 | ||
15 | #include <mach/regs-clock.h> | 16 | #include <mach/regs-clock.h> |
16 | #include <mach/pmu.h> | 17 | #include <mach/pmu.h> |
@@ -314,10 +315,68 @@ static struct exynos_pmu_conf exynos5250_pmu_config[] = { | |||
314 | { PMU_TABLE_END,}, | 315 | { PMU_TABLE_END,}, |
315 | }; | 316 | }; |
316 | 317 | ||
318 | void __iomem *exynos5_list_both_cnt_feed[] = { | ||
319 | EXYNOS5_ARM_CORE0_OPTION, | ||
320 | EXYNOS5_ARM_CORE1_OPTION, | ||
321 | EXYNOS5_ARM_COMMON_OPTION, | ||
322 | EXYNOS5_GSCL_OPTION, | ||
323 | EXYNOS5_ISP_OPTION, | ||
324 | EXYNOS5_MFC_OPTION, | ||
325 | EXYNOS5_G3D_OPTION, | ||
326 | EXYNOS5_DISP1_OPTION, | ||
327 | EXYNOS5_MAU_OPTION, | ||
328 | EXYNOS5_TOP_PWR_OPTION, | ||
329 | EXYNOS5_TOP_PWR_SYSMEM_OPTION, | ||
330 | }; | ||
331 | |||
332 | void __iomem *exynos5_list_diable_wfi_wfe[] = { | ||
333 | EXYNOS5_ARM_CORE1_OPTION, | ||
334 | EXYNOS5_FSYS_ARM_OPTION, | ||
335 | EXYNOS5_ISP_ARM_OPTION, | ||
336 | }; | ||
337 | |||
338 | static void exynos5_init_pmu(void) | ||
339 | { | ||
340 | unsigned int i; | ||
341 | unsigned int tmp; | ||
342 | |||
343 | /* | ||
344 | * Enable both SC_FEEDBACK and SC_COUNTER | ||
345 | */ | ||
346 | for (i = 0 ; i < ARRAY_SIZE(exynos5_list_both_cnt_feed) ; i++) { | ||
347 | tmp = __raw_readl(exynos5_list_both_cnt_feed[i]); | ||
348 | tmp |= (EXYNOS5_USE_SC_FEEDBACK | | ||
349 | EXYNOS5_USE_SC_COUNTER); | ||
350 | __raw_writel(tmp, exynos5_list_both_cnt_feed[i]); | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * SKIP_DEACTIVATE_ACEACP_IN_PWDN_BITFIELD Enable | ||
355 | * MANUAL_L2RSTDISABLE_CONTROL_BITFIELD Enable | ||
356 | */ | ||
357 | tmp = __raw_readl(EXYNOS5_ARM_COMMON_OPTION); | ||
358 | tmp |= (EXYNOS5_MANUAL_L2RSTDISABLE_CONTROL | | ||
359 | EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN); | ||
360 | __raw_writel(tmp, EXYNOS5_ARM_COMMON_OPTION); | ||
361 | |||
362 | /* | ||
363 | * Disable WFI/WFE on XXX_OPTION | ||
364 | */ | ||
365 | for (i = 0 ; i < ARRAY_SIZE(exynos5_list_diable_wfi_wfe) ; i++) { | ||
366 | tmp = __raw_readl(exynos5_list_diable_wfi_wfe[i]); | ||
367 | tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE | | ||
368 | EXYNOS5_OPTION_USE_STANDBYWFI); | ||
369 | __raw_writel(tmp, exynos5_list_diable_wfi_wfe[i]); | ||
370 | } | ||
371 | } | ||
372 | |||
317 | void exynos_sys_powerdown_conf(enum sys_powerdown mode) | 373 | void exynos_sys_powerdown_conf(enum sys_powerdown mode) |
318 | { | 374 | { |
319 | unsigned int i; | 375 | unsigned int i; |
320 | 376 | ||
377 | if (soc_is_exynos5250()) | ||
378 | exynos5_init_pmu(); | ||
379 | |||
321 | for (i = 0; (exynos_pmu_config[i].reg != PMU_TABLE_END) ; i++) | 380 | for (i = 0; (exynos_pmu_config[i].reg != PMU_TABLE_END) ; i++) |
322 | __raw_writel(exynos_pmu_config[i].val[mode], | 381 | __raw_writel(exynos_pmu_config[i].val[mode], |
323 | exynos_pmu_config[i].reg); | 382 | exynos_pmu_config[i].reg); |