aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile/pm-sh7372.c
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/arm/mach-shmobile/pm-sh7372.c
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/arm/mach-shmobile/pm-sh7372.c')
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c66
1 files changed, 48 insertions, 18 deletions
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");