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 sp */ 52 mov.l r15, @(SH_SLEEP_SP, r5) 53 54 /* save stbcr */ 55 bsr save_register 56 mov #SH_SLEEP_REG_STBCR, r0 57 58 /* save mmu and cache context if needed */ 59 mov.l @(SH_SLEEP_MODE, r5), r0 60 tst #SUSP_SH_MMU, r0 61 bt skip_mmu_save_disable 62 63 /* save mmu state */ 64 bsr save_register 65 mov #SH_SLEEP_REG_PTEH, r0 66 67 bsr save_register 68 mov #SH_SLEEP_REG_PTEL, r0 69 70 bsr save_register 71 mov #SH_SLEEP_REG_TTB, r0 72 73 bsr save_register 74 mov #SH_SLEEP_REG_TEA, r0 75 76 bsr save_register 77 mov #SH_SLEEP_REG_MMUCR, r0 78 79 bsr save_register 80 mov #SH_SLEEP_REG_PTEA, r0 81 82 bsr save_register 83 mov #SH_SLEEP_REG_PASCR, r0 84 85 bsr save_register 86 mov #SH_SLEEP_REG_IRMCR, r0 87 88 /* invalidate TLBs and disable the MMU */ 89 bsr get_register 90 mov #SH_SLEEP_REG_MMUCR, r0 91 mov #4, r1 92 mov.l r1, @r0 93 icbi @r0 94 95 /* save cache registers and disable caches */ 96 bsr save_register 97 mov #SH_SLEEP_REG_CCR, r0 98 99 bsr save_register 100 mov #SH_SLEEP_REG_RAMCR, r0 101 102 bsr get_register 103 mov #SH_SLEEP_REG_CCR, r0 104 mov #0, r1 105 mov.l r1, @r0 106 icbi @r0 107 108skip_mmu_save_disable: 109 /* call self-refresh entering code if needed */ 110 mov.l @(SH_SLEEP_MODE, r5), r0 111 tst #SUSP_SH_SF, r0 112 bt skip_set_sf 113 114 mov.l @(SH_SLEEP_SF_PRE, r5), r0 115 jsr @r0 116 nop 117 118skip_set_sf: 119 mov.l @(SH_SLEEP_MODE, r5), r0 120 tst #SUSP_SH_STANDBY, r0 121 bt test_rstandby 122 123 /* set mode to "software standby mode" */ 124 bra do_sleep 125 mov #0x80, r1 126 127test_rstandby: 128 tst #SUSP_SH_RSTANDBY, r0 129 bt test_ustandby 130 131 /* setup BAR register */ 132 bsr get_register 133 mov #SH_SLEEP_REG_BAR, r0 134 mov.l @(SH_SLEEP_RESUME, r5), r1 135 mov.l r1, @r0 136 137 /* set mode to "r-standby mode" */ 138 bra do_sleep 139 mov #0x20, r1 140 141test_ustandby: 142 tst #SUSP_SH_USTANDBY, r0 143 bt force_sleep 144 145 /* set mode to "u-standby mode" */ 146 bra do_sleep 147 mov #0x10, r1 148 149force_sleep: 150 151 /* set mode to "sleep mode" */ 152 mov #0x00, r1 153 154do_sleep: 155 /* setup and enter selected standby mode */ 156 bsr get_register 157 mov #SH_SLEEP_REG_STBCR, r0 158 mov.l r1, @r0 159again: 160 sleep 161 bra again 162 nop 163 164save_register: 165 add #SH_SLEEP_BASE_ADDR, r0 166 mov.l @(r0, r5), r1 167 add #-SH_SLEEP_BASE_ADDR, r0 168 mov.l @r1, r1 169 add #SH_SLEEP_BASE_DATA, r0 170 mov.l r1, @(r0, r5) 171 add #-SH_SLEEP_BASE_DATA, r0 172 rts 173 nop 174 175get_register: 176 add #SH_SLEEP_BASE_ADDR, r0 177 mov.l @(r0, r5), r0 178 rts 179 nop 180ENTRY(sh_mobile_sleep_enter_end) 181 182 .balign 4 183ENTRY(sh_mobile_sleep_resume_start) 184 185 /* figure out start address */ 186 bsr 0f 187 nop 1880: 189 sts pr, k1 190 mov.l 1f, k0 191 and k0, k1 192 193 /* store pointer to data area in VBR */ 194 ldc k1, vbr 195 196 /* setup sr with saved sr */ 197 mov.l @(SH_SLEEP_SR, k1), k0 198 ldc k0, sr 199 200 /* now: user register set! */ 201 stc vbr, r5 202 203 /* setup spc with return address to c code */ 204 mov.l @(SH_SLEEP_SPC, r5), r0 205 ldc r0, spc 206 207 /* restore vbr */ 208 mov.l @(SH_SLEEP_VBR, r5), r0 209 ldc r0, vbr 210 211 /* setup ssr with saved sr */ 212 mov.l @(SH_SLEEP_SR, r5), r0 213 ldc r0, ssr 214 215 /* restore sp */ 216 mov.l @(SH_SLEEP_SP, r5), r15 217 218 /* restore sleep mode register */ 219 bsr restore_register 220 mov #SH_SLEEP_REG_STBCR, r0 221 222 /* call self-refresh resume code if needed */ 223 mov.l @(SH_SLEEP_MODE, r5), r0 224 tst #SUSP_SH_SF, r0 225 bt skip_restore_sf 226 227 mov.l @(SH_SLEEP_SF_POST, r5), r0 228 jsr @r0 229 nop 230 231skip_restore_sf: 232 /* restore mmu and cache state if needed */ 233 mov.l @(SH_SLEEP_MODE, r5), r0 234 tst #SUSP_SH_MMU, r0 235 bt skip_restore_mmu 236 237 /* restore mmu state */ 238 bsr restore_register 239 mov #SH_SLEEP_REG_PTEH, r0 240 241 bsr restore_register 242 mov #SH_SLEEP_REG_PTEL, r0 243 244 bsr restore_register 245 mov #SH_SLEEP_REG_TTB, r0 246 247 bsr restore_register 248 mov #SH_SLEEP_REG_TEA, r0 249 250 bsr restore_register 251 mov #SH_SLEEP_REG_PTEA, r0 252 253 bsr restore_register 254 mov #SH_SLEEP_REG_PASCR, r0 255 256 bsr restore_register 257 mov #SH_SLEEP_REG_IRMCR, r0 258 259 bsr restore_register 260 mov #SH_SLEEP_REG_MMUCR, r0 261 icbi @r0 262 263 /* restore cache settings */ 264 bsr restore_register 265 mov #SH_SLEEP_REG_RAMCR, r0 266 icbi @r0 267 268 bsr restore_register 269 mov #SH_SLEEP_REG_CCR, r0 270 icbi @r0 271 272skip_restore_mmu: 273 rte 274 nop 275 276restore_register: 277 add #SH_SLEEP_BASE_DATA, r0 278 mov.l @(r0, r5), r1 279 add #-SH_SLEEP_BASE_DATA, r0 280 add #SH_SLEEP_BASE_ADDR, r0 281 mov.l @(r0, r5), r0 282 mov.l r1, @r0 283 rts 284 nop 285 286 .balign 4 2871: .long ~0x7ff 288ENTRY(sh_mobile_sleep_resume_end) 289