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#include "qemu/osdep.h"
27#include "hw/sysbus.h"
28#include "hw/ptimer.h"
29#include "hw/register.h"
30#include "qemu/log.h"
31#include "qemu/main-loop.h"
32#include "qapi/error.h"
33#include "hw/fdt_generic_util.h"
34
35#ifndef XILINX_IO_MODULE_PIT_ERR_DEBUG
36#define XILINX_IO_MODULE_PIT_ERR_DEBUG 0
37#endif
38
39#define TYPE_XILINX_IO_MODULE_PIT "xlnx.io_pit"
40
41#define XILINX_IO_MODULE_PIT(obj) \
42 OBJECT_CHECK(XilinxPIT, (obj), TYPE_XILINX_IO_MODULE_PIT)
43
44
45#define R_IOM_PIT_PRELOAD (0x00 / 4)
46#define R_IOM_PIT_COUNTER (0x04 / 4)
47#define R_IOM_PIT_CONTROL (0x08 / 4)
48#define IOM_PIT_CONTROL_EN (1 << 0)
49#define IOM_PIT_CONTROL_PRELOAD (1 << 1)
50#define R_MAX (R_IOM_PIT_CONTROL + 1)
51
52typedef struct XilinxPIT {
53 SysBusDevice parent_obj;
54 MemoryRegion iomem;
55 qemu_irq irq;
56
57 struct {
58 bool use;
59 uint32_t size;
60 bool readable;
61 bool interrupt;
62 } cfg;
63 uint32_t frequency;
64
65 uint32_t ps_counter;
66
67 bool ps_enable;
68
69 qemu_irq hit_out;
70
71 bool ps_level;
72
73 QEMUBH *bh;
74 ptimer_state *ptimer;
75 uint32_t regs[R_MAX];
76 RegisterInfo regs_info[R_MAX];
77 const char *prefix;
78} XilinxPIT;
79
80static Property xlx_iom_properties[] = {
81 DEFINE_PROP_UINT32("frequency", XilinxPIT, frequency, 66*1000000),
82 DEFINE_PROP_BOOL("use-pit", XilinxPIT, cfg.use, 0),
83 DEFINE_PROP_UINT32("pit-size", XilinxPIT, cfg.size, 1),
84 DEFINE_PROP_BOOL("pit-readable", XilinxPIT, cfg.readable, 1),
85 DEFINE_PROP_BOOL("pit-interrupt", XilinxPIT, cfg.interrupt, 0),
86 DEFINE_PROP_END_OF_LIST(),
87};
88
89static uint64_t pit_ctr_pr(RegisterInfo *reg, uint64_t val)
90{
91 XilinxPIT *s = XILINX_IO_MODULE_PIT(reg->opaque);
92 uint32_t r;
93
94 if (!s->cfg.use) {
95 qemu_log_mask(LOG_GUEST_ERROR, "%s: Disabled\n", s->prefix);
96 return 0xdeadbeef;
97 }
98
99 if (s->ps_enable) {
100 r = s->ps_counter;
101 } else {
102 r = ptimer_get_count(s->ptimer);
103 }
104 return r;
105}
106
107static void pit_control_pw(RegisterInfo *reg, uint64_t value)
108{
109 XilinxPIT *s = XILINX_IO_MODULE_PIT(reg->opaque);
110 uint32_t v32 = value;
111
112 if (!s->cfg.use) {
113 qemu_log_mask(LOG_GUEST_ERROR, "%s: Disabled\n", s->prefix);
114 return;
115 }
116
117 ptimer_stop(s->ptimer);
118 if (v32 & IOM_PIT_CONTROL_EN) {
119 if (s->ps_enable) {
120
121
122 s->ps_counter = s->regs[R_IOM_PIT_PRELOAD];
123 } else {
124 ptimer_set_limit(s->ptimer, s->regs[R_IOM_PIT_PRELOAD], 1);
125 ptimer_run(s->ptimer, !(v32 & IOM_PIT_CONTROL_PRELOAD));
126
127 }
128 }
129}
130
131static void pit_timer_hit(void *opaque)
132{
133 XilinxPIT *s = XILINX_IO_MODULE_PIT(opaque);
134
135 qemu_irq_pulse(s->irq);
136
137 qemu_irq_pulse(s->hit_out);
138}
139
140static void iom_pit_ps_hit_in(void *opaque, int n, int level)
141{
142 XilinxPIT *s = XILINX_IO_MODULE_PIT(opaque);
143
144 if (!(s->regs[R_IOM_PIT_CONTROL] & IOM_PIT_CONTROL_EN)) {
145
146 qemu_log_mask(LOG_GUEST_ERROR, "%s: Received pre-scalar hit when pit is\
147 Disabled. PIT is in One-shot mode or not enabled\n",\
148 s->prefix);
149 return;
150 }
151
152
153 if (!s->ps_level && level) {
154 s->ps_counter--;
155 s->ps_level = level;
156 } else {
157
158 s->ps_level = level;
159 return;
160 }
161
162
163 if (s->ps_counter == 0) {
164 pit_timer_hit(opaque);
165
166 if (s->regs[R_IOM_PIT_CONTROL] & IOM_PIT_CONTROL_PRELOAD) {
167
168 s->ps_counter = s->regs[R_IOM_PIT_PRELOAD];
169 } else {
170
171 s->regs[R_IOM_PIT_CONTROL] &= ~IOM_PIT_CONTROL_EN;
172 }
173 }
174}
175
176static void iom_pit_ps_config(void *opaque, int n, int level)
177{
178 XilinxPIT *s = XILINX_IO_MODULE_PIT(opaque);
179 s->ps_enable = level;
180}
181
182static const RegisterAccessInfo pit_regs_info[] = {
183 [R_IOM_PIT_PRELOAD] = { .name = "PRELOAD" },
184 [R_IOM_PIT_COUNTER] = { .name = "COUNTER", .post_read = pit_ctr_pr },
185 [R_IOM_PIT_CONTROL] = { .name = "CONTROL", .post_write = pit_control_pw },
186};
187
188static const MemoryRegionOps iom_pit_ops = {
189 .read = register_read_memory_le,
190 .write = register_write_memory_le,
191 .endianness = DEVICE_LITTLE_ENDIAN,
192 .valid = {
193 .min_access_size = 4,
194 .max_access_size = 4,
195 },
196};
197
198static void iom_pit_reset(DeviceState *dev)
199{
200 XilinxPIT *s = XILINX_IO_MODULE_PIT(dev);
201 unsigned int i;
202
203 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
204 register_reset(&s->regs_info[i]);
205 }
206 s->ps_level = false;
207}
208
209static void xlx_iom_realize(DeviceState *dev, Error **errp)
210{
211 XilinxPIT *s = XILINX_IO_MODULE_PIT(dev);
212 unsigned int i;
213
214 s->prefix = object_get_canonical_path(OBJECT(dev));
215
216 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
217 RegisterInfo *r = &s->regs_info[i];
218
219 *r = (RegisterInfo) {
220 .data = (uint8_t *)&s->regs[i],
221 .data_size = sizeof(uint32_t),
222 .access = &pit_regs_info[i],
223 .debug = XILINX_IO_MODULE_PIT_ERR_DEBUG,
224 .prefix = s->prefix,
225 .opaque = s,
226 };
227 memory_region_init_io(&r->mem, OBJECT(dev), &iom_pit_ops, r,
228 r->access->name, 4);
229 memory_region_add_subregion(&s->iomem, i * 4, &r->mem);
230 }
231
232 if (s->cfg.use) {
233 s->bh = qemu_bh_new(pit_timer_hit, s);
234 s->ptimer = ptimer_init(s->bh);
235 ptimer_set_freq(s->ptimer, s->frequency);
236
237 qdev_init_gpio_out(dev, &s->hit_out, 1);
238
239 qdev_init_gpio_in_named(dev, iom_pit_ps_config, "ps_config", 1);
240
241 qdev_init_gpio_in_named(dev, iom_pit_ps_hit_in, "ps_hit_in", 1);
242 }
243}
244
245static void xlx_iom_pit_init(Object *obj)
246{
247 XilinxPIT *s = XILINX_IO_MODULE_PIT(obj);
248 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
249
250 memory_region_init_io(&s->iomem, obj, &iom_pit_ops, s,
251 TYPE_XILINX_IO_MODULE_PIT,
252 R_MAX * 4);
253 sysbus_init_mmio(sbd, &s->iomem);
254 sysbus_init_irq(sbd, &s->irq);
255}
256
257static const VMStateDescription vmstate_xlx_iom = {
258 .name = TYPE_XILINX_IO_MODULE_PIT,
259 .version_id = 1,
260 .minimum_version_id = 1,
261 .minimum_version_id_old = 1,
262 .fields = (VMStateField[]) {
263 VMSTATE_END_OF_LIST(),
264 }
265};
266
267static void xlx_iom_class_init(ObjectClass *klass, void *data)
268{
269 DeviceClass *dc = DEVICE_CLASS(klass);
270
271 dc->reset = iom_pit_reset;
272 dc->realize = xlx_iom_realize;
273 dc->props = xlx_iom_properties;
274 dc->vmsd = &vmstate_xlx_iom;
275}
276
277static const TypeInfo xlx_iom_info = {
278 .name = TYPE_XILINX_IO_MODULE_PIT,
279 .parent = TYPE_SYS_BUS_DEVICE,
280 .instance_size = sizeof(XilinxPIT),
281 .class_init = xlx_iom_class_init,
282 .instance_init = xlx_iom_pit_init,
283};
284
285static void xlx_iom_register_types(void)
286{
287 type_register_static(&xlx_iom_info);
288}
289
290type_init(xlx_iom_register_types)
291