linux/arch/sh/kernel/cpu/shmobile/sleep.S
<<
>>
Prefs
   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