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#include "qemu/osdep.h"
28#include "qapi/error.h"
29#include "hw/sysbus.h"
30#include "hw/register-dep.h"
31#include "qemu/bitops.h"
32#include "qemu/log.h"
33
34#include "hw/fdt_generic_util.h"
35
36#ifndef GIC_PROXY_ERR_DEBUG
37#define GIC_PROXY_ERR_DEBUG 0
38#endif
39
40#define TYPE_XILINX_GIC_PROXY "xlnx.zynqmp-gicp"
41
42#define XILINX_GIC_PROXY(obj) \
43 OBJECT_CHECK(GICProxy, (obj), TYPE_XILINX_GIC_PROXY)
44
45#define MAX_INTS 160
46#define GICP_GROUPS 5
47#define GICP_GROUP_STRIDE 0x14
48
49DEP_REG32(GICP0_IRQ_STATUS, 0x0)
50DEP_REG32(GICP0_IRQ_MASK, 0x4)
51DEP_REG32(GICP0_IRQ_ENABLE, 0x8)
52DEP_REG32(GICP0_IRQ_DISABLE, 0xc)
53DEP_REG32(GICP0_IRQ_TRIGGER, 0x10)
54 #define R_GICP0_RSVD 0x000000ff
55 #define R_GICP1_RSVD 0
56 #define R_GICP2_RSVD 0
57 #define R_GICP3_RSVD 0x000000ff
58 #define R_GICP4_RSVD 0xf0000000
59DEP_REG32(GICP_PMU_IRQ_STATUS, 0xa0)
60DEP_REG32(GICP_PMU_IRQ_MASK, 0xa4)
61DEP_REG32(GICP_PMU_IRQ_ENABLE, 0xa8)
62DEP_REG32(GICP_PMU_IRQ_DISABLE, 0xac)
63DEP_REG32(GICP_PMU_IRQ_TRIGGER, 0xb0)
64
65#define R_MAX (R_GICP_PMU_IRQ_TRIGGER + 1)
66
67typedef struct GICProxy {
68 SysBusDevice parent_obj;
69 MemoryRegion iomem;
70 qemu_irq irq;
71
72 uint32_t regs[R_MAX];
73 DepRegisterInfo regs_info[R_MAX];
74} GICProxy;
75
76
77
78
79#define GICPN_STATUS_REG(n) ((A_GICP0_IRQ_STATUS + \
80 (n) * GICP_GROUP_STRIDE) >> 2)
81#define GICPN_MASK_REG(n) ((A_GICP0_IRQ_MASK + \
82 (n) * GICP_GROUP_STRIDE) >> 2)
83
84static void gicp_update_irq(void *opaque)
85{
86 GICProxy *s = XILINX_GIC_PROXY(opaque);
87 bool pending = s->regs[R_GICP_PMU_IRQ_STATUS] &
88 ~s->regs[R_GICP_PMU_IRQ_MASK];
89
90 qemu_set_irq(s->irq, pending);
91}
92
93
94
95static void gicp_update(void *opaque, uint8_t nr)
96{
97 GICProxy *s = XILINX_GIC_PROXY(opaque);
98
99 if (s->regs[GICPN_STATUS_REG(nr)] & ~s->regs[GICPN_MASK_REG(nr)]) {
100 s->regs[R_GICP_PMU_IRQ_STATUS] |= 1 << nr;
101 } else {
102 s->regs[R_GICP_PMU_IRQ_STATUS] &= ~(1 << nr);
103 }
104 gicp_update_irq(s);
105}
106
107static void gicp_status_postw(DepRegisterInfo *reg, uint64_t val64)
108{
109 GICProxy *s = XILINX_GIC_PROXY(reg->opaque);
110 unsigned int i;
111
112 for (i = 0; i < GICP_GROUPS; i++) {
113 gicp_update(s, i);
114 }
115}
116
117static void gicp_enable_postw(DepRegisterInfo *reg, uint64_t val64)
118{
119 GICProxy *s = XILINX_GIC_PROXY(reg->opaque);
120 uint32_t val = val64;
121
122 s->regs[R_GICP_PMU_IRQ_MASK] &= ~val;
123 gicp_update_irq(s);
124}
125
126static void gicp_disable_postw(DepRegisterInfo *reg, uint64_t val64)
127{
128 GICProxy *s = XILINX_GIC_PROXY(reg->opaque);
129 uint32_t val = val64;
130
131 s->regs[R_GICP_PMU_IRQ_MASK] |= val;
132 gicp_update_irq(s);
133}
134
135static void gicp_trigger_postw(DepRegisterInfo *reg, uint64_t val64)
136{
137 GICProxy *s = XILINX_GIC_PROXY(reg->opaque);
138 uint32_t val = val64;
139
140 s->regs[R_GICP_PMU_IRQ_STATUS] |= val;
141 gicp_update_irq(s);
142}
143
144
145
146static void gicpn_status_postw(DepRegisterInfo *reg, uint64_t val64)
147{
148 GICProxy *s = XILINX_GIC_PROXY(reg->opaque);
149 uint64_t nr = (uintptr_t)reg->access->opaque;
150
151 gicp_update(s, nr);
152}
153
154static void gicpn_enable_postw(DepRegisterInfo *reg, uint64_t val64)
155{
156 GICProxy *s = XILINX_GIC_PROXY(reg->opaque);
157 uint32_t val = val64;
158 uint64_t nr = (uintptr_t)reg->access->opaque;
159
160 s->regs[GICPN_MASK_REG(nr)] &= ~val;
161 gicp_update(s, nr);
162}
163
164static void gicpn_disable_postw(DepRegisterInfo *reg, uint64_t val64)
165{
166 GICProxy *s = XILINX_GIC_PROXY(reg->opaque);
167 uint32_t val = val64;
168 uint64_t nr = (uintptr_t)reg->access->opaque;
169
170 s->regs[GICPN_MASK_REG(nr)] |= val;
171 gicp_update(s, nr);
172}
173
174static void gicpn_trigger_postw(DepRegisterInfo *reg, uint64_t val64)
175{
176 GICProxy *s = XILINX_GIC_PROXY(reg->opaque);
177 uint32_t val = val64;
178 uint64_t nr = (uintptr_t)reg->access->opaque;
179
180 s->regs[GICPN_STATUS_REG(nr)] |= val;
181 gicp_update(s, nr);
182}
183
184
185static uint64_t gicp_wo_postr(DepRegisterInfo *reg, uint64_t val64)
186{
187 GICProxy *s = XILINX_GIC_PROXY(reg->opaque);
188 qemu_log_mask(LOG_GUEST_ERROR,
189 "%s: Reading from wo register at %" HWADDR_PRIx "\n",
190 object_get_canonical_path(OBJECT(s)),
191 reg->access->decode.addr);
192 return 0;
193}
194
195
196static uint64_t gicp_raz_hi24_postr(DepRegisterInfo *reg, uint64_t val64)
197{
198 return val64 & 0xff;
199}
200
201static DepRegisterAccessInfo gic_proxy_regs_info[] = {
202#define GICPN_REG_DEFS(n) \
203 { .name = "GICP" #n "_IRQ_STATUS", \
204 .decode.addr = A_GICP0_IRQ_STATUS + n * GICP_GROUP_STRIDE, \
205 .w1c = 0xffffffff, \
206 .rsvd = R_GICP ## n ## _RSVD, \
207 .post_write = gicpn_status_postw, \
208 .opaque = (void *)n, \
209 },{ .name = "GICP" #n "_IRQ_MASK", \
210 .decode.addr = A_GICP0_IRQ_MASK + n * GICP_GROUP_STRIDE, \
211 .ro = 0xffffffff, \
212 .rsvd = R_GICP ## n ## _RSVD, \
213 .reset = 0xffffffff, \
214 },{ .name = "GICP" #n "_IRQ_ENABLE", \
215 .decode.addr = A_GICP0_IRQ_ENABLE + n * GICP_GROUP_STRIDE, \
216 .rsvd = R_GICP ## n ## _RSVD, \
217 .post_read = gicp_wo_postr, \
218 .post_write = gicpn_enable_postw, \
219 .opaque = (void *)n, \
220 },{ .name = "GICP" #n "_IRQ_DISABLE", \
221 .decode.addr = A_GICP0_IRQ_DISABLE + n * GICP_GROUP_STRIDE, \
222 .rsvd = R_GICP ## n ## _RSVD, \
223 .post_read = gicp_wo_postr, \
224 .post_write = gicpn_disable_postw, \
225 .opaque = (void *)n, \
226 },{ .name = "GICP" #n "_IRQ_TRIGGER", \
227 .decode.addr = A_GICP0_IRQ_TRIGGER + n * GICP_GROUP_STRIDE, \
228 .rsvd = R_GICP ## n ## _RSVD, \
229 .post_read = gicp_wo_postr, \
230 .post_write = gicpn_trigger_postw, \
231 .opaque = (void *)n, \
232 }
233 GICPN_REG_DEFS(0),
234 GICPN_REG_DEFS(1),
235 GICPN_REG_DEFS(2),
236 GICPN_REG_DEFS(3),
237 GICPN_REG_DEFS(4),
238 { .name = "GICP_PMU_IRQ_STATUS", .decode.addr = A_GICP_PMU_IRQ_STATUS,
239 .w1c = 0x000000ff,
240 .rsvd = 0xffffffe0,
241 .post_read = gicp_raz_hi24_postr,
242 .post_write = gicp_status_postw,
243 },{ .name = "GICP_PMU_IRQ_MASK", .decode.addr = A_GICP_PMU_IRQ_MASK,
244 .ro = 0x000000ff,
245 .rsvd = 0xffffffe0,
246 .reset = 0x000000ff,
247 .post_read = gicp_raz_hi24_postr,
248 },{ .name = "GICP_PMU_IRQ_ENABLE", .decode.addr = A_GICP_PMU_IRQ_ENABLE,
249 .rsvd = 0xffffffe0,
250 .post_read = gicp_wo_postr,
251 .post_write = gicp_enable_postw,
252 },{ .name = "GICP_PMU_IRQ_DISABLE", .decode.addr = A_GICP_PMU_IRQ_DISABLE,
253 .rsvd = 0xffffffe0,
254 .post_read = gicp_wo_postr,
255 .post_write = gicp_disable_postw,
256 },{ .name = "GICP_PMU_IRQ_TRIGGER", .decode.addr = A_GICP_PMU_IRQ_TRIGGER,
257 .rsvd = 0xffffffe0,
258 .post_read = gicp_wo_postr,
259 .post_write = gicp_trigger_postw,
260 }
261};
262
263static void gic_proxy_reset(DeviceState *dev)
264{
265 GICProxy *s = XILINX_GIC_PROXY(dev);
266 unsigned int i;
267
268 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
269 dep_register_reset(&s->regs_info[i]);
270 }
271}
272
273static uint64_t gic_proxy_read(void *opaque, hwaddr addr, unsigned size)
274{
275 GICProxy *s = XILINX_GIC_PROXY(opaque);
276 DepRegisterInfo *r = &s->regs_info[addr / 4];
277
278 if (!r->data) {
279 qemu_log_mask(LOG_GUEST_ERROR,
280 "%s: Decode error: read from %" HWADDR_PRIx "\n",
281 object_get_canonical_path(OBJECT(s)),
282 addr);
283 return 0;
284 }
285 return dep_register_read(r);
286}
287
288static void gic_proxy_write(void *opaque, hwaddr addr, uint64_t value,
289 unsigned size)
290{
291 GICProxy *s = XILINX_GIC_PROXY(opaque);
292 DepRegisterInfo *r = &s->regs_info[addr / 4];
293
294 if (!r->data) {
295 qemu_log_mask(LOG_GUEST_ERROR,
296 "%s: Decode error: write %" HWADDR_PRIx "=%" PRIx64 "\n",
297 object_get_canonical_path(OBJECT(s)),
298 addr, value);
299 return;
300 }
301 dep_register_write(r, value, ~0);
302}
303
304static const MemoryRegionOps gic_proxy_ops = {
305 .read = gic_proxy_read,
306 .write = gic_proxy_write,
307 .endianness = DEVICE_LITTLE_ENDIAN,
308 .valid = {
309 .min_access_size = 4,
310 .max_access_size = 4,
311 },
312};
313
314static void gic_proxy_realize(DeviceState *dev, Error **errp)
315{
316 GICProxy *s = XILINX_GIC_PROXY(dev);
317 const char *prefix = object_get_canonical_path(OBJECT(dev));
318 unsigned int i;
319
320 for (i = 0; i < ARRAY_SIZE(gic_proxy_regs_info); ++i) {
321 DepRegisterInfo *r = &s->regs_info[gic_proxy_regs_info[i].decode.addr/4];
322
323 *r = (DepRegisterInfo) {
324 .data = (uint8_t *)&s->regs[
325 gic_proxy_regs_info[i].decode.addr/4],
326 .data_size = sizeof(uint32_t),
327 .access = &gic_proxy_regs_info[i],
328 .debug = GIC_PROXY_ERR_DEBUG,
329 .prefix = prefix,
330 .opaque = s,
331 };
332 dep_register_init(r);
333 }
334}
335
336static void gic_proxy_set_irq(void *opaque, int irq, int level)
337{
338 GICProxy *s = XILINX_GIC_PROXY(opaque);
339 int group = irq / 32;
340 int bit = irq % 32;
341
342 if (level) {
343 s->regs[GICPN_STATUS_REG(group)] |= 1 << bit;
344 } else {
345 s->regs[GICPN_STATUS_REG(group)] &= ~(1 << bit);
346 }
347 gicp_update(s, group);
348}
349
350static void gic_proxy_init(Object *obj)
351{
352 GICProxy *s = XILINX_GIC_PROXY(obj);
353 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
354 DeviceState *dev = DEVICE(s);
355
356
357
358
359
360
361
362
363 qdev_init_gpio_in(dev, gic_proxy_set_irq, MAX_INTS);
364 qdev_init_gpio_out_named(dev, &s->irq, "gicp-irq", 1);
365
366 memory_region_init_io(&s->iomem, obj, &gic_proxy_ops, s,
367 TYPE_XILINX_GIC_PROXY, R_MAX * 4);
368 sysbus_init_mmio(sbd, &s->iomem);
369 sysbus_init_irq(sbd, &s->irq);
370}
371
372static int gic_proxy_get_irq(FDTGenericIntc *obj, qemu_irq *irqs,
373 uint32_t *cells, int ncells, int max,
374 Error **errp)
375{
376 int idx;
377
378 if (ncells != 3) {
379 error_setg(errp, "Xilinx GIC Proxy requires 3 interrupt cells, "
380 "%d cells given", ncells);
381 return 0;
382 }
383 idx = cells[1];
384
385 switch (cells[0]) {
386 case 0:
387 if (idx >= MAX_INTS) {
388 error_setg(errp, "Xilinx GIC Proxy has maximum index of %" PRId32
389 ", index %" PRId32 " given", MAX_INTS - 1, idx);
390 return 0;
391 }
392 (*irqs) = qdev_get_gpio_in(DEVICE(obj), cells[1]);
393 return 1;
394 default:
395 error_setg(errp, "Invalid cell 0 value in interrupt binding: %d",
396 cells[0]);
397 return 0;
398 }
399};
400
401static const VMStateDescription vmstate_gic_proxy = {
402 .name = TYPE_XILINX_GIC_PROXY,
403 .version_id = 1,
404 .minimum_version_id = 1,
405 .minimum_version_id_old = 1,
406 .fields = (VMStateField[]) {
407 VMSTATE_UINT32_ARRAY(regs, GICProxy, R_MAX),
408 VMSTATE_END_OF_LIST(),
409 }
410};
411
412static const FDTGenericGPIOSet gic_proxy_client_gpios[] = {
413 {
414 .names = &fdt_generic_gpio_name_set_gpio,
415 .gpios = (FDTGenericGPIOConnection[]) {
416 { .name = "gicp-irq", .fdt_index = 0 },
417 { },
418 },
419 },
420 { },
421};
422
423static void gic_proxy_class_init(ObjectClass *oc, void *data)
424{
425 DeviceClass *dc = DEVICE_CLASS(oc);
426 FDTGenericIntcClass *fgic = FDT_GENERIC_INTC_CLASS(oc);
427 FDTGenericGPIOClass *fggc = FDT_GENERIC_GPIO_CLASS(oc);
428
429 dc->reset = gic_proxy_reset;
430 dc->realize = gic_proxy_realize;
431 dc->vmsd = &vmstate_gic_proxy;
432 fgic->get_irq = gic_proxy_get_irq;
433 fggc->client_gpios = gic_proxy_client_gpios;
434}
435
436static const TypeInfo gic_proxy_info = {
437 .name = TYPE_XILINX_GIC_PROXY,
438 .parent = TYPE_SYS_BUS_DEVICE,
439 .instance_size = sizeof(GICProxy),
440 .instance_init = gic_proxy_init,
441 .class_init = gic_proxy_class_init,
442 .interfaces = (InterfaceInfo[]) {
443 { TYPE_FDT_GENERIC_INTC },
444 { TYPE_FDT_GENERIC_GPIO },
445 { },
446 },
447};
448
449static void gic_proxy_register_types(void)
450{
451 type_register_static(&gic_proxy_info);
452}
453
454type_init(gic_proxy_register_types)
455