root / hw / cpu / a9mpcore.c @ f487b677
History | View | Annotate | Download (4.7 kB)
1 | f7c70325 | Paul Brook | /*
|
---|---|---|---|
2 | f7c70325 | Paul Brook | * Cortex-A9MPCore internal peripheral emulation.
|
3 | f7c70325 | Paul Brook | *
|
4 | f7c70325 | Paul Brook | * Copyright (c) 2009 CodeSourcery.
|
5 | b12080cd | Peter Maydell | * Copyright (c) 2011 Linaro Limited.
|
6 | b12080cd | Peter Maydell | * Written by Paul Brook, Peter Maydell.
|
7 | f7c70325 | Paul Brook | *
|
8 | 8e31bf38 | Matthew Fernandez | * This code is licensed under the GPL.
|
9 | f7c70325 | Paul Brook | */
|
10 | f7c70325 | Paul Brook | |
11 | 83c9f4ca | Paolo Bonzini | #include "hw/sysbus.h" |
12 | b12080cd | Peter Maydell | |
13 | 845769fc | Peter Crosthwaite | typedef struct A9MPPrivState { |
14 | ddd76165 | Peter Maydell | SysBusDevice busdev; |
15 | b12080cd | Peter Maydell | uint32_t num_cpu; |
16 | b12080cd | Peter Maydell | MemoryRegion container; |
17 | b12080cd | Peter Maydell | DeviceState *mptimer; |
18 | cde4577f | Peter Crosthwaite | DeviceState *wdt; |
19 | ddd76165 | Peter Maydell | DeviceState *gic; |
20 | 353575f0 | Peter Crosthwaite | DeviceState *scu; |
21 | a32134aa | Mark Langsdorf | uint32_t num_irq; |
22 | 845769fc | Peter Crosthwaite | } A9MPPrivState; |
23 | b12080cd | Peter Maydell | |
24 | ddd76165 | Peter Maydell | static void a9mp_priv_set_irq(void *opaque, int irq, int level) |
25 | ddd76165 | Peter Maydell | { |
26 | 845769fc | Peter Crosthwaite | A9MPPrivState *s = (A9MPPrivState *)opaque; |
27 | ddd76165 | Peter Maydell | qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); |
28 | ddd76165 | Peter Maydell | } |
29 | ddd76165 | Peter Maydell | |
30 | b12080cd | Peter Maydell | static int a9mp_priv_init(SysBusDevice *dev) |
31 | b12080cd | Peter Maydell | { |
32 | 845769fc | Peter Crosthwaite | A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, dev); |
33 | 353575f0 | Peter Crosthwaite | SysBusDevice *timerbusdev, *wdtbusdev, *gicbusdev, *scubusdev; |
34 | b12080cd | Peter Maydell | int i;
|
35 | b12080cd | Peter Maydell | |
36 | ddd76165 | Peter Maydell | s->gic = qdev_create(NULL, "arm_gic"); |
37 | ddd76165 | Peter Maydell | qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
|
38 | ddd76165 | Peter Maydell | qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
|
39 | ddd76165 | Peter Maydell | qdev_init_nofail(s->gic); |
40 | 1356b98d | Andreas Färber | gicbusdev = SYS_BUS_DEVICE(s->gic); |
41 | ddd76165 | Peter Maydell | |
42 | ddd76165 | Peter Maydell | /* Pass through outbound IRQ lines from the GIC */
|
43 | ddd76165 | Peter Maydell | sysbus_pass_irq(dev, gicbusdev); |
44 | ddd76165 | Peter Maydell | |
45 | ddd76165 | Peter Maydell | /* Pass through inbound GPIO lines to the GIC */
|
46 | ddd76165 | Peter Maydell | qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32);
|
47 | b12080cd | Peter Maydell | |
48 | 353575f0 | Peter Crosthwaite | s->scu = qdev_create(NULL, "a9-scu"); |
49 | 353575f0 | Peter Crosthwaite | qdev_prop_set_uint32(s->scu, "num-cpu", s->num_cpu);
|
50 | 353575f0 | Peter Crosthwaite | qdev_init_nofail(s->scu); |
51 | 353575f0 | Peter Crosthwaite | scubusdev = SYS_BUS_DEVICE(s->scu); |
52 | 353575f0 | Peter Crosthwaite | |
53 | b12080cd | Peter Maydell | s->mptimer = qdev_create(NULL, "arm_mptimer"); |
54 | b12080cd | Peter Maydell | qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
|
55 | b12080cd | Peter Maydell | qdev_init_nofail(s->mptimer); |
56 | cde4577f | Peter Crosthwaite | timerbusdev = SYS_BUS_DEVICE(s->mptimer); |
57 | cde4577f | Peter Crosthwaite | |
58 | cde4577f | Peter Crosthwaite | s->wdt = qdev_create(NULL, "arm_mptimer"); |
59 | cde4577f | Peter Crosthwaite | qdev_prop_set_uint32(s->wdt, "num-cpu", s->num_cpu);
|
60 | cde4577f | Peter Crosthwaite | qdev_init_nofail(s->wdt); |
61 | cde4577f | Peter Crosthwaite | wdtbusdev = SYS_BUS_DEVICE(s->wdt); |
62 | b12080cd | Peter Maydell | |
63 | b12080cd | Peter Maydell | /* Memory map (addresses are offsets from PERIPHBASE):
|
64 | b12080cd | Peter Maydell | * 0x0000-0x00ff -- Snoop Control Unit
|
65 | b12080cd | Peter Maydell | * 0x0100-0x01ff -- GIC CPU interface
|
66 | b12080cd | Peter Maydell | * 0x0200-0x02ff -- Global Timer
|
67 | b12080cd | Peter Maydell | * 0x0300-0x05ff -- nothing
|
68 | b12080cd | Peter Maydell | * 0x0600-0x06ff -- private timers and watchdogs
|
69 | b12080cd | Peter Maydell | * 0x0700-0x0fff -- nothing
|
70 | b12080cd | Peter Maydell | * 0x1000-0x1fff -- GIC Distributor
|
71 | b12080cd | Peter Maydell | *
|
72 | b12080cd | Peter Maydell | * We should implement the global timer but don't currently do so.
|
73 | b12080cd | Peter Maydell | */
|
74 | b12080cd | Peter Maydell | memory_region_init(&s->container, "a9mp-priv-container", 0x2000); |
75 | 353575f0 | Peter Crosthwaite | memory_region_add_subregion(&s->container, 0,
|
76 | 353575f0 | Peter Crosthwaite | sysbus_mmio_get_region(scubusdev, 0));
|
77 | b12080cd | Peter Maydell | /* GIC CPU interface */
|
78 | ddd76165 | Peter Maydell | memory_region_add_subregion(&s->container, 0x100,
|
79 | ddd76165 | Peter Maydell | sysbus_mmio_get_region(gicbusdev, 1));
|
80 | b12080cd | Peter Maydell | /* Note that the A9 exposes only the "timer/watchdog for this core"
|
81 | b12080cd | Peter Maydell | * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
|
82 | b12080cd | Peter Maydell | */
|
83 | b12080cd | Peter Maydell | memory_region_add_subregion(&s->container, 0x600,
|
84 | cde4577f | Peter Crosthwaite | sysbus_mmio_get_region(timerbusdev, 0));
|
85 | b12080cd | Peter Maydell | memory_region_add_subregion(&s->container, 0x620,
|
86 | cde4577f | Peter Crosthwaite | sysbus_mmio_get_region(wdtbusdev, 0));
|
87 | ddd76165 | Peter Maydell | memory_region_add_subregion(&s->container, 0x1000,
|
88 | ddd76165 | Peter Maydell | sysbus_mmio_get_region(gicbusdev, 0));
|
89 | b12080cd | Peter Maydell | |
90 | b12080cd | Peter Maydell | sysbus_init_mmio(dev, &s->container); |
91 | b12080cd | Peter Maydell | |
92 | ddd76165 | Peter Maydell | /* Wire up the interrupt from each watchdog and timer.
|
93 | ddd76165 | Peter Maydell | * For each core the timer is PPI 29 and the watchdog PPI 30.
|
94 | ddd76165 | Peter Maydell | */
|
95 | ddd76165 | Peter Maydell | for (i = 0; i < s->num_cpu; i++) { |
96 | ddd76165 | Peter Maydell | int ppibase = (s->num_irq - 32) + i * 32; |
97 | cde4577f | Peter Crosthwaite | sysbus_connect_irq(timerbusdev, i, |
98 | ddd76165 | Peter Maydell | qdev_get_gpio_in(s->gic, ppibase + 29));
|
99 | cde4577f | Peter Crosthwaite | sysbus_connect_irq(wdtbusdev, i, |
100 | ddd76165 | Peter Maydell | qdev_get_gpio_in(s->gic, ppibase + 30));
|
101 | b12080cd | Peter Maydell | } |
102 | b12080cd | Peter Maydell | return 0; |
103 | b12080cd | Peter Maydell | } |
104 | b12080cd | Peter Maydell | |
105 | 39bffca2 | Anthony Liguori | static Property a9mp_priv_properties[] = {
|
106 | 845769fc | Peter Crosthwaite | DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, num_cpu, 1), |
107 | 39bffca2 | Anthony Liguori | /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
|
108 | 39bffca2 | Anthony Liguori | * IRQ lines (with another 32 internal). We default to 64+32, which
|
109 | 39bffca2 | Anthony Liguori | * is the number provided by the Cortex-A9MP test chip in the
|
110 | 39bffca2 | Anthony Liguori | * Realview PBX-A9 and Versatile Express A9 development boards.
|
111 | 39bffca2 | Anthony Liguori | * Other boards may differ and should set this property appropriately.
|
112 | 39bffca2 | Anthony Liguori | */
|
113 | 845769fc | Peter Crosthwaite | DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 96), |
114 | 39bffca2 | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
115 | 39bffca2 | Anthony Liguori | }; |
116 | 39bffca2 | Anthony Liguori | |
117 | 999e12bb | Anthony Liguori | static void a9mp_priv_class_init(ObjectClass *klass, void *data) |
118 | 999e12bb | Anthony Liguori | { |
119 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
120 | 999e12bb | Anthony Liguori | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
121 | 999e12bb | Anthony Liguori | |
122 | 999e12bb | Anthony Liguori | k->init = a9mp_priv_init; |
123 | 39bffca2 | Anthony Liguori | dc->props = a9mp_priv_properties; |
124 | 999e12bb | Anthony Liguori | } |
125 | 999e12bb | Anthony Liguori | |
126 | 8c43a6f0 | Andreas Färber | static const TypeInfo a9mp_priv_info = { |
127 | 39bffca2 | Anthony Liguori | .name = "a9mpcore_priv",
|
128 | 39bffca2 | Anthony Liguori | .parent = TYPE_SYS_BUS_DEVICE, |
129 | 845769fc | Peter Crosthwaite | .instance_size = sizeof(A9MPPrivState),
|
130 | 39bffca2 | Anthony Liguori | .class_init = a9mp_priv_class_init, |
131 | f7c70325 | Paul Brook | }; |
132 | f7c70325 | Paul Brook | |
133 | 83f7d43a | Andreas Färber | static void a9mp_register_types(void) |
134 | f7c70325 | Paul Brook | { |
135 | 39bffca2 | Anthony Liguori | type_register_static(&a9mp_priv_info); |
136 | f7c70325 | Paul Brook | } |
137 | f7c70325 | Paul Brook | |
138 | 83f7d43a | Andreas Färber | type_init(a9mp_register_types) |