1 /*
2 * QEMU Xilinx OPB Interrupt Controller.
3 *
4 * Copyright (c) 2009 Edgar E. Iglesias.
5 *
6 * https://docs.amd.com/v/u/en-US/xps_intc
7 * DS572: LogiCORE IP XPS Interrupt Controller (v2.01a)
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28 #include "qemu/osdep.h"
29 #include "qapi/error.h"
30 #include "hw/sysbus.h"
31 #include "qemu/module.h"
32 #include "hw/irq.h"
33 #include "hw/qdev-properties.h"
34 #include "hw/qdev-properties-system.h"
35 #include "qom/object.h"
36
37 #define D(x)
38
39 #define R_ISR 0
40 #define R_IPR 1
41 #define R_IER 2
42 #define R_IAR 3
43 #define R_SIE 4
44 #define R_CIE 5
45 #define R_IVR 6
46 #define R_MER 7
47 #define R_MAX 8
48
49 #define TYPE_XILINX_INTC "xlnx.xps-intc"
50 typedef struct XpsIntc XpsIntc;
51 DECLARE_INSTANCE_CHECKER(XpsIntc, XILINX_INTC, TYPE_XILINX_INTC)
52
53 struct XpsIntc
54 {
55 SysBusDevice parent_obj;
56
57 EndianMode model_endianness;
58 MemoryRegion mmio;
59 qemu_irq parent_irq;
60
61 /* Configuration reg chosen at synthesis-time. QEMU populates
62 the bits at board-setup. */
63 uint32_t c_kind_of_intr;
64
65 /* Runtime control registers. */
66 uint32_t regs[R_MAX];
67 /* state of the interrupt input pins */
68 uint32_t irq_pin_state;
69 };
70
update_irq(XpsIntc * p)71 static void update_irq(XpsIntc *p)
72 {
73 uint32_t i;
74
75 /* level triggered interrupt */
76 if (p->regs[R_MER] & 2) {
77 p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
78 }
79
80 /* Update the pending register. */
81 p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
82
83 /* Update the vector register. */
84 for (i = 0; i < 32; i++) {
85 if (p->regs[R_IPR] & (1U << i)) {
86 break;
87 }
88 }
89 if (i == 32)
90 i = ~0;
91
92 p->regs[R_IVR] = i;
93 qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
94 }
95
pic_read(void * opaque,hwaddr addr,unsigned int size)96 static uint64_t pic_read(void *opaque, hwaddr addr, unsigned int size)
97 {
98 XpsIntc *p = opaque;
99 uint32_t r = 0;
100
101 addr >>= 2;
102 switch (addr)
103 {
104 default:
105 if (addr < ARRAY_SIZE(p->regs))
106 r = p->regs[addr];
107 break;
108
109 }
110 D(printf("%s %x=%x\n", __func__, addr * 4, r));
111 return r;
112 }
113
pic_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)114 static void pic_write(void *opaque, hwaddr addr,
115 uint64_t val64, unsigned int size)
116 {
117 XpsIntc *p = opaque;
118 uint32_t value = val64;
119
120 addr >>= 2;
121 D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
122 switch (addr)
123 {
124 case R_IAR:
125 p->regs[R_ISR] &= ~value; /* ACK. */
126 break;
127 case R_SIE:
128 p->regs[R_IER] |= value; /* Atomic set ie. */
129 break;
130 case R_CIE:
131 p->regs[R_IER] &= ~value; /* Atomic clear ie. */
132 break;
133 case R_MER:
134 p->regs[R_MER] = value & 0x3;
135 break;
136 case R_ISR:
137 if ((p->regs[R_MER] & 2)) {
138 break;
139 }
140 /* fallthrough */
141 default:
142 if (addr < ARRAY_SIZE(p->regs))
143 p->regs[addr] = value;
144 break;
145 }
146 update_irq(p);
147 }
148
149 static const MemoryRegionOps pic_ops[2] = {
150 [0 ... 1] = {
151 .read = pic_read,
152 .write = pic_write,
153 .impl = {
154 .min_access_size = 4,
155 .max_access_size = 4,
156 },
157 .valid = {
158 /*
159 * All XPS INTC registers are accessed through the PLB interface.
160 * The base address for these registers is provided by the
161 * configuration parameter, C_BASEADDR. Each register is 32 bits
162 * although some bits may be unused and is accessed on a 4-byte
163 * boundary offset from the base address.
164 */
165 .min_access_size = 4,
166 .max_access_size = 4,
167 },
168 },
169 [0].endianness = DEVICE_LITTLE_ENDIAN,
170 [1].endianness = DEVICE_BIG_ENDIAN,
171 };
172
irq_handler(void * opaque,int irq,int level)173 static void irq_handler(void *opaque, int irq, int level)
174 {
175 XpsIntc *p = opaque;
176
177 /* edge triggered interrupt */
178 if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
179 p->regs[R_ISR] |= (level << irq);
180 }
181
182 p->irq_pin_state &= ~(1 << irq);
183 p->irq_pin_state |= level << irq;
184 update_irq(p);
185 }
186
xilinx_intc_init(Object * obj)187 static void xilinx_intc_init(Object *obj)
188 {
189 XpsIntc *p = XILINX_INTC(obj);
190
191 qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
192 sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq);
193 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
194 }
195
xilinx_intc_realize(DeviceState * dev,Error ** errp)196 static void xilinx_intc_realize(DeviceState *dev, Error **errp)
197 {
198 XpsIntc *p = XILINX_INTC(dev);
199
200 if (p->model_endianness == ENDIAN_MODE_UNSPECIFIED) {
201 error_setg(errp, TYPE_XILINX_INTC " property 'endianness'"
202 " must be set to 'big' or 'little'");
203 return;
204 }
205
206 memory_region_init_io(&p->mmio, OBJECT(dev),
207 &pic_ops[p->model_endianness == ENDIAN_MODE_BIG],
208 p, "xlnx.xps-intc",
209 R_MAX * 4);
210 }
211
212 static const Property xilinx_intc_properties[] = {
213 DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XpsIntc, model_endianness),
214 DEFINE_PROP_UINT32("kind-of-intr", XpsIntc, c_kind_of_intr, 0),
215 };
216
xilinx_intc_class_init(ObjectClass * klass,const void * data)217 static void xilinx_intc_class_init(ObjectClass *klass, const void *data)
218 {
219 DeviceClass *dc = DEVICE_CLASS(klass);
220
221 dc->realize = xilinx_intc_realize;
222 device_class_set_props(dc, xilinx_intc_properties);
223 }
224
225 static const TypeInfo xilinx_intc_info = {
226 .name = TYPE_XILINX_INTC,
227 .parent = TYPE_SYS_BUS_DEVICE,
228 .instance_size = sizeof(XpsIntc),
229 .instance_init = xilinx_intc_init,
230 .class_init = xilinx_intc_class_init,
231 };
232
xilinx_intc_register_types(void)233 static void xilinx_intc_register_types(void)
234 {
235 type_register_static(&xilinx_intc_info);
236 }
237
238 type_init(xilinx_intc_register_types)
239