]> Git Repo - qemu.git/blame - hw/arm11mpcore.c
hw/exynos4210_gic: Convert to using sysbus GIC
[qemu.git] / hw / arm11mpcore.c
CommitLineData
f7c70325
PB
1/*
2 * ARM11MPCore internal peripheral emulation.
3 *
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
6 *
8e31bf38 7 * This code is licensed under the GPL.
f7c70325
PB
8 */
9
2a6ab1e3
PM
10#include "sysbus.h"
11#include "qemu-timer.h"
12
496dbcd1 13#define LEGACY_INCLUDED_GIC
2a6ab1e3
PM
14#include "arm_gic.c"
15
16/* MPCore private memory region. */
17
18typedef struct mpcore_priv_state {
19 gic_state gic;
20 uint32_t scu_control;
21 int iomemtype;
22 uint32_t old_timer_status[8];
23 uint32_t num_cpu;
24 qemu_irq *timer_irq;
25 MemoryRegion iomem;
26 MemoryRegion container;
27 DeviceState *mptimer;
a32134aa 28 uint32_t num_irq;
2a6ab1e3
PM
29} mpcore_priv_state;
30
31/* Per-CPU private memory mapped IO. */
32
33static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset,
34 unsigned size)
35{
36 mpcore_priv_state *s = (mpcore_priv_state *)opaque;
37 int id;
2a6ab1e3
PM
38 /* SCU */
39 switch (offset) {
40 case 0x00: /* Control. */
41 return s->scu_control;
42 case 0x04: /* Configuration. */
43 id = ((1 << s->num_cpu) - 1) << 4;
44 return id | (s->num_cpu - 1);
45 case 0x08: /* CPU status. */
46 return 0;
47 case 0x0c: /* Invalidate all. */
48 return 0;
49 default:
50 hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
51 }
52}
53
54static void mpcore_scu_write(void *opaque, target_phys_addr_t offset,
55 uint64_t value, unsigned size)
56{
57 mpcore_priv_state *s = (mpcore_priv_state *)opaque;
2a6ab1e3
PM
58 /* SCU */
59 switch (offset) {
60 case 0: /* Control register. */
61 s->scu_control = value & 1;
62 break;
63 case 0x0c: /* Invalidate all. */
64 /* This is a no-op as cache is not emulated. */
65 break;
66 default:
67 hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
68 }
69}
70
71static const MemoryRegionOps mpcore_scu_ops = {
72 .read = mpcore_scu_read,
73 .write = mpcore_scu_write,
74 .endianness = DEVICE_NATIVE_ENDIAN,
75};
76
77static void mpcore_timer_irq_handler(void *opaque, int irq, int level)
78{
79 mpcore_priv_state *s = (mpcore_priv_state *)opaque;
80 if (level && !s->old_timer_status[irq]) {
81 gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
82 }
83 s->old_timer_status[irq] = level;
84}
85
86static void mpcore_priv_map_setup(mpcore_priv_state *s)
87{
88 int i;
89 SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
90 memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
91 memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
92 memory_region_add_subregion(&s->container, 0, &s->iomem);
93 /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
94 * at 0x200, 0x300...
95 */
96 for (i = 0; i < (s->num_cpu + 1); i++) {
97 target_phys_addr_t offset = 0x100 + (i * 0x100);
98 memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]);
99 }
100 /* Add the regions for timer and watchdog for "current CPU" and
101 * for each specific CPU.
102 */
103 s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler,
104 s, (s->num_cpu + 1) * 2);
105 for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
106 /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
107 target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
108 memory_region_add_subregion(&s->container, offset,
109 sysbus_mmio_get_region(busdev, i));
110 }
111 memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
112 /* Wire up the interrupt from each watchdog and timer. */
113 for (i = 0; i < s->num_cpu * 2; i++) {
114 sysbus_connect_irq(busdev, i, s->timer_irq[i]);
115 }
116}
117
118static int mpcore_priv_init(SysBusDevice *dev)
119{
120 mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
121
a32134aa 122 gic_init(&s->gic, s->num_cpu, s->num_irq);
2a6ab1e3
PM
123 s->mptimer = qdev_create(NULL, "arm_mptimer");
124 qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
125 qdev_init_nofail(s->mptimer);
126 mpcore_priv_map_setup(s);
127 sysbus_init_mmio(dev, &s->container);
128 return 0;
129}
f7c70325
PB
130
131/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
132 controllers. The output of these, plus some of the raw input lines
133 are fed into a single SMP-aware interrupt controller on the CPU. */
134typedef struct {
135 SysBusDevice busdev;
136 SysBusDevice *priv;
137 qemu_irq cpuic[32];
138 qemu_irq rvic[4][64];
139 uint32_t num_cpu;
140} mpcore_rirq_state;
141
142/* Map baseboard IRQs onto CPU IRQ lines. */
143static const int mpcore_irq_map[32] = {
144 -1, -1, -1, -1, 1, 2, -1, -1,
145 -1, -1, 6, -1, 4, 5, -1, -1,
146 -1, 14, 15, 0, 7, 8, -1, -1,
147 -1, -1, -1, -1, 9, 3, -1, -1,
148};
149
150static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
151{
152 mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
153 int i;
154
155 for (i = 0; i < 4; i++) {
156 qemu_set_irq(s->rvic[i][irq], level);
157 }
158 if (irq < 32) {
159 irq = mpcore_irq_map[irq];
160 if (irq >= 0) {
161 qemu_set_irq(s->cpuic[irq], level);
162 }
163 }
164}
165
f7c70325
PB
166static int realview_mpcore_init(SysBusDevice *dev)
167{
168 mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
169 DeviceState *gic;
170 DeviceState *priv;
171 int n;
172 int i;
173
174 priv = qdev_create(NULL, "arm11mpcore_priv");
175 qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
176 qdev_init_nofail(priv);
177 s->priv = sysbus_from_qdev(priv);
178 sysbus_pass_irq(dev, s->priv);
179 for (i = 0; i < 32; i++) {
180 s->cpuic[i] = qdev_get_gpio_in(priv, i);
181 }
182 /* ??? IRQ routing is hardcoded to "normal" mode. */
183 for (n = 0; n < 4; n++) {
184 gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
185 s->cpuic[10 + n]);
186 for (i = 0; i < 64; i++) {
187 s->rvic[n][i] = qdev_get_gpio_in(gic, i);
188 }
189 }
190 qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
750ecd44 191 sysbus_init_mmio(dev, sysbus_mmio_get_region(s->priv, 0));
f7c70325
PB
192 return 0;
193}
194
999e12bb 195static Property mpcore_rirq_properties[] = {
0f58a188 196 DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
999e12bb 197 DEFINE_PROP_END_OF_LIST(),
f7c70325
PB
198};
199
999e12bb
AL
200static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
201{
39bffca2 202 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb
AL
203 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
204
205 k->init = realview_mpcore_init;
39bffca2 206 dc->props = mpcore_rirq_properties;
999e12bb
AL
207}
208
39bffca2
AL
209static TypeInfo mpcore_rirq_info = {
210 .name = "realview_mpcore",
211 .parent = TYPE_SYS_BUS_DEVICE,
212 .instance_size = sizeof(mpcore_rirq_state),
213 .class_init = mpcore_rirq_class_init,
999e12bb
AL
214};
215
216static Property mpcore_priv_properties[] = {
217 DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
0f58a188
PM
218 /* The ARM11 MPCORE TRM says the on-chip controller may have
219 * anything from 0 to 224 external interrupt IRQ lines (with another
220 * 32 internal). We default to 32+32, which is the number provided by
221 * the ARM11 MPCore test chip in the Realview Versatile Express
222 * coretile. Other boards may differ and should set this property
223 * appropriately. Some Linux kernels may not boot if the hardware
224 * has more IRQ lines than the kernel expects.
225 */
226 DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64),
999e12bb
AL
227 DEFINE_PROP_END_OF_LIST(),
228};
229
230static void mpcore_priv_class_init(ObjectClass *klass, void *data)
231{
39bffca2 232 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb
AL
233 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
234
235 k->init = mpcore_priv_init;
39bffca2 236 dc->props = mpcore_priv_properties;
999e12bb
AL
237}
238
39bffca2
AL
239static TypeInfo mpcore_priv_info = {
240 .name = "arm11mpcore_priv",
241 .parent = TYPE_SYS_BUS_DEVICE,
242 .instance_size = sizeof(mpcore_priv_state),
243 .class_init = mpcore_priv_class_init,
f7c70325
PB
244};
245
83f7d43a 246static void arm11mpcore_register_types(void)
f7c70325 247{
39bffca2
AL
248 type_register_static(&mpcore_rirq_info);
249 type_register_static(&mpcore_priv_info);
f7c70325
PB
250}
251
83f7d43a 252type_init(arm11mpcore_register_types)
This page took 0.331331 seconds and 4 git commands to generate.