root/arch/sh/kernel/cpu/sh3/swsusp.S
/* SPDX-License-Identifier: GPL-2.0
 *
 * arch/sh/kernel/cpu/sh3/swsusp.S
 *
 * Copyright (C) 2009 Magnus Damm
 */
#include <linux/sys.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/page.h>

#define k0      r0
#define k1      r1
#define k2      r2
#define k3      r3
#define k4      r4

! swsusp_arch_resume()
! - copy restore_pblist pages
! - restore registers from swsusp_arch_regs_cpu0

ENTRY(swsusp_arch_resume)
        mov.l   1f, r15
        mov.l   2f, r4
        mov.l   @r4, r4

swsusp_copy_loop:
        mov     r4, r0
        cmp/eq  #0, r0
        bt      swsusp_restore_regs

        mov.l   @(PBE_ADDRESS, r4), r2
        mov.l   @(PBE_ORIG_ADDRESS, r4), r5

        mov     #(PAGE_SIZE >> 10), r3
        shll8   r3
        shlr2   r3 /* PAGE_SIZE / 16 */
swsusp_copy_page:
        dt      r3
        mov.l   @r2+,r1   /*  16n+0 */
        mov.l   r1,@r5
        add     #4,r5
        mov.l   @r2+,r1   /*  16n+4 */
        mov.l   r1,@r5
        add     #4,r5
        mov.l   @r2+,r1   /*  16n+8 */
        mov.l   r1,@r5
        add     #4,r5
        mov.l   @r2+,r1   /*  16n+12 */
        mov.l   r1,@r5
        bf/s    swsusp_copy_page
         add    #4,r5

        bra     swsusp_copy_loop
         mov.l  @(PBE_NEXT, r4), r4

swsusp_restore_regs:
        ! BL=0: R7->R0 is bank0
        mov.l   3f, r8
        mov.l   4f, r5
        jsr     @r5
         nop

        ! BL=1: R7->R0 is bank1
        lds     k2, pr
        ldc     k3, ssr

        mov.l   @r15+, r0
        mov.l   @r15+, r1
        mov.l   @r15+, r2
        mov.l   @r15+, r3
        mov.l   @r15+, r4
        mov.l   @r15+, r5
        mov.l   @r15+, r6
        mov.l   @r15+, r7

        rte
         nop
        ! BL=0: R7->R0 is bank0

        .align  2
1:      .long   swsusp_arch_regs_cpu0
2:      .long   restore_pblist
3:      .long   0x20000000 ! RB=1
4:      .long   restore_regs

! swsusp_arch_suspend()
! - prepare pc for resume, return from function without swsusp_save on resume
! - save registers in swsusp_arch_regs_cpu0
! - call swsusp_save write suspend image

ENTRY(swsusp_arch_suspend)
        sts     pr, r0          ! save pr in r0
        mov     r15, r2         ! save sp in r2
        mov     r8, r5          ! save r8 in r5
        stc     sr, r1
        ldc     r1, ssr         ! save sr in ssr
        mov.l   1f, r1
        ldc     r1, spc         ! setup pc value for resuming
        mov.l   5f, r15         ! use swsusp_arch_regs_cpu0 as stack
        mov.l   6f, r3
        add     r3, r15         ! save from top of structure

        ! BL=0: R7->R0 is bank0
        mov.l   2f, r3          ! get new SR value for bank1
        mov     #0, r4
        mov.l   7f, r1
        jsr     @r1             ! switch to bank1 and save bank1 r7->r0
         not    r4, r4

        ! BL=1: R7->R0 is bank1
        stc     r2_bank, k0     ! fetch old sp from r2_bank0
        mov.l   3f, k4          ! SR bits to clear in k4
        mov.l   8f, k1
        jsr     @k1             ! switch to bank0 and save all regs
         stc    r0_bank, k3     ! fetch old pr from r0_bank0

        ! BL=0: R7->R0 is bank0
        mov     r2, r15         ! restore old sp
        mov     r5, r8          ! restore old r8
        stc     ssr, r1
        ldc     r1, sr          ! restore old sr
        lds     r0, pr          ! restore old pr
        mov.l   4f, r0
        jmp     @r0
         nop

swsusp_call_save:
        mov     r2, r15         ! restore old sp
        mov     r5, r8          ! restore old r8
        lds     r0, pr          ! restore old pr
        rts
         mov    #0, r0

        .align  2
1:      .long   swsusp_call_save
2:      .long   0x20000000 ! RB=1
3:      .long   0xdfffffff ! RB=0
4:      .long   swsusp_save
5:      .long   swsusp_arch_regs_cpu0
6:      .long   SWSUSP_ARCH_REGS_SIZE
7:      .long   save_low_regs
8:      .long   save_regs