root / hw / xilinx_intc.c @ 84f15818
History | View | Annotate | Download (4.6 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 | 17628bc6 | Edgar E. Iglesias | qemu_irq parent_irq; |
44 | 17628bc6 | Edgar E. Iglesias | |
45 | 17628bc6 | Edgar E. Iglesias | /* Configuration reg chosen at synthesis-time. QEMU populates
|
46 | 17628bc6 | Edgar E. Iglesias | the bits at board-setup. */
|
47 | 17628bc6 | Edgar E. Iglesias | uint32_t c_kind_of_intr; |
48 | 17628bc6 | Edgar E. Iglesias | |
49 | 17628bc6 | Edgar E. Iglesias | /* Runtime control registers. */
|
50 | 17628bc6 | Edgar E. Iglesias | uint32_t regs[R_MAX]; |
51 | 17628bc6 | Edgar E. Iglesias | }; |
52 | 17628bc6 | Edgar E. Iglesias | |
53 | 17628bc6 | Edgar E. Iglesias | static void update_irq(struct xlx_pic *p) |
54 | 17628bc6 | Edgar E. Iglesias | { |
55 | 17628bc6 | Edgar E. Iglesias | uint32_t i; |
56 | 17628bc6 | Edgar E. Iglesias | /* Update the pending register. */
|
57 | 17628bc6 | Edgar E. Iglesias | p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER]; |
58 | 17628bc6 | Edgar E. Iglesias | |
59 | 17628bc6 | Edgar E. Iglesias | /* Update the vector register. */
|
60 | 17628bc6 | Edgar E. Iglesias | for (i = 0; i < 32; i++) { |
61 | 17628bc6 | Edgar E. Iglesias | if (p->regs[R_IPR] & (1 << i)) |
62 | 17628bc6 | Edgar E. Iglesias | break;
|
63 | 17628bc6 | Edgar E. Iglesias | } |
64 | 17628bc6 | Edgar E. Iglesias | if (i == 32) |
65 | 17628bc6 | Edgar E. Iglesias | i = ~0;
|
66 | 17628bc6 | Edgar E. Iglesias | |
67 | 17628bc6 | Edgar E. Iglesias | p->regs[R_IVR] = i; |
68 | 17628bc6 | Edgar E. Iglesias | if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) { |
69 | 17628bc6 | Edgar E. Iglesias | qemu_irq_raise(p->parent_irq); |
70 | 17628bc6 | Edgar E. Iglesias | } else {
|
71 | 17628bc6 | Edgar E. Iglesias | qemu_irq_lower(p->parent_irq); |
72 | 17628bc6 | Edgar E. Iglesias | } |
73 | 17628bc6 | Edgar E. Iglesias | } |
74 | 17628bc6 | Edgar E. Iglesias | |
75 | 17628bc6 | Edgar E. Iglesias | static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) |
76 | 17628bc6 | Edgar E. Iglesias | { |
77 | 17628bc6 | Edgar E. Iglesias | struct xlx_pic *p = opaque;
|
78 | 17628bc6 | Edgar E. Iglesias | uint32_t r = 0;
|
79 | 17628bc6 | Edgar E. Iglesias | |
80 | 17628bc6 | Edgar E. Iglesias | addr >>= 2;
|
81 | 17628bc6 | Edgar E. Iglesias | switch (addr)
|
82 | 17628bc6 | Edgar E. Iglesias | { |
83 | 17628bc6 | Edgar E. Iglesias | default:
|
84 | 17628bc6 | Edgar E. Iglesias | if (addr < ARRAY_SIZE(p->regs))
|
85 | 17628bc6 | Edgar E. Iglesias | r = p->regs[addr]; |
86 | 17628bc6 | Edgar E. Iglesias | break;
|
87 | 17628bc6 | Edgar E. Iglesias | |
88 | 17628bc6 | Edgar E. Iglesias | } |
89 | 17628bc6 | Edgar E. Iglesias | D(printf("%s %x=%x\n", __func__, addr * 4, r)); |
90 | 17628bc6 | Edgar E. Iglesias | return r;
|
91 | 17628bc6 | Edgar E. Iglesias | } |
92 | 17628bc6 | Edgar E. Iglesias | |
93 | 17628bc6 | Edgar E. Iglesias | static void |
94 | 17628bc6 | Edgar E. Iglesias | pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
95 | 17628bc6 | Edgar E. Iglesias | { |
96 | 17628bc6 | Edgar E. Iglesias | struct xlx_pic *p = opaque;
|
97 | 17628bc6 | Edgar E. Iglesias | |
98 | 17628bc6 | Edgar E. Iglesias | addr >>= 2;
|
99 | 17628bc6 | Edgar E. Iglesias | D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); |
100 | 17628bc6 | Edgar E. Iglesias | switch (addr)
|
101 | 17628bc6 | Edgar E. Iglesias | { |
102 | 17628bc6 | Edgar E. Iglesias | case R_IAR:
|
103 | 17628bc6 | Edgar E. Iglesias | p->regs[R_ISR] &= ~value; /* ACK. */
|
104 | 17628bc6 | Edgar E. Iglesias | break;
|
105 | 17628bc6 | Edgar E. Iglesias | case R_SIE:
|
106 | 17628bc6 | Edgar E. Iglesias | p->regs[R_IER] |= value; /* Atomic set ie. */
|
107 | 17628bc6 | Edgar E. Iglesias | break;
|
108 | 17628bc6 | Edgar E. Iglesias | case R_CIE:
|
109 | 17628bc6 | Edgar E. Iglesias | p->regs[R_IER] &= ~value; /* Atomic clear ie. */
|
110 | 17628bc6 | Edgar E. Iglesias | break;
|
111 | 17628bc6 | Edgar E. Iglesias | default:
|
112 | 17628bc6 | Edgar E. Iglesias | if (addr < ARRAY_SIZE(p->regs))
|
113 | 17628bc6 | Edgar E. Iglesias | p->regs[addr] = value; |
114 | 17628bc6 | Edgar E. Iglesias | break;
|
115 | 17628bc6 | Edgar E. Iglesias | } |
116 | 17628bc6 | Edgar E. Iglesias | update_irq(p); |
117 | 17628bc6 | Edgar E. Iglesias | } |
118 | 17628bc6 | Edgar E. Iglesias | |
119 | 17628bc6 | Edgar E. Iglesias | static CPUReadMemoryFunc *pic_read[] = {
|
120 | 17628bc6 | Edgar E. Iglesias | NULL, NULL, |
121 | 17628bc6 | Edgar E. Iglesias | &pic_readl, |
122 | 17628bc6 | Edgar E. Iglesias | }; |
123 | 17628bc6 | Edgar E. Iglesias | |
124 | 17628bc6 | Edgar E. Iglesias | static CPUWriteMemoryFunc *pic_write[] = {
|
125 | 17628bc6 | Edgar E. Iglesias | NULL, NULL, |
126 | 17628bc6 | Edgar E. Iglesias | &pic_writel, |
127 | 17628bc6 | Edgar E. Iglesias | }; |
128 | 17628bc6 | Edgar E. Iglesias | |
129 | 17628bc6 | Edgar E. Iglesias | static void irq_handler(void *opaque, int irq, int level) |
130 | 17628bc6 | Edgar E. Iglesias | { |
131 | 17628bc6 | Edgar E. Iglesias | struct xlx_pic *p = opaque;
|
132 | 17628bc6 | Edgar E. Iglesias | |
133 | 17628bc6 | Edgar E. Iglesias | if (!(p->regs[R_MER] & 2)) { |
134 | 17628bc6 | Edgar E. Iglesias | qemu_irq_lower(p->parent_irq); |
135 | 17628bc6 | Edgar E. Iglesias | return;
|
136 | 17628bc6 | Edgar E. Iglesias | } |
137 | 17628bc6 | Edgar E. Iglesias | |
138 | 17628bc6 | Edgar E. Iglesias | /* Update source flops. Don't clear unless level triggered.
|
139 | 17628bc6 | Edgar E. Iglesias | Edge triggered interrupts only go away when explicitely acked to
|
140 | 17628bc6 | Edgar E. Iglesias | the interrupt controller. */
|
141 | 17628bc6 | Edgar E. Iglesias | if (!(p->c_kind_of_intr & (1 << irq)) || level) { |
142 | 17628bc6 | Edgar E. Iglesias | p->regs[R_ISR] &= ~(1 << irq);
|
143 | 17628bc6 | Edgar E. Iglesias | p->regs[R_ISR] |= (level << irq); |
144 | 17628bc6 | Edgar E. Iglesias | } |
145 | 17628bc6 | Edgar E. Iglesias | update_irq(p); |
146 | 17628bc6 | Edgar E. Iglesias | } |
147 | 17628bc6 | Edgar E. Iglesias | |
148 | 17628bc6 | Edgar E. Iglesias | static void xilinx_intc_init(SysBusDevice *dev) |
149 | 17628bc6 | Edgar E. Iglesias | { |
150 | 17628bc6 | Edgar E. Iglesias | struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
|
151 | 17628bc6 | Edgar E. Iglesias | int pic_regs;
|
152 | 17628bc6 | Edgar E. Iglesias | |
153 | 17628bc6 | Edgar E. Iglesias | qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
|
154 | 17628bc6 | Edgar E. Iglesias | sysbus_init_irq(dev, &p->parent_irq); |
155 | 17628bc6 | Edgar E. Iglesias | |
156 | 1eed09cb | Avi Kivity | pic_regs = cpu_register_io_memory(pic_read, pic_write, p); |
157 | 17628bc6 | Edgar E. Iglesias | sysbus_init_mmio(dev, R_MAX * 4, pic_regs);
|
158 | 17628bc6 | Edgar E. Iglesias | } |
159 | 17628bc6 | Edgar E. Iglesias | |
160 | ee6847d1 | Gerd Hoffmann | static SysBusDeviceInfo xilinx_intc_info = {
|
161 | ee6847d1 | Gerd Hoffmann | .init = xilinx_intc_init, |
162 | ee6847d1 | Gerd Hoffmann | .qdev.name = "xilinx,intc",
|
163 | ee6847d1 | Gerd Hoffmann | .qdev.size = sizeof(struct xlx_pic), |
164 | ee6847d1 | Gerd Hoffmann | .qdev.props = (Property[]) { |
165 | ee6847d1 | Gerd Hoffmann | { |
166 | ee6847d1 | Gerd Hoffmann | .name = "kind-of-intr",
|
167 | ee6847d1 | Gerd Hoffmann | .info = &qdev_prop_uint32, |
168 | ee6847d1 | Gerd Hoffmann | .offset = offsetof(struct xlx_pic, c_kind_of_intr),
|
169 | ee6847d1 | Gerd Hoffmann | }, |
170 | ee6847d1 | Gerd Hoffmann | {/* end of list */}
|
171 | ee6847d1 | Gerd Hoffmann | } |
172 | ee6847d1 | Gerd Hoffmann | }; |
173 | ee6847d1 | Gerd Hoffmann | |
174 | 17628bc6 | Edgar E. Iglesias | static void xilinx_intc_register(void) |
175 | 17628bc6 | Edgar E. Iglesias | { |
176 | ee6847d1 | Gerd Hoffmann | sysbus_register_withprop(&xilinx_intc_info); |
177 | 17628bc6 | Edgar E. Iglesias | } |
178 | 17628bc6 | Edgar E. Iglesias | |
179 | 17628bc6 | Edgar E. Iglesias | device_init(xilinx_intc_register) |