uboot/arch/arm/cpu/armv8/fwcall.c
<<
>>
Prefs
   1/**
   2 * (C) Copyright 2014, Cavium Inc.
   3 * (C) Copyright 2017, Xilinx Inc.
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   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 */
  22static 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
  56void __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 */
  86static const __efi_runtime_data bool use_smc_for_psci = true;
  87
  88void __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(&regs);
  96        else
  97                hvc_call(&regs);
  98
  99        while (1)
 100                ;
 101}
 102
 103void __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(&regs);
 111        else
 112                hvc_call(&regs);
 113
 114        while (1)
 115                ;
 116}
 117
 118#ifdef CONFIG_CMD_POWEROFF
 119int 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
 135void reset_misc(void)
 136{
 137        psci_system_reset();
 138}
 139
 140#ifdef CONFIG_EFI_LOADER
 141void __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        switch (reset_type) {
 147        case EFI_RESET_COLD:
 148        case EFI_RESET_WARM:
 149                psci_system_reset();
 150                break;
 151        case EFI_RESET_SHUTDOWN:
 152                psci_system_off();
 153                break;
 154        }
 155
 156        while (1) { }
 157}
 158#endif /* CONFIG_EFI_LOADER */
 159#endif /* CONFIG_PSCI_RESET */
 160