aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJongpill Lee <boyko.lee@samsung.com>2012-02-16 22:23:51 -0500
committerKukjin Kim <kgene.kim@samsung.com>2012-05-19 14:14:36 -0400
commit60e49ca654eea42e04912b259fa36bad2c3e56ef (patch)
tree733d7c478de6df42761a2938b6129d6242bb84fd /arch
parenta2fa3041b666e6aecee7929ffbc1759ef63a0c5c (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/Kconfig2
-rw-r--r--arch/arm/mach-exynos/include/mach/pm-core.h2
-rw-r--r--arch/arm/mach-exynos/pm.c83
-rw-r--r--arch/arm/mach-exynos/pmu.c59
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
39static inline void s3c_pm_arch_stop_clocks(void) 39static 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
78static int exynos_cpu_suspend(unsigned long arg) 78static 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
89static void exynos_pm_prepare(void) 91static 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
192static struct subsys_interface exynos_pm_interface = { 201static 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
301early_wakeup: 314early_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
310static __init int exynos4_pm_syscore_init(void) 323static __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}
315arch_initcall(exynos4_pm_syscore_init); 328arch_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
318void __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
332void __iomem *exynos5_list_diable_wfi_wfe[] = {
333 EXYNOS5_ARM_CORE1_OPTION,
334 EXYNOS5_FSYS_ARM_OPTION,
335 EXYNOS5_ISP_ARM_OPTION,
336};
337
338static 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
317void exynos_sys_powerdown_conf(enum sys_powerdown mode) 373void 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);