From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jan Kiszka Date: Tue, 23 Jun 2020 14:26:28 +0200 Subject: [PATCH v2 1/3] watchdog: Add support for K3 RTI watchdog In-Reply-To: References: <6a9a9f9c875c6cd3e0c1738297f81da150e45bcd.1592910910.git.jan.kiszka@siemens.com> Message-ID: <565a2ade-9d58-71fd-1d69-ada4d7764e47@siemens.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On 23.06.20 13:47, Lokesh Vutla wrote: > > > On 23/06/20 4:45 pm, Jan Kiszka wrote: >> From: Jan Kiszka >> >> This is based on the Linux kernel driver for the RTI watchdog. >> >> To actually reset the system on an AM65x, it requires firmware running >> on the R5 that accepts the NMI and issues the actual system reset via >> TISCI. Kind of an iTCO, except that this watchdog hardware has support >> for no-way-out, and only for that. >> >> On the J721E, reset works without extra firmware help when routing the >> RTI interrupt via the ESM. >> >> Signed-off-by: Jan Kiszka >> --- >> drivers/watchdog/Kconfig | 7 +++ >> drivers/watchdog/Makefile | 1 + >> drivers/watchdog/rti_wdt.c | 123 +++++++++++++++++++++++++++++++++++++ >> 3 files changed, 131 insertions(+) >> create mode 100644 drivers/watchdog/rti_wdt.c >> >> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig >> index bf06180cdd..ee99bd2af1 100644 >> --- a/drivers/watchdog/Kconfig >> +++ b/drivers/watchdog/Kconfig >> @@ -155,6 +155,13 @@ config WDT_ORION >> Select this to enable Orion watchdog timer, which can be found on some >> Marvell Armada chips. >> >> +config WDT_K3_RTI >> + bool "Texas Instruments K3 RTI watchdog" >> + depends on WDT && ARCH_K3 >> + help >> + Say Y here if you want to include support for the K3 watchdog >> + timer (RTI module) available in the K3 generation of processors. >> + >> config WDT_SANDBOX >> bool "Enable Watchdog Timer support for Sandbox" >> depends on SANDBOX && WDT >> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile >> index 519bbd3a40..16bdbf4970 100644 >> --- a/drivers/watchdog/Makefile >> +++ b/drivers/watchdog/Makefile >> @@ -27,6 +27,7 @@ obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o >> obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o >> obj-$(CONFIG_WDT_MTK) += mtk_wdt.o >> obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o >> +obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o >> obj-$(CONFIG_WDT_SP805) += sp805_wdt.o >> obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o >> obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o >> diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c >> new file mode 100644 >> index 0000000000..ebe29c7409 >> --- /dev/null >> +++ b/drivers/watchdog/rti_wdt.c >> @@ -0,0 +1,123 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Copyright (c) Siemens AG, 2020 >> + * >> + * Authors: >> + * Jan Kiszka >> + * >> + * Derived from linux/drivers/watchdog/rti_wdt.c >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +/* Timer register set definition */ >> +#define RTIDWDCTRL 0x90 >> +#define RTIDWDPRLD 0x94 >> +#define RTIWDSTATUS 0x98 >> +#define RTIWDKEY 0x9c >> +#define RTIDWDCNTR 0xa0 >> +#define RTIWWDRXCTRL 0xa4 >> +#define RTIWWDSIZECTRL 0xa8 >> + >> +#define RTIWWDRX_NMI 0xa >> + >> +#define RTIWWDSIZE_50P 0x50 >> + >> +#define WDENABLE_KEY 0xa98559da >> + >> +#define WDKEY_SEQ0 0xe51a >> +#define WDKEY_SEQ1 0xa35c >> + >> +#define WDT_PRELOAD_SHIFT 13 >> + >> +#define WDT_PRELOAD_MAX 0xfff >> + >> +struct rti_wdt_priv { >> + phys_addr_t regs; >> + unsigned int clk_khz; >> +}; >> + >> +static int rti_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) >> +{ >> + struct rti_wdt_priv *priv = dev_get_priv(dev); >> + u32 timer_margin; >> + int ret; >> + >> + if (readl(priv->regs + RTIDWDCTRL) == WDENABLE_KEY) >> + return -EBUSY; >> + >> + timer_margin = timeout_ms * priv->clk_khz / 1000; >> + timer_margin >>= WDT_PRELOAD_SHIFT; >> + if (timer_margin > WDT_PRELOAD_MAX) >> + timer_margin = WDT_PRELOAD_MAX; >> + >> + writel(timer_margin, priv->regs + RTIDWDPRLD); >> + writel(RTIWWDRX_NMI, priv->regs + RTIWWDRXCTRL); >> + writel(RTIWWDSIZE_50P, priv->regs + RTIWWDSIZECTRL); >> + >> + readl(priv->regs + RTIWWDSIZECTRL); >> + >> + writel(WDENABLE_KEY, priv->regs + RTIDWDCTRL); > > What happens if the watchdog timer expires in U-Boot? > Then we reset. You can feed the watchdog also from U-Boot, just enable CONFIG_WATCHDOG. > Is the watchdog started from U-Boot command line? > U-Boot automatically starts the first watchdog it finds. I didn't find a switch to disable that. If you have multiple watchdogs, you can start others also via "wdt". >> + >> + return 0; >> +} >> + >> +static int rti_wdt_reset(struct udevice *dev) >> +{ >> + struct rti_wdt_priv *priv = dev_get_priv(dev); >> + u32 prld; >> + >> + /* Make sure we do not reset too early */ >> + prld = readl(priv->regs + RTIDWDPRLD) << WDT_PRELOAD_SHIFT; >> + if (readl(priv->regs + RTIDWDCNTR) >= prld / 2) >> + return -EPERM; >> + >> + writel(WDKEY_SEQ0, priv->regs + RTIWDKEY); >> + writel(WDKEY_SEQ1, priv->regs + RTIWDKEY); >> + >> + return 0; >> +} >> + >> +static int rti_wdt_probe(struct udevice *dev) >> +{ >> + struct rti_wdt_priv *priv = dev_get_priv(dev); >> + struct clk clk; >> + int ret; >> + >> + priv->regs = devfdt_get_addr(dev); >> + if (!priv->regs) >> + return -EINVAL; >> + >> + ret = clk_get_by_index(dev, 0, &clk); >> + if (ret) >> + return ret; >> + >> + priv->clk_khz = clk_get_rate(&clk); >> + >> + return 0; >> +} >> + >> +static const struct wdt_ops rti_wdt_ops = { >> + .start = rti_wdt_start, >> + .reset = rti_wdt_reset, >> +}; >> + >> +static const struct udevice_id rti_wdt_ids[] = { >> + { .compatible = "ti,j7-rti-wdt" }, > > Is this compatible matching with Kernel's compatible? > Yes. Jan -- Siemens AG, Corporate Technology, CT RDA IOT SES-DE Corporate Competence Center Embedded Linux