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