xref: /openbmc/linux/arch/arm/mach-sunxi/sunxi.c (revision f1dc6c4f)
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>
17f1dc6c4fSMaxime Ripard #include <linux/irqchip.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>
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>
273b52634fSMaxime Ripard 
283b52634fSMaxime Ripard #include "sunxi.h"
293b52634fSMaxime Ripard 
3067bea88dSMaxime Ripard #define WATCHDOG_CTRL_REG	0x00
31b60decadSMaxime Ripard #define WATCHDOG_CTRL_RESTART		(1 << 0)
3267bea88dSMaxime Ripard #define WATCHDOG_MODE_REG	0x04
33b60decadSMaxime Ripard #define WATCHDOG_MODE_ENABLE		(1 << 0)
34b60decadSMaxime Ripard #define WATCHDOG_MODE_RESET_ENABLE	(1 << 1)
3567bea88dSMaxime Ripard 
3667bea88dSMaxime Ripard static void __iomem *wdt_base;
3767bea88dSMaxime Ripard 
3867bea88dSMaxime Ripard static void sunxi_setup_restart(void)
3967bea88dSMaxime Ripard {
4067bea88dSMaxime Ripard 	struct device_node *np = of_find_compatible_node(NULL, NULL,
4167bea88dSMaxime Ripard 						"allwinner,sunxi-wdt");
4267bea88dSMaxime Ripard 	if (WARN(!np, "unable to setup watchdog restart"))
4367bea88dSMaxime Ripard 		return;
4467bea88dSMaxime Ripard 
4567bea88dSMaxime Ripard 	wdt_base = of_iomap(np, 0);
4667bea88dSMaxime Ripard 	WARN(!wdt_base, "failed to map watchdog base address");
4767bea88dSMaxime Ripard }
4867bea88dSMaxime Ripard 
4967bea88dSMaxime Ripard static void sunxi_restart(char mode, const char *cmd)
5067bea88dSMaxime Ripard {
5167bea88dSMaxime Ripard 	if (!wdt_base)
5267bea88dSMaxime Ripard 		return;
5367bea88dSMaxime Ripard 
5467bea88dSMaxime Ripard 	/* Enable timer and set reset bit in the watchdog */
55b60decadSMaxime Ripard 	writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE,
56b60decadSMaxime Ripard 		wdt_base + WATCHDOG_MODE_REG);
57b60decadSMaxime Ripard 
58b60decadSMaxime Ripard 	/*
59b60decadSMaxime Ripard 	 * Restart the watchdog. The default (and lowest) interval
60b60decadSMaxime Ripard 	 * value for the watchdog is 0.5s.
61b60decadSMaxime Ripard 	 */
62b60decadSMaxime Ripard 	writel(WATCHDOG_CTRL_RESTART, wdt_base + WATCHDOG_CTRL_REG);
63b60decadSMaxime Ripard 
6467bea88dSMaxime Ripard 	while (1) {
6567bea88dSMaxime Ripard 		mdelay(5);
66b60decadSMaxime Ripard 		writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE,
67b60decadSMaxime Ripard 			wdt_base + WATCHDOG_MODE_REG);
6867bea88dSMaxime Ripard 	}
6967bea88dSMaxime Ripard }
7067bea88dSMaxime Ripard 
713b52634fSMaxime Ripard static struct map_desc sunxi_io_desc[] __initdata = {
723b52634fSMaxime Ripard 	{
733b52634fSMaxime Ripard 		.virtual	= (unsigned long) SUNXI_REGS_VIRT_BASE,
743b52634fSMaxime Ripard 		.pfn		= __phys_to_pfn(SUNXI_REGS_PHYS_BASE),
753b52634fSMaxime Ripard 		.length		= SUNXI_REGS_SIZE,
763b52634fSMaxime Ripard 		.type		= MT_DEVICE,
773b52634fSMaxime Ripard 	},
783b52634fSMaxime Ripard };
793b52634fSMaxime Ripard 
803b52634fSMaxime Ripard void __init sunxi_map_io(void)
813b52634fSMaxime Ripard {
823b52634fSMaxime Ripard 	iotable_init(sunxi_io_desc, ARRAY_SIZE(sunxi_io_desc));
833b52634fSMaxime Ripard }
843b52634fSMaxime Ripard 
85ea71d9a6SMaxime Ripard static void __init sunxi_timer_init(void)
86ea71d9a6SMaxime Ripard {
87ea71d9a6SMaxime Ripard 	sunxi_init_clocks();
88ea71d9a6SMaxime Ripard 	clocksource_of_init();
89ea71d9a6SMaxime Ripard }
90ea71d9a6SMaxime Ripard 
913b52634fSMaxime Ripard static void __init sunxi_dt_init(void)
923b52634fSMaxime Ripard {
9367bea88dSMaxime Ripard 	sunxi_setup_restart();
9467bea88dSMaxime Ripard 
953b52634fSMaxime Ripard 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
963b52634fSMaxime Ripard }
973b52634fSMaxime Ripard 
983b52634fSMaxime Ripard static const char * const sunxi_board_dt_compat[] = {
9943880f70SMaxime Ripard 	"allwinner,sun4i-a10",
10043880f70SMaxime Ripard 	"allwinner,sun5i-a13",
1013b52634fSMaxime Ripard 	NULL,
1023b52634fSMaxime Ripard };
1033b52634fSMaxime Ripard 
1043b52634fSMaxime Ripard DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
1053b52634fSMaxime Ripard 	.init_machine	= sunxi_dt_init,
1063b52634fSMaxime Ripard 	.map_io		= sunxi_map_io,
107f1dc6c4fSMaxime Ripard 	.init_irq	= irqchip_init,
10867bea88dSMaxime Ripard 	.restart	= sunxi_restart,
109ea71d9a6SMaxime Ripard 	.init_time	= sunxi_timer_init,
1103b52634fSMaxime Ripard 	.dt_compat	= sunxi_board_dt_compat,
1113b52634fSMaxime Ripard MACHINE_END
112