1 /*
2 * RealView ARM11MPCore internal peripheral emulation
3 *
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Copyright (c) 2013 SUSE LINUX Products GmbH
6 * Written by Paul Brook and Andreas Färber
7 *
8 * This code is licensed under the GPL.
9 */
10
11 #include "qemu/osdep.h"
12 #include "qapi/error.h"
13 #include "qemu/module.h"
14 #include "hw/cpu/arm11mpcore.h"
15 #include "hw/intc/realview_gic.h"
16 #include "hw/irq.h"
17 #include "qom/object.h"
18
19 #define TYPE_REALVIEW_MPCORE_RIRQ "realview_mpcore"
20 OBJECT_DECLARE_SIMPLE_TYPE(mpcore_rirq_state, REALVIEW_MPCORE_RIRQ)
21
22 /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
23 controllers. The output of these, plus some of the raw input lines
24 are fed into a single SMP-aware interrupt controller on the CPU. */
25 struct mpcore_rirq_state {
26 SysBusDevice parent_obj;
27
28 qemu_irq cpuic[32];
29 qemu_irq rvic[4][64];
30 uint32_t num_cpu;
31
32 ARM11MPCorePriveState priv;
33 RealViewGICState gic[4];
34 };
35
36 /* Map baseboard IRQs onto CPU IRQ lines. */
37 static const int mpcore_irq_map[32] = {
38 -1, -1, -1, -1, 1, 2, -1, -1,
39 -1, -1, 6, -1, 4, 5, -1, -1,
40 -1, 14, 15, 0, 7, 8, -1, -1,
41 -1, -1, -1, -1, 9, 3, -1, -1,
42 };
43
mpcore_rirq_set_irq(void * opaque,int irq,int level)44 static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
45 {
46 mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
47 int i;
48
49 for (i = 0; i < 4; i++) {
50 qemu_set_irq(s->rvic[i][irq], level);
51 }
52 if (irq < 32) {
53 irq = mpcore_irq_map[irq];
54 if (irq >= 0) {
55 qemu_set_irq(s->cpuic[irq], level);
56 }
57 }
58 }
59
realview_mpcore_realize(DeviceState * dev,Error ** errp)60 static void realview_mpcore_realize(DeviceState *dev, Error **errp)
61 {
62 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
63 mpcore_rirq_state *s = REALVIEW_MPCORE_RIRQ(dev);
64 DeviceState *priv = DEVICE(&s->priv);
65 DeviceState *gic;
66 SysBusDevice *gicbusdev;
67 int n;
68 int i;
69
70 if (!sysbus_realize(SYS_BUS_DEVICE(&s->priv), errp)) {
71 return;
72 }
73 sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->priv));
74 for (i = 0; i < 32; i++) {
75 s->cpuic[i] = qdev_get_gpio_in(priv, i);
76 }
77 /* ??? IRQ routing is hardcoded to "normal" mode. */
78 for (n = 0; n < 4; n++) {
79 if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic[n]), errp)) {
80 return;
81 }
82 gic = DEVICE(&s->gic[n]);
83 gicbusdev = SYS_BUS_DEVICE(&s->gic[n]);
84 sysbus_mmio_map(gicbusdev, 0, 0x10040000 + n * 0x10000);
85 sysbus_connect_irq(gicbusdev, 0, s->cpuic[10 + n]);
86 for (i = 0; i < 64; i++) {
87 s->rvic[n][i] = qdev_get_gpio_in(gic, i);
88 }
89 }
90 qdev_init_gpio_in(dev, mpcore_rirq_set_irq, 64);
91 }
92
mpcore_rirq_init(Object * obj)93 static void mpcore_rirq_init(Object *obj)
94 {
95 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
96 mpcore_rirq_state *s = REALVIEW_MPCORE_RIRQ(obj);
97 SysBusDevice *privbusdev;
98 int i;
99
100 object_initialize_child(obj, "a11priv", &s->priv, TYPE_ARM11MPCORE_PRIV);
101 object_property_add_alias(obj, "num-cpu", OBJECT(&s->priv), "num-cpu");
102 privbusdev = SYS_BUS_DEVICE(&s->priv);
103 sysbus_init_mmio(sbd, sysbus_mmio_get_region(privbusdev, 0));
104
105 for (i = 0; i < 4; i++) {
106 object_initialize_child(obj, "gic[*]", &s->gic[i], TYPE_REALVIEW_GIC);
107 }
108 }
109
mpcore_rirq_class_init(ObjectClass * klass,const void * data)110 static void mpcore_rirq_class_init(ObjectClass *klass, const void *data)
111 {
112 DeviceClass *dc = DEVICE_CLASS(klass);
113
114 dc->realize = realview_mpcore_realize;
115 }
116
117 static const TypeInfo realview_mpcore_types[] = {
118 {
119 .name = TYPE_REALVIEW_MPCORE_RIRQ,
120 .parent = TYPE_SYS_BUS_DEVICE,
121 .instance_size = sizeof(mpcore_rirq_state),
122 .instance_init = mpcore_rirq_init,
123 .class_init = mpcore_rirq_class_init,
124 },
125 };
126
127 DEFINE_TYPES(realview_mpcore_types)
128