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#include "qemu/osdep.h"
28#include "hw/sysbus.h"
29#include "hw/register.h"
30#include "qemu/timer.h"
31#include "qemu/bitops.h"
32#include "qapi/error.h"
33#include "qemu/log.h"
34
35#include "qapi/qmp/qerror.h"
36
37#ifndef XLNX_SWDT_ERR_DEBUG
38#define XLNX_SWDT_ERR_DEBUG 0
39#endif
40
41#define TYPE_XLNX_SWDT "xlnx.swdt"
42
43#define XLNX_SWDT(obj) \
44 OBJECT_CHECK(SWDTState, (obj), TYPE_XLNX_SWDT)
45
46REG32(SWDT_MODE, 0x0)
47 FIELD(SWDT_MODE, ZKEY, 11, 12)
48 FIELD(SWDT_MODE, IRQLN, 2, 7)
49 FIELD(SWDT_MODE, RSTLN, 3, 4)
50 FIELD(SWDT_MODE, IRQEN, 1, 2)
51 FIELD(SWDT_MODE, RSTEN, 1, 1)
52 FIELD(SWDT_MODE, WDEN, 1, 0)
53REG32(SWDT_CONTROL, 0x4)
54 FIELD(SWDT_CONTROL, CKEY, 12, 14)
55 FIELD(SWDT_CONTROL, CRV, 12, 2)
56 FIELD(SWDT_CONTROL, CLKSEL, 2, 0)
57REG32(SWDT_RESTART, 0x8)
58 FIELD(SWDT_RESTART, RSTKEY, 16, 0)
59REG32(SWDT_STATUS, 0xC)
60 FIELD(SWDT_STATUS, WDZ, 1, 0)
61
62#define R_MAX (R_SWDT_STATUS + 1)
63
64typedef struct SWDTState {
65 SysBusDevice parent_obj;
66 MemoryRegion iomem;
67 qemu_irq irq;
68 qemu_irq rst;
69 QEMUTimer *timer;
70
71 QEMUTimer *irq_done_timer;
72 QEMUTimer *rst_done_timer;
73
74 uint64_t pclk;
75 uint32_t current_mode;
76 uint32_t current_control;
77 uint32_t regs[R_MAX];
78 RegisterInfo regs_info[R_MAX];
79} SWDTState;
80
81static void swdt_done_irq_update(SWDTState *s)
82{
83 qemu_set_irq(s->irq, 1);
84 timer_mod(s->irq_done_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
85 + muldiv64(1000000000,
86 4 << AF_EX32(s->regs, SWDT_MODE, IRQLN),
87 s->pclk));
88}
89
90static void swdt_reset_irq_update(SWDTState *s)
91{
92 qemu_set_irq(s->rst, 1);
93 timer_mod(s->rst_done_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
94 + muldiv64(1000000000,
95 2 << AF_EX32(s->regs, SWDT_MODE, RSTLN),
96 s->pclk));
97}
98
99static void swdt_irq_done(void *opaque)
100{
101 SWDTState *s = XLNX_SWDT(opaque);
102
103 qemu_set_irq(s->irq, 0);
104}
105
106static void swdt_reset_done(void *opaque)
107{
108 SWDTState *s = XLNX_SWDT(opaque);
109
110 qemu_set_irq(s->rst, 0);
111}
112
113static void swdt_time_elapsed(void *opaque)
114{
115 SWDTState *s = XLNX_SWDT(opaque);
116 bool do_a_reset = AF_EX32(s->regs, SWDT_MODE, RSTEN);
117 bool do_an_irq = AF_EX32(s->regs, SWDT_MODE, IRQEN);
118
119 s->regs[R_SWDT_STATUS] = 1;
120
121 if (do_a_reset) {
122 swdt_reset_irq_update(s);
123 }
124 if (do_an_irq) {
125 swdt_done_irq_update(s);
126 }
127}
128
129static uint32_t swdt_reload_value(SWDTState *s)
130{
131 return (AF_EX32(s->regs, SWDT_CONTROL, CRV) << 12) + 0xFFF;
132}
133
134static uint64_t swdt_next_trigger(SWDTState *s)
135{
136 return (muldiv64(1000000000,
137 8 << (3 * AF_EX32(s->regs, SWDT_CONTROL, CLKSEL)), s->pclk)
138 * swdt_reload_value(s)) + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
139}
140
141
142static void swdt_counter_reload(SWDTState *s)
143{
144 bool watchdog_enabled = AF_EX32(s->regs, SWDT_MODE, WDEN);
145
146 if (watchdog_enabled) {
147 s->regs[R_SWDT_STATUS] = 0;
148 timer_mod(s->timer, swdt_next_trigger(s));
149 } else {
150 timer_del(s->timer);
151 }
152}
153
154static void swdt_mode_postw(RegisterInfo *reg, uint64_t val64)
155{
156 SWDTState *s = XLNX_SWDT(reg->opaque);
157 bool valid = (AF_EX32(s->regs, SWDT_MODE, ZKEY) == 0xABC);
158
159 if (!valid) {
160
161
162 s->regs[R_SWDT_MODE] = s->current_mode;
163 return;
164 }
165
166 s->current_mode = s->regs[R_SWDT_MODE];
167
168 swdt_counter_reload(s);
169}
170
171static void swdt_control_postw(RegisterInfo *reg, uint64_t val64)
172{
173 SWDTState *s = XLNX_SWDT(reg->opaque);
174 bool valid = (AF_EX32(s->regs, SWDT_CONTROL, CKEY) == 0x248);
175
176 if (!valid) {
177
178
179 s->regs[R_SWDT_CONTROL] = s->current_control;
180 return;
181 }
182
183 s->current_control = s->regs[R_SWDT_CONTROL];
184}
185
186static void swdt_restart_key_postw(RegisterInfo *reg, uint64_t val64)
187{
188 SWDTState *s = XLNX_SWDT(reg->opaque);
189 bool valid = (AF_EX32(s->regs, SWDT_RESTART, RSTKEY) == 0x1999);
190
191 if (valid) {
192 swdt_counter_reload(s);
193 }
194
195
196 s->regs[R_SWDT_RESTART] = 0x0000;
197}
198
199static RegisterAccessInfo swdt_regs_info[] = {
200 { .name = "SWDT_MODE", .decode.addr = A_SWDT_MODE,
201 .reset = 0x000001C2,
202 .rsvd = 0x00000E08,
203 .ro = 0x00000E08,
204 .post_write = swdt_mode_postw,
205 },{ .name = "SWDT_CONTROL", .decode.addr = A_SWDT_CONTROL,
206 .reset = 0x00003FFC,
207 .post_write = swdt_control_postw,
208 },{ .name = "SWDT_RESTART", .decode.addr = A_SWDT_RESTART,
209 .reset = 0x00000000,
210 .post_write = swdt_restart_key_postw,
211 },{ .name = "SWDT_STATUS", .decode.addr = A_SWDT_STATUS,
212 .reset = 0x00000000,
213 .ro = 0x00000001
214 }
215};
216
217static void swdt_reset(DeviceState *dev)
218{
219 SWDTState *s = XLNX_SWDT(dev);
220 unsigned int i;
221
222
223
224
225
226 s->current_mode = 0x000001C2;
227 s->current_control = 0x00003FFC;
228
229 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
230 register_reset(&s->regs_info[i]);
231 }
232
233 swdt_counter_reload(s);
234 swdt_irq_done(s);
235 swdt_reset_done(s);
236}
237
238static const MemoryRegionOps swdt_ops = {
239 .read = register_read_memory_le,
240 .write = register_write_memory_le,
241 .endianness = DEVICE_LITTLE_ENDIAN,
242 .valid = {
243 .min_access_size = 4,
244 .max_access_size = 4,
245 },
246};
247
248static void swdt_realize(DeviceState *dev, Error **errp)
249{
250 SWDTState *s = XLNX_SWDT(dev);
251 const char *prefix = object_get_canonical_path(OBJECT(dev));
252 unsigned int i;
253
254 if (!s->pclk) {
255 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "pclk");
256 return;
257 }
258
259 for (i = 0; i < ARRAY_SIZE(swdt_regs_info); ++i) {
260 RegisterInfo *r = &s->regs_info[i];
261
262 *r = (RegisterInfo) {
263 .data = (uint8_t *)&s->regs[swdt_regs_info[i].decode.addr / 4],
264 .data_size = sizeof(uint32_t),
265 .access = &swdt_regs_info[i],
266 .debug = XLNX_SWDT_ERR_DEBUG,
267 .prefix = prefix,
268 .opaque = s,
269 };
270 memory_region_init_io(&r->mem, OBJECT(dev), &swdt_ops, r,
271 r->access->name, 4);
272 memory_region_add_subregion(&s->iomem, r->access->decode.addr, &r->mem);
273 }
274}
275
276static void swdt_init(Object *obj)
277{
278 SWDTState *s = XLNX_SWDT(obj);
279 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
280
281 memory_region_init(&s->iomem, obj, TYPE_XLNX_SWDT, R_MAX * 4);
282 sysbus_init_mmio(sbd, &s->iomem);
283 sysbus_init_irq(sbd, &s->irq);
284
285 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, swdt_time_elapsed, s);
286 s->irq_done_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, swdt_irq_done, s);
287 s->rst_done_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, swdt_reset_done, s);
288}
289
290static Property swdt_properties[] = {
291
292 DEFINE_PROP_UINT64("pclk", SWDTState, pclk, 0),
293 DEFINE_PROP_END_OF_LIST(),
294};
295
296static const VMStateDescription vmstate_swdt = {
297 .name = TYPE_XLNX_SWDT,
298 .version_id = 1,
299 .minimum_version_id = 1,
300 .fields = (VMStateField[]) {
301 VMSTATE_UINT32_ARRAY(regs, SWDTState, R_MAX),
302 VMSTATE_END_OF_LIST(),
303 }
304};
305
306static void swdt_class_init(ObjectClass *klass, void *data)
307{
308 DeviceClass *dc = DEVICE_CLASS(klass);
309
310 dc->reset = swdt_reset;
311 dc->realize = swdt_realize;
312 dc->vmsd = &vmstate_swdt;
313 dc->props = swdt_properties;
314}
315
316static const TypeInfo swdt_info = {
317 .name = TYPE_XLNX_SWDT,
318 .parent = TYPE_SYS_BUS_DEVICE,
319 .instance_size = sizeof(SWDTState),
320 .class_init = swdt_class_init,
321 .instance_init = swdt_init,
322};
323
324static void swdt_register_types(void)
325{
326 type_register_static(&swdt_info);
327}
328
329type_init(swdt_register_types)
330