Skip to content

Commit

Permalink
sh: Rework SuperH Mobile sleep mode code
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Magnus Damm authored and Paul Mundt committed Oct 30, 2009
1 parent eb0cd9e commit 323ef8d
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 164 deletions.
27 changes: 27 additions & 0 deletions arch/sh/include/asm/suspend.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,33 @@ extern struct atomic_notifier_head sh_mobile_post_sleep_notifier_list;
void sh_mobile_register_self_refresh(unsigned long flags,
void *pre_start, void *pre_end,
void *post_start, void *post_end);

/* register structure for address/data information */
struct sh_sleep_regs {
unsigned long stbcr;
};

/* data area for low-level sleep code */
struct sh_sleep_data {
/* current sleep mode (SUSP_SH_...) */
unsigned long mode;

/* addresses of board specific self-refresh snippets */
unsigned long sf_pre;
unsigned long sf_post;

/* register state saved and restored by the assembly code */
unsigned long vbr;
unsigned long spc;
unsigned long sr;

/* structure for keeping register addresses */
struct sh_sleep_regs addr;

/* structure for saving/restoring register state */
struct sh_sleep_regs data;
};

#endif

/* flags passed to assembly suspend code */
Expand Down
10 changes: 10 additions & 0 deletions arch/sh/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,15 @@ int main(void)
DEFINE(PBE_NEXT, offsetof(struct pbe, next));
DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs));
#endif

DEFINE(SH_SLEEP_MODE, offsetof(struct sh_sleep_data, mode));
DEFINE(SH_SLEEP_SF_PRE, offsetof(struct sh_sleep_data, sf_pre));
DEFINE(SH_SLEEP_SF_POST, offsetof(struct sh_sleep_data, sf_post));
DEFINE(SH_SLEEP_VBR, offsetof(struct sh_sleep_data, vbr));
DEFINE(SH_SLEEP_SPC, offsetof(struct sh_sleep_data, spc));
DEFINE(SH_SLEEP_SR, offsetof(struct sh_sleep_data, sr));
DEFINE(SH_SLEEP_BASE_ADDR, offsetof(struct sh_sleep_data, addr));
DEFINE(SH_SLEEP_BASE_DATA, offsetof(struct sh_sleep_data, data));
DEFINE(SH_SLEEP_REG_STBCR, offsetof(struct sh_sleep_regs, stbcr));
return 0;
}
54 changes: 43 additions & 11 deletions arch/sh/kernel/cpu/shmobile/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand All @@ -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;
Expand Down
Loading

0 comments on commit 323ef8d

Please sign in to comment.