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