xref: /qemu/hw/watchdog/cmsdk-apb-watchdog.c (revision 64552b6be4758d3a774f7787b294543ccebd5358)
1050c2ea0SPeter Maydell /*
2050c2ea0SPeter Maydell  * ARM CMSDK APB watchdog emulation
3050c2ea0SPeter Maydell  *
4050c2ea0SPeter Maydell  * Copyright (c) 2018 Linaro Limited
5050c2ea0SPeter Maydell  * Written by Peter Maydell
6050c2ea0SPeter Maydell  *
7050c2ea0SPeter Maydell  *  This program is free software; you can redistribute it and/or modify
8050c2ea0SPeter Maydell  *  it under the terms of the GNU General Public License version 2 or
9050c2ea0SPeter Maydell  *  (at your option) any later version.
10050c2ea0SPeter Maydell  */
11050c2ea0SPeter Maydell 
12050c2ea0SPeter Maydell /*
13050c2ea0SPeter Maydell  * This is a model of the "APB watchdog" which is part of the Cortex-M
14050c2ea0SPeter Maydell  * System Design Kit (CMSDK) and documented in the Cortex-M System
15050c2ea0SPeter Maydell  * Design Kit Technical Reference Manual (ARM DDI0479C):
16050c2ea0SPeter Maydell  * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
17566528f8SMichel Heily  *
18566528f8SMichel Heily  * We also support the variant of this device found in the TI
19566528f8SMichel Heily  * Stellaris/Luminary boards and documented in:
20566528f8SMichel Heily  * http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
21050c2ea0SPeter Maydell  */
22050c2ea0SPeter Maydell 
23050c2ea0SPeter Maydell #include "qemu/osdep.h"
24050c2ea0SPeter Maydell #include "qemu/log.h"
25050c2ea0SPeter Maydell #include "trace.h"
26050c2ea0SPeter Maydell #include "qapi/error.h"
27050c2ea0SPeter Maydell #include "qemu/main-loop.h"
280b8fa32fSMarkus Armbruster #include "qemu/module.h"
29050c2ea0SPeter Maydell #include "sysemu/watchdog.h"
30050c2ea0SPeter Maydell #include "hw/sysbus.h"
31*64552b6bSMarkus Armbruster #include "hw/irq.h"
32050c2ea0SPeter Maydell #include "hw/registerfields.h"
33050c2ea0SPeter Maydell #include "hw/watchdog/cmsdk-apb-watchdog.h"
34050c2ea0SPeter Maydell 
35050c2ea0SPeter Maydell REG32(WDOGLOAD, 0x0)
36050c2ea0SPeter Maydell REG32(WDOGVALUE, 0x4)
37050c2ea0SPeter Maydell REG32(WDOGCONTROL, 0x8)
38050c2ea0SPeter Maydell     FIELD(WDOGCONTROL, INTEN, 0, 1)
39050c2ea0SPeter Maydell     FIELD(WDOGCONTROL, RESEN, 1, 1)
40050c2ea0SPeter Maydell #define R_WDOGCONTROL_VALID_MASK (R_WDOGCONTROL_INTEN_MASK | \
41050c2ea0SPeter Maydell                                   R_WDOGCONTROL_RESEN_MASK)
42050c2ea0SPeter Maydell REG32(WDOGINTCLR, 0xc)
43050c2ea0SPeter Maydell REG32(WDOGRIS, 0x10)
44050c2ea0SPeter Maydell     FIELD(WDOGRIS, INT, 0, 1)
45050c2ea0SPeter Maydell REG32(WDOGMIS, 0x14)
46566528f8SMichel Heily REG32(WDOGTEST, 0x418) /* only in Stellaris/Luminary version of the device */
47050c2ea0SPeter Maydell REG32(WDOGLOCK, 0xc00)
48050c2ea0SPeter Maydell #define WDOG_UNLOCK_VALUE 0x1ACCE551
49050c2ea0SPeter Maydell REG32(WDOGITCR, 0xf00)
50050c2ea0SPeter Maydell     FIELD(WDOGITCR, ENABLE, 0, 1)
51050c2ea0SPeter Maydell #define R_WDOGITCR_VALID_MASK R_WDOGITCR_ENABLE_MASK
52050c2ea0SPeter Maydell REG32(WDOGITOP, 0xf04)
53050c2ea0SPeter Maydell     FIELD(WDOGITOP, WDOGRES, 0, 1)
54050c2ea0SPeter Maydell     FIELD(WDOGITOP, WDOGINT, 1, 1)
55050c2ea0SPeter Maydell #define R_WDOGITOP_VALID_MASK (R_WDOGITOP_WDOGRES_MASK | \
56050c2ea0SPeter Maydell                                R_WDOGITOP_WDOGINT_MASK)
57050c2ea0SPeter Maydell REG32(PID4, 0xfd0)
58050c2ea0SPeter Maydell REG32(PID5, 0xfd4)
59050c2ea0SPeter Maydell REG32(PID6, 0xfd8)
60050c2ea0SPeter Maydell REG32(PID7, 0xfdc)
61050c2ea0SPeter Maydell REG32(PID0, 0xfe0)
62050c2ea0SPeter Maydell REG32(PID1, 0xfe4)
63050c2ea0SPeter Maydell REG32(PID2, 0xfe8)
64050c2ea0SPeter Maydell REG32(PID3, 0xfec)
65050c2ea0SPeter Maydell REG32(CID0, 0xff0)
66050c2ea0SPeter Maydell REG32(CID1, 0xff4)
67050c2ea0SPeter Maydell REG32(CID2, 0xff8)
68050c2ea0SPeter Maydell REG32(CID3, 0xffc)
69050c2ea0SPeter Maydell 
70050c2ea0SPeter Maydell /* PID/CID values */
71566528f8SMichel Heily static const uint32_t cmsdk_apb_watchdog_id[] = {
72050c2ea0SPeter Maydell     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
73050c2ea0SPeter Maydell     0x24, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
74050c2ea0SPeter Maydell     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
75050c2ea0SPeter Maydell };
76050c2ea0SPeter Maydell 
77566528f8SMichel Heily static const uint32_t luminary_watchdog_id[] = {
78566528f8SMichel Heily     0x00, 0x00, 0x00, 0x00, /* PID4..PID7 */
79566528f8SMichel Heily     0x05, 0x18, 0x18, 0x01, /* PID0..PID3 */
80566528f8SMichel Heily     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
81566528f8SMichel Heily };
82566528f8SMichel Heily 
83050c2ea0SPeter Maydell static bool cmsdk_apb_watchdog_intstatus(CMSDKAPBWatchdog *s)
84050c2ea0SPeter Maydell {
85050c2ea0SPeter Maydell     /* Return masked interrupt status */
86050c2ea0SPeter Maydell     return s->intstatus && (s->control & R_WDOGCONTROL_INTEN_MASK);
87050c2ea0SPeter Maydell }
88050c2ea0SPeter Maydell 
89050c2ea0SPeter Maydell static bool cmsdk_apb_watchdog_resetstatus(CMSDKAPBWatchdog *s)
90050c2ea0SPeter Maydell {
91050c2ea0SPeter Maydell     /* Return masked reset status */
92050c2ea0SPeter Maydell     return s->resetstatus && (s->control & R_WDOGCONTROL_RESEN_MASK);
93050c2ea0SPeter Maydell }
94050c2ea0SPeter Maydell 
95050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_update(CMSDKAPBWatchdog *s)
96050c2ea0SPeter Maydell {
97050c2ea0SPeter Maydell     bool wdogint;
98050c2ea0SPeter Maydell     bool wdogres;
99050c2ea0SPeter Maydell 
100050c2ea0SPeter Maydell     if (s->itcr) {
101566528f8SMichel Heily         /*
102566528f8SMichel Heily          * Not checking that !s->is_luminary since s->itcr can't be written
103566528f8SMichel Heily          * when s->is_luminary in the first place.
104566528f8SMichel Heily          */
105050c2ea0SPeter Maydell         wdogint = s->itop & R_WDOGITOP_WDOGINT_MASK;
106050c2ea0SPeter Maydell         wdogres = s->itop & R_WDOGITOP_WDOGRES_MASK;
107050c2ea0SPeter Maydell     } else {
108050c2ea0SPeter Maydell         wdogint = cmsdk_apb_watchdog_intstatus(s);
109050c2ea0SPeter Maydell         wdogres = cmsdk_apb_watchdog_resetstatus(s);
110050c2ea0SPeter Maydell     }
111050c2ea0SPeter Maydell 
112050c2ea0SPeter Maydell     qemu_set_irq(s->wdogint, wdogint);
113050c2ea0SPeter Maydell     if (wdogres) {
114050c2ea0SPeter Maydell         watchdog_perform_action();
115050c2ea0SPeter Maydell     }
116050c2ea0SPeter Maydell }
117050c2ea0SPeter Maydell 
118050c2ea0SPeter Maydell static uint64_t cmsdk_apb_watchdog_read(void *opaque, hwaddr offset,
119050c2ea0SPeter Maydell                                         unsigned size)
120050c2ea0SPeter Maydell {
121050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
122050c2ea0SPeter Maydell     uint64_t r;
123050c2ea0SPeter Maydell 
124050c2ea0SPeter Maydell     switch (offset) {
125050c2ea0SPeter Maydell     case A_WDOGLOAD:
126050c2ea0SPeter Maydell         r = ptimer_get_limit(s->timer);
127050c2ea0SPeter Maydell         break;
128050c2ea0SPeter Maydell     case A_WDOGVALUE:
129050c2ea0SPeter Maydell         r = ptimer_get_count(s->timer);
130050c2ea0SPeter Maydell         break;
131050c2ea0SPeter Maydell     case A_WDOGCONTROL:
132050c2ea0SPeter Maydell         r = s->control;
133050c2ea0SPeter Maydell         break;
134050c2ea0SPeter Maydell     case A_WDOGRIS:
135050c2ea0SPeter Maydell         r = s->intstatus;
136050c2ea0SPeter Maydell         break;
137050c2ea0SPeter Maydell     case A_WDOGMIS:
138050c2ea0SPeter Maydell         r = cmsdk_apb_watchdog_intstatus(s);
139050c2ea0SPeter Maydell         break;
140050c2ea0SPeter Maydell     case A_WDOGLOCK:
141050c2ea0SPeter Maydell         r = s->lock;
142050c2ea0SPeter Maydell         break;
143050c2ea0SPeter Maydell     case A_WDOGITCR:
144566528f8SMichel Heily         if (s->is_luminary) {
145566528f8SMichel Heily             goto bad_offset;
146566528f8SMichel Heily         }
147050c2ea0SPeter Maydell         r = s->itcr;
148050c2ea0SPeter Maydell         break;
149050c2ea0SPeter Maydell     case A_PID4 ... A_CID3:
150566528f8SMichel Heily         r = s->id[(offset - A_PID4) / 4];
151050c2ea0SPeter Maydell         break;
152050c2ea0SPeter Maydell     case A_WDOGINTCLR:
153050c2ea0SPeter Maydell     case A_WDOGITOP:
154566528f8SMichel Heily         if (s->is_luminary) {
155566528f8SMichel Heily             goto bad_offset;
156566528f8SMichel Heily         }
157050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
158050c2ea0SPeter Maydell                       "CMSDK APB watchdog read: read of WO offset %x\n",
159050c2ea0SPeter Maydell                       (int)offset);
160050c2ea0SPeter Maydell         r = 0;
161050c2ea0SPeter Maydell         break;
162566528f8SMichel Heily     case A_WDOGTEST:
163566528f8SMichel Heily         if (!s->is_luminary) {
164566528f8SMichel Heily             goto bad_offset;
165566528f8SMichel Heily         }
166566528f8SMichel Heily         qemu_log_mask(LOG_UNIMP,
167566528f8SMichel Heily                       "Luminary watchdog read: stall not implemented\n");
168566528f8SMichel Heily         r = 0;
169566528f8SMichel Heily         break;
170050c2ea0SPeter Maydell     default:
171566528f8SMichel Heily bad_offset:
172050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
173050c2ea0SPeter Maydell                       "CMSDK APB watchdog read: bad offset %x\n", (int)offset);
174050c2ea0SPeter Maydell         r = 0;
175050c2ea0SPeter Maydell         break;
176050c2ea0SPeter Maydell     }
177050c2ea0SPeter Maydell     trace_cmsdk_apb_watchdog_read(offset, r, size);
178050c2ea0SPeter Maydell     return r;
179050c2ea0SPeter Maydell }
180050c2ea0SPeter Maydell 
181050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
182050c2ea0SPeter Maydell                                      uint64_t value, unsigned size)
183050c2ea0SPeter Maydell {
184050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
185050c2ea0SPeter Maydell 
186050c2ea0SPeter Maydell     trace_cmsdk_apb_watchdog_write(offset, value, size);
187050c2ea0SPeter Maydell 
188050c2ea0SPeter Maydell     if (s->lock && offset != A_WDOGLOCK) {
189050c2ea0SPeter Maydell         /* Write access is disabled via WDOGLOCK */
190050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
191050c2ea0SPeter Maydell                       "CMSDK APB watchdog write: write to locked watchdog\n");
192050c2ea0SPeter Maydell         return;
193050c2ea0SPeter Maydell     }
194050c2ea0SPeter Maydell 
195050c2ea0SPeter Maydell     switch (offset) {
196050c2ea0SPeter Maydell     case A_WDOGLOAD:
197050c2ea0SPeter Maydell         /*
198050c2ea0SPeter Maydell          * Reset the load value and the current count, and make sure
199050c2ea0SPeter Maydell          * we're counting.
200050c2ea0SPeter Maydell          */
201050c2ea0SPeter Maydell         ptimer_set_limit(s->timer, value, 1);
202050c2ea0SPeter Maydell         ptimer_run(s->timer, 0);
203050c2ea0SPeter Maydell         break;
204050c2ea0SPeter Maydell     case A_WDOGCONTROL:
205566528f8SMichel Heily         if (s->is_luminary && 0 != (R_WDOGCONTROL_INTEN_MASK & s->control)) {
206566528f8SMichel Heily             /*
207566528f8SMichel Heily              * The Luminary version of this device ignores writes to
208566528f8SMichel Heily              * this register after the guest has enabled interrupts
209566528f8SMichel Heily              * (so they can only be disabled again via reset).
210566528f8SMichel Heily              */
211566528f8SMichel Heily             break;
212566528f8SMichel Heily         }
213050c2ea0SPeter Maydell         s->control = value & R_WDOGCONTROL_VALID_MASK;
214050c2ea0SPeter Maydell         cmsdk_apb_watchdog_update(s);
215050c2ea0SPeter Maydell         break;
216050c2ea0SPeter Maydell     case A_WDOGINTCLR:
217050c2ea0SPeter Maydell         s->intstatus = 0;
218050c2ea0SPeter Maydell         ptimer_set_count(s->timer, ptimer_get_limit(s->timer));
219050c2ea0SPeter Maydell         cmsdk_apb_watchdog_update(s);
220050c2ea0SPeter Maydell         break;
221050c2ea0SPeter Maydell     case A_WDOGLOCK:
222050c2ea0SPeter Maydell         s->lock = (value != WDOG_UNLOCK_VALUE);
223050c2ea0SPeter Maydell         break;
224050c2ea0SPeter Maydell     case A_WDOGITCR:
225566528f8SMichel Heily         if (s->is_luminary) {
226566528f8SMichel Heily             goto bad_offset;
227566528f8SMichel Heily         }
228050c2ea0SPeter Maydell         s->itcr = value & R_WDOGITCR_VALID_MASK;
229050c2ea0SPeter Maydell         cmsdk_apb_watchdog_update(s);
230050c2ea0SPeter Maydell         break;
231050c2ea0SPeter Maydell     case A_WDOGITOP:
232566528f8SMichel Heily         if (s->is_luminary) {
233566528f8SMichel Heily             goto bad_offset;
234566528f8SMichel Heily         }
235050c2ea0SPeter Maydell         s->itop = value & R_WDOGITOP_VALID_MASK;
236050c2ea0SPeter Maydell         cmsdk_apb_watchdog_update(s);
237050c2ea0SPeter Maydell         break;
238050c2ea0SPeter Maydell     case A_WDOGVALUE:
239050c2ea0SPeter Maydell     case A_WDOGRIS:
240050c2ea0SPeter Maydell     case A_WDOGMIS:
241050c2ea0SPeter Maydell     case A_PID4 ... A_CID3:
242050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
243050c2ea0SPeter Maydell                       "CMSDK APB watchdog write: write to RO offset 0x%x\n",
244050c2ea0SPeter Maydell                       (int)offset);
245050c2ea0SPeter Maydell         break;
246566528f8SMichel Heily     case A_WDOGTEST:
247566528f8SMichel Heily         if (!s->is_luminary) {
248566528f8SMichel Heily             goto bad_offset;
249566528f8SMichel Heily         }
250566528f8SMichel Heily         qemu_log_mask(LOG_UNIMP,
251566528f8SMichel Heily                       "Luminary watchdog write: stall not implemented\n");
252566528f8SMichel Heily         break;
253050c2ea0SPeter Maydell     default:
254566528f8SMichel Heily bad_offset:
255050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
256050c2ea0SPeter Maydell                       "CMSDK APB watchdog write: bad offset 0x%x\n",
257050c2ea0SPeter Maydell                       (int)offset);
258050c2ea0SPeter Maydell         break;
259050c2ea0SPeter Maydell     }
260050c2ea0SPeter Maydell }
261050c2ea0SPeter Maydell 
262050c2ea0SPeter Maydell static const MemoryRegionOps cmsdk_apb_watchdog_ops = {
263050c2ea0SPeter Maydell     .read = cmsdk_apb_watchdog_read,
264050c2ea0SPeter Maydell     .write = cmsdk_apb_watchdog_write,
265050c2ea0SPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
266050c2ea0SPeter Maydell     /* byte/halfword accesses are just zero-padded on reads and writes */
267050c2ea0SPeter Maydell     .impl.min_access_size = 4,
268050c2ea0SPeter Maydell     .impl.max_access_size = 4,
269050c2ea0SPeter Maydell     .valid.min_access_size = 1,
270050c2ea0SPeter Maydell     .valid.max_access_size = 4,
271050c2ea0SPeter Maydell };
272050c2ea0SPeter Maydell 
273050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_tick(void *opaque)
274050c2ea0SPeter Maydell {
275050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
276050c2ea0SPeter Maydell 
277050c2ea0SPeter Maydell     if (!s->intstatus) {
278050c2ea0SPeter Maydell         /* Count expired for the first time: raise interrupt */
279050c2ea0SPeter Maydell         s->intstatus = R_WDOGRIS_INT_MASK;
280050c2ea0SPeter Maydell     } else {
281050c2ea0SPeter Maydell         /* Count expired for the second time: raise reset and stop clock */
282050c2ea0SPeter Maydell         s->resetstatus = 1;
283050c2ea0SPeter Maydell         ptimer_stop(s->timer);
284050c2ea0SPeter Maydell     }
285050c2ea0SPeter Maydell     cmsdk_apb_watchdog_update(s);
286050c2ea0SPeter Maydell }
287050c2ea0SPeter Maydell 
288050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_reset(DeviceState *dev)
289050c2ea0SPeter Maydell {
290050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
291050c2ea0SPeter Maydell 
292050c2ea0SPeter Maydell     trace_cmsdk_apb_watchdog_reset();
293050c2ea0SPeter Maydell     s->control = 0;
294050c2ea0SPeter Maydell     s->intstatus = 0;
295050c2ea0SPeter Maydell     s->lock = 0;
296050c2ea0SPeter Maydell     s->itcr = 0;
297050c2ea0SPeter Maydell     s->itop = 0;
298050c2ea0SPeter Maydell     s->resetstatus = 0;
299050c2ea0SPeter Maydell     /* Set the limit and the count */
300050c2ea0SPeter Maydell     ptimer_set_limit(s->timer, 0xffffffff, 1);
301050c2ea0SPeter Maydell     ptimer_run(s->timer, 0);
302050c2ea0SPeter Maydell }
303050c2ea0SPeter Maydell 
304050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_init(Object *obj)
305050c2ea0SPeter Maydell {
306050c2ea0SPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
307050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(obj);
308050c2ea0SPeter Maydell 
309050c2ea0SPeter Maydell     memory_region_init_io(&s->iomem, obj, &cmsdk_apb_watchdog_ops,
310050c2ea0SPeter Maydell                           s, "cmsdk-apb-watchdog", 0x1000);
311050c2ea0SPeter Maydell     sysbus_init_mmio(sbd, &s->iomem);
312050c2ea0SPeter Maydell     sysbus_init_irq(sbd, &s->wdogint);
313566528f8SMichel Heily 
314566528f8SMichel Heily     s->is_luminary = false;
315566528f8SMichel Heily     s->id = cmsdk_apb_watchdog_id;
316050c2ea0SPeter Maydell }
317050c2ea0SPeter Maydell 
318050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
319050c2ea0SPeter Maydell {
320050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
321050c2ea0SPeter Maydell     QEMUBH *bh;
322050c2ea0SPeter Maydell 
323050c2ea0SPeter Maydell     if (s->wdogclk_frq == 0) {
324050c2ea0SPeter Maydell         error_setg(errp,
325050c2ea0SPeter Maydell                    "CMSDK APB watchdog: wdogclk-frq property must be set");
326050c2ea0SPeter Maydell         return;
327050c2ea0SPeter Maydell     }
328050c2ea0SPeter Maydell 
329050c2ea0SPeter Maydell     bh = qemu_bh_new(cmsdk_apb_watchdog_tick, s);
330050c2ea0SPeter Maydell     s->timer = ptimer_init(bh,
331050c2ea0SPeter Maydell                            PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
332050c2ea0SPeter Maydell                            PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
333050c2ea0SPeter Maydell                            PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
334050c2ea0SPeter Maydell                            PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
335050c2ea0SPeter Maydell 
336050c2ea0SPeter Maydell     ptimer_set_freq(s->timer, s->wdogclk_frq);
337050c2ea0SPeter Maydell }
338050c2ea0SPeter Maydell 
339050c2ea0SPeter Maydell static const VMStateDescription cmsdk_apb_watchdog_vmstate = {
340050c2ea0SPeter Maydell     .name = "cmsdk-apb-watchdog",
341050c2ea0SPeter Maydell     .version_id = 1,
342050c2ea0SPeter Maydell     .minimum_version_id = 1,
343050c2ea0SPeter Maydell     .fields = (VMStateField[]) {
344050c2ea0SPeter Maydell         VMSTATE_PTIMER(timer, CMSDKAPBWatchdog),
345050c2ea0SPeter Maydell         VMSTATE_UINT32(control, CMSDKAPBWatchdog),
346050c2ea0SPeter Maydell         VMSTATE_UINT32(intstatus, CMSDKAPBWatchdog),
347050c2ea0SPeter Maydell         VMSTATE_UINT32(lock, CMSDKAPBWatchdog),
348050c2ea0SPeter Maydell         VMSTATE_UINT32(itcr, CMSDKAPBWatchdog),
349050c2ea0SPeter Maydell         VMSTATE_UINT32(itop, CMSDKAPBWatchdog),
350050c2ea0SPeter Maydell         VMSTATE_UINT32(resetstatus, CMSDKAPBWatchdog),
351050c2ea0SPeter Maydell         VMSTATE_END_OF_LIST()
352050c2ea0SPeter Maydell     }
353050c2ea0SPeter Maydell };
354050c2ea0SPeter Maydell 
355050c2ea0SPeter Maydell static Property cmsdk_apb_watchdog_properties[] = {
356050c2ea0SPeter Maydell     DEFINE_PROP_UINT32("wdogclk-frq", CMSDKAPBWatchdog, wdogclk_frq, 0),
357050c2ea0SPeter Maydell     DEFINE_PROP_END_OF_LIST(),
358050c2ea0SPeter Maydell };
359050c2ea0SPeter Maydell 
360050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, void *data)
361050c2ea0SPeter Maydell {
362050c2ea0SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
363050c2ea0SPeter Maydell 
364050c2ea0SPeter Maydell     dc->realize = cmsdk_apb_watchdog_realize;
365050c2ea0SPeter Maydell     dc->vmsd = &cmsdk_apb_watchdog_vmstate;
366050c2ea0SPeter Maydell     dc->reset = cmsdk_apb_watchdog_reset;
367050c2ea0SPeter Maydell     dc->props = cmsdk_apb_watchdog_properties;
368050c2ea0SPeter Maydell }
369050c2ea0SPeter Maydell 
370050c2ea0SPeter Maydell static const TypeInfo cmsdk_apb_watchdog_info = {
371050c2ea0SPeter Maydell     .name = TYPE_CMSDK_APB_WATCHDOG,
372050c2ea0SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
373050c2ea0SPeter Maydell     .instance_size = sizeof(CMSDKAPBWatchdog),
374050c2ea0SPeter Maydell     .instance_init = cmsdk_apb_watchdog_init,
375050c2ea0SPeter Maydell     .class_init = cmsdk_apb_watchdog_class_init,
376050c2ea0SPeter Maydell };
377050c2ea0SPeter Maydell 
378566528f8SMichel Heily static void luminary_watchdog_init(Object *obj)
379566528f8SMichel Heily {
380566528f8SMichel Heily     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(obj);
381566528f8SMichel Heily 
382566528f8SMichel Heily     s->is_luminary = true;
383566528f8SMichel Heily     s->id = luminary_watchdog_id;
384566528f8SMichel Heily }
385566528f8SMichel Heily 
386566528f8SMichel Heily static const TypeInfo luminary_watchdog_info = {
387566528f8SMichel Heily     .name = TYPE_LUMINARY_WATCHDOG,
388566528f8SMichel Heily     .parent = TYPE_CMSDK_APB_WATCHDOG,
389566528f8SMichel Heily     .instance_init = luminary_watchdog_init
390566528f8SMichel Heily };
391566528f8SMichel Heily 
392050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_register_types(void)
393050c2ea0SPeter Maydell {
394050c2ea0SPeter Maydell     type_register_static(&cmsdk_apb_watchdog_info);
395566528f8SMichel Heily     type_register_static(&luminary_watchdog_info);
396050c2ea0SPeter Maydell }
397050c2ea0SPeter Maydell 
398050c2ea0SPeter Maydell type_init(cmsdk_apb_watchdog_register_types);
399