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-dep.h"
29#include "qemu/log.h"
30
31#include "hw/fdt_generic_util.h"
32
33#ifndef XILINX_IO_MODULE_GPI_ERR_DEBUG
34#define XILINX_IO_MODULE_GPI_ERR_DEBUG 0
35#endif
36
37#define TYPE_XILINX_IO_MODULE_GPI "xlnx.io_gpi"
38
39#define XILINX_IO_MODULE_GPI(obj) \
40 OBJECT_CHECK(XilinxGPI, (obj), TYPE_XILINX_IO_MODULE_GPI)
41
42#define R_IOM_GPI (0x00 / 4)
43#define R_MAX (1)
44
45typedef struct XilinxGPI {
46 SysBusDevice parent_obj;
47 MemoryRegion iomem;
48 qemu_irq parent_irq;
49
50 uint32_t ien;
51
52 struct {
53 bool use;
54 bool interrupt;
55 uint32_t size;
56 } cfg;
57 uint32_t regs[R_MAX];
58 DepRegisterInfo regs_info[R_MAX];
59 const char *prefix;
60} XilinxGPI;
61
62static Property xlx_iom_properties[] = {
63 DEFINE_PROP_BOOL("use-gpi", XilinxGPI, cfg.use, 0),
64 DEFINE_PROP_BOOL("gpi-interrupt", XilinxGPI, cfg.interrupt, 0),
65 DEFINE_PROP_UINT32("gpi-size", XilinxGPI, cfg.size, 0),
66 DEFINE_PROP_END_OF_LIST(),
67};
68
69static const MemoryRegionOps iom_gpi_ops = {
70 .read = dep_register_read_memory_le,
71 .write = dep_register_write_memory_le,
72 .endianness = DEVICE_LITTLE_ENDIAN,
73 .valid = {
74 .min_access_size = 4,
75 .max_access_size = 4,
76 },
77};
78
79static void irq_handler(void *opaque, int irq, int level)
80{
81 XilinxGPI *s = XILINX_IO_MODULE_GPI(opaque);
82 uint32_t old = s->regs[R_IOM_GPI];
83
84
85
86 if (s->ien & (1 << irq)) {
87 s->regs[R_IOM_GPI] &= ~(1 << irq);
88 s->regs[R_IOM_GPI] |= level << irq;
89
90 if ((old != s->regs[R_IOM_GPI]) && level) {
91 qemu_irq_pulse(s->parent_irq);
92 }
93 }
94}
95
96
97static void named_irq_handler(void *opaque, int n, int level)
98{
99 XilinxGPI *s = XILINX_IO_MODULE_GPI(opaque);
100 irq_handler(s, n, level);
101}
102
103
104static void ien_handler(void *opaque, int n, int level)
105{
106 XilinxGPI *s = XILINX_IO_MODULE_GPI(opaque);
107
108 s->ien = level;
109
110 s->regs[R_IOM_GPI] &= s->ien;
111}
112
113static const DepRegisterAccessInfo gpi_regs_info[] = {
114 [R_IOM_GPI] = { .name = "GPI", .ro = ~0 },
115};
116
117static void iom_gpi_reset(DeviceState *dev)
118{
119 XilinxGPI *s = XILINX_IO_MODULE_GPI(dev);
120 unsigned int i;
121
122 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
123 dep_register_reset(&s->regs_info[i]);
124 }
125
126 s->ien = 0;
127}
128
129static void xlx_iom_realize(DeviceState *dev, Error **errp)
130{
131 XilinxGPI *s = XILINX_IO_MODULE_GPI(dev);
132 unsigned int i;
133 s->prefix = object_get_canonical_path(OBJECT(dev));
134
135 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
136 DepRegisterInfo *r = &s->regs_info[i];
137
138 *r = (DepRegisterInfo) {
139 .data = (uint8_t *)&s->regs[i],
140 .data_size = sizeof(uint32_t),
141 .access = &gpi_regs_info[i],
142 .debug = XILINX_IO_MODULE_GPI_ERR_DEBUG,
143 .prefix = s->prefix,
144 .opaque = s,
145 };
146 memory_region_init_io(&r->mem, OBJECT(dev), &iom_gpi_ops, r,
147 r->access->name, 4);
148 memory_region_add_subregion(&s->iomem, i * 4, &r->mem);
149 }
150
151 assert(s->cfg.size <= 32);
152
153
154 qdev_init_gpio_in(dev, irq_handler, s->cfg.size);
155 qdev_init_gpio_in_named(dev, named_irq_handler, "GPI", 32);
156 qdev_init_gpio_in_named(dev, ien_handler, "IEN", 32);
157}
158
159static void xlx_iom_init(Object *obj)
160{
161 XilinxGPI *s = XILINX_IO_MODULE_GPI(obj);
162 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
163
164 memory_region_init_io(&s->iomem, obj, &iom_gpi_ops, s,
165 TYPE_XILINX_IO_MODULE_GPI,
166 R_MAX * 4);
167 sysbus_init_mmio(sbd, &s->iomem);
168 sysbus_init_irq(sbd, &s->parent_irq);
169}
170
171static const VMStateDescription vmstate_xlx_iom = {
172 .name = TYPE_XILINX_IO_MODULE_GPI,
173 .version_id = 1,
174 .minimum_version_id = 1,
175 .minimum_version_id_old = 1,
176 .fields = (VMStateField[]) {
177 VMSTATE_END_OF_LIST(),
178 }
179};
180
181
182static const FDTGenericGPIOSet gpio_sets [] = {
183 {
184 .names = &fdt_generic_gpio_name_set_gpio,
185 .gpios = (FDTGenericGPIOConnection[]) {
186 { .name = "GPI", .fdt_index = 0, .range = 32 },
187 { },
188 },
189 },
190 { },
191};
192
193static const FDTGenericGPIOSet gpio_client_sets[] = {
194 {
195 .names = &fdt_generic_gpio_name_set_gpio,
196 .gpios = (FDTGenericGPIOConnection[]) {
197 { .name = "IEN", .fdt_index = 0 },
198 { },
199 },
200 },
201 { },
202};
203
204static void xlx_iom_class_init(ObjectClass *klass, void *data)
205{
206 DeviceClass *dc = DEVICE_CLASS(klass);
207 FDTGenericGPIOClass *fggc = FDT_GENERIC_GPIO_CLASS(klass);
208
209 dc->reset = iom_gpi_reset;
210 dc->realize = xlx_iom_realize;
211 dc->props = xlx_iom_properties;
212 dc->vmsd = &vmstate_xlx_iom;
213 fggc->controller_gpios = gpio_sets;
214 fggc->client_gpios = gpio_client_sets;
215}
216
217static const TypeInfo xlx_iom_info = {
218 .name = TYPE_XILINX_IO_MODULE_GPI,
219 .parent = TYPE_SYS_BUS_DEVICE,
220 .instance_size = sizeof(XilinxGPI),
221 .class_init = xlx_iom_class_init,
222 .instance_init = xlx_iom_init,
223 .interfaces = (InterfaceInfo[]) {
224 { TYPE_FDT_GENERIC_GPIO },
225 { }
226 },
227};
228
229static void xlx_iom_register_types(void)
230{
231 type_register_static(&xlx_iom_info);
232}
233
234type_init(xlx_iom_register_types)
235