]> git.proxmox.com Git - qemu.git/blob - hw/cpu/arm11mpcore.c
arm11mpcore: Convert mpcore_rirq_state to QOM realize
[qemu.git] / hw / cpu / 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 licensed under the GPL.
8 */
9
10 #include "hw/sysbus.h"
11 #include "hw/misc/arm11scu.h"
12 #include "hw/intc/arm_gic.h"
13 #include "hw/intc/realview_gic.h"
14 #include "hw/timer/arm_mptimer.h"
15 #include "qemu/timer.h"
16
17 /* MPCore private memory region. */
18
19 #define TYPE_ARM11MPCORE_PRIV "arm11mpcore_priv"
20 #define ARM11MPCORE_PRIV(obj) \
21 OBJECT_CHECK(ARM11MPCorePriveState, (obj), TYPE_ARM11MPCORE_PRIV)
22
23 typedef struct ARM11MPCorePriveState {
24 SysBusDevice parent_obj;
25
26 uint32_t num_cpu;
27 MemoryRegion container;
28 uint32_t num_irq;
29
30 ARM11SCUState scu;
31 GICState gic;
32 ARMMPTimerState mptimer;
33 ARMMPTimerState wdtimer;
34 } ARM11MPCorePriveState;
35
36 /* Per-CPU private memory mapped IO. */
37
38
39 static void mpcore_priv_set_irq(void *opaque, int irq, int level)
40 {
41 ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
42
43 qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
44 }
45
46 static void mpcore_priv_map_setup(ARM11MPCorePriveState *s)
47 {
48 int i;
49 SysBusDevice *scubusdev = SYS_BUS_DEVICE(&s->scu);
50 DeviceState *gicdev = DEVICE(&s->gic);
51 SysBusDevice *gicbusdev = SYS_BUS_DEVICE(&s->gic);
52 SysBusDevice *timerbusdev = SYS_BUS_DEVICE(&s->mptimer);
53 SysBusDevice *wdtbusdev = SYS_BUS_DEVICE(&s->wdtimer);
54
55 memory_region_add_subregion(&s->container, 0,
56 sysbus_mmio_get_region(scubusdev, 0));
57 /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
58 * at 0x200, 0x300...
59 */
60 for (i = 0; i < (s->num_cpu + 1); i++) {
61 hwaddr offset = 0x100 + (i * 0x100);
62 memory_region_add_subregion(&s->container, offset,
63 sysbus_mmio_get_region(gicbusdev, i + 1));
64 }
65 /* Add the regions for timer and watchdog for "current CPU" and
66 * for each specific CPU.
67 */
68 for (i = 0; i < (s->num_cpu + 1); i++) {
69 /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
70 hwaddr offset = 0x600 + i * 0x100;
71 memory_region_add_subregion(&s->container, offset,
72 sysbus_mmio_get_region(timerbusdev, i));
73 memory_region_add_subregion(&s->container, offset + 0x20,
74 sysbus_mmio_get_region(wdtbusdev, i));
75 }
76 memory_region_add_subregion(&s->container, 0x1000,
77 sysbus_mmio_get_region(gicbusdev, 0));
78 /* Wire up the interrupt from each watchdog and timer.
79 * For each core the timer is PPI 29 and the watchdog PPI 30.
80 */
81 for (i = 0; i < s->num_cpu; i++) {
82 int ppibase = (s->num_irq - 32) + i * 32;
83 sysbus_connect_irq(timerbusdev, i,
84 qdev_get_gpio_in(gicdev, ppibase + 29));
85 sysbus_connect_irq(wdtbusdev, i,
86 qdev_get_gpio_in(gicdev, ppibase + 30));
87 }
88 }
89
90 static void mpcore_priv_realize(DeviceState *dev, Error **errp)
91 {
92 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
93 ARM11MPCorePriveState *s = ARM11MPCORE_PRIV(dev);
94 DeviceState *scudev = DEVICE(&s->scu);
95 DeviceState *gicdev = DEVICE(&s->gic);
96 DeviceState *mptimerdev = DEVICE(&s->mptimer);
97 DeviceState *wdtimerdev = DEVICE(&s->wdtimer);
98 Error *err = NULL;
99
100 qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu);
101 object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
102 if (err != NULL) {
103 error_propagate(errp, err);
104 return;
105 }
106
107 qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
108 qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
109 object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
110 if (err != NULL) {
111 error_propagate(errp, err);
112 return;
113 }
114
115 /* Pass through outbound IRQ lines from the GIC */
116 sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->gic));
117
118 /* Pass through inbound GPIO lines to the GIC */
119 qdev_init_gpio_in(dev, mpcore_priv_set_irq, s->num_irq - 32);
120
121 qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu);
122 object_property_set_bool(OBJECT(&s->mptimer), true, "realized", &err);
123 if (err != NULL) {
124 error_propagate(errp, err);
125 return;
126 }
127
128 qdev_prop_set_uint32(wdtimerdev, "num-cpu", s->num_cpu);
129 object_property_set_bool(OBJECT(&s->wdtimer), true, "realized", &err);
130 if (err != NULL) {
131 error_propagate(errp, err);
132 return;
133 }
134
135 mpcore_priv_map_setup(s);
136 }
137
138 static void mpcore_priv_initfn(Object *obj)
139 {
140 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
141 ARM11MPCorePriveState *s = ARM11MPCORE_PRIV(obj);
142
143 memory_region_init(&s->container, OBJECT(s),
144 "mpcore-priv-container", 0x2000);
145 sysbus_init_mmio(sbd, &s->container);
146
147 object_initialize(&s->scu, sizeof(s->scu), TYPE_ARM11_SCU);
148 qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default());
149
150 object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
151 qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
152 /* Request the legacy 11MPCore GIC behaviour: */
153 qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 0);
154
155 object_initialize(&s->mptimer, sizeof(s->mptimer), TYPE_ARM_MPTIMER);
156 qdev_set_parent_bus(DEVICE(&s->mptimer), sysbus_get_default());
157
158 object_initialize(&s->wdtimer, sizeof(s->wdtimer), TYPE_ARM_MPTIMER);
159 qdev_set_parent_bus(DEVICE(&s->wdtimer), sysbus_get_default());
160 }
161
162 #define TYPE_REALVIEW_MPCORE_RIRQ "realview_mpcore"
163 #define REALVIEW_MPCORE_RIRQ(obj) \
164 OBJECT_CHECK(mpcore_rirq_state, (obj), TYPE_REALVIEW_MPCORE_RIRQ)
165
166 /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
167 controllers. The output of these, plus some of the raw input lines
168 are fed into a single SMP-aware interrupt controller on the CPU. */
169 typedef struct {
170 SysBusDevice parent_obj;
171
172 qemu_irq cpuic[32];
173 qemu_irq rvic[4][64];
174 uint32_t num_cpu;
175
176 ARM11MPCorePriveState priv;
177 RealViewGICState gic[4];
178 } mpcore_rirq_state;
179
180 /* Map baseboard IRQs onto CPU IRQ lines. */
181 static const int mpcore_irq_map[32] = {
182 -1, -1, -1, -1, 1, 2, -1, -1,
183 -1, -1, 6, -1, 4, 5, -1, -1,
184 -1, 14, 15, 0, 7, 8, -1, -1,
185 -1, -1, -1, -1, 9, 3, -1, -1,
186 };
187
188 static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
189 {
190 mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
191 int i;
192
193 for (i = 0; i < 4; i++) {
194 qemu_set_irq(s->rvic[i][irq], level);
195 }
196 if (irq < 32) {
197 irq = mpcore_irq_map[irq];
198 if (irq >= 0) {
199 qemu_set_irq(s->cpuic[irq], level);
200 }
201 }
202 }
203
204 static void realview_mpcore_realize(DeviceState *dev, Error **errp)
205 {
206 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
207 mpcore_rirq_state *s = REALVIEW_MPCORE_RIRQ(dev);
208 DeviceState *priv = DEVICE(&s->priv);
209 DeviceState *gic;
210 SysBusDevice *gicbusdev;
211 Error *err = NULL;
212 int n;
213 int i;
214
215 qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
216 object_property_set_bool(OBJECT(&s->priv), true, "realized", &err);
217 if (err != NULL) {
218 error_propagate(errp, err);
219 return;
220 }
221 sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->priv));
222 for (i = 0; i < 32; i++) {
223 s->cpuic[i] = qdev_get_gpio_in(priv, i);
224 }
225 /* ??? IRQ routing is hardcoded to "normal" mode. */
226 for (n = 0; n < 4; n++) {
227 object_property_set_bool(OBJECT(&s->gic[n]), true, "realized", &err);
228 if (err != NULL) {
229 error_propagate(errp, err);
230 return;
231 }
232 gic = DEVICE(&s->gic[n]);
233 gicbusdev = SYS_BUS_DEVICE(&s->gic[n]);
234 sysbus_mmio_map(gicbusdev, 0, 0x10040000 + n * 0x10000);
235 sysbus_connect_irq(gicbusdev, 0, s->cpuic[10 + n]);
236 for (i = 0; i < 64; i++) {
237 s->rvic[n][i] = qdev_get_gpio_in(gic, i);
238 }
239 }
240 qdev_init_gpio_in(dev, mpcore_rirq_set_irq, 64);
241 }
242
243 static void mpcore_rirq_init(Object *obj)
244 {
245 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
246 mpcore_rirq_state *s = REALVIEW_MPCORE_RIRQ(obj);
247 SysBusDevice *privbusdev;
248 int i;
249
250 object_initialize(&s->priv, sizeof(s->priv), TYPE_ARM11MPCORE_PRIV);
251 qdev_set_parent_bus(DEVICE(&s->priv), sysbus_get_default());
252 privbusdev = SYS_BUS_DEVICE(&s->priv);
253 sysbus_init_mmio(sbd, sysbus_mmio_get_region(privbusdev, 0));
254
255 for (i = 0; i < 4; i++) {
256 object_initialize(&s->gic[i], sizeof(s->gic[i]), TYPE_REALVIEW_GIC);
257 qdev_set_parent_bus(DEVICE(&s->gic[i]), sysbus_get_default());
258 }
259 }
260
261 static Property mpcore_rirq_properties[] = {
262 DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
263 DEFINE_PROP_END_OF_LIST(),
264 };
265
266 static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
267 {
268 DeviceClass *dc = DEVICE_CLASS(klass);
269
270 dc->realize = realview_mpcore_realize;
271 dc->props = mpcore_rirq_properties;
272 }
273
274 static const TypeInfo mpcore_rirq_info = {
275 .name = TYPE_REALVIEW_MPCORE_RIRQ,
276 .parent = TYPE_SYS_BUS_DEVICE,
277 .instance_size = sizeof(mpcore_rirq_state),
278 .instance_init = mpcore_rirq_init,
279 .class_init = mpcore_rirq_class_init,
280 };
281
282 static Property mpcore_priv_properties[] = {
283 DEFINE_PROP_UINT32("num-cpu", ARM11MPCorePriveState, num_cpu, 1),
284 /* The ARM11 MPCORE TRM says the on-chip controller may have
285 * anything from 0 to 224 external interrupt IRQ lines (with another
286 * 32 internal). We default to 32+32, which is the number provided by
287 * the ARM11 MPCore test chip in the Realview Versatile Express
288 * coretile. Other boards may differ and should set this property
289 * appropriately. Some Linux kernels may not boot if the hardware
290 * has more IRQ lines than the kernel expects.
291 */
292 DEFINE_PROP_UINT32("num-irq", ARM11MPCorePriveState, num_irq, 64),
293 DEFINE_PROP_END_OF_LIST(),
294 };
295
296 static void mpcore_priv_class_init(ObjectClass *klass, void *data)
297 {
298 DeviceClass *dc = DEVICE_CLASS(klass);
299
300 dc->realize = mpcore_priv_realize;
301 dc->props = mpcore_priv_properties;
302 }
303
304 static const TypeInfo mpcore_priv_info = {
305 .name = TYPE_ARM11MPCORE_PRIV,
306 .parent = TYPE_SYS_BUS_DEVICE,
307 .instance_size = sizeof(ARM11MPCorePriveState),
308 .instance_init = mpcore_priv_initfn,
309 .class_init = mpcore_priv_class_init,
310 };
311
312 static void arm11mpcore_register_types(void)
313 {
314 type_register_static(&mpcore_rirq_info);
315 type_register_static(&mpcore_priv_info);
316 }
317
318 type_init(arm11mpcore_register_types)