root / hw / mpcore.c @ 4f4cc0ef
History | View | Annotate | Download (9.2 kB)
1 | 9ee6e8bb | pbrook | /*
|
---|---|---|---|
2 | 9ee6e8bb | pbrook | * ARM MPCore internal peripheral emulation.
|
3 | 9ee6e8bb | pbrook | *
|
4 | 9ee6e8bb | pbrook | * Copyright (c) 2006-2007 CodeSourcery.
|
5 | 9ee6e8bb | pbrook | * Written by Paul Brook
|
6 | 9ee6e8bb | pbrook | *
|
7 | 9ee6e8bb | pbrook | * This code is licenced under the GPL.
|
8 | 9ee6e8bb | pbrook | */
|
9 | 9ee6e8bb | pbrook | |
10 | fe7e8758 | Paul Brook | #include "sysbus.h" |
11 | 87ecb68b | pbrook | #include "qemu-timer.h" |
12 | 9ee6e8bb | pbrook | |
13 | 9ee6e8bb | pbrook | #define MPCORE_PRIV_BASE 0x10100000 |
14 | 9ee6e8bb | pbrook | #define NCPU 4 |
15 | 9ee6e8bb | pbrook | /* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
|
16 | 9ee6e8bb | pbrook | (+ 32 internal). However my test chip only exposes/reports 32.
|
17 | 9ee6e8bb | pbrook | More importantly Linux falls over if more than 32 are present! */
|
18 | 9ee6e8bb | pbrook | #define GIC_NIRQ 64 |
19 | 9ee6e8bb | pbrook | |
20 | 9ee6e8bb | pbrook | static inline int |
21 | 9ee6e8bb | pbrook | gic_get_current_cpu(void)
|
22 | 9ee6e8bb | pbrook | { |
23 | 9ee6e8bb | pbrook | return cpu_single_env->cpu_index;
|
24 | 9ee6e8bb | pbrook | } |
25 | 9ee6e8bb | pbrook | |
26 | 9ee6e8bb | pbrook | #include "arm_gic.c" |
27 | 9ee6e8bb | pbrook | |
28 | 9ee6e8bb | pbrook | /* MPCore private memory region. */
|
29 | 9ee6e8bb | pbrook | |
30 | 9ee6e8bb | pbrook | typedef struct { |
31 | 9ee6e8bb | pbrook | uint32_t count; |
32 | 9ee6e8bb | pbrook | uint32_t load; |
33 | 9ee6e8bb | pbrook | uint32_t control; |
34 | 9ee6e8bb | pbrook | uint32_t status; |
35 | 9ee6e8bb | pbrook | uint32_t old_status; |
36 | 9ee6e8bb | pbrook | int64_t tick; |
37 | 9ee6e8bb | pbrook | QEMUTimer *timer; |
38 | 9ee6e8bb | pbrook | struct mpcore_priv_state *mpcore;
|
39 | 9ee6e8bb | pbrook | int id; /* Encodes both timer/watchdog and CPU. */ |
40 | 9ee6e8bb | pbrook | } mpcore_timer_state; |
41 | 9ee6e8bb | pbrook | |
42 | 9ee6e8bb | pbrook | typedef struct mpcore_priv_state { |
43 | fe7e8758 | Paul Brook | gic_state gic; |
44 | 9ee6e8bb | pbrook | uint32_t scu_control; |
45 | fe7e8758 | Paul Brook | int iomemtype;
|
46 | 9ee6e8bb | pbrook | mpcore_timer_state timer[8];
|
47 | 9ee6e8bb | pbrook | } mpcore_priv_state; |
48 | 9ee6e8bb | pbrook | |
49 | 9ee6e8bb | pbrook | /* Per-CPU Timers. */
|
50 | 9ee6e8bb | pbrook | |
51 | 9ee6e8bb | pbrook | static inline void mpcore_timer_update_irq(mpcore_timer_state *s) |
52 | 9ee6e8bb | pbrook | { |
53 | 9ee6e8bb | pbrook | if (s->status & ~s->old_status) {
|
54 | fe7e8758 | Paul Brook | gic_set_pending_private(&s->mpcore->gic, s->id >> 1, 29 + (s->id & 1)); |
55 | 9ee6e8bb | pbrook | } |
56 | 9ee6e8bb | pbrook | s->old_status = s->status; |
57 | 9ee6e8bb | pbrook | } |
58 | 9ee6e8bb | pbrook | |
59 | 9ee6e8bb | pbrook | /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */
|
60 | 9ee6e8bb | pbrook | static inline uint32_t mpcore_timer_scale(mpcore_timer_state *s) |
61 | 9ee6e8bb | pbrook | { |
62 | 9ee6e8bb | pbrook | return (((s->control >> 8) & 0xff) + 1) * 10; |
63 | 9ee6e8bb | pbrook | } |
64 | 9ee6e8bb | pbrook | |
65 | 9ee6e8bb | pbrook | static void mpcore_timer_reload(mpcore_timer_state *s, int restart) |
66 | 9ee6e8bb | pbrook | { |
67 | 9ee6e8bb | pbrook | if (s->count == 0) |
68 | 9ee6e8bb | pbrook | return;
|
69 | 9ee6e8bb | pbrook | if (restart)
|
70 | 9ee6e8bb | pbrook | s->tick = qemu_get_clock(vm_clock); |
71 | 9ee6e8bb | pbrook | s->tick += (int64_t)s->count * mpcore_timer_scale(s); |
72 | 9ee6e8bb | pbrook | qemu_mod_timer(s->timer, s->tick); |
73 | 9ee6e8bb | pbrook | } |
74 | 9ee6e8bb | pbrook | |
75 | 9ee6e8bb | pbrook | static void mpcore_timer_tick(void *opaque) |
76 | 9ee6e8bb | pbrook | { |
77 | 9ee6e8bb | pbrook | mpcore_timer_state *s = (mpcore_timer_state *)opaque; |
78 | 9ee6e8bb | pbrook | s->status = 1;
|
79 | 9ee6e8bb | pbrook | if (s->control & 2) { |
80 | 9ee6e8bb | pbrook | s->count = s->load; |
81 | 9ee6e8bb | pbrook | mpcore_timer_reload(s, 0);
|
82 | 9ee6e8bb | pbrook | } else {
|
83 | 9ee6e8bb | pbrook | s->count = 0;
|
84 | 9ee6e8bb | pbrook | } |
85 | 9ee6e8bb | pbrook | mpcore_timer_update_irq(s); |
86 | 9ee6e8bb | pbrook | } |
87 | 9ee6e8bb | pbrook | |
88 | 9ee6e8bb | pbrook | static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset) |
89 | 9ee6e8bb | pbrook | { |
90 | 9ee6e8bb | pbrook | int64_t val; |
91 | 9ee6e8bb | pbrook | switch (offset) {
|
92 | 9ee6e8bb | pbrook | case 0: /* Load */ |
93 | 9ee6e8bb | pbrook | return s->load;
|
94 | 9ee6e8bb | pbrook | /* Fall through. */
|
95 | 9ee6e8bb | pbrook | case 4: /* Counter. */ |
96 | 9ee6e8bb | pbrook | if (((s->control & 1) == 0) || (s->count == 0)) |
97 | 9ee6e8bb | pbrook | return 0; |
98 | 9ee6e8bb | pbrook | /* Slow and ugly, but hopefully won't happen too often. */
|
99 | 9ee6e8bb | pbrook | val = s->tick - qemu_get_clock(vm_clock); |
100 | 9ee6e8bb | pbrook | val /= mpcore_timer_scale(s); |
101 | 9ee6e8bb | pbrook | if (val < 0) |
102 | 9ee6e8bb | pbrook | val = 0;
|
103 | 9ee6e8bb | pbrook | return val;
|
104 | 9ee6e8bb | pbrook | case 8: /* Control. */ |
105 | 9ee6e8bb | pbrook | return s->control;
|
106 | 9ee6e8bb | pbrook | case 12: /* Interrupt status. */ |
107 | 9ee6e8bb | pbrook | return s->status;
|
108 | a38131b6 | blueswir1 | default:
|
109 | a38131b6 | blueswir1 | return 0; |
110 | 9ee6e8bb | pbrook | } |
111 | 9ee6e8bb | pbrook | } |
112 | 9ee6e8bb | pbrook | |
113 | 9ee6e8bb | pbrook | static void mpcore_timer_write(mpcore_timer_state *s, int offset, |
114 | 9ee6e8bb | pbrook | uint32_t value) |
115 | 9ee6e8bb | pbrook | { |
116 | 9ee6e8bb | pbrook | int64_t old; |
117 | 9ee6e8bb | pbrook | switch (offset) {
|
118 | 9ee6e8bb | pbrook | case 0: /* Load */ |
119 | 9ee6e8bb | pbrook | s->load = value; |
120 | 9ee6e8bb | pbrook | /* Fall through. */
|
121 | 9ee6e8bb | pbrook | case 4: /* Counter. */ |
122 | 9ee6e8bb | pbrook | if ((s->control & 1) && s->count) { |
123 | 9ee6e8bb | pbrook | /* Cancel the previous timer. */
|
124 | 9ee6e8bb | pbrook | qemu_del_timer(s->timer); |
125 | 9ee6e8bb | pbrook | } |
126 | 9ee6e8bb | pbrook | s->count = value; |
127 | 9ee6e8bb | pbrook | if (s->control & 1) { |
128 | 9ee6e8bb | pbrook | mpcore_timer_reload(s, 1);
|
129 | 9ee6e8bb | pbrook | } |
130 | 9ee6e8bb | pbrook | break;
|
131 | 9ee6e8bb | pbrook | case 8: /* Control. */ |
132 | 9ee6e8bb | pbrook | old = s->control; |
133 | 9ee6e8bb | pbrook | s->control = value; |
134 | 9ee6e8bb | pbrook | if (((old & 1) == 0) && (value & 1)) { |
135 | 9ee6e8bb | pbrook | if (s->count == 0 && (s->control & 2)) |
136 | 9ee6e8bb | pbrook | s->count = s->load; |
137 | 9ee6e8bb | pbrook | mpcore_timer_reload(s, 1);
|
138 | 9ee6e8bb | pbrook | } |
139 | 9ee6e8bb | pbrook | break;
|
140 | 9ee6e8bb | pbrook | case 12: /* Interrupt status. */ |
141 | 9ee6e8bb | pbrook | s->status &= ~value; |
142 | 9ee6e8bb | pbrook | mpcore_timer_update_irq(s); |
143 | 9ee6e8bb | pbrook | break;
|
144 | 9ee6e8bb | pbrook | } |
145 | 9ee6e8bb | pbrook | } |
146 | 9ee6e8bb | pbrook | |
147 | 9ee6e8bb | pbrook | static void mpcore_timer_init(mpcore_priv_state *mpcore, |
148 | 9ee6e8bb | pbrook | mpcore_timer_state *s, int id)
|
149 | 9ee6e8bb | pbrook | { |
150 | 9ee6e8bb | pbrook | s->id = id; |
151 | 9ee6e8bb | pbrook | s->mpcore = mpcore; |
152 | 9ee6e8bb | pbrook | s->timer = qemu_new_timer(vm_clock, mpcore_timer_tick, s); |
153 | 9ee6e8bb | pbrook | } |
154 | 9ee6e8bb | pbrook | |
155 | 9ee6e8bb | pbrook | |
156 | 9ee6e8bb | pbrook | /* Per-CPU private memory mapped IO. */
|
157 | 9ee6e8bb | pbrook | |
158 | 9ee6e8bb | pbrook | static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset) |
159 | 9ee6e8bb | pbrook | { |
160 | 9ee6e8bb | pbrook | mpcore_priv_state *s = (mpcore_priv_state *)opaque; |
161 | 9ee6e8bb | pbrook | int id;
|
162 | 9ee6e8bb | pbrook | offset &= 0xfff;
|
163 | 9ee6e8bb | pbrook | if (offset < 0x100) { |
164 | 9ee6e8bb | pbrook | /* SCU */
|
165 | 9ee6e8bb | pbrook | switch (offset) {
|
166 | 9ee6e8bb | pbrook | case 0x00: /* Control. */ |
167 | 9ee6e8bb | pbrook | return s->scu_control;
|
168 | 9ee6e8bb | pbrook | case 0x04: /* Configuration. */ |
169 | 9ee6e8bb | pbrook | return 0xf3; |
170 | 9ee6e8bb | pbrook | case 0x08: /* CPU status. */ |
171 | 9ee6e8bb | pbrook | return 0; |
172 | 9ee6e8bb | pbrook | case 0x0c: /* Invalidate all. */ |
173 | 9ee6e8bb | pbrook | return 0; |
174 | 9ee6e8bb | pbrook | default:
|
175 | 9ee6e8bb | pbrook | goto bad_reg;
|
176 | 9ee6e8bb | pbrook | } |
177 | 9ee6e8bb | pbrook | } else if (offset < 0x600) { |
178 | 9ee6e8bb | pbrook | /* Interrupt controller. */
|
179 | 9ee6e8bb | pbrook | if (offset < 0x200) { |
180 | 9ee6e8bb | pbrook | id = gic_get_current_cpu(); |
181 | 9ee6e8bb | pbrook | } else {
|
182 | 9ee6e8bb | pbrook | id = (offset - 0x200) >> 8; |
183 | 9ee6e8bb | pbrook | } |
184 | fe7e8758 | Paul Brook | return gic_cpu_read(&s->gic, id, offset & 0xff); |
185 | 9ee6e8bb | pbrook | } else if (offset < 0xb00) { |
186 | 9ee6e8bb | pbrook | /* Timers. */
|
187 | 9ee6e8bb | pbrook | if (offset < 0x700) { |
188 | 9ee6e8bb | pbrook | id = gic_get_current_cpu(); |
189 | 9ee6e8bb | pbrook | } else {
|
190 | 9ee6e8bb | pbrook | id = (offset - 0x700) >> 8; |
191 | 9ee6e8bb | pbrook | } |
192 | 9ee6e8bb | pbrook | id <<= 1;
|
193 | 9ee6e8bb | pbrook | if (offset & 0x20) |
194 | 9ee6e8bb | pbrook | id++; |
195 | 9ee6e8bb | pbrook | return mpcore_timer_read(&s->timer[id], offset & 0xf); |
196 | 9ee6e8bb | pbrook | } |
197 | 9ee6e8bb | pbrook | bad_reg:
|
198 | 2ac71179 | Paul Brook | hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset); |
199 | 9ee6e8bb | pbrook | return 0; |
200 | 9ee6e8bb | pbrook | } |
201 | 9ee6e8bb | pbrook | |
202 | 9ee6e8bb | pbrook | static void mpcore_priv_write(void *opaque, target_phys_addr_t offset, |
203 | 9ee6e8bb | pbrook | uint32_t value) |
204 | 9ee6e8bb | pbrook | { |
205 | 9ee6e8bb | pbrook | mpcore_priv_state *s = (mpcore_priv_state *)opaque; |
206 | 9ee6e8bb | pbrook | int id;
|
207 | 9ee6e8bb | pbrook | offset &= 0xfff;
|
208 | 9ee6e8bb | pbrook | if (offset < 0x100) { |
209 | 9ee6e8bb | pbrook | /* SCU */
|
210 | 9ee6e8bb | pbrook | switch (offset) {
|
211 | 9ee6e8bb | pbrook | case 0: /* Control register. */ |
212 | 9ee6e8bb | pbrook | s->scu_control = value & 1;
|
213 | 9ee6e8bb | pbrook | break;
|
214 | 9ee6e8bb | pbrook | case 0x0c: /* Invalidate all. */ |
215 | 9ee6e8bb | pbrook | /* This is a no-op as cache is not emulated. */
|
216 | 9ee6e8bb | pbrook | break;
|
217 | 9ee6e8bb | pbrook | default:
|
218 | 9ee6e8bb | pbrook | goto bad_reg;
|
219 | 9ee6e8bb | pbrook | } |
220 | 9ee6e8bb | pbrook | } else if (offset < 0x600) { |
221 | 9ee6e8bb | pbrook | /* Interrupt controller. */
|
222 | 9ee6e8bb | pbrook | if (offset < 0x200) { |
223 | 9ee6e8bb | pbrook | id = gic_get_current_cpu(); |
224 | 9ee6e8bb | pbrook | } else {
|
225 | 9ee6e8bb | pbrook | id = (offset - 0x200) >> 8; |
226 | 9ee6e8bb | pbrook | } |
227 | fe7e8758 | Paul Brook | gic_cpu_write(&s->gic, id, offset & 0xff, value);
|
228 | 9ee6e8bb | pbrook | } else if (offset < 0xb00) { |
229 | 9ee6e8bb | pbrook | /* Timers. */
|
230 | 9ee6e8bb | pbrook | if (offset < 0x700) { |
231 | 9ee6e8bb | pbrook | id = gic_get_current_cpu(); |
232 | 9ee6e8bb | pbrook | } else {
|
233 | 9ee6e8bb | pbrook | id = (offset - 0x700) >> 8; |
234 | 9ee6e8bb | pbrook | } |
235 | 9ee6e8bb | pbrook | id <<= 1;
|
236 | 9ee6e8bb | pbrook | if (offset & 0x20) |
237 | 9ee6e8bb | pbrook | id++; |
238 | 9ee6e8bb | pbrook | mpcore_timer_write(&s->timer[id], offset & 0xf, value);
|
239 | 9ee6e8bb | pbrook | return;
|
240 | 9ee6e8bb | pbrook | } |
241 | 9ee6e8bb | pbrook | return;
|
242 | 9ee6e8bb | pbrook | bad_reg:
|
243 | 2ac71179 | Paul Brook | hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset); |
244 | 9ee6e8bb | pbrook | } |
245 | 9ee6e8bb | pbrook | |
246 | d60efc6b | Blue Swirl | static CPUReadMemoryFunc * const mpcore_priv_readfn[] = { |
247 | 9ee6e8bb | pbrook | mpcore_priv_read, |
248 | 9ee6e8bb | pbrook | mpcore_priv_read, |
249 | 9ee6e8bb | pbrook | mpcore_priv_read |
250 | 9ee6e8bb | pbrook | }; |
251 | 9ee6e8bb | pbrook | |
252 | d60efc6b | Blue Swirl | static CPUWriteMemoryFunc * const mpcore_priv_writefn[] = { |
253 | 9ee6e8bb | pbrook | mpcore_priv_write, |
254 | 9ee6e8bb | pbrook | mpcore_priv_write, |
255 | 9ee6e8bb | pbrook | mpcore_priv_write |
256 | 9ee6e8bb | pbrook | }; |
257 | 9ee6e8bb | pbrook | |
258 | fe7e8758 | Paul Brook | static void mpcore_priv_map(SysBusDevice *dev, target_phys_addr_t base) |
259 | fe7e8758 | Paul Brook | { |
260 | fe7e8758 | Paul Brook | mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); |
261 | fe7e8758 | Paul Brook | cpu_register_physical_memory(base, 0x1000, s->iomemtype);
|
262 | fe7e8758 | Paul Brook | cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype); |
263 | fe7e8758 | Paul Brook | } |
264 | 9ee6e8bb | pbrook | |
265 | 81a322d4 | Gerd Hoffmann | static int mpcore_priv_init(SysBusDevice *dev) |
266 | 9ee6e8bb | pbrook | { |
267 | fe7e8758 | Paul Brook | mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); |
268 | 9ee6e8bb | pbrook | int i;
|
269 | 9ee6e8bb | pbrook | |
270 | fe7e8758 | Paul Brook | gic_init(&s->gic); |
271 | 1eed09cb | Avi Kivity | s->iomemtype = cpu_register_io_memory(mpcore_priv_readfn, |
272 | fe7e8758 | Paul Brook | mpcore_priv_writefn, s); |
273 | fe7e8758 | Paul Brook | sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map);
|
274 | 9ee6e8bb | pbrook | for (i = 0; i < 8; i++) { |
275 | 9ee6e8bb | pbrook | mpcore_timer_init(s, &s->timer[i], i); |
276 | 9ee6e8bb | pbrook | } |
277 | 81a322d4 | Gerd Hoffmann | return 0; |
278 | 9ee6e8bb | pbrook | } |
279 | 9ee6e8bb | pbrook | |
280 | 9ee6e8bb | pbrook | /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
|
281 | 9ee6e8bb | pbrook | controllers. The output of these, plus some of the raw input lines
|
282 | 9ee6e8bb | pbrook | are fed into a single SMP-aware interrupt controller on the CPU. */
|
283 | 9ee6e8bb | pbrook | typedef struct { |
284 | fe7e8758 | Paul Brook | SysBusDevice busdev; |
285 | fe7e8758 | Paul Brook | qemu_irq cpuic[32];
|
286 | fe7e8758 | Paul Brook | qemu_irq rvic[4][64]; |
287 | 9ee6e8bb | pbrook | } mpcore_rirq_state; |
288 | 9ee6e8bb | pbrook | |
289 | 9ee6e8bb | pbrook | /* Map baseboard IRQs onto CPU IRQ lines. */
|
290 | 9ee6e8bb | pbrook | static const int mpcore_irq_map[32] = { |
291 | 9ee6e8bb | pbrook | -1, -1, -1, -1, 1, 2, -1, -1, |
292 | 9ee6e8bb | pbrook | -1, -1, 6, -1, 4, 5, -1, -1, |
293 | 9ee6e8bb | pbrook | -1, 14, 15, 0, 7, 8, -1, -1, |
294 | 9ee6e8bb | pbrook | -1, -1, -1, -1, 9, 3, -1, -1, |
295 | 9ee6e8bb | pbrook | }; |
296 | 9ee6e8bb | pbrook | |
297 | 9ee6e8bb | pbrook | static void mpcore_rirq_set_irq(void *opaque, int irq, int level) |
298 | 9ee6e8bb | pbrook | { |
299 | 9ee6e8bb | pbrook | mpcore_rirq_state *s = (mpcore_rirq_state *)opaque; |
300 | 9ee6e8bb | pbrook | int i;
|
301 | 9ee6e8bb | pbrook | |
302 | 9ee6e8bb | pbrook | for (i = 0; i < 4; i++) { |
303 | 9ee6e8bb | pbrook | qemu_set_irq(s->rvic[i][irq], level); |
304 | 9ee6e8bb | pbrook | } |
305 | 9ee6e8bb | pbrook | if (irq < 32) { |
306 | 9ee6e8bb | pbrook | irq = mpcore_irq_map[irq]; |
307 | 9ee6e8bb | pbrook | if (irq >= 0) { |
308 | 9ee6e8bb | pbrook | qemu_set_irq(s->cpuic[irq], level); |
309 | 9ee6e8bb | pbrook | } |
310 | 9ee6e8bb | pbrook | } |
311 | 9ee6e8bb | pbrook | } |
312 | 9ee6e8bb | pbrook | |
313 | 81a322d4 | Gerd Hoffmann | static int realview_mpcore_init(SysBusDevice *dev) |
314 | 9ee6e8bb | pbrook | { |
315 | fe7e8758 | Paul Brook | mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev); |
316 | fe7e8758 | Paul Brook | DeviceState *gic; |
317 | fe7e8758 | Paul Brook | DeviceState *priv; |
318 | 9ee6e8bb | pbrook | int n;
|
319 | fe7e8758 | Paul Brook | int i;
|
320 | 9ee6e8bb | pbrook | |
321 | fe7e8758 | Paul Brook | priv = sysbus_create_simple("arm11mpcore_priv", MPCORE_PRIV_BASE, NULL); |
322 | fe7e8758 | Paul Brook | sysbus_pass_irq(dev, sysbus_from_qdev(priv)); |
323 | fe7e8758 | Paul Brook | for (i = 0; i < 32; i++) { |
324 | 067a3ddc | Paul Brook | s->cpuic[i] = qdev_get_gpio_in(priv, i); |
325 | fe7e8758 | Paul Brook | } |
326 | 9ee6e8bb | pbrook | /* ??? IRQ routing is hardcoded to "normal" mode. */
|
327 | 9ee6e8bb | pbrook | for (n = 0; n < 4; n++) { |
328 | fe7e8758 | Paul Brook | gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000, |
329 | fe7e8758 | Paul Brook | s->cpuic[10 + n]);
|
330 | fe7e8758 | Paul Brook | for (i = 0; i < 64; i++) { |
331 | 067a3ddc | Paul Brook | s->rvic[n][i] = qdev_get_gpio_in(gic, i); |
332 | fe7e8758 | Paul Brook | } |
333 | 9ee6e8bb | pbrook | } |
334 | 067a3ddc | Paul Brook | qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
|
335 | 81a322d4 | Gerd Hoffmann | return 0; |
336 | 9ee6e8bb | pbrook | } |
337 | fe7e8758 | Paul Brook | |
338 | fe7e8758 | Paul Brook | static void mpcore_register_devices(void) |
339 | fe7e8758 | Paul Brook | { |
340 | fe7e8758 | Paul Brook | sysbus_register_dev("realview_mpcore", sizeof(mpcore_rirq_state), |
341 | fe7e8758 | Paul Brook | realview_mpcore_init); |
342 | fe7e8758 | Paul Brook | sysbus_register_dev("arm11mpcore_priv", sizeof(mpcore_priv_state), |
343 | fe7e8758 | Paul Brook | mpcore_priv_init); |
344 | fe7e8758 | Paul Brook | } |
345 | fe7e8758 | Paul Brook | |
346 | fe7e8758 | Paul Brook | device_init(mpcore_register_devices) |