1/* SPDX-License-Identifier: GPL-2.0 2 * 3 * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S 4 * 5 * Sleep mode and Standby modes support for SuperH Mobile 6 * 7 * Copyright (C) 2009 Magnus Damm 8 */ 9 10#include <linux/sys.h> 11#include <linux/errno.h> 12#include <linux/linkage.h> 13#include <asm/asm-offsets.h> 14#include <asm/suspend.h> 15 16/* 17 * Kernel mode register usage, see entry.S: 18 * k0 scratch 19 * k1 scratch 20 */ 21#define k0 r0 22#define k1 r1 23 24/* manage self-refresh and enter standby mode. must be self-contained. 25 * this code will be copied to on-chip memory and executed from there. 26 */ 27 .balign 4 28ENTRY(sh_mobile_sleep_enter_start) 29 30 /* save mode flags */ 31 mov.l r4, @(SH_SLEEP_MODE, r5) 32 33 /* save original vbr */ 34 stc vbr, r0 35 mov.l r0, @(SH_SLEEP_VBR, r5) 36 37 /* point vbr to our on-chip memory page */ 38 ldc r5, vbr 39 40 /* save return address */ 41 sts pr, r0 42 mov.l r0, @(SH_SLEEP_SPC, r5) 43 44 /* save sr */ 45 stc sr, r0 46 mov.l r0, @(SH_SLEEP_SR, r5) 47 48 /* save general purpose registers to stack if needed */ 49 mov.l @(SH_SLEEP_MODE, r5), r0 50 tst #SUSP_SH_REGS, r0 51 bt skip_regs_save 52 53 sts.l pr, @-r15 54 mov.l r14, @-r15 55 mov.l r13, @-r15 56 mov.l r12, @-r15 57 mov.l r11, @-r15 58 mov.l r10, @-r15 59 mov.l r9, @-r15 60 mov.l r8, @-r15 61 62 /* make sure bank0 is selected, save low registers */ 63 mov.l rb_bit, r9 64 not r9, r9 65 bsr set_sr 66 mov #0, r10 67 68 bsr save_low_regs 69 nop 70 71 /* switch to bank 1, save low registers */ 72 mov.l rb_bit, r10 73 bsr set_sr 74 mov #-1, r9 75 76 bsr save_low_regs 77 nop 78 79 /* switch back to bank 0 */ 80 mov.l rb_bit, r9 81 not r9, r9 82 bsr set_sr 83 mov #0, r10 84 85skip_regs_save: 86 87 /* save sp, also set to internal ram */ 88 mov.l r15, @(SH_SLEEP_SP, r5) 89 mov r5, r15 90 91 /* save stbcr */ 92 bsr save_register 93 mov #SH_SLEEP_REG_STBCR, r0 94 95 /* save mmu and cache context if needed */ 96 mov.l @(SH_SLEEP_MODE, r5), r0 97 tst #SUSP_SH_MMU, r0 98 bt skip_mmu_save_disable 99 100 /* save mmu state */ 101 bsr save_register 102 mov #SH_SLEEP_REG_PTEH, r0 103 104 bsr save_register 105 mov #SH_SLEEP_REG_PTEL, r0 106 107 bsr save_register 108 mov #SH_SLEEP_REG_TTB, r0 109 110 bsr save_register 111 mov #SH_SLEEP_REG_TEA, r0 112 113 bsr save_register 114 mov #SH_SLEEP_REG_MMUCR, r0 115 116 bsr save_register 117 mov #SH_SLEEP_REG_PTEA, r0 118 119 bsr save_register 120 mov #SH_SLEEP_REG_PASCR, r0 121 122 bsr save_register 123 mov #SH_SLEEP_REG_IRMCR, r0 124 125 /* invalidate TLBs and disable the MMU */ 126 bsr get_register 127 mov #SH_SLEEP_REG_MMUCR, r0 128 mov #4, r1 129 mov.l r1, @r0 130 icbi @r0 131 132 /* save cache registers and disable caches */ 133 bsr save_register 134 mov #SH_SLEEP_REG_CCR, r0 135 136 bsr save_register 137 mov #SH_SLEEP_REG_RAMCR, r0 138 139 bsr get_register 140 mov #SH_SLEEP_REG_CCR, r0 141 mov #0, r1 142 mov.l r1, @r0 143 icbi @r0 144 145skip_mmu_save_disable: 146 /* call self-refresh entering code if needed */ 147 mov.l @(SH_SLEEP_MODE, r5), r0 148 tst #SUSP_SH_SF, r0 149 bt skip_set_sf 150 151 mov.l @(SH_SLEEP_SF_PRE, r5), r0 152 jsr @r0 153 nop 154 155skip_set_sf: 156 mov.l @(SH_SLEEP_MODE, r5), r0 157 tst #SUSP_SH_STANDBY, r0 158 bt test_rstandby 159 160 /* set mode to "software standby mode" */ 161 bra do_sleep 162 mov #0x80, r1 163 164test_rstandby: 165 tst #SUSP_SH_RSTANDBY, r0 166 bt test_ustandby 167 168 /* setup BAR register */ 169 bsr get_register 170 mov #SH_SLEEP_REG_BAR, r0 171 mov.l @(SH_SLEEP_RESUME, r5), r1 172 mov.l r1, @r0 173 174 /* set mode to "r-standby mode" */ 175 bra do_sleep 176 mov #0x20, r1 177 178test_ustandby: 179 tst #SUSP_SH_USTANDBY, r0 180 bt force_sleep 181 182 /* set mode to "u-standby mode" */ 183 bra do_sleep 184 mov #0x10, r1 185 186force_sleep: 187 188 /* set mode to "sleep mode" */ 189 mov #0x00, r1 190 191do_sleep: 192 /* setup and enter selected standby mode */ 193 bsr get_register 194 mov #SH_SLEEP_REG_STBCR, r0 195 mov.l r1, @r0 196again: 197 sleep 198 bra again 199 nop 200 201save_register: 202 add #SH_SLEEP_BASE_ADDR, r0 203 mov.l @(r0, r5), r1 204 add #-SH_SLEEP_BASE_ADDR, r0 205 mov.l @r1, r1 206 add #SH_SLEEP_BASE_DATA, r0 207 mov.l r1, @(r0, r5) 208 add #-SH_SLEEP_BASE_DATA, r0 209 rts 210 nop 211 212get_register: 213 add #SH_SLEEP_BASE_ADDR, r0 214 mov.l @(r0, r5), r0 215 rts 216 nop 217 218set_sr: 219 stc sr, r8 220 and r9, r8 221 or r10, r8 222 ldc r8, sr 223 rts 224 nop 225 226save_low_regs: 227 mov.l r7, @-r15 228 mov.l r6, @-r15 229 mov.l r5, @-r15 230 mov.l r4, @-r15 231 mov.l r3, @-r15 232 mov.l r2, @-r15 233 mov.l r1, @-r15 234 rts 235 mov.l r0, @-r15 236 237 .balign 4 238rb_bit: .long 0x20000000 ! RB=1 239 240ENTRY(sh_mobile_sleep_enter_end) 241 242 .balign 4 243ENTRY(sh_mobile_sleep_resume_start) 244 245 /* figure out start address */ 246 bsr 0f 247 nop 2480: 249 sts pr, k1 250 mov.l 1f, k0 251 and k0, k1 252 253 /* store pointer to data area in VBR */ 254 ldc k1, vbr 255 256 /* setup sr with saved sr */ 257 mov.l @(SH_SLEEP_SR, k1), k0 258 ldc k0, sr 259 260 /* now: user register set! */ 261 stc vbr, r5 262 263 /* setup spc with return address to c code */ 264 mov.l @(SH_SLEEP_SPC, r5), r0 265 ldc r0, spc 266 267 /* restore vbr */ 268 mov.l @(SH_SLEEP_VBR, r5), r0 269 ldc r0, vbr 270 271 /* setup ssr with saved sr */ 272 mov.l @(SH_SLEEP_SR, r5), r0 273 ldc r0, ssr 274 275 /* restore sp */ 276 mov.l @(SH_SLEEP_SP, r5), r15 277 278 /* restore sleep mode register */ 279 bsr restore_register 280 mov #SH_SLEEP_REG_STBCR, r0 281 282 /* call self-refresh resume code if needed */ 283 mov.l @(SH_SLEEP_MODE, r5), r0 284 tst #SUSP_SH_SF, r0 285 bt skip_restore_sf 286 287 mov.l @(SH_SLEEP_SF_POST, r5), r0 288 jsr @r0 289 nop 290 291skip_restore_sf: 292 /* restore mmu and cache state if needed */ 293 mov.l @(SH_SLEEP_MODE, r5), r0 294 tst #SUSP_SH_MMU, r0 295 bt skip_restore_mmu 296 297 /* restore mmu state */ 298 bsr restore_register 299 mov #SH_SLEEP_REG_PTEH, r0 300 301 bsr restore_register 302 mov #SH_SLEEP_REG_PTEL, r0 303 304 bsr restore_register 305 mov #SH_SLEEP_REG_TTB, r0 306 307 bsr restore_register 308 mov #SH_SLEEP_REG_TEA, r0 309 310 bsr restore_register 311 mov #SH_SLEEP_REG_PTEA, r0 312 313 bsr restore_register 314 mov #SH_SLEEP_REG_PASCR, r0 315 316 bsr restore_register 317 mov #SH_SLEEP_REG_IRMCR, r0 318 319 bsr restore_register 320 mov #SH_SLEEP_REG_MMUCR, r0 321 icbi @r0 322 323 /* restore cache settings */ 324 bsr restore_register 325 mov #SH_SLEEP_REG_RAMCR, r0 326 icbi @r0 327 328 bsr restore_register 329 mov #SH_SLEEP_REG_CCR, r0 330 icbi @r0 331 332skip_restore_mmu: 333 334 /* restore general purpose registers if needed */ 335 mov.l @(SH_SLEEP_MODE, r5), r0 336 tst #SUSP_SH_REGS, r0 337 bt skip_restore_regs 338 339 /* switch to bank 1, restore low registers */ 340 mov.l _rb_bit, r10 341 bsr _set_sr 342 mov #-1, r9 343 344 bsr restore_low_regs 345 nop 346 347 /* switch to bank0, restore low registers */ 348 mov.l _rb_bit, r9 349 not r9, r9 350 bsr _set_sr 351 mov #0, r10 352 353 bsr restore_low_regs 354 nop 355 356 /* restore the rest of the registers */ 357 mov.l @r15+, r8 358 mov.l @r15+, r9 359 mov.l @r15+, r10 360 mov.l @r15+, r11 361 mov.l @r15+, r12 362 mov.l @r15+, r13 363 mov.l @r15+, r14 364 lds.l @r15+, pr 365 366skip_restore_regs: 367 rte 368 nop 369 370restore_register: 371 add #SH_SLEEP_BASE_DATA, r0 372 mov.l @(r0, r5), r1 373 add #-SH_SLEEP_BASE_DATA, r0 374 add #SH_SLEEP_BASE_ADDR, r0 375 mov.l @(r0, r5), r0 376 mov.l r1, @r0 377 rts 378 nop 379 380_set_sr: 381 stc sr, r8 382 and r9, r8 383 or r10, r8 384 ldc r8, sr 385 rts 386 nop 387 388restore_low_regs: 389 mov.l @r15+, r0 390 mov.l @r15+, r1 391 mov.l @r15+, r2 392 mov.l @r15+, r3 393 mov.l @r15+, r4 394 mov.l @r15+, r5 395 mov.l @r15+, r6 396 rts 397 mov.l @r15+, r7 398 399 .balign 4 400_rb_bit: .long 0x20000000 ! RB=1 4011: .long ~0x7ff 402ENTRY(sh_mobile_sleep_resume_end) 403