diff --git a/lib/utils/reset/fdt_reset.c b/lib/utils/reset/fdt_reset.c index 7f4b02a4..168bb0c1 100644 --- a/lib/utils/reset/fdt_reset.c +++ b/lib/utils/reset/fdt_reset.c @@ -16,6 +16,7 @@ extern struct fdt_reset fdt_poweroff_gpio; extern struct fdt_reset fdt_reset_gpio; extern struct fdt_reset fdt_reset_htif; extern struct fdt_reset fdt_reset_sifive_test; +extern struct fdt_reset fdt_reset_sunxi_wdt; extern struct fdt_reset fdt_reset_thead; static struct fdt_reset *reset_drivers[] = { @@ -23,6 +24,7 @@ static struct fdt_reset *reset_drivers[] = { &fdt_reset_gpio, &fdt_reset_htif, &fdt_reset_sifive_test, + &fdt_reset_sunxi_wdt, &fdt_reset_thead, }; diff --git a/lib/utils/reset/fdt_reset_sunxi_wdt.c b/lib/utils/reset/fdt_reset_sunxi_wdt.c new file mode 100644 index 00000000..e4f16e3b --- /dev/null +++ b/lib/utils/reset/fdt_reset_sunxi_wdt.c @@ -0,0 +1,77 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021 Samuel Holland + */ + +#include +#include +#include +#include +#include +#include +#include + +#define WDT_KEY_VAL 0x16aa0000 + +#define WDT_SOFT_RST_REG 0x08 +#define WDT_SOFT_RST_EN BIT(0) + +#define WDT_MODE_REG 0x18 + +static volatile void *sunxi_wdt_base; + +static int sunxi_wdt_system_reset_check(u32 type, u32 reason) +{ + switch (type) { + case SBI_SRST_RESET_TYPE_COLD_REBOOT: + case SBI_SRST_RESET_TYPE_WARM_REBOOT: + return 1; + } + + return 0; +} + +static void sunxi_wdt_system_reset(u32 type, u32 reason) +{ + /* Disable the watchdog. */ + writel_relaxed(WDT_KEY_VAL, + sunxi_wdt_base + WDT_MODE_REG); + + /* Trigger soft reset. */ + writel_relaxed(WDT_KEY_VAL | WDT_SOFT_RST_EN, + sunxi_wdt_base + WDT_SOFT_RST_REG); +} + +static struct sbi_system_reset_device sunxi_wdt_reset = { + .name = "sunxi-wdt-reset", + .system_reset_check = sunxi_wdt_system_reset_check, + .system_reset = sunxi_wdt_system_reset, +}; + +static int sunxi_wdt_reset_init(void *fdt, int nodeoff, + const struct fdt_match *match) +{ + uint64_t reg_addr; + int rc; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, NULL); + if (rc < 0 || !reg_addr) + return SBI_ENODEV; + + sunxi_wdt_base = (volatile void *)(unsigned long)reg_addr; + + sbi_system_reset_set_device(&sunxi_wdt_reset); + + return 0; +} + +static const struct fdt_match sunxi_wdt_reset_match[] = { + { .compatible = "allwinner,sun20i-d1-wdt-reset" }, + { }, +}; + +struct fdt_reset fdt_reset_sunxi_wdt = { + .match_table = sunxi_wdt_reset_match, + .init = sunxi_wdt_reset_init, +}; diff --git a/lib/utils/reset/objects.mk b/lib/utils/reset/objects.mk index bb33179b..6c95db39 100644 --- a/lib/utils/reset/objects.mk +++ b/lib/utils/reset/objects.mk @@ -11,5 +11,6 @@ libsbiutils-objs-y += reset/fdt_reset.o libsbiutils-objs-y += reset/fdt_reset_gpio.o libsbiutils-objs-y += reset/fdt_reset_htif.o libsbiutils-objs-y += reset/fdt_reset_sifive_test.o +libsbiutils-objs-y += reset/fdt_reset_sunxi_wdt.o libsbiutils-objs-y += reset/fdt_reset_thead.o libsbiutils-objs-y += reset/fdt_reset_thead_asm.o