1 | /* |
2 | * Copyright (c) 2018, Impinj, Inc. |
3 | * |
4 | * i.MX2 Watchdog IP block |
5 | * |
6 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> |
7 | * |
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. |
10 | */ |
11 | |
12 | #include "qemu/osdep.h" |
13 | #include "qemu/bitops.h" |
14 | #include "qemu/module.h" |
15 | #include "sysemu/watchdog.h" |
16 | |
17 | #include "hw/misc/imx2_wdt.h" |
18 | |
19 | #define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */ |
20 | #define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */ |
21 | |
22 | static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, |
23 | unsigned int size) |
24 | { |
25 | return 0; |
26 | } |
27 | |
28 | static void imx2_wdt_write(void *opaque, hwaddr addr, |
29 | uint64_t value, unsigned int size) |
30 | { |
31 | if (addr == IMX2_WDT_WCR && |
32 | (value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS))) { |
33 | watchdog_perform_action(); |
34 | } |
35 | } |
36 | |
37 | static const MemoryRegionOps imx2_wdt_ops = { |
38 | .read = imx2_wdt_read, |
39 | .write = imx2_wdt_write, |
40 | .endianness = DEVICE_NATIVE_ENDIAN, |
41 | .impl = { |
42 | /* |
43 | * Our device would not work correctly if the guest was doing |
44 | * unaligned access. This might not be a limitation on the |
45 | * real device but in practice there is no reason for a guest |
46 | * to access this device unaligned. |
47 | */ |
48 | .min_access_size = 4, |
49 | .max_access_size = 4, |
50 | .unaligned = false, |
51 | }, |
52 | }; |
53 | |
54 | static void imx2_wdt_realize(DeviceState *dev, Error **errp) |
55 | { |
56 | IMX2WdtState *s = IMX2_WDT(dev); |
57 | |
58 | memory_region_init_io(&s->mmio, OBJECT(dev), |
59 | &imx2_wdt_ops, s, |
60 | TYPE_IMX2_WDT".mmio" , |
61 | IMX2_WDT_REG_NUM * sizeof(uint16_t)); |
62 | sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); |
63 | } |
64 | |
65 | static void imx2_wdt_class_init(ObjectClass *klass, void *data) |
66 | { |
67 | DeviceClass *dc = DEVICE_CLASS(klass); |
68 | |
69 | dc->realize = imx2_wdt_realize; |
70 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); |
71 | } |
72 | |
73 | static const TypeInfo imx2_wdt_info = { |
74 | .name = TYPE_IMX2_WDT, |
75 | .parent = TYPE_SYS_BUS_DEVICE, |
76 | .instance_size = sizeof(IMX2WdtState), |
77 | .class_init = imx2_wdt_class_init, |
78 | }; |
79 | |
80 | static WatchdogTimerModel model = { |
81 | .wdt_name = "imx2-watchdog" , |
82 | .wdt_description = "i.MX2 Watchdog" , |
83 | }; |
84 | |
85 | static void imx2_wdt_register_type(void) |
86 | { |
87 | watchdog_add_model(&model); |
88 | type_register_static(&imx2_wdt_info); |
89 | } |
90 | type_init(imx2_wdt_register_type) |
91 | |