From f606c9a8959728f7df539e182fb799d3ccc92cc6 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Mon, 15 Nov 2021 23:45:43 +0100 Subject: watchdog: add sl28cpld watchdog driver The watchdog timer is part of the sl28cpld management controller. The watchdog timer usually supervises the bootloader boot-up and if it bites the failsafe bootloader will be activated. Apart from that it supports the usual board level reset and one SMARC speciality: driving the WDT_TIMEOUT# signal. Signed-off-by: Michael Walle Reviewed-by: Priyanka Jain --- drivers/watchdog/Kconfig | 7 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/sl28cpld-wdt.c | 109 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 drivers/watchdog/sl28cpld-wdt.c (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index cabac29053..f90f0ca02b 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -266,6 +266,13 @@ config WDT_SBSA In the single stage mode, when the timeout is reached, your system will be reset by WS1. The first signal (WS0) is ignored. +config WDT_SL28CPLD + bool "sl28cpld watchdog timer support" + depends on WDT && SL28CPLD + help + Enable support for the watchdog timer in the Kontron sl28cpld + management controller. + config WDT_SP805 bool "SP805 watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 6d2b3822c0..a35bd559f5 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o +obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o obj-$(CONFIG_WDT_SP805) += sp805_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o diff --git a/drivers/watchdog/sl28cpld-wdt.c b/drivers/watchdog/sl28cpld-wdt.c new file mode 100644 index 0000000000..af5a6b1a28 --- /dev/null +++ b/drivers/watchdog/sl28cpld-wdt.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for the sl28cpld + * + * Copyright (c) 2021 Michael Walle + */ + +#include +#include +#include +#include +#include + +#define SL28CPLD_WDT_CTRL 0x00 +#define WDT_CTRL_EN0 BIT(0) +#define WDT_CTRL_EN1 BIT(1) +#define WDT_CTRL_EN_MASK GENMASK(1, 0) +#define WDT_CTRL_LOCK BIT(2) +#define WDT_CTRL_ASSERT_SYS_RESET BIT(6) +#define WDT_CTRL_ASSERT_WDT_TIMEOUT BIT(7) +#define SL28CPLD_WDT_TIMEOUT 0x01 +#define SL28CPLD_WDT_KICK 0x02 +#define WDT_KICK_VALUE 0x6b + +static int sl28cpld_wdt_reset(struct udevice *dev) +{ + return sl28cpld_write(dev, SL28CPLD_WDT_KICK, WDT_KICK_VALUE); +} + +static int sl28cpld_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + int ret, val; + + val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL); + if (val < 0) + return val; + + /* (1) disable watchdog */ + val &= ~WDT_CTRL_EN_MASK; + ret = sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val); + if (ret) + return ret; + + /* (2) set timeout */ + ret = sl28cpld_write(dev, SL28CPLD_WDT_TIMEOUT, lldiv(timeout, 1000)); + if (ret) + return ret; + + /* (3) kick it, will reset timer to the timeout value */ + ret = sl28cpld_wdt_reset(dev); + if (ret) + return ret; + + /* (4) enable either recovery or normal one */ + if (flags & BIT(0)) + val |= WDT_CTRL_EN1; + else + val |= WDT_CTRL_EN0; + + if (flags & BIT(1)) + val |= WDT_CTRL_LOCK; + + if (flags & BIT(2)) + val &= ~WDT_CTRL_ASSERT_SYS_RESET; + else + val |= WDT_CTRL_ASSERT_SYS_RESET; + + if (flags & BIT(3)) + val |= WDT_CTRL_ASSERT_WDT_TIMEOUT; + else + val &= ~WDT_CTRL_ASSERT_WDT_TIMEOUT; + + return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val); +} + +static int sl28cpld_wdt_stop(struct udevice *dev) +{ + int val; + + val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL); + if (val < 0) + return val; + + return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val & ~WDT_CTRL_EN_MASK); +} + +static int sl28cpld_wdt_expire_now(struct udevice *dev, ulong flags) +{ + return sl28cpld_wdt_start(dev, 0, flags); +} + +static const struct wdt_ops sl28cpld_wdt_ops = { + .start = sl28cpld_wdt_start, + .reset = sl28cpld_wdt_reset, + .stop = sl28cpld_wdt_stop, + .expire_now = sl28cpld_wdt_expire_now, +}; + +static const struct udevice_id sl28cpld_wdt_ids[] = { + { .compatible = "kontron,sl28cpld-wdt", }, + {} +}; + +U_BOOT_DRIVER(sl28cpld_wdt) = { + .name = "sl28cpld-wdt", + .id = UCLASS_WDT, + .of_match = sl28cpld_wdt_ids, + .ops = &sl28cpld_wdt_ops, +}; -- cgit v1.2.3