xref: /OK3568_Linux_fs/u-boot/arch/arm/cpu/armv8/psci.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/*
2*4882a593Smuzhiyun * Copyright 2016 Freescale Semiconductor, Inc.
3*4882a593Smuzhiyun * Author: Hongbo Zhang <hongbo.zhang@nxp.com>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun * This file implements LS102X platform PSCI SYSTEM-SUSPEND function
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun#include <config.h>
10*4882a593Smuzhiyun#include <linux/linkage.h>
11*4882a593Smuzhiyun#include <asm/psci.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun/* Default PSCI function, return -1, Not Implemented */
14*4882a593Smuzhiyun#define PSCI_DEFAULT(__fn) \
15*4882a593Smuzhiyun	ENTRY(__fn); \
16*4882a593Smuzhiyun	mov	w0, #ARM_PSCI_RET_NI; \
17*4882a593Smuzhiyun	ret; \
18*4882a593Smuzhiyun	ENDPROC(__fn); \
19*4882a593Smuzhiyun	.weak __fn
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun/* PSCI function and ID table definition*/
22*4882a593Smuzhiyun#define PSCI_TABLE(__id, __fn) \
23*4882a593Smuzhiyun	.word __id; \
24*4882a593Smuzhiyun	.word __fn
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun.pushsection ._secure.text, "ax"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun/* 32 bits PSCI default functions */
29*4882a593SmuzhiyunPSCI_DEFAULT(psci_version)
30*4882a593SmuzhiyunPSCI_DEFAULT(psci_cpu_suspend)
31*4882a593SmuzhiyunPSCI_DEFAULT(psci_cpu_off)
32*4882a593SmuzhiyunPSCI_DEFAULT(psci_cpu_on)
33*4882a593SmuzhiyunPSCI_DEFAULT(psci_affinity_info)
34*4882a593SmuzhiyunPSCI_DEFAULT(psci_migrate)
35*4882a593SmuzhiyunPSCI_DEFAULT(psci_migrate_info_type)
36*4882a593SmuzhiyunPSCI_DEFAULT(psci_migrate_info_up_cpu)
37*4882a593SmuzhiyunPSCI_DEFAULT(psci_system_off)
38*4882a593SmuzhiyunPSCI_DEFAULT(psci_system_reset)
39*4882a593SmuzhiyunPSCI_DEFAULT(psci_features)
40*4882a593SmuzhiyunPSCI_DEFAULT(psci_cpu_freeze)
41*4882a593SmuzhiyunPSCI_DEFAULT(psci_cpu_default_suspend)
42*4882a593SmuzhiyunPSCI_DEFAULT(psci_node_hw_state)
43*4882a593SmuzhiyunPSCI_DEFAULT(psci_system_suspend)
44*4882a593SmuzhiyunPSCI_DEFAULT(psci_set_suspend_mode)
45*4882a593SmuzhiyunPSCI_DEFAULT(psi_stat_residency)
46*4882a593SmuzhiyunPSCI_DEFAULT(psci_stat_count)
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun.align 3
49*4882a593Smuzhiyun_psci_32_table:
50*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_FN_CPU_SUSPEND, psci_cpu_suspend)
51*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_FN_CPU_OFF, psci_cpu_off)
52*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_FN_CPU_ON, psci_cpu_on)
53*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_FN_MIGRATE, psci_migrate)
54*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_PSCI_VERSION, psci_version)
55*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_CPU_SUSPEND, psci_cpu_suspend)
56*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_CPU_OFF, psci_cpu_off)
57*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_CPU_ON, psci_cpu_on)
58*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_AFFINITY_INFO, psci_affinity_info)
59*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE, psci_migrate)
60*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE, psci_migrate_info_type)
61*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu)
62*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_OFF, psci_system_off)
63*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_RESET, psci_system_reset)
64*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN_PSCI_FEATURES, psci_features)
65*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN_CPU_FREEZE, psci_cpu_freeze)
66*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend)
67*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN_NODE_HW_STATE, psci_node_hw_state)
68*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN_SYSTEM_SUSPEND, psci_system_suspend)
69*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN_SET_SUSPEND_MODE, psci_set_suspend_mode)
70*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN_STAT_RESIDENCY, psi_stat_residency)
71*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN_STAT_COUNT, psci_stat_count)
72*4882a593SmuzhiyunPSCI_TABLE(0, 0)
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun/* 64 bits PSCI default functions */
75*4882a593SmuzhiyunPSCI_DEFAULT(psci_cpu_suspend_64)
76*4882a593SmuzhiyunPSCI_DEFAULT(psci_cpu_on_64)
77*4882a593SmuzhiyunPSCI_DEFAULT(psci_affinity_info_64)
78*4882a593SmuzhiyunPSCI_DEFAULT(psci_migrate_64)
79*4882a593SmuzhiyunPSCI_DEFAULT(psci_migrate_info_up_cpu_64)
80*4882a593SmuzhiyunPSCI_DEFAULT(psci_cpu_default_suspend_64)
81*4882a593SmuzhiyunPSCI_DEFAULT(psci_node_hw_state_64)
82*4882a593SmuzhiyunPSCI_DEFAULT(psci_system_suspend_64)
83*4882a593SmuzhiyunPSCI_DEFAULT(psci_stat_residency_64)
84*4882a593SmuzhiyunPSCI_DEFAULT(psci_stat_count_64)
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun.align 3
87*4882a593Smuzhiyun_psci_64_table:
88*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_SUSPEND, psci_cpu_suspend_64)
89*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_ON, psci_cpu_on_64)
90*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN64_AFFINITY_INFO, psci_affinity_info_64)
91*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE, psci_migrate_64)
92*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu_64)
93*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend_64)
94*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN64_NODE_HW_STATE, psci_node_hw_state_64)
95*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND, psci_system_suspend_64)
96*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_RESIDENCY, psci_stat_residency_64)
97*4882a593SmuzhiyunPSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_COUNT, psci_stat_count_64)
98*4882a593SmuzhiyunPSCI_TABLE(0, 0)
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun.macro	psci_enter
101*4882a593Smuzhiyun	/* PSCI call is Fast Call(atomic), so mask DAIF */
102*4882a593Smuzhiyun	mrs	x15, DAIF
103*4882a593Smuzhiyun	stp	x15, xzr, [sp, #-16]!
104*4882a593Smuzhiyun	ldr	x15, =0x3C0
105*4882a593Smuzhiyun	msr	DAIF, x15
106*4882a593Smuzhiyun	/* SMC convention, x18 ~ x30 should be saved by callee */
107*4882a593Smuzhiyun	stp	x29, x30, [sp, #-16]!
108*4882a593Smuzhiyun	stp	x27, x28, [sp, #-16]!
109*4882a593Smuzhiyun	stp	x25, x26, [sp, #-16]!
110*4882a593Smuzhiyun	stp	x23, x24, [sp, #-16]!
111*4882a593Smuzhiyun	stp	x21, x22, [sp, #-16]!
112*4882a593Smuzhiyun	stp	x19, x20, [sp, #-16]!
113*4882a593Smuzhiyun	mrs	x15, elr_el3
114*4882a593Smuzhiyun	stp	x18, x15, [sp, #-16]!
115*4882a593Smuzhiyun.endm
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun.macro	psci_return
118*4882a593Smuzhiyun	/* restore registers */
119*4882a593Smuzhiyun	ldp	x18, x15, [sp], #16
120*4882a593Smuzhiyun	msr	elr_el3, x15
121*4882a593Smuzhiyun	ldp	x19, x20, [sp], #16
122*4882a593Smuzhiyun	ldp	x21, x22, [sp], #16
123*4882a593Smuzhiyun	ldp	x23, x24, [sp], #16
124*4882a593Smuzhiyun	ldp	x25, x26, [sp], #16
125*4882a593Smuzhiyun	ldp	x27, x28, [sp], #16
126*4882a593Smuzhiyun	ldp	x29, x30, [sp], #16
127*4882a593Smuzhiyun	/* restore DAIF */
128*4882a593Smuzhiyun	ldp	x15, xzr, [sp], #16
129*4882a593Smuzhiyun	msr	DAIF, x15
130*4882a593Smuzhiyun	eret
131*4882a593Smuzhiyun.endm
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun/* Caller must put PSCI function-ID table base in x9 */
134*4882a593Smuzhiyunhandle_psci:
135*4882a593Smuzhiyun	psci_enter
136*4882a593Smuzhiyun1:	ldr x10, [x9]			/* Load PSCI function table */
137*4882a593Smuzhiyun	ubfx x11, x10, #32, #32
138*4882a593Smuzhiyun	ubfx x10, x10, #0, #32
139*4882a593Smuzhiyun	cbz	x10, 3f			/* If reach the end, bail out */
140*4882a593Smuzhiyun	cmp	x10, x0
141*4882a593Smuzhiyun	b.eq	2f			/* PSCI function found */
142*4882a593Smuzhiyun	add x9, x9, #8			/* If not match, try next entry */
143*4882a593Smuzhiyun	b	1b
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun2:	blr	x11			/* Call PSCI function */
146*4882a593Smuzhiyun	psci_return
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun3:	mov	x0, #ARM_PSCI_RET_NI
149*4882a593Smuzhiyun	psci_return
150*4882a593Smuzhiyun
151*4882a593Smuzhiyununknown_smc_id:
152*4882a593Smuzhiyun	ldr	x0, =0xFFFFFFFF
153*4882a593Smuzhiyun	eret
154*4882a593Smuzhiyun
155*4882a593Smuzhiyunhandle_smc32:
156*4882a593Smuzhiyun	/* SMC function ID  0x84000000-0x8400001F: 32 bits PSCI */
157*4882a593Smuzhiyun	ldr	w9, =0x8400001F
158*4882a593Smuzhiyun	cmp	w0, w9
159*4882a593Smuzhiyun	b.gt	unknown_smc_id
160*4882a593Smuzhiyun	ldr	w9, =0x84000000
161*4882a593Smuzhiyun	cmp	w0, w9
162*4882a593Smuzhiyun	b.lt	unknown_smc_id
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun	adr	x9, _psci_32_table
165*4882a593Smuzhiyun	b	handle_psci
166*4882a593Smuzhiyun
167*4882a593Smuzhiyunhandle_smc64:
168*4882a593Smuzhiyun	/* check SMC32 or SMC64 calls */
169*4882a593Smuzhiyun	ubfx	x9, x0, #30, #1
170*4882a593Smuzhiyun	cbz	x9, handle_smc32
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun	/* SMC function ID 0xC4000000-0xC400001F: 64 bits PSCI */
173*4882a593Smuzhiyun	ldr	x9, =0xC400001F
174*4882a593Smuzhiyun	cmp	x0, x9
175*4882a593Smuzhiyun	b.gt	unknown_smc_id
176*4882a593Smuzhiyun	ldr	x9, =0xC4000000
177*4882a593Smuzhiyun	cmp	x0, x9
178*4882a593Smuzhiyun	b.lt	unknown_smc_id
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun	adr	x9, _psci_64_table
181*4882a593Smuzhiyun	b	handle_psci
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun/*
184*4882a593Smuzhiyun * Get CPU ID from MPIDR, suppose every cluster has same number of CPU cores,
185*4882a593Smuzhiyun * Platform with asymmetric clusters should implement their own interface.
186*4882a593Smuzhiyun * In case this function being called by other platform's C code, the ARM
187*4882a593Smuzhiyun * Architecture Procedure Call Standard is considered, e.g. register X0 is
188*4882a593Smuzhiyun * used for the return value, while in this PSCI environment, X0 usually holds
189*4882a593Smuzhiyun * the SMC function identifier, so X0 should be saved by caller function.
190*4882a593Smuzhiyun */
191*4882a593SmuzhiyunENTRY(psci_get_cpu_id)
192*4882a593Smuzhiyun#ifdef CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER
193*4882a593Smuzhiyun	mrs	x9, MPIDR_EL1
194*4882a593Smuzhiyun	ubfx	x9, x9, #8, #8
195*4882a593Smuzhiyun	ldr	x10, =CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER
196*4882a593Smuzhiyun	mul	x9, x10, x9
197*4882a593Smuzhiyun#else
198*4882a593Smuzhiyun	mov	x9, xzr
199*4882a593Smuzhiyun#endif
200*4882a593Smuzhiyun	mrs	x10, MPIDR_EL1
201*4882a593Smuzhiyun	ubfx	x10, x10, #0, #8
202*4882a593Smuzhiyun	add	x0, x10, x9
203*4882a593Smuzhiyun	ret
204*4882a593SmuzhiyunENDPROC(psci_get_cpu_id)
205*4882a593Smuzhiyun.weak psci_get_cpu_id
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun/* CPU ID input in x0, stack top output in x0*/
208*4882a593SmuzhiyunLENTRY(psci_get_cpu_stack_top)
209*4882a593Smuzhiyun	adr	x9, __secure_stack_end
210*4882a593Smuzhiyun	lsl	x0, x0, #ARM_PSCI_STACK_SHIFT
211*4882a593Smuzhiyun	sub	x0, x9, x0
212*4882a593Smuzhiyun	ret
213*4882a593SmuzhiyunENDPROC(psci_get_cpu_stack_top)
214*4882a593Smuzhiyun
215*4882a593Smuzhiyununhandled_exception:
216*4882a593Smuzhiyun	b	unhandled_exception	/* simply dead loop */
217*4882a593Smuzhiyun
218*4882a593Smuzhiyunhandle_sync:
219*4882a593Smuzhiyun	mov	x15, x30
220*4882a593Smuzhiyun	mov	x14, x0
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun	bl	psci_get_cpu_id
223*4882a593Smuzhiyun	bl	psci_get_cpu_stack_top
224*4882a593Smuzhiyun	mov	x9, #1
225*4882a593Smuzhiyun	msr	spsel, x9
226*4882a593Smuzhiyun	mov	sp, x0
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun	mov	x0, x14
229*4882a593Smuzhiyun	mov	x30, x15
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun	mrs	x9, esr_el3
232*4882a593Smuzhiyun	ubfx	x9, x9, #26, #6
233*4882a593Smuzhiyun	cmp	x9, #0x13
234*4882a593Smuzhiyun	b.eq	handle_smc32
235*4882a593Smuzhiyun	cmp	x9, #0x17
236*4882a593Smuzhiyun	b.eq	handle_smc64
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun	b	unhandled_exception
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun	.align	11
241*4882a593Smuzhiyun	.globl	el3_exception_vectors
242*4882a593Smuzhiyunel3_exception_vectors:
243*4882a593Smuzhiyun	b	unhandled_exception	/* Sync, Current EL using SP0 */
244*4882a593Smuzhiyun	.align	7
245*4882a593Smuzhiyun	b	unhandled_exception	/* IRQ, Current EL using SP0 */
246*4882a593Smuzhiyun	.align	7
247*4882a593Smuzhiyun	b	unhandled_exception	/* FIQ, Current EL using SP0 */
248*4882a593Smuzhiyun	.align	7
249*4882a593Smuzhiyun	b	unhandled_exception	/* SError, Current EL using SP0 */
250*4882a593Smuzhiyun	.align	7
251*4882a593Smuzhiyun	b	unhandled_exception	/* Sync, Current EL using SPx */
252*4882a593Smuzhiyun	.align	7
253*4882a593Smuzhiyun	b	unhandled_exception	/* IRQ, Current EL using SPx */
254*4882a593Smuzhiyun	.align	7
255*4882a593Smuzhiyun	b	unhandled_exception	/* FIQ, Current EL using SPx */
256*4882a593Smuzhiyun	.align	7
257*4882a593Smuzhiyun	b	unhandled_exception	/* SError, Current EL using SPx */
258*4882a593Smuzhiyun	.align	7
259*4882a593Smuzhiyun	b	handle_sync		/* Sync, Lower EL using AArch64 */
260*4882a593Smuzhiyun	.align	7
261*4882a593Smuzhiyun	b	unhandled_exception	/* IRQ, Lower EL using AArch64 */
262*4882a593Smuzhiyun	.align	7
263*4882a593Smuzhiyun	b	unhandled_exception	/* FIQ, Lower EL using AArch64 */
264*4882a593Smuzhiyun	.align	7
265*4882a593Smuzhiyun	b	unhandled_exception	/* SError, Lower EL using AArch64 */
266*4882a593Smuzhiyun	.align	7
267*4882a593Smuzhiyun	b	unhandled_exception	/* Sync, Lower EL using AArch32 */
268*4882a593Smuzhiyun	.align	7
269*4882a593Smuzhiyun	b	unhandled_exception	/* IRQ, Lower EL using AArch32 */
270*4882a593Smuzhiyun	.align	7
271*4882a593Smuzhiyun	b	unhandled_exception	/* FIQ, Lower EL using AArch32 */
272*4882a593Smuzhiyun	.align	7
273*4882a593Smuzhiyun	b	unhandled_exception	/* SError, Lower EL using AArch32 */
274*4882a593Smuzhiyun
275*4882a593SmuzhiyunENTRY(psci_setup_vectors)
276*4882a593Smuzhiyun	adr	x0, el3_exception_vectors
277*4882a593Smuzhiyun	msr	vbar_el3, x0
278*4882a593Smuzhiyun	ret
279*4882a593SmuzhiyunENDPROC(psci_setup_vectors)
280*4882a593Smuzhiyun
281*4882a593SmuzhiyunENTRY(psci_arch_init)
282*4882a593Smuzhiyun	ret
283*4882a593SmuzhiyunENDPROC(psci_arch_init)
284*4882a593Smuzhiyun.weak psci_arch_init
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun.popsection
287