diff mbox

[U-Boot,2/2] tegra: Add watchdog driver

Message ID 1462188966-32476-2-git-send-email-julian@jusst.de
State Deferred
Delegated to: Tom Warren
Headers show

Commit Message

Julian Scheel May 2, 2016, 11:36 a.m. UTC
Add support for the tegra (t30 and newer) watchdog component.

Signed-off-by: Julian Scheel <julian@jusst.de>
---
 arch/arm/include/asm/arch-tegra/tegra.h |  2 ++
 arch/arm/include/asm/arch-tegra/wdt.h   | 41 ++++++++++++++++++++++
 arch/arm/mach-tegra/board2.c            |  4 +++
 drivers/watchdog/Makefile               |  1 +
 drivers/watchdog/tegra_wdt.c            | 60 +++++++++++++++++++++++++++++++++
 5 files changed, 108 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-tegra/wdt.h
 create mode 100644 drivers/watchdog/tegra_wdt.c
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-tegra/tegra.h b/arch/arm/include/asm/arch-tegra/tegra.h
index 3add1b3..790a7ae 100644
--- a/arch/arm/include/asm/arch-tegra/tegra.h
+++ b/arch/arm/include/asm/arch-tegra/tegra.h
@@ -11,6 +11,8 @@ 
 #define NV_PA_ARM_PERIPHBASE	0x50040000
 #define NV_PA_PG_UP_BASE	0x60000000
 #define NV_PA_TMRUS_BASE	0x60005010
+#define NV_PA_TMR5_BASE		0x60005060
+#define NV_PA_TMRWDT0_BASE	0x60005100
 #define NV_PA_CLK_RST_BASE	0x60006000
 #define NV_PA_FLOW_BASE		0x60007000
 #define NV_PA_GPIO_BASE		0x6000D000
diff --git a/arch/arm/include/asm/arch-tegra/wdt.h b/arch/arm/include/asm/arch-tegra/wdt.h
new file mode 100644
index 0000000..642b0b2
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra/wdt.h
@@ -0,0 +1,41 @@ 
+/*
+ * Copyright 2016 Avionic Design GmbH
+ * Copyright 2016 Julian Scheel <julian@jusst.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _TEGRA_WDT_H_
+#define _TEGRA_WDT_H_
+
+struct wdt_ctrl {
+	u32 config;
+	u32 status;
+	u32 command;
+	u32 unlock;
+};
+
+#define WDT_CFG_SOURCE_MASK 0xf
+
+#define WDT_CFG_PERIOD_SHIFT 4
+#define WDT_CFG_PERIOD_MASK (0xff << WDT_CFG_PERIOD_SHIFT)
+
+#define WDT_CFG_PMC2CAR_RST_EN (1 << 15)
+
+#define WDT_STS_COUNT_SHIFT 4
+#define WDT_STS_COUNT_MASK (0xff << WDT_STS_COUNT_SHIFT)
+
+#define WDT_CMD_START_COUNTER (1 << 0)
+#define WDT_CMD_DISABLE_COUNTER (1 << 1)
+
+#define WDT_UNLOCK_PATTERN 0xc45a
+
+/* Timer registers */
+struct timer_ctrl {
+	u32 ptv;
+};
+
+#define TIMER_PTV_EN (1 << 31)
+#define TIMER_PTV_PERIODIC (1 << 30)
+
+#endif /* _TEGRA_WDT_H_ */
diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c
index 896c1cc..77426f3 100644
--- a/arch/arm/mach-tegra/board2.c
+++ b/arch/arm/mach-tegra/board2.c
@@ -124,6 +124,10 @@  int board_init(void)
 
 	tegra_gpu_config();
 
+#ifdef CONFIG_HW_WATCHDOG
+	hw_watchdog_init();
+#endif
+
 #ifdef CONFIG_TEGRA_SPI
 	pin_mux_spi();
 #endif
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index a007ae8..e580e1b 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -15,3 +15,4 @@  obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o
 obj-$(CONFIG_BFIN_WATCHDOG)  += bfin_wdt.o
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o
+obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
new file mode 100644
index 0000000..70c0de7
--- /dev/null
+++ b/drivers/watchdog/tegra_wdt.c
@@ -0,0 +1,60 @@ 
+/*
+ * Copyright 2016 Avionic Design GmbH
+ * Copyright 2016 Julian Scheel <julian@jusst.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <asm/io.h>
+#include <asm/arch-tegra/wdt.h>
+#include <asm/arch-tegra/tegra.h>
+
+/* Timeout in seconds */
+#define WDT_TIMEOUT 60
+
+/* Timer to use - 5 is used in linux kernel */
+#define WDT_TIMER_ID 5
+void hw_watchdog_init(void)
+{
+	struct timer_ctrl *timer = (struct timer_ctrl *)NV_PA_TMR5_BASE;
+	struct wdt_ctrl *wdt = (struct wdt_ctrl *)NV_PA_TMRWDT0_BASE;
+	u32 val;
+
+	/* Timer runs fixed at 1 MHz, reset is triggered at 4th timeout of
+	 * timer */
+	val = 1000000ul / 4;
+	val |= (TIMER_PTV_EN | TIMER_PTV_PERIODIC);
+	writel(val, &timer->ptv);
+
+	/* Setup actual wdt */
+	val = WDT_TIMER_ID |
+		((WDT_TIMEOUT << WDT_CFG_PERIOD_SHIFT) & WDT_CFG_PERIOD_MASK) |
+		WDT_CFG_PMC2CAR_RST_EN;
+	writel(val, &wdt->config);
+
+	/* Activate the wdt */
+	writel(WDT_CMD_START_COUNTER, &wdt->command);
+}
+
+void hw_watchdog_reset(void)
+{
+	struct wdt_ctrl *wdt = (struct wdt_ctrl *)NV_PA_TMRWDT0_BASE;
+
+	/* Activate the wdt */
+	writel(WDT_CMD_START_COUNTER, &wdt->command);
+}
+
+void hw_watchdog_disable(void)
+{
+	struct timer_ctrl *timer = (struct timer_ctrl *)NV_PA_TMR5_BASE;
+	struct wdt_ctrl *wdt = (struct wdt_ctrl *)NV_PA_TMRWDT0_BASE;
+
+	/* Write unlock pattern */
+	writel(WDT_UNLOCK_PATTERN, &wdt->unlock);
+	/* Disable wdt */
+	writel(WDT_CMD_DISABLE_COUNTER, &wdt->command);
+	/* Stop timer */
+	writel(0, &timer->ptv);
+}