Path: blob/master/arch/sh/kernel/cpu/shmobile/sleep.S
17372 views
/*1* arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S2*3* Sleep mode and Standby modes support for SuperH Mobile4*5* Copyright (C) 2009 Magnus Damm6*7* This file is subject to the terms and conditions of the GNU General Public8* License. See the file "COPYING" in the main directory of this archive9* for more details.10*/1112#include <linux/sys.h>13#include <linux/errno.h>14#include <linux/linkage.h>15#include <asm/asm-offsets.h>16#include <asm/suspend.h>1718/*19* Kernel mode register usage, see entry.S:20* k0 scratch21* k1 scratch22*/23#define k0 r024#define k1 r12526/* manage self-refresh and enter standby mode. must be self-contained.27* this code will be copied to on-chip memory and executed from there.28*/29.balign 430ENTRY(sh_mobile_sleep_enter_start)3132/* save mode flags */33mov.l r4, @(SH_SLEEP_MODE, r5)3435/* save original vbr */36stc vbr, r037mov.l r0, @(SH_SLEEP_VBR, r5)3839/* point vbr to our on-chip memory page */40ldc r5, vbr4142/* save return address */43sts pr, r044mov.l r0, @(SH_SLEEP_SPC, r5)4546/* save sr */47stc sr, r048mov.l r0, @(SH_SLEEP_SR, r5)4950/* save general purpose registers to stack if needed */51mov.l @(SH_SLEEP_MODE, r5), r052tst #SUSP_SH_REGS, r053bt skip_regs_save5455sts.l pr, @-r1556mov.l r14, @-r1557mov.l r13, @-r1558mov.l r12, @-r1559mov.l r11, @-r1560mov.l r10, @-r1561mov.l r9, @-r1562mov.l r8, @-r156364/* make sure bank0 is selected, save low registers */65mov.l rb_bit, r966not r9, r967bsr set_sr68mov #0, r106970bsr save_low_regs71nop7273/* switch to bank 1, save low registers */74mov.l rb_bit, r1075bsr set_sr76mov #-1, r97778bsr save_low_regs79nop8081/* switch back to bank 0 */82mov.l rb_bit, r983not r9, r984bsr set_sr85mov #0, r108687skip_regs_save:8889/* save sp, also set to internal ram */90mov.l r15, @(SH_SLEEP_SP, r5)91mov r5, r159293/* save stbcr */94bsr save_register95mov #SH_SLEEP_REG_STBCR, r09697/* save mmu and cache context if needed */98mov.l @(SH_SLEEP_MODE, r5), r099tst #SUSP_SH_MMU, r0100bt skip_mmu_save_disable101102/* save mmu state */103bsr save_register104mov #SH_SLEEP_REG_PTEH, r0105106bsr save_register107mov #SH_SLEEP_REG_PTEL, r0108109bsr save_register110mov #SH_SLEEP_REG_TTB, r0111112bsr save_register113mov #SH_SLEEP_REG_TEA, r0114115bsr save_register116mov #SH_SLEEP_REG_MMUCR, r0117118bsr save_register119mov #SH_SLEEP_REG_PTEA, r0120121bsr save_register122mov #SH_SLEEP_REG_PASCR, r0123124bsr save_register125mov #SH_SLEEP_REG_IRMCR, r0126127/* invalidate TLBs and disable the MMU */128bsr get_register129mov #SH_SLEEP_REG_MMUCR, r0130mov #4, r1131mov.l r1, @r0132icbi @r0133134/* save cache registers and disable caches */135bsr save_register136mov #SH_SLEEP_REG_CCR, r0137138bsr save_register139mov #SH_SLEEP_REG_RAMCR, r0140141bsr get_register142mov #SH_SLEEP_REG_CCR, r0143mov #0, r1144mov.l r1, @r0145icbi @r0146147skip_mmu_save_disable:148/* call self-refresh entering code if needed */149mov.l @(SH_SLEEP_MODE, r5), r0150tst #SUSP_SH_SF, r0151bt skip_set_sf152153mov.l @(SH_SLEEP_SF_PRE, r5), r0154jsr @r0155nop156157skip_set_sf:158mov.l @(SH_SLEEP_MODE, r5), r0159tst #SUSP_SH_STANDBY, r0160bt test_rstandby161162/* set mode to "software standby mode" */163bra do_sleep164mov #0x80, r1165166test_rstandby:167tst #SUSP_SH_RSTANDBY, r0168bt test_ustandby169170/* setup BAR register */171bsr get_register172mov #SH_SLEEP_REG_BAR, r0173mov.l @(SH_SLEEP_RESUME, r5), r1174mov.l r1, @r0175176/* set mode to "r-standby mode" */177bra do_sleep178mov #0x20, r1179180test_ustandby:181tst #SUSP_SH_USTANDBY, r0182bt force_sleep183184/* set mode to "u-standby mode" */185bra do_sleep186mov #0x10, r1187188force_sleep:189190/* set mode to "sleep mode" */191mov #0x00, r1192193do_sleep:194/* setup and enter selected standby mode */195bsr get_register196mov #SH_SLEEP_REG_STBCR, r0197mov.l r1, @r0198again:199sleep200bra again201nop202203save_register:204add #SH_SLEEP_BASE_ADDR, r0205mov.l @(r0, r5), r1206add #-SH_SLEEP_BASE_ADDR, r0207mov.l @r1, r1208add #SH_SLEEP_BASE_DATA, r0209mov.l r1, @(r0, r5)210add #-SH_SLEEP_BASE_DATA, r0211rts212nop213214get_register:215add #SH_SLEEP_BASE_ADDR, r0216mov.l @(r0, r5), r0217rts218nop219220set_sr:221stc sr, r8222and r9, r8223or r10, r8224ldc r8, sr225rts226nop227228save_low_regs:229mov.l r7, @-r15230mov.l r6, @-r15231mov.l r5, @-r15232mov.l r4, @-r15233mov.l r3, @-r15234mov.l r2, @-r15235mov.l r1, @-r15236rts237mov.l r0, @-r15238239.balign 4240rb_bit: .long 0x20000000 ! RB=1241242ENTRY(sh_mobile_sleep_enter_end)243244.balign 4245ENTRY(sh_mobile_sleep_resume_start)246247/* figure out start address */248bsr 0f249nop2500:251sts pr, k1252mov.l 1f, k0253and k0, k1254255/* store pointer to data area in VBR */256ldc k1, vbr257258/* setup sr with saved sr */259mov.l @(SH_SLEEP_SR, k1), k0260ldc k0, sr261262/* now: user register set! */263stc vbr, r5264265/* setup spc with return address to c code */266mov.l @(SH_SLEEP_SPC, r5), r0267ldc r0, spc268269/* restore vbr */270mov.l @(SH_SLEEP_VBR, r5), r0271ldc r0, vbr272273/* setup ssr with saved sr */274mov.l @(SH_SLEEP_SR, r5), r0275ldc r0, ssr276277/* restore sp */278mov.l @(SH_SLEEP_SP, r5), r15279280/* restore sleep mode register */281bsr restore_register282mov #SH_SLEEP_REG_STBCR, r0283284/* call self-refresh resume code if needed */285mov.l @(SH_SLEEP_MODE, r5), r0286tst #SUSP_SH_SF, r0287bt skip_restore_sf288289mov.l @(SH_SLEEP_SF_POST, r5), r0290jsr @r0291nop292293skip_restore_sf:294/* restore mmu and cache state if needed */295mov.l @(SH_SLEEP_MODE, r5), r0296tst #SUSP_SH_MMU, r0297bt skip_restore_mmu298299/* restore mmu state */300bsr restore_register301mov #SH_SLEEP_REG_PTEH, r0302303bsr restore_register304mov #SH_SLEEP_REG_PTEL, r0305306bsr restore_register307mov #SH_SLEEP_REG_TTB, r0308309bsr restore_register310mov #SH_SLEEP_REG_TEA, r0311312bsr restore_register313mov #SH_SLEEP_REG_PTEA, r0314315bsr restore_register316mov #SH_SLEEP_REG_PASCR, r0317318bsr restore_register319mov #SH_SLEEP_REG_IRMCR, r0320321bsr restore_register322mov #SH_SLEEP_REG_MMUCR, r0323icbi @r0324325/* restore cache settings */326bsr restore_register327mov #SH_SLEEP_REG_RAMCR, r0328icbi @r0329330bsr restore_register331mov #SH_SLEEP_REG_CCR, r0332icbi @r0333334skip_restore_mmu:335336/* restore general purpose registers if needed */337mov.l @(SH_SLEEP_MODE, r5), r0338tst #SUSP_SH_REGS, r0339bt skip_restore_regs340341/* switch to bank 1, restore low registers */342mov.l _rb_bit, r10343bsr _set_sr344mov #-1, r9345346bsr restore_low_regs347nop348349/* switch to bank0, restore low registers */350mov.l _rb_bit, r9351not r9, r9352bsr _set_sr353mov #0, r10354355bsr restore_low_regs356nop357358/* restore the rest of the registers */359mov.l @r15+, r8360mov.l @r15+, r9361mov.l @r15+, r10362mov.l @r15+, r11363mov.l @r15+, r12364mov.l @r15+, r13365mov.l @r15+, r14366lds.l @r15+, pr367368skip_restore_regs:369rte370nop371372restore_register:373add #SH_SLEEP_BASE_DATA, r0374mov.l @(r0, r5), r1375add #-SH_SLEEP_BASE_DATA, r0376add #SH_SLEEP_BASE_ADDR, r0377mov.l @(r0, r5), r0378mov.l r1, @r0379rts380nop381382_set_sr:383stc sr, r8384and r9, r8385or r10, r8386ldc r8, sr387rts388nop389390restore_low_regs:391mov.l @r15+, r0392mov.l @r15+, r1393mov.l @r15+, r2394mov.l @r15+, r3395mov.l @r15+, r4396mov.l @r15+, r5397mov.l @r15+, r6398rts399mov.l @r15+, r7400401.balign 4402_rb_bit: .long 0x20000000 ! RB=14031: .long ~0x7ff404ENTRY(sh_mobile_sleep_resume_end)405406407