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> 27bc34b5f2SMaxime Ripard #include <asm/system_misc.h> 283b52634fSMaxime Ripard 293b52634fSMaxime Ripard #include "sunxi.h" 303b52634fSMaxime Ripard 31bc34b5f2SMaxime Ripard #define SUN4I_WATCHDOG_CTRL_REG 0x00 32bc34b5f2SMaxime Ripard #define SUN4I_WATCHDOG_CTRL_RESTART (1 << 0) 33bc34b5f2SMaxime Ripard #define SUN4I_WATCHDOG_MODE_REG 0x04 34bc34b5f2SMaxime Ripard #define SUN4I_WATCHDOG_MODE_ENABLE (1 << 0) 35bc34b5f2SMaxime Ripard #define SUN4I_WATCHDOG_MODE_RESET_ENABLE (1 << 1) 3667bea88dSMaxime Ripard 3767bea88dSMaxime Ripard static void __iomem *wdt_base; 3867bea88dSMaxime Ripard 39bc34b5f2SMaxime Ripard static void sun4i_restart(char mode, const char *cmd) 4067bea88dSMaxime Ripard { 4167bea88dSMaxime Ripard if (!wdt_base) 4267bea88dSMaxime Ripard return; 4367bea88dSMaxime Ripard 4467bea88dSMaxime Ripard /* Enable timer and set reset bit in the watchdog */ 45bc34b5f2SMaxime Ripard writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE, 46bc34b5f2SMaxime Ripard wdt_base + SUN4I_WATCHDOG_MODE_REG); 47b60decadSMaxime Ripard 48b60decadSMaxime Ripard /* 49b60decadSMaxime Ripard * Restart the watchdog. The default (and lowest) interval 50b60decadSMaxime Ripard * value for the watchdog is 0.5s. 51b60decadSMaxime Ripard */ 52bc34b5f2SMaxime Ripard writel(SUN4I_WATCHDOG_CTRL_RESTART, wdt_base + SUN4I_WATCHDOG_CTRL_REG); 53b60decadSMaxime Ripard 5467bea88dSMaxime Ripard while (1) { 5567bea88dSMaxime Ripard mdelay(5); 56bc34b5f2SMaxime Ripard writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE, 57bc34b5f2SMaxime Ripard wdt_base + SUN4I_WATCHDOG_MODE_REG); 5867bea88dSMaxime Ripard } 5967bea88dSMaxime Ripard } 6067bea88dSMaxime Ripard 61bc34b5f2SMaxime Ripard static struct of_device_id sunxi_restart_ids[] = { 62bc34b5f2SMaxime Ripard { .compatible = "allwinner,sun4i-wdt", .data = sun4i_restart }, 63bc34b5f2SMaxime Ripard { /*sentinel*/ } 64bc34b5f2SMaxime Ripard }; 65bc34b5f2SMaxime Ripard 66bc34b5f2SMaxime Ripard static void sunxi_setup_restart(void) 67bc34b5f2SMaxime Ripard { 68bc34b5f2SMaxime Ripard const struct of_device_id *of_id; 69bc34b5f2SMaxime Ripard struct device_node *np; 70bc34b5f2SMaxime Ripard 71bc34b5f2SMaxime Ripard np = of_find_matching_node(NULL, sunxi_restart_ids); 72bc34b5f2SMaxime Ripard if (WARN(!np, "unable to setup watchdog restart")) 73bc34b5f2SMaxime Ripard return; 74bc34b5f2SMaxime Ripard 75bc34b5f2SMaxime Ripard wdt_base = of_iomap(np, 0); 76bc34b5f2SMaxime Ripard WARN(!wdt_base, "failed to map watchdog base address"); 77bc34b5f2SMaxime Ripard 78bc34b5f2SMaxime Ripard of_id = of_match_node(sunxi_restart_ids, np); 79bc34b5f2SMaxime Ripard WARN(!of_id, "restart function not available"); 80bc34b5f2SMaxime Ripard 81bc34b5f2SMaxime Ripard arm_pm_restart = of_id->data; 82bc34b5f2SMaxime Ripard } 83bc34b5f2SMaxime Ripard 843b52634fSMaxime Ripard static struct map_desc sunxi_io_desc[] __initdata = { 853b52634fSMaxime Ripard { 863b52634fSMaxime Ripard .virtual = (unsigned long) SUNXI_REGS_VIRT_BASE, 873b52634fSMaxime Ripard .pfn = __phys_to_pfn(SUNXI_REGS_PHYS_BASE), 883b52634fSMaxime Ripard .length = SUNXI_REGS_SIZE, 893b52634fSMaxime Ripard .type = MT_DEVICE, 903b52634fSMaxime Ripard }, 913b52634fSMaxime Ripard }; 923b52634fSMaxime Ripard 933b52634fSMaxime Ripard void __init sunxi_map_io(void) 943b52634fSMaxime Ripard { 953b52634fSMaxime Ripard iotable_init(sunxi_io_desc, ARRAY_SIZE(sunxi_io_desc)); 963b52634fSMaxime Ripard } 973b52634fSMaxime Ripard 98ea71d9a6SMaxime Ripard static void __init sunxi_timer_init(void) 99ea71d9a6SMaxime Ripard { 100ea71d9a6SMaxime Ripard sunxi_init_clocks(); 101ea71d9a6SMaxime Ripard clocksource_of_init(); 102ea71d9a6SMaxime Ripard } 103ea71d9a6SMaxime Ripard 1043b52634fSMaxime Ripard static void __init sunxi_dt_init(void) 1053b52634fSMaxime Ripard { 10667bea88dSMaxime Ripard sunxi_setup_restart(); 10767bea88dSMaxime Ripard 1083b52634fSMaxime Ripard of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 1093b52634fSMaxime Ripard } 1103b52634fSMaxime Ripard 1113b52634fSMaxime Ripard static const char * const sunxi_board_dt_compat[] = { 11243880f70SMaxime Ripard "allwinner,sun4i-a10", 11343880f70SMaxime Ripard "allwinner,sun5i-a13", 1143b52634fSMaxime Ripard NULL, 1153b52634fSMaxime Ripard }; 1163b52634fSMaxime Ripard 1173b52634fSMaxime Ripard DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)") 1183b52634fSMaxime Ripard .init_machine = sunxi_dt_init, 1193b52634fSMaxime Ripard .map_io = sunxi_map_io, 120f1dc6c4fSMaxime Ripard .init_irq = irqchip_init, 121ea71d9a6SMaxime Ripard .init_time = sunxi_timer_init, 1223b52634fSMaxime Ripard .dt_compat = sunxi_board_dt_compat, 1233b52634fSMaxime Ripard MACHINE_END 124