1 // SPDX-License-Identifier: GPL-2.0+ 2 /** 3 * (C) Copyright 2014, Cavium Inc. 4 * (C) Copyright 2017, Xilinx Inc. 5 * 6 **/ 7 8 #include <asm-offsets.h> 9 #include <config.h> 10 #include <version.h> 11 #include <asm/macro.h> 12 #include <asm/psci.h> 13 #include <asm/system.h> 14 15 /* 16 * Issue the hypervisor call 17 * 18 * x0~x7: input arguments 19 * x0~x3: output arguments 20 */ 21 static void hvc_call(struct pt_regs *args) 22 { 23 asm volatile( 24 "ldr x0, %0\n" 25 "ldr x1, %1\n" 26 "ldr x2, %2\n" 27 "ldr x3, %3\n" 28 "ldr x4, %4\n" 29 "ldr x5, %5\n" 30 "ldr x6, %6\n" 31 "ldr x7, %7\n" 32 "hvc #0\n" 33 "str x0, %0\n" 34 "str x1, %1\n" 35 "str x2, %2\n" 36 "str x3, %3\n" 37 : "+m" (args->regs[0]), "+m" (args->regs[1]), 38 "+m" (args->regs[2]), "+m" (args->regs[3]) 39 : "m" (args->regs[4]), "m" (args->regs[5]), 40 "m" (args->regs[6]), "m" (args->regs[7]) 41 : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 42 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 43 "x16", "x17"); 44 } 45 46 /* 47 * void smc_call(arg0, arg1...arg7) 48 * 49 * issue the secure monitor call 50 * 51 * x0~x7: input arguments 52 * x0~x3: output arguments 53 */ 54 55 void smc_call(struct pt_regs *args) 56 { 57 asm volatile( 58 "ldr x0, %0\n" 59 "ldr x1, %1\n" 60 "ldr x2, %2\n" 61 "ldr x3, %3\n" 62 "ldr x4, %4\n" 63 "ldr x5, %5\n" 64 "ldr x6, %6\n" 65 "smc #0\n" 66 "str x0, %0\n" 67 "str x1, %1\n" 68 "str x2, %2\n" 69 "str x3, %3\n" 70 : "+m" (args->regs[0]), "+m" (args->regs[1]), 71 "+m" (args->regs[2]), "+m" (args->regs[3]) 72 : "m" (args->regs[4]), "m" (args->regs[5]), 73 "m" (args->regs[6]) 74 : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 75 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 76 "x16", "x17"); 77 } 78 79 /* 80 * For now, all systems we support run at least in EL2 and thus 81 * trigger PSCI calls to EL3 using SMC. If anyone ever wants to 82 * use PSCI on U-Boot running below a hypervisor, please detect 83 * this and set the flag accordingly. 84 */ 85 static const bool use_smc_for_psci = true; 86 87 void __noreturn psci_system_reset(void) 88 { 89 struct pt_regs regs; 90 91 regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET; 92 93 if (use_smc_for_psci) 94 smc_call(®s); 95 else 96 hvc_call(®s); 97 98 while (1) 99 ; 100 } 101 102 void __noreturn psci_system_off(void) 103 { 104 struct pt_regs regs; 105 106 regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_OFF; 107 108 if (use_smc_for_psci) 109 smc_call(®s); 110 else 111 hvc_call(®s); 112 113 while (1) 114 ; 115 } 116