diff options
author | Varun Wadekar <vwadekar@nvidia.com> | 2013-10-11 12:43:03 +0530 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2013-10-16 01:44:58 -0700 |
commit | 459d61d7fc74baf77408f892a2e14f5457d1a04a (patch) | |
tree | 6a5d58f9bc557015533dfdbeb10f79ff00474e65 /drivers/watchdog | |
parent | 2b81ea80d7a4f144977592349ac36e5c54f659cf (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.c | 171 |
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 |