diff options
author | vdumpa <vdumpa@nvidia.com> | 2011-02-16 00:01:24 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 01:31:54 -0700 |
commit | 327616b824098fc7e16fbd63d14a2303a9c4fb2c (patch) | |
tree | 00212f870ef2bddc40dcf62fc363914e6eb058d0 /drivers/watchdog | |
parent | 19679744ac7dc844af6a5a833a2fffed43baa94a (diff) |
tegra:watchdog: Use new watchdog controller.
Use new watch dog controller for CONFIG_ARCH_TEGRA_3x_SOC.
Bug 790458
Original-Change-Id: I43975a2794f44f612a5f16674cd674aeebe4e6be
Reviewed-on: http://git-master/r/19715
Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>
Tested-by: Krishna Reddy <vdumpa@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Original-Change-Id: Ic8c9907998a2ab1777ea2b00f1acceb6d66c10e5
Rebase-Id: Ra0b9af5a0642fab2d13816f04c0c340ea42a45c8
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/tegra_wdt.c | 101 |
1 files changed, 83 insertions, 18 deletions
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index e364632f1514..05a481ef847b 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c @@ -3,7 +3,7 @@ * * watchdog driver for NVIDIA tegra internal watchdog * - * Copyright (c) 2010, NVIDIA Corporation. + * Copyright (c) 2011, NVIDIA Corporation. * * based on drivers/watchdog/softdog.c and drivers/watchdog/omap_wdt.c * @@ -39,23 +39,6 @@ #define MIN_WDT_PERIOD 5 #define MAX_WDT_PERIOD 1000 -#define TIMER_PTV 0x0 -#define TIMER_EN (1 << 31) -#define TIMER_PERIODIC (1 << 30) - -#define TIMER_PCR 0x4 -#define TIMER_PCR_INTR (1 << 30) - -#define WDT_EN (1 << 5) -#define WDT_SEL_TMR1 (0 << 4) -#define WDT_SYS_RST (1 << 2) - -/* - * For spinlock lockup detection to work, the heartbeat should be 2*lockup - * for cases where the spinlock disabled irqs. - */ -static int heartbeat = 120; /* must be greater than MIN_WDT_PERIOD and lower than MAX_WDT_PERIOD */ - struct tegra_wdt { struct miscdevice miscdev; struct notifier_block notifier; @@ -70,6 +53,22 @@ struct tegra_wdt { }; static struct platform_device *tegra_wdt_dev; +/* + * For spinlock lockup detection to work, the heartbeat should be 2*lockup + * for cases where the spinlock disabled irqs. + */ +static int heartbeat = 120; /* must be greater than MIN_WDT_PERIOD and lower than MAX_WDT_PERIOD */ + +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) + +#define TIMER_PTV 0x0 + #define TIMER_EN (1 << 31) + #define TIMER_PERIODIC (1 << 30) +#define TIMER_PCR 0x4 + #define TIMER_PCR_INTR (1 << 30) +#define WDT_EN (1 << 5) +#define WDT_SEL_TMR1 (0 << 4) +#define WDT_SYS_RST (1 << 2) static void tegra_wdt_enable(struct tegra_wdt *wdt) { @@ -99,6 +98,72 @@ static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id) writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR); return IRQ_HANDLED; } +#elif defined(CONFIG_ARCH_TEGRA_3x_SOC) + +#define TIMER_PTV 0 + #define TIMER_EN (1 << 31) + #define TIMER_PERIODIC (1 << 30) +#define TIMER_PCR 0x4 + #define TIMER_PCR_INTR (1 << 30) +#define WDT_CFG (0) + #define WDT_CFG_TMR_SRC (6 << 0) /* for TMR6. */ + #define WDT_CFG_PERIOD (1 << 4) + #define WDT_CFG_INT_EN (1 << 12) + #define WDT_CFG_SYS_RST_EN (1 << 14) + #define WDT_CFG_PMC2CAR_RST_EN (1 << 15) +#define WDT_CMD (8) + #define WDT_CMD_START_COUNTER (1 << 0) + #define WDT_CMD_DISABLE_COUNTER (1 << 1) +#define WDT_UNLOCK (0xC) + #define WDT_UNLOCK_PATTERN (0xC45A << 0) + +static void tegra_wdt_set_timeout(struct tegra_wdt *wdt, int sec) +{ + u32 ptv; + + ptv = readl(wdt->wdt_timer + TIMER_PTV); + + wdt->timeout = clamp(sec, MIN_WDT_PERIOD, MAX_WDT_PERIOD); + if (ptv & TIMER_EN) { + /* since the watchdog reset occurs when a fourth interrupt + * is asserted before the first is processed, program the + * timer period to one-fourth of the watchdog period */ + ptv = (wdt->timeout * 1000000ul) / 4; + ptv |= (TIMER_EN | TIMER_PERIODIC); + writel(ptv, wdt->wdt_timer + TIMER_PTV); + } +} + +static void tegra_wdt_enable(struct tegra_wdt *wdt) +{ + u32 val; + + val = (wdt->timeout * 1000000ul) / 4; + val |= (TIMER_EN | TIMER_PERIODIC); + writel(val, wdt->wdt_timer + TIMER_PTV); + + val = WDT_CFG_TMR_SRC | WDT_CFG_PERIOD | WDT_CFG_INT_EN | + /*WDT_CFG_SYS_RST_EN |*/ WDT_CFG_PMC2CAR_RST_EN; + writel(val, wdt->wdt_source + WDT_CFG); + writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD); +} + +static void tegra_wdt_disable(struct tegra_wdt *wdt) +{ + writel(WDT_UNLOCK_PATTERN, wdt->wdt_source + WDT_UNLOCK); + writel(WDT_CMD_DISABLE_COUNTER, wdt->wdt_source + WDT_CMD); + + writel(0, wdt->wdt_timer + TIMER_PTV); +} + +static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id) +{ + struct tegra_wdt *wdt = dev_id; + + writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD); + return IRQ_HANDLED; +} +#endif static int tegra_wdt_notify(struct notifier_block *this, unsigned long code, void *dev) |