2 * sh7372 Power management support
4 * Copyright (C) 2011 Magnus Damm
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
12 #include <linux/suspend.h>
13 #include <linux/cpuidle.h>
14 #include <linux/module.h>
15 #include <linux/list.h>
16 #include <linux/err.h>
17 #include <linux/slab.h>
18 #include <linux/pm_clock.h>
19 #include <linux/platform_device.h>
20 #include <linux/delay.h>
21 #include <linux/irq.h>
22 #include <linux/bitrev.h>
23 #include <linux/console.h>
25 #include <asm/tlbflush.h>
26 #include <asm/suspend.h>
27 #include <mach/common.h>
28 #include <mach/sh7372.h>
29 #include <mach/pm-rmobile.h>
32 #define DBGREG1 0xe6100020
33 #define DBGREG9 0xe6100040
36 #define SYSTBCR 0xe6150024
37 #define MSTPSR0 0xe6150030
38 #define MSTPSR1 0xe6150038
39 #define MSTPSR2 0xe6150040
40 #define MSTPSR3 0xe6150048
41 #define MSTPSR4 0xe615004c
42 #define PLLC01STPCR 0xe61500c8
45 #define SBAR 0xe6180020
46 #define WUPRMSK 0xe6180028
47 #define WUPSMSK 0xe618002c
48 #define WUPSMSK2 0xe6180048
49 #define WUPSFAC 0xe6180098
50 #define IRQCR 0xe618022c
51 #define IRQCR2 0xe6180238
52 #define IRQCR3 0xe6180244
53 #define IRQCR4 0xe6180248
54 #define PDNSEL 0xe6180254
57 #define ICR1A 0xe6900000
58 #define ICR2A 0xe6900004
59 #define ICR3A 0xe6900008
60 #define ICR4A 0xe690000c
61 #define INTMSK00A 0xe6900040
62 #define INTMSK10A 0xe6900044
63 #define INTMSK20A 0xe6900048
64 #define INTMSK30A 0xe690004c
67 #define SMFRAM 0xe6a70000
70 #define APARMBAREA 0xe6f10020
74 struct rmobile_pm_domain sh7372_pd_a4lc
= {
79 struct rmobile_pm_domain sh7372_pd_a4mp
= {
84 struct rmobile_pm_domain sh7372_pd_d4
= {
89 static int sh7372_a4r_pd_suspend(void)
91 sh7372_intcs_suspend();
92 __raw_writel(0x300fffff, WUPRMSK
); /* avoid wakeup */
96 struct rmobile_pm_domain sh7372_pd_a4r
= {
99 .suspend
= sh7372_a4r_pd_suspend
,
100 .resume
= sh7372_intcs_resume
,
103 struct rmobile_pm_domain sh7372_pd_a3rv
= {
104 .genpd
.name
= "A3RV",
108 struct rmobile_pm_domain sh7372_pd_a3ri
= {
109 .genpd
.name
= "A3RI",
113 static int sh7372_pd_a4s_suspend(void)
116 * The A4S domain contains the CPU core and therefore it should
117 * only be turned off if the CPU is in use.
122 struct rmobile_pm_domain sh7372_pd_a4s
= {
125 .gov
= &pm_domain_always_on_gov
,
127 .suspend
= sh7372_pd_a4s_suspend
,
130 static int sh7372_a3sp_pd_suspend(void)
133 * Serial consoles make use of SCIF hardware located in A3SP,
134 * keep such power domain on if "no_console_suspend" is set.
136 return console_suspend_enabled
? 0 : -EBUSY
;
139 struct rmobile_pm_domain sh7372_pd_a3sp
= {
140 .genpd
.name
= "A3SP",
142 .gov
= &pm_domain_always_on_gov
,
144 .suspend
= sh7372_a3sp_pd_suspend
,
147 struct rmobile_pm_domain sh7372_pd_a3sg
= {
148 .genpd
.name
= "A3SG",
152 #endif /* CONFIG_PM */
154 #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
155 static void sh7372_set_reset_vector(unsigned long address
)
157 /* set reset vector, translate 4k */
158 __raw_writel(address
, SBAR
);
159 __raw_writel(0, APARMBAREA
);
162 static void sh7372_enter_sysc(int pllc0_on
, unsigned long sleep_mode
)
165 __raw_writel(0, PLLC01STPCR
);
167 __raw_writel(1 << 28, PLLC01STPCR
);
169 __raw_readl(WUPSFAC
); /* read wakeup int. factor before sleep */
170 cpu_suspend(sleep_mode
, sh7372_do_idle_sysc
);
171 __raw_readl(WUPSFAC
); /* read wakeup int. factor after wakeup */
173 /* disable reset vector translation */
174 __raw_writel(0, SBAR
);
177 static int sh7372_sysc_valid(unsigned long *mskp
, unsigned long *msk2p
)
179 unsigned long mstpsr0
, mstpsr1
, mstpsr2
, mstpsr3
, mstpsr4
;
180 unsigned long msk
, msk2
;
182 /* check active clocks to determine potential wakeup sources */
184 mstpsr0
= __raw_readl(MSTPSR0
);
185 if ((mstpsr0
& 0x00000003) != 0x00000003) {
186 pr_debug("sh7372 mstpsr0 0x%08lx\n", mstpsr0
);
190 mstpsr1
= __raw_readl(MSTPSR1
);
191 if ((mstpsr1
& 0xff079b7f) != 0xff079b7f) {
192 pr_debug("sh7372 mstpsr1 0x%08lx\n", mstpsr1
);
196 mstpsr2
= __raw_readl(MSTPSR2
);
197 if ((mstpsr2
& 0x000741ff) != 0x000741ff) {
198 pr_debug("sh7372 mstpsr2 0x%08lx\n", mstpsr2
);
202 mstpsr3
= __raw_readl(MSTPSR3
);
203 if ((mstpsr3
& 0x1a60f010) != 0x1a60f010) {
204 pr_debug("sh7372 mstpsr3 0x%08lx\n", mstpsr3
);
208 mstpsr4
= __raw_readl(MSTPSR4
);
209 if ((mstpsr4
& 0x00008cf0) != 0x00008cf0) {
210 pr_debug("sh7372 mstpsr4 0x%08lx\n", mstpsr4
);
217 /* make bitmaps of limited number of wakeup sources */
219 if ((mstpsr2
& (1 << 23)) == 0) /* SPU2 */
222 if ((mstpsr2
& (1 << 12)) == 0) /* MFI_MFIM */
225 if ((mstpsr4
& (1 << 3)) == 0) /* KEYSC */
228 if ((mstpsr1
& (1 << 24)) == 0) /* CMT0 */
231 if ((mstpsr3
& (1 << 29)) == 0) /* CMT1 */
234 if ((mstpsr4
& (1 << 0)) == 0) /* CMT2 */
237 if ((mstpsr2
& (1 << 13)) == 0) /* MFI_MFIS */
246 static void sh7372_icr_to_irqcr(unsigned long icr
, u16
*irqcr1p
, u16
*irqcr2p
)
248 u16 tmp
, irqcr1
, irqcr2
;
254 /* convert INTCA ICR register layout to SYSC IRQCR+IRQCR2 */
255 for (k
= 0; k
<= 7; k
++) {
256 tmp
= (icr
>> ((7 - k
) * 4)) & 0xf;
257 irqcr1
|= (tmp
& 0x03) << (k
* 2);
258 irqcr2
|= (tmp
>> 2) << (k
* 2);
265 static void sh7372_setup_sysc(unsigned long msk
, unsigned long msk2
)
267 u16 irqcrx_low
, irqcrx_high
, irqcry_low
, irqcry_high
;
270 /* read IRQ0A -> IRQ15A mask */
271 tmp
= bitrev8(__raw_readb(INTMSK00A
));
272 tmp
|= bitrev8(__raw_readb(INTMSK10A
)) << 8;
274 /* setup WUPSMSK from clocks and external IRQ mask */
275 msk
= (~msk
& 0xc030000f) | (tmp
<< 4);
276 __raw_writel(msk
, WUPSMSK
);
278 /* propage level/edge trigger for external IRQ 0->15 */
279 sh7372_icr_to_irqcr(__raw_readl(ICR1A
), &irqcrx_low
, &irqcry_low
);
280 sh7372_icr_to_irqcr(__raw_readl(ICR2A
), &irqcrx_high
, &irqcry_high
);
281 __raw_writel((irqcrx_high
<< 16) | irqcrx_low
, IRQCR
);
282 __raw_writel((irqcry_high
<< 16) | irqcry_low
, IRQCR2
);
284 /* read IRQ16A -> IRQ31A mask */
285 tmp
= bitrev8(__raw_readb(INTMSK20A
));
286 tmp
|= bitrev8(__raw_readb(INTMSK30A
)) << 8;
288 /* setup WUPSMSK2 from clocks and external IRQ mask */
289 msk2
= (~msk2
& 0x00030000) | tmp
;
290 __raw_writel(msk2
, WUPSMSK2
);
292 /* propage level/edge trigger for external IRQ 16->31 */
293 sh7372_icr_to_irqcr(__raw_readl(ICR3A
), &irqcrx_low
, &irqcry_low
);
294 sh7372_icr_to_irqcr(__raw_readl(ICR4A
), &irqcrx_high
, &irqcry_high
);
295 __raw_writel((irqcrx_high
<< 16) | irqcrx_low
, IRQCR3
);
296 __raw_writel((irqcry_high
<< 16) | irqcry_low
, IRQCR4
);
299 static void sh7372_enter_a3sm_common(int pllc0_on
)
301 /* use INTCA together with SYSC for wakeup */
302 sh7372_setup_sysc(1 << 0, 0);
303 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc
));
304 sh7372_enter_sysc(pllc0_on
, 1 << 12);
306 #endif /* CONFIG_SUSPEND || CONFIG_CPU_IDLE */
308 #ifdef CONFIG_CPU_IDLE
309 static int sh7372_do_idle_core_standby(unsigned long unused
)
311 cpu_do_idle(); /* WFI when SYSTBCR == 0x10 -> Core Standby */
315 static void sh7372_enter_core_standby(void)
317 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc
));
319 /* enter sleep mode with SYSTBCR to 0x10 */
320 __raw_writel(0x10, SYSTBCR
);
321 cpu_suspend(0, sh7372_do_idle_core_standby
);
322 __raw_writel(0, SYSTBCR
);
324 /* disable reset vector translation */
325 __raw_writel(0, SBAR
);
328 static void sh7372_enter_a3sm_pll_on(void)
330 sh7372_enter_a3sm_common(1);
333 static void sh7372_enter_a3sm_pll_off(void)
335 sh7372_enter_a3sm_common(0);
338 static void sh7372_cpuidle_setup(struct cpuidle_driver
*drv
)
340 struct cpuidle_state
*state
= &drv
->states
[drv
->state_count
];
342 snprintf(state
->name
, CPUIDLE_NAME_LEN
, "C2");
343 strncpy(state
->desc
, "Core Standby Mode", CPUIDLE_DESC_LEN
);
344 state
->exit_latency
= 10;
345 state
->target_residency
= 20 + 10;
346 state
->flags
= CPUIDLE_FLAG_TIME_VALID
;
347 shmobile_cpuidle_modes
[drv
->state_count
] = sh7372_enter_core_standby
;
350 state
= &drv
->states
[drv
->state_count
];
351 snprintf(state
->name
, CPUIDLE_NAME_LEN
, "C3");
352 strncpy(state
->desc
, "A3SM PLL ON", CPUIDLE_DESC_LEN
);
353 state
->exit_latency
= 20;
354 state
->target_residency
= 30 + 20;
355 state
->flags
= CPUIDLE_FLAG_TIME_VALID
;
356 shmobile_cpuidle_modes
[drv
->state_count
] = sh7372_enter_a3sm_pll_on
;
359 state
= &drv
->states
[drv
->state_count
];
360 snprintf(state
->name
, CPUIDLE_NAME_LEN
, "C4");
361 strncpy(state
->desc
, "A3SM PLL OFF", CPUIDLE_DESC_LEN
);
362 state
->exit_latency
= 120;
363 state
->target_residency
= 30 + 120;
364 state
->flags
= CPUIDLE_FLAG_TIME_VALID
;
365 shmobile_cpuidle_modes
[drv
->state_count
] = sh7372_enter_a3sm_pll_off
;
369 static void sh7372_cpuidle_init(void)
371 shmobile_cpuidle_setup
= sh7372_cpuidle_setup
;
374 static void sh7372_cpuidle_init(void) {}
377 #ifdef CONFIG_SUSPEND
378 static void sh7372_enter_a4s_common(int pllc0_on
)
380 sh7372_intca_suspend();
381 memcpy((void *)SMFRAM
, sh7372_resume_core_standby_sysc
, 0x100);
382 sh7372_set_reset_vector(SMFRAM
);
383 sh7372_enter_sysc(pllc0_on
, 1 << 10);
384 sh7372_intca_resume();
387 static int sh7372_enter_suspend(suspend_state_t suspend_state
)
389 unsigned long msk
, msk2
;
391 /* check active clocks to determine potential wakeup sources */
392 if (sh7372_sysc_valid(&msk
, &msk2
)) {
393 if (!console_suspend_enabled
&&
394 sh7372_pd_a4s
.genpd
.status
== GPD_STATE_POWER_OFF
) {
395 /* convert INTC mask/sense to SYSC mask/sense */
396 sh7372_setup_sysc(msk
, msk2
);
398 /* enter A4S sleep with PLLC0 off */
399 pr_debug("entering A4S\n");
400 sh7372_enter_a4s_common(0);
405 /* default to enter A3SM sleep with PLLC0 off */
406 pr_debug("entering A3SM\n");
407 sh7372_enter_a3sm_common(0);
412 * sh7372_pm_notifier_fn - SH7372 PM notifier routine.
414 * @pm_event: Event being handled.
417 static int sh7372_pm_notifier_fn(struct notifier_block
*notifier
,
418 unsigned long pm_event
, void *unused
)
421 case PM_SUSPEND_PREPARE
:
423 * This is necessary, because the A4R domain has to be "on"
424 * when suspend_device_irqs() and resume_device_irqs() are
425 * executed during system suspend and resume, respectively, so
426 * that those functions don't crash while accessing the INTCS.
428 pm_genpd_poweron(&sh7372_pd_a4r
.genpd
);
430 case PM_POST_SUSPEND
:
431 pm_genpd_poweroff_unused();
438 static void sh7372_suspend_init(void)
440 shmobile_suspend_ops
.enter
= sh7372_enter_suspend
;
441 pm_notifier(sh7372_pm_notifier_fn
, 0);
444 static void sh7372_suspend_init(void) {}
447 void __init
sh7372_pm_init(void)
449 /* enable DBG hardware block to kick SYSC */
450 __raw_writel(0x0000a500, DBGREG9
);
451 __raw_writel(0x0000a501, DBGREG9
);
452 __raw_writel(0x00000000, DBGREG1
);
454 /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */
455 __raw_writel(0, PDNSEL
);
457 sh7372_suspend_init();
458 sh7372_cpuidle_init();