summaryrefslogtreecommitdiff
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorVarun Wadekar <vwadekar@nvidia.com>2013-10-11 12:43:03 +0530
committerVarun Wadekar <vwadekar@nvidia.com>2013-10-16 01:44:58 -0700
commit459d61d7fc74baf77408f892a2e14f5457d1a04a (patch)
tree6a5d58f9bc557015533dfdbeb10f79ff00474e65 /drivers/watchdog
parent2b81ea80d7a4f144977592349ac36e5c54f659cf (diff)
arm: tegra: support for FIQ debugger with secure OS
Most of the set up for the debugger is done by the secure OS, but the kernel setup that needs to be done is done here. Use the following config options to enable the debugger - CONFIG_FIQ=y CONFIG_TEGRA_FIQ_DEBUGGER=y CONFIG_FIQ_GLUE=y CONFIG_FIQ_DEBUGGER=y CONFIG_FIQ_DEBUGGER_CONSOLE=y CONFIG_TEGRA_WATCHDOG=y CONFIG_TEGRA_WATCHDOG_ENABLE_ON_PROBE=y Bug 1326082 Original-author: Hyung Taek Ryoo <hryoo@nvidia.com> Change-Id: If1a5dd4f158530dea6c0455ead74a8eeaa226163 Reviewed-on: http://git-master/r/#/c/261217 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/289165
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/tegra_wdt.c171
1 files changed, 159 insertions, 12 deletions
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
index a2923d2a63e2..c3f513ebe273 100644
--- a/drivers/watchdog/tegra_wdt.c
+++ b/drivers/watchdog/tegra_wdt.c
@@ -39,7 +39,6 @@
#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
@@ -59,14 +58,21 @@ struct tegra_wdt {
struct resource *res_src;
struct resource *res_wdt;
struct resource *res_int_base;
+ struct resource *res_pmc;
unsigned long users;
void __iomem *wdt_source;
void __iomem *wdt_timer;
void __iomem *int_base;
+ void __iomem *pmc_base;
int irq;
int tmrsrc;
int timeout;
int status;
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ struct resource *res_avp_src;
+ void __iomem *wdt_avp_source;
+#endif
};
/*
@@ -119,7 +125,7 @@ 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) || defined(CONFIG_ARCH_TEGRA_11x_SOC)
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC) || defined(CONFIG_ARCH_TEGRA_12x_SOC)
#define TIMER_PTV 0
#define TIMER_EN (1 << 31)
@@ -148,8 +154,14 @@ struct tegra_wdt *tegra_wdt[MAX_NR_CPU_WDT];
static inline void tegra_wdt_ping(struct tegra_wdt *wdt)
{
writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD);
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ /* Comment out to test FIQ debugger */
+ writel(WDT_CMD_START_COUNTER, wdt->wdt_avp_source + WDT_CMD);
+#endif
}
+#if !defined(CONFIG_ARCH_TEGRA_12x_SOC) || !defined(CONFIG_FIQ_DEBUGGER)
#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
static void tegra_wdt_int_priority(struct tegra_wdt *wdt)
{
@@ -162,6 +174,7 @@ static void tegra_wdt_int_priority(struct tegra_wdt *wdt)
writel(val, wdt->int_base + ICTLR_IEP_CLASS);
}
#endif
+#endif
static void tegra_wdt_enable(struct tegra_wdt *wdt)
{
@@ -180,11 +193,23 @@ static void tegra_wdt_enable(struct tegra_wdt *wdt)
*/
val = wdt->tmrsrc | WDT_CFG_PERIOD | /*WDT_CFG_INT_EN |*/
/*WDT_CFG_SYS_RST_EN |*/ WDT_CFG_PMC2CAR_RST_EN;
+
+#if !defined(CONFIG_ARCH_TEGRA_12x_SOC) || !defined(CONFIG_FIQ_DEBUGGER)
#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
val |= WDT_CFG_FIQ_INT_EN;
#endif
+#endif
writel(val, wdt->wdt_source + WDT_CFG);
writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD);
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ val = wdt->tmrsrc | (WDT_CFG_PERIOD << 1) | /*WDT_CFG_INT_EN |*/
+ /*WDT_CFG_SYS_RST_EN |*/ WDT_CFG_PMC2CAR_RST_EN;
+ writel(val, wdt->wdt_avp_source + WDT_CFG);
+ writel(WDT_CMD_START_COUNTER, wdt->wdt_avp_source + WDT_CMD);
+
+#endif
}
static void tegra_wdt_disable(struct tegra_wdt *wdt)
@@ -192,6 +217,12 @@ 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);
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ writel(WDT_UNLOCK_PATTERN, wdt->wdt_avp_source + WDT_UNLOCK);
+ writel(WDT_CMD_DISABLE_COUNTER, wdt->wdt_avp_source + WDT_CMD);
+#endif
+
writel(0, wdt->wdt_timer + TIMER_PTV);
}
@@ -210,6 +241,15 @@ static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+static irqreturn_t tegra_wdt_avp_interrupt(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+#endif
+
#endif
static int tegra_wdt_notify(struct notifier_block *this,
@@ -258,7 +298,6 @@ static long tegra_wdt_ioctl(struct file *file, unsigned int cmd,
struct tegra_wdt *wdt = file->private_data;
static DEFINE_SPINLOCK(lock);
int new_timeout;
- int option;
static const struct watchdog_info ident = {
.identity = "Tegra Watchdog",
.options = WDIOF_SETTIMEOUT,
@@ -326,7 +365,7 @@ 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)
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || defined(CONFIG_ARCH_TEGRA_12x_SOC)
/*
* There are two pathes to make the WDT reset:
* (a) WDT -> PMC -> CAR
@@ -348,7 +387,6 @@ static void tegra_wdt_log_reset_reason(struct platform_device *pdev,
* 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),
@@ -362,8 +400,7 @@ static void tegra_wdt_log_reset_reason(struct platform_device *pdev,
if (pdev->id > 0)
return;
- pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
- val = readl(pmc_base + PMC_RST_STATUS) & 0x7;
+ val = readl(wdt->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
@@ -389,7 +426,11 @@ static const struct file_operations tegra_wdt_fops = {
static int tegra_wdt_probe(struct platform_device *pdev)
{
- struct resource *res_src, *res_wdt, *res_irq;
+ struct resource *res_src, *res_wdt, *res_irq, *res_pmc;
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ struct resource *res_avp_src, *res_avp_irq;
+#endif
struct resource *res_int_base = NULL;
struct tegra_wdt *wdt;
int ret = 0;
@@ -401,20 +442,35 @@ static int tegra_wdt_probe(struct platform_device *pdev)
res_src = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res_wdt = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res_pmc = platform_get_resource(pdev, IORESOURCE_MEM, 2);
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res_src || !res_wdt || (!pdev->id && !res_irq)) {
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ res_avp_src = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+ res_avp_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+#endif
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ if (!res_src || !res_wdt || !res_avp_src || (!pdev->id && !res_irq) ||
+ !res_pmc) {
+#else
+ if (!res_src || !res_wdt || (!pdev->id && !res_irq) || !res_pmc) {
+#endif
dev_err(&pdev->dev, "incorrect resources\n");
return -ENOENT;
}
+#if !defined(CONFIG_ARCH_TEGRA_12x_SOC) || !defined(CONFIG_FIQ_DEBUGGER)
#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
- res_int_base = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ res_int_base = platform_get_resource(pdev, IORESOURCE_MEM, 3);
if (!pdev->id && !res_int_base) {
dev_err(&pdev->dev, "FIQ_DBG: INT base not defined\n");
return -ENOENT;
}
#endif
+#endif
if (pdev->id == -1 && !res_irq) {
dev_err(&pdev->dev, "incorrect irq\n");
@@ -451,8 +507,22 @@ static int tegra_wdt_probe(struct platform_device *pdev)
pdev->name);
res_wdt = request_mem_region(res_wdt->start, resource_size(res_wdt),
pdev->name);
+ res_pmc = request_mem_region(res_pmc->start, resource_size(res_pmc),
+ pdev->name);
- if (!res_src || !res_wdt) {
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ res_avp_src = request_mem_region(res_avp_src->start,
+ resource_size(res_avp_src),
+ pdev->name);
+#endif
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ if (!res_src || !res_wdt || !res_avp_src || !res_pmc) {
+#else
+ if (!res_src || !res_wdt || !res_pmc) {
+#endif
dev_err(&pdev->dev, "unable to request memory resources\n");
ret = -EBUSY;
goto fail;
@@ -460,9 +530,23 @@ static int tegra_wdt_probe(struct platform_device *pdev)
wdt->wdt_source = ioremap(res_src->start, resource_size(res_src));
wdt->wdt_timer = ioremap(res_wdt->start, resource_size(res_wdt));
+ wdt->pmc_base = ioremap(res_pmc->start, resource_size(res_pmc));
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ wdt->wdt_avp_source = ioremap(res_avp_src->start,
+ resource_size(res_avp_src));
+#endif
/* tmrsrc will be used to set WDT_CFG */
wdt->tmrsrc = (TMR_SRC_START + pdev->id) % 10;
- if (!wdt->wdt_source || !wdt->wdt_timer) {
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ if (!wdt->wdt_source || !wdt->wdt_timer || !wdt->wdt_avp_source ||
+ !wdt->pmc_base) {
+#else
+ if (!wdt->wdt_source || !wdt->wdt_timer || !wdt->pmc_base) {
+#endif
dev_err(&pdev->dev, "unable to map registers\n");
ret = -ENOMEM;
goto fail;
@@ -474,6 +558,7 @@ static int tegra_wdt_probe(struct platform_device *pdev)
writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR);
if (res_irq != NULL) {
+#if !defined(CONFIG_ARCH_TEGRA_12x_SOC) || !defined(CONFIG_FIQ_DEBUGGER)
#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
/* FIQ debugger enables FIQ priority for INT_WDT_CPU.
* But that will disable IRQ on WDT expiration.
@@ -492,18 +577,36 @@ static int tegra_wdt_probe(struct platform_device *pdev)
goto fail;
tegra_wdt_int_priority(wdt);
#endif
+#endif
ret = request_irq(res_irq->start, tegra_wdt_interrupt,
IRQF_DISABLED, dev_name(&pdev->dev), wdt);
if (ret) {
dev_err(&pdev->dev, "unable to configure IRQ\n");
goto fail;
}
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ ret = request_irq(res_avp_irq->start, tegra_wdt_avp_interrupt,
+ IRQF_DISABLED, "avp_wdt", wdt);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to configure WDT AVP IRQ\n");
+ goto fail;
+ }
+#endif
+
wdt->irq = res_irq->start;
}
wdt->res_src = res_src;
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ wdt->res_avp_src = res_avp_src;
+#endif
wdt->res_wdt = res_wdt;
wdt->res_int_base = res_int_base;
+ wdt->res_pmc = res_pmc;
wdt->status = WDT_DISABLED;
ret = register_reboot_notifier(&wdt->notifier);
@@ -532,6 +635,14 @@ static int tegra_wdt_probe(struct platform_device *pdev)
val = readl(wdt->wdt_source + WDT_CFG);
val |= WDT_CFG_INT_EN;
writel(val, wdt->wdt_source + WDT_CFG);
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ val = readl(wdt->wdt_avp_source + WDT_CFG);
+ val |= WDT_CFG_INT_EN;
+ writel(val, wdt->wdt_avp_source + WDT_CFG);
+
+#endif
pr_info("WDT heartbeat enabled on probe\n");
}
#endif
@@ -548,6 +659,8 @@ fail:
iounmap(wdt->wdt_timer);
if (wdt->int_base)
iounmap(wdt->int_base);
+ if (wdt->pmc_base)
+ iounmap(wdt->pmc_base);
if (res_src)
release_mem_region(res_src->start, resource_size(res_src));
if (res_wdt)
@@ -555,6 +668,17 @@ fail:
if (res_int_base)
release_mem_region(res_int_base->start,
resource_size(res_int_base));
+ if (res_pmc)
+ release_mem_region(res_pmc->start, resource_size(res_pmc));
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ if (wdt->wdt_avp_source)
+ iounmap(wdt->wdt_avp_source);
+ if (res_avp_src)
+ release_mem_region(res_avp_src->start,
+ resource_size(res_avp_src));
+#endif
kfree(wdt);
return ret;
}
@@ -570,14 +694,30 @@ static int tegra_wdt_remove(struct platform_device *pdev)
if (wdt->irq != -1)
free_irq(wdt->irq, wdt);
iounmap(wdt->wdt_source);
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ iounmap(wdt->wdt_avp_source);
+#endif
iounmap(wdt->wdt_timer);
if (wdt->int_base)
iounmap(wdt->int_base);
+ if (wdt->pmc_base)
+ iounmap(wdt->pmc_base);
release_mem_region(wdt->res_src->start, resource_size(wdt->res_src));
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ release_mem_region(wdt->res_avp_src->start,
+ resource_size(wdt->res_avp_src));
+#endif
release_mem_region(wdt->res_wdt->start, resource_size(wdt->res_wdt));
if (wdt->res_int_base)
release_mem_region(wdt->res_int_base->start,
resource_size(wdt->res_int_base));
+ if (wdt->res_pmc)
+ release_mem_region(wdt->res_pmc->start,
+ resource_size(wdt->res_pmc));
kfree(wdt);
platform_set_drvdata(pdev, NULL);
return 0;
@@ -606,6 +746,13 @@ static int tegra_wdt_resume(struct platform_device *pdev)
val = readl(wdt->wdt_source + WDT_CFG);
val |= WDT_CFG_INT_EN;
writel(val, wdt->wdt_source + WDT_CFG);
+
+#if defined(CONFIG_TEGRA_USE_SECURE_KERNEL) && \
+ defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
+ val = readl(wdt->wdt_avp_source + WDT_CFG);
+ val |= WDT_CFG_INT_EN;
+ writel(val, wdt->wdt_avp_source + WDT_CFG);
+#endif
pr_info("WDT heartbeat enabled on probe\n");
}
#endif