xilinx: Add interrupt controller.
[qemu] / hw / xilinx_intc.c
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 "sysbus.h"
26 #include "hw.h"
27
28 #define D(x)
29
30 #define R_ISR       0
31 #define R_IPR       1
32 #define R_IER       2
33 #define R_IAR       3
34 #define R_SIE       4
35 #define R_CIE       5
36 #define R_IVR       6
37 #define R_MER       7
38 #define R_MAX       8
39
40 struct xlx_pic
41 {
42     SysBusDevice busdev;
43     qemu_irq parent_irq;
44
45     /* Configuration reg chosen at synthesis-time. QEMU populates
46        the bits at board-setup.  */
47     uint32_t c_kind_of_intr;
48
49     /* Runtime control registers.  */
50     uint32_t regs[R_MAX];
51 };
52
53 static void update_irq(struct xlx_pic *p)
54 {
55     uint32_t i;
56     /* Update the pending register.  */
57     p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
58
59     /* Update the vector register.  */
60     for (i = 0; i < 32; i++) {
61         if (p->regs[R_IPR] & (1 << i))
62             break;
63     }
64     if (i == 32)
65         i = ~0;
66
67     p->regs[R_IVR] = i;
68     if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) {
69         qemu_irq_raise(p->parent_irq);
70     } else {
71         qemu_irq_lower(p->parent_irq);
72     }
73 }
74
75 static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
76 {
77     struct xlx_pic *p = opaque;
78     uint32_t r = 0;
79
80     addr >>= 2;
81     switch (addr)
82     {
83         default:
84             if (addr < ARRAY_SIZE(p->regs))
85                 r = p->regs[addr];
86             break;
87
88     }
89     D(printf("%s %x=%x\n", __func__, addr * 4, r));
90     return r;
91 }
92
93 static void
94 pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
95 {
96     struct xlx_pic *p = opaque;
97
98     addr >>= 2;
99     D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
100     switch (addr) 
101     {
102         case R_IAR:
103             p->regs[R_ISR] &= ~value; /* ACK.  */
104             break;
105         case R_SIE:
106             p->regs[R_IER] |= value;  /* Atomic set ie.  */
107             break;
108         case R_CIE:
109             p->regs[R_IER] &= ~value; /* Atomic clear ie.  */
110             break;
111         default:
112             if (addr < ARRAY_SIZE(p->regs))
113                 p->regs[addr] = value;
114             break;
115     }
116     update_irq(p);
117 }
118
119 static CPUReadMemoryFunc *pic_read[] = {
120     NULL, NULL,
121     &pic_readl,
122 };
123
124 static CPUWriteMemoryFunc *pic_write[] = {
125     NULL, NULL,
126     &pic_writel,
127 };
128
129 static void irq_handler(void *opaque, int irq, int level)
130 {
131     struct xlx_pic *p = opaque;
132
133     if (!(p->regs[R_MER] & 2)) {
134         qemu_irq_lower(p->parent_irq);
135         return;
136     }
137
138     /* Update source flops. Don't clear unless level triggered.
139        Edge triggered interrupts only go away when explicitely acked to
140        the interrupt controller.  */
141     if (!(p->c_kind_of_intr & (1 << irq)) || level) {
142         p->regs[R_ISR] &= ~(1 << irq);
143         p->regs[R_ISR] |= (level << irq);
144     }
145     update_irq(p);
146 }
147
148 static void xilinx_intc_init(SysBusDevice *dev)
149 {
150     struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
151     int pic_regs;
152
153     p->c_kind_of_intr = qdev_get_prop_int(&dev->qdev, "kind-of-intr", 0);
154     qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
155     sysbus_init_irq(dev, &p->parent_irq);
156
157     pic_regs = cpu_register_io_memory(0, pic_read, pic_write, p);
158     sysbus_init_mmio(dev, R_MAX * 4, pic_regs);
159 }
160
161 static void xilinx_intc_register(void)
162 {
163     sysbus_register_dev("xilinx,intc", sizeof (struct xlx_pic),
164                         xilinx_intc_init);
165 }
166
167 device_init(xilinx_intc_register)