Revision f7c70325
b/Makefile.target | ||
---|---|---|
270 | 270 |
obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o |
271 | 271 |
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o |
272 | 272 |
obj-arm-y += versatile_pci.o |
273 |
obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o |
|
273 |
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
|
|
274 | 274 |
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o |
275 | 275 |
obj-arm-y += pl061.o |
276 | 276 |
obj-arm-y += arm-semi.o |
b/hw/a9mpcore.c | ||
---|---|---|
1 |
/* |
|
2 |
* Cortex-A9MPCore internal peripheral emulation. |
|
3 |
* |
|
4 |
* Copyright (c) 2009 CodeSourcery. |
|
5 |
* Written by Paul Brook |
|
6 |
* |
|
7 |
* This code is licenced under the GPL. |
|
8 |
*/ |
|
9 |
|
|
10 |
/* 64 external IRQ lines. */ |
|
11 |
#define GIC_NIRQ 96 |
|
12 |
#include "mpcore.c" |
|
13 |
|
|
14 |
static SysBusDeviceInfo mpcore_priv_info = { |
|
15 |
.init = mpcore_priv_init, |
|
16 |
.qdev.name = "a9mpcore_priv", |
|
17 |
.qdev.size = sizeof(mpcore_priv_state), |
|
18 |
.qdev.props = (Property[]) { |
|
19 |
DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), |
|
20 |
DEFINE_PROP_END_OF_LIST(), |
|
21 |
} |
|
22 |
}; |
|
23 |
|
|
24 |
static void a9mpcore_register_devices(void) |
|
25 |
{ |
|
26 |
sysbus_register_withprop(&mpcore_priv_info); |
|
27 |
} |
|
28 |
|
|
29 |
device_init(a9mpcore_register_devices) |
b/hw/arm-misc.h | ||
---|---|---|
28 | 28 |
const char *initrd_filename; |
29 | 29 |
target_phys_addr_t loader_start; |
30 | 30 |
target_phys_addr_t smp_loader_start; |
31 |
target_phys_addr_t smp_priv_base; |
|
31 | 32 |
int nb_cpus; |
32 | 33 |
int board_id; |
33 | 34 |
int (*atag_board)(struct arm_boot_info *info, void *p); |
b/hw/arm11mpcore.c | ||
---|---|---|
1 |
/* |
|
2 |
* ARM11MPCore internal peripheral emulation. |
|
3 |
* |
|
4 |
* Copyright (c) 2006-2007 CodeSourcery. |
|
5 |
* Written by Paul Brook |
|
6 |
* |
|
7 |
* This code is licenced 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 void mpcore_rirq_map(SysBusDevice *dev, target_phys_addr_t base) |
|
52 |
{ |
|
53 |
mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev); |
|
54 |
sysbus_mmio_map(s->priv, 0, base); |
|
55 |
} |
|
56 |
|
|
57 |
static int realview_mpcore_init(SysBusDevice *dev) |
|
58 |
{ |
|
59 |
mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev); |
|
60 |
DeviceState *gic; |
|
61 |
DeviceState *priv; |
|
62 |
int n; |
|
63 |
int i; |
|
64 |
|
|
65 |
priv = qdev_create(NULL, "arm11mpcore_priv"); |
|
66 |
qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu); |
|
67 |
qdev_init_nofail(priv); |
|
68 |
s->priv = sysbus_from_qdev(priv); |
|
69 |
sysbus_pass_irq(dev, s->priv); |
|
70 |
for (i = 0; i < 32; i++) { |
|
71 |
s->cpuic[i] = qdev_get_gpio_in(priv, i); |
|
72 |
} |
|
73 |
/* ??? IRQ routing is hardcoded to "normal" mode. */ |
|
74 |
for (n = 0; n < 4; n++) { |
|
75 |
gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000, |
|
76 |
s->cpuic[10 + n]); |
|
77 |
for (i = 0; i < 64; i++) { |
|
78 |
s->rvic[n][i] = qdev_get_gpio_in(gic, i); |
|
79 |
} |
|
80 |
} |
|
81 |
qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64); |
|
82 |
sysbus_init_mmio_cb(dev, 0x2000, mpcore_rirq_map); |
|
83 |
return 0; |
|
84 |
} |
|
85 |
|
|
86 |
static SysBusDeviceInfo mpcore_rirq_info = { |
|
87 |
.init = realview_mpcore_init, |
|
88 |
.qdev.name = "realview_mpcore", |
|
89 |
.qdev.size = sizeof(mpcore_rirq_state), |
|
90 |
.qdev.props = (Property[]) { |
|
91 |
DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1), |
|
92 |
DEFINE_PROP_END_OF_LIST(), |
|
93 |
} |
|
94 |
}; |
|
95 |
|
|
96 |
static SysBusDeviceInfo mpcore_priv_info = { |
|
97 |
.init = mpcore_priv_init, |
|
98 |
.qdev.name = "arm11mpcore_priv", |
|
99 |
.qdev.size = sizeof(mpcore_priv_state), |
|
100 |
.qdev.props = (Property[]) { |
|
101 |
DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), |
|
102 |
DEFINE_PROP_END_OF_LIST(), |
|
103 |
} |
|
104 |
}; |
|
105 |
|
|
106 |
static void arm11mpcore_register_devices(void) |
|
107 |
{ |
|
108 |
sysbus_register_withprop(&mpcore_rirq_info); |
|
109 |
sysbus_register_withprop(&mpcore_priv_info); |
|
110 |
} |
|
111 |
|
|
112 |
device_init(arm11mpcore_register_devices) |
b/hw/arm_boot.c | ||
---|---|---|
31 | 31 |
/* Entry point for secondary CPUs. Enable interrupt controller and |
32 | 32 |
Issue WFI until start address is written to system controller. */ |
33 | 33 |
static uint32_t smpboot[] = { |
34 |
0xe3a00201, /* mov r0, #0x10000000 */ |
|
35 |
0xe3800601, /* orr r0, r0, #0x001000000 */ |
|
34 |
0xe59f0020, /* ldr r0, privbase */ |
|
36 | 35 |
0xe3a01001, /* mov r1, #1 */ |
37 | 36 |
0xe5801100, /* str r1, [r0, #0x100] */ |
38 | 37 |
0xe3a00201, /* mov r0, #0x10000000 */ |
... | ... | |
41 | 40 |
0xe5901000, /* ldr r1, [r0] */ |
42 | 41 |
0xe1110001, /* tst r1, r1 */ |
43 | 42 |
0x0afffffb, /* beq <wfi> */ |
44 |
0xe12fff11 /* bx r1 */ |
|
43 |
0xe12fff11, /* bx r1 */ |
|
44 |
0 /* privbase: Private memory region base address. */ |
|
45 | 45 |
}; |
46 | 46 |
|
47 | 47 |
#define WRITE_WORD(p, value) do { \ |
... | ... | |
268 | 268 |
rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader), |
269 | 269 |
info->loader_start); |
270 | 270 |
if (info->nb_cpus > 1) { |
271 |
smpboot[10] = info->smp_priv_base; |
|
271 | 272 |
for (n = 0; n < sizeof(smpboot) / 4; n++) { |
272 | 273 |
smpboot[n] = tswap32(smpboot[n]); |
273 | 274 |
} |
b/hw/arm_gic.c | ||
---|---|---|
607 | 607 |
switch (offset) { |
608 | 608 |
case 0x00: /* Control */ |
609 | 609 |
s->cpu_enabled[cpu] = (value & 1); |
610 |
DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis");
|
|
610 |
DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled ? "En" : "Dis");
|
|
611 | 611 |
break; |
612 | 612 |
case 0x04: /* Priority mask */ |
613 | 613 |
s->priority_mask[cpu] = (value & 0xff); |
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) |
b/hw/realview.c | ||
---|---|---|
34 | 34 |
env->regs[15] = SMP_BOOT_ADDR; |
35 | 35 |
} |
36 | 36 |
|
37 |
/* The following two lists must be consistent. */ |
|
37 | 38 |
enum realview_board_type { |
38 | 39 |
BOARD_EB, |
39 | 40 |
BOARD_EB_MPCORE, |
40 |
BOARD_PB_A8 |
|
41 |
BOARD_PB_A8, |
|
42 |
BOARD_PBX_A9, |
|
43 |
}; |
|
44 |
|
|
45 |
int realview_board_id[] = { |
|
46 |
0x33b, |
|
47 |
0x33b, |
|
48 |
0x769, |
|
49 |
0x76d |
|
41 | 50 |
}; |
42 | 51 |
|
43 | 52 |
static void realview_init(ram_addr_t ram_size, |
... | ... | |
57 | 66 |
int n; |
58 | 67 |
int done_nic = 0; |
59 | 68 |
qemu_irq cpu_irq[4]; |
60 |
int is_mpcore = (board_type == BOARD_EB_MPCORE);
|
|
61 |
int is_pb = (board_type == BOARD_PB_A8);
|
|
69 |
int is_mpcore = 0;
|
|
70 |
int is_pb = 0;
|
|
62 | 71 |
uint32_t proc_id = 0; |
63 | 72 |
uint32_t sys_id; |
64 | 73 |
ram_addr_t low_ram_size; |
65 | 74 |
|
75 |
switch (board_type) { |
|
76 |
case BOARD_EB: |
|
77 |
break; |
|
78 |
case BOARD_EB_MPCORE: |
|
79 |
is_mpcore = 1; |
|
80 |
break; |
|
81 |
case BOARD_PB_A8: |
|
82 |
is_pb = 1; |
|
83 |
break; |
|
84 |
case BOARD_PBX_A9: |
|
85 |
is_mpcore = 1; |
|
86 |
is_pb = 1; |
|
87 |
break; |
|
88 |
} |
|
66 | 89 |
for (n = 0; n < smp_cpus; n++) { |
67 | 90 |
env = cpu_init(cpu_model); |
68 | 91 |
if (!env) { |
... | ... | |
76 | 99 |
} |
77 | 100 |
} |
78 | 101 |
if (arm_feature(env, ARM_FEATURE_V7)) { |
79 |
proc_id = 0x0e000000; |
|
102 |
if (is_mpcore) { |
|
103 |
proc_id = 0x0c000000; |
|
104 |
} else { |
|
105 |
proc_id = 0x0e000000; |
|
106 |
} |
|
80 | 107 |
} else if (arm_feature(env, ARM_FEATURE_V6K)) { |
81 | 108 |
proc_id = 0x06000000; |
82 | 109 |
} else if (arm_feature(env, ARM_FEATURE_V6)) { |
... | ... | |
104 | 131 |
arm_sysctl_init(0x10000000, sys_id, proc_id); |
105 | 132 |
|
106 | 133 |
if (is_mpcore) { |
107 |
dev = qdev_create(NULL, "realview_mpcore"); |
|
134 |
dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
|
|
108 | 135 |
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); |
109 | 136 |
qdev_init_nofail(dev); |
110 | 137 |
busdev = sysbus_from_qdev(dev); |
138 |
if (is_pb) { |
|
139 |
realview_binfo.smp_priv_base = 0x1f000000; |
|
140 |
} else { |
|
141 |
realview_binfo.smp_priv_base = 0x10100000; |
|
142 |
} |
|
143 |
sysbus_mmio_map(busdev, 0, realview_binfo.smp_priv_base); |
|
111 | 144 |
for (n = 0; n < smp_cpus; n++) { |
112 | 145 |
sysbus_connect_irq(busdev, n, cpu_irq[n]); |
113 | 146 |
} |
... | ... | |
238 | 271 |
realview_binfo.kernel_cmdline = kernel_cmdline; |
239 | 272 |
realview_binfo.initrd_filename = initrd_filename; |
240 | 273 |
realview_binfo.nb_cpus = smp_cpus; |
241 |
realview_binfo.board_id = is_pb ? 0x769 : 0x33b;
|
|
274 |
realview_binfo.board_id = realview_board_id[board_type];
|
|
242 | 275 |
realview_binfo.loader_start = is_pb ? 0x70000000 : 0; |
243 | 276 |
arm_load_kernel(first_cpu, &realview_binfo); |
244 | 277 |
} |
... | ... | |
279 | 312 |
initrd_filename, cpu_model, BOARD_PB_A8); |
280 | 313 |
} |
281 | 314 |
|
315 |
static void realview_pbx_a9_init(ram_addr_t ram_size, |
|
316 |
const char *boot_device, |
|
317 |
const char *kernel_filename, const char *kernel_cmdline, |
|
318 |
const char *initrd_filename, const char *cpu_model) |
|
319 |
{ |
|
320 |
if (!cpu_model) { |
|
321 |
cpu_model = "cortex-a9"; |
|
322 |
} |
|
323 |
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline, |
|
324 |
initrd_filename, cpu_model, BOARD_PBX_A9); |
|
325 |
} |
|
326 |
|
|
282 | 327 |
static QEMUMachine realview_eb_machine = { |
283 | 328 |
.name = "realview-eb", |
284 | 329 |
.desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)", |
... | ... | |
298 | 343 |
.name = "realview-pb-a8", |
299 | 344 |
.desc = "ARM RealView Platform Baseboard for Cortex-A8", |
300 | 345 |
.init = realview_pb_a8_init, |
346 |
}; |
|
347 |
|
|
348 |
static QEMUMachine realview_pbx_a9_machine = { |
|
349 |
.name = "realview-pbx-a9", |
|
350 |
.desc = "ARM RealView Platform Baseboard Explore for Cortex-A9", |
|
351 |
.init = realview_pbx_a9_init, |
|
301 | 352 |
.use_scsi = 1, |
353 |
.max_cpus = 4, |
|
302 | 354 |
}; |
303 | 355 |
|
304 | 356 |
static void realview_machine_init(void) |
... | ... | |
306 | 358 |
qemu_register_machine(&realview_eb_machine); |
307 | 359 |
qemu_register_machine(&realview_eb_mpcore_machine); |
308 | 360 |
qemu_register_machine(&realview_pb_a8_machine); |
361 |
qemu_register_machine(&realview_pbx_a9_machine); |
|
309 | 362 |
} |
310 | 363 |
|
311 | 364 |
machine_init(realview_machine_init); |
b/qemu-doc.texi | ||
---|---|---|
1664 | 1664 |
|
1665 | 1665 |
@itemize @minus |
1666 | 1666 |
@item |
1667 |
ARM926E, ARM1136, ARM11MPCORE or Cortex-A8 CPU
|
|
1667 |
ARM926E, ARM1136, ARM11MPCore, Cortex-A8 or Cortex-A9 MPCore CPU
|
|
1668 | 1668 |
@item |
1669 | 1669 |
ARM AMBA Generic/Distributed Interrupt Controller |
1670 | 1670 |
@item |
Also available in: Unified diff