1*053fce84SStefan Roese // SPDX-License-Identifier: GPL-2.0+
2*053fce84SStefan Roese /*
3*053fce84SStefan Roese  * Ralink / Mediatek RT288x/RT3xxx/MT76xx built-in hardware watchdog timer
4*053fce84SStefan Roese  *
5*053fce84SStefan Roese  * Copyright (C) 2018 Stefan Roese <sr@denx.de>
6*053fce84SStefan Roese  *
7*053fce84SStefan Roese  * Based on the Linux driver version which is:
8*053fce84SStefan Roese  *   Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
9*053fce84SStefan Roese  *   Copyright (C) 2013 John Crispin <blogic@openwrt.org>
10*053fce84SStefan Roese  */
11*053fce84SStefan Roese 
12*053fce84SStefan Roese #include <common.h>
13*053fce84SStefan Roese #include <dm.h>
14*053fce84SStefan Roese #include <wdt.h>
15*053fce84SStefan Roese #include <linux/io.h>
16*053fce84SStefan Roese 
17*053fce84SStefan Roese DECLARE_GLOBAL_DATA_PTR;
18*053fce84SStefan Roese 
19*053fce84SStefan Roese struct mt762x_wdt {
20*053fce84SStefan Roese 	void __iomem *regs;
21*053fce84SStefan Roese };
22*053fce84SStefan Roese 
23*053fce84SStefan Roese #define TIMER_REG_TMRSTAT		0x00
24*053fce84SStefan Roese #define TIMER_REG_TMR1CTL		0x20
25*053fce84SStefan Roese #define TIMER_REG_TMR1LOAD		0x24
26*053fce84SStefan Roese 
27*053fce84SStefan Roese #define TMR1CTL_ENABLE			BIT(7)
28*053fce84SStefan Roese #define TMR1CTL_RESTART			BIT(9)
29*053fce84SStefan Roese #define TMR1CTL_PRESCALE_SHIFT		16
30*053fce84SStefan Roese 
mt762x_wdt_ping(struct mt762x_wdt * priv)31*053fce84SStefan Roese static int mt762x_wdt_ping(struct mt762x_wdt *priv)
32*053fce84SStefan Roese {
33*053fce84SStefan Roese 	writel(TMR1CTL_RESTART, priv->regs + TIMER_REG_TMRSTAT);
34*053fce84SStefan Roese 
35*053fce84SStefan Roese 	return 0;
36*053fce84SStefan Roese }
37*053fce84SStefan Roese 
mt762x_wdt_start(struct udevice * dev,u64 ms,ulong flags)38*053fce84SStefan Roese static int mt762x_wdt_start(struct udevice *dev, u64 ms, ulong flags)
39*053fce84SStefan Roese {
40*053fce84SStefan Roese 	struct mt762x_wdt *priv = dev_get_priv(dev);
41*053fce84SStefan Roese 
42*053fce84SStefan Roese 	/* set the prescaler to 1ms == 1000us */
43*053fce84SStefan Roese 	writel(1000 << TMR1CTL_PRESCALE_SHIFT, priv->regs + TIMER_REG_TMR1CTL);
44*053fce84SStefan Roese 	writel(ms, priv->regs + TIMER_REG_TMR1LOAD);
45*053fce84SStefan Roese 
46*053fce84SStefan Roese 	setbits_le32(priv->regs + TIMER_REG_TMR1CTL, TMR1CTL_ENABLE);
47*053fce84SStefan Roese 
48*053fce84SStefan Roese 	return 0;
49*053fce84SStefan Roese }
50*053fce84SStefan Roese 
mt762x_wdt_stop(struct udevice * dev)51*053fce84SStefan Roese static int mt762x_wdt_stop(struct udevice *dev)
52*053fce84SStefan Roese {
53*053fce84SStefan Roese 	struct mt762x_wdt *priv = dev_get_priv(dev);
54*053fce84SStefan Roese 
55*053fce84SStefan Roese 	mt762x_wdt_ping(priv);
56*053fce84SStefan Roese 
57*053fce84SStefan Roese 	clrbits_le32(priv->regs + TIMER_REG_TMR1CTL, TMR1CTL_ENABLE);
58*053fce84SStefan Roese 
59*053fce84SStefan Roese 	return 0;
60*053fce84SStefan Roese }
61*053fce84SStefan Roese 
mt762x_wdt_reset(struct udevice * dev)62*053fce84SStefan Roese static int mt762x_wdt_reset(struct udevice *dev)
63*053fce84SStefan Roese {
64*053fce84SStefan Roese 	struct mt762x_wdt *priv = dev_get_priv(dev);
65*053fce84SStefan Roese 
66*053fce84SStefan Roese 	mt762x_wdt_ping(priv);
67*053fce84SStefan Roese 
68*053fce84SStefan Roese 	return 0;
69*053fce84SStefan Roese }
70*053fce84SStefan Roese 
mt762x_wdt_probe(struct udevice * dev)71*053fce84SStefan Roese static int mt762x_wdt_probe(struct udevice *dev)
72*053fce84SStefan Roese {
73*053fce84SStefan Roese 	struct mt762x_wdt *priv = dev_get_priv(dev);
74*053fce84SStefan Roese 
75*053fce84SStefan Roese 	priv->regs = dev_remap_addr(dev);
76*053fce84SStefan Roese 	if (!priv->regs)
77*053fce84SStefan Roese 		return -EINVAL;
78*053fce84SStefan Roese 
79*053fce84SStefan Roese 	mt762x_wdt_stop(dev);
80*053fce84SStefan Roese 
81*053fce84SStefan Roese 	return 0;
82*053fce84SStefan Roese }
83*053fce84SStefan Roese 
84*053fce84SStefan Roese static const struct wdt_ops mt762x_wdt_ops = {
85*053fce84SStefan Roese 	.start = mt762x_wdt_start,
86*053fce84SStefan Roese 	.reset = mt762x_wdt_reset,
87*053fce84SStefan Roese 	.stop = mt762x_wdt_stop,
88*053fce84SStefan Roese };
89*053fce84SStefan Roese 
90*053fce84SStefan Roese static const struct udevice_id mt762x_wdt_ids[] = {
91*053fce84SStefan Roese 	{ .compatible = "mediatek,mt7621-wdt" },
92*053fce84SStefan Roese 	{}
93*053fce84SStefan Roese };
94*053fce84SStefan Roese 
95*053fce84SStefan Roese U_BOOT_DRIVER(mt762x_wdt) = {
96*053fce84SStefan Roese 	.name = "mt762x_wdt",
97*053fce84SStefan Roese 	.id = UCLASS_WDT,
98*053fce84SStefan Roese 	.of_match = mt762x_wdt_ids,
99*053fce84SStefan Roese 	.probe = mt762x_wdt_probe,
100*053fce84SStefan Roese 	.priv_auto_alloc_size = sizeof(struct mt762x_wdt),
101*053fce84SStefan Roese 	.ops = &mt762x_wdt_ops,
102*053fce84SStefan Roese };
103