1/* 2 * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S 3 * 4 * Sleep mode and Standby modes support for SuperH Mobile 5 * 6 * Copyright (C) 2009 Magnus Damm 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 */ 12 13#include <linux/sys.h> 14#include <linux/errno.h> 15#include <linux/linkage.h> 16#include <asm/asm-offsets.h> 17#include <asm/suspend.h> 18 19/* 20 * Kernel mode register usage, see entry.S: 21 * k0 scratch 22 * k1 scratch 23 */ 24#define k0 r0 25#define k1 r1 26 27/* manage self-refresh and enter standby mode. must be self-contained. 28 * this code will be copied to on-chip memory and executed from there. 29 */ 30 .balign 4 31ENTRY(sh_mobile_sleep_enter_start) 32 33 /* save mode flags */ 34 mov.l r4, @(SH_SLEEP_MODE, r5) 35 36 /* save original vbr */ 37 stc vbr, r0 38 mov.l r0, @(SH_SLEEP_VBR, r5) 39 40 /* point vbr to our on-chip memory page */ 41 ldc r5, vbr 42 43 /* save return address */ 44 sts pr, r0 45 mov.l r0, @(SH_SLEEP_SPC, r5) 46 47 /* save sr */ 48 stc sr, r0 49 mov.l r0, @(SH_SLEEP_SR, r5) 50 51 /* save stbcr */ 52 bsr save_register 53 mov #SH_SLEEP_REG_STBCR, r0 54 55 /* call self-refresh entering code if needed */ 56 mov.l @(SH_SLEEP_MODE, r5), r0 57 tst #SUSP_SH_SF, r0 58 bt skip_set_sf 59 60 mov.l @(SH_SLEEP_SF_PRE, r5), r0 61 jsr @r0 62 nop 63 64skip_set_sf: 65 mov.l @(SH_SLEEP_MODE, r5), r0 66 tst #SUSP_SH_STANDBY, r0 67 bt test_rstandby 68 69 /* set mode to "software standby mode" */ 70 bra do_sleep 71 mov #0x80, r1 72 73test_rstandby: 74 tst #SUSP_SH_RSTANDBY, r0 75 bt test_ustandby 76 77 /* set mode to "r-standby mode" */ 78 bra do_sleep 79 mov #0x20, r1 80 81test_ustandby: 82 tst #SUSP_SH_USTANDBY, r0 83 bt force_sleep 84 85 /* set mode to "u-standby mode" */ 86 bra do_sleep 87 mov #0x10, r1 88 89force_sleep: 90 91 /* set mode to "sleep mode" */ 92 mov #0x00, r1 93 94do_sleep: 95 /* setup and enter selected standby mode */ 96 bsr get_register 97 mov #SH_SLEEP_REG_STBCR, r0 98 mov.l r1, @r0 99again: 100 sleep 101 bra again 102 nop 103 104save_register: 105 add #SH_SLEEP_BASE_ADDR, r0 106 mov.l @(r0, r5), r1 107 add #-SH_SLEEP_BASE_ADDR, r0 108 mov.l @r1, r1 109 add #SH_SLEEP_BASE_DATA, r0 110 mov.l r1, @(r0, r5) 111 add #-SH_SLEEP_BASE_DATA, r0 112 rts 113 nop 114 115get_register: 116 add #SH_SLEEP_BASE_ADDR, r0 117 mov.l @(r0, r5), r0 118 rts 119 nop 120ENTRY(sh_mobile_sleep_enter_end) 121 122 .balign 4 123ENTRY(sh_mobile_sleep_resume_start) 124 125 /* figure out start address */ 126 bsr 0f 127 nop 1280: 129 sts pr, k1 130 mov.l 1f, k0 131 and k0, k1 132 133 /* store pointer to data area in VBR */ 134 ldc k1, vbr 135 136 /* setup sr with saved sr */ 137 mov.l @(SH_SLEEP_SR, k1), k0 138 ldc k0, sr 139 140 /* now: user register set! */ 141 stc vbr, r5 142 143 /* setup spc with return address to c code */ 144 mov.l @(SH_SLEEP_SPC, r5), r0 145 ldc r0, spc 146 147 /* restore vbr */ 148 mov.l @(SH_SLEEP_VBR, r5), r0 149 ldc r0, vbr 150 151 /* setup ssr with saved sr */ 152 mov.l @(SH_SLEEP_SR, r5), r0 153 ldc r0, ssr 154 155 /* restore sleep mode register */ 156 bsr restore_register 157 mov #SH_SLEEP_REG_STBCR, r0 158 159 /* call self-refresh resume code if needed */ 160 mov.l @(SH_SLEEP_MODE, r5), r0 161 tst #SUSP_SH_SF, r0 162 bt skip_restore_sf 163 164 mov.l @(SH_SLEEP_SF_POST, r5), r0 165 jsr @r0 166 nop 167 168skip_restore_sf: 169 rte 170 nop 171 172restore_register: 173 add #SH_SLEEP_BASE_DATA, r0 174 mov.l @(r0, r5), r1 175 add #-SH_SLEEP_BASE_DATA, r0 176 add #SH_SLEEP_BASE_ADDR, r0 177 mov.l @(r0, r5), r0 178 mov.l r1, @r0 179 rts 180 nop 181 182 .balign 4 1831: .long ~0x7ff 184ENTRY(sh_mobile_sleep_resume_end) 185