root / hw / arm11mpcore.c @ cde844fa
History | View | Annotate | Download (3.1 kB)
1 |
/*
|
---|---|
2 |
* ARM11MPCore internal peripheral emulation.
|
3 |
*
|
4 |
* Copyright (c) 2006-2007 CodeSourcery.
|
5 |
* Written by Paul Brook
|
6 |
*
|
7 |
* This code is licensed under the GPL.
|
8 |
*/
|
9 |
|
10 |
/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
|
11 |
(+ 32 internal). However my test chip only exposes/reports 32.
|
12 |
More importantly Linux falls over if more than 32 are present! */
|
13 |
#define GIC_NIRQ 64 |
14 |
#include "mpcore.c" |
15 |
|
16 |
/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
|
17 |
controllers. The output of these, plus some of the raw input lines
|
18 |
are fed into a single SMP-aware interrupt controller on the CPU. */
|
19 |
typedef struct { |
20 |
SysBusDevice busdev; |
21 |
SysBusDevice *priv; |
22 |
qemu_irq cpuic[32];
|
23 |
qemu_irq rvic[4][64]; |
24 |
uint32_t num_cpu; |
25 |
} mpcore_rirq_state; |
26 |
|
27 |
/* Map baseboard IRQs onto CPU IRQ lines. */
|
28 |
static const int mpcore_irq_map[32] = { |
29 |
-1, -1, -1, -1, 1, 2, -1, -1, |
30 |
-1, -1, 6, -1, 4, 5, -1, -1, |
31 |
-1, 14, 15, 0, 7, 8, -1, -1, |
32 |
-1, -1, -1, -1, 9, 3, -1, -1, |
33 |
}; |
34 |
|
35 |
static void mpcore_rirq_set_irq(void *opaque, int irq, int level) |
36 |
{ |
37 |
mpcore_rirq_state *s = (mpcore_rirq_state *)opaque; |
38 |
int i;
|
39 |
|
40 |
for (i = 0; i < 4; i++) { |
41 |
qemu_set_irq(s->rvic[i][irq], level); |
42 |
} |
43 |
if (irq < 32) { |
44 |
irq = mpcore_irq_map[irq]; |
45 |
if (irq >= 0) { |
46 |
qemu_set_irq(s->cpuic[irq], level); |
47 |
} |
48 |
} |
49 |
} |
50 |
|
51 |
static int realview_mpcore_init(SysBusDevice *dev) |
52 |
{ |
53 |
mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev); |
54 |
DeviceState *gic; |
55 |
DeviceState *priv; |
56 |
int n;
|
57 |
int i;
|
58 |
|
59 |
priv = qdev_create(NULL, "arm11mpcore_priv"); |
60 |
qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
|
61 |
qdev_init_nofail(priv); |
62 |
s->priv = sysbus_from_qdev(priv); |
63 |
sysbus_pass_irq(dev, s->priv); |
64 |
for (i = 0; i < 32; i++) { |
65 |
s->cpuic[i] = qdev_get_gpio_in(priv, i); |
66 |
} |
67 |
/* ??? IRQ routing is hardcoded to "normal" mode. */
|
68 |
for (n = 0; n < 4; n++) { |
69 |
gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000, |
70 |
s->cpuic[10 + n]);
|
71 |
for (i = 0; i < 64; i++) { |
72 |
s->rvic[n][i] = qdev_get_gpio_in(gic, i); |
73 |
} |
74 |
} |
75 |
qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
|
76 |
sysbus_init_mmio_region(dev, sysbus_mmio_get_region(s->priv, 0));
|
77 |
return 0; |
78 |
} |
79 |
|
80 |
static SysBusDeviceInfo mpcore_rirq_info = {
|
81 |
.init = realview_mpcore_init, |
82 |
.qdev.name = "realview_mpcore",
|
83 |
.qdev.size = sizeof(mpcore_rirq_state),
|
84 |
.qdev.props = (Property[]) { |
85 |
DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1), |
86 |
DEFINE_PROP_END_OF_LIST(), |
87 |
} |
88 |
}; |
89 |
|
90 |
static SysBusDeviceInfo mpcore_priv_info = {
|
91 |
.init = mpcore_priv_init, |
92 |
.qdev.name = "arm11mpcore_priv",
|
93 |
.qdev.size = sizeof(mpcore_priv_state),
|
94 |
.qdev.props = (Property[]) { |
95 |
DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), |
96 |
DEFINE_PROP_END_OF_LIST(), |
97 |
} |
98 |
}; |
99 |
|
100 |
static void arm11mpcore_register_devices(void) |
101 |
{ |
102 |
sysbus_register_withprop(&mpcore_rirq_info); |
103 |
sysbus_register_withprop(&mpcore_priv_info); |
104 |
} |
105 |
|
106 |
device_init(arm11mpcore_register_devices) |