1
2
3
4
5
6
7
8
9#include <common.h>
10#include <dm.h>
11#include <wdt.h>
12#include <clk.h>
13#include <linux/io.h>
14
15DECLARE_GLOBAL_DATA_PTR;
16
17struct cdns_regs {
18 u32 zmr;
19 u32 ccr;
20 u32 restart;
21 u32 status;
22};
23
24struct cdns_wdt_priv {
25 bool rst;
26 u32 timeout;
27 struct cdns_regs *regs;
28};
29
30#define CDNS_WDT_DEFAULT_TIMEOUT 10
31
32
33#define CDNS_WDT_MIN_TIMEOUT 1
34#define CDNS_WDT_MAX_TIMEOUT 516
35
36
37#define CDNS_WDT_RESTART_KEY 0x00001999
38
39
40#define CDNS_WDT_REGISTER_ACCESS_KEY 0x00920000
41
42
43#define CDNS_WDT_COUNTER_VALUE_DIVISOR 0x1000
44
45
46#define CDNS_WDT_PRESCALE_64 64
47#define CDNS_WDT_PRESCALE_512 512
48#define CDNS_WDT_PRESCALE_4096 4096
49#define CDNS_WDT_PRESCALE_SELECT_64 1
50#define CDNS_WDT_PRESCALE_SELECT_512 2
51#define CDNS_WDT_PRESCALE_SELECT_4096 3
52
53
54#define CDNS_WDT_CLK_75MHZ 75000000
55
56
57#define CDNS_WDT_COUNTER_MAX 0xFFF
58
59
60
61
62
63
64
65#define CDNS_WDT_ZMR_WDEN_MASK 0x00000001
66#define CDNS_WDT_ZMR_RSTEN_MASK 0x00000002
67#define CDNS_WDT_ZMR_IRQEN_MASK 0x00000004
68#define CDNS_WDT_ZMR_RSTLEN_16 0x00000030
69#define CDNS_WDT_ZMR_ZKEY_VAL 0x00ABC000
70
71
72
73
74
75
76#define CDNS_WDT_CCR_CRV_MASK 0x00003FFC
77
78
79static inline void cdns_wdt_writereg(u32 *addr, u32 val)
80{
81 writel(val, addr);
82}
83
84
85
86
87
88
89
90
91
92
93static int cdns_wdt_reset(struct udevice *dev)
94{
95 struct cdns_wdt_priv *priv = dev_get_priv(dev);
96
97 debug("%s\n", __func__);
98
99 cdns_wdt_writereg(&priv->regs->restart, CDNS_WDT_RESTART_KEY);
100
101 return 0;
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
127static int cdns_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
128{
129 ulong clk_f;
130 u32 count, prescaler, ctrl_clksel, data = 0;
131 struct clk clock;
132 struct cdns_wdt_priv *priv = dev_get_priv(dev);
133
134 if (clk_get_by_index(dev, 0, &clock) < 0) {
135 dev_err(dev, "failed to get clock\n");
136 return -1;
137 }
138
139 clk_f = clk_get_rate(&clock);
140 if (IS_ERR_VALUE(clk_f)) {
141 dev_err(dev, "failed to get rate\n");
142 return -1;
143 }
144
145 if ((timeout < CDNS_WDT_MIN_TIMEOUT) ||
146 (timeout > CDNS_WDT_MAX_TIMEOUT)) {
147 timeout = priv->timeout;
148 }
149
150 debug("%s: CLK_FREQ %ld, timeout %lld\n", __func__, clk_f, timeout);
151
152 if (clk_f <= CDNS_WDT_CLK_75MHZ) {
153 prescaler = CDNS_WDT_PRESCALE_512;
154 ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512;
155 } else {
156 prescaler = CDNS_WDT_PRESCALE_4096;
157 ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_4096;
158 }
159
160
161
162
163
164 count = (timeout * (clk_f / prescaler)) /
165 CDNS_WDT_COUNTER_VALUE_DIVISOR + 1;
166
167 if (count > CDNS_WDT_COUNTER_MAX)
168 count = CDNS_WDT_COUNTER_MAX;
169
170 cdns_wdt_writereg(&priv->regs->zmr, CDNS_WDT_ZMR_ZKEY_VAL);
171
172 count = (count << 2) & CDNS_WDT_CCR_CRV_MASK;
173
174
175 data = count | CDNS_WDT_REGISTER_ACCESS_KEY | ctrl_clksel;
176 cdns_wdt_writereg(&priv->regs->ccr, data);
177
178 data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTLEN_16 |
179 CDNS_WDT_ZMR_ZKEY_VAL;
180
181
182 if (priv->rst) {
183 data |= CDNS_WDT_ZMR_RSTEN_MASK;
184 data &= ~CDNS_WDT_ZMR_IRQEN_MASK;
185 } else {
186 data &= ~CDNS_WDT_ZMR_RSTEN_MASK;
187 data |= CDNS_WDT_ZMR_IRQEN_MASK;
188 }
189
190 cdns_wdt_writereg(&priv->regs->zmr, data);
191 cdns_wdt_writereg(&priv->regs->restart, CDNS_WDT_RESTART_KEY);
192
193 return 0;
194}
195
196
197
198
199
200
201
202
203
204
205
206static int cdns_wdt_stop(struct udevice *dev)
207{
208 struct cdns_wdt_priv *priv = dev_get_priv(dev);
209
210 cdns_wdt_writereg(&priv->regs->zmr,
211 CDNS_WDT_ZMR_ZKEY_VAL & (~CDNS_WDT_ZMR_WDEN_MASK));
212
213 return 0;
214}
215
216
217
218
219
220
221
222
223static int cdns_wdt_probe(struct udevice *dev)
224{
225 debug("%s: Probing wdt%u\n", __func__, dev->seq);
226
227 return 0;
228}
229
230static int cdns_wdt_ofdata_to_platdata(struct udevice *dev)
231{
232 struct cdns_wdt_priv *priv = dev_get_priv(dev);
233
234 priv->regs = (struct cdns_regs *)dev_read_addr(dev);
235 if (IS_ERR(priv->regs))
236 return PTR_ERR(priv->regs);
237
238 priv->timeout = dev_read_u32_default(dev, "timeout-sec",
239 CDNS_WDT_DEFAULT_TIMEOUT);
240
241 priv->rst = dev_read_bool(dev, "reset-on-timeout");
242
243 debug("%s: timeout %d, reset %d\n", __func__, priv->timeout, priv->rst);
244
245 return 0;
246}
247
248static const struct wdt_ops cdns_wdt_ops = {
249 .start = cdns_wdt_start,
250 .reset = cdns_wdt_reset,
251 .stop = cdns_wdt_stop,
252
253};
254
255static const struct udevice_id cdns_wdt_ids[] = {
256 { .compatible = "cdns,wdt-r1p2" },
257 {}
258};
259
260U_BOOT_DRIVER(cdns_wdt) = {
261 .name = "cdns_wdt",
262 .id = UCLASS_WDT,
263 .of_match = cdns_wdt_ids,
264 .probe = cdns_wdt_probe,
265 .priv_auto_alloc_size = sizeof(struct cdns_wdt_priv),
266 .ofdata_to_platdata = cdns_wdt_ofdata_to_platdata,
267 .ops = &cdns_wdt_ops,
268};
269