xref: /OK3568_Linux_fs/u-boot/arch/arm/cpu/armv8/fwcall.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /**
2*4882a593Smuzhiyun  * (C) Copyright 2014, Cavium Inc.
3*4882a593Smuzhiyun  * (C) Copyright 2017, Xilinx Inc.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun **/
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <asm-offsets.h>
9*4882a593Smuzhiyun #include <config.h>
10*4882a593Smuzhiyun #include <efi_loader.h>
11*4882a593Smuzhiyun #include <version.h>
12*4882a593Smuzhiyun #include <asm/macro.h>
13*4882a593Smuzhiyun #include <asm/psci.h>
14*4882a593Smuzhiyun #include <asm/system.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /*
17*4882a593Smuzhiyun  * Issue the hypervisor call
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * x0~x7: input arguments
20*4882a593Smuzhiyun  * x0~x3: output arguments
21*4882a593Smuzhiyun  */
hvc_call(struct pt_regs * args)22*4882a593Smuzhiyun static void __efi_runtime hvc_call(struct pt_regs *args)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun 	asm volatile(
25*4882a593Smuzhiyun 		"ldr x0, %0\n"
26*4882a593Smuzhiyun 		"ldr x1, %1\n"
27*4882a593Smuzhiyun 		"ldr x2, %2\n"
28*4882a593Smuzhiyun 		"ldr x3, %3\n"
29*4882a593Smuzhiyun 		"ldr x4, %4\n"
30*4882a593Smuzhiyun 		"ldr x5, %5\n"
31*4882a593Smuzhiyun 		"ldr x6, %6\n"
32*4882a593Smuzhiyun 		"ldr x7, %7\n"
33*4882a593Smuzhiyun 		"hvc	#0\n"
34*4882a593Smuzhiyun 		"str x0, %0\n"
35*4882a593Smuzhiyun 		"str x1, %1\n"
36*4882a593Smuzhiyun 		"str x2, %2\n"
37*4882a593Smuzhiyun 		"str x3, %3\n"
38*4882a593Smuzhiyun 		: "+m" (args->regs[0]), "+m" (args->regs[1]),
39*4882a593Smuzhiyun 		  "+m" (args->regs[2]), "+m" (args->regs[3])
40*4882a593Smuzhiyun 		: "m" (args->regs[4]), "m" (args->regs[5]),
41*4882a593Smuzhiyun 		  "m" (args->regs[6]), "m" (args->regs[7])
42*4882a593Smuzhiyun 		: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
43*4882a593Smuzhiyun 		  "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
44*4882a593Smuzhiyun 		  "x16", "x17");
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /*
48*4882a593Smuzhiyun  * void smc_call(arg0, arg1...arg7)
49*4882a593Smuzhiyun  *
50*4882a593Smuzhiyun  * issue the secure monitor call
51*4882a593Smuzhiyun  *
52*4882a593Smuzhiyun  * x0~x7: input arguments
53*4882a593Smuzhiyun  * x0~x3: output arguments
54*4882a593Smuzhiyun  */
55*4882a593Smuzhiyun 
smc_call(struct pt_regs * args)56*4882a593Smuzhiyun void __efi_runtime smc_call(struct pt_regs *args)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	asm volatile(
59*4882a593Smuzhiyun 		"ldr x0, %0\n"
60*4882a593Smuzhiyun 		"ldr x1, %1\n"
61*4882a593Smuzhiyun 		"ldr x2, %2\n"
62*4882a593Smuzhiyun 		"ldr x3, %3\n"
63*4882a593Smuzhiyun 		"ldr x4, %4\n"
64*4882a593Smuzhiyun 		"ldr x5, %5\n"
65*4882a593Smuzhiyun 		"ldr x6, %6\n"
66*4882a593Smuzhiyun 		"smc	#0\n"
67*4882a593Smuzhiyun 		"str x0, %0\n"
68*4882a593Smuzhiyun 		"str x1, %1\n"
69*4882a593Smuzhiyun 		"str x2, %2\n"
70*4882a593Smuzhiyun 		"str x3, %3\n"
71*4882a593Smuzhiyun 		: "+m" (args->regs[0]), "+m" (args->regs[1]),
72*4882a593Smuzhiyun 		  "+m" (args->regs[2]), "+m" (args->regs[3])
73*4882a593Smuzhiyun 		: "m" (args->regs[4]), "m" (args->regs[5]),
74*4882a593Smuzhiyun 		  "m" (args->regs[6])
75*4882a593Smuzhiyun 		: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
76*4882a593Smuzhiyun 		  "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
77*4882a593Smuzhiyun 		  "x16", "x17");
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /*
81*4882a593Smuzhiyun  * For now, all systems we support run at least in EL2 and thus
82*4882a593Smuzhiyun  * trigger PSCI calls to EL3 using SMC. If anyone ever wants to
83*4882a593Smuzhiyun  * use PSCI on U-Boot running below a hypervisor, please detect
84*4882a593Smuzhiyun  * this and set the flag accordingly.
85*4882a593Smuzhiyun  */
86*4882a593Smuzhiyun static const __efi_runtime_data bool use_smc_for_psci = true;
87*4882a593Smuzhiyun 
psci_system_reset(void)88*4882a593Smuzhiyun void __noreturn __efi_runtime psci_system_reset(void)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	struct pt_regs regs;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if (use_smc_for_psci)
95*4882a593Smuzhiyun 		smc_call(&regs);
96*4882a593Smuzhiyun 	else
97*4882a593Smuzhiyun 		hvc_call(&regs);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	while (1)
100*4882a593Smuzhiyun 		;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
psci_system_off(void)103*4882a593Smuzhiyun void __noreturn __efi_runtime psci_system_off(void)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	struct pt_regs regs;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_OFF;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	if (use_smc_for_psci)
110*4882a593Smuzhiyun 		smc_call(&regs);
111*4882a593Smuzhiyun 	else
112*4882a593Smuzhiyun 		hvc_call(&regs);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	while (1)
115*4882a593Smuzhiyun 		;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun #ifdef CONFIG_CMD_POWEROFF
do_poweroff(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])119*4882a593Smuzhiyun int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	puts("poweroff ...\n");
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	udelay(50000); /* wait 50 ms */
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	disable_interrupts();
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	psci_system_off();
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	/*NOTREACHED*/
130*4882a593Smuzhiyun 	return 0;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun #endif
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun #ifdef CONFIG_PSCI_RESET
reset_misc(void)135*4882a593Smuzhiyun void reset_misc(void)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	psci_system_reset();
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun #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)141*4882a593Smuzhiyun void __efi_runtime EFIAPI efi_reset_system(
142*4882a593Smuzhiyun 			enum efi_reset_type reset_type,
143*4882a593Smuzhiyun 			efi_status_t reset_status,
144*4882a593Smuzhiyun 			unsigned long data_size, void *reset_data)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	switch (reset_type) {
147*4882a593Smuzhiyun 	case EFI_RESET_COLD:
148*4882a593Smuzhiyun 	case EFI_RESET_WARM:
149*4882a593Smuzhiyun 		psci_system_reset();
150*4882a593Smuzhiyun 		break;
151*4882a593Smuzhiyun 	case EFI_RESET_SHUTDOWN:
152*4882a593Smuzhiyun 		psci_system_off();
153*4882a593Smuzhiyun 		break;
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	while (1) { }
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun #endif /* CONFIG_EFI_LOADER */
159*4882a593Smuzhiyun #endif /* CONFIG_PSCI_RESET */
160