xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv8/sleep.S (revision 41372211f3a5743369426780c3496834ab22daca)
1d007e796SJoseph Chen/*
2d007e796SJoseph Chen * (C) Copyright 2017 Rockchip Electronics Co., Ltd.
3d007e796SJoseph Chen *
4d007e796SJoseph Chen * SPDX-License-Identifier:	GPL-2.0+
5d007e796SJoseph Chen */
6d007e796SJoseph Chen
7d007e796SJoseph Chen#include <asm/macro.h>
8d007e796SJoseph Chen#include <asm-offsets.h>
9d007e796SJoseph Chen#include <asm/psci.h>
10d007e796SJoseph Chen#include <config.h>
11d007e796SJoseph Chen#include <linux/linkage.h>
12d007e796SJoseph Chen
13d007e796SJoseph Chen	.globl cpu_suspend
14d007e796SJoseph Chen	.globl cpu_do_suspend
15d007e796SJoseph Chen	.globl cpu_suspend_save
16d007e796SJoseph Chen	.globl cpu_resume
17d007e796SJoseph Chen	.globl cpu_do_resume
18d007e796SJoseph Chen
19d007e796SJoseph Chen/*
20d007e796SJoseph Chen * int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
21d007e796SJoseph Chen * @arg will be passed to fn as argument
22d007e796SJoseph Chen * return value: 0 - cpu resumed from suspended state.
23d007e796SJoseph Chen *		 -1 - cpu not suspended.
24d007e796SJoseph Chen */
25d007e796SJoseph ChenENTRY(cpu_suspend)
26d007e796SJoseph Chen	/*
27d007e796SJoseph Chen	 * Save x8~x30(lr is x30, sp is x29), total (23 + 1 reserved)*8=192
28d007e796SJoseph Chen	 */
29d007e796SJoseph Chen	stp	x29, lr, [sp, #-192]!
30d007e796SJoseph Chen	/* Reserve 8-byte after x8, just for offset with 16-byte aligned */
31d007e796SJoseph Chen	str	x8, [sp, #16]
32d007e796SJoseph Chen	stp	x9, x10, [sp, #32]
33d007e796SJoseph Chen	stp	x11, x12, [sp, #48]
34d007e796SJoseph Chen	stp	x13, x14, [sp, #64]
35d007e796SJoseph Chen	stp	x15, x16, [sp, #80]
36d007e796SJoseph Chen	stp	x17, x18, [sp, #96]
37d007e796SJoseph Chen	stp	x19, x20, [sp,#112]
38d007e796SJoseph Chen	stp	x21, x22, [sp,#128]
39d007e796SJoseph Chen	stp	x23, x24, [sp,#144]
40d007e796SJoseph Chen	stp	x25, x26, [sp,#160]
41d007e796SJoseph Chen	stp	x27, x28, [sp,#176]
42d007e796SJoseph Chen
43d007e796SJoseph Chen	mov	x19, sp
44d007e796SJoseph Chen	mov	x20, x0
45d007e796SJoseph Chen	mov	x21, x1
46d007e796SJoseph Chen
47d007e796SJoseph Chen	/* Save arch specific suspend fn and arg to stack */
48d007e796SJoseph Chen	sub	sp, sp, #PM_CTX_SIZE
49d007e796SJoseph Chen	stp	x0, x1, [sp, #-16]!
50d007e796SJoseph Chen
51d007e796SJoseph Chen	/* x18 is gd, save it to _suspend_gd !! */
52d007e796SJoseph Chen	adr	x0, _suspend_gd
53d007e796SJoseph Chen	str	x18, [x0]
54d007e796SJoseph Chen
55d007e796SJoseph Chen	/* x0: pm_ctx;	x1: sp where restore x8~x30 from */
56d007e796SJoseph Chen	add	x0, sp, #16
57d007e796SJoseph Chen	mov	x1, x19
58d007e796SJoseph Chen	bl	cpu_suspend_save
59d007e796SJoseph Chen
60d007e796SJoseph Chen	adr	lr, aborted
61d007e796SJoseph Chen	/* Jump to arch specific suspend */
62d007e796SJoseph Chen	mov	x0, x20
63d007e796SJoseph Chen	br	x21
64d007e796SJoseph Chen
65d007e796SJoseph Chen	/* Should never reach here, otherwise failed */
66d007e796SJoseph Chenaborted:
67d007e796SJoseph Chen	/* cpu not suspended */
68d007e796SJoseph Chen	add	sp, sp, #(16 + PM_CTX_SIZE)
69d007e796SJoseph Chen	/* Return -1 to the caller */
70d007e796SJoseph Chen	mov	x0, #(-1)
71d007e796SJoseph Chen
72d007e796SJoseph Chensuspend_return:
73d007e796SJoseph Chen	ldr	x8, [sp, #16]
74d007e796SJoseph Chen	ldp	x9, x10, [sp, #32]
75d007e796SJoseph Chen	ldp	x11, x12, [sp, #48]
76d007e796SJoseph Chen	ldp	x13, x14, [sp, #64]
77d007e796SJoseph Chen	ldp	x15, x16, [sp, #80]
78d007e796SJoseph Chen	ldp	x17, x18, [sp, #96]
79d007e796SJoseph Chen	ldp	x19, x20, [sp,#112]
80d007e796SJoseph Chen	ldp	x21, x22, [sp,#128]
81d007e796SJoseph Chen	ldp	x23, x24, [sp,#144]
82d007e796SJoseph Chen	ldp	x25, x26, [sp,#160]
83d007e796SJoseph Chen	ldp	x27, x28, [sp,#176]
84d007e796SJoseph Chen	ldp	x29, lr, [sp], #192
85d007e796SJoseph Chen	ret
86d007e796SJoseph ChenENDPROC(cpu_suspend)
87d007e796SJoseph Chen
88d007e796SJoseph ChenENTRY(cpu_do_suspend)
89d007e796SJoseph Chen	/*
90d007e796SJoseph Chen	 * Save temporary x2~x12, total: 11*8=88, maybe you need not so many
91d007e796SJoseph Chen	 * registers now, but I save them for future extendion.
92d007e796SJoseph Chen	 */
93d007e796SJoseph Chen	stp	x2,  x3, [sp, #-88]!
94d007e796SJoseph Chen	stp	x4,  x5, [sp, #16]
95d007e796SJoseph Chen	stp	x6,  x7, [sp, #32]
96d007e796SJoseph Chen	stp	x8,  x9, [sp, #48]
97d007e796SJoseph Chen	stp	x10, x11, [sp,#64]
98d007e796SJoseph Chen	str	x12, [sp, #80]
99d007e796SJoseph Chen
100d007e796SJoseph Chen	/*
101d007e796SJoseph Chen	 * Save core registers.
102d007e796SJoseph Chen	 *
103d007e796SJoseph Chen	 * Note: If you want to add/sub the register here,
104d007e796SJoseph Chen	 *	 remember update suspend_regs[] of struct pm_ctx.
105d007e796SJoseph Chen	 */
106d007e796SJoseph Chen	mrs	x2, vbar_el2
107d007e796SJoseph Chen	mrs	x3, cptr_el2
108d007e796SJoseph Chen	mrs	x4, ttbr0_el2
109d007e796SJoseph Chen	mrs	x5, tcr_el2
110d007e796SJoseph Chen	mrs	x6, mair_el2
111d007e796SJoseph Chen	mrs	x7, cntvoff_el2
112d007e796SJoseph Chen	mrs	x8, sctlr_el2
113d007e796SJoseph Chen	mrs	x9, hcr_el2
114d007e796SJoseph Chen	mrs	x10, daif
115d007e796SJoseph Chen
116d007e796SJoseph Chen	stp	x2,  x3, [x0, #0]
117d007e796SJoseph Chen	stp	x4,  x5, [x0, #16]
118d007e796SJoseph Chen	stp	x6,  x7, [x0, #32]
119d007e796SJoseph Chen	stp	x8,  x9, [x0, #48]
120d007e796SJoseph Chen	str	x10, [x0, #64]
121d007e796SJoseph Chen
122d007e796SJoseph Chen	/* Restore temporary x2~x12 */
123d007e796SJoseph Chen	ldp	x4,  x5, [sp, #16]
124d007e796SJoseph Chen	ldp	x6,  x7, [sp, #32]
125d007e796SJoseph Chen	ldp	x8,  x9, [sp, #48]
126d007e796SJoseph Chen	ldp	x10, x11, [sp,#64]
127d007e796SJoseph Chen	ldr	x12, [sp, #80]
128d007e796SJoseph Chen	ldp	x2,  x3, [sp], #88
129d007e796SJoseph Chen	ret
130d007e796SJoseph ChenENDPROC(cpu_do_suspend)
131d007e796SJoseph Chen
132d007e796SJoseph ChenENTRY(cpu_resume)
133d007e796SJoseph Chen	/* Disable interrupt */
134d007e796SJoseph Chen	msr       daifset, #0x03
135d007e796SJoseph Chen
136d007e796SJoseph Chen	/* Load gd !! */
137d007e796SJoseph Chen	adr x1, _suspend_gd
138d007e796SJoseph Chen	ldr x2, [x1]
139d007e796SJoseph Chen
140d007e796SJoseph Chen	/* Get pm_ctx */
141d007e796SJoseph Chen	add x2, x2, #PM_CTX_PHYS
142d007e796SJoseph Chen	ldr x0, [x2]
143d007e796SJoseph Chen
144d007e796SJoseph Chen	/* Need x0=x0-16, because cpu_do_resume needs it */
145d007e796SJoseph Chen	ldp	x1, lr, [x0], #16
146d007e796SJoseph Chen	mov	sp, x1
147d007e796SJoseph Chen	ret
148d007e796SJoseph ChenENDPROC(cpu_resume)
149d007e796SJoseph Chen
150d007e796SJoseph Chen/*
151d007e796SJoseph Chen * void sm_do_cpu_do_resume(paddr suspend_regs) __noreturn;
152d007e796SJoseph Chen * Restore the registers stored when cpu_do_suspend
153d007e796SJoseph Chen * x0 points to the physical base address of the suspend_regs
154d007e796SJoseph Chen * field of struct pm_ctx.
155d007e796SJoseph Chen */
156d007e796SJoseph ChenENTRY(cpu_do_resume)
157d007e796SJoseph Chen	/*
158d007e796SJoseph Chen	 * Invalidate local tlb entries before turning on MMU !!!
159d007e796SJoseph Chen	 */
160d007e796SJoseph Chen	tlbi	alle2
161d007e796SJoseph Chen	dsb	sy
162d007e796SJoseph Chen	isb
163d007e796SJoseph Chen
164d007e796SJoseph Chen	ldp	x2, x3, [x0]
165d007e796SJoseph Chen	ldp	x4, x5, [x0, #16]
166d007e796SJoseph Chen	ldp	x6, x7, [x0, #32]
167d007e796SJoseph Chen	ldp	x8, x9, [x0, #48]
168d007e796SJoseph Chen	ldp	x10, x11, [x0, #64]
169d007e796SJoseph Chen	ldr	x12, [x0, #80]
170d007e796SJoseph Chen
171d007e796SJoseph Chen	/* Restore core register */
172d007e796SJoseph Chen	msr	vbar_el2, x2
173d007e796SJoseph Chen	msr	cptr_el2, x3
174d007e796SJoseph Chen	msr	ttbr0_el2, x4
175d007e796SJoseph Chen	msr	tcr_el2, x5
176d007e796SJoseph Chen	msr	mair_el2, x6
177d007e796SJoseph Chen	msr	cntvoff_el2, x7
178d007e796SJoseph Chen	msr	hcr_el2, x9
179d007e796SJoseph Chen
180d007e796SJoseph Chen	/* Enable MMU here */
181d007e796SJoseph Chen	msr	sctlr_el2, x8
182d007e796SJoseph Chen	dsb	sy
183d007e796SJoseph Chen	isb
184d007e796SJoseph Chen
185d007e796SJoseph Chen	/* resume interrupt */
186d007e796SJoseph Chen	msr	daif, x10
187d007e796SJoseph Chen
188d007e796SJoseph Chen	mov	x0, #0
189d007e796SJoseph Chen	b	suspend_return
190d007e796SJoseph ChenENDPROC(cpu_do_resume)
191d007e796SJoseph Chen
1921cd698aeSJoseph Chen.align 3
193d007e796SJoseph Chen_suspend_gd:
194d007e796SJoseph Chen	.long	0x0
195*41372211SJoseph Chen
196