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/register.h"
29#include "qemu/log.h"
30
31#ifndef XILINX_IO_MODULE_GPO_ERR_DEBUG
32#define XILINX_IO_MODULE_GPO_ERR_DEBUG 0
33#endif
34
35#define TYPE_XILINX_IO_MODULE_GPO "xlnx.io_gpo"
36
37#define XILINX_IO_MODULE_GPO(obj) \
38 OBJECT_CHECK(XilinxGPO, (obj), TYPE_XILINX_IO_MODULE_GPO)
39
40#define R_IOM_GPO (0x00 / 4)
41#define R_MAX (1)
42
43typedef struct XilinxGPO {
44 SysBusDevice parent_obj;
45 MemoryRegion iomem;
46
47 struct {
48 bool use;
49 uint32_t size;
50 uint32_t init;
51 } cfg;
52 RegisterInfo regs_info[R_MAX];
53
54 qemu_irq outputs[32];
55 const char *prefix;
56} XilinxGPO;
57
58static Property xlx_iom_properties[] = {
59 DEFINE_PROP_BOOL("use-gpo", XilinxGPO, cfg.use, 0),
60 DEFINE_PROP_UINT32("gpo-size", XilinxGPO, cfg.size, 0),
61 DEFINE_PROP_UINT32("gpo-init", XilinxGPO, cfg.init, 0),
62 DEFINE_PROP_END_OF_LIST(),
63};
64
65static const MemoryRegionOps iom_gpo_ops = {
66 .read = register_read_memory_le,
67 .write = register_write_memory_le,
68 .endianness = DEVICE_LITTLE_ENDIAN,
69 .valid = {
70 .min_access_size = 4,
71 .max_access_size = 4,
72 },
73};
74
75static void gpo_pw(RegisterInfo *reg, uint64_t value)
76{
77 XilinxGPO *s = XILINX_IO_MODULE_GPO(reg->opaque);
78 unsigned int i;
79
80 for (i = 0; i < s->cfg.size; i++) {
81 bool flag = !!(value & (1 << i));
82 qemu_set_irq(s->outputs[i], flag);
83 }
84}
85
86static uint64_t gpo_pr(RegisterInfo *reg, uint64_t value)
87{
88 return 0;
89}
90
91static const RegisterAccessInfo gpo_regs_info[] = {
92 [R_IOM_GPO] = { .name = "GPO", .post_write = gpo_pw, .post_read = gpo_pr, },
93};
94
95static void iom_gpo_reset(DeviceState *dev)
96{
97 XilinxGPO *s = XILINX_IO_MODULE_GPO(dev);
98
99 gpo_pw(&s->regs_info[R_IOM_GPO], s->cfg.init);
100}
101
102static void xlx_iom_realize(DeviceState *dev, Error **errp)
103{
104 XilinxGPO *s = XILINX_IO_MODULE_GPO(dev);
105 unsigned int i;
106 s->prefix = object_get_canonical_path(OBJECT(dev));
107
108 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
109 RegisterInfo *r = &s->regs_info[i];
110
111 *r = (RegisterInfo) {
112 .data_size = sizeof(uint32_t),
113 .access = &gpo_regs_info[i],
114 .debug = XILINX_IO_MODULE_GPO_ERR_DEBUG,
115 .prefix = s->prefix,
116 .opaque = s,
117 };
118 memory_region_init_io(&r->mem, OBJECT(dev), &iom_gpo_ops, r,
119 r->access->name, 4);
120 memory_region_add_subregion(&s->iomem, i * 4, &r->mem);
121 }
122
123 assert(s->cfg.size <= 32);
124 qdev_init_gpio_out(dev, s->outputs, s->cfg.size);
125}
126
127static void xlx_iom_init(Object *obj)
128{
129 XilinxGPO *s = XILINX_IO_MODULE_GPO(obj);
130 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
131
132 memory_region_init_io(&s->iomem, obj, &iom_gpo_ops, s,
133 TYPE_XILINX_IO_MODULE_GPO,
134 R_MAX * 4);
135 sysbus_init_mmio(sbd, &s->iomem);
136}
137
138static const VMStateDescription vmstate_xlx_iom = {
139 .name = TYPE_XILINX_IO_MODULE_GPO,
140 .version_id = 1,
141 .minimum_version_id = 1,
142 .minimum_version_id_old = 1,
143 .fields = (VMStateField[]) {
144 VMSTATE_END_OF_LIST(),
145 }
146};
147
148static void xlx_iom_class_init(ObjectClass *klass, void *data)
149{
150 DeviceClass *dc = DEVICE_CLASS(klass);
151
152 dc->reset = iom_gpo_reset;
153 dc->realize = xlx_iom_realize;
154 dc->props = xlx_iom_properties;
155 dc->vmsd = &vmstate_xlx_iom;
156}
157
158static const TypeInfo xlx_iom_info = {
159 .name = TYPE_XILINX_IO_MODULE_GPO,
160 .parent = TYPE_SYS_BUS_DEVICE,
161 .instance_size = sizeof(XilinxGPO),
162 .class_init = xlx_iom_class_init,
163 .instance_init = xlx_iom_init,
164};
165
166static void xlx_iom_register_types(void)
167{
168 type_register_static(&xlx_iom_info);
169}
170
171type_init(xlx_iom_register_types)
172