Provide sysreset driver using the SBI system reset extension. Signed-off-by: Heinrich Schuchardt <xypron.g...@gmx.de> --- v3: no change --- MAINTAINERS | 1 + arch/riscv/cpu/cpu.c | 13 ++++- arch/riscv/include/asm/sbi.h | 1 + arch/riscv/lib/sbi.c | 21 ++++++-- drivers/sysreset/Kconfig | 11 ++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset_sbi.c | 96 +++++++++++++++++++++++++++++++++ lib/efi_loader/Kconfig | 2 +- 8 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 drivers/sysreset/sysreset_sbi.c
diff --git a/MAINTAINERS b/MAINTAINERS index 4cf0c33c5d..88d7aa2bc7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1017,6 +1017,7 @@ T: git https://source.denx.de/u-boot/custodians/u-boot-riscv.git F: arch/riscv/ F: cmd/riscv/ F: doc/usage/sbi.rst +F: drivers/sysreset/sysreset_sbi.c F: drivers/timer/andes_plmt_timer.c F: drivers/timer/sifive_clint_timer.c F: tools/prelink-riscv.c diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index c894ac10b5..8e49b6d736 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -6,6 +6,7 @@ #include <common.h> #include <cpu.h> #include <dm.h> +#include <dm/lists.h> #include <init.h> #include <log.h> #include <asm/encoding.h> @@ -138,7 +139,17 @@ int arch_cpu_init_dm(void) int arch_early_init_r(void) { - return riscv_cpu_probe(); + int ret; + + ret = riscv_cpu_probe(); + if (ret) + return ret; + + if (IS_ENABLED(CONFIG_SYSRESET_SBI)) + device_bind_driver(gd->dm_root, "sbi-sysreset", + "sbi-sysreset", NULL); + + return 0; } /** diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index e9caa78d17..69cddda245 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -154,5 +154,6 @@ void sbi_set_timer(uint64_t stime_value); long sbi_get_spec_version(void); int sbi_get_impl_id(void); int sbi_probe_extension(int ext); +void sbi_srst_reset(unsigned long type, unsigned long reason); #endif diff --git a/arch/riscv/lib/sbi.c b/arch/riscv/lib/sbi.c index 77845a73ca..8508041f2a 100644 --- a/arch/riscv/lib/sbi.c +++ b/arch/riscv/lib/sbi.c @@ -8,13 +8,14 @@ */ #include <common.h> +#include <efi_loader.h> #include <asm/encoding.h> #include <asm/sbi.h> -struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, - unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5) +struct sbiret __efi_runtime sbi_ecall(int ext, int fid, unsigned long arg0, + unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, + unsigned long arg5) { struct sbiret ret; @@ -108,6 +109,18 @@ int sbi_probe_extension(int extid) return -ENOTSUPP; } +/** + * sbi_srst_reset() - invoke system reset extension + * + * @type: type of reset + * @reason: reason for reset + */ +void __efi_runtime sbi_srst_reset(unsigned long type, unsigned long reason) +{ + sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason, + 0, 0, 0, 0); +} + #ifdef CONFIG_SBI_V01 /** diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index ac77ffbc8b..6782331181 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -85,6 +85,17 @@ config SYSRESET_PSCI Enable PSCI SYSTEM_RESET function call. To use this, PSCI firmware must be running on your system. +config SYSRESET_SBI + bool "Enable support for SBI System Reset" + depends on RISCV_SMODE && SBI_V02 + select SYSRESET_CMD_POWEROFF if CMD_POWEROFF + help + Enable system reset and poweroff via the SBI system reset extension. + If the SBI implementation provides the extension, is board specific. + The extension was introduced in version 0.3 of the SBI specification. + The SBI system reset driver supports the UEFI ResetSystem() service + at runtime. + config SYSRESET_SOCFPGA bool "Enable support for Intel SOCFPGA family" depends on ARCH_SOCFPGA && (TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10) diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index de81c399d7..8e00be0779 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o +obj-$(CONFIG_SYSRESET_SBI) += sysreset_sbi.o obj-$(CONFIG_SYSRESET_SOCFPGA) += sysreset_socfpga.o obj-$(CONFIG_SYSRESET_SOCFPGA_SOC64) += sysreset_socfpga_soc64.o obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o diff --git a/drivers/sysreset/sysreset_sbi.c b/drivers/sysreset/sysreset_sbi.c new file mode 100644 index 0000000000..fec5a66515 --- /dev/null +++ b/drivers/sysreset/sysreset_sbi.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021, Heinrich Schuchardt <xypron.g...@gmx.de> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <efi_loader.h> +#include <log.h> +#include <sysreset.h> +#include <asm/sbi.h> + +static long __efi_runtime_data have_reset; + +static int sbi_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + enum sbi_srst_reset_type reset_type; + + switch (type) { + case SYSRESET_WARM: + reset_type = SBI_SRST_RESET_TYPE_WARM_REBOOT; + break; + case SYSRESET_COLD: + reset_type = SBI_SRST_RESET_TYPE_COLD_REBOOT; + break; + case SYSRESET_POWER_OFF: + reset_type = SBI_SRST_RESET_TYPE_SHUTDOWN; + break; + default: + log_err("SBI has no system reset extension\n"); + return -ENOSYS; + } + + sbi_srst_reset(reset_type, SBI_SRST_RESET_REASON_NONE); + + return -EINPROGRESS; +} + +efi_status_t efi_reset_system_init(void) +{ + return EFI_SUCCESS; +} + +void __efi_runtime EFIAPI efi_reset_system(enum efi_reset_type type, + efi_status_t reset_status, + unsigned long data_size, + void *reset_data) +{ + enum sbi_srst_reset_type reset_type; + enum sbi_srst_reset_reason reset_reason; + + if (have_reset) + switch (type) { + case SYSRESET_COLD: + reset_type = SBI_SRST_RESET_TYPE_COLD_REBOOT; + break; + case SYSRESET_POWER_OFF: + reset_type = SBI_SRST_RESET_TYPE_SHUTDOWN; + break; + default: + reset_type = SBI_SRST_RESET_TYPE_WARM_REBOOT; + break; + } + + if (reset_status == EFI_SUCCESS) + reset_reason = SBI_SRST_RESET_REASON_NONE; + else + reset_reason = SBI_SRST_RESET_REASON_SYS_FAILURE; + + sbi_srst_reset(reset_type, reset_reason); + + while (1) + ; +} + +static int sbi_sysreset_probe(struct udevice *dev) +{ + have_reset = sbi_probe_extension(SBI_EXT_SRST); + if (have_reset) + return 0; + + log_warning("SBI has no system reset extension\n"); + return -ENOENT; +} + +static struct sysreset_ops sbi_sysreset_ops = { + .request = sbi_sysreset_request, +}; + +U_BOOT_DRIVER(sbi_sysreset) = { + .name = "sbi-sysreset", + .id = UCLASS_SYSRESET, + .ops = &sbi_sysreset_ops, + .probe = sbi_sysreset_probe, +}; diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index dacc3b5881..36985fce2c 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -297,7 +297,7 @@ config EFI_HAVE_RUNTIME_RESET bool default y depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || \ - SANDBOX || SYSRESET_X86 + SANDBOX || SYSRESET_SBI || SYSRESET_X86 config EFI_GRUB_ARM32_WORKAROUND bool "Workaround for GRUB on 32bit ARM" -- 2.30.2