summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorKamal Kannan Balagopalan <kbalagopalan@nvidia.com>2011-12-12 14:15:02 -0800
committerVarun Wadekar <vwadekar@nvidia.com>2011-12-22 11:12:35 +0530
commitf0fa117c3fef2df54c2151c0d2c6ec7278cd45ee (patch)
tree90a4809963d40404df8fbc6c3271983e0e6eb1ac /arch/arm/mach-tegra
parent964834f1203e375c13be8d3fb58b3fada083c579 (diff)
arm: tegra: power: add watchdog recovery function
Add watchdog recovery mechanism to protect against hangs during driver suspend/resume sequence Bug 857748 Change-Id: I03d540b38318a5a953b1a697af123291b48991e9 Signed-off-by: Kamal Kannan Balagopalan <kbalagopalan@nvidia.com> Reviewed-on: http://git-master/r/65986 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Kconfig7
-rw-r--r--arch/arm/mach-tegra/Makefile1
-rw-r--r--arch/arm/mach-tegra/board-cardhu.c4
-rw-r--r--arch/arm/mach-tegra/wdt-recovery.c131
-rw-r--r--arch/arm/mach-tegra/wdt-recovery.h17
5 files changed, 160 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index bf5f4dd04862..7306df5d3672 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -448,5 +448,12 @@ config TEGRA_PLLM_RESTRICTED
capable of dividing maximum PLLM frequency at minimum voltage. When
disabled, PLLM is used as a clock source with no restrictions (which
may effectively increase lower limit for core voltage).
+
+config TEGRA_WDT_RECOVERY
+ bool "Enable suspend/resume watchdog recovery mechanism"
+ default n
+ help
+ Enables watchdog recovery mechanism to protect against
+ suspend/resume hangs.
endif
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 45860e27a3e0..a4d1b217c163 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -22,6 +22,7 @@ obj-y += devices.o
obj-y += delay.o
obj-y += powergate.o
obj-y += pm.o
+obj-$(CONFIG_TEGRA_WDT_RECOVERY) += wdt-recovery.o
obj-$(CONFIG_PM_SLEEP) += pm-irq.o
obj-y += gic.o
obj-y += sleep.o
diff --git a/arch/arm/mach-tegra/board-cardhu.c b/arch/arm/mach-tegra/board-cardhu.c
index b571e799749a..81129d1a2762 100644
--- a/arch/arm/mach-tegra/board-cardhu.c
+++ b/arch/arm/mach-tegra/board-cardhu.c
@@ -64,6 +64,7 @@
#include "fuse.h"
#include "pm.h"
#include "baseband-xmm-power.h"
+#include "wdt-recovery.h"
/* All units are in millicelsius */
static struct tegra_thermal_data thermal_data = {
@@ -997,6 +998,9 @@ static void __init tegra_cardhu_init(void)
tegra_release_bootloader_fb();
cardhu_nfc_init();
cardhu_pci_init();
+#ifdef CONFIG_TEGRA_WDT_RECOVERY
+ tegra_wdt_recovery_init();
+#endif
}
static void __init cardhu_ramconsole_reserve(unsigned long size)
diff --git a/arch/arm/mach-tegra/wdt-recovery.c b/arch/arm/mach-tegra/wdt-recovery.c
new file mode 100644
index 000000000000..537b1c0db853
--- /dev/null
+++ b/arch/arm/mach-tegra/wdt-recovery.c
@@ -0,0 +1,131 @@
+/*
+ * arch/arm/mach-tegra/wdt-recovery.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/resource.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/syscore_ops.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/time.h>
+#include <asm/localtimer.h>
+
+#include <mach/nvmap.h>
+#include <mach/irqs.h>
+#include <mach/iomap.h>
+#include <mach/clk.h>
+#include <mach/io.h>
+
+static int wdt_heartbeat = 30;
+
+#if 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 (7 << 0) /* for TMR7. */
+ #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 __iomem *wdt_timer = IO_ADDRESS(TEGRA_TMR7_BASE);
+static void __iomem *wdt_source = IO_ADDRESS(TEGRA_WDT0_BASE);
+
+static void tegra_wdt_reset_enable(void)
+{
+ u32 val;
+
+ writel(TIMER_PCR_INTR, wdt_timer + TIMER_PCR);
+ val = (wdt_heartbeat * 1000000ul) / 4;
+ val |= (TIMER_EN | TIMER_PERIODIC);
+ writel(val, 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_source + WDT_CFG);
+ writel(WDT_CMD_START_COUNTER, wdt_source + WDT_CMD);
+ pr_info("%s: WDT Recovery Enabled\n", __func__);
+}
+
+static int tegra_wdt_reset_disable(void)
+{
+ writel(TIMER_PCR_INTR, wdt_timer + TIMER_PCR);
+ writel(WDT_UNLOCK_PATTERN, wdt_source + WDT_UNLOCK);
+ writel(WDT_CMD_DISABLE_COUNTER, wdt_source + WDT_CMD);
+
+ writel(0, wdt_timer + TIMER_PTV);
+ pr_info("%s: WDT Recovery Disabled\n", __func__);
+
+ return 0;
+}
+#elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
+
+static void tegra_wdt_reset_enable(void)
+{
+}
+static int tegra_wdt_reset_disable(void)
+{
+ return 0;
+}
+#endif
+
+static int tegra_pm_notify(struct notifier_block *nb,
+ unsigned long event, void *nouse)
+{
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ tegra_wdt_reset_enable();
+ break;
+ case PM_POST_SUSPEND:
+ tegra_wdt_reset_disable();
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block tegra_wdt_notify = {
+ .notifier_call = tegra_pm_notify,
+};
+
+static struct syscore_ops tegra_wdt_syscore_ops = {
+ .suspend = tegra_wdt_reset_disable,
+ .resume = tegra_wdt_reset_enable,
+};
+
+void __init tegra_wdt_recovery_init(void)
+{
+#ifdef CONFIG_PM
+ /* Register PM notifier. */
+ register_pm_notifier(&tegra_wdt_notify);
+#endif
+ register_syscore_ops(&tegra_wdt_syscore_ops);
+}
diff --git a/arch/arm/mach-tegra/wdt-recovery.h b/arch/arm/mach-tegra/wdt-recovery.h
new file mode 100644
index 000000000000..e26c1d038574
--- /dev/null
+++ b/arch/arm/mach-tegra/wdt-recovery.h
@@ -0,0 +1,17 @@
+/*
+ * arch/arm/mach-tegra/wdt-recovery.h
+ *
+ * Copyright (C) 2011 NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+void __init tegra_wdt_recovery_init(void);