1 /* SPDX-License-Identifier: GPL-2.0+ */
2 /*
3  * Workaround for "PSCI bug" on DragonBoard 410c
4  * Copyright (C) 2021 Stephan Gerhold <stephan@gerhold.net>
5  *
6  * Syscall parameters taken from Qualcomm's LK fork (scm.h):
7  * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
8  *
9  * The PSCI implementation in the TrustZone/tz firmware on DragonBoard 410c has
10  * a bug that starts all other CPU cores in 32-bit mode unless the TZ syscall
11  * that switches from 32-bit to 64-bit mode is executed at least once.
12  *
13  * Normally this happens inside Qualcomm's LK bootloader which runs in 32-bit
14  * mode and uses the TZ syscall to boot a kernel in 64-bit mode. However, if
15  * U-Boot is installed to the "aboot" partition (replacing LK) the switch to
16  * 64-bit mode never happens since U-Boot is already running in 64-bit mode.
17  *
18  * A workaround for this "PSCI bug" is to execute the TZ syscall when entering
19  * U-Boot. That way PSCI is made aware of the 64-bit switch and starts all other
20  * CPU cores in 64-bit mode as well.
21  */
22 #include <linux/arm-smccc.h>
23 
24 #define ARM_SMCCC_SIP32_FAST_CALL \
25 	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, ARM_SMCCC_OWNER_SIP, 0)
26 
27 	/*
28 	 * U-Boot might be started in EL2 or EL3 with custom firmware.
29 	 * In that case, we assume that the workaround is not necessary or is
30 	 * handled already by the alternative firmware. Using the syscall in EL2
31 	 * would demote U-Boot to EL1; in EL3 it would probably just crash.
32 	 */
33 	mrs	x0, CurrentEL
34 	cmp	x0, #(1 << 2)	/* EL1 */
35 	bne	reset
36 
37 	/* Prepare TZ syscall parameters */
38 	mov	x0, #ARM_SMCCC_SIP32_FAST_CALL
39 	movk	x0, #0x10f	/* SCM_SVC_MILESTONE_CMD_ID */
40 	mov	x1, #0x12	/* MAKE_SCM_ARGS(0x2, SMC_PARAM_TYPE_BUFFER_READ) */
41 	adr	x2, el1_system_param
42 	mov	x3, el1_system_param_end - el1_system_param
43 
44 	/* Switch PSCI to 64-bit mode. Resets CPU and returns at el1_elr */
45 	smc	#0
46 
47 	/* Something went wrong, perhaps PSCI is already in 64-bit mode? */
48 	b	reset
49 
50 	.align	3
51 el1_system_param:
52 	.quad	0, 0, 0, 0, 0, 0, 0, 0, 0	/* el1_x0-x8 */
53 	.quad	reset				/* el1_elr */
54 el1_system_param_end:
55