/* * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S * * Sleep mode and Standby modes support for SuperH Mobile * * Copyright (C) 2009 Magnus Damm * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */ #include #include #include #include #include /* * Kernel mode register usage, see entry.S: * k0 scratch * k1 scratch */ #define k0 r0 #define k1 r1 /* manage self-refresh and enter standby mode. must be self-contained. * this code will be copied to on-chip memory and executed from there. */ .balign 4 ENTRY(sh_mobile_sleep_enter_start) /* save mode flags */ mov.l r4, @(SH_SLEEP_MODE, r5) /* save original vbr */ stc vbr, r0 mov.l r0, @(SH_SLEEP_VBR, r5) /* point vbr to our on-chip memory page */ ldc r5, vbr /* save return address */ sts pr, r0 mov.l r0, @(SH_SLEEP_SPC, r5) /* save sr */ stc sr, r0 mov.l r0, @(SH_SLEEP_SR, r5) /* save stbcr */ bsr save_register mov #SH_SLEEP_REG_STBCR, r0 /* call self-refresh entering code if needed */ mov.l @(SH_SLEEP_MODE, r5), r0 tst #SUSP_SH_SF, r0 bt skip_set_sf mov.l @(SH_SLEEP_SF_PRE, r5), r0 jsr @r0 nop skip_set_sf: mov.l @(SH_SLEEP_MODE, r5), r0 tst #SUSP_SH_STANDBY, r0 bt test_rstandby /* set mode to "software standby mode" */ bra do_sleep mov #0x80, r1 test_rstandby: tst #SUSP_SH_RSTANDBY, r0 bt test_ustandby /* set mode to "r-standby mode" */ bra do_sleep mov #0x20, r1 test_ustandby: tst #SUSP_SH_USTANDBY, r0 bt force_sleep /* set mode to "u-standby mode" */ bra do_sleep mov #0x10, r1 force_sleep: /* set mode to "sleep mode" */ mov #0x00, r1 do_sleep: /* setup and enter selected standby mode */ bsr get_register mov #SH_SLEEP_REG_STBCR, r0 mov.l r1, @r0 again: sleep bra again nop save_register: add #SH_SLEEP_BASE_ADDR, r0 mov.l @(r0, r5), r1 add #-SH_SLEEP_BASE_ADDR, r0 mov.l @r1, r1 add #SH_SLEEP_BASE_DATA, r0 mov.l r1, @(r0, r5) add #-SH_SLEEP_BASE_DATA, r0 rts nop get_register: add #SH_SLEEP_BASE_ADDR, r0 mov.l @(r0, r5), r0 rts nop ENTRY(sh_mobile_sleep_enter_end) .balign 4 ENTRY(sh_mobile_sleep_resume_start) /* figure out start address */ bsr 0f nop 0: sts pr, k1 mov.l 1f, k0 and k0, k1 /* store pointer to data area in VBR */ ldc k1, vbr /* setup sr with saved sr */ mov.l @(SH_SLEEP_SR, k1), k0 ldc k0, sr /* now: user register set! */ stc vbr, r5 /* setup spc with return address to c code */ mov.l @(SH_SLEEP_SPC, r5), r0 ldc r0, spc /* restore vbr */ mov.l @(SH_SLEEP_VBR, r5), r0 ldc r0, vbr /* setup ssr with saved sr */ mov.l @(SH_SLEEP_SR, r5), r0 ldc r0, ssr /* restore sleep mode register */ bsr restore_register mov #SH_SLEEP_REG_STBCR, r0 /* call self-refresh resume code if needed */ mov.l @(SH_SLEEP_MODE, r5), r0 tst #SUSP_SH_SF, r0 bt skip_restore_sf mov.l @(SH_SLEEP_SF_POST, r5), r0 jsr @r0 nop skip_restore_sf: rte nop restore_register: add #SH_SLEEP_BASE_DATA, r0 mov.l @(r0, r5), r1 add #-SH_SLEEP_BASE_DATA, r0 add #SH_SLEEP_BASE_ADDR, r0 mov.l @(r0, r5), r0 mov.l r1, @r0 rts nop .balign 4 1: .long ~0x7ff ENTRY(sh_mobile_sleep_resume_end)