13b52634fSMaxime Ripard /* 23b52634fSMaxime Ripard * Device Tree support for Allwinner A1X SoCs 33b52634fSMaxime Ripard * 43b52634fSMaxime Ripard * Copyright (C) 2012 Maxime Ripard 53b52634fSMaxime Ripard * 63b52634fSMaxime Ripard * Maxime Ripard <maxime.ripard@free-electrons.com> 73b52634fSMaxime Ripard * 83b52634fSMaxime Ripard * This file is licensed under the terms of the GNU General Public 93b52634fSMaxime Ripard * License version 2. This program is licensed "as is" without any 103b52634fSMaxime Ripard * warranty of any kind, whether express or implied. 113b52634fSMaxime Ripard */ 123b52634fSMaxime Ripard 13ea71d9a6SMaxime Ripard #include <linux/clocksource.h> 145e51651dSJosh Cartwright #include <linux/delay.h> 153b52634fSMaxime Ripard #include <linux/kernel.h> 163b52634fSMaxime Ripard #include <linux/init.h> 17f1dc6c4fSMaxime Ripard #include <linux/irqchip.h> 1867bea88dSMaxime Ripard #include <linux/of_address.h> 193b52634fSMaxime Ripard #include <linux/of_irq.h> 203b52634fSMaxime Ripard #include <linux/of_platform.h> 213b52634fSMaxime Ripard #include <linux/io.h> 223b52634fSMaxime Ripard 23ea71d9a6SMaxime Ripard #include <linux/clk/sunxi.h> 243b52634fSMaxime Ripard 253b52634fSMaxime Ripard #include <asm/mach/arch.h> 263b52634fSMaxime Ripard #include <asm/mach/map.h> 273b52634fSMaxime Ripard 283b52634fSMaxime Ripard #include "sunxi.h" 293b52634fSMaxime Ripard 3067bea88dSMaxime Ripard #define WATCHDOG_CTRL_REG 0x00 31b60decadSMaxime Ripard #define WATCHDOG_CTRL_RESTART (1 << 0) 3267bea88dSMaxime Ripard #define WATCHDOG_MODE_REG 0x04 33b60decadSMaxime Ripard #define WATCHDOG_MODE_ENABLE (1 << 0) 34b60decadSMaxime Ripard #define WATCHDOG_MODE_RESET_ENABLE (1 << 1) 3567bea88dSMaxime Ripard 3667bea88dSMaxime Ripard static void __iomem *wdt_base; 3767bea88dSMaxime Ripard 3867bea88dSMaxime Ripard static void sunxi_setup_restart(void) 3967bea88dSMaxime Ripard { 4067bea88dSMaxime Ripard struct device_node *np = of_find_compatible_node(NULL, NULL, 4167bea88dSMaxime Ripard "allwinner,sunxi-wdt"); 4267bea88dSMaxime Ripard if (WARN(!np, "unable to setup watchdog restart")) 4367bea88dSMaxime Ripard return; 4467bea88dSMaxime Ripard 4567bea88dSMaxime Ripard wdt_base = of_iomap(np, 0); 4667bea88dSMaxime Ripard WARN(!wdt_base, "failed to map watchdog base address"); 4767bea88dSMaxime Ripard } 4867bea88dSMaxime Ripard 4967bea88dSMaxime Ripard static void sunxi_restart(char mode, const char *cmd) 5067bea88dSMaxime Ripard { 5167bea88dSMaxime Ripard if (!wdt_base) 5267bea88dSMaxime Ripard return; 5367bea88dSMaxime Ripard 5467bea88dSMaxime Ripard /* Enable timer and set reset bit in the watchdog */ 55b60decadSMaxime Ripard writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE, 56b60decadSMaxime Ripard wdt_base + WATCHDOG_MODE_REG); 57b60decadSMaxime Ripard 58b60decadSMaxime Ripard /* 59b60decadSMaxime Ripard * Restart the watchdog. The default (and lowest) interval 60b60decadSMaxime Ripard * value for the watchdog is 0.5s. 61b60decadSMaxime Ripard */ 62b60decadSMaxime Ripard writel(WATCHDOG_CTRL_RESTART, wdt_base + WATCHDOG_CTRL_REG); 63b60decadSMaxime Ripard 6467bea88dSMaxime Ripard while (1) { 6567bea88dSMaxime Ripard mdelay(5); 66b60decadSMaxime Ripard writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE, 67b60decadSMaxime Ripard wdt_base + WATCHDOG_MODE_REG); 6867bea88dSMaxime Ripard } 6967bea88dSMaxime Ripard } 7067bea88dSMaxime Ripard 713b52634fSMaxime Ripard static struct map_desc sunxi_io_desc[] __initdata = { 723b52634fSMaxime Ripard { 733b52634fSMaxime Ripard .virtual = (unsigned long) SUNXI_REGS_VIRT_BASE, 743b52634fSMaxime Ripard .pfn = __phys_to_pfn(SUNXI_REGS_PHYS_BASE), 753b52634fSMaxime Ripard .length = SUNXI_REGS_SIZE, 763b52634fSMaxime Ripard .type = MT_DEVICE, 773b52634fSMaxime Ripard }, 783b52634fSMaxime Ripard }; 793b52634fSMaxime Ripard 803b52634fSMaxime Ripard void __init sunxi_map_io(void) 813b52634fSMaxime Ripard { 823b52634fSMaxime Ripard iotable_init(sunxi_io_desc, ARRAY_SIZE(sunxi_io_desc)); 833b52634fSMaxime Ripard } 843b52634fSMaxime Ripard 85ea71d9a6SMaxime Ripard static void __init sunxi_timer_init(void) 86ea71d9a6SMaxime Ripard { 87ea71d9a6SMaxime Ripard sunxi_init_clocks(); 88ea71d9a6SMaxime Ripard clocksource_of_init(); 89ea71d9a6SMaxime Ripard } 90ea71d9a6SMaxime Ripard 913b52634fSMaxime Ripard static void __init sunxi_dt_init(void) 923b52634fSMaxime Ripard { 9367bea88dSMaxime Ripard sunxi_setup_restart(); 9467bea88dSMaxime Ripard 953b52634fSMaxime Ripard of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 963b52634fSMaxime Ripard } 973b52634fSMaxime Ripard 983b52634fSMaxime Ripard static const char * const sunxi_board_dt_compat[] = { 9943880f70SMaxime Ripard "allwinner,sun4i-a10", 10043880f70SMaxime Ripard "allwinner,sun5i-a13", 1013b52634fSMaxime Ripard NULL, 1023b52634fSMaxime Ripard }; 1033b52634fSMaxime Ripard 1043b52634fSMaxime Ripard DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)") 1053b52634fSMaxime Ripard .init_machine = sunxi_dt_init, 1063b52634fSMaxime Ripard .map_io = sunxi_map_io, 107f1dc6c4fSMaxime Ripard .init_irq = irqchip_init, 10867bea88dSMaxime Ripard .restart = sunxi_restart, 109ea71d9a6SMaxime Ripard .init_time = sunxi_timer_init, 1103b52634fSMaxime Ripard .dt_compat = sunxi_board_dt_compat, 1113b52634fSMaxime Ripard MACHINE_END 112