Commit 309214af authored by Magnus Damm's avatar Magnus Damm Committed by Paul Mundt

sh: rework SuperH Mobile sleep code exception handling

This patch updates the exception handling in the sleep code
for SuperH Mobile. With the patch applied the sleep code
always rewrites the VBR and resumes from the exception vector,
re-initializes hardware and jumps straight to the original
interrupt vector.

Tested on sh7722 and sh7724 with "Sleep Mode", "Sleep Mode + SF"
and "Software Standby Mode + SF" with CONFIG_SUSPEND.
Signed-off-by: default avatarMagnus Damm <damm@igel.co.jp>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent cd7246f0
...@@ -41,23 +41,11 @@ extern const unsigned int sh_mobile_standby_size; ...@@ -41,23 +41,11 @@ extern const unsigned int sh_mobile_standby_size;
void sh_mobile_call_standby(unsigned long mode) void sh_mobile_call_standby(unsigned long mode)
{ {
extern void *vbr_base;
void *onchip_mem = (void *)ILRAM_BASE; void *onchip_mem = (void *)ILRAM_BASE;
void (*standby_onchip_mem)(unsigned long) = onchip_mem; void (*standby_onchip_mem)(unsigned long, unsigned long) = onchip_mem;
/* Note: Wake up from sleep may generate exceptions!
* Setup VBR to point to on-chip ram if self-refresh is
* going to be used.
*/
if (mode & SUSP_SH_SF)
asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory");
/* Let assembly snippet in on-chip memory handle the rest */ /* Let assembly snippet in on-chip memory handle the rest */
standby_onchip_mem(mode); standby_onchip_mem(mode, ILRAM_BASE);
/* Put VBR back in System RAM again */
if (mode & SUSP_SH_SF)
asm volatile("ldc %0, vbr" : : "r" (&vbr_base) : "memory");
} }
static int sh_pm_enter(suspend_state_t state) static int sh_pm_enter(suspend_state_t state)
......
...@@ -16,19 +16,52 @@ ...@@ -16,19 +16,52 @@
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/suspend.h> #include <asm/suspend.h>
/*
* Kernel mode register usage, see entry.S:
* k0 scratch
* k1 scratch
* k4 scratch
*/
#define k0 r0
#define k1 r1
#define k4 r4
/* manage self-refresh and enter standby mode. /* manage self-refresh and enter standby mode.
* this code will be copied to on-chip memory and executed from there. * this code will be copied to on-chip memory and executed from there.
*/ */
.balign 4096,0,4096 .balign 4096,0,4096
ENTRY(sh_mobile_standby) ENTRY(sh_mobile_standby)
/* save original vbr */
stc vbr, r1
mova saved_vbr, r0
mov.l r1, @r0
/* point vbr to our on-chip memory page */
ldc r5, vbr
/* save return address */
mova saved_spc, r0
sts pr, r5
mov.l r5, @r0
/* save sr */
mova saved_sr, r0
stc sr, r5
mov.l r5, @r0
/* save mode flags */
mova saved_mode, r0
mov.l r4, @r0
/* put mode flags in r0 */
mov r4, r0 mov r4, r0
tst #SUSP_SH_SF, r0 tst #SUSP_SH_SF, r0
bt skip_set_sf bt skip_set_sf
#ifdef CONFIG_CPU_SUBTYPE_SH7724 #ifdef CONFIG_CPU_SUBTYPE_SH7724
/* DBSC: put memory in self-refresh mode */ /* DBSC: put memory in self-refresh mode */
mov.l dben_reg, r4 mov.l dben_reg, r4
mov.l dben_data0, r1 mov.l dben_data0, r1
mov.l r1, @r4 mov.l r1, @r4
...@@ -60,14 +93,6 @@ ENTRY(sh_mobile_standby) ...@@ -60,14 +93,6 @@ ENTRY(sh_mobile_standby)
#endif #endif
skip_set_sf: skip_set_sf:
tst #SUSP_SH_SLEEP, r0
bt test_standby
/* set mode to "sleep mode" */
bra do_sleep
mov #0x00, r1
test_standby:
tst #SUSP_SH_STANDBY, r0 tst #SUSP_SH_STANDBY, r0
bt test_rstandby bt test_rstandby
...@@ -85,77 +110,107 @@ test_rstandby: ...@@ -85,77 +110,107 @@ test_rstandby:
test_ustandby: test_ustandby:
tst #SUSP_SH_USTANDBY, r0 tst #SUSP_SH_USTANDBY, r0
bt done_sleep bt force_sleep
/* set mode to "u-standby mode" */ /* set mode to "u-standby mode" */
mov #0x10, r1 bra do_sleep
mov #0x10, r1
/* fall-through */ force_sleep:
/* set mode to "sleep mode" */
mov #0x00, r1
do_sleep: do_sleep:
/* setup and enter selected standby mode */ /* setup and enter selected standby mode */
mov.l 5f, r4 mov.l 5f, r4
mov.l r1, @r4 mov.l r1, @r4
again:
sleep sleep
bra again
nop
restore_jump_vbr:
/* setup spc with return address to c code */
mov.l saved_spc, k0
ldc k0, spc
/* restore vbr */
mov.l saved_vbr, k0
ldc k0, vbr
/* setup ssr with saved sr */
mov.l saved_sr, k0
ldc k0, ssr
/* get mode flags */
mov.l saved_mode, k0
done_sleep: done_sleep:
/* reset standby mode to sleep mode */ /* reset standby mode to sleep mode */
mov.l 5f, r4 mov.l 5f, k4
mov #0x00, r1 mov #0x00, k1
mov.l r1, @r4 mov.l k1, @k4
tst #SUSP_SH_SF, r0 tst #SUSP_SH_SF, k0
bt skip_restore_sf bt skip_restore_sf
#ifdef CONFIG_CPU_SUBTYPE_SH7724 #ifdef CONFIG_CPU_SUBTYPE_SH7724
/* DBSC: put memory in auto-refresh mode */ /* DBSC: put memory in auto-refresh mode */
mov.l dbrfpdn0_reg, k4
mov.l dbrfpdn0_data0, k1
mov.l k1, @k4
mov.l dbrfpdn0_reg, r4 nop /* sleep 140 ns */
mov.l dbrfpdn0_data0, r1
mov.l r1, @r4
/* sleep 140 ns */
nop
nop nop
nop nop
nop nop
mov.l dbcmdcnt_reg, r4 mov.l dbcmdcnt_reg, k4
mov.l dbcmdcnt_data0, r1 mov.l dbcmdcnt_data0, k1
mov.l r1, @r4 mov.l k1, @k4
mov.l dbcmdcnt_reg, r4 mov.l dbcmdcnt_reg, k4
mov.l dbcmdcnt_data1, r1 mov.l dbcmdcnt_data1, k1
mov.l r1, @r4 mov.l k1, @k4
mov.l dben_reg, r4 mov.l dben_reg, k4
mov.l dben_data1, r1 mov.l dben_data1, k1
mov.l r1, @r4 mov.l k1, @k4
mov.l dbrfpdn0_reg, r4 mov.l dbrfpdn0_reg, k4
mov.l dbrfpdn0_data2, r1 mov.l dbrfpdn0_data2, k1
mov.l r1, @r4 mov.l k1, @k4
#else #else
/* SBSC: set auto-refresh mode */ /* SBSC: set auto-refresh mode */
mov.l 1f, r4 mov.l 1f, k4
mov.l @r4, r2 mov.l @k4, k0
mov.l 4f, r3 mov.l 4f, k1
and r3, r2 and k1, k0
mov.l r2, @r4 mov.l k0, @k4
mov.l 6f, r4 mov.l 6f, k4
mov.l 7f, r1 mov.l 8f, k0
mov.l 8f, r2 mov.l @k4, k1
mov.l @r4, r3 mov #-1, k4
mov #-1, r4 add k4, k1
add r4, r3 or k1, k0
or r2, r3 mov.l 7f, k1
mov.l r3, @r1 mov.l k0, @k1
#endif #endif
skip_restore_sf: skip_restore_sf:
rts /* jump to vbr vector */
mov.l saved_vbr, k0
mov.l offset_vbr, k4
add k4, k0
jmp @k0
nop nop
.balign 4 .balign 4
saved_mode: .long 0
saved_spc: .long 0
saved_sr: .long 0
saved_vbr: .long 0
offset_vbr: .long 0x600
#ifdef CONFIG_CPU_SUBTYPE_SH7724 #ifdef CONFIG_CPU_SUBTYPE_SH7724
dben_reg: .long 0xfd000010 /* DBEN */ dben_reg: .long 0xfd000010 /* DBEN */
dben_data0: .long 0 dben_data0: .long 0
...@@ -178,12 +233,12 @@ dbcmdcnt_data1: .long 4 ...@@ -178,12 +233,12 @@ dbcmdcnt_data1: .long 4
7: .long 0xfe400018 /* RTCNT */ 7: .long 0xfe400018 /* RTCNT */
8: .long 0xa55a0000 8: .long 0xa55a0000
/* interrupt vector @ 0x600 */ /* interrupt vector @ 0x600 */
.balign 0x400,0,0x400 .balign 0x400,0,0x400
.long 0xdeadbeef .long 0xdeadbeef
.balign 0x200,0,0x200 .balign 0x200,0,0x200
/* sh7722 will end up here in sleep mode */ bra restore_jump_vbr
rte
nop nop
sh_mobile_standby_end: sh_mobile_standby_end:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment