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