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