xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv8/fwcall.c (revision 94179a6f324d7385dea77a2968858b82b7be3131)
1a5b9fa30SSergey Temerkhanov /**
2a5b9fa30SSergey Temerkhanov  * (C) Copyright 2014, Cavium Inc.
33c85417fSMichal Simek  * (C) Copyright 2017, Xilinx Inc.
4a5b9fa30SSergey Temerkhanov  *
5a5b9fa30SSergey Temerkhanov  * SPDX-License-Identifier:	GPL-2.0+
6a5b9fa30SSergey Temerkhanov **/
7a5b9fa30SSergey Temerkhanov 
8a5b9fa30SSergey Temerkhanov #include <asm-offsets.h>
9a5b9fa30SSergey Temerkhanov #include <config.h>
10b6575f34SAlexander Graf #include <efi_loader.h>
11a5b9fa30SSergey Temerkhanov #include <version.h>
12a5b9fa30SSergey Temerkhanov #include <asm/macro.h>
135a07abb3SBeniamino Galvani #include <asm/psci.h>
14a5b9fa30SSergey Temerkhanov #include <asm/system.h>
15a5b9fa30SSergey Temerkhanov 
16a5b9fa30SSergey Temerkhanov /*
17a5b9fa30SSergey Temerkhanov  * Issue the hypervisor call
18a5b9fa30SSergey Temerkhanov  *
19a5b9fa30SSergey Temerkhanov  * x0~x7: input arguments
20a5b9fa30SSergey Temerkhanov  * x0~x3: output arguments
21a5b9fa30SSergey Temerkhanov  */
hvc_call(struct pt_regs * args)223c63db9cSAlexander Graf static void __efi_runtime hvc_call(struct pt_regs *args)
23a5b9fa30SSergey Temerkhanov {
24a5b9fa30SSergey Temerkhanov 	asm volatile(
25a5b9fa30SSergey Temerkhanov 		"ldr x0, %0\n"
26a5b9fa30SSergey Temerkhanov 		"ldr x1, %1\n"
27a5b9fa30SSergey Temerkhanov 		"ldr x2, %2\n"
28a5b9fa30SSergey Temerkhanov 		"ldr x3, %3\n"
29a5b9fa30SSergey Temerkhanov 		"ldr x4, %4\n"
30a5b9fa30SSergey Temerkhanov 		"ldr x5, %5\n"
31a5b9fa30SSergey Temerkhanov 		"ldr x6, %6\n"
32a5b9fa30SSergey Temerkhanov 		"ldr x7, %7\n"
33a5b9fa30SSergey Temerkhanov 		"hvc	#0\n"
34a5b9fa30SSergey Temerkhanov 		"str x0, %0\n"
35a5b9fa30SSergey Temerkhanov 		"str x1, %1\n"
36a5b9fa30SSergey Temerkhanov 		"str x2, %2\n"
37a5b9fa30SSergey Temerkhanov 		"str x3, %3\n"
38a5b9fa30SSergey Temerkhanov 		: "+m" (args->regs[0]), "+m" (args->regs[1]),
39a5b9fa30SSergey Temerkhanov 		  "+m" (args->regs[2]), "+m" (args->regs[3])
40a5b9fa30SSergey Temerkhanov 		: "m" (args->regs[4]), "m" (args->regs[5]),
41a5b9fa30SSergey Temerkhanov 		  "m" (args->regs[6]), "m" (args->regs[7])
42a5b9fa30SSergey Temerkhanov 		: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
43a5b9fa30SSergey Temerkhanov 		  "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
44a5b9fa30SSergey Temerkhanov 		  "x16", "x17");
45a5b9fa30SSergey Temerkhanov }
46a5b9fa30SSergey Temerkhanov 
47a5b9fa30SSergey Temerkhanov /*
48a5b9fa30SSergey Temerkhanov  * void smc_call(arg0, arg1...arg7)
49a5b9fa30SSergey Temerkhanov  *
50a5b9fa30SSergey Temerkhanov  * issue the secure monitor call
51a5b9fa30SSergey Temerkhanov  *
52a5b9fa30SSergey Temerkhanov  * x0~x7: input arguments
53a5b9fa30SSergey Temerkhanov  * x0~x3: output arguments
54a5b9fa30SSergey Temerkhanov  */
55a5b9fa30SSergey Temerkhanov 
smc_call(struct pt_regs * args)563c63db9cSAlexander Graf void __efi_runtime smc_call(struct pt_regs *args)
57a5b9fa30SSergey Temerkhanov {
58a5b9fa30SSergey Temerkhanov 	asm volatile(
59a5b9fa30SSergey Temerkhanov 		"ldr x0, %0\n"
60a5b9fa30SSergey Temerkhanov 		"ldr x1, %1\n"
61a5b9fa30SSergey Temerkhanov 		"ldr x2, %2\n"
62a5b9fa30SSergey Temerkhanov 		"ldr x3, %3\n"
63a5b9fa30SSergey Temerkhanov 		"ldr x4, %4\n"
64a5b9fa30SSergey Temerkhanov 		"ldr x5, %5\n"
65a5b9fa30SSergey Temerkhanov 		"ldr x6, %6\n"
66a5b9fa30SSergey Temerkhanov 		"smc	#0\n"
67a5b9fa30SSergey Temerkhanov 		"str x0, %0\n"
68a5b9fa30SSergey Temerkhanov 		"str x1, %1\n"
69a5b9fa30SSergey Temerkhanov 		"str x2, %2\n"
70a5b9fa30SSergey Temerkhanov 		"str x3, %3\n"
71a5b9fa30SSergey Temerkhanov 		: "+m" (args->regs[0]), "+m" (args->regs[1]),
72a5b9fa30SSergey Temerkhanov 		  "+m" (args->regs[2]), "+m" (args->regs[3])
73a5b9fa30SSergey Temerkhanov 		: "m" (args->regs[4]), "m" (args->regs[5]),
74a5b9fa30SSergey Temerkhanov 		  "m" (args->regs[6])
75a5b9fa30SSergey Temerkhanov 		: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
76a5b9fa30SSergey Temerkhanov 		  "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
77a5b9fa30SSergey Temerkhanov 		  "x16", "x17");
78a5b9fa30SSergey Temerkhanov }
795a07abb3SBeniamino Galvani 
8051bfb5b6SAlexander Graf /*
8151bfb5b6SAlexander Graf  * For now, all systems we support run at least in EL2 and thus
8251bfb5b6SAlexander Graf  * trigger PSCI calls to EL3 using SMC. If anyone ever wants to
8351bfb5b6SAlexander Graf  * use PSCI on U-Boot running below a hypervisor, please detect
8451bfb5b6SAlexander Graf  * this and set the flag accordingly.
8551bfb5b6SAlexander Graf  */
863c63db9cSAlexander Graf static const __efi_runtime_data bool use_smc_for_psci = true;
8751bfb5b6SAlexander Graf 
psci_system_reset(void)883c63db9cSAlexander Graf void __noreturn __efi_runtime psci_system_reset(void)
895a07abb3SBeniamino Galvani {
905a07abb3SBeniamino Galvani 	struct pt_regs regs;
915a07abb3SBeniamino Galvani 
925a07abb3SBeniamino Galvani 	regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET;
935a07abb3SBeniamino Galvani 
9451bfb5b6SAlexander Graf 	if (use_smc_for_psci)
955a07abb3SBeniamino Galvani 		smc_call(&regs);
965a07abb3SBeniamino Galvani 	else
975a07abb3SBeniamino Galvani 		hvc_call(&regs);
985a07abb3SBeniamino Galvani 
995a07abb3SBeniamino Galvani 	while (1)
1005a07abb3SBeniamino Galvani 		;
1015a07abb3SBeniamino Galvani }
1023ee655edSAlexander Graf 
psci_system_off(void)1033c63db9cSAlexander Graf void __noreturn __efi_runtime psci_system_off(void)
1043ee655edSAlexander Graf {
1053ee655edSAlexander Graf 	struct pt_regs regs;
1063ee655edSAlexander Graf 
1073ee655edSAlexander Graf 	regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_OFF;
1083ee655edSAlexander Graf 
1093ee655edSAlexander Graf 	if (use_smc_for_psci)
1103ee655edSAlexander Graf 		smc_call(&regs);
1113ee655edSAlexander Graf 	else
1123ee655edSAlexander Graf 		hvc_call(&regs);
1133ee655edSAlexander Graf 
1143ee655edSAlexander Graf 	while (1)
1153ee655edSAlexander Graf 		;
1163ee655edSAlexander Graf }
1178069821fSAlexander Graf 
1183c85417fSMichal Simek #ifdef CONFIG_CMD_POWEROFF
do_poweroff(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])1193c85417fSMichal Simek int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1203c85417fSMichal Simek {
1213c85417fSMichal Simek 	puts("poweroff ...\n");
1223c85417fSMichal Simek 
1233c85417fSMichal Simek 	udelay(50000); /* wait 50 ms */
1243c85417fSMichal Simek 
1253c85417fSMichal Simek 	disable_interrupts();
1263c85417fSMichal Simek 
1273c85417fSMichal Simek 	psci_system_off();
1283c85417fSMichal Simek 
1293c85417fSMichal Simek 	/*NOTREACHED*/
1303c85417fSMichal Simek 	return 0;
1313c85417fSMichal Simek }
1323c85417fSMichal Simek #endif
1333c85417fSMichal Simek 
134*94179a6fSJoseph Chen #if defined(CONFIG_PSCI_RESET) && !defined(CONFIG_SYSRESET_PSCI)
reset_misc(void)1358069821fSAlexander Graf void reset_misc(void)
1368069821fSAlexander Graf {
1378069821fSAlexander Graf 	psci_system_reset();
1388069821fSAlexander Graf }
139b6575f34SAlexander Graf 
140b6575f34SAlexander Graf #ifdef CONFIG_EFI_LOADER
efi_reset_system(enum efi_reset_type reset_type,efi_status_t reset_status,unsigned long data_size,void * reset_data)1413c63db9cSAlexander Graf void __efi_runtime EFIAPI efi_reset_system(
142b6575f34SAlexander Graf 			enum efi_reset_type reset_type,
143b6575f34SAlexander Graf 			efi_status_t reset_status,
144b6575f34SAlexander Graf 			unsigned long data_size, void *reset_data)
145b6575f34SAlexander Graf {
146b6575f34SAlexander Graf 	switch (reset_type) {
147b6575f34SAlexander Graf 	case EFI_RESET_COLD:
148b6575f34SAlexander Graf 	case EFI_RESET_WARM:
149b6575f34SAlexander Graf 		psci_system_reset();
150b6575f34SAlexander Graf 		break;
151b6575f34SAlexander Graf 	case EFI_RESET_SHUTDOWN:
152b6575f34SAlexander Graf 		psci_system_off();
153b6575f34SAlexander Graf 		break;
154b6575f34SAlexander Graf 	}
155b6575f34SAlexander Graf 
156b6575f34SAlexander Graf 	while (1) { }
157b6575f34SAlexander Graf }
158b6575f34SAlexander Graf #endif /* CONFIG_EFI_LOADER */
1598069821fSAlexander Graf #endif /* CONFIG_PSCI_RESET */
160