From f0fa117c3fef2df54c2151c0d2c6ec7278cd45ee Mon Sep 17 00:00:00 2001 From: Kamal Kannan Balagopalan Date: Mon, 12 Dec 2011 14:15:02 -0800 Subject: 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 Reviewed-on: http://git-master/r/65986 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Krishna Reddy --- arch/arm/mach-tegra/Kconfig | 7 ++ arch/arm/mach-tegra/Makefile | 1 + arch/arm/mach-tegra/board-cardhu.c | 4 ++ arch/arm/mach-tegra/wdt-recovery.c | 131 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-tegra/wdt-recovery.h | 17 +++++ 5 files changed, 160 insertions(+) create mode 100644 arch/arm/mach-tegra/wdt-recovery.c create mode 100644 arch/arm/mach-tegra/wdt-recovery.h (limited to 'arch/arm/mach-tegra') 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +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); -- cgit v1.2.3