[PATCH 5/6] lib: utils/reset: Add syscon based reboot and poweroff

Xiang W wxjstz at 126.com
Fri Jul 28 06:42:37 PDT 2023


在 2023-07-21星期五的 22:40 +0530,Anup Patel写道:
> Let us have common FDT based reset driver for syscon reboot and
> poweroff. The device tree bindings for syscon reboot and poweroff
> are already available in the Linux kernel sources.
> 
> Signed-off-by: Anup Patel <apatel at ventanamicro.com>

Look good to me.

Reviewed-by: Xiang W <wxjstz at 126.com>
> ---
>  lib/utils/reset/Kconfig            |   5 +
>  lib/utils/reset/fdt_reset_syscon.c | 167 +++++++++++++++++++++++++++++
>  lib/utils/reset/objects.mk         |   4 +
>  platform/generic/configs/defconfig |   1 +
>  4 files changed, 177 insertions(+)
>  create mode 100644 lib/utils/reset/fdt_reset_syscon.c
> 
> diff --git a/lib/utils/reset/Kconfig b/lib/utils/reset/Kconfig
> index 4748cc8..c0b9640 100644
> --- a/lib/utils/reset/Kconfig
> +++ b/lib/utils/reset/Kconfig
> @@ -33,6 +33,11 @@ config FDT_RESET_SUNXI_WDT
>         bool "Sunxi WDT FDT reset driver"
>         default n
>  
> +config FDT_RESET_SYSCON
> +       bool "Syscon FDT reset driver"
> +       depends on FDT_REGMAP
> +       default n
> +
>  config FDT_RESET_THEAD
>         bool "T-HEAD FDT reset driver"
>         default n
> diff --git a/lib/utils/reset/fdt_reset_syscon.c b/lib/utils/reset/fdt_reset_syscon.c
> new file mode 100644
> index 0000000..bae9ec5
> --- /dev/null
> +++ b/lib/utils/reset/fdt_reset_syscon.c
> @@ -0,0 +1,167 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2023 Ventana Micro Systems Inc.
> + *
> + * Authors:
> + *   Anup Patel <apatel at ventanamicro.com>
> + */
> +
> +#include <libfdt.h>
> +#include <sbi/sbi_ecall_interface.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_hart.h>
> +#include <sbi/sbi_system.h>
> +#include <sbi_utils/fdt/fdt_helper.h>
> +#include <sbi_utils/regmap/fdt_regmap.h>
> +#include <sbi_utils/reset/fdt_reset.h>
> +
> +struct syscon_reset {
> +       struct regmap *rmap;
> +       u32 priority;
> +       u32 offset;
> +       u32 value;
> +       u32 mask;
> +};
> +
> +static struct syscon_reset poweroff;
> +static struct syscon_reset reboot;
> +
> +static struct syscon_reset *syscon_reset_get(bool is_reboot, u32 type)
> +{
> +       struct syscon_reset *reset = NULL;
> +
> +       switch (type) {
> +       case SBI_SRST_RESET_TYPE_SHUTDOWN:
> +               if (!is_reboot)
> +                       reset = &poweroff;
> +               break;
> +       case SBI_SRST_RESET_TYPE_COLD_REBOOT:
> +       case SBI_SRST_RESET_TYPE_WARM_REBOOT:
> +               if (is_reboot)
> +                       reset = &reboot;
> +               break;
> +       }
> +
> +       if (reset && !reset->rmap)
> +               reset = NULL;
> +
> +       return reset;
> +}
> +
> +static void syscon_reset_exec(struct syscon_reset *reset)
> +{
> +       /* Issue the reset through regmap */
> +       if (reset)
> +               regmap_update_bits(reset->rmap, reset->offset,
> +                                  reset->mask, reset->value);
> +
> +       /* hang !!! */
> +       sbi_hart_hang();
> +}
> +
> +static int syscon_poweroff_check(u32 type, u32 reason)
> +{
> +       struct syscon_reset *reset = syscon_reset_get(false, type);
> +
> +       return (reset) ? reset->priority : 0;
> +}
> +
> +static void syscon_do_poweroff(u32 type, u32 reason)
> +{
> +       syscon_reset_exec(syscon_reset_get(false, type));
> +}
> +
> +static struct sbi_system_reset_device syscon_poweroff = {
> +       .name = "syscon-poweroff",
> +       .system_reset_check = syscon_poweroff_check,
> +       .system_reset = syscon_do_poweroff
> +};
> +
> +static int syscon_reboot_check(u32 type, u32 reason)
> +{
> +       struct syscon_reset *reset = syscon_reset_get(true, type);
> +
> +       return (reset) ? reset->priority : 0;
> +}
> +
> +static void syscon_do_reboot(u32 type, u32 reason)
> +{
> +       syscon_reset_exec(syscon_reset_get(true, type));
> +}
> +
> +static struct sbi_system_reset_device syscon_reboot = {
> +       .name = "syscon-reboot",
> +       .system_reset_check = syscon_reboot_check,
> +       .system_reset = syscon_do_reboot
> +};
> +
> +static int syscon_reset_init(void *fdt, int nodeoff,
> +                          const struct fdt_match *match)
> +{
> +       int rc, len;
> +       const fdt32_t *val, *mask;
> +       bool is_reboot = (ulong)match->data;
> +       struct syscon_reset *reset = (is_reboot) ? &reboot : &poweroff;
> +
> +       if (reset->rmap)
> +               return SBI_EALREADY;
> +
> +       rc = fdt_regmap_get(fdt, nodeoff, &reset->rmap);
> +       if (rc)
> +               return rc;
> +
> +       val = fdt_getprop(fdt, nodeoff, "priority", &len);
> +       reset->priority = (val && len > 0) ? fdt32_to_cpu(*val) : 192;
> +
> +       val = fdt_getprop(fdt, nodeoff, "offset", &len);
> +       if (val && len > 0)
> +               reset->offset = fdt32_to_cpu(*val);
> +       else
> +               return SBI_EINVAL;
> +
> +       val = fdt_getprop(fdt, nodeoff, "value", &len);
> +       mask = fdt_getprop(fdt, nodeoff, "mask", &len);
> +       if (!val && !mask)
> +               return SBI_EINVAL;
> +
> +       if (!val) {
> +               /* support old binding */
> +               reset->value = fdt32_to_cpu(*mask);
> +               reset->mask = 0xFFFFFFFF;
> +       } else if (!mask) {
> +               /* support value without mask */
> +               reset->value = fdt32_to_cpu(*val);
> +               reset->mask = 0xFFFFFFFF;
> +       } else {
> +               reset->value = fdt32_to_cpu(*val);
> +               reset->mask = fdt32_to_cpu(*mask);
> +       }
> +
> +       if (is_reboot)
> +               sbi_system_reset_add_device(&syscon_reboot);
> +       else
> +               sbi_system_reset_add_device(&syscon_poweroff);
> +
> +       return 0;
> +}
> +
> +static const struct fdt_match syscon_poweroff_match[] = {
> +       { .compatible = "syscon-poweroff", .data = (const void *)false },
> +       { },
> +};
> +
> +struct fdt_reset fdt_syscon_poweroff = {
> +       .match_table = syscon_poweroff_match,
> +       .init = syscon_reset_init,
> +};
> +
> +static const struct fdt_match syscon_reboot_match[] = {
> +       { .compatible = "syscon-reboot", .data = (const void *)true },
> +       { },
> +};
> +
> +struct fdt_reset fdt_syscon_reboot = {
> +       .match_table = syscon_reboot_match,
> +       .init = syscon_reset_init,
> +};
> diff --git a/lib/utils/reset/objects.mk b/lib/utils/reset/objects.mk
> index c9f851c..17287a5 100644
> --- a/lib/utils/reset/objects.mk
> +++ b/lib/utils/reset/objects.mk
> @@ -26,6 +26,10 @@ libsbiutils-objs-$(CONFIG_FDT_RESET_SIFIVE_TEST) += reset/fdt_reset_sifive_test.
>  carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SUNXI_WDT) += fdt_reset_sunxi_wdt
>  libsbiutils-objs-$(CONFIG_FDT_RESET_SUNXI_WDT) += reset/fdt_reset_sunxi_wdt.o
>  
> +carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SYSCON) += fdt_syscon_poweroff
> +carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SYSCON) += fdt_syscon_reboot
> +libsbiutils-objs-$(CONFIG_FDT_RESET_SYSCON) += reset/fdt_reset_syscon.o
> +
>  carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_THEAD) += fdt_reset_thead
>  libsbiutils-objs-$(CONFIG_FDT_RESET_THEAD) += reset/fdt_reset_thead.o
>  libsbiutils-objs-$(CONFIG_FDT_RESET_THEAD) += reset/fdt_reset_thead_asm.o
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index b767290..5008c7e 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -26,6 +26,7 @@ CONFIG_FDT_RESET_GPIO=y
>  CONFIG_FDT_RESET_HTIF=y
>  CONFIG_FDT_RESET_SIFIVE_TEST=y
>  CONFIG_FDT_RESET_SUNXI_WDT=y
> +CONFIG_FDT_RESET_SYSCON=y
>  CONFIG_FDT_RESET_THEAD=y
>  CONFIG_FDT_SERIAL=y
>  CONFIG_FDT_SERIAL_CADENCE=y
> -- 
> 2.34.1
> 
> 



More information about the opensbi mailing list