xref: /qemu/hw/watchdog/cmsdk-apb-watchdog.c (revision 4f67d30b5e74e060b8dbe10528829b47345cd6e8) !
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"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
28050c2ea0SPeter Maydell #include "sysemu/watchdog.h"
29050c2ea0SPeter Maydell #include "hw/sysbus.h"
3064552b6bSMarkus Armbruster #include "hw/irq.h"
31a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
32050c2ea0SPeter Maydell #include "hw/registerfields.h"
33050c2ea0SPeter Maydell #include "hw/watchdog/cmsdk-apb-watchdog.h"
34d6454270SMarkus Armbruster #include "migration/vmstate.h"
35050c2ea0SPeter Maydell 
36050c2ea0SPeter Maydell REG32(WDOGLOAD, 0x0)
37050c2ea0SPeter Maydell REG32(WDOGVALUE, 0x4)
38050c2ea0SPeter Maydell REG32(WDOGCONTROL, 0x8)
39050c2ea0SPeter Maydell     FIELD(WDOGCONTROL, INTEN, 0, 1)
40050c2ea0SPeter Maydell     FIELD(WDOGCONTROL, RESEN, 1, 1)
41050c2ea0SPeter Maydell #define R_WDOGCONTROL_VALID_MASK (R_WDOGCONTROL_INTEN_MASK | \
42050c2ea0SPeter Maydell                                   R_WDOGCONTROL_RESEN_MASK)
43050c2ea0SPeter Maydell REG32(WDOGINTCLR, 0xc)
44050c2ea0SPeter Maydell REG32(WDOGRIS, 0x10)
45050c2ea0SPeter Maydell     FIELD(WDOGRIS, INT, 0, 1)
46050c2ea0SPeter Maydell REG32(WDOGMIS, 0x14)
47566528f8SMichel Heily REG32(WDOGTEST, 0x418) /* only in Stellaris/Luminary version of the device */
48050c2ea0SPeter Maydell REG32(WDOGLOCK, 0xc00)
49050c2ea0SPeter Maydell #define WDOG_UNLOCK_VALUE 0x1ACCE551
50050c2ea0SPeter Maydell REG32(WDOGITCR, 0xf00)
51050c2ea0SPeter Maydell     FIELD(WDOGITCR, ENABLE, 0, 1)
52050c2ea0SPeter Maydell #define R_WDOGITCR_VALID_MASK R_WDOGITCR_ENABLE_MASK
53050c2ea0SPeter Maydell REG32(WDOGITOP, 0xf04)
54050c2ea0SPeter Maydell     FIELD(WDOGITOP, WDOGRES, 0, 1)
55050c2ea0SPeter Maydell     FIELD(WDOGITOP, WDOGINT, 1, 1)
56050c2ea0SPeter Maydell #define R_WDOGITOP_VALID_MASK (R_WDOGITOP_WDOGRES_MASK | \
57050c2ea0SPeter Maydell                                R_WDOGITOP_WDOGINT_MASK)
58050c2ea0SPeter Maydell REG32(PID4, 0xfd0)
59050c2ea0SPeter Maydell REG32(PID5, 0xfd4)
60050c2ea0SPeter Maydell REG32(PID6, 0xfd8)
61050c2ea0SPeter Maydell REG32(PID7, 0xfdc)
62050c2ea0SPeter Maydell REG32(PID0, 0xfe0)
63050c2ea0SPeter Maydell REG32(PID1, 0xfe4)
64050c2ea0SPeter Maydell REG32(PID2, 0xfe8)
65050c2ea0SPeter Maydell REG32(PID3, 0xfec)
66050c2ea0SPeter Maydell REG32(CID0, 0xff0)
67050c2ea0SPeter Maydell REG32(CID1, 0xff4)
68050c2ea0SPeter Maydell REG32(CID2, 0xff8)
69050c2ea0SPeter Maydell REG32(CID3, 0xffc)
70050c2ea0SPeter Maydell 
71050c2ea0SPeter Maydell /* PID/CID values */
72566528f8SMichel Heily static const uint32_t cmsdk_apb_watchdog_id[] = {
73050c2ea0SPeter Maydell     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
74050c2ea0SPeter Maydell     0x24, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
75050c2ea0SPeter Maydell     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
76050c2ea0SPeter Maydell };
77050c2ea0SPeter Maydell 
78566528f8SMichel Heily static const uint32_t luminary_watchdog_id[] = {
79566528f8SMichel Heily     0x00, 0x00, 0x00, 0x00, /* PID4..PID7 */
80566528f8SMichel Heily     0x05, 0x18, 0x18, 0x01, /* PID0..PID3 */
81566528f8SMichel Heily     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
82566528f8SMichel Heily };
83566528f8SMichel Heily 
84050c2ea0SPeter Maydell static bool cmsdk_apb_watchdog_intstatus(CMSDKAPBWatchdog *s)
85050c2ea0SPeter Maydell {
86050c2ea0SPeter Maydell     /* Return masked interrupt status */
87050c2ea0SPeter Maydell     return s->intstatus && (s->control & R_WDOGCONTROL_INTEN_MASK);
88050c2ea0SPeter Maydell }
89050c2ea0SPeter Maydell 
90050c2ea0SPeter Maydell static bool cmsdk_apb_watchdog_resetstatus(CMSDKAPBWatchdog *s)
91050c2ea0SPeter Maydell {
92050c2ea0SPeter Maydell     /* Return masked reset status */
93050c2ea0SPeter Maydell     return s->resetstatus && (s->control & R_WDOGCONTROL_RESEN_MASK);
94050c2ea0SPeter Maydell }
95050c2ea0SPeter Maydell 
96050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_update(CMSDKAPBWatchdog *s)
97050c2ea0SPeter Maydell {
98050c2ea0SPeter Maydell     bool wdogint;
99050c2ea0SPeter Maydell     bool wdogres;
100050c2ea0SPeter Maydell 
101050c2ea0SPeter Maydell     if (s->itcr) {
102566528f8SMichel Heily         /*
103566528f8SMichel Heily          * Not checking that !s->is_luminary since s->itcr can't be written
104566528f8SMichel Heily          * when s->is_luminary in the first place.
105566528f8SMichel Heily          */
106050c2ea0SPeter Maydell         wdogint = s->itop & R_WDOGITOP_WDOGINT_MASK;
107050c2ea0SPeter Maydell         wdogres = s->itop & R_WDOGITOP_WDOGRES_MASK;
108050c2ea0SPeter Maydell     } else {
109050c2ea0SPeter Maydell         wdogint = cmsdk_apb_watchdog_intstatus(s);
110050c2ea0SPeter Maydell         wdogres = cmsdk_apb_watchdog_resetstatus(s);
111050c2ea0SPeter Maydell     }
112050c2ea0SPeter Maydell 
113050c2ea0SPeter Maydell     qemu_set_irq(s->wdogint, wdogint);
114050c2ea0SPeter Maydell     if (wdogres) {
115050c2ea0SPeter Maydell         watchdog_perform_action();
116050c2ea0SPeter Maydell     }
117050c2ea0SPeter Maydell }
118050c2ea0SPeter Maydell 
119050c2ea0SPeter Maydell static uint64_t cmsdk_apb_watchdog_read(void *opaque, hwaddr offset,
120050c2ea0SPeter Maydell                                         unsigned size)
121050c2ea0SPeter Maydell {
122050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
123050c2ea0SPeter Maydell     uint64_t r;
124050c2ea0SPeter Maydell 
125050c2ea0SPeter Maydell     switch (offset) {
126050c2ea0SPeter Maydell     case A_WDOGLOAD:
127050c2ea0SPeter Maydell         r = ptimer_get_limit(s->timer);
128050c2ea0SPeter Maydell         break;
129050c2ea0SPeter Maydell     case A_WDOGVALUE:
130050c2ea0SPeter Maydell         r = ptimer_get_count(s->timer);
131050c2ea0SPeter Maydell         break;
132050c2ea0SPeter Maydell     case A_WDOGCONTROL:
133050c2ea0SPeter Maydell         r = s->control;
134050c2ea0SPeter Maydell         break;
135050c2ea0SPeter Maydell     case A_WDOGRIS:
136050c2ea0SPeter Maydell         r = s->intstatus;
137050c2ea0SPeter Maydell         break;
138050c2ea0SPeter Maydell     case A_WDOGMIS:
139050c2ea0SPeter Maydell         r = cmsdk_apb_watchdog_intstatus(s);
140050c2ea0SPeter Maydell         break;
141050c2ea0SPeter Maydell     case A_WDOGLOCK:
142050c2ea0SPeter Maydell         r = s->lock;
143050c2ea0SPeter Maydell         break;
144050c2ea0SPeter Maydell     case A_WDOGITCR:
145566528f8SMichel Heily         if (s->is_luminary) {
146566528f8SMichel Heily             goto bad_offset;
147566528f8SMichel Heily         }
148050c2ea0SPeter Maydell         r = s->itcr;
149050c2ea0SPeter Maydell         break;
150050c2ea0SPeter Maydell     case A_PID4 ... A_CID3:
151566528f8SMichel Heily         r = s->id[(offset - A_PID4) / 4];
152050c2ea0SPeter Maydell         break;
153050c2ea0SPeter Maydell     case A_WDOGINTCLR:
154050c2ea0SPeter Maydell     case A_WDOGITOP:
155566528f8SMichel Heily         if (s->is_luminary) {
156566528f8SMichel Heily             goto bad_offset;
157566528f8SMichel Heily         }
158050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
159050c2ea0SPeter Maydell                       "CMSDK APB watchdog read: read of WO offset %x\n",
160050c2ea0SPeter Maydell                       (int)offset);
161050c2ea0SPeter Maydell         r = 0;
162050c2ea0SPeter Maydell         break;
163566528f8SMichel Heily     case A_WDOGTEST:
164566528f8SMichel Heily         if (!s->is_luminary) {
165566528f8SMichel Heily             goto bad_offset;
166566528f8SMichel Heily         }
167566528f8SMichel Heily         qemu_log_mask(LOG_UNIMP,
168566528f8SMichel Heily                       "Luminary watchdog read: stall not implemented\n");
169566528f8SMichel Heily         r = 0;
170566528f8SMichel Heily         break;
171050c2ea0SPeter Maydell     default:
172566528f8SMichel Heily bad_offset:
173050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
174050c2ea0SPeter Maydell                       "CMSDK APB watchdog read: bad offset %x\n", (int)offset);
175050c2ea0SPeter Maydell         r = 0;
176050c2ea0SPeter Maydell         break;
177050c2ea0SPeter Maydell     }
178050c2ea0SPeter Maydell     trace_cmsdk_apb_watchdog_read(offset, r, size);
179050c2ea0SPeter Maydell     return r;
180050c2ea0SPeter Maydell }
181050c2ea0SPeter Maydell 
182050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
183050c2ea0SPeter Maydell                                      uint64_t value, unsigned size)
184050c2ea0SPeter Maydell {
185050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
186050c2ea0SPeter Maydell 
187050c2ea0SPeter Maydell     trace_cmsdk_apb_watchdog_write(offset, value, size);
188050c2ea0SPeter Maydell 
189050c2ea0SPeter Maydell     if (s->lock && offset != A_WDOGLOCK) {
190050c2ea0SPeter Maydell         /* Write access is disabled via WDOGLOCK */
191050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
192050c2ea0SPeter Maydell                       "CMSDK APB watchdog write: write to locked watchdog\n");
193050c2ea0SPeter Maydell         return;
194050c2ea0SPeter Maydell     }
195050c2ea0SPeter Maydell 
196050c2ea0SPeter Maydell     switch (offset) {
197050c2ea0SPeter Maydell     case A_WDOGLOAD:
198050c2ea0SPeter Maydell         /*
199050c2ea0SPeter Maydell          * Reset the load value and the current count, and make sure
200050c2ea0SPeter Maydell          * we're counting.
201050c2ea0SPeter Maydell          */
2028c9dbc62SPeter Maydell         ptimer_transaction_begin(s->timer);
203050c2ea0SPeter Maydell         ptimer_set_limit(s->timer, value, 1);
204050c2ea0SPeter Maydell         ptimer_run(s->timer, 0);
2058c9dbc62SPeter Maydell         ptimer_transaction_commit(s->timer);
206050c2ea0SPeter Maydell         break;
207050c2ea0SPeter Maydell     case A_WDOGCONTROL:
208566528f8SMichel Heily         if (s->is_luminary && 0 != (R_WDOGCONTROL_INTEN_MASK & s->control)) {
209566528f8SMichel Heily             /*
210566528f8SMichel Heily              * The Luminary version of this device ignores writes to
211566528f8SMichel Heily              * this register after the guest has enabled interrupts
212566528f8SMichel Heily              * (so they can only be disabled again via reset).
213566528f8SMichel Heily              */
214566528f8SMichel Heily             break;
215566528f8SMichel Heily         }
216050c2ea0SPeter Maydell         s->control = value & R_WDOGCONTROL_VALID_MASK;
217050c2ea0SPeter Maydell         cmsdk_apb_watchdog_update(s);
218050c2ea0SPeter Maydell         break;
219050c2ea0SPeter Maydell     case A_WDOGINTCLR:
220050c2ea0SPeter Maydell         s->intstatus = 0;
2218c9dbc62SPeter Maydell         ptimer_transaction_begin(s->timer);
222050c2ea0SPeter Maydell         ptimer_set_count(s->timer, ptimer_get_limit(s->timer));
2238c9dbc62SPeter Maydell         ptimer_transaction_commit(s->timer);
224050c2ea0SPeter Maydell         cmsdk_apb_watchdog_update(s);
225050c2ea0SPeter Maydell         break;
226050c2ea0SPeter Maydell     case A_WDOGLOCK:
227050c2ea0SPeter Maydell         s->lock = (value != WDOG_UNLOCK_VALUE);
228050c2ea0SPeter Maydell         break;
229050c2ea0SPeter Maydell     case A_WDOGITCR:
230566528f8SMichel Heily         if (s->is_luminary) {
231566528f8SMichel Heily             goto bad_offset;
232566528f8SMichel Heily         }
233050c2ea0SPeter Maydell         s->itcr = value & R_WDOGITCR_VALID_MASK;
234050c2ea0SPeter Maydell         cmsdk_apb_watchdog_update(s);
235050c2ea0SPeter Maydell         break;
236050c2ea0SPeter Maydell     case A_WDOGITOP:
237566528f8SMichel Heily         if (s->is_luminary) {
238566528f8SMichel Heily             goto bad_offset;
239566528f8SMichel Heily         }
240050c2ea0SPeter Maydell         s->itop = value & R_WDOGITOP_VALID_MASK;
241050c2ea0SPeter Maydell         cmsdk_apb_watchdog_update(s);
242050c2ea0SPeter Maydell         break;
243050c2ea0SPeter Maydell     case A_WDOGVALUE:
244050c2ea0SPeter Maydell     case A_WDOGRIS:
245050c2ea0SPeter Maydell     case A_WDOGMIS:
246050c2ea0SPeter Maydell     case A_PID4 ... A_CID3:
247050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
248050c2ea0SPeter Maydell                       "CMSDK APB watchdog write: write to RO offset 0x%x\n",
249050c2ea0SPeter Maydell                       (int)offset);
250050c2ea0SPeter Maydell         break;
251566528f8SMichel Heily     case A_WDOGTEST:
252566528f8SMichel Heily         if (!s->is_luminary) {
253566528f8SMichel Heily             goto bad_offset;
254566528f8SMichel Heily         }
255566528f8SMichel Heily         qemu_log_mask(LOG_UNIMP,
256566528f8SMichel Heily                       "Luminary watchdog write: stall not implemented\n");
257566528f8SMichel Heily         break;
258050c2ea0SPeter Maydell     default:
259566528f8SMichel Heily bad_offset:
260050c2ea0SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
261050c2ea0SPeter Maydell                       "CMSDK APB watchdog write: bad offset 0x%x\n",
262050c2ea0SPeter Maydell                       (int)offset);
263050c2ea0SPeter Maydell         break;
264050c2ea0SPeter Maydell     }
265050c2ea0SPeter Maydell }
266050c2ea0SPeter Maydell 
267050c2ea0SPeter Maydell static const MemoryRegionOps cmsdk_apb_watchdog_ops = {
268050c2ea0SPeter Maydell     .read = cmsdk_apb_watchdog_read,
269050c2ea0SPeter Maydell     .write = cmsdk_apb_watchdog_write,
270050c2ea0SPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
271050c2ea0SPeter Maydell     /* byte/halfword accesses are just zero-padded on reads and writes */
272050c2ea0SPeter Maydell     .impl.min_access_size = 4,
273050c2ea0SPeter Maydell     .impl.max_access_size = 4,
274050c2ea0SPeter Maydell     .valid.min_access_size = 1,
275050c2ea0SPeter Maydell     .valid.max_access_size = 4,
276050c2ea0SPeter Maydell };
277050c2ea0SPeter Maydell 
278050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_tick(void *opaque)
279050c2ea0SPeter Maydell {
280050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
281050c2ea0SPeter Maydell 
282050c2ea0SPeter Maydell     if (!s->intstatus) {
283050c2ea0SPeter Maydell         /* Count expired for the first time: raise interrupt */
284050c2ea0SPeter Maydell         s->intstatus = R_WDOGRIS_INT_MASK;
285050c2ea0SPeter Maydell     } else {
286050c2ea0SPeter Maydell         /* Count expired for the second time: raise reset and stop clock */
287050c2ea0SPeter Maydell         s->resetstatus = 1;
288050c2ea0SPeter Maydell         ptimer_stop(s->timer);
289050c2ea0SPeter Maydell     }
290050c2ea0SPeter Maydell     cmsdk_apb_watchdog_update(s);
291050c2ea0SPeter Maydell }
292050c2ea0SPeter Maydell 
293050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_reset(DeviceState *dev)
294050c2ea0SPeter Maydell {
295050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
296050c2ea0SPeter Maydell 
297050c2ea0SPeter Maydell     trace_cmsdk_apb_watchdog_reset();
298050c2ea0SPeter Maydell     s->control = 0;
299050c2ea0SPeter Maydell     s->intstatus = 0;
300050c2ea0SPeter Maydell     s->lock = 0;
301050c2ea0SPeter Maydell     s->itcr = 0;
302050c2ea0SPeter Maydell     s->itop = 0;
303050c2ea0SPeter Maydell     s->resetstatus = 0;
304050c2ea0SPeter Maydell     /* Set the limit and the count */
3058c9dbc62SPeter Maydell     ptimer_transaction_begin(s->timer);
306050c2ea0SPeter Maydell     ptimer_set_limit(s->timer, 0xffffffff, 1);
307050c2ea0SPeter Maydell     ptimer_run(s->timer, 0);
3088c9dbc62SPeter Maydell     ptimer_transaction_commit(s->timer);
309050c2ea0SPeter Maydell }
310050c2ea0SPeter Maydell 
311050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_init(Object *obj)
312050c2ea0SPeter Maydell {
313050c2ea0SPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
314050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(obj);
315050c2ea0SPeter Maydell 
316050c2ea0SPeter Maydell     memory_region_init_io(&s->iomem, obj, &cmsdk_apb_watchdog_ops,
317050c2ea0SPeter Maydell                           s, "cmsdk-apb-watchdog", 0x1000);
318050c2ea0SPeter Maydell     sysbus_init_mmio(sbd, &s->iomem);
319050c2ea0SPeter Maydell     sysbus_init_irq(sbd, &s->wdogint);
320566528f8SMichel Heily 
321566528f8SMichel Heily     s->is_luminary = false;
322566528f8SMichel Heily     s->id = cmsdk_apb_watchdog_id;
323050c2ea0SPeter Maydell }
324050c2ea0SPeter Maydell 
325050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
326050c2ea0SPeter Maydell {
327050c2ea0SPeter Maydell     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
328050c2ea0SPeter Maydell 
329050c2ea0SPeter Maydell     if (s->wdogclk_frq == 0) {
330050c2ea0SPeter Maydell         error_setg(errp,
331050c2ea0SPeter Maydell                    "CMSDK APB watchdog: wdogclk-frq property must be set");
332050c2ea0SPeter Maydell         return;
333050c2ea0SPeter Maydell     }
334050c2ea0SPeter Maydell 
3358c9dbc62SPeter Maydell     s->timer = ptimer_init(cmsdk_apb_watchdog_tick, s,
336050c2ea0SPeter Maydell                            PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
337050c2ea0SPeter Maydell                            PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
338050c2ea0SPeter Maydell                            PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
339050c2ea0SPeter Maydell                            PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
340050c2ea0SPeter Maydell 
3418c9dbc62SPeter Maydell     ptimer_transaction_begin(s->timer);
342050c2ea0SPeter Maydell     ptimer_set_freq(s->timer, s->wdogclk_frq);
3438c9dbc62SPeter Maydell     ptimer_transaction_commit(s->timer);
344050c2ea0SPeter Maydell }
345050c2ea0SPeter Maydell 
346050c2ea0SPeter Maydell static const VMStateDescription cmsdk_apb_watchdog_vmstate = {
347050c2ea0SPeter Maydell     .name = "cmsdk-apb-watchdog",
348050c2ea0SPeter Maydell     .version_id = 1,
349050c2ea0SPeter Maydell     .minimum_version_id = 1,
350050c2ea0SPeter Maydell     .fields = (VMStateField[]) {
351050c2ea0SPeter Maydell         VMSTATE_PTIMER(timer, CMSDKAPBWatchdog),
352050c2ea0SPeter Maydell         VMSTATE_UINT32(control, CMSDKAPBWatchdog),
353050c2ea0SPeter Maydell         VMSTATE_UINT32(intstatus, CMSDKAPBWatchdog),
354050c2ea0SPeter Maydell         VMSTATE_UINT32(lock, CMSDKAPBWatchdog),
355050c2ea0SPeter Maydell         VMSTATE_UINT32(itcr, CMSDKAPBWatchdog),
356050c2ea0SPeter Maydell         VMSTATE_UINT32(itop, CMSDKAPBWatchdog),
357050c2ea0SPeter Maydell         VMSTATE_UINT32(resetstatus, CMSDKAPBWatchdog),
358050c2ea0SPeter Maydell         VMSTATE_END_OF_LIST()
359050c2ea0SPeter Maydell     }
360050c2ea0SPeter Maydell };
361050c2ea0SPeter Maydell 
362050c2ea0SPeter Maydell static Property cmsdk_apb_watchdog_properties[] = {
363050c2ea0SPeter Maydell     DEFINE_PROP_UINT32("wdogclk-frq", CMSDKAPBWatchdog, wdogclk_frq, 0),
364050c2ea0SPeter Maydell     DEFINE_PROP_END_OF_LIST(),
365050c2ea0SPeter Maydell };
366050c2ea0SPeter Maydell 
367050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, void *data)
368050c2ea0SPeter Maydell {
369050c2ea0SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
370050c2ea0SPeter Maydell 
371050c2ea0SPeter Maydell     dc->realize = cmsdk_apb_watchdog_realize;
372050c2ea0SPeter Maydell     dc->vmsd = &cmsdk_apb_watchdog_vmstate;
373050c2ea0SPeter Maydell     dc->reset = cmsdk_apb_watchdog_reset;
374*4f67d30bSMarc-André Lureau     device_class_set_props(dc, cmsdk_apb_watchdog_properties);
375050c2ea0SPeter Maydell }
376050c2ea0SPeter Maydell 
377050c2ea0SPeter Maydell static const TypeInfo cmsdk_apb_watchdog_info = {
378050c2ea0SPeter Maydell     .name = TYPE_CMSDK_APB_WATCHDOG,
379050c2ea0SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
380050c2ea0SPeter Maydell     .instance_size = sizeof(CMSDKAPBWatchdog),
381050c2ea0SPeter Maydell     .instance_init = cmsdk_apb_watchdog_init,
382050c2ea0SPeter Maydell     .class_init = cmsdk_apb_watchdog_class_init,
383050c2ea0SPeter Maydell };
384050c2ea0SPeter Maydell 
385566528f8SMichel Heily static void luminary_watchdog_init(Object *obj)
386566528f8SMichel Heily {
387566528f8SMichel Heily     CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(obj);
388566528f8SMichel Heily 
389566528f8SMichel Heily     s->is_luminary = true;
390566528f8SMichel Heily     s->id = luminary_watchdog_id;
391566528f8SMichel Heily }
392566528f8SMichel Heily 
393566528f8SMichel Heily static const TypeInfo luminary_watchdog_info = {
394566528f8SMichel Heily     .name = TYPE_LUMINARY_WATCHDOG,
395566528f8SMichel Heily     .parent = TYPE_CMSDK_APB_WATCHDOG,
396566528f8SMichel Heily     .instance_init = luminary_watchdog_init
397566528f8SMichel Heily };
398566528f8SMichel Heily 
399050c2ea0SPeter Maydell static void cmsdk_apb_watchdog_register_types(void)
400050c2ea0SPeter Maydell {
401050c2ea0SPeter Maydell     type_register_static(&cmsdk_apb_watchdog_info);
402566528f8SMichel Heily     type_register_static(&luminary_watchdog_info);
403050c2ea0SPeter Maydell }
404050c2ea0SPeter Maydell 
405050c2ea0SPeter Maydell type_init(cmsdk_apb_watchdog_register_types);
406