summaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/sh3/swsusp.S
blob: dc111c4ccf219982821b307ea4e4b7cc24282b25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* 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