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