2 * Copyright (c) 2018, Impinj, Inc.
4 * i.MX2 Watchdog IP block
6 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
12 #include "qemu/osdep.h"
13 #include "qemu/bitops.h"
14 #include "qemu/module.h"
15 #include "sysemu/watchdog.h"
16 #include "migration/vmstate.h"
17 #include "hw/qdev-properties.h"
19 #include "hw/watchdog/wdt_imx2.h"
21 static void imx2_wdt_interrupt(void *opaque
)
23 IMX2WdtState
*s
= IMX2_WDT(opaque
);
25 s
->wicr
|= IMX2_WDT_WICR_WTIS
;
26 qemu_set_irq(s
->irq
, 1);
29 static void imx2_wdt_expired(void *opaque
)
31 IMX2WdtState
*s
= IMX2_WDT(opaque
);
33 s
->wrsr
= IMX2_WDT_WRSR_TOUT
;
35 /* Perform watchdog action if watchdog is enabled */
36 if (s
->wcr
& IMX2_WDT_WCR_WDE
) {
37 s
->wrsr
= IMX2_WDT_WRSR_TOUT
;
38 watchdog_perform_action();
42 static void imx2_wdt_reset(DeviceState
*dev
)
44 IMX2WdtState
*s
= IMX2_WDT(dev
);
46 ptimer_transaction_begin(s
->timer
);
47 ptimer_stop(s
->timer
);
48 ptimer_transaction_commit(s
->timer
);
50 if (s
->pretimeout_support
) {
51 ptimer_transaction_begin(s
->itimer
);
52 ptimer_stop(s
->itimer
);
53 ptimer_transaction_commit(s
->itimer
);
56 s
->wicr_locked
= false;
57 s
->wcr_locked
= false;
58 s
->wcr_wde_locked
= false;
60 s
->wcr
= IMX2_WDT_WCR_WDA
| IMX2_WDT_WCR_SRS
;
62 s
->wrsr
&= ~(IMX2_WDT_WRSR_TOUT
| IMX2_WDT_WRSR_SFTW
);
63 s
->wicr
= IMX2_WDT_WICR_WICT_DEF
;
64 s
->wmcr
= IMX2_WDT_WMCR_PDE
;
67 static uint64_t imx2_wdt_read(void *opaque
, hwaddr addr
, unsigned int size
)
69 IMX2WdtState
*s
= IMX2_WDT(opaque
);
86 static void imx_wdt2_update_itimer(IMX2WdtState
*s
, bool start
)
88 bool running
= (s
->wcr
& IMX2_WDT_WCR_WDE
) && (s
->wcr
& IMX2_WDT_WCR_WT
);
89 bool enabled
= s
->wicr
& IMX2_WDT_WICR_WIE
;
91 ptimer_transaction_begin(s
->itimer
);
92 if (start
|| !enabled
) {
93 ptimer_stop(s
->itimer
);
95 if (running
&& enabled
) {
96 int count
= ptimer_get_count(s
->timer
);
97 int pretimeout
= s
->wicr
& IMX2_WDT_WICR_WICT
;
100 * Only (re-)start pretimeout timer if its counter value is larger
101 * than 0. Otherwise it will fire right away and we'll get an
104 if (count
> pretimeout
) {
105 ptimer_set_count(s
->itimer
, count
- pretimeout
);
107 ptimer_run(s
->itimer
, 1);
111 ptimer_transaction_commit(s
->itimer
);
114 static void imx_wdt2_update_timer(IMX2WdtState
*s
, bool start
)
116 ptimer_transaction_begin(s
->timer
);
118 ptimer_stop(s
->timer
);
120 if ((s
->wcr
& IMX2_WDT_WCR_WDE
) && (s
->wcr
& IMX2_WDT_WCR_WT
)) {
121 int count
= (s
->wcr
& IMX2_WDT_WCR_WT
) >> 8;
123 /* A value of 0 reflects one period (0.5s). */
124 ptimer_set_count(s
->timer
, count
+ 1);
126 ptimer_run(s
->timer
, 1);
129 ptimer_transaction_commit(s
->timer
);
130 if (s
->pretimeout_support
) {
131 imx_wdt2_update_itimer(s
, start
);
135 static void imx2_wdt_write(void *opaque
, hwaddr addr
,
136 uint64_t value
, unsigned int size
)
138 IMX2WdtState
*s
= IMX2_WDT(opaque
);
143 value
&= ~IMX2_WDT_WCR_LOCK_MASK
;
144 value
|= (s
->wicr
& IMX2_WDT_WCR_LOCK_MASK
);
146 s
->wcr_locked
= true;
147 if (s
->wcr_wde_locked
) {
148 value
&= ~IMX2_WDT_WCR_WDE
;
149 value
|= (s
->wicr
& ~IMX2_WDT_WCR_WDE
);
150 } else if (value
& IMX2_WDT_WCR_WDE
) {
151 s
->wcr_wde_locked
= true;
153 if (s
->wcr_wdt_locked
) {
154 value
&= ~IMX2_WDT_WCR_WDT
;
155 value
|= (s
->wicr
& ~IMX2_WDT_WCR_WDT
);
156 } else if (value
& IMX2_WDT_WCR_WDT
) {
157 s
->wcr_wdt_locked
= true;
161 if (!(value
& IMX2_WDT_WCR_SRS
)) {
162 s
->wrsr
= IMX2_WDT_WRSR_SFTW
;
164 if (!(value
& (IMX2_WDT_WCR_WDA
| IMX2_WDT_WCR_SRS
)) ||
165 (!(value
& IMX2_WDT_WCR_WT
) && (value
& IMX2_WDT_WCR_WDE
))) {
166 watchdog_perform_action();
168 s
->wcr
|= IMX2_WDT_WCR_SRS
;
169 imx_wdt2_update_timer(s
, true);
172 if (s
->wsr
== IMX2_WDT_SEQ1
&& value
== IMX2_WDT_SEQ2
) {
173 imx_wdt2_update_timer(s
, false);
180 if (!s
->pretimeout_support
) {
183 value
&= IMX2_WDT_WICR_LOCK_MASK
| IMX2_WDT_WICR_WTIS
;
184 if (s
->wicr_locked
) {
185 value
&= IMX2_WDT_WICR_WTIS
;
186 value
|= (s
->wicr
& IMX2_WDT_WICR_LOCK_MASK
);
188 s
->wicr
= value
| (s
->wicr
& IMX2_WDT_WICR_WTIS
);
189 if (value
& IMX2_WDT_WICR_WTIS
) {
190 s
->wicr
&= ~IMX2_WDT_WICR_WTIS
;
191 qemu_set_irq(s
->irq
, 0);
193 imx_wdt2_update_itimer(s
, true);
194 s
->wicr_locked
= true;
197 s
->wmcr
= value
& IMX2_WDT_WMCR_PDE
;
202 static const MemoryRegionOps imx2_wdt_ops
= {
203 .read
= imx2_wdt_read
,
204 .write
= imx2_wdt_write
,
205 .endianness
= DEVICE_NATIVE_ENDIAN
,
208 * Our device would not work correctly if the guest was doing
209 * unaligned access. This might not be a limitation on the
210 * real device but in practice there is no reason for a guest
211 * to access this device unaligned.
213 .min_access_size
= 2,
214 .max_access_size
= 2,
219 static const VMStateDescription vmstate_imx2_wdt
= {
221 .fields
= (VMStateField
[]) {
222 VMSTATE_PTIMER(timer
, IMX2WdtState
),
223 VMSTATE_PTIMER(itimer
, IMX2WdtState
),
224 VMSTATE_BOOL(wicr_locked
, IMX2WdtState
),
225 VMSTATE_BOOL(wcr_locked
, IMX2WdtState
),
226 VMSTATE_BOOL(wcr_wde_locked
, IMX2WdtState
),
227 VMSTATE_BOOL(wcr_wdt_locked
, IMX2WdtState
),
228 VMSTATE_UINT16(wcr
, IMX2WdtState
),
229 VMSTATE_UINT16(wsr
, IMX2WdtState
),
230 VMSTATE_UINT16(wrsr
, IMX2WdtState
),
231 VMSTATE_UINT16(wmcr
, IMX2WdtState
),
232 VMSTATE_UINT16(wicr
, IMX2WdtState
),
233 VMSTATE_END_OF_LIST()
237 static void imx2_wdt_realize(DeviceState
*dev
, Error
**errp
)
239 IMX2WdtState
*s
= IMX2_WDT(dev
);
240 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
242 memory_region_init_io(&s
->mmio
, OBJECT(dev
),
246 sysbus_init_mmio(sbd
, &s
->mmio
);
247 sysbus_init_irq(sbd
, &s
->irq
);
249 s
->timer
= ptimer_init(imx2_wdt_expired
, s
,
250 PTIMER_POLICY_NO_IMMEDIATE_TRIGGER
|
251 PTIMER_POLICY_NO_IMMEDIATE_RELOAD
|
252 PTIMER_POLICY_NO_COUNTER_ROUND_DOWN
);
253 ptimer_transaction_begin(s
->timer
);
254 ptimer_set_freq(s
->timer
, 2);
255 ptimer_set_limit(s
->timer
, 0xff, 1);
256 ptimer_transaction_commit(s
->timer
);
257 if (s
->pretimeout_support
) {
258 s
->itimer
= ptimer_init(imx2_wdt_interrupt
, s
,
259 PTIMER_POLICY_NO_IMMEDIATE_TRIGGER
|
260 PTIMER_POLICY_NO_IMMEDIATE_RELOAD
|
261 PTIMER_POLICY_NO_COUNTER_ROUND_DOWN
);
262 ptimer_transaction_begin(s
->itimer
);
263 ptimer_set_freq(s
->itimer
, 2);
264 ptimer_set_limit(s
->itimer
, 0xff, 1);
265 ptimer_transaction_commit(s
->itimer
);
269 static Property imx2_wdt_properties
[] = {
270 DEFINE_PROP_BOOL("pretimeout-support", IMX2WdtState
, pretimeout_support
,
272 DEFINE_PROP_END_OF_LIST()
275 static void imx2_wdt_class_init(ObjectClass
*klass
, void *data
)
277 DeviceClass
*dc
= DEVICE_CLASS(klass
);
279 device_class_set_props(dc
, imx2_wdt_properties
);
280 dc
->realize
= imx2_wdt_realize
;
281 dc
->reset
= imx2_wdt_reset
;
282 dc
->vmsd
= &vmstate_imx2_wdt
;
283 dc
->desc
= "i.MX2 watchdog timer";
284 set_bit(DEVICE_CATEGORY_WATCHDOG
, dc
->categories
);
287 static const TypeInfo imx2_wdt_info
= {
288 .name
= TYPE_IMX2_WDT
,
289 .parent
= TYPE_SYS_BUS_DEVICE
,
290 .instance_size
= sizeof(IMX2WdtState
),
291 .class_init
= imx2_wdt_class_init
,
294 static void imx2_wdt_register_type(void)
296 type_register_static(&imx2_wdt_info
);
298 type_init(imx2_wdt_register_type
)