aboutsummaryrefslogtreecommitdiff
path: root/arch/sh/kernel/cpu/shmobile/pm.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2009-10-30 04:24:07 +0000
committerPaul Mundt <lethal@linux-sh.org>2009-10-30 14:36:52 +0900
commit323ef8dba67fb7b9c709457bd0374d88cfb8f25f (patch)
treef8d4ae7d78837f13970fecdba061fc0df818ae11 /arch/sh/kernel/cpu/shmobile/pm.c
parenteb0cd9e88c6a6561055b32a17d44d8918aecc3c7 (diff)
sh: Rework SuperH Mobile sleep mode code
Rework the SuperH Mobile sleep code from including board specific code to allowing each board to provide pre/post code snippets. These snippets should contain sdram management code to enter and leave self-refresh. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/cpu/shmobile/pm.c')
-rw-r--r--arch/sh/kernel/cpu/shmobile/pm.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c
index b424747e425..cb3d28f2968 100644
--- a/arch/sh/kernel/cpu/shmobile/pm.c
+++ b/arch/sh/kernel/cpu/shmobile/pm.c
@@ -42,13 +42,14 @@ ATOMIC_NOTIFIER_HEAD(sh_mobile_post_sleep_notifier_list);
#define ILRAM_BASE 0xe5200000
-extern const unsigned char sh_mobile_standby[];
-extern const unsigned int sh_mobile_standby_size;
-
void sh_mobile_call_standby(unsigned long mode)
{
void *onchip_mem = (void *)ILRAM_BASE;
- void (*standby_onchip_mem)(unsigned long, unsigned long) = onchip_mem;
+ struct sh_sleep_data *sdp = onchip_mem;
+ void (*standby_onchip_mem)(unsigned long, unsigned long);
+
+ /* code located directly after data structure */
+ standby_onchip_mem = (void *)(sdp + 1);
atomic_notifier_call_chain(&sh_mobile_pre_sleep_notifier_list,
mode, NULL);
@@ -60,10 +61,48 @@ void sh_mobile_call_standby(unsigned long mode)
mode, NULL);
}
+extern char sh_mobile_sleep_enter_start;
+extern char sh_mobile_sleep_enter_end;
+
+extern char sh_mobile_sleep_resume_start;
+extern char sh_mobile_sleep_resume_end;
+
void sh_mobile_register_self_refresh(unsigned long flags,
void *pre_start, void *pre_end,
void *post_start, void *post_end)
{
+ void *onchip_mem = (void *)ILRAM_BASE;
+ void *vp;
+ struct sh_sleep_data *sdp;
+ int n;
+
+ /* part 0: data area */
+ sdp = onchip_mem;
+ sdp->addr.stbcr = 0xa4150020; /* STBCR */
+ vp = sdp + 1;
+
+ /* part 1: common code to enter sleep mode */
+ n = &sh_mobile_sleep_enter_end - &sh_mobile_sleep_enter_start;
+ memcpy(vp, &sh_mobile_sleep_enter_start, n);
+ vp += roundup(n, 4);
+
+ /* part 2: board specific code to enter self-refresh mode */
+ n = pre_end - pre_start;
+ memcpy(vp, pre_start, n);
+ sdp->sf_pre = (unsigned long)vp;
+ vp += roundup(n, 4);
+
+ /* part 3: board specific code to resume from self-refresh mode */
+ n = post_end - post_start;
+ memcpy(vp, post_start, n);
+ sdp->sf_post = (unsigned long)vp;
+ vp += roundup(n, 4);
+
+ /* part 4: common code to resume from sleep mode */
+ WARN_ON(vp > (onchip_mem + 0x600));
+ vp = onchip_mem + 0x600; /* located at interrupt vector */
+ n = &sh_mobile_sleep_resume_end - &sh_mobile_sleep_resume_start;
+ memcpy(vp, &sh_mobile_sleep_resume_start, n);
}
static int sh_pm_enter(suspend_state_t state)
@@ -83,13 +122,6 @@ static struct platform_suspend_ops sh_pm_ops = {
static int __init sh_pm_init(void)
{
- void *onchip_mem = (void *)ILRAM_BASE;
-
- /* Copy the assembly snippet to the otherwise ununsed ILRAM */
- memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
- wmb();
- ctrl_barrier();
-
suspend_set_ops(&sh_pm_ops);
sh_mobile_setup_cpuidle();
return 0;