xref: /openbmc/linux/arch/arm/mach-sunxi/sunxi.c (revision d767af5e)
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