aboutsummaryrefslogtreecommitdiff
path: root/plat/nvidia/tegra194/watchdog.c
diff options
context:
space:
mode:
Diffstat (limited to 'plat/nvidia/tegra194/watchdog.c')
-rw-r--r--plat/nvidia/tegra194/watchdog.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/plat/nvidia/tegra194/watchdog.c b/plat/nvidia/tegra194/watchdog.c
new file mode 100644
index 000000000..3773a3b6e
--- /dev/null
+++ b/plat/nvidia/tegra194/watchdog.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <mmio.h>
+#include <platform.h>
+
+/* Timer registers */
+#define TIMER_PTV U(0)
+ #define TIMER_EN_BIT BIT_32(31)
+ #define TIMER_PERIODIC_BIT BIT_32(30)
+#define TIMER_PCR U(0x4)
+ #define TIMER_PCR_INTR_BIT BIT_32(30)
+
+/* WDT registers */
+#define WDT_CFG U(0)
+ #define WDT_CFG_TMR_SRC U(0) /* for TMR0. */
+ #define WDT_CFG_PERIOD_BIT BIT_32(4)
+ #define WDT_CFG_INT_EN_BIT BIT_32(12)
+ #define WDT_CFG_SYS_RST_EN_BIT BIT_32(14)
+ #define WDT_CFG_PMC2CAR_RST_EN_BIT BIT_32(15)
+#define WDT_CMD U(8)
+ #define WDT_CMD_START_COUNTER_BIT BIT_32(0)
+ #define WDT_CMD_DISABLE_COUNTER_BIT BIT_32(1)
+#define WDT_UNLOCK U(0xC)
+ #define WDT_UNLOCK_PATTERN U(0xC45A)
+
+/* watchdog will fire after this timeout value is reached */
+#define WDT_TIMEOUT_SECONDS U(10)
+#define WDT_TIMEOUT_MULTIPLIER UL(125000)
+
+static inline void tegra194_wdt_write(uint32_t offset, uint32_t val)
+{
+ mmio_write_32(TEGRA194_WDT0_BASE + offset, val);
+}
+
+static inline uint32_t tegra194_wdt_read(uint32_t offset)
+{
+ return mmio_read_32(TEGRA194_WDT0_BASE + offset);
+}
+
+static inline void tegra194_tmr_write(uint32_t offset, uint32_t val)
+{
+ mmio_write_32(TEGRA194_TMR0_BASE + offset, val);
+}
+
+static inline uint32_t tegra194_tmr_read(uint32_t offset)
+{
+ return mmio_read_32(TEGRA194_TMR0_BASE + offset);
+}
+
+/*
+ * Start the watchdog timer
+ */
+void tftf_platform_watchdog_set(void)
+{
+ uint32_t val;
+
+ /* Clear pending interrupts first */
+ tegra194_tmr_write(TIMER_PCR, TIMER_PCR_INTR_BIT);
+
+ /*
+ * Normally, we would set the period to 1 second by writing 125000ul,
+ * but the watchdog system reset actually occurs on the 4th expiration
+ * of this counter, so we set the period to 1/4 of this amount.
+ */
+ val = (WDT_TIMEOUT_SECONDS * WDT_TIMEOUT_MULTIPLIER) / 4;
+ val |= (TIMER_EN_BIT | TIMER_PERIODIC_BIT);
+ tegra194_tmr_write(TIMER_PTV, val);
+
+ /*
+ * Set number of periods and start counter.
+ */
+ val = WDT_CFG_TMR_SRC | WDT_CFG_SYS_RST_EN_BIT |
+ WDT_CFG_PMC2CAR_RST_EN_BIT;
+ tegra194_wdt_write(WDT_CFG, val);
+ tegra194_wdt_write(WDT_CMD, WDT_CMD_START_COUNTER_BIT);
+}
+
+/*
+ * Stop the watchdog timer
+ */
+void tftf_platform_watchdog_reset(void)
+{
+ tegra194_tmr_write(TIMER_PCR, TIMER_PCR_INTR_BIT);
+ tegra194_wdt_write(WDT_UNLOCK, WDT_UNLOCK_PATTERN);
+ tegra194_wdt_write(WDT_CMD, WDT_CMD_DISABLE_COUNTER_BIT);
+ tegra194_tmr_write(TIMER_PTV, 0);
+}