|  | /* | 
|  | * Copyright (c) 2011 Picochip Ltd., Jamie Iles | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or modify | 
|  | * it under the terms of the GNU General Public License version 2 as | 
|  | * published by the Free Software Foundation. | 
|  | * | 
|  | * All enquiries to support@picochip.com | 
|  | */ | 
|  | #include <linux/delay.h> | 
|  | #include <linux/of.h> | 
|  | #include <linux/of_address.h> | 
|  | #include <linux/reboot.h> | 
|  |  | 
|  | #include <asm/mach/arch.h> | 
|  | #include <asm/mach/map.h> | 
|  |  | 
|  | #define PHYS_TO_IO(x)			(((x) & 0x00ffffff) | 0xfe000000) | 
|  | #define PICOXCELL_PERIPH_BASE		0x80000000 | 
|  | #define PICOXCELL_PERIPH_LENGTH		SZ_4M | 
|  |  | 
|  | #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), | 
|  | .length		= PICOXCELL_PERIPH_LENGTH, | 
|  | .type		= MT_DEVICE, | 
|  | }; | 
|  |  | 
|  | static void __init picoxcell_map_io(void) | 
|  | { | 
|  | iotable_init(&io_map, 1); | 
|  | } | 
|  |  | 
|  | static void __init picoxcell_init_machine(void) | 
|  | { | 
|  | picoxcell_setup_restart(); | 
|  | } | 
|  |  | 
|  | static const char *picoxcell_dt_match[] = { | 
|  | "picochip,pc3x2", | 
|  | "picochip,pc3x3", | 
|  | NULL | 
|  | }; | 
|  |  | 
|  | static void picoxcell_wdt_restart(enum reboot_mode 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, | 
|  | .init_machine	= picoxcell_init_machine, | 
|  | .dt_compat	= picoxcell_dt_match, | 
|  | .restart	= picoxcell_wdt_restart, | 
|  | MACHINE_END |