1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include "qemu/osdep.h"
30#include "hw/sysbus.h"
31#include "hw/ptimer.h"
32#include "qemu/main-loop.h"
33#include "qemu/module.h"
34#include "qemu/log.h"
35
36#include "hw/timer/digic-timer.h"
37
38static const VMStateDescription vmstate_digic_timer = {
39 .name = "digic.timer",
40 .version_id = 1,
41 .minimum_version_id = 1,
42 .fields = (VMStateField[]) {
43 VMSTATE_PTIMER(ptimer, DigicTimerState),
44 VMSTATE_UINT32(control, DigicTimerState),
45 VMSTATE_UINT32(relvalue, DigicTimerState),
46 VMSTATE_END_OF_LIST()
47 }
48};
49
50static void digic_timer_reset(DeviceState *dev)
51{
52 DigicTimerState *s = DIGIC_TIMER(dev);
53
54 ptimer_stop(s->ptimer);
55 s->control = 0;
56 s->relvalue = 0;
57}
58
59static uint64_t digic_timer_read(void *opaque, hwaddr offset, unsigned size)
60{
61 DigicTimerState *s = opaque;
62 uint64_t ret = 0;
63
64 switch (offset) {
65 case DIGIC_TIMER_CONTROL:
66 ret = s->control;
67 break;
68 case DIGIC_TIMER_RELVALUE:
69 ret = s->relvalue;
70 break;
71 case DIGIC_TIMER_VALUE:
72 ret = ptimer_get_count(s->ptimer) & 0xffff;
73 break;
74 default:
75 qemu_log_mask(LOG_UNIMP,
76 "digic-timer: read access to unknown register 0x"
77 TARGET_FMT_plx "\n", offset);
78 }
79
80 return ret;
81}
82
83static void digic_timer_write(void *opaque, hwaddr offset,
84 uint64_t value, unsigned size)
85{
86 DigicTimerState *s = opaque;
87
88 switch (offset) {
89 case DIGIC_TIMER_CONTROL:
90 if (value & DIGIC_TIMER_CONTROL_RST) {
91 digic_timer_reset((DeviceState *)s);
92 break;
93 }
94
95 if (value & DIGIC_TIMER_CONTROL_EN) {
96 ptimer_run(s->ptimer, 0);
97 }
98
99 s->control = (uint32_t)value;
100 break;
101
102 case DIGIC_TIMER_RELVALUE:
103 s->relvalue = extract32(value, 0, 16);
104 ptimer_set_limit(s->ptimer, s->relvalue, 1);
105 break;
106
107 case DIGIC_TIMER_VALUE:
108 break;
109
110 default:
111 qemu_log_mask(LOG_UNIMP,
112 "digic-timer: read access to unknown register 0x"
113 TARGET_FMT_plx "\n", offset);
114 }
115}
116
117static const MemoryRegionOps digic_timer_ops = {
118 .read = digic_timer_read,
119 .write = digic_timer_write,
120 .impl = {
121 .min_access_size = 4,
122 .max_access_size = 4,
123 },
124 .endianness = DEVICE_NATIVE_ENDIAN,
125};
126
127static void digic_timer_init(Object *obj)
128{
129 DigicTimerState *s = DIGIC_TIMER(obj);
130
131 s->ptimer = ptimer_init(NULL, PTIMER_POLICY_DEFAULT);
132
133
134
135
136
137 ptimer_set_freq(s->ptimer, 1 * 1000 * 1000);
138
139 memory_region_init_io(&s->iomem, OBJECT(s), &digic_timer_ops, s,
140 TYPE_DIGIC_TIMER, 0x100);
141 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
142}
143
144static void digic_timer_class_init(ObjectClass *klass, void *class_data)
145{
146 DeviceClass *dc = DEVICE_CLASS(klass);
147
148 dc->reset = digic_timer_reset;
149 dc->vmsd = &vmstate_digic_timer;
150}
151
152static const TypeInfo digic_timer_info = {
153 .name = TYPE_DIGIC_TIMER,
154 .parent = TYPE_SYS_BUS_DEVICE,
155 .instance_size = sizeof(DigicTimerState),
156 .instance_init = digic_timer_init,
157 .class_init = digic_timer_class_init,
158};
159
160static void digic_timer_register_type(void)
161{
162 type_register_static(&digic_timer_info);
163}
164
165type_init(digic_timer_register_type)
166