[U-Boot] [PATCH 0/2] Watchdog: Add support for sunxi hardware watchdog

The following patches are needed to add support for the hardware watchdog found in most sunxi SoC's.
The patches below have only been tested on a sun50i device (H5 SoC) and work as expected. The actual sunxi_wdt.c was roughly based off of the mainline linux driver, and is enabled by adding CONFIG_SUNXI_WDT to your config. It is not enabled by default.
Chris Blake (2): watchdog: Fix SPL builds when watchdog is enabled watchdog: Add sunxi watchdog driver
common/board_f.c | 3 +- drivers/watchdog/Kconfig | 18 ++++++++ drivers/watchdog/Makefile | 1 + drivers/watchdog/sunxi_wdt.c | 103 +++++++++++++++++++++++++++++++++++++++++++ include/watchdog.h | 4 +- 5 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 drivers/watchdog/sunxi_wdt.c

Without this fix, u-boot fails to comple as it tries to load watchdog.h during an SPL build. This breaks support for things such as the sunxi arch.
Signed-off-by: Chris Blake chrisrblake93@gmail.com --- include/watchdog.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/watchdog.h b/include/watchdog.h index 14073cf..555f058 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -20,7 +20,7 @@ int init_func_watchdog_reset(void); #endif
-#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG) +#if (defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG)) && !defined(CONFIG_SPL_BUILD) #define INIT_FUNC_WATCHDOG_INIT init_func_watchdog_init, #define INIT_FUNC_WATCHDOG_RESET init_func_watchdog_reset, #else @@ -47,7 +47,7 @@ int init_func_watchdog_reset(void); /* * Maybe a software watchdog? */ - #if defined(CONFIG_WATCHDOG) + #if defined(CONFIG_WATCHDOG) && !defined(CONFIG_SPL_BUILD) #if defined(__ASSEMBLY__) #define WATCHDOG_RESET bl watchdog_reset #else

On Tue, Sep 4, 2018 at 6:36 AM, Chris Blake chrisrblake93@gmail.com wrote:
Without this fix, u-boot fails to comple as it tries to load watchdog.h during an SPL build. This breaks support for things such as the sunxi arch.
I'm not quite clear about the issue, was it a build break or functionality? better to paste the log or elaborate more can helpful.

