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