149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * QEMU Xilinx OPB Interrupt Controller.
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Copyright (c) 2009 Edgar E. Iglesias.
549ab747fSPaolo Bonzini *
649ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini *
1349ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini *
1649ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini * THE SOFTWARE.
2349ab747fSPaolo Bonzini */
2449ab747fSPaolo Bonzini
2590191d07SPeter Maydell #include "qemu/osdep.h"
2649ab747fSPaolo Bonzini #include "hw/sysbus.h"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
2864552b6bSMarkus Armbruster #include "hw/irq.h"
29a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
30db1015e9SEduardo Habkost #include "qom/object.h"
3149ab747fSPaolo Bonzini
3249ab747fSPaolo Bonzini #define D(x)
3349ab747fSPaolo Bonzini
3449ab747fSPaolo Bonzini #define R_ISR 0
3549ab747fSPaolo Bonzini #define R_IPR 1
3649ab747fSPaolo Bonzini #define R_IER 2
3749ab747fSPaolo Bonzini #define R_IAR 3
3849ab747fSPaolo Bonzini #define R_SIE 4
3949ab747fSPaolo Bonzini #define R_CIE 5
4049ab747fSPaolo Bonzini #define R_IVR 6
4149ab747fSPaolo Bonzini #define R_MER 7
4249ab747fSPaolo Bonzini #define R_MAX 8
4349ab747fSPaolo Bonzini
44cc3e064eSAndreas Färber #define TYPE_XILINX_INTC "xlnx.xps-intc"
45*d2960be0SPhilippe Mathieu-Daudé typedef struct XpsIntc XpsIntc;
46*d2960be0SPhilippe Mathieu-Daudé DECLARE_INSTANCE_CHECKER(XpsIntc, XILINX_INTC, TYPE_XILINX_INTC)
47cc3e064eSAndreas Färber
48*d2960be0SPhilippe Mathieu-Daudé struct XpsIntc
4949ab747fSPaolo Bonzini {
50cc3e064eSAndreas Färber SysBusDevice parent_obj;
51cc3e064eSAndreas Färber
5249ab747fSPaolo Bonzini MemoryRegion mmio;
5349ab747fSPaolo Bonzini qemu_irq parent_irq;
5449ab747fSPaolo Bonzini
5549ab747fSPaolo Bonzini /* Configuration reg chosen at synthesis-time. QEMU populates
5649ab747fSPaolo Bonzini the bits at board-setup. */
5749ab747fSPaolo Bonzini uint32_t c_kind_of_intr;
5849ab747fSPaolo Bonzini
5949ab747fSPaolo Bonzini /* Runtime control registers. */
6049ab747fSPaolo Bonzini uint32_t regs[R_MAX];
6145fdd3bfSPeter Crosthwaite /* state of the interrupt input pins */
6245fdd3bfSPeter Crosthwaite uint32_t irq_pin_state;
6349ab747fSPaolo Bonzini };
6449ab747fSPaolo Bonzini
update_irq(XpsIntc * p)65*d2960be0SPhilippe Mathieu-Daudé static void update_irq(XpsIntc *p)
6649ab747fSPaolo Bonzini {
6749ab747fSPaolo Bonzini uint32_t i;
6845fdd3bfSPeter Crosthwaite
6945fdd3bfSPeter Crosthwaite /* level triggered interrupt */
7045fdd3bfSPeter Crosthwaite if (p->regs[R_MER] & 2) {
7145fdd3bfSPeter Crosthwaite p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
7245fdd3bfSPeter Crosthwaite }
7345fdd3bfSPeter Crosthwaite
7449ab747fSPaolo Bonzini /* Update the pending register. */
7549ab747fSPaolo Bonzini p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
7649ab747fSPaolo Bonzini
7749ab747fSPaolo Bonzini /* Update the vector register. */
7849ab747fSPaolo Bonzini for (i = 0; i < 32; i++) {
790bc60bd7SPeter Maydell if (p->regs[R_IPR] & (1U << i)) {
8049ab747fSPaolo Bonzini break;
8149ab747fSPaolo Bonzini }
820bc60bd7SPeter Maydell }
8349ab747fSPaolo Bonzini if (i == 32)
8449ab747fSPaolo Bonzini i = ~0;
8549ab747fSPaolo Bonzini
8649ab747fSPaolo Bonzini p->regs[R_IVR] = i;
875c9f4336SPeter Crosthwaite qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
8849ab747fSPaolo Bonzini }
8949ab747fSPaolo Bonzini
pic_read(void * opaque,hwaddr addr,unsigned int size)90*d2960be0SPhilippe Mathieu-Daudé static uint64_t pic_read(void *opaque, hwaddr addr, unsigned int size)
9149ab747fSPaolo Bonzini {
92*d2960be0SPhilippe Mathieu-Daudé XpsIntc *p = opaque;
9349ab747fSPaolo Bonzini uint32_t r = 0;
9449ab747fSPaolo Bonzini
9549ab747fSPaolo Bonzini addr >>= 2;
9649ab747fSPaolo Bonzini switch (addr)
9749ab747fSPaolo Bonzini {
9849ab747fSPaolo Bonzini default:
9949ab747fSPaolo Bonzini if (addr < ARRAY_SIZE(p->regs))
10049ab747fSPaolo Bonzini r = p->regs[addr];
10149ab747fSPaolo Bonzini break;
10249ab747fSPaolo Bonzini
10349ab747fSPaolo Bonzini }
10449ab747fSPaolo Bonzini D(printf("%s %x=%x\n", __func__, addr * 4, r));
10549ab747fSPaolo Bonzini return r;
10649ab747fSPaolo Bonzini }
10749ab747fSPaolo Bonzini
pic_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)108*d2960be0SPhilippe Mathieu-Daudé static void pic_write(void *opaque, hwaddr addr,
10949ab747fSPaolo Bonzini uint64_t val64, unsigned int size)
11049ab747fSPaolo Bonzini {
111*d2960be0SPhilippe Mathieu-Daudé XpsIntc *p = opaque;
11249ab747fSPaolo Bonzini uint32_t value = val64;
11349ab747fSPaolo Bonzini
11449ab747fSPaolo Bonzini addr >>= 2;
11549ab747fSPaolo Bonzini D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
11649ab747fSPaolo Bonzini switch (addr)
11749ab747fSPaolo Bonzini {
11849ab747fSPaolo Bonzini case R_IAR:
11949ab747fSPaolo Bonzini p->regs[R_ISR] &= ~value; /* ACK. */
12049ab747fSPaolo Bonzini break;
12149ab747fSPaolo Bonzini case R_SIE:
12249ab747fSPaolo Bonzini p->regs[R_IER] |= value; /* Atomic set ie. */
12349ab747fSPaolo Bonzini break;
12449ab747fSPaolo Bonzini case R_CIE:
12549ab747fSPaolo Bonzini p->regs[R_IER] &= ~value; /* Atomic clear ie. */
12649ab747fSPaolo Bonzini break;
12712f7fb60SGuenter Roeck case R_MER:
12812f7fb60SGuenter Roeck p->regs[R_MER] = value & 0x3;
12912f7fb60SGuenter Roeck break;
130fa96d614SPeter Crosthwaite case R_ISR:
131fa96d614SPeter Crosthwaite if ((p->regs[R_MER] & 2)) {
132fa96d614SPeter Crosthwaite break;
133fa96d614SPeter Crosthwaite }
134fa96d614SPeter Crosthwaite /* fallthrough */
13549ab747fSPaolo Bonzini default:
13649ab747fSPaolo Bonzini if (addr < ARRAY_SIZE(p->regs))
13749ab747fSPaolo Bonzini p->regs[addr] = value;
13849ab747fSPaolo Bonzini break;
13949ab747fSPaolo Bonzini }
14049ab747fSPaolo Bonzini update_irq(p);
14149ab747fSPaolo Bonzini }
14249ab747fSPaolo Bonzini
14349ab747fSPaolo Bonzini static const MemoryRegionOps pic_ops = {
14449ab747fSPaolo Bonzini .read = pic_read,
14549ab747fSPaolo Bonzini .write = pic_write,
14649ab747fSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
14749ab747fSPaolo Bonzini .valid = {
14849ab747fSPaolo Bonzini .min_access_size = 4,
14949ab747fSPaolo Bonzini .max_access_size = 4
15049ab747fSPaolo Bonzini }
15149ab747fSPaolo Bonzini };
15249ab747fSPaolo Bonzini
irq_handler(void * opaque,int irq,int level)15349ab747fSPaolo Bonzini static void irq_handler(void *opaque, int irq, int level)
15449ab747fSPaolo Bonzini {
155*d2960be0SPhilippe Mathieu-Daudé XpsIntc *p = opaque;
15649ab747fSPaolo Bonzini
15745fdd3bfSPeter Crosthwaite /* edge triggered interrupt */
15845fdd3bfSPeter Crosthwaite if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
15949ab747fSPaolo Bonzini p->regs[R_ISR] |= (level << irq);
16045fdd3bfSPeter Crosthwaite }
16145fdd3bfSPeter Crosthwaite
16245fdd3bfSPeter Crosthwaite p->irq_pin_state &= ~(1 << irq);
16345fdd3bfSPeter Crosthwaite p->irq_pin_state |= level << irq;
16449ab747fSPaolo Bonzini update_irq(p);
16549ab747fSPaolo Bonzini }
16649ab747fSPaolo Bonzini
xilinx_intc_init(Object * obj)167a373cdb5SPeter Crosthwaite static void xilinx_intc_init(Object *obj)
16849ab747fSPaolo Bonzini {
169*d2960be0SPhilippe Mathieu-Daudé XpsIntc *p = XILINX_INTC(obj);
17049ab747fSPaolo Bonzini
171a373cdb5SPeter Crosthwaite qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
172a373cdb5SPeter Crosthwaite sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq);
17349ab747fSPaolo Bonzini
174a373cdb5SPeter Crosthwaite memory_region_init_io(&p->mmio, obj, &pic_ops, p, "xlnx.xps-intc",
1751437c94bSPaolo Bonzini R_MAX * 4);
176a373cdb5SPeter Crosthwaite sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
17749ab747fSPaolo Bonzini }
17849ab747fSPaolo Bonzini
17949ab747fSPaolo Bonzini static Property xilinx_intc_properties[] = {
180*d2960be0SPhilippe Mathieu-Daudé DEFINE_PROP_UINT32("kind-of-intr", XpsIntc, c_kind_of_intr, 0),
18149ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
18249ab747fSPaolo Bonzini };
18349ab747fSPaolo Bonzini
xilinx_intc_class_init(ObjectClass * klass,void * data)18449ab747fSPaolo Bonzini static void xilinx_intc_class_init(ObjectClass *klass, void *data)
18549ab747fSPaolo Bonzini {
18649ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
18749ab747fSPaolo Bonzini
1884f67d30bSMarc-André Lureau device_class_set_props(dc, xilinx_intc_properties);
18949ab747fSPaolo Bonzini }
19049ab747fSPaolo Bonzini
19149ab747fSPaolo Bonzini static const TypeInfo xilinx_intc_info = {
192cc3e064eSAndreas Färber .name = TYPE_XILINX_INTC,
19349ab747fSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
194*d2960be0SPhilippe Mathieu-Daudé .instance_size = sizeof(XpsIntc),
195a373cdb5SPeter Crosthwaite .instance_init = xilinx_intc_init,
19649ab747fSPaolo Bonzini .class_init = xilinx_intc_class_init,
19749ab747fSPaolo Bonzini };
19849ab747fSPaolo Bonzini
xilinx_intc_register_types(void)19949ab747fSPaolo Bonzini static void xilinx_intc_register_types(void)
20049ab747fSPaolo Bonzini {
20149ab747fSPaolo Bonzini type_register_static(&xilinx_intc_info);
20249ab747fSPaolo Bonzini }
20349ab747fSPaolo Bonzini
20449ab747fSPaolo Bonzini type_init(xilinx_intc_register_types)
205