diff options
author | Jamie Iles <jamie@jamieiles.com> | 2011-12-17 13:42:37 +0000 |
---|---|---|
committer | Jamie Iles <jamie@jamieiles.com> | 2011-12-18 10:48:41 +0000 |
commit | 1b46f8782c2607afa1298b0c7f7fe307fc0f7a5b (patch) | |
tree | fe154b4ed20efe29ac246418f06f24b9dd07715d /arch/arm/mach-picoxcell/common.c | |
parent | a53bfa07369b7c3448a60d29f0fc2e81751ed0b7 (diff) |
ARM: picoxcell: implement watchdog restart
Allow the platform to be restarted by triggering the watchdog to expire
with the shortest possible expiry. This should reset the CPU core and
all on-chip peripherals.
v2: - use writel_relaxed().
Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Diffstat (limited to 'arch/arm/mach-picoxcell/common.c')
-rw-r--r-- | arch/arm/mach-picoxcell/common.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/arch/arm/mach-picoxcell/common.c b/arch/arm/mach-picoxcell/common.c index febee47bc116..a2e8ae8b5821 100644 --- a/arch/arm/mach-picoxcell/common.c +++ b/arch/arm/mach-picoxcell/common.c @@ -7,6 +7,7 @@ * * All enquiries to support@picochip.com */ +#include <linux/delay.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/of.h> @@ -23,6 +24,26 @@ #include "common.h" +#define WDT_CTRL_REG_EN_MASK (1 << 0) +#define WDT_CTRL_REG_OFFS (0x00) +#define WDT_TIMEOUT_REG_OFFS (0x04) +static void __iomem *wdt_regs; + +/* + * The machine restart method can be called from an atomic context so we won't + * be able to ioremap the regs then. + */ +static void picoxcell_setup_restart(void) +{ + struct device_node *np = of_find_compatible_node(NULL, NULL, + "snps,dw-apb-wdg"); + if (WARN(!np, "unable to setup watchdog restart")) + return; + + wdt_regs = of_iomap(np, 0); + WARN(!wdt_regs, "failed to remap watchdog regs"); +} + static struct map_desc io_map __initdata = { .virtual = PHYS_TO_IO(PICOXCELL_PERIPH_BASE), .pfn = __phys_to_pfn(PICOXCELL_PERIPH_BASE), @@ -38,6 +59,7 @@ static void __init picoxcell_map_io(void) static void __init picoxcell_init_machine(void) { of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + picoxcell_setup_restart(); } static const char *picoxcell_dt_match[] = { @@ -56,6 +78,20 @@ static void __init picoxcell_init_irq(void) of_irq_init(vic_of_match); } +static void picoxcell_wdt_restart(char mode, const char *cmd) +{ + /* + * Configure the watchdog to reset with the shortest possible timeout + * and give it chance to do the reset. + */ + if (wdt_regs) { + writel_relaxed(WDT_CTRL_REG_EN_MASK, wdt_regs + WDT_CTRL_REG_OFFS); + writel_relaxed(0, wdt_regs + WDT_TIMEOUT_REG_OFFS); + /* No sleeping, possibly atomic. */ + mdelay(500); + } +} + DT_MACHINE_START(PICOXCELL, "Picochip picoXcell") .map_io = picoxcell_map_io, .nr_irqs = NR_IRQS_LEGACY, @@ -64,4 +100,5 @@ DT_MACHINE_START(PICOXCELL, "Picochip picoXcell") .timer = &picoxcell_timer, .init_machine = picoxcell_init_machine, .dt_compat = picoxcell_dt_match, + .restart = picoxcell_wdt_restart, MACHINE_END |