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 13751b2ac4SMaxime Ripard #include <linux/clk-provider.h> 14751b2ac4SMaxime Ripard #include <linux/clocksource.h> 15d767af5eSMaxime Ripard #include <linux/delay.h> 16d767af5eSMaxime Ripard #include <linux/kernel.h> 17d767af5eSMaxime Ripard #include <linux/init.h> 18d767af5eSMaxime Ripard #include <linux/of_address.h> 19d767af5eSMaxime Ripard #include <linux/of_irq.h> 20d767af5eSMaxime Ripard #include <linux/of_platform.h> 21d767af5eSMaxime Ripard #include <linux/io.h> 22d767af5eSMaxime Ripard #include <linux/reboot.h> 233b52634fSMaxime Ripard 243b52634fSMaxime Ripard #include <asm/mach/arch.h> 25d767af5eSMaxime Ripard #include <asm/mach/map.h> 26d767af5eSMaxime Ripard #include <asm/system_misc.h> 27d767af5eSMaxime Ripard 28d767af5eSMaxime Ripard #define SUN4I_WATCHDOG_CTRL_REG 0x00 29d767af5eSMaxime Ripard #define SUN4I_WATCHDOG_CTRL_RESTART BIT(0) 30d767af5eSMaxime Ripard #define SUN4I_WATCHDOG_MODE_REG 0x04 31d767af5eSMaxime Ripard #define SUN4I_WATCHDOG_MODE_ENABLE BIT(0) 32d767af5eSMaxime Ripard #define SUN4I_WATCHDOG_MODE_RESET_ENABLE BIT(1) 33d767af5eSMaxime Ripard 34d767af5eSMaxime Ripard #define SUN6I_WATCHDOG1_IRQ_REG 0x00 35d767af5eSMaxime Ripard #define SUN6I_WATCHDOG1_CTRL_REG 0x10 36d767af5eSMaxime Ripard #define SUN6I_WATCHDOG1_CTRL_RESTART BIT(0) 37d767af5eSMaxime Ripard #define SUN6I_WATCHDOG1_CONFIG_REG 0x14 38d767af5eSMaxime Ripard #define SUN6I_WATCHDOG1_CONFIG_RESTART BIT(0) 39d767af5eSMaxime Ripard #define SUN6I_WATCHDOG1_CONFIG_IRQ BIT(1) 40d767af5eSMaxime Ripard #define SUN6I_WATCHDOG1_MODE_REG 0x18 41d767af5eSMaxime Ripard #define SUN6I_WATCHDOG1_MODE_ENABLE BIT(0) 42d767af5eSMaxime Ripard 43d767af5eSMaxime Ripard static void __iomem *wdt_base; 44d767af5eSMaxime Ripard 45d767af5eSMaxime Ripard static void sun4i_restart(enum reboot_mode mode, const char *cmd) 46d767af5eSMaxime Ripard { 47d767af5eSMaxime Ripard if (!wdt_base) 48d767af5eSMaxime Ripard return; 49d767af5eSMaxime Ripard 50d767af5eSMaxime Ripard /* Enable timer and set reset bit in the watchdog */ 51d767af5eSMaxime Ripard writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE, 52d767af5eSMaxime Ripard wdt_base + SUN4I_WATCHDOG_MODE_REG); 53d767af5eSMaxime Ripard 54d767af5eSMaxime Ripard /* 55d767af5eSMaxime Ripard * Restart the watchdog. The default (and lowest) interval 56d767af5eSMaxime Ripard * value for the watchdog is 0.5s. 57d767af5eSMaxime Ripard */ 58d767af5eSMaxime Ripard writel(SUN4I_WATCHDOG_CTRL_RESTART, wdt_base + SUN4I_WATCHDOG_CTRL_REG); 59d767af5eSMaxime Ripard 60d767af5eSMaxime Ripard while (1) { 61d767af5eSMaxime Ripard mdelay(5); 62d767af5eSMaxime Ripard writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE, 63d767af5eSMaxime Ripard wdt_base + SUN4I_WATCHDOG_MODE_REG); 64d767af5eSMaxime Ripard } 65d767af5eSMaxime Ripard } 66d767af5eSMaxime Ripard 67d767af5eSMaxime Ripard static struct of_device_id sunxi_restart_ids[] = { 68d767af5eSMaxime Ripard { .compatible = "allwinner,sun4i-a10-wdt" }, 69d767af5eSMaxime Ripard { /*sentinel*/ } 70d767af5eSMaxime Ripard }; 71d767af5eSMaxime Ripard 72d767af5eSMaxime Ripard static void sunxi_setup_restart(void) 73d767af5eSMaxime Ripard { 74d767af5eSMaxime Ripard struct device_node *np; 75d767af5eSMaxime Ripard 76d767af5eSMaxime Ripard np = of_find_matching_node(NULL, sunxi_restart_ids); 77d767af5eSMaxime Ripard if (WARN(!np, "unable to setup watchdog restart")) 78d767af5eSMaxime Ripard return; 79d767af5eSMaxime Ripard 80d767af5eSMaxime Ripard wdt_base = of_iomap(np, 0); 81d767af5eSMaxime Ripard WARN(!wdt_base, "failed to map watchdog base address"); 82d767af5eSMaxime Ripard } 83d767af5eSMaxime Ripard 84d767af5eSMaxime Ripard static void __init sunxi_dt_init(void) 85d767af5eSMaxime Ripard { 86d767af5eSMaxime Ripard sunxi_setup_restart(); 87d767af5eSMaxime Ripard 88d767af5eSMaxime Ripard of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 89d767af5eSMaxime Ripard } 90bc34b5f2SMaxime Ripard 913b52634fSMaxime Ripard static const char * const sunxi_board_dt_compat[] = { 9243880f70SMaxime Ripard "allwinner,sun4i-a10", 9381265dfbSMaxime Ripard "allwinner,sun5i-a10s", 9443880f70SMaxime Ripard "allwinner,sun5i-a13", 953b52634fSMaxime Ripard NULL, 963b52634fSMaxime Ripard }; 973b52634fSMaxime Ripard 983b52634fSMaxime Ripard DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)") 99d767af5eSMaxime Ripard .init_machine = sunxi_dt_init, 1003b52634fSMaxime Ripard .dt_compat = sunxi_board_dt_compat, 101d767af5eSMaxime Ripard .restart = sun4i_restart, 1023b52634fSMaxime Ripard MACHINE_END 10391a31977SMaxime Ripard 10491a31977SMaxime Ripard static const char * const sun6i_board_dt_compat[] = { 10591a31977SMaxime Ripard "allwinner,sun6i-a31", 10691a31977SMaxime Ripard NULL, 10791a31977SMaxime Ripard }; 10891a31977SMaxime Ripard 109751b2ac4SMaxime Ripard extern void __init sun6i_reset_init(void); 110751b2ac4SMaxime Ripard static void __init sun6i_timer_init(void) 111751b2ac4SMaxime Ripard { 112751b2ac4SMaxime Ripard of_clk_init(NULL); 113e58cf019SArnd Bergmann if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) 114751b2ac4SMaxime Ripard sun6i_reset_init(); 115751b2ac4SMaxime Ripard clocksource_of_init(); 116751b2ac4SMaxime Ripard } 117751b2ac4SMaxime Ripard 11891a31977SMaxime Ripard DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") 119751b2ac4SMaxime Ripard .init_time = sun6i_timer_init, 12091a31977SMaxime Ripard .dt_compat = sun6i_board_dt_compat, 12191a31977SMaxime Ripard MACHINE_END 12291a31977SMaxime Ripard 12391a31977SMaxime Ripard static const char * const sun7i_board_dt_compat[] = { 12491a31977SMaxime Ripard "allwinner,sun7i-a20", 12591a31977SMaxime Ripard NULL, 12691a31977SMaxime Ripard }; 12791a31977SMaxime Ripard 12891a31977SMaxime Ripard DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family") 129d767af5eSMaxime Ripard .init_machine = sunxi_dt_init, 13091a31977SMaxime Ripard .dt_compat = sun7i_board_dt_compat, 131d767af5eSMaxime Ripard .restart = sun4i_restart, 1323b52634fSMaxime Ripard MACHINE_END 133