Revision f7c70325 hw/mpcore.c
b/hw/mpcore.c | ||
---|---|---|
1 | 1 |
/* |
2 |
* ARM MPCore internal peripheral emulation. |
|
2 |
* ARM MPCore internal peripheral emulation (common code).
|
|
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2006-2007 CodeSourcery. |
5 | 5 |
* Written by Paul Brook |
... | ... | |
10 | 10 |
#include "sysbus.h" |
11 | 11 |
#include "qemu-timer.h" |
12 | 12 |
|
13 |
#define MPCORE_PRIV_BASE 0x10100000 |
|
14 | 13 |
#define NCPU 4 |
15 |
/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines |
|
16 |
(+ 32 internal). However my test chip only exposes/reports 32. |
|
17 |
More importantly Linux falls over if more than 32 are present! */ |
|
18 |
#define GIC_NIRQ 64 |
|
19 | 14 |
|
20 | 15 |
static inline int |
21 | 16 |
gic_get_current_cpu(void) |
... | ... | |
288 | 283 |
} |
289 | 284 |
return 0; |
290 | 285 |
} |
291 |
|
|
292 |
/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ |
|
293 |
controllers. The output of these, plus some of the raw input lines |
|
294 |
are fed into a single SMP-aware interrupt controller on the CPU. */ |
|
295 |
typedef struct { |
|
296 |
SysBusDevice busdev; |
|
297 |
qemu_irq cpuic[32]; |
|
298 |
qemu_irq rvic[4][64]; |
|
299 |
uint32_t num_cpu; |
|
300 |
} mpcore_rirq_state; |
|
301 |
|
|
302 |
/* Map baseboard IRQs onto CPU IRQ lines. */ |
|
303 |
static const int mpcore_irq_map[32] = { |
|
304 |
-1, -1, -1, -1, 1, 2, -1, -1, |
|
305 |
-1, -1, 6, -1, 4, 5, -1, -1, |
|
306 |
-1, 14, 15, 0, 7, 8, -1, -1, |
|
307 |
-1, -1, -1, -1, 9, 3, -1, -1, |
|
308 |
}; |
|
309 |
|
|
310 |
static void mpcore_rirq_set_irq(void *opaque, int irq, int level) |
|
311 |
{ |
|
312 |
mpcore_rirq_state *s = (mpcore_rirq_state *)opaque; |
|
313 |
int i; |
|
314 |
|
|
315 |
for (i = 0; i < 4; i++) { |
|
316 |
qemu_set_irq(s->rvic[i][irq], level); |
|
317 |
} |
|
318 |
if (irq < 32) { |
|
319 |
irq = mpcore_irq_map[irq]; |
|
320 |
if (irq >= 0) { |
|
321 |
qemu_set_irq(s->cpuic[irq], level); |
|
322 |
} |
|
323 |
} |
|
324 |
} |
|
325 |
|
|
326 |
static int realview_mpcore_init(SysBusDevice *dev) |
|
327 |
{ |
|
328 |
mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev); |
|
329 |
DeviceState *gic; |
|
330 |
DeviceState *priv; |
|
331 |
SysBusDevice *bus_priv; |
|
332 |
int n; |
|
333 |
int i; |
|
334 |
|
|
335 |
priv = qdev_create(NULL, "arm11mpcore_priv"); |
|
336 |
qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu); |
|
337 |
qdev_init_nofail(priv); |
|
338 |
bus_priv = sysbus_from_qdev(priv); |
|
339 |
sysbus_mmio_map(bus_priv, 0, MPCORE_PRIV_BASE); |
|
340 |
sysbus_pass_irq(dev, bus_priv); |
|
341 |
for (i = 0; i < 32; i++) { |
|
342 |
s->cpuic[i] = qdev_get_gpio_in(priv, i); |
|
343 |
} |
|
344 |
/* ??? IRQ routing is hardcoded to "normal" mode. */ |
|
345 |
for (n = 0; n < 4; n++) { |
|
346 |
gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000, |
|
347 |
s->cpuic[10 + n]); |
|
348 |
for (i = 0; i < 64; i++) { |
|
349 |
s->rvic[n][i] = qdev_get_gpio_in(gic, i); |
|
350 |
} |
|
351 |
} |
|
352 |
qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64); |
|
353 |
return 0; |
|
354 |
} |
|
355 |
|
|
356 |
static SysBusDeviceInfo mpcore_rirq_info = { |
|
357 |
.init = realview_mpcore_init, |
|
358 |
.qdev.name = "realview_mpcore", |
|
359 |
.qdev.size = sizeof(mpcore_rirq_state), |
|
360 |
.qdev.props = (Property[]) { |
|
361 |
DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1), |
|
362 |
DEFINE_PROP_END_OF_LIST(), |
|
363 |
} |
|
364 |
}; |
|
365 |
|
|
366 |
static SysBusDeviceInfo mpcore_priv_info = { |
|
367 |
.init = mpcore_priv_init, |
|
368 |
.qdev.name = "arm11mpcore_priv", |
|
369 |
.qdev.size = sizeof(mpcore_priv_state), |
|
370 |
.qdev.props = (Property[]) { |
|
371 |
DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), |
|
372 |
DEFINE_PROP_END_OF_LIST(), |
|
373 |
} |
|
374 |
}; |
|
375 |
|
|
376 |
static void mpcore_register_devices(void) |
|
377 |
{ |
|
378 |
sysbus_register_withprop(&mpcore_rirq_info); |
|
379 |
sysbus_register_withprop(&mpcore_priv_info); |
|
380 |
} |
|
381 |
|
|
382 |
device_init(mpcore_register_devices) |
Also available in: Unified diff