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> 1767bea88dSMaxime Ripard #include <linux/of_address.h> 183b52634fSMaxime Ripard #include <linux/of_irq.h> 193b52634fSMaxime Ripard #include <linux/of_platform.h> 203b52634fSMaxime Ripard #include <linux/io.h> 217b6d864bSRobin Holt #include <linux/reboot.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 29bc34b5f2SMaxime Ripard #define SUN4I_WATCHDOG_CTRL_REG 0x00 3006d71bcfSMaxime Ripard #define SUN4I_WATCHDOG_CTRL_RESTART BIT(0) 31bc34b5f2SMaxime Ripard #define SUN4I_WATCHDOG_MODE_REG 0x04 3206d71bcfSMaxime Ripard #define SUN4I_WATCHDOG_MODE_ENABLE BIT(0) 3306d71bcfSMaxime Ripard #define SUN4I_WATCHDOG_MODE_RESET_ENABLE BIT(1) 3406d71bcfSMaxime Ripard 3506d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_IRQ_REG 0x00 3606d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CTRL_REG 0x10 3706d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CTRL_RESTART BIT(0) 3806d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CONFIG_REG 0x14 3906d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CONFIG_RESTART BIT(0) 4006d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CONFIG_IRQ BIT(1) 4106d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_MODE_REG 0x18 4206d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_MODE_ENABLE BIT(0) 4367bea88dSMaxime Ripard 4467bea88dSMaxime Ripard static void __iomem *wdt_base; 4567bea88dSMaxime Ripard 467b6d864bSRobin Holt static void sun4i_restart(enum reboot_mode mode, const char *cmd) 4767bea88dSMaxime Ripard { 4867bea88dSMaxime Ripard if (!wdt_base) 4967bea88dSMaxime Ripard return; 5067bea88dSMaxime Ripard 5167bea88dSMaxime Ripard /* Enable timer and set reset bit in the watchdog */ 52bc34b5f2SMaxime Ripard writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE, 53bc34b5f2SMaxime Ripard wdt_base + SUN4I_WATCHDOG_MODE_REG); 54b60decadSMaxime Ripard 55b60decadSMaxime Ripard /* 56b60decadSMaxime Ripard * Restart the watchdog. The default (and lowest) interval 57b60decadSMaxime Ripard * value for the watchdog is 0.5s. 58b60decadSMaxime Ripard */ 59bc34b5f2SMaxime Ripard writel(SUN4I_WATCHDOG_CTRL_RESTART, wdt_base + SUN4I_WATCHDOG_CTRL_REG); 60b60decadSMaxime Ripard 6167bea88dSMaxime Ripard while (1) { 6267bea88dSMaxime Ripard mdelay(5); 63bc34b5f2SMaxime Ripard writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE, 64bc34b5f2SMaxime Ripard wdt_base + SUN4I_WATCHDOG_MODE_REG); 6567bea88dSMaxime Ripard } 6667bea88dSMaxime Ripard } 6767bea88dSMaxime Ripard 6806d71bcfSMaxime Ripard static void sun6i_restart(enum reboot_mode mode, const char *cmd) 6906d71bcfSMaxime Ripard { 7006d71bcfSMaxime Ripard if (!wdt_base) 7106d71bcfSMaxime Ripard return; 7206d71bcfSMaxime Ripard 7306d71bcfSMaxime Ripard /* Disable interrupts */ 7406d71bcfSMaxime Ripard writel(0, wdt_base + SUN6I_WATCHDOG1_IRQ_REG); 7506d71bcfSMaxime Ripard 7606d71bcfSMaxime Ripard /* We want to disable the IRQ and just reset the whole system */ 7706d71bcfSMaxime Ripard writel(SUN6I_WATCHDOG1_CONFIG_RESTART, 7806d71bcfSMaxime Ripard wdt_base + SUN6I_WATCHDOG1_CONFIG_REG); 7906d71bcfSMaxime Ripard 8006d71bcfSMaxime Ripard /* Enable timer. The default and lowest interval value is 0.5s */ 8106d71bcfSMaxime Ripard writel(SUN6I_WATCHDOG1_MODE_ENABLE, 8206d71bcfSMaxime Ripard wdt_base + SUN6I_WATCHDOG1_MODE_REG); 8306d71bcfSMaxime Ripard 8406d71bcfSMaxime Ripard /* Restart the watchdog. */ 8506d71bcfSMaxime Ripard writel(SUN6I_WATCHDOG1_CTRL_RESTART, 8606d71bcfSMaxime Ripard wdt_base + SUN6I_WATCHDOG1_CTRL_REG); 8706d71bcfSMaxime Ripard 8806d71bcfSMaxime Ripard while (1) { 8906d71bcfSMaxime Ripard mdelay(5); 9006d71bcfSMaxime Ripard writel(SUN6I_WATCHDOG1_MODE_ENABLE, 9106d71bcfSMaxime Ripard wdt_base + SUN6I_WATCHDOG1_MODE_REG); 9206d71bcfSMaxime Ripard } 9306d71bcfSMaxime Ripard } 9406d71bcfSMaxime Ripard 95bc34b5f2SMaxime Ripard static struct of_device_id sunxi_restart_ids[] = { 96bc34b5f2SMaxime Ripard { .compatible = "allwinner,sun4i-wdt", .data = sun4i_restart }, 9706d71bcfSMaxime Ripard { .compatible = "allwinner,sun6i-wdt", .data = sun6i_restart }, 98bc34b5f2SMaxime Ripard { /*sentinel*/ } 99bc34b5f2SMaxime Ripard }; 100bc34b5f2SMaxime Ripard 101bc34b5f2SMaxime Ripard static void sunxi_setup_restart(void) 102bc34b5f2SMaxime Ripard { 103bc34b5f2SMaxime Ripard const struct of_device_id *of_id; 104bc34b5f2SMaxime Ripard struct device_node *np; 105bc34b5f2SMaxime Ripard 106bc34b5f2SMaxime Ripard np = of_find_matching_node(NULL, sunxi_restart_ids); 107bc34b5f2SMaxime Ripard if (WARN(!np, "unable to setup watchdog restart")) 108bc34b5f2SMaxime Ripard return; 109bc34b5f2SMaxime Ripard 110bc34b5f2SMaxime Ripard wdt_base = of_iomap(np, 0); 111bc34b5f2SMaxime Ripard WARN(!wdt_base, "failed to map watchdog base address"); 112bc34b5f2SMaxime Ripard 113bc34b5f2SMaxime Ripard of_id = of_match_node(sunxi_restart_ids, np); 114bc34b5f2SMaxime Ripard WARN(!of_id, "restart function not available"); 115bc34b5f2SMaxime Ripard 116bc34b5f2SMaxime Ripard arm_pm_restart = of_id->data; 117bc34b5f2SMaxime Ripard } 118bc34b5f2SMaxime Ripard 119ea71d9a6SMaxime Ripard static void __init sunxi_timer_init(void) 120ea71d9a6SMaxime Ripard { 121ea71d9a6SMaxime Ripard sunxi_init_clocks(); 122ea71d9a6SMaxime Ripard clocksource_of_init(); 123ea71d9a6SMaxime Ripard } 124ea71d9a6SMaxime Ripard 1253b52634fSMaxime Ripard static void __init sunxi_dt_init(void) 1263b52634fSMaxime Ripard { 12767bea88dSMaxime Ripard sunxi_setup_restart(); 12867bea88dSMaxime Ripard 1293b52634fSMaxime Ripard of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 1303b52634fSMaxime Ripard } 1313b52634fSMaxime Ripard 1323b52634fSMaxime Ripard static const char * const sunxi_board_dt_compat[] = { 13343880f70SMaxime Ripard "allwinner,sun4i-a10", 13481265dfbSMaxime Ripard "allwinner,sun5i-a10s", 13543880f70SMaxime Ripard "allwinner,sun5i-a13", 1363b52634fSMaxime Ripard NULL, 1373b52634fSMaxime Ripard }; 1383b52634fSMaxime Ripard 1393b52634fSMaxime Ripard DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)") 1403b52634fSMaxime Ripard .init_machine = sunxi_dt_init, 141ea71d9a6SMaxime Ripard .init_time = sunxi_timer_init, 1423b52634fSMaxime Ripard .dt_compat = sunxi_board_dt_compat, 1433b52634fSMaxime Ripard MACHINE_END 14491a31977SMaxime Ripard 14591a31977SMaxime Ripard static const char * const sun6i_board_dt_compat[] = { 14691a31977SMaxime Ripard "allwinner,sun6i-a31", 14791a31977SMaxime Ripard NULL, 14891a31977SMaxime Ripard }; 14991a31977SMaxime Ripard 15091a31977SMaxime Ripard DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") 15191a31977SMaxime Ripard .init_machine = sunxi_dt_init, 15291a31977SMaxime Ripard .init_time = sunxi_timer_init, 15391a31977SMaxime Ripard .dt_compat = sun6i_board_dt_compat, 15491a31977SMaxime Ripard MACHINE_END 15591a31977SMaxime Ripard 15691a31977SMaxime Ripard static const char * const sun7i_board_dt_compat[] = { 15791a31977SMaxime Ripard "allwinner,sun7i-a20", 15891a31977SMaxime Ripard NULL, 15991a31977SMaxime Ripard }; 16091a31977SMaxime Ripard 16191a31977SMaxime Ripard DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family") 16291a31977SMaxime Ripard .init_machine = sunxi_dt_init, 16391a31977SMaxime Ripard .init_time = sunxi_timer_init, 16491a31977SMaxime Ripard .dt_compat = sun7i_board_dt_compat, 16591a31977SMaxime Ripard MACHINE_END 166