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