sysreset: provide SBI based sysreset driver
authorHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Sun, 12 Sep 2021 19:11:46 +0000 (21:11 +0200)
committerLeo Yu-Chi Liang <ycliang@andestech.com>
Thu, 7 Oct 2021 08:08:23 +0000 (16:08 +0800)
Provide sysreset driver using the SBI system reset extension.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Samuel Holland <samuel@sholland.org>
MAINTAINERS
arch/riscv/cpu/cpu.c
arch/riscv/include/asm/sbi.h
arch/riscv/lib/sbi.c
drivers/sysreset/Kconfig
drivers/sysreset/Makefile
drivers/sysreset/sysreset_sbi.c [new file with mode: 0644]

index 31b49c0..71f468c 100644 (file)
@@ -1026,6 +1026,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
index c894ac1..8e49b6d 100644 (file)
@@ -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;
 }
 
 /**
index 34a115a..5030892 100644 (file)
@@ -153,5 +153,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
index 77845a7..2b53896 100644 (file)
@@ -108,6 +108,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 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
 
 /**
index ac77ffb..43a948c 100644 (file)
@@ -85,6 +85,18 @@ 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.
+         The extension was introduced in version 0.3 of the SBI specification.
+
+         If the SBI implementation provides the extension, is board specific.
+         The RISC-V platform specification mandates the extension for rich
+         operating system platforms.
+
 config SYSRESET_SOCFPGA
        bool "Enable support for Intel SOCFPGA family"
        depends on ARCH_SOCFPGA && (TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10)
index de81c39..8e00be0 100644 (file)
@@ -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 (file)
index 0000000..5e8090d
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021, Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <sysreset.h>
+#include <asm/sbi.h>
+
+static enum sbi_srst_reset_type reset_type_map[SYSRESET_COUNT] = {
+       [SYSRESET_WARM] = SBI_SRST_RESET_TYPE_WARM_REBOOT,
+       [SYSRESET_COLD] = SBI_SRST_RESET_TYPE_COLD_REBOOT,
+       [SYSRESET_POWER] = SBI_SRST_RESET_TYPE_COLD_REBOOT,
+       [SYSRESET_POWER_OFF] = SBI_SRST_RESET_TYPE_SHUTDOWN,
+};
+
+static int sbi_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+       enum sbi_srst_reset_type reset_type;
+
+       reset_type = reset_type_map[type];
+       sbi_srst_reset(reset_type, SBI_SRST_RESET_REASON_NONE);
+
+       return -EINPROGRESS;
+}
+
+static int sbi_sysreset_probe(struct udevice *dev)
+{
+       long have_reset;
+
+       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,
+};