1 /** 2 * (C) Copyright 2014, Cavium Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 **/ 6 7 #include <asm-offsets.h> 8 #include <config.h> 9 #include <efi_loader.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 __efi_runtime 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 __efi_runtime 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 __efi_runtime_data bool use_smc_for_psci = true; 86 87 void __noreturn __efi_runtime 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 __efi_runtime 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 117 #ifdef CONFIG_PSCI_RESET 118 void reset_misc(void) 119 { 120 psci_system_reset(); 121 } 122 123 #ifdef CONFIG_EFI_LOADER 124 void __efi_runtime EFIAPI efi_reset_system( 125 enum efi_reset_type reset_type, 126 efi_status_t reset_status, 127 unsigned long data_size, void *reset_data) 128 { 129 switch (reset_type) { 130 case EFI_RESET_COLD: 131 case EFI_RESET_WARM: 132 psci_system_reset(); 133 break; 134 case EFI_RESET_SHUTDOWN: 135 psci_system_off(); 136 break; 137 } 138 139 while (1) { } 140 } 141 #endif /* CONFIG_EFI_LOADER */ 142 #endif /* CONFIG_PSCI_RESET */ 143