diff options
author | Xin Xie <xxie@nvidia.com> | 2013-02-20 13:52:59 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 13:00:57 -0700 |
commit | eeb81888c41ebce8f6822fd241934e582c13a773 (patch) | |
tree | c205234f3ac81a9c046238506a9c278ccf4f87c8 /drivers/watchdog | |
parent | 16d65c456be545d1e6d44c8a96962681d640573a (diff) |
watchdog: tegra: fix reboot reason
bug 1239765
Change-Id: Ia2c5c83c0489b21d3fb5dcc005a9b7c07fb9b98c
Signed-off-by: Xin Xie <xxie@nvidia.com>
Reviewed-on: http://git-master/r/202662
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/tegra_wdt.c | 63 |
1 files changed, 59 insertions, 4 deletions
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index fcefb9bac880..6306e351f744 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c @@ -39,6 +39,7 @@ #ifdef CONFIG_TEGRA_FIQ_DEBUGGER #include <mach/irqs.h> #endif +#include <mach/iomap.h> /* minimum and maximum watchdog trigger periods, in seconds */ #define MIN_WDT_PERIOD 5 @@ -140,6 +141,7 @@ static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id) #define WDT_UNLOCK_PATTERN (0xC45A << 0) #define ICTLR_IEP_CLASS 0x2C #define MAX_NR_CPU_WDT 0x4 +#define PMC_RST_STATUS 0x1b4 struct tegra_wdt *tegra_wdt[MAX_NR_CPU_WDT]; @@ -320,6 +322,62 @@ static ssize_t tegra_wdt_write(struct file *file, const char __user *data, return len; } +static void tegra_wdt_log_reset_reason(struct platform_device *pdev, + struct tegra_wdt *wdt) +{ + +#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || defined(CONFIG_ARCH_TEGRA_11x_SOC) + /* + * There are two pathes to make the WDT reset: + * (a) WDT -> PMC -> CAR + * ^ + * | + * v + * PMIC + * + * (b) WDT -> CAR + * + * Path (a) is enabled by WDT_CFG_PMC2CAR_RST_EN bit in the WDT + * configuration register, as it will reset the CAR module, and we + * cannot read back the reset reason from the CAR module. However, we + * can read back the reaset reason from the PMC module. + * + * Path (b) is enabled by the WDT_CFG_SYS_RST_EN bit, and we can + * read back the reset reason from the CAR moudle. However, this reset + * path will not reset the peripherals which might be the hard hang + * source. We will not use this path. + */ + u32 val; + void __iomem *pmc_base; +#define RESET_STR(REASON) "last reset is due to "#REASON"\n" + char *reset_reason[] = { + RESET_STR(power on reset), + RESET_STR(watchdog timeout), + RESET_STR(sensor), + RESET_STR(software reset), + RESET_STR(deep sleep reset), + }; + + /* report reset reason only once */ + if (pdev->id > 0) + return; + + pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); + val = readl(pmc_base + PMC_RST_STATUS) & 0x7; + if (val >= ARRAY_SIZE(reset_reason)) + dev_info(&pdev->dev, "last reset value is invalid 0x%x\n", val); + else + dev_info(&pdev->dev, reset_reason[val]); + +#else + u32 val; + + val = readl(wdt->wdt_source); + if (val & BIT(12)) + dev_info(&pdev->dev, "last reset due to watchdog timeout\n"); +#endif +} + static const struct file_operations tegra_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -334,7 +392,6 @@ static int tegra_wdt_probe(struct platform_device *pdev) struct resource *res_src, *res_wdt, *res_irq; struct resource *res_int_base = NULL; struct tegra_wdt *wdt; - u32 src; int ret = 0; if (pdev->id < -1 && pdev->id > 3) { @@ -411,9 +468,7 @@ static int tegra_wdt_probe(struct platform_device *pdev) goto fail; } - src = readl(wdt->wdt_source); - if (src & BIT(12)) - dev_info(&pdev->dev, "last reset due to watchdog timeout\n"); + tegra_wdt_log_reset_reason(pdev, wdt); tegra_wdt_disable(wdt); writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR); |