xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv8/fwcall.c (revision 3c63db9ca9765c85bbcf2a06f4183cfb0036ea33)
1a5b9fa30SSergey Temerkhanov /**
2a5b9fa30SSergey Temerkhanov  * (C) Copyright 2014, Cavium Inc.
3a5b9fa30SSergey Temerkhanov  *
4a5b9fa30SSergey Temerkhanov  * SPDX-License-Identifier:	GPL-2.0+
5a5b9fa30SSergey Temerkhanov **/
6a5b9fa30SSergey Temerkhanov 
7a5b9fa30SSergey Temerkhanov #include <asm-offsets.h>
8a5b9fa30SSergey Temerkhanov #include <config.h>
9b6575f34SAlexander Graf #include <efi_loader.h>
10a5b9fa30SSergey Temerkhanov #include <version.h>
11a5b9fa30SSergey Temerkhanov #include <asm/macro.h>
125a07abb3SBeniamino Galvani #include <asm/psci.h>
13a5b9fa30SSergey Temerkhanov #include <asm/system.h>
14a5b9fa30SSergey Temerkhanov 
15a5b9fa30SSergey Temerkhanov /*
16a5b9fa30SSergey Temerkhanov  * Issue the hypervisor call
17a5b9fa30SSergey Temerkhanov  *
18a5b9fa30SSergey Temerkhanov  * x0~x7: input arguments
19a5b9fa30SSergey Temerkhanov  * x0~x3: output arguments
20a5b9fa30SSergey Temerkhanov  */
21*3c63db9cSAlexander Graf static void __efi_runtime hvc_call(struct pt_regs *args)
22a5b9fa30SSergey Temerkhanov {
23a5b9fa30SSergey Temerkhanov 	asm volatile(
24a5b9fa30SSergey Temerkhanov 		"ldr x0, %0\n"
25a5b9fa30SSergey Temerkhanov 		"ldr x1, %1\n"
26a5b9fa30SSergey Temerkhanov 		"ldr x2, %2\n"
27a5b9fa30SSergey Temerkhanov 		"ldr x3, %3\n"
28a5b9fa30SSergey Temerkhanov 		"ldr x4, %4\n"
29a5b9fa30SSergey Temerkhanov 		"ldr x5, %5\n"
30a5b9fa30SSergey Temerkhanov 		"ldr x6, %6\n"
31a5b9fa30SSergey Temerkhanov 		"ldr x7, %7\n"
32a5b9fa30SSergey Temerkhanov 		"hvc	#0\n"
33a5b9fa30SSergey Temerkhanov 		"str x0, %0\n"
34a5b9fa30SSergey Temerkhanov 		"str x1, %1\n"
35a5b9fa30SSergey Temerkhanov 		"str x2, %2\n"
36a5b9fa30SSergey Temerkhanov 		"str x3, %3\n"
37a5b9fa30SSergey Temerkhanov 		: "+m" (args->regs[0]), "+m" (args->regs[1]),
38a5b9fa30SSergey Temerkhanov 		  "+m" (args->regs[2]), "+m" (args->regs[3])
39a5b9fa30SSergey Temerkhanov 		: "m" (args->regs[4]), "m" (args->regs[5]),
40a5b9fa30SSergey Temerkhanov 		  "m" (args->regs[6]), "m" (args->regs[7])
41a5b9fa30SSergey Temerkhanov 		: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
42a5b9fa30SSergey Temerkhanov 		  "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
43a5b9fa30SSergey Temerkhanov 		  "x16", "x17");
44a5b9fa30SSergey Temerkhanov }
45a5b9fa30SSergey Temerkhanov 
46a5b9fa30SSergey Temerkhanov /*
47a5b9fa30SSergey Temerkhanov  * void smc_call(arg0, arg1...arg7)
48a5b9fa30SSergey Temerkhanov  *
49a5b9fa30SSergey Temerkhanov  * issue the secure monitor call
50a5b9fa30SSergey Temerkhanov  *
51a5b9fa30SSergey Temerkhanov  * x0~x7: input arguments
52a5b9fa30SSergey Temerkhanov  * x0~x3: output arguments
53a5b9fa30SSergey Temerkhanov  */
54a5b9fa30SSergey Temerkhanov 
55*3c63db9cSAlexander Graf void __efi_runtime smc_call(struct pt_regs *args)
56a5b9fa30SSergey Temerkhanov {
57a5b9fa30SSergey Temerkhanov 	asm volatile(
58a5b9fa30SSergey Temerkhanov 		"ldr x0, %0\n"
59a5b9fa30SSergey Temerkhanov 		"ldr x1, %1\n"
60a5b9fa30SSergey Temerkhanov 		"ldr x2, %2\n"
61a5b9fa30SSergey Temerkhanov 		"ldr x3, %3\n"
62a5b9fa30SSergey Temerkhanov 		"ldr x4, %4\n"
63a5b9fa30SSergey Temerkhanov 		"ldr x5, %5\n"
64a5b9fa30SSergey Temerkhanov 		"ldr x6, %6\n"
65a5b9fa30SSergey Temerkhanov 		"smc	#0\n"
66a5b9fa30SSergey Temerkhanov 		"str x0, %0\n"
67a5b9fa30SSergey Temerkhanov 		"str x1, %1\n"
68a5b9fa30SSergey Temerkhanov 		"str x2, %2\n"
69a5b9fa30SSergey Temerkhanov 		"str x3, %3\n"
70a5b9fa30SSergey Temerkhanov 		: "+m" (args->regs[0]), "+m" (args->regs[1]),
71a5b9fa30SSergey Temerkhanov 		  "+m" (args->regs[2]), "+m" (args->regs[3])
72a5b9fa30SSergey Temerkhanov 		: "m" (args->regs[4]), "m" (args->regs[5]),
73a5b9fa30SSergey Temerkhanov 		  "m" (args->regs[6])
74a5b9fa30SSergey Temerkhanov 		: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
75a5b9fa30SSergey Temerkhanov 		  "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
76a5b9fa30SSergey Temerkhanov 		  "x16", "x17");
77a5b9fa30SSergey Temerkhanov }
785a07abb3SBeniamino Galvani 
7951bfb5b6SAlexander Graf /*
8051bfb5b6SAlexander Graf  * For now, all systems we support run at least in EL2 and thus
8151bfb5b6SAlexander Graf  * trigger PSCI calls to EL3 using SMC. If anyone ever wants to
8251bfb5b6SAlexander Graf  * use PSCI on U-Boot running below a hypervisor, please detect
8351bfb5b6SAlexander Graf  * this and set the flag accordingly.
8451bfb5b6SAlexander Graf  */
85*3c63db9cSAlexander Graf static const __efi_runtime_data bool use_smc_for_psci = true;
8651bfb5b6SAlexander Graf 
87*3c63db9cSAlexander Graf void __noreturn __efi_runtime psci_system_reset(void)
885a07abb3SBeniamino Galvani {
895a07abb3SBeniamino Galvani 	struct pt_regs regs;
905a07abb3SBeniamino Galvani 
915a07abb3SBeniamino Galvani 	regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET;
925a07abb3SBeniamino Galvani 
9351bfb5b6SAlexander Graf 	if (use_smc_for_psci)
945a07abb3SBeniamino Galvani 		smc_call(&regs);
955a07abb3SBeniamino Galvani 	else
965a07abb3SBeniamino Galvani 		hvc_call(&regs);
975a07abb3SBeniamino Galvani 
985a07abb3SBeniamino Galvani 	while (1)
995a07abb3SBeniamino Galvani 		;
1005a07abb3SBeniamino Galvani }
1013ee655edSAlexander Graf 
102*3c63db9cSAlexander Graf void __noreturn __efi_runtime psci_system_off(void)
1033ee655edSAlexander Graf {
1043ee655edSAlexander Graf 	struct pt_regs regs;
1053ee655edSAlexander Graf 
1063ee655edSAlexander Graf 	regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_OFF;
1073ee655edSAlexander Graf 
1083ee655edSAlexander Graf 	if (use_smc_for_psci)
1093ee655edSAlexander Graf 		smc_call(&regs);
1103ee655edSAlexander Graf 	else
1113ee655edSAlexander Graf 		hvc_call(&regs);
1123ee655edSAlexander Graf 
1133ee655edSAlexander Graf 	while (1)
1143ee655edSAlexander Graf 		;
1153ee655edSAlexander Graf }
1168069821fSAlexander Graf 
1178069821fSAlexander Graf #ifdef CONFIG_PSCI_RESET
1188069821fSAlexander Graf void reset_misc(void)
1198069821fSAlexander Graf {
1208069821fSAlexander Graf 	psci_system_reset();
1218069821fSAlexander Graf }
122b6575f34SAlexander Graf 
123b6575f34SAlexander Graf #ifdef CONFIG_EFI_LOADER
124*3c63db9cSAlexander Graf void __efi_runtime EFIAPI efi_reset_system(
125b6575f34SAlexander Graf 			enum efi_reset_type reset_type,
126b6575f34SAlexander Graf 			efi_status_t reset_status,
127b6575f34SAlexander Graf 			unsigned long data_size, void *reset_data)
128b6575f34SAlexander Graf {
129b6575f34SAlexander Graf 	switch (reset_type) {
130b6575f34SAlexander Graf 	case EFI_RESET_COLD:
131b6575f34SAlexander Graf 	case EFI_RESET_WARM:
132b6575f34SAlexander Graf 		psci_system_reset();
133b6575f34SAlexander Graf 		break;
134b6575f34SAlexander Graf 	case EFI_RESET_SHUTDOWN:
135b6575f34SAlexander Graf 		psci_system_off();
136b6575f34SAlexander Graf 		break;
137b6575f34SAlexander Graf 	}
138b6575f34SAlexander Graf 
139b6575f34SAlexander Graf 	while (1) { }
140b6575f34SAlexander Graf }
141b6575f34SAlexander Graf #endif /* CONFIG_EFI_LOADER */
1428069821fSAlexander Graf #endif /* CONFIG_PSCI_RESET */
143