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#include "qemu/osdep.h"
26#include "hw/sysbus.h"
27#include "qapi/error.h"
28#include "hw/hw.h"
29#include "qom/cpu.h"
30#include "hw/fdt_generic_util.h"
31
32#define D(x)
33
34#define R_ISR 0
35#define R_IPR 1
36#define R_IER 2
37#define R_IAR 3
38#define R_SIE 4
39#define R_CIE 5
40#define R_IVR 6
41#define R_MER 7
42#define R_MAX 8
43
44#define TYPE_XILINX_INTC "xlnx.xps-intc"
45#define XILINX_INTC(obj) OBJECT_CHECK(struct xlx_pic, (obj), TYPE_XILINX_INTC)
46
47struct xlx_pic
48{
49 SysBusDevice parent_obj;
50
51 MemoryRegion mmio;
52 qemu_irq parent_irq;
53
54
55
56 uint32_t c_kind_of_intr;
57
58
59 uint32_t regs[R_MAX];
60
61 uint32_t irq_pin_state;
62};
63
64static void update_irq(struct xlx_pic *p)
65{
66 uint32_t i;
67
68
69 if (p->regs[R_MER] & 2) {
70 p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
71 }
72
73
74 p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
75
76
77 for (i = 0; i < 32; i++) {
78 if (p->regs[R_IPR] & (1U << i)) {
79 break;
80 }
81 }
82 if (i == 32)
83 i = ~0;
84
85 p->regs[R_IVR] = i;
86 qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
87}
88
89static uint64_t
90pic_read(void *opaque, hwaddr addr, unsigned int size)
91{
92 struct xlx_pic *p = opaque;
93 uint32_t r = 0;
94
95 addr >>= 2;
96 switch (addr)
97 {
98 default:
99 if (addr < ARRAY_SIZE(p->regs))
100 r = p->regs[addr];
101 break;
102
103 }
104 D(printf("%s %x=%x\n", __func__, addr * 4, r));
105 return r;
106}
107
108static void
109pic_write(void *opaque, hwaddr addr,
110 uint64_t val64, unsigned int size)
111{
112 struct xlx_pic *p = opaque;
113 uint32_t value = val64;
114
115 addr >>= 2;
116 D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
117 switch (addr)
118 {
119 case R_IAR:
120 p->regs[R_ISR] &= ~value;
121 break;
122 case R_SIE:
123 p->regs[R_IER] |= value;
124 break;
125 case R_CIE:
126 p->regs[R_IER] &= ~value;
127 break;
128 case R_MER:
129 p->regs[R_MER] = value & 0x3;
130 break;
131 case R_ISR:
132 if ((p->regs[R_MER] & 2)) {
133 break;
134 }
135
136 default:
137 if (addr < ARRAY_SIZE(p->regs))
138 p->regs[addr] = value;
139 break;
140 }
141 update_irq(p);
142}
143
144static const MemoryRegionOps pic_ops = {
145 .read = pic_read,
146 .write = pic_write,
147 .endianness = DEVICE_NATIVE_ENDIAN,
148 .valid = {
149 .min_access_size = 4,
150 .max_access_size = 4
151 }
152};
153
154static void irq_handler(void *opaque, int irq, int level)
155{
156 struct xlx_pic *p = opaque;
157
158
159 if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
160 p->regs[R_ISR] |= (level << irq);
161 }
162
163 p->irq_pin_state &= ~(1 << irq);
164 p->irq_pin_state |= level << irq;
165 update_irq(p);
166}
167
168static void xilinx_intc_init(Object *obj)
169{
170 struct xlx_pic *p = XILINX_INTC(obj);
171
172 qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
173 qdev_init_gpio_out_named(DEVICE(obj), &p->parent_irq, "Outputs", 1);
174
175 memory_region_init_io(&p->mmio, obj, &pic_ops, p, "xlnx.xps-intc",
176 R_MAX * 4);
177 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
178}
179
180static int xilinx_intc_fdt_get_irq(FDTGenericIntc *obj, qemu_irq *irqs,
181 uint32_t *cells, int ncells, int max,
182 Error **errp)
183{
184
185 struct xlx_pic *p = (struct xlx_pic *)obj;
186 uint32_t idx;
187 uint32_t exp_type;
188
189 if (ncells != 2) {
190 error_setg(errp, "Xilinx Intc requires 2 interrupt cells: %d given",
191 ncells);
192 return 0;
193 }
194 idx = cells[0];
195
196 if (idx >= 32) {
197 error_setg(errp, "Xilinx Intc only supports 32 interrupts: index %"
198 PRId32 " requested", idx);
199 return 0;
200 }
201
202 exp_type = p->c_kind_of_intr & (1 << idx) ? 0 : 2;
203 if (cells[1] != exp_type) {
204 error_setg(errp, "Xilinx Intc expects interrupt mode %" PRIx32
205 " for interrupt %" PRIx32 ", mode %" PRIx32 " given",
206 exp_type, idx, cells[1]);
207 return 0;
208 }
209
210 (*irqs) = qdev_get_gpio_in(DEVICE(obj), idx);
211 return 1;
212};
213
214static Property xilinx_intc_properties[] = {
215 DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
216 DEFINE_PROP_END_OF_LIST(),
217};
218
219static void xilinx_intc_fdt_auto_parent(FDTGenericIntc *obj, Error **errp)
220{
221 qdev_connect_gpio_out_named(DEVICE(obj), "Outputs", 0,
222 qdev_get_gpio_in(DEVICE(first_cpu), 0));
223}
224
225
226static void xilinx_intc_class_init(ObjectClass *klass, void *data)
227{
228 DeviceClass *dc = DEVICE_CLASS(klass);
229 FDTGenericIntcClass *fgic = FDT_GENERIC_INTC_CLASS(klass);
230
231 dc->props = xilinx_intc_properties;
232 fgic->get_irq = xilinx_intc_fdt_get_irq;
233 fgic->auto_parent = xilinx_intc_fdt_auto_parent;
234}
235
236static const TypeInfo xilinx_intc_info = {
237 .name = TYPE_XILINX_INTC,
238 .parent = TYPE_SYS_BUS_DEVICE,
239 .instance_size = sizeof(struct xlx_pic),
240 .instance_init = xilinx_intc_init,
241 .class_init = xilinx_intc_class_init,
242 .interfaces = (InterfaceInfo[]) {
243 { TYPE_FDT_GENERIC_INTC },
244 { }
245 },
246};
247
248static void xilinx_intc_register_types(void)
249{
250 type_register_static(&xilinx_intc_info);
251}
252
253type_init(xilinx_intc_register_types)
254