1e9edb3feSPaul Mundt/* 2e9edb3feSPaul Mundt * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S 3e9edb3feSPaul Mundt * 4e9edb3feSPaul Mundt * Sleep mode and Standby modes support for SuperH Mobile 5e9edb3feSPaul Mundt * 6e9edb3feSPaul Mundt * Copyright (C) 2009 Magnus Damm 7e9edb3feSPaul Mundt * 8e9edb3feSPaul Mundt * This file is subject to the terms and conditions of the GNU General Public 9e9edb3feSPaul Mundt * License. See the file "COPYING" in the main directory of this archive 10e9edb3feSPaul Mundt * for more details. 11e9edb3feSPaul Mundt */ 12e9edb3feSPaul Mundt 13e9edb3feSPaul Mundt#include <linux/sys.h> 14e9edb3feSPaul Mundt#include <linux/errno.h> 15e9edb3feSPaul Mundt#include <linux/linkage.h> 16e9edb3feSPaul Mundt#include <asm/asm-offsets.h> 17e9edb3feSPaul Mundt#include <asm/suspend.h> 18e9edb3feSPaul Mundt 19309214afSMagnus Damm/* 20309214afSMagnus Damm * Kernel mode register usage, see entry.S: 21309214afSMagnus Damm * k0 scratch 22309214afSMagnus Damm * k1 scratch 23309214afSMagnus Damm */ 24309214afSMagnus Damm#define k0 r0 25309214afSMagnus Damm#define k1 r1 26309214afSMagnus Damm 27323ef8dbSMagnus Damm/* manage self-refresh and enter standby mode. must be self-contained. 28e9edb3feSPaul Mundt * this code will be copied to on-chip memory and executed from there. 29e9edb3feSPaul Mundt */ 30323ef8dbSMagnus Damm .balign 4 31323ef8dbSMagnus DammENTRY(sh_mobile_sleep_enter_start) 32e9edb3feSPaul Mundt 33323ef8dbSMagnus Damm /* save mode flags */ 34323ef8dbSMagnus Damm mov.l r4, @(SH_SLEEP_MODE, r5) 35309214afSMagnus Damm 36309214afSMagnus Damm /* save original vbr */ 37323ef8dbSMagnus Damm stc vbr, r0 38323ef8dbSMagnus Damm mov.l r0, @(SH_SLEEP_VBR, r5) 39309214afSMagnus Damm 40309214afSMagnus Damm /* point vbr to our on-chip memory page */ 41309214afSMagnus Damm ldc r5, vbr 42309214afSMagnus Damm 43309214afSMagnus Damm /* save return address */ 44323ef8dbSMagnus Damm sts pr, r0 45323ef8dbSMagnus Damm mov.l r0, @(SH_SLEEP_SPC, r5) 46309214afSMagnus Damm 47309214afSMagnus Damm /* save sr */ 48323ef8dbSMagnus Damm stc sr, r0 49323ef8dbSMagnus Damm mov.l r0, @(SH_SLEEP_SR, r5) 50309214afSMagnus Damm 51323ef8dbSMagnus Damm /* save stbcr */ 52323ef8dbSMagnus Damm bsr save_register 53323ef8dbSMagnus Damm mov #SH_SLEEP_REG_STBCR, r0 54309214afSMagnus Damm 55323ef8dbSMagnus Damm /* call self-refresh entering code if needed */ 56323ef8dbSMagnus Damm mov.l @(SH_SLEEP_MODE, r5), r0 57e9edb3feSPaul Mundt tst #SUSP_SH_SF, r0 58e9edb3feSPaul Mundt bt skip_set_sf 59237674e0SMagnus Damm 60323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SF_PRE, r5), r0 61323ef8dbSMagnus Damm jsr @r0 62323ef8dbSMagnus Damm nop 63e9edb3feSPaul Mundt 64e9edb3feSPaul Mundtskip_set_sf: 65323ef8dbSMagnus Damm mov.l @(SH_SLEEP_MODE, r5), r0 66e9edb3feSPaul Mundt tst #SUSP_SH_STANDBY, r0 67e9edb3feSPaul Mundt bt test_rstandby 68e9edb3feSPaul Mundt 69e9edb3feSPaul Mundt /* set mode to "software standby mode" */ 70e9edb3feSPaul Mundt bra do_sleep 71e9edb3feSPaul Mundt mov #0x80, r1 72e9edb3feSPaul Mundt 73e9edb3feSPaul Mundttest_rstandby: 74e9edb3feSPaul Mundt tst #SUSP_SH_RSTANDBY, r0 75e9edb3feSPaul Mundt bt test_ustandby 76e9edb3feSPaul Mundt 77e9edb3feSPaul Mundt /* set mode to "r-standby mode" */ 78e9edb3feSPaul Mundt bra do_sleep 79e9edb3feSPaul Mundt mov #0x20, r1 80e9edb3feSPaul Mundt 81e9edb3feSPaul Mundttest_ustandby: 82e9edb3feSPaul Mundt tst #SUSP_SH_USTANDBY, r0 83309214afSMagnus Damm bt force_sleep 84e9edb3feSPaul Mundt 85e9edb3feSPaul Mundt /* set mode to "u-standby mode" */ 86309214afSMagnus Damm bra do_sleep 87e9edb3feSPaul Mundt mov #0x10, r1 88e9edb3feSPaul Mundt 89309214afSMagnus Dammforce_sleep: 90309214afSMagnus Damm 91309214afSMagnus Damm /* set mode to "sleep mode" */ 92309214afSMagnus Damm mov #0x00, r1 93e9edb3feSPaul Mundt 94e9edb3feSPaul Mundtdo_sleep: 95e9edb3feSPaul Mundt /* setup and enter selected standby mode */ 96323ef8dbSMagnus Damm bsr get_register 97323ef8dbSMagnus Damm mov #SH_SLEEP_REG_STBCR, r0 98323ef8dbSMagnus Damm mov.l r1, @r0 99309214afSMagnus Dammagain: 100e9edb3feSPaul Mundt sleep 101309214afSMagnus Damm bra again 102309214afSMagnus Damm nop 103309214afSMagnus Damm 104323ef8dbSMagnus Dammsave_register: 105323ef8dbSMagnus Damm add #SH_SLEEP_BASE_ADDR, r0 106323ef8dbSMagnus Damm mov.l @(r0, r5), r1 107323ef8dbSMagnus Damm add #-SH_SLEEP_BASE_ADDR, r0 108323ef8dbSMagnus Damm mov.l @r1, r1 109323ef8dbSMagnus Damm add #SH_SLEEP_BASE_DATA, r0 110323ef8dbSMagnus Damm mov.l r1, @(r0, r5) 111323ef8dbSMagnus Damm add #-SH_SLEEP_BASE_DATA, r0 112323ef8dbSMagnus Damm rts 113323ef8dbSMagnus Damm nop 114323ef8dbSMagnus Damm 115323ef8dbSMagnus Dammget_register: 116323ef8dbSMagnus Damm add #SH_SLEEP_BASE_ADDR, r0 117323ef8dbSMagnus Damm mov.l @(r0, r5), r0 118323ef8dbSMagnus Damm rts 119323ef8dbSMagnus Damm nop 120323ef8dbSMagnus DammENTRY(sh_mobile_sleep_enter_end) 121323ef8dbSMagnus Damm 122323ef8dbSMagnus Damm .balign 4 123323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_start) 124323ef8dbSMagnus Damm 125323ef8dbSMagnus Damm /* figure out start address */ 126323ef8dbSMagnus Damm bsr 0f 127323ef8dbSMagnus Damm nop 128323ef8dbSMagnus Damm0: 129323ef8dbSMagnus Damm sts pr, k1 130323ef8dbSMagnus Damm mov.l 1f, k0 131323ef8dbSMagnus Damm and k0, k1 132323ef8dbSMagnus Damm 133323ef8dbSMagnus Damm /* store pointer to data area in VBR */ 134323ef8dbSMagnus Damm ldc k1, vbr 135323ef8dbSMagnus Damm 136323ef8dbSMagnus Damm /* setup sr with saved sr */ 137323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SR, k1), k0 138323ef8dbSMagnus Damm ldc k0, sr 139323ef8dbSMagnus Damm 140323ef8dbSMagnus Damm /* now: user register set! */ 141323ef8dbSMagnus Damm stc vbr, r5 142323ef8dbSMagnus Damm 143309214afSMagnus Damm /* setup spc with return address to c code */ 144323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SPC, r5), r0 145323ef8dbSMagnus Damm ldc r0, spc 146309214afSMagnus Damm 147309214afSMagnus Damm /* restore vbr */ 148323ef8dbSMagnus Damm mov.l @(SH_SLEEP_VBR, r5), r0 149323ef8dbSMagnus Damm ldc r0, vbr 150309214afSMagnus Damm 151309214afSMagnus Damm /* setup ssr with saved sr */ 152323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SR, r5), r0 153323ef8dbSMagnus Damm ldc r0, ssr 154309214afSMagnus Damm 155323ef8dbSMagnus Damm /* restore sleep mode register */ 156323ef8dbSMagnus Damm bsr restore_register 157323ef8dbSMagnus Damm mov #SH_SLEEP_REG_STBCR, r0 158e9edb3feSPaul Mundt 159323ef8dbSMagnus Damm /* call self-refresh resume code if needed */ 160323ef8dbSMagnus Damm mov.l @(SH_SLEEP_MODE, r5), r0 161323ef8dbSMagnus Damm tst #SUSP_SH_SF, r0 162e9edb3feSPaul Mundt bt skip_restore_sf 163e9edb3feSPaul Mundt 164323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SF_POST, r5), r0 165323ef8dbSMagnus Damm jsr @r0 166237674e0SMagnus Damm nop 167237674e0SMagnus Damm 168e9edb3feSPaul Mundtskip_restore_sf: 169323ef8dbSMagnus Damm rte 170323ef8dbSMagnus Damm nop 171323ef8dbSMagnus Damm 172323ef8dbSMagnus Dammrestore_register: 173323ef8dbSMagnus Damm add #SH_SLEEP_BASE_DATA, r0 174323ef8dbSMagnus Damm mov.l @(r0, r5), r1 175323ef8dbSMagnus Damm add #-SH_SLEEP_BASE_DATA, r0 176323ef8dbSMagnus Damm add #SH_SLEEP_BASE_ADDR, r0 177323ef8dbSMagnus Damm mov.l @(r0, r5), r0 178323ef8dbSMagnus Damm mov.l r1, @r0 179323ef8dbSMagnus Damm rts 180e9edb3feSPaul Mundt nop 181e9edb3feSPaul Mundt 182e9edb3feSPaul Mundt .balign 4 183323ef8dbSMagnus Damm1: .long ~0x7ff 184323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_end) 185