1 /* 2 * Device Tree support for Allwinner A1X SoCs 3 * 4 * Copyright (C) 2012 Maxime Ripard 5 * 6 * Maxime Ripard <maxime.ripard@free-electrons.com> 7 * 8 * This file is licensed under the terms of the GNU General Public 9 * License version 2. This program is licensed "as is" without any 10 * warranty of any kind, whether express or implied. 11 */ 12 13 #include <linux/clk-provider.h> 14 #include <linux/clocksource.h> 15 #include <linux/delay.h> 16 #include <linux/kernel.h> 17 #include <linux/init.h> 18 #include <linux/of_address.h> 19 #include <linux/of_irq.h> 20 #include <linux/of_platform.h> 21 #include <linux/io.h> 22 #include <linux/reboot.h> 23 24 #include <asm/mach/arch.h> 25 #include <asm/mach/map.h> 26 #include <asm/system_misc.h> 27 28 #include "common.h" 29 30 #define SUN4I_WATCHDOG_CTRL_REG 0x00 31 #define SUN4I_WATCHDOG_CTRL_RESTART BIT(0) 32 #define SUN4I_WATCHDOG_MODE_REG 0x04 33 #define SUN4I_WATCHDOG_MODE_ENABLE BIT(0) 34 #define SUN4I_WATCHDOG_MODE_RESET_ENABLE BIT(1) 35 36 #define SUN6I_WATCHDOG1_IRQ_REG 0x00 37 #define SUN6I_WATCHDOG1_CTRL_REG 0x10 38 #define SUN6I_WATCHDOG1_CTRL_RESTART BIT(0) 39 #define SUN6I_WATCHDOG1_CONFIG_REG 0x14 40 #define SUN6I_WATCHDOG1_CONFIG_RESTART BIT(0) 41 #define SUN6I_WATCHDOG1_CONFIG_IRQ BIT(1) 42 #define SUN6I_WATCHDOG1_MODE_REG 0x18 43 #define SUN6I_WATCHDOG1_MODE_ENABLE BIT(0) 44 45 static void __iomem *wdt_base; 46 47 static void sun4i_restart(enum reboot_mode mode, const char *cmd) 48 { 49 if (!wdt_base) 50 return; 51 52 /* Enable timer and set reset bit in the watchdog */ 53 writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE, 54 wdt_base + SUN4I_WATCHDOG_MODE_REG); 55 56 /* 57 * Restart the watchdog. The default (and lowest) interval 58 * value for the watchdog is 0.5s. 59 */ 60 writel(SUN4I_WATCHDOG_CTRL_RESTART, wdt_base + SUN4I_WATCHDOG_CTRL_REG); 61 62 while (1) { 63 mdelay(5); 64 writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE, 65 wdt_base + SUN4I_WATCHDOG_MODE_REG); 66 } 67 } 68 69 static void sun6i_restart(enum reboot_mode mode, const char *cmd) 70 { 71 if (!wdt_base) 72 return; 73 74 /* Disable interrupts */ 75 writel(0, wdt_base + SUN6I_WATCHDOG1_IRQ_REG); 76 77 /* We want to disable the IRQ and just reset the whole system */ 78 writel(SUN6I_WATCHDOG1_CONFIG_RESTART, 79 wdt_base + SUN6I_WATCHDOG1_CONFIG_REG); 80 81 /* Enable timer. The default and lowest interval value is 0.5s */ 82 writel(SUN6I_WATCHDOG1_MODE_ENABLE, 83 wdt_base + SUN6I_WATCHDOG1_MODE_REG); 84 85 /* Restart the watchdog. */ 86 writel(SUN6I_WATCHDOG1_CTRL_RESTART, 87 wdt_base + SUN6I_WATCHDOG1_CTRL_REG); 88 89 while (1) { 90 mdelay(5); 91 writel(SUN6I_WATCHDOG1_MODE_ENABLE, 92 wdt_base + SUN6I_WATCHDOG1_MODE_REG); 93 } 94 } 95 96 static struct of_device_id sunxi_restart_ids[] = { 97 { .compatible = "allwinner,sun4i-a10-wdt" }, 98 { .compatible = "allwinner,sun6i-a31-wdt" }, 99 { /*sentinel*/ } 100 }; 101 102 static void sunxi_setup_restart(void) 103 { 104 struct device_node *np; 105 106 np = of_find_matching_node(NULL, sunxi_restart_ids); 107 if (WARN(!np, "unable to setup watchdog restart")) 108 return; 109 110 wdt_base = of_iomap(np, 0); 111 WARN(!wdt_base, "failed to map watchdog base address"); 112 } 113 114 static void __init sunxi_dt_init(void) 115 { 116 sunxi_setup_restart(); 117 118 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 119 } 120 121 static const char * const sunxi_board_dt_compat[] = { 122 "allwinner,sun4i-a10", 123 "allwinner,sun5i-a10s", 124 "allwinner,sun5i-a13", 125 NULL, 126 }; 127 128 DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)") 129 .init_machine = sunxi_dt_init, 130 .dt_compat = sunxi_board_dt_compat, 131 .restart = sun4i_restart, 132 MACHINE_END 133 134 static const char * const sun6i_board_dt_compat[] = { 135 "allwinner,sun6i-a31", 136 NULL, 137 }; 138 139 extern void __init sun6i_reset_init(void); 140 static void __init sun6i_timer_init(void) 141 { 142 of_clk_init(NULL); 143 sun6i_reset_init(); 144 clocksource_of_init(); 145 } 146 147 DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") 148 .init_machine = sunxi_dt_init, 149 .init_time = sun6i_timer_init, 150 .dt_compat = sun6i_board_dt_compat, 151 .restart = sun6i_restart, 152 .smp = smp_ops(sun6i_smp_ops), 153 MACHINE_END 154 155 static const char * const sun7i_board_dt_compat[] = { 156 "allwinner,sun7i-a20", 157 NULL, 158 }; 159 160 DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family") 161 .init_machine = sunxi_dt_init, 162 .dt_compat = sun7i_board_dt_compat, 163 .restart = sun4i_restart, 164 MACHINE_END 165