hw/isa/Kconfig: Add missing dependency VIA VT82C686 -> APM
[qemu/ar7.git] / hw / watchdog / sbsa_gwdt.c
blobd0998f8489cb665a4d3da98abb3085455fa1e44c
1 /*
2 * Generic watchdog device model for SBSA
4 * The watchdog device has been implemented as revision 1 variant of
5 * the ARM SBSA specification v6.0
6 * (https://developer.arm.com/documentation/den0029/d?lang=en)
8 * Copyright Linaro.org 2020
10 * Authors:
11 * Shashi Mallela <shashi.mallela@linaro.org>
13 * This work is licensed under the terms of the GNU GPL, version 2 or (at your
14 * option) any later version. See the COPYING file in the top-level directory.
18 #include "qemu/osdep.h"
19 #include "sysemu/reset.h"
20 #include "sysemu/watchdog.h"
21 #include "hw/watchdog/sbsa_gwdt.h"
22 #include "qemu/timer.h"
23 #include "migration/vmstate.h"
24 #include "qemu/log.h"
25 #include "qemu/module.h"
27 static WatchdogTimerModel model = {
28 .wdt_name = TYPE_WDT_SBSA,
29 .wdt_description = "SBSA-compliant generic watchdog device",
32 static const VMStateDescription vmstate_sbsa_gwdt = {
33 .name = "sbsa-gwdt",
34 .version_id = 1,
35 .minimum_version_id = 1,
36 .fields = (VMStateField[]) {
37 VMSTATE_TIMER_PTR(timer, SBSA_GWDTState),
38 VMSTATE_UINT32(wcs, SBSA_GWDTState),
39 VMSTATE_UINT32(worl, SBSA_GWDTState),
40 VMSTATE_UINT32(woru, SBSA_GWDTState),
41 VMSTATE_UINT32(wcvl, SBSA_GWDTState),
42 VMSTATE_UINT32(wcvu, SBSA_GWDTState),
43 VMSTATE_END_OF_LIST()
47 typedef enum WdtRefreshType {
48 EXPLICIT_REFRESH = 0,
49 TIMEOUT_REFRESH = 1,
50 } WdtRefreshType;
52 static uint64_t sbsa_gwdt_rread(void *opaque, hwaddr addr, unsigned int size)
54 SBSA_GWDTState *s = SBSA_GWDT(opaque);
55 uint32_t ret = 0;
57 switch (addr) {
58 case SBSA_GWDT_WRR:
59 /* watch refresh read has no effect and returns 0 */
60 ret = 0;
61 break;
62 case SBSA_GWDT_W_IIDR:
63 ret = s->id;
64 break;
65 default:
66 qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame read :"
67 " 0x%x\n", (int)addr);
69 return ret;
72 static uint64_t sbsa_gwdt_read(void *opaque, hwaddr addr, unsigned int size)
74 SBSA_GWDTState *s = SBSA_GWDT(opaque);
75 uint32_t ret = 0;
77 switch (addr) {
78 case SBSA_GWDT_WCS:
79 ret = s->wcs;
80 break;
81 case SBSA_GWDT_WOR:
82 ret = s->worl;
83 break;
84 case SBSA_GWDT_WORU:
85 ret = s->woru;
86 break;
87 case SBSA_GWDT_WCV:
88 ret = s->wcvl;
89 break;
90 case SBSA_GWDT_WCVU:
91 ret = s->wcvu;
92 break;
93 case SBSA_GWDT_W_IIDR:
94 ret = s->id;
95 break;
96 default:
97 qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame read :"
98 " 0x%x\n", (int)addr);
100 return ret;
103 static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype)
105 uint64_t timeout = 0;
107 timer_del(s->timer);
109 if (s->wcs & SBSA_GWDT_WCS_EN) {
111 * Extract the upper 16 bits from woru & 32 bits from worl
112 * registers to construct the 48 bit offset value
114 timeout = s->woru;
115 timeout <<= 32;
116 timeout |= s->worl;
117 timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, SBSA_TIMER_FREQ);
118 timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
120 if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) &&
121 (!(s->wcs & SBSA_GWDT_WCS_WS0)))) {
122 /* store the current timeout value into compare registers */
123 s->wcvu = timeout >> 32;
124 s->wcvl = timeout;
126 timer_mod(s->timer, timeout);
130 static void sbsa_gwdt_rwrite(void *opaque, hwaddr offset, uint64_t data,
131 unsigned size) {
132 SBSA_GWDTState *s = SBSA_GWDT(opaque);
134 if (offset == SBSA_GWDT_WRR) {
135 s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
137 sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
138 } else {
139 qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame write :"
140 " 0x%x\n", (int)offset);
144 static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data,
145 unsigned size) {
146 SBSA_GWDTState *s = SBSA_GWDT(opaque);
148 switch (offset) {
149 case SBSA_GWDT_WCS:
150 s->wcs = data & SBSA_GWDT_WCS_EN;
151 qemu_set_irq(s->irq, 0);
152 sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
153 break;
155 case SBSA_GWDT_WOR:
156 s->worl = data;
157 s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
158 qemu_set_irq(s->irq, 0);
159 sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
160 break;
162 case SBSA_GWDT_WORU:
163 s->woru = data & SBSA_GWDT_WOR_MASK;
164 s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
165 qemu_set_irq(s->irq, 0);
166 sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
167 break;
169 case SBSA_GWDT_WCV:
170 s->wcvl = data;
171 break;
173 case SBSA_GWDT_WCVU:
174 s->wcvu = data;
175 break;
177 default:
178 qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame write :"
179 " 0x%x\n", (int)offset);
181 return;
184 static void wdt_sbsa_gwdt_reset(DeviceState *dev)
186 SBSA_GWDTState *s = SBSA_GWDT(dev);
188 timer_del(s->timer);
190 s->wcs = 0;
191 s->wcvl = 0;
192 s->wcvu = 0;
193 s->worl = 0;
194 s->woru = 0;
195 s->id = SBSA_GWDT_ID;
198 static void sbsa_gwdt_timer_sysinterrupt(void *opaque)
200 SBSA_GWDTState *s = SBSA_GWDT(opaque);
202 if (!(s->wcs & SBSA_GWDT_WCS_WS0)) {
203 s->wcs |= SBSA_GWDT_WCS_WS0;
204 sbsa_gwdt_update_timer(s, TIMEOUT_REFRESH);
205 qemu_set_irq(s->irq, 1);
206 } else {
207 s->wcs |= SBSA_GWDT_WCS_WS1;
208 qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
210 * Reset the watchdog only if the guest gets notified about
211 * expiry. watchdog_perform_action() may temporarily relinquish
212 * the BQL; reset before triggering the action to avoid races with
213 * sbsa_gwdt instructions.
215 switch (get_watchdog_action()) {
216 case WATCHDOG_ACTION_DEBUG:
217 case WATCHDOG_ACTION_NONE:
218 case WATCHDOG_ACTION_PAUSE:
219 break;
220 default:
221 wdt_sbsa_gwdt_reset(DEVICE(s));
223 watchdog_perform_action();
227 static const MemoryRegionOps sbsa_gwdt_rops = {
228 .read = sbsa_gwdt_rread,
229 .write = sbsa_gwdt_rwrite,
230 .endianness = DEVICE_LITTLE_ENDIAN,
231 .valid.min_access_size = 4,
232 .valid.max_access_size = 4,
233 .valid.unaligned = false,
236 static const MemoryRegionOps sbsa_gwdt_ops = {
237 .read = sbsa_gwdt_read,
238 .write = sbsa_gwdt_write,
239 .endianness = DEVICE_LITTLE_ENDIAN,
240 .valid.min_access_size = 4,
241 .valid.max_access_size = 4,
242 .valid.unaligned = false,
245 static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
247 SBSA_GWDTState *s = SBSA_GWDT(dev);
248 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
250 memory_region_init_io(&s->rmmio, OBJECT(dev),
251 &sbsa_gwdt_rops, s,
252 "sbsa_gwdt.refresh",
253 SBSA_GWDT_RMMIO_SIZE);
255 memory_region_init_io(&s->cmmio, OBJECT(dev),
256 &sbsa_gwdt_ops, s,
257 "sbsa_gwdt.control",
258 SBSA_GWDT_CMMIO_SIZE);
260 sysbus_init_mmio(sbd, &s->rmmio);
261 sysbus_init_mmio(sbd, &s->cmmio);
263 sysbus_init_irq(sbd, &s->irq);
265 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sbsa_gwdt_timer_sysinterrupt,
266 dev);
269 static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data)
271 DeviceClass *dc = DEVICE_CLASS(klass);
273 dc->realize = wdt_sbsa_gwdt_realize;
274 dc->reset = wdt_sbsa_gwdt_reset;
275 dc->hotpluggable = false;
276 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
277 dc->vmsd = &vmstate_sbsa_gwdt;
280 static const TypeInfo wdt_sbsa_gwdt_info = {
281 .class_init = wdt_sbsa_gwdt_class_init,
282 .parent = TYPE_SYS_BUS_DEVICE,
283 .name = TYPE_WDT_SBSA,
284 .instance_size = sizeof(SBSA_GWDTState),
287 static void wdt_sbsa_gwdt_register_types(void)
289 watchdog_add_model(&model);
290 type_register_static(&wdt_sbsa_gwdt_info);
293 type_init(wdt_sbsa_gwdt_register_types)