aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2011-12-22 19:23:07 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-25 17:39:03 -0500
commitf7dadb37931a6ffa2aa6b443188299166dc5e638 (patch)
treee769f8b7e8a62ef1674874aa2849af6fd841b67f /arch
parentc656c30668b9408c46d6bfbd1eea472f39a3155d (diff)
PM / shmobile: Add support for the sh7372 A4S power domain / sleep mode
The sh7372 contains a power domain named A4S which in turn contains power domains for both I/O Devices and CPU cores. At this point only System wide Suspend-to-RAM is supported, but the the hardware can also support CPUIdle. With more efforts in the future CPUIdle can work with bot A4S and A3SM. Tested on the sh7372 Mackerel board. [rjw: Rebased on top of the current linux-pm tree.] Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h4
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh7372.h3
-rw-r--r--arch/arm/mach-shmobile/intc-sh7372.c49
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c66
-rw-r--r--arch/arm/mach-shmobile/setup-sh7372.c6
-rw-r--r--arch/arm/mach-shmobile/sleep-sh7372.S21
6 files changed, 118 insertions, 31 deletions
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index 834bd6cd508f..4807623fb71c 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -35,8 +35,8 @@ extern void sh7372_add_standard_devices(void);
35extern void sh7372_clock_init(void); 35extern void sh7372_clock_init(void);
36extern void sh7372_pinmux_init(void); 36extern void sh7372_pinmux_init(void);
37extern void sh7372_pm_init(void); 37extern void sh7372_pm_init(void);
38extern void sh7372_resume_core_standby_a3sm(void); 38extern void sh7372_resume_core_standby_sysc(void);
39extern int sh7372_do_idle_a3sm(unsigned long unused); 39extern int sh7372_do_idle_sysc(unsigned long sleep_mode);
40extern struct clk sh7372_extal1_clk; 40extern struct clk sh7372_extal1_clk;
41extern struct clk sh7372_extal2_clk; 41extern struct clk sh7372_extal2_clk;
42 42
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index 84532f9629b2..d0731d973f1f 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -499,6 +499,7 @@ extern struct sh7372_pm_domain sh7372_d4;
499extern struct sh7372_pm_domain sh7372_a4r; 499extern struct sh7372_pm_domain sh7372_a4r;
500extern struct sh7372_pm_domain sh7372_a3rv; 500extern struct sh7372_pm_domain sh7372_a3rv;
501extern struct sh7372_pm_domain sh7372_a3ri; 501extern struct sh7372_pm_domain sh7372_a3ri;
502extern struct sh7372_pm_domain sh7372_a4s;
502extern struct sh7372_pm_domain sh7372_a3sp; 503extern struct sh7372_pm_domain sh7372_a3sp;
503extern struct sh7372_pm_domain sh7372_a3sg; 504extern struct sh7372_pm_domain sh7372_a3sg;
504 505
@@ -515,5 +516,7 @@ extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
515 516
516extern void sh7372_intcs_suspend(void); 517extern void sh7372_intcs_suspend(void);
517extern void sh7372_intcs_resume(void); 518extern void sh7372_intcs_resume(void);
519extern void sh7372_intca_suspend(void);
520extern void sh7372_intca_resume(void);
518 521
519#endif /* __ASM_SH7372_H__ */ 522#endif /* __ASM_SH7372_H__ */
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 2d8856df80e2..d087b31b5d12 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -611,3 +611,52 @@ void sh7372_intcs_resume(void)
611 for (k = 0x80; k <= 0x9c; k += 4) 611 for (k = 0x80; k <= 0x9c; k += 4)
612 __raw_writeb(ffd5[k], intcs_ffd5 + k); 612 __raw_writeb(ffd5[k], intcs_ffd5 + k);
613} 613}
614
615static unsigned short e694[0x200];
616static unsigned short e695[0x200];
617
618void sh7372_intca_suspend(void)
619{
620 int k;
621
622 for (k = 0x00; k <= 0x38; k += 4)
623 e694[k] = __raw_readw(0xe6940000 + k);
624
625 for (k = 0x80; k <= 0xb4; k += 4)
626 e694[k] = __raw_readb(0xe6940000 + k);
627
628 for (k = 0x180; k <= 0x1b4; k += 4)
629 e694[k] = __raw_readb(0xe6940000 + k);
630
631 for (k = 0x00; k <= 0x50; k += 4)
632 e695[k] = __raw_readw(0xe6950000 + k);
633
634 for (k = 0x80; k <= 0xa8; k += 4)
635 e695[k] = __raw_readb(0xe6950000 + k);
636
637 for (k = 0x180; k <= 0x1a8; k += 4)
638 e695[k] = __raw_readb(0xe6950000 + k);
639}
640
641void sh7372_intca_resume(void)
642{
643 int k;
644
645 for (k = 0x00; k <= 0x38; k += 4)
646 __raw_writew(e694[k], 0xe6940000 + k);
647
648 for (k = 0x80; k <= 0xb4; k += 4)
649 __raw_writeb(e694[k], 0xe6940000 + k);
650
651 for (k = 0x180; k <= 0x1b4; k += 4)
652 __raw_writeb(e694[k], 0xe6940000 + k);
653
654 for (k = 0x00; k <= 0x50; k += 4)
655 __raw_writew(e695[k], 0xe6950000 + k);
656
657 for (k = 0x80; k <= 0xa8; k += 4)
658 __raw_writeb(e695[k], 0xe6950000 + k);
659
660 for (k = 0x180; k <= 0x1a8; k += 4)
661 __raw_writeb(e695[k], 0xe6950000 + k);
662}
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index f742c61c8902..1e659d7360d1 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -256,6 +256,14 @@ struct sh7372_pm_domain sh7372_a3ri = {
256 .bit_shift = 8, 256 .bit_shift = 8,
257}; 257};
258 258
259struct sh7372_pm_domain sh7372_a4s = {
260 .genpd.name = "A4S",
261 .bit_shift = 10,
262 .gov = &pm_domain_always_on_gov,
263 .no_debug = true,
264 .stay_on = true,
265};
266
259struct sh7372_pm_domain sh7372_a3sp = { 267struct sh7372_pm_domain sh7372_a3sp = {
260 .genpd.name = "A3SP", 268 .genpd.name = "A3SP",
261 .bit_shift = 11, 269 .bit_shift = 11,
@@ -289,11 +297,16 @@ static int sh7372_do_idle_core_standby(unsigned long unused)
289 return 0; 297 return 0;
290} 298}
291 299
292static void sh7372_enter_core_standby(void) 300static void sh7372_set_reset_vector(unsigned long address)
293{ 301{
294 /* set reset vector, translate 4k */ 302 /* set reset vector, translate 4k */
295 __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR); 303 __raw_writel(address, SBAR);
296 __raw_writel(0, APARMBAREA); 304 __raw_writel(0, APARMBAREA);
305}
306
307static void sh7372_enter_core_standby(void)
308{
309 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
297 310
298 /* enter sleep mode with SYSTBCR to 0x10 */ 311 /* enter sleep mode with SYSTBCR to 0x10 */
299 __raw_writel(0x10, SYSTBCR); 312 __raw_writel(0x10, SYSTBCR);
@@ -306,27 +319,22 @@ static void sh7372_enter_core_standby(void)
306#endif 319#endif
307 320
308#ifdef CONFIG_SUSPEND 321#ifdef CONFIG_SUSPEND
309static void sh7372_enter_a3sm_common(int pllc0_on) 322static void sh7372_enter_sysc(int pllc0_on, unsigned long sleep_mode)
310{ 323{
311 /* set reset vector, translate 4k */
312 __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR);
313 __raw_writel(0, APARMBAREA);
314
315 if (pllc0_on) 324 if (pllc0_on)
316 __raw_writel(0, PLLC01STPCR); 325 __raw_writel(0, PLLC01STPCR);
317 else 326 else
318 __raw_writel(1 << 28, PLLC01STPCR); 327 __raw_writel(1 << 28, PLLC01STPCR);
319 328
320 __raw_writel(0, PDNSEL); /* power-down A3SM only, not A4S */
321 __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */ 329 __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */
322 cpu_suspend(0, sh7372_do_idle_a3sm); 330 cpu_suspend(sleep_mode, sh7372_do_idle_sysc);
323 __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */ 331 __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */
324 332
325 /* disable reset vector translation */ 333 /* disable reset vector translation */
326 __raw_writel(0, SBAR); 334 __raw_writel(0, SBAR);
327} 335}
328 336
329static int sh7372_a3sm_valid(unsigned long *mskp, unsigned long *msk2p) 337static int sh7372_sysc_valid(unsigned long *mskp, unsigned long *msk2p)
330{ 338{
331 unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4; 339 unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4;
332 unsigned long msk, msk2; 340 unsigned long msk, msk2;
@@ -414,7 +422,7 @@ static void sh7372_icr_to_irqcr(unsigned long icr, u16 *irqcr1p, u16 *irqcr2p)
414 *irqcr2p = irqcr2; 422 *irqcr2p = irqcr2;
415} 423}
416 424
417static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2) 425static void sh7372_setup_sysc(unsigned long msk, unsigned long msk2)
418{ 426{
419 u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high; 427 u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high;
420 unsigned long tmp; 428 unsigned long tmp;
@@ -447,6 +455,22 @@ static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2)
447 __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3); 455 __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3);
448 __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4); 456 __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4);
449} 457}
458
459static void sh7372_enter_a3sm_common(int pllc0_on)
460{
461 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
462 sh7372_enter_sysc(pllc0_on, 1 << 12);
463}
464
465static void sh7372_enter_a4s_common(int pllc0_on)
466{
467 sh7372_intca_suspend();
468 memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100);
469 sh7372_set_reset_vector(SMFRAM);
470 sh7372_enter_sysc(pllc0_on, 1 << 10);
471 sh7372_intca_resume();
472}
473
450#endif 474#endif
451 475
452#ifdef CONFIG_CPU_IDLE 476#ifdef CONFIG_CPU_IDLE
@@ -480,14 +504,20 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state)
480 unsigned long msk, msk2; 504 unsigned long msk, msk2;
481 505
482 /* check active clocks to determine potential wakeup sources */ 506 /* check active clocks to determine potential wakeup sources */
483 if (sh7372_a3sm_valid(&msk, &msk2)) { 507 if (sh7372_sysc_valid(&msk, &msk2)) {
484
485 /* convert INTC mask and sense to SYSC mask and sense */ 508 /* convert INTC mask and sense to SYSC mask and sense */
486 sh7372_setup_a3sm(msk, msk2); 509 sh7372_setup_sysc(msk, msk2);
487 510
488 /* enter A3SM sleep with PLLC0 off */ 511 if (!sh7372_a3sp.stay_on &&
489 pr_debug("entering A3SM\n"); 512 sh7372_a4s.genpd.status == GPD_STATE_POWER_OFF) {
490 sh7372_enter_a3sm_common(0); 513 /* enter A4S sleep with PLLC0 off */
514 pr_debug("entering A4S\n");
515 sh7372_enter_a4s_common(0);
516 } else {
517 /* enter A3SM sleep with PLLC0 off */
518 pr_debug("entering A3SM\n");
519 sh7372_enter_a3sm_common(0);
520 }
491 } else { 521 } else {
492 /* default to Core Standby that supports all wakeup sources */ 522 /* default to Core Standby that supports all wakeup sources */
493 pr_debug("entering Core Standby\n"); 523 pr_debug("entering Core Standby\n");
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 2380389e6ac5..c197f9d29d04 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -994,12 +994,16 @@ void __init sh7372_add_standard_devices(void)
994 sh7372_init_pm_domain(&sh7372_a4r); 994 sh7372_init_pm_domain(&sh7372_a4r);
995 sh7372_init_pm_domain(&sh7372_a3rv); 995 sh7372_init_pm_domain(&sh7372_a3rv);
996 sh7372_init_pm_domain(&sh7372_a3ri); 996 sh7372_init_pm_domain(&sh7372_a3ri);
997 sh7372_init_pm_domain(&sh7372_a3sg); 997 sh7372_init_pm_domain(&sh7372_a4s);
998 sh7372_init_pm_domain(&sh7372_a3sp); 998 sh7372_init_pm_domain(&sh7372_a3sp);
999 sh7372_init_pm_domain(&sh7372_a3sg);
999 1000
1000 sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv); 1001 sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
1001 sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc); 1002 sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc);
1002 1003
1004 sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sg);
1005 sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sp);
1006
1003 platform_add_devices(sh7372_early_devices, 1007 platform_add_devices(sh7372_early_devices,
1004 ARRAY_SIZE(sh7372_early_devices)); 1008 ARRAY_SIZE(sh7372_early_devices));
1005 1009
diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S
index f3ab3c5810ea..1d564674451d 100644
--- a/arch/arm/mach-shmobile/sleep-sh7372.S
+++ b/arch/arm/mach-shmobile/sleep-sh7372.S
@@ -37,13 +37,18 @@
37#if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE) 37#if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
38 .align 12 38 .align 12
39 .text 39 .text
40 .global sh7372_resume_core_standby_a3sm 40 .global sh7372_resume_core_standby_sysc
41sh7372_resume_core_standby_a3sm: 41sh7372_resume_core_standby_sysc:
42 ldr pc, 1f 42 ldr pc, 1f
431: .long cpu_resume - PAGE_OFFSET + PLAT_PHYS_OFFSET 431: .long cpu_resume - PAGE_OFFSET + PLAT_PHYS_OFFSET
44 44
45 .global sh7372_do_idle_a3sm 45#define SPDCR 0xe6180008
46sh7372_do_idle_a3sm: 46
47 /* A3SM & A4S power down */
48 .global sh7372_do_idle_sysc
49sh7372_do_idle_sysc:
50 mov r8, r0 /* sleep mode passed in r0 */
51
47 /* 52 /*
48 * Clear the SCTLR.C bit to prevent further data cache 53 * Clear the SCTLR.C bit to prevent further data cache
49 * allocation. Clearing SCTLR.C would make all the data accesses 54 * allocation. Clearing SCTLR.C would make all the data accesses
@@ -80,13 +85,9 @@ sh7372_do_idle_a3sm:
80 dsb 85 dsb
81 dmb 86 dmb
82 87
83#define SPDCR 0xe6180008 88 /* SYSC power down */
84#define A3SM (1 << 12)
85
86 /* A3SM power down */
87 ldr r0, =SPDCR 89 ldr r0, =SPDCR
88 ldr r1, =A3SM 90 str r8, [r0]
89 str r1, [r0]
901: 911:
91 b 1b 92 b 1b
92 93