blob: aeea6ceea725f5e8fb8495f09850616400679710 [file] [log] [blame]
Maxime Ripard3b526342012-11-08 12:40:16 +01001/*
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
Maxime Ripard751b2ac2013-10-05 14:53:48 +020013#include <linux/clk-provider.h>
14#include <linux/clocksource.h>
Josh Cartwright5e516512012-11-29 19:37:30 -060015#include <linux/delay.h>
Maxime Ripard3b526342012-11-08 12:40:16 +010016#include <linux/kernel.h>
17#include <linux/init.h>
Maxime Ripard67bea882012-11-19 18:57:08 +010018#include <linux/of_address.h>
Maxime Ripard3b526342012-11-08 12:40:16 +010019#include <linux/of_irq.h>
20#include <linux/of_platform.h>
21#include <linux/io.h>
Robin Holt7b6d8642013-07-08 16:01:40 -070022#include <linux/reboot.h>
Maxime Ripard3b526342012-11-08 12:40:16 +010023
Maxime Ripard3b526342012-11-08 12:40:16 +010024#include <asm/mach/arch.h>
25#include <asm/mach/map.h>
Maxime Ripardbc34b5f2013-03-11 20:21:11 +010026#include <asm/system_misc.h>
Maxime Ripard3b526342012-11-08 12:40:16 +010027
Maxime Ripard73346792013-11-03 10:30:13 +010028#include "common.h"
29
Maxime Ripardbc34b5f2013-03-11 20:21:11 +010030#define SUN4I_WATCHDOG_CTRL_REG 0x00
Maxime Ripard06d71bc2013-03-11 20:21:11 +010031#define SUN4I_WATCHDOG_CTRL_RESTART BIT(0)
Maxime Ripardbc34b5f2013-03-11 20:21:11 +010032#define SUN4I_WATCHDOG_MODE_REG 0x04
Maxime Ripard06d71bc2013-03-11 20:21:11 +010033#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)
Maxime Ripard67bea882012-11-19 18:57:08 +010044
45static void __iomem *wdt_base;
46
Robin Holt7b6d8642013-07-08 16:01:40 -070047static void sun4i_restart(enum reboot_mode mode, const char *cmd)
Maxime Ripard67bea882012-11-19 18:57:08 +010048{
49 if (!wdt_base)
50 return;
51
52 /* Enable timer and set reset bit in the watchdog */
Maxime Ripardbc34b5f2013-03-11 20:21:11 +010053 writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE,
54 wdt_base + SUN4I_WATCHDOG_MODE_REG);
Maxime Ripardb60deca2013-02-04 23:32:39 +010055
56 /*
57 * Restart the watchdog. The default (and lowest) interval
58 * value for the watchdog is 0.5s.
59 */
Maxime Ripardbc34b5f2013-03-11 20:21:11 +010060 writel(SUN4I_WATCHDOG_CTRL_RESTART, wdt_base + SUN4I_WATCHDOG_CTRL_REG);
Maxime Ripardb60deca2013-02-04 23:32:39 +010061
62 while (1) {
Maxime Ripard67bea882012-11-19 18:57:08 +010063 mdelay(5);
Maxime Ripardbc34b5f2013-03-11 20:21:11 +010064 writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE,
65 wdt_base + SUN4I_WATCHDOG_MODE_REG);
Maxime Ripard67bea882012-11-19 18:57:08 +010066 }
67}
68
Maxime Ripard06d71bc2013-03-11 20:21:11 +010069static 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
Maxime Ripardbc34b5f2013-03-11 20:21:11 +010096static struct of_device_id sunxi_restart_ids[] = {
Maxime Ripard53ea6882013-08-11 14:38:59 +020097 { .compatible = "allwinner,sun4i-wdt" },
98 { .compatible = "allwinner,sun6i-wdt" },
Maxime Ripardbc34b5f2013-03-11 20:21:11 +010099 { /*sentinel*/ }
100};
101
102static void sunxi_setup_restart(void)
103{
Maxime Ripardbc34b5f2013-03-11 20:21:11 +0100104 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");
Maxime Ripardbc34b5f2013-03-11 20:21:11 +0100112}
113
Maxime Ripard3b526342012-11-08 12:40:16 +0100114static void __init sunxi_dt_init(void)
115{
Maxime Ripard67bea882012-11-19 18:57:08 +0100116 sunxi_setup_restart();
117
Maxime Ripard3b526342012-11-08 12:40:16 +0100118 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
119}
120
121static const char * const sunxi_board_dt_compat[] = {
Maxime Ripard43880f72012-12-18 15:17:12 +0100122 "allwinner,sun4i-a10",
Maxime Ripard81265df2013-06-09 09:40:05 +0200123 "allwinner,sun5i-a10s",
Maxime Ripard43880f72012-12-18 15:17:12 +0100124 "allwinner,sun5i-a13",
Maxime Ripard3b526342012-11-08 12:40:16 +0100125 NULL,
126};
127
128DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
129 .init_machine = sunxi_dt_init,
Maxime Ripard3b526342012-11-08 12:40:16 +0100130 .dt_compat = sunxi_board_dt_compat,
Maxime Ripard53ea6882013-08-11 14:38:59 +0200131 .restart = sun4i_restart,
Maxime Ripard3b526342012-11-08 12:40:16 +0100132MACHINE_END
Maxime Ripard91a31972013-08-11 14:35:08 +0200133
134static const char * const sun6i_board_dt_compat[] = {
135 "allwinner,sun6i-a31",
136 NULL,
137};
138
Maxime Ripard751b2ac2013-10-05 14:53:48 +0200139extern void __init sun6i_reset_init(void);
140static void __init sun6i_timer_init(void)
141{
142 of_clk_init(NULL);
143 sun6i_reset_init();
144 clocksource_of_init();
145}
146
Maxime Ripard91a31972013-08-11 14:35:08 +0200147DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family")
148 .init_machine = sunxi_dt_init,
Maxime Ripard751b2ac2013-10-05 14:53:48 +0200149 .init_time = sun6i_timer_init,
Maxime Ripard91a31972013-08-11 14:35:08 +0200150 .dt_compat = sun6i_board_dt_compat,
Maxime Ripard53ea6882013-08-11 14:38:59 +0200151 .restart = sun6i_restart,
Maxime Ripard73346792013-11-03 10:30:13 +0100152 .smp = smp_ops(sun6i_smp_ops),
Maxime Ripard91a31972013-08-11 14:35:08 +0200153MACHINE_END
154
155static const char * const sun7i_board_dt_compat[] = {
156 "allwinner,sun7i-a20",
157 NULL,
158};
159
160DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family")
161 .init_machine = sunxi_dt_init,
Maxime Ripard91a31972013-08-11 14:35:08 +0200162 .dt_compat = sun7i_board_dt_compat,
Maxime Ripard53ea6882013-08-11 14:38:59 +0200163 .restart = sun4i_restart,
Maxime Ripard3b526342012-11-08 12:40:16 +0100164MACHINE_END