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