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