18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2011 Picochip Ltd., Jamie Iles
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * All enquiries to support@picochip.com
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/delay.h>
88c2ecf20Sopenharmony_ci#include <linux/of.h>
98c2ecf20Sopenharmony_ci#include <linux/of_address.h>
108c2ecf20Sopenharmony_ci#include <linux/reboot.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <asm/mach/arch.h>
138c2ecf20Sopenharmony_ci#include <asm/mach/map.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define PHYS_TO_IO(x)			(((x) & 0x00ffffff) | 0xfe000000)
168c2ecf20Sopenharmony_ci#define PICOXCELL_PERIPH_BASE		0x80000000
178c2ecf20Sopenharmony_ci#define PICOXCELL_PERIPH_LENGTH		SZ_4M
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define WDT_CTRL_REG_EN_MASK		(1 << 0)
208c2ecf20Sopenharmony_ci#define WDT_CTRL_REG_OFFS		(0x00)
218c2ecf20Sopenharmony_ci#define WDT_TIMEOUT_REG_OFFS		(0x04)
228c2ecf20Sopenharmony_cistatic void __iomem *wdt_regs;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * The machine restart method can be called from an atomic context so we won't
268c2ecf20Sopenharmony_ci * be able to ioremap the regs then.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_cistatic void picoxcell_setup_restart(void)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	struct device_node *np = of_find_compatible_node(NULL, NULL,
318c2ecf20Sopenharmony_ci							 "snps,dw-apb-wdg");
328c2ecf20Sopenharmony_ci	if (WARN(!np, "unable to setup watchdog restart"))
338c2ecf20Sopenharmony_ci		return;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	wdt_regs = of_iomap(np, 0);
368c2ecf20Sopenharmony_ci	WARN(!wdt_regs, "failed to remap watchdog regs");
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic struct map_desc io_map __initdata = {
408c2ecf20Sopenharmony_ci	.virtual	= PHYS_TO_IO(PICOXCELL_PERIPH_BASE),
418c2ecf20Sopenharmony_ci	.pfn		= __phys_to_pfn(PICOXCELL_PERIPH_BASE),
428c2ecf20Sopenharmony_ci	.length		= PICOXCELL_PERIPH_LENGTH,
438c2ecf20Sopenharmony_ci	.type		= MT_DEVICE,
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic void __init picoxcell_map_io(void)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	iotable_init(&io_map, 1);
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void __init picoxcell_init_machine(void)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	picoxcell_setup_restart();
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic const char *picoxcell_dt_match[] = {
578c2ecf20Sopenharmony_ci	"picochip,pc3x2",
588c2ecf20Sopenharmony_ci	"picochip,pc3x3",
598c2ecf20Sopenharmony_ci	NULL
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic void picoxcell_wdt_restart(enum reboot_mode mode, const char *cmd)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	/*
658c2ecf20Sopenharmony_ci	 * Configure the watchdog to reset with the shortest possible timeout
668c2ecf20Sopenharmony_ci	 * and give it chance to do the reset.
678c2ecf20Sopenharmony_ci	 */
688c2ecf20Sopenharmony_ci	if (wdt_regs) {
698c2ecf20Sopenharmony_ci		writel_relaxed(WDT_CTRL_REG_EN_MASK, wdt_regs + WDT_CTRL_REG_OFFS);
708c2ecf20Sopenharmony_ci		writel_relaxed(0, wdt_regs + WDT_TIMEOUT_REG_OFFS);
718c2ecf20Sopenharmony_ci		/* No sleeping, possibly atomic. */
728c2ecf20Sopenharmony_ci		mdelay(500);
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ciDT_MACHINE_START(PICOXCELL, "Picochip picoXcell")
778c2ecf20Sopenharmony_ci	.map_io		= picoxcell_map_io,
788c2ecf20Sopenharmony_ci	.init_machine	= picoxcell_init_machine,
798c2ecf20Sopenharmony_ci	.dt_compat	= picoxcell_dt_match,
808c2ecf20Sopenharmony_ci	.restart	= picoxcell_wdt_restart,
818c2ecf20Sopenharmony_ciMACHINE_END
82