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
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"
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
= {
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
),
47 typedef enum WdtRefreshType
{
52 static uint64_t sbsa_gwdt_rread(void *opaque
, hwaddr addr
, unsigned int size
)
54 SBSA_GWDTState
*s
= SBSA_GWDT(opaque
);
59 /* watch refresh read has no effect and returns 0 */
62 case SBSA_GWDT_W_IIDR
:
66 qemu_log_mask(LOG_GUEST_ERROR
, "bad address in refresh frame read :"
67 " 0x%x\n", (int)addr
);
72 static uint64_t sbsa_gwdt_read(void *opaque
, hwaddr addr
, unsigned int size
)
74 SBSA_GWDTState
*s
= SBSA_GWDT(opaque
);
93 case SBSA_GWDT_W_IIDR
:
97 qemu_log_mask(LOG_GUEST_ERROR
, "bad address in control frame read :"
98 " 0x%x\n", (int)addr
);
103 static void sbsa_gwdt_update_timer(SBSA_GWDTState
*s
, WdtRefreshType rtype
)
105 uint64_t timeout
= 0;
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
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;
126 timer_mod(s
->timer
, timeout
);
130 static void sbsa_gwdt_rwrite(void *opaque
, hwaddr offset
, uint64_t data
,
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
);
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
,
146 SBSA_GWDTState
*s
= SBSA_GWDT(opaque
);
150 s
->wcs
= data
& SBSA_GWDT_WCS_EN
;
151 qemu_set_irq(s
->irq
, 0);
152 sbsa_gwdt_update_timer(s
, EXPLICIT_REFRESH
);
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
);
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
);
178 qemu_log_mask(LOG_GUEST_ERROR
, "bad address in control frame write :"
179 " 0x%x\n", (int)offset
);
184 static void wdt_sbsa_gwdt_reset(DeviceState
*dev
)
186 SBSA_GWDTState
*s
= SBSA_GWDT(dev
);
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);
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
:
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
),
253 SBSA_GWDT_RMMIO_SIZE
);
255 memory_region_init_io(&s
->cmmio
, OBJECT(dev
),
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
,
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
)