[PATCH 2/2] watchdog: Add implementation of NVIDIA's Tegra 30 watchdog driver
Svyatoslav Ryhel
clamor95 at gmail.com
Wed Sep 17 16:01:05 CEST 2025
вт, 26 серп. 2025 р. о 12:39 Lukasz Majewski <lukma at nabladev.com> пише:
>
> This commit provides support for Tegra's 30 watchdog functionality.
> The WATCHDOG index 0 in conjunction with TIMER 5 has been used. as the
> same setup is used in Linux kernel driver.
>
> Signed-off-by: Lukasz Majewski <lukma at nabladev.com>
> ---
> drivers/watchdog/Kconfig | 7 ++
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/tegra_wdt.c | 121 +++++++++++++++++++++++++++++++++++
> 3 files changed, 129 insertions(+)
> create mode 100644 drivers/watchdog/tegra_wdt.c
>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 9e149a75e81..a10baed7232 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -454,6 +454,13 @@ config WDT_TANGIER
> Intel Tangier SoC. If you're using a board with Intel Tangier
> SoC, say Y here.
>
> +config WDT_TEGRA
> + bool "Tegra watchdog"
> + depends on WDT && ARCH_TEGRA
> + help
> + Select this to enable support for the watchdog timer
> + embedded in NVIDIA Tegra SoCs.
> +
> config WDT_ARM_SMC
> bool "ARM SMC watchdog timer support"
> depends on WDT && ARM_SMCCC
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index d52d17e1c90..02e2674f8af 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -53,6 +53,7 @@ obj-$(CONFIG_WDT_STARFIVE) += starfive_wdt.o
> obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
> obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
> obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
> +obj-$(CONFIG_WDT_TEGRA) += tegra_wdt.o
> obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o
> obj-$(CONFIG_WDT_ADI) += adi_wdt.o
> obj-$(CONFIG_WDT_QCOM) += qcom-wdt.o
> diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
> new file mode 100644
> index 00000000000..812ec312fee
> --- /dev/null
> +++ b/drivers/watchdog/tegra_wdt.c
> @@ -0,0 +1,121 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * NVIDIA Tegra Watchdog driver
> + *
> + * Copyright (C) 2025 NABLA Software Engineering
> + * Lukasz Majewski, NABLA Software Engineering, lukma at nabladev.com
> + */
> +
> +#include <dm.h>
> +#include <wdt.h>
> +#include <hang.h>
> +#include <asm/io.h>
> +#include <watchdog.h>
> +
> +/* Timer registers */
> +#define TIMER_PTV (0x0)
Here and further, use 0x0 without (), hex numbers in lower case
> +#define TIMER_EN BIT(31)
> +#define TIMER_PERIODIC BIT(30)
> +
> +/* WDT registers */
> +#define WDT_CFG (0x0)
> +#define WDT_CFG_PERIOD_SHIFT 4
> +#define WDT_CFG_PERIOD_MASK GENMASK(7, 0)
> +#define WDT_CFG_INT_EN BIT(12)
> +#define WDT_CFG_PMC2CAR_RST_EN BIT(15)
> +#define WDT_CMD (0x8)
> +#define WDT_CMD_START_COUNTER BIT(0)
> +#define WDT_CMD_DISABLE_COUNTER BIT(1)
> +#define WDT_UNLOCK (0xC)
> +#define WDT_UNLOCK_PATTERN (0xc45a)
> +
> +/* Use watchdog ID 0 */
> +#define WDT0_BASE 0x100
> +
> +/* Use Timer 5 as WDT counter */
> +#define WDT_TIM5_BASE 0x60
> +#define WDT_TIM5_ID 5
> +
> +struct tegra_wdt_priv {
> + void __iomem *wdt_base;
> + void __iomem *tim_base;
> +};
> +
> +static int tegra_wdt_reset(struct udevice *dev)
> +{
> + struct tegra_wdt_priv *priv = dev_get_priv(dev);
> +
> + writel(WDT_CMD_START_COUNTER, priv->wdt_base + WDT_CMD);
> +
> + return 0;
> +}
> +
> +static int tegra_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
> +{
> + struct tegra_wdt_priv *priv = dev_get_priv(dev);
> + u32 timeout_sec = timeout / 1000;
> +
> + /*
> + * Timer for WDT has a fixed 1MHz clock, so for 1 second period one
> + * shall write 1000000ul.
> + *
> + * On Tegra the watchdog reset actually occurs on the 4th expiration
> + * of this counter, so we set the period to 1/4.
> + */
> + writel(TIMER_EN | TIMER_PERIODIC | (1000000ul / 4),
> + priv->tim_base + TIMER_PTV);
> +
> + /* Support for timeout from 1 to 255 seconds */
> + if (timeout_sec < 1 || timeout_sec > 255)
> + return -EINVAL;
Check should be before any register writing is done.
> +
> + writel(WDT_CFG_PMC2CAR_RST_EN | (timeout_sec << WDT_CFG_PERIOD_SHIFT) |
> + WDT_TIM5_ID, priv->wdt_base + WDT_CFG);
> +
> + writel(WDT_CMD_START_COUNTER, priv->wdt_base + WDT_CMD);
> +
> + return 0;
> +}
> +
> +static int tegra_wdt_stop(struct udevice *dev)
> +{
> + struct tegra_wdt_priv *priv = dev_get_priv(dev);
> +
> + writel(WDT_UNLOCK_PATTERN, priv->wdt_base + WDT_UNLOCK);
> + writel(WDT_CMD_DISABLE_COUNTER, priv->wdt_base + WDT_CMD);
> + writel(0, priv->tim_base + TIMER_PTV);
> +
> + return 0;
> +}
> +
> +static int tegra_wdt_probe(struct udevice *dev)
> +{
> + struct tegra_wdt_priv *priv = dev_get_priv(dev);
> + void __iomem *base;
> +
> + if (!device_is_compatible(dev, "nvidia,tegra30-timer"))
> + return -ENODEV;
Remove this restriction, it is not needed.
> +
> + base = dev_read_addr_ptr(dev);
> + if (!base)
> + return -ENOENT;
> +
> + priv->wdt_base = base + WDT0_BASE;
> + priv->tim_base = base + WDT_TIM5_BASE;
> +
> + return 0;
> +}
> +
> +static const struct wdt_ops tegra_wdt_ops = {
> + .start = tegra_wdt_start,
> + .stop = tegra_wdt_stop,
> + .reset = tegra_wdt_reset,
> +};
> +
> +U_BOOT_DRIVER(tegra_wdt) = {
> + .name = "tegra_wdt",
> + .id = UCLASS_WDT,
> + .priv_auto = sizeof(struct tegra_wdt_priv),
> + .probe = tegra_wdt_probe,
> + .ops = &tegra_wdt_ops,
> +};
> --
> 2.39.5
>
Everything else seems to be fine. Apply those cosmetic changes and I
will pick your patches.
More information about the U-Boot
mailing list