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