xref: /openbmc/qemu/hw/intc/xilinx_intc.c (revision 886fb67020e32ce6a2cf7049c6f017acf1f0d69a)
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