123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- /*
- * 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 <linux/sys.h>
- #include <linux/errno.h>
- #include <linux/linkage.h>
- #include <asm/asm-offsets.h>
- #include <asm/suspend.h>
- /*
- * 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 general purpose registers to stack if needed */
- mov.l @(SH_SLEEP_MODE, r5), r0
- tst #SUSP_SH_REGS, r0
- bt skip_regs_save
- sts.l pr, @-r15
- mov.l r14, @-r15
- mov.l r13, @-r15
- mov.l r12, @-r15
- mov.l r11, @-r15
- mov.l r10, @-r15
- mov.l r9, @-r15
- mov.l r8, @-r15
- /* make sure bank0 is selected, save low registers */
- mov.l rb_bit, r9
- not r9, r9
- bsr set_sr
- mov #0, r10
- bsr save_low_regs
- nop
- /* switch to bank 1, save low registers */
- mov.l rb_bit, r10
- bsr set_sr
- mov #-1, r9
- bsr save_low_regs
- nop
- /* switch back to bank 0 */
- mov.l rb_bit, r9
- not r9, r9
- bsr set_sr
- mov #0, r10
- skip_regs_save:
- /* save sp, also set to internal ram */
- mov.l r15, @(SH_SLEEP_SP, r5)
- mov r5, r15
- /* save stbcr */
- bsr save_register
- mov #SH_SLEEP_REG_STBCR, r0
- /* save mmu and cache context if needed */
- mov.l @(SH_SLEEP_MODE, r5), r0
- tst #SUSP_SH_MMU, r0
- bt skip_mmu_save_disable
- /* save mmu state */
- bsr save_register
- mov #SH_SLEEP_REG_PTEH, r0
- bsr save_register
- mov #SH_SLEEP_REG_PTEL, r0
- bsr save_register
- mov #SH_SLEEP_REG_TTB, r0
- bsr save_register
- mov #SH_SLEEP_REG_TEA, r0
- bsr save_register
- mov #SH_SLEEP_REG_MMUCR, r0
- bsr save_register
- mov #SH_SLEEP_REG_PTEA, r0
- bsr save_register
- mov #SH_SLEEP_REG_PASCR, r0
- bsr save_register
- mov #SH_SLEEP_REG_IRMCR, r0
- /* invalidate TLBs and disable the MMU */
- bsr get_register
- mov #SH_SLEEP_REG_MMUCR, r0
- mov #4, r1
- mov.l r1, @r0
- icbi @r0
- /* save cache registers and disable caches */
- bsr save_register
- mov #SH_SLEEP_REG_CCR, r0
- bsr save_register
- mov #SH_SLEEP_REG_RAMCR, r0
- bsr get_register
- mov #SH_SLEEP_REG_CCR, r0
- mov #0, r1
- mov.l r1, @r0
- icbi @r0
- skip_mmu_save_disable:
- /* 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
- /* setup BAR register */
- bsr get_register
- mov #SH_SLEEP_REG_BAR, r0
- mov.l @(SH_SLEEP_RESUME, r5), r1
- mov.l r1, @r0
- /* 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
- set_sr:
- stc sr, r8
- and r9, r8
- or r10, r8
- ldc r8, sr
- rts
- nop
- save_low_regs:
- mov.l r7, @-r15
- mov.l r6, @-r15
- mov.l r5, @-r15
- mov.l r4, @-r15
- mov.l r3, @-r15
- mov.l r2, @-r15
- mov.l r1, @-r15
- rts
- mov.l r0, @-r15
- .balign 4
- rb_bit: .long 0x20000000 ! RB=1
- 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 sp */
- mov.l @(SH_SLEEP_SP, r5), r15
- /* 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:
- /* restore mmu and cache state if needed */
- mov.l @(SH_SLEEP_MODE, r5), r0
- tst #SUSP_SH_MMU, r0
- bt skip_restore_mmu
- /* restore mmu state */
- bsr restore_register
- mov #SH_SLEEP_REG_PTEH, r0
- bsr restore_register
- mov #SH_SLEEP_REG_PTEL, r0
- bsr restore_register
- mov #SH_SLEEP_REG_TTB, r0
- bsr restore_register
- mov #SH_SLEEP_REG_TEA, r0
- bsr restore_register
- mov #SH_SLEEP_REG_PTEA, r0
- bsr restore_register
- mov #SH_SLEEP_REG_PASCR, r0
- bsr restore_register
- mov #SH_SLEEP_REG_IRMCR, r0
- bsr restore_register
- mov #SH_SLEEP_REG_MMUCR, r0
- icbi @r0
- /* restore cache settings */
- bsr restore_register
- mov #SH_SLEEP_REG_RAMCR, r0
- icbi @r0
- bsr restore_register
- mov #SH_SLEEP_REG_CCR, r0
- icbi @r0
- skip_restore_mmu:
- /* restore general purpose registers if needed */
- mov.l @(SH_SLEEP_MODE, r5), r0
- tst #SUSP_SH_REGS, r0
- bt skip_restore_regs
- /* switch to bank 1, restore low registers */
- mov.l _rb_bit, r10
- bsr _set_sr
- mov #-1, r9
- bsr restore_low_regs
- nop
- /* switch to bank0, restore low registers */
- mov.l _rb_bit, r9
- not r9, r9
- bsr _set_sr
- mov #0, r10
- bsr restore_low_regs
- nop
- /* restore the rest of the registers */
- mov.l @r15+, r8
- mov.l @r15+, r9
- mov.l @r15+, r10
- mov.l @r15+, r11
- mov.l @r15+, r12
- mov.l @r15+, r13
- mov.l @r15+, r14
- lds.l @r15+, pr
- skip_restore_regs:
- 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
- _set_sr:
- stc sr, r8
- and r9, r8
- or r10, r8
- ldc r8, sr
- rts
- nop
- restore_low_regs:
- mov.l @r15+, r0
- mov.l @r15+, r1
- mov.l @r15+, r2
- mov.l @r15+, r3
- mov.l @r15+, r4
- mov.l @r15+, r5
- mov.l @r15+, r6
- rts
- mov.l @r15+, r7
- .balign 4
- _rb_bit: .long 0x20000000 ! RB=1
- 1: .long ~0x7ff
- ENTRY(sh_mobile_sleep_resume_end)
|