blob: fa8d7842e9424a9156d6776e2ecbad6511d6963f [file] [log] [blame]
Bastien Curutchet617f5d22024-10-03 10:42:55 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * DaVinci Watchdog driver
4 *
5 */
6
7#include <asm/io.h>
8#include <clk.h>
9#include <dm.h>
10#include <wdt.h>
11
12/* Control Register */
13#define DAVINCI_WDT_ID 0x00
14#define DAVINCI_WDT_TIM12 0x10
15#define DAVINCI_WDT_TIM34 0x14
16#define DAVINCI_WDT_PRD12 0x18
17#define DAVINCI_WDT_PRD34 0x1C
18#define DAVINCI_WDT_TCR 0x20
19#define DAVINCI_WDT_TGCR 0x24
20#define DAVINCI_WDT_WDTCR 0x28
21
22#define DAVINCI_TCR_CONT_EN BIT(7)
23
24#define DAVINCI_TGCR_PLUSEN BIT(4)
25#define DAVINCI_TGCR_WDT_MODE BIT(3)
26#define DAVINCI_TGCR_TIM34RS BIT(1)
27#define DAVINCI_TGCR_TIM12RS BIT(0)
28
29#define DAVINCI_WDTCR_INVALID_KEY (0x5555 << 16)
30#define DAVINCI_WDTCR_WDKEY0 (0xA5C6 << 16)
31#define DAVINCI_WDTCR_WDKEY1 (0xDA7E << 16)
32#define DAVINCI_WDTCR_WDFLAG BIT(15)
33#define DAVINCI_WDTCR_WDEN BIT(14)
34
35#define DEFAULT_THRESHOLD 0xA03200000
36
37struct davinci_wdt_priv {
38 void __iomem *base;
39 struct clk *ref_clk;
40};
41
42static int davinci_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
43{
44 struct davinci_wdt_priv *priv = dev_get_priv(dev);
45 ulong rate = clk_get_rate(priv->ref_clk);
46 u64 threshold;
47
48 if (!rate)
49 threshold = DEFAULT_THRESHOLD;
50 else
51 threshold = rate * timeout_ms / 1000;
52
53 /* Reset control registers */
54 writel(0, priv->base + DAVINCI_WDT_TCR);
55 writel(0, priv->base + DAVINCI_WDT_TGCR);
56
57 /* Enable watchdog mode and timers */
58 writel(DAVINCI_TGCR_WDT_MODE | DAVINCI_TGCR_TIM12RS | DAVINCI_TGCR_TIM34RS,
59 priv->base + DAVINCI_WDT_TGCR);
60
61 /* Reset counters */
62 writel(0, priv->base + DAVINCI_WDT_TIM12);
63 writel(0, priv->base + DAVINCI_WDT_TIM34);
64
65 /* Set timeout threshold */
66 writel(threshold & 0xFFFFFFFF, priv->base + DAVINCI_WDT_PRD12);
67 writel(threshold >> 32, priv->base + DAVINCI_WDT_PRD34);
68
69 /* Enable counter */
70 writel(DAVINCI_TCR_CONT_EN, priv->base + DAVINCI_WDT_TCR);
71
72 /* Go to watchdog's active state */
73 writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY0, priv->base + DAVINCI_WDT_WDTCR);
74 writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY1, priv->base + DAVINCI_WDT_WDTCR);
75
76 return 0;
77}
78
79static int davinci_wdt_expire_now(struct udevice *dev, ulong flags)
80{
81 struct davinci_wdt_priv *priv = dev_get_priv(dev);
82
83 writel(DAVINCI_WDTCR_INVALID_KEY, priv->base + DAVINCI_WDT_WDTCR);
84
85 return 0;
86}
87
88static int davinci_wdt_restart(struct udevice *dev)
89{
90 struct davinci_wdt_priv *priv = dev_get_priv(dev);
91
92 writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY0, priv->base + DAVINCI_WDT_WDTCR);
93 writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY1, priv->base + DAVINCI_WDT_WDTCR);
94
95 return 0;
96}
97
98static int davinci_wdt_probe(struct udevice *dev)
99{
100 struct davinci_wdt_priv *priv = dev_get_priv(dev);
101
102 priv->base = dev_remap_addr_index(dev, 0);
103 if (!priv->base)
104 return -EFAULT;
105
106 priv->ref_clk = devm_clk_get(dev, "ref");
107 if (IS_ERR(priv->ref_clk))
108 return PTR_ERR(priv->ref_clk);
109
110 return 0;
111}
112
113static const struct wdt_ops davinci_wdt_ops = {
114 .start = davinci_wdt_start,
115 .reset = davinci_wdt_restart,
116 .expire_now = davinci_wdt_expire_now,
117};
118
119static const struct udevice_id davinci_wdt_ids[] = {
120 {.compatible = "ti,davinci-wdt"},
121 {}
122};
123
124U_BOOT_DRIVER(davinci_wdt) = {
125 .name = "davinci_wdt",
126 .id = UCLASS_WDT,
127 .probe = davinci_wdt_probe,
128 .of_match = davinci_wdt_ids,
129 .ops = &davinci_wdt_ops,
130 .priv_auto = sizeof(struct davinci_wdt_priv),
131};