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/qdev-properties.h"
22 #include "hw/watchdog/sbsa_gwdt.h"
23 #include "qemu/timer.h"
24 #include "migration/vmstate.h"
26 #include "qemu/module.h"
28 static const VMStateDescription vmstate_sbsa_gwdt
= {
31 .minimum_version_id
= 1,
32 .fields
= (const VMStateField
[]) {
33 VMSTATE_TIMER_PTR(timer
, SBSA_GWDTState
),
34 VMSTATE_UINT32(wcs
, SBSA_GWDTState
),
35 VMSTATE_UINT32(worl
, SBSA_GWDTState
),
36 VMSTATE_UINT32(woru
, SBSA_GWDTState
),
37 VMSTATE_UINT32(wcvl
, SBSA_GWDTState
),
38 VMSTATE_UINT32(wcvu
, SBSA_GWDTState
),
43 typedef enum WdtRefreshType
{
48 static uint64_t sbsa_gwdt_rread(void *opaque
, hwaddr addr
, unsigned int size
)
50 SBSA_GWDTState
*s
= SBSA_GWDT(opaque
);
55 /* watch refresh read has no effect and returns 0 */
58 case SBSA_GWDT_W_IIDR
:
62 qemu_log_mask(LOG_GUEST_ERROR
, "bad address in refresh frame read :"
63 " 0x%x\n", (int)addr
);
68 static uint64_t sbsa_gwdt_read(void *opaque
, hwaddr addr
, unsigned int size
)
70 SBSA_GWDTState
*s
= SBSA_GWDT(opaque
);
89 case SBSA_GWDT_W_IIDR
:
93 qemu_log_mask(LOG_GUEST_ERROR
, "bad address in control frame read :"
94 " 0x%x\n", (int)addr
);
99 static void sbsa_gwdt_update_timer(SBSA_GWDTState
*s
, WdtRefreshType rtype
)
101 uint64_t timeout
= 0;
105 if (s
->wcs
& SBSA_GWDT_WCS_EN
) {
107 * Extract the upper 16 bits from woru & 32 bits from worl
108 * registers to construct the 48 bit offset value
113 timeout
= muldiv64(timeout
, NANOSECONDS_PER_SECOND
, s
->freq
);
114 timeout
+= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
116 if ((rtype
== EXPLICIT_REFRESH
) || ((rtype
== TIMEOUT_REFRESH
) &&
117 (!(s
->wcs
& SBSA_GWDT_WCS_WS0
)))) {
118 /* store the current timeout value into compare registers */
119 s
->wcvu
= timeout
>> 32;
122 timer_mod(s
->timer
, timeout
);
126 static void sbsa_gwdt_rwrite(void *opaque
, hwaddr offset
, uint64_t data
,
128 SBSA_GWDTState
*s
= SBSA_GWDT(opaque
);
130 if (offset
== SBSA_GWDT_WRR
) {
131 s
->wcs
&= ~(SBSA_GWDT_WCS_WS0
| SBSA_GWDT_WCS_WS1
);
133 sbsa_gwdt_update_timer(s
, EXPLICIT_REFRESH
);
135 qemu_log_mask(LOG_GUEST_ERROR
, "bad address in refresh frame write :"
136 " 0x%x\n", (int)offset
);
140 static void sbsa_gwdt_write(void *opaque
, hwaddr offset
, uint64_t data
,
142 SBSA_GWDTState
*s
= SBSA_GWDT(opaque
);
146 s
->wcs
= data
& SBSA_GWDT_WCS_EN
;
147 qemu_set_irq(s
->irq
, 0);
148 sbsa_gwdt_update_timer(s
, EXPLICIT_REFRESH
);
153 s
->wcs
&= ~(SBSA_GWDT_WCS_WS0
| SBSA_GWDT_WCS_WS1
);
154 qemu_set_irq(s
->irq
, 0);
155 sbsa_gwdt_update_timer(s
, EXPLICIT_REFRESH
);
159 s
->woru
= data
& SBSA_GWDT_WOR_MASK
;
160 s
->wcs
&= ~(SBSA_GWDT_WCS_WS0
| SBSA_GWDT_WCS_WS1
);
161 qemu_set_irq(s
->irq
, 0);
162 sbsa_gwdt_update_timer(s
, EXPLICIT_REFRESH
);
174 qemu_log_mask(LOG_GUEST_ERROR
, "bad address in control frame write :"
175 " 0x%x\n", (int)offset
);
180 static void wdt_sbsa_gwdt_reset(DeviceState
*dev
)
182 SBSA_GWDTState
*s
= SBSA_GWDT(dev
);
191 s
->id
= SBSA_GWDT_ID
;
194 static void sbsa_gwdt_timer_sysinterrupt(void *opaque
)
196 SBSA_GWDTState
*s
= SBSA_GWDT(opaque
);
198 if (!(s
->wcs
& SBSA_GWDT_WCS_WS0
)) {
199 s
->wcs
|= SBSA_GWDT_WCS_WS0
;
200 sbsa_gwdt_update_timer(s
, TIMEOUT_REFRESH
);
201 qemu_set_irq(s
->irq
, 1);
203 s
->wcs
|= SBSA_GWDT_WCS_WS1
;
204 qemu_log_mask(CPU_LOG_RESET
, "Watchdog timer expired.\n");
206 * Reset the watchdog only if the guest gets notified about
207 * expiry. watchdog_perform_action() may temporarily relinquish
208 * the BQL; reset before triggering the action to avoid races with
209 * sbsa_gwdt instructions.
211 switch (get_watchdog_action()) {
212 case WATCHDOG_ACTION_DEBUG
:
213 case WATCHDOG_ACTION_NONE
:
214 case WATCHDOG_ACTION_PAUSE
:
217 wdt_sbsa_gwdt_reset(DEVICE(s
));
219 watchdog_perform_action();
223 static const MemoryRegionOps sbsa_gwdt_rops
= {
224 .read
= sbsa_gwdt_rread
,
225 .write
= sbsa_gwdt_rwrite
,
226 .endianness
= DEVICE_LITTLE_ENDIAN
,
227 .valid
.min_access_size
= 4,
228 .valid
.max_access_size
= 4,
229 .valid
.unaligned
= false,
232 static const MemoryRegionOps sbsa_gwdt_ops
= {
233 .read
= sbsa_gwdt_read
,
234 .write
= sbsa_gwdt_write
,
235 .endianness
= DEVICE_LITTLE_ENDIAN
,
236 .valid
.min_access_size
= 4,
237 .valid
.max_access_size
= 4,
238 .valid
.unaligned
= false,
241 static void wdt_sbsa_gwdt_realize(DeviceState
*dev
, Error
**errp
)
243 SBSA_GWDTState
*s
= SBSA_GWDT(dev
);
244 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
246 memory_region_init_io(&s
->rmmio
, OBJECT(dev
),
249 SBSA_GWDT_RMMIO_SIZE
);
251 memory_region_init_io(&s
->cmmio
, OBJECT(dev
),
254 SBSA_GWDT_CMMIO_SIZE
);
256 sysbus_init_mmio(sbd
, &s
->rmmio
);
257 sysbus_init_mmio(sbd
, &s
->cmmio
);
259 sysbus_init_irq(sbd
, &s
->irq
);
261 s
->timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, sbsa_gwdt_timer_sysinterrupt
,
265 static Property wdt_sbsa_gwdt_props
[] = {
267 * Timer frequency in Hz. This must match the frequency used by
268 * the CPU's generic timer. Default 62.5Hz matches QEMU's legacy
269 * CPU timer frequency default.
271 DEFINE_PROP_UINT64("clock-frequency", struct SBSA_GWDTState
, freq
,
273 DEFINE_PROP_END_OF_LIST(),
276 static void wdt_sbsa_gwdt_class_init(ObjectClass
*klass
, void *data
)
278 DeviceClass
*dc
= DEVICE_CLASS(klass
);
280 dc
->realize
= wdt_sbsa_gwdt_realize
;
281 device_class_set_legacy_reset(dc
, wdt_sbsa_gwdt_reset
);
282 dc
->hotpluggable
= false;
283 set_bit(DEVICE_CATEGORY_WATCHDOG
, dc
->categories
);
284 dc
->vmsd
= &vmstate_sbsa_gwdt
;
285 dc
->desc
= "SBSA-compliant generic watchdog device";
286 device_class_set_props(dc
, wdt_sbsa_gwdt_props
);
289 static const TypeInfo wdt_sbsa_gwdt_info
= {
290 .class_init
= wdt_sbsa_gwdt_class_init
,
291 .parent
= TYPE_SYS_BUS_DEVICE
,
292 .name
= TYPE_WDT_SBSA
,
293 .instance_size
= sizeof(SBSA_GWDTState
),
296 static void wdt_sbsa_gwdt_register_types(void)
298 type_register_static(&wdt_sbsa_gwdt_info
);
301 type_init(wdt_sbsa_gwdt_register_types
)