2 * Syborg interrupt controller.
4 * Copyright (c) 2008 CodeSourcery
5 * Copyright (c) 2010, 2013 Stefan Weil
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 #include "qemu/osdep.h"
27 #include "hw/sysbus.h"
30 //#define DEBUG_SYBORG_INT
32 #ifdef DEBUG_SYBORG_INT
33 #define DPRINTF(fmt, ...) \
34 do { printf("syborg_int: " fmt , ## __VA_ARGS__); } while (0)
35 #define BADF(fmt, ...) \
36 do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__); \
39 #define DPRINTF(fmt, ...) do {} while(0)
40 #define BADF(fmt, ...) \
41 do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__);} while (0)
45 INT_STATUS
= 1, /* number of pending interrupts */
46 INT_CURRENT
= 2, /* next interrupt to be serviced */
63 syborg_int_flags
*flags
;
67 static void syborg_int_update(SyborgIntState
*s
)
69 DPRINTF("pending %d\n", s
->pending_count
);
70 qemu_set_irq(s
->parent_irq
, s
->pending_count
> 0);
73 static void syborg_int_set_irq(void *opaque
, int irq
, int level
)
75 SyborgIntState
*s
= (SyborgIntState
*)opaque
;
77 if (s
->flags
[irq
].level
== level
)
80 s
->flags
[irq
].level
= level
;
81 if (s
->flags
[irq
].enabled
) {
90 static uint64_t syborg_int_read(void *opaque
, hwaddr offset
,
93 SyborgIntState
*s
= (SyborgIntState
*)opaque
;
97 switch (offset
>> 2) {
101 DPRINTF("read status=%d\n", s
->pending_count
);
102 return s
->pending_count
;
105 for (i
= 0; i
< s
->num_irqs
; i
++) {
106 if (s
->flags
[i
].level
& s
->flags
[i
].enabled
) {
107 DPRINTF("read current=%d\n", i
);
111 DPRINTF("read current=none\n");
115 cpu_abort(cpu_single_env
, "syborg_int_read: Bad offset %x\n",
121 static void syborg_int_write(void *opaque
, hwaddr offset
,
122 uint64_t value
, unsigned size
)
124 SyborgIntState
*s
= (SyborgIntState
*)opaque
;
128 DPRINTF("syborg_int_write offset=%d val=%d\n", (int)offset
, (int)value
);
129 switch (offset
>> 2) {
130 case INT_DISABLE_ALL
:
131 s
->pending_count
= 0;
132 for (i
= 0; i
< s
->num_irqs
; i
++)
133 s
->flags
[i
].enabled
= 0;
137 if (value
>= s
->num_irqs
)
139 if (s
->flags
[value
].enabled
) {
140 if (s
->flags
[value
].enabled
)
142 s
->flags
[value
].enabled
= 0;
147 if (value
>= s
->num_irqs
)
149 if (!(s
->flags
[value
].enabled
)) {
150 if(s
->flags
[value
].level
)
152 s
->flags
[value
].enabled
= 1;
157 cpu_abort(cpu_single_env
, "syborg_int_write: Bad offset %x\n",
161 syborg_int_update(s
);
164 static const MemoryRegionOps syborg_int_ops
= {
165 .read
= syborg_int_read
,
166 .write
= syborg_int_write
,
167 .endianness
= DEVICE_NATIVE_ENDIAN
,
170 static void syborg_int_save(QEMUFile
*f
, void *opaque
)
172 SyborgIntState
*s
= (SyborgIntState
*)opaque
;
175 qemu_put_be32(f
, s
->num_irqs
);
176 qemu_put_be32(f
, s
->pending_count
);
177 for (i
= 0; i
< s
->num_irqs
; i
++) {
178 qemu_put_be32(f
, s
->flags
[i
].enabled
179 | ((unsigned)s
->flags
[i
].level
<< 1));
183 static int syborg_int_load(QEMUFile
*f
, void *opaque
, int version_id
)
185 SyborgIntState
*s
= (SyborgIntState
*)opaque
;
192 val
= qemu_get_be32(f
);
193 if (val
!= s
->num_irqs
)
195 s
->pending_count
= qemu_get_be32(f
);
196 for (i
= 0; i
< s
->num_irqs
; i
++) {
197 val
= qemu_get_be32(f
);
198 s
->flags
[i
].enabled
= val
& 1;
199 s
->flags
[i
].level
= (val
>> 1) & 1;
204 static int syborg_int_init(SysBusDevice
*sbd
)
206 DeviceState
*dev
= DEVICE(sbd
);
207 SyborgIntState
*s
= SYBORG_INT(dev
);
209 sysbus_init_irq(dev
, &s
->parent_irq
);
210 qdev_init_gpio_in(&dev
->qdev
, syborg_int_set_irq
, s
->num_irqs
);
211 memory_region_init_io(&s
->iomem
, &syborg_int_ops
, s
,
212 "interrupt", 0x1000);
213 sysbus_init_mmio(sbd
, &s
->iomem
);
214 s
->flags
= g_malloc0(s
->num_irqs
* sizeof(syborg_int_flags
));
216 register_savevm(&dev
->qdev
, "syborg_int", -1, 1, syborg_int_save
,
221 static Property syborg_fb_properties
[] = {
222 DEFINE_PROP_UINT32("num-interrupts", SyborgIntState
, num_irqs
, 64),
223 DEFINE_PROP_END_OF_LIST()
226 static void syborg_int_class_init(ObjectClass
*klass
, void *data
)
228 DeviceClass
*dc
= DEVICE_CLASS(klass
);
229 SysBusDeviceClass
*k
= SYS_BUS_DEVICE_CLASS(klass
);
230 dc
->props
= syborg_fb_properties
;
231 k
->init
= syborg_int_init
;
234 static const TypeInfo syborg_int_info
= {
235 .name
= "syborg,interrupt",
236 .parent
= TYPE_SYS_BUS_DEVICE
,
237 .instance_size
= sizeof(SyborgIntState
),
238 .class_init
= syborg_int_class_init
241 static void syborg_interrupt_register_types(void)
243 type_register_static(&syborg_int_info
);
246 type_init(syborg_interrupt_register_types
)