root/arch/sh/kernel/cpu/shmobile/sleep.S

/* [<][>][^][v][top][bottom][index][help] */
   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
  28 ENTRY(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 
  85 skip_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 
 145 skip_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 
 155 skip_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 
 164 test_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 
 178 test_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 
 186 force_sleep:
 187 
 188         /* set mode to "sleep mode" */
 189         mov     #0x00, r1
 190 
 191 do_sleep:
 192         /* setup and enter selected standby mode */
 193         bsr     get_register
 194          mov    #SH_SLEEP_REG_STBCR, r0
 195         mov.l   r1, @r0
 196 again:
 197         sleep
 198         bra     again
 199          nop
 200 
 201 save_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 
 212 get_register:
 213         add     #SH_SLEEP_BASE_ADDR, r0
 214         mov.l   @(r0, r5), r0
 215         rts
 216          nop
 217 
 218 set_sr:
 219         stc     sr, r8
 220         and     r9, r8
 221         or      r10, r8
 222         ldc     r8, sr
 223         rts
 224          nop
 225 
 226 save_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
 238 rb_bit: .long   0x20000000 ! RB=1
 239 
 240 ENTRY(sh_mobile_sleep_enter_end)
 241 
 242         .balign 4
 243 ENTRY(sh_mobile_sleep_resume_start)
 244 
 245         /* figure out start address */
 246         bsr     0f
 247          nop
 248 0:
 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 
 291 skip_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 
 332 skip_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 
 366 skip_restore_regs:
 367         rte
 368          nop
 369 
 370 restore_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 
 388 restore_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
 401 1:      .long   ~0x7ff
 402 ENTRY(sh_mobile_sleep_resume_end)

/* [<][>][^][v][top][bottom][index][help] */