aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/hibernate_asm.S
blob: 95387894937ced7c69ecf27db5885d59ee2a9a30 (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
/*
 * Hibernation support specific for ARM
 *
 * Copyright (C) 2010 Nokia Corporation
 * Copyright (C) 2010 Texas Instruments, Inc.
 * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
 *
 * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
 *
 * License terms: GNU General Public License (GPL) version 2
 */

#include <linux/linkage.h>
	.text
ENTRY(swsusp_arch_suspend)
	/*
	 * Save current program status register
	 */
	ldr     r3, .Lsaved_cpsr
	mrs     r0, cpsr
	str     r0, [r3]

	/*
	 * Change to system(user) mode
	 */
	mov     r1, r0
	orr     r1, r1, #0x1f
	msr     cpsr_c, r1

	/*
	 * Save User context
	 */
	ldr     r3, .Lsaved_context_r0
	stmia   r3, {r0-r14}

	/*
	 * Go back to original SVC mode
	 */
	msr     cpsr_c, r0

	/*
	 * Save SVC context
	 */
	ldr     r3, .Lsaved_context_r13_svc
	stmia   r3, {r13-r14}
	ldr     r3, .Lsaved_spsr_svc
	mrs     r1, spsr
	str     r1, [r3]

	bl      swsusp_save

	/*
	 * Restore return address
	 */
	ldr     r3, .Lsaved_context_r14_svc
	ldr     lr, [r3]
	mov     pc, lr
ENDPROC(swsusp_arch_suspend)

ENTRY(swsusp_arch_resume)
	/*
	 * Restore_pblist is the starting point for loaded pages
	 */
	ldr     r0, .Lrestore_pblist
	ldr     r6, [r0]

.Lcopy_loop:
	ldr     r4, [r6]     /* src IOW present address */
	ldr     r5, [r6, #4] /* dst IOW original address*/

	/* No. of entries in one page, where each entry is 4 bytes */
	mov     r9, #1024

.Lcopy_one_page:
	/*
	 * This loop could be optimized by using stm and ldm.
	 */
	ldr     r8, [r4], #4
	str     r8, [r5], #4
	subs    r9, r9, #1
	bne     .Lcopy_one_page

	/*
	 * The last field of struct pbe is a pointer to the next pbe structure
	 */
	ldr     r6, [r6, #8]
	cmp     r6, #0
	bne     .Lcopy_loop

	/*
	 * Restore SVC context
	 */
	ldr     r3, .Lsaved_context_r13_svc
	ldmia   r3, {r13-r14}
	ldr     r3, .Lsaved_spsr_svc
	ldr     r1, [r3]
	msr     spsr_cxsf, r1

	mrs     r0, cpsr	/* Save current mode into r0 */

	/*
	 * Change to system(user) mode
	 */
	mov     r1, r0
	orr     r1, r1, #0x1f
	msr     cpsr_c, r1

	/*
	 * Restore User context
	 */
	ldr     r3, .Lsaved_context_r0
	ldmia   r3, {r0-r14}
	ldr     r3, .Lsaved_cpsr
	ldr     r1, [r3]
	msr     cpsr_cxsf, r1

	msr     cpsr_c, r0	/* Restore original mode from r0 */

	/*
	 * Flush TLB (Invalidate unified TLB unlocked entries)
	 */
	mov     r1, #0
	mcr     p15, 0, r1, c8, c7, 0

	/* Set the return value */
	mov	r0, #0

	/* Restore return address */
	ldr     r3, .Lsaved_context_r14_svc
	ldr     lr, [r3]
	mov     pc, lr
ENDPROC(swsusp_arch_resume)
	.align	4
.Lsaved_context_r0:		.long	saved_context_r0
.Lsaved_cpsr:			.long	saved_cpsr
.Lsaved_context_r13_svc: 	.long	saved_context_r13_svc
.Lsaved_context_r14_svc:	.long	saved_context_r14_svc
.Lsaved_spsr_svc:		.long	saved_spsr_svc
.Lrestore_pblist:		.long	restore_pblist