Based on the linux mainline driver, this adds support for the hardware watchdog timer found on some sunxi boards.
Signed-off-by: Chris Blake chrisrblake93@gmail.com --- common/board_f.c | 3 +- drivers/watchdog/Kconfig | 18 ++++++++ drivers/watchdog/Makefile | 1 + drivers/watchdog/sunxi_wdt.c | 103 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 drivers/watchdog/sunxi_wdt.c
diff --git a/common/board_f.c b/common/board_f.c index 88d7700..7b0d912 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -91,7 +91,8 @@ static int init_func_watchdog_init(void) (defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \ defined(CONFIG_SH) || defined(CONFIG_AT91SAM9_WATCHDOG) || \ defined(CONFIG_DESIGNWARE_WATCHDOG) || \ - defined(CONFIG_IMX_WATCHDOG)) + defined(CONFIG_IMX_WATCHDOG) || \ + defined(CONFIG_SUNXI_WDT)) hw_watchdog_init(); puts(" Watchdog enabled\n"); # endif diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index d545b3e..bd09dad 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -20,6 +20,24 @@ config BCM2835_WDT This provides basic infrastructure to support BCM2835/2836 watchdog hardware, with a max timeout of ~15secs.
+config SUNXI_WDT + bool "SUNXI watchdog timer support" + select HW_WATCHDOG + help + Select this to enable the SUNXI watchdog timer. + +if SUNXI_WDT + +config SUNXI_WDT_TIMEOUT + int "SUNXI watchdog timeout setting" + default 10 + range 1 16 + depends on SUNXI_WDT + help + Adjust the timeout window for the SUNXI watchdog timer. + +endif + config OMAP_WATCHDOG bool "TI OMAP watchdog driver" depends on ARCH_OMAP2PLUS diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index f405f51..ce27bb5 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o +obj-$(CONFIG_SUNXI_WDT) += sunxi_wdt.o diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c new file mode 100644 index 0000000..9d88b86 --- /dev/null +++ b/drivers/watchdog/sunxi_wdt.c @@ -0,0 +1,103 @@ +/* + * (C) Copyright 2018 Chris Blake <chrisrblake93 at gmail.com> + * Roughly based on the mainline linux driver, sunxi_wdt.c + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +#include <common.h> +#include <watchdog.h> +#include <asm/arch/timer.h> +#include <asm/io.h> + +#define WDT_CTRL_RESTART (0x1 << 0) +#define WDT_CTRL_KEY (0x0a57 << 1) +#define WDT_MODE_EN (0x1 << 0) +#define WDT_TIMEOUT_MASK (0xf) + +struct sunxi_wdt_reg { + u32 wdt_ctrl; + u32 wdt_cfg; + u32 wdt_mode; + u32 wdt_timeout_shift; + u32 wdt_reset_mask; + u32 wdt_reset_val; +}; + +static const struct sunxi_wdt_reg sun4i_wdt_reg = { + .wdt_ctrl = 0x00, + .wdt_cfg = 0x04, + .wdt_mode = 0x04, + .wdt_timeout_shift = 3, + .wdt_reset_mask = 0x02, + .wdt_reset_val = 0x02, +}; + +static const struct sunxi_wdt_reg sun6i_dog_regs = { + .wdt_ctrl = 0x10, + .wdt_cfg = 0x14, + .wdt_mode = 0x18, + .wdt_timeout_shift = 4, + .wdt_reset_mask = 0x03, + .wdt_reset_val = 0x01, +}; + +static const int wdt_timeout_map[] = { + [1] = 0x1, /* 1s */ + [2] = 0x2, /* 2s */ + [3] = 0x3, /* 3s */ + [4] = 0x4, /* 4s */ + [5] = 0x5, /* 5s */ + [6] = 0x6, /* 6s */ + [8] = 0x7, /* 8s */ + [10] = 0x8, /* 10s */ + [12] = 0x9, /* 12s */ + [14] = 0xA, /* 14s */ + [16] = 0xB, /* 16s */ +}; + +#if defined(CONFIG_SUNXI_GEN_SUN6I) +static const struct sunxi_wdt_reg *regs = &sun6i_dog_regs; +#else +static const struct sunxi_wdt_reg *regs = &sun4i_dog_regs; +#endif + +static void *wdt_base = &((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog; + +void hw_watchdog_reset(void) +{ + /* reload the watchdog */ + writel(WDT_CTRL_KEY | WDT_CTRL_RESTART, wdt_base + regs->wdt_ctrl); +} + +void hw_watchdog_disable(void) +{ + /* Reset WDT Config */ + writel(0, wdt_base + regs->wdt_mode); +} + +void hw_watchdog_init(void) +{ + const u32 timeout = CONFIG_SUNXI_WDT_TIMEOUT; + u32 reg; + + reg = readl(wdt_base + regs->wdt_mode); + reg &= ~(WDT_TIMEOUT_MASK << regs->wdt_timeout_shift); + reg |= wdt_timeout_map[timeout] << regs->wdt_timeout_shift; + writel(reg, wdt_base + regs->wdt_mode); + + hw_watchdog_reset(); + + /* Set system reset function */ + reg = readl(wdt_base + regs->wdt_cfg); + reg &= ~(regs->wdt_reset_mask); + reg |= regs->wdt_reset_val; + writel(reg, wdt_base + regs->wdt_cfg); + + /* Enable watchdog */ + reg = readl(wdt_base + regs->wdt_mode); + reg |= WDT_MODE_EN; + writel(reg, wdt_base + regs->wdt_mode); + }

On Tue, Sep 4, 2018 at 6:36 AM, Chris Blake chrisrblake93@gmail.com wrote:
Based on the linux mainline driver, this adds support for the hardware watchdog timer found on some sunxi boards.
This has to do it via UCLASS_WDT and there is enough sunxi code using watchdog so update the same accordingly.
participants (2)
-
Chris Blake
-
Jagan Teki