xref: /openbmc/linux/arch/arm/mach-sunxi/sunxi.c (revision 751b2ac4)
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>
155e51651dSJosh Cartwright #include <linux/delay.h>
163b52634fSMaxime Ripard #include <linux/kernel.h>
173b52634fSMaxime Ripard #include <linux/init.h>
1867bea88dSMaxime Ripard #include <linux/of_address.h>
193b52634fSMaxime Ripard #include <linux/of_irq.h>
203b52634fSMaxime Ripard #include <linux/of_platform.h>
213b52634fSMaxime Ripard #include <linux/io.h>
227b6d864bSRobin Holt #include <linux/reboot.h>
233b52634fSMaxime Ripard 
243b52634fSMaxime Ripard #include <asm/mach/arch.h>
253b52634fSMaxime Ripard #include <asm/mach/map.h>
26bc34b5f2SMaxime Ripard #include <asm/system_misc.h>
273b52634fSMaxime Ripard 
28bc34b5f2SMaxime Ripard #define SUN4I_WATCHDOG_CTRL_REG		0x00
2906d71bcfSMaxime Ripard #define SUN4I_WATCHDOG_CTRL_RESTART		BIT(0)
30bc34b5f2SMaxime Ripard #define SUN4I_WATCHDOG_MODE_REG		0x04
3106d71bcfSMaxime Ripard #define SUN4I_WATCHDOG_MODE_ENABLE		BIT(0)
3206d71bcfSMaxime Ripard #define SUN4I_WATCHDOG_MODE_RESET_ENABLE	BIT(1)
3306d71bcfSMaxime Ripard 
3406d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_IRQ_REG		0x00
3506d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CTRL_REG	0x10
3606d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CTRL_RESTART		BIT(0)
3706d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CONFIG_REG	0x14
3806d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CONFIG_RESTART		BIT(0)
3906d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_CONFIG_IRQ		BIT(1)
4006d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_MODE_REG	0x18
4106d71bcfSMaxime Ripard #define SUN6I_WATCHDOG1_MODE_ENABLE		BIT(0)
4267bea88dSMaxime Ripard 
4367bea88dSMaxime Ripard static void __iomem *wdt_base;
4467bea88dSMaxime Ripard 
457b6d864bSRobin Holt static void sun4i_restart(enum reboot_mode mode, const char *cmd)
4667bea88dSMaxime Ripard {
4767bea88dSMaxime Ripard 	if (!wdt_base)
4867bea88dSMaxime Ripard 		return;
4967bea88dSMaxime Ripard 
5067bea88dSMaxime Ripard 	/* Enable timer and set reset bit in the watchdog */
51bc34b5f2SMaxime Ripard 	writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE,
52bc34b5f2SMaxime Ripard 	       wdt_base + SUN4I_WATCHDOG_MODE_REG);
53b60decadSMaxime Ripard 
54b60decadSMaxime Ripard 	/*
55b60decadSMaxime Ripard 	 * Restart the watchdog. The default (and lowest) interval
56b60decadSMaxime Ripard 	 * value for the watchdog is 0.5s.
57b60decadSMaxime Ripard 	 */
58bc34b5f2SMaxime Ripard 	writel(SUN4I_WATCHDOG_CTRL_RESTART, wdt_base + SUN4I_WATCHDOG_CTRL_REG);
59b60decadSMaxime Ripard 
6067bea88dSMaxime Ripard 	while (1) {
6167bea88dSMaxime Ripard 		mdelay(5);
62bc34b5f2SMaxime Ripard 		writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE,
63bc34b5f2SMaxime Ripard 		       wdt_base + SUN4I_WATCHDOG_MODE_REG);
6467bea88dSMaxime Ripard 	}
6567bea88dSMaxime Ripard }
6667bea88dSMaxime Ripard 
6706d71bcfSMaxime Ripard static void sun6i_restart(enum reboot_mode mode, const char *cmd)
6806d71bcfSMaxime Ripard {
6906d71bcfSMaxime Ripard 	if (!wdt_base)
7006d71bcfSMaxime Ripard 		return;
7106d71bcfSMaxime Ripard 
7206d71bcfSMaxime Ripard 	/* Disable interrupts */
7306d71bcfSMaxime Ripard 	writel(0, wdt_base + SUN6I_WATCHDOG1_IRQ_REG);
7406d71bcfSMaxime Ripard 
7506d71bcfSMaxime Ripard 	/* We want to disable the IRQ and just reset the whole system */
7606d71bcfSMaxime Ripard 	writel(SUN6I_WATCHDOG1_CONFIG_RESTART,
7706d71bcfSMaxime Ripard 		wdt_base + SUN6I_WATCHDOG1_CONFIG_REG);
7806d71bcfSMaxime Ripard 
7906d71bcfSMaxime Ripard 	/* Enable timer. The default and lowest interval value is 0.5s */
8006d71bcfSMaxime Ripard 	writel(SUN6I_WATCHDOG1_MODE_ENABLE,
8106d71bcfSMaxime Ripard 		wdt_base + SUN6I_WATCHDOG1_MODE_REG);
8206d71bcfSMaxime Ripard 
8306d71bcfSMaxime Ripard 	/* Restart the watchdog. */
8406d71bcfSMaxime Ripard 	writel(SUN6I_WATCHDOG1_CTRL_RESTART,
8506d71bcfSMaxime Ripard 		wdt_base + SUN6I_WATCHDOG1_CTRL_REG);
8606d71bcfSMaxime Ripard 
8706d71bcfSMaxime Ripard 	while (1) {
8806d71bcfSMaxime Ripard 		mdelay(5);
8906d71bcfSMaxime Ripard 		writel(SUN6I_WATCHDOG1_MODE_ENABLE,
9006d71bcfSMaxime Ripard 			wdt_base + SUN6I_WATCHDOG1_MODE_REG);
9106d71bcfSMaxime Ripard 	}
9206d71bcfSMaxime Ripard }
9306d71bcfSMaxime Ripard 
94bc34b5f2SMaxime Ripard static struct of_device_id sunxi_restart_ids[] = {
9553ea6887SMaxime Ripard 	{ .compatible = "allwinner,sun4i-wdt" },
9653ea6887SMaxime Ripard 	{ .compatible = "allwinner,sun6i-wdt" },
97bc34b5f2SMaxime Ripard 	{ /*sentinel*/ }
98bc34b5f2SMaxime Ripard };
99bc34b5f2SMaxime Ripard 
100bc34b5f2SMaxime Ripard static void sunxi_setup_restart(void)
101bc34b5f2SMaxime Ripard {
102bc34b5f2SMaxime Ripard 	struct device_node *np;
103bc34b5f2SMaxime Ripard 
104bc34b5f2SMaxime Ripard 	np = of_find_matching_node(NULL, sunxi_restart_ids);
105bc34b5f2SMaxime Ripard 	if (WARN(!np, "unable to setup watchdog restart"))
106bc34b5f2SMaxime Ripard 		return;
107bc34b5f2SMaxime Ripard 
108bc34b5f2SMaxime Ripard 	wdt_base = of_iomap(np, 0);
109bc34b5f2SMaxime Ripard 	WARN(!wdt_base, "failed to map watchdog base address");
110bc34b5f2SMaxime Ripard }
111bc34b5f2SMaxime Ripard 
1123b52634fSMaxime Ripard static void __init sunxi_dt_init(void)
1133b52634fSMaxime Ripard {
11467bea88dSMaxime Ripard 	sunxi_setup_restart();
11567bea88dSMaxime Ripard 
1163b52634fSMaxime Ripard 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
1173b52634fSMaxime Ripard }
1183b52634fSMaxime Ripard 
1193b52634fSMaxime Ripard static const char * const sunxi_board_dt_compat[] = {
12043880f70SMaxime Ripard 	"allwinner,sun4i-a10",
12181265dfbSMaxime Ripard 	"allwinner,sun5i-a10s",
12243880f70SMaxime Ripard 	"allwinner,sun5i-a13",
1233b52634fSMaxime Ripard 	NULL,
1243b52634fSMaxime Ripard };
1253b52634fSMaxime Ripard 
1263b52634fSMaxime Ripard DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
1273b52634fSMaxime Ripard 	.init_machine	= sunxi_dt_init,
1283b52634fSMaxime Ripard 	.dt_compat	= sunxi_board_dt_compat,
12953ea6887SMaxime Ripard 	.restart	= sun4i_restart,
1303b52634fSMaxime Ripard MACHINE_END
13191a31977SMaxime Ripard 
13291a31977SMaxime Ripard static const char * const sun6i_board_dt_compat[] = {
13391a31977SMaxime Ripard 	"allwinner,sun6i-a31",
13491a31977SMaxime Ripard 	NULL,
13591a31977SMaxime Ripard };
13691a31977SMaxime Ripard 
137751b2ac4SMaxime Ripard extern void __init sun6i_reset_init(void);
138751b2ac4SMaxime Ripard static void __init sun6i_timer_init(void)
139751b2ac4SMaxime Ripard {
140751b2ac4SMaxime Ripard 	of_clk_init(NULL);
141751b2ac4SMaxime Ripard 	sun6i_reset_init();
142751b2ac4SMaxime Ripard 	clocksource_of_init();
143751b2ac4SMaxime Ripard }
144751b2ac4SMaxime Ripard 
14591a31977SMaxime Ripard DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family")
14691a31977SMaxime Ripard 	.init_machine	= sunxi_dt_init,
147751b2ac4SMaxime Ripard 	.init_time	= sun6i_timer_init,
14891a31977SMaxime Ripard 	.dt_compat	= sun6i_board_dt_compat,
14953ea6887SMaxime Ripard 	.restart	= sun6i_restart,
15091a31977SMaxime Ripard MACHINE_END
15191a31977SMaxime Ripard 
15291a31977SMaxime Ripard static const char * const sun7i_board_dt_compat[] = {
15391a31977SMaxime Ripard 	"allwinner,sun7i-a20",
15491a31977SMaxime Ripard 	NULL,
15591a31977SMaxime Ripard };
15691a31977SMaxime Ripard 
15791a31977SMaxime Ripard DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family")
15891a31977SMaxime Ripard 	.init_machine	= sunxi_dt_init,
15991a31977SMaxime Ripard 	.dt_compat	= sun7i_board_dt_compat,
16053ea6887SMaxime Ripard 	.restart	= sun4i_restart,
1613b52634fSMaxime Ripard MACHINE_END
162