bcm2835_dma: refactor to use header file
[qemu/ar7.git] / hw / arm / bcm2835_peripherals.c
blob3101e4b8d50bfe3dd601c159146dd6e696244763
1 /*
2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
3 * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
5 * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
6 * Written by Andrew Baumann
8 * This code is licensed under the GNU GPLv2 and later.
9 */
11 #include "hw/arm/bcm2835_peripherals.h"
12 #include "hw/arm/bcm2835_mbox.h"
13 #include "hw/arm/raspi_platform.h"
15 static void bcm2835_peripherals_init(Object *obj)
17 BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj);
18 SysBusDevice *dev;
20 /* Memory region for peripheral devices, which we export to our parent */
21 memory_region_init_io(&s->peri_mr, OBJECT(s), NULL, s,
22 "bcm2835_peripherals", 0x1000000);
23 object_property_add_child(obj, "peripheral_io", OBJECT(&s->peri_mr), NULL);
24 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr);
26 /* Internal memory region for peripheral bus addresses (not exported) */
27 memory_region_init_io(&s->gpu_bus_mr, OBJECT(s), NULL, s, "bcm2835_gpu_bus",
28 (uint64_t)1 << 32);
29 object_property_add_child(obj, "gpu_bus", OBJECT(&s->gpu_bus_mr), NULL);
31 /* Internal memory region for communication of mailbox channel data */
32 memory_region_init_io(&s->mbox_mr, OBJECT(s), NULL, s, "bcm2835_mbox",
33 MBOX_CHAN_COUNT << 4);
35 /* Interrupt Controller */
36 s->ic = dev = SYS_BUS_DEVICE(object_new("bcm2835_ic"));
37 object_property_add_child(obj, "ic", OBJECT(dev), NULL);
38 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
40 /* UART0 */
41 s->uart0 = dev = SYS_BUS_DEVICE(object_new("pl011"));
42 object_property_add_child(obj, "uart0", OBJECT(dev), NULL);
43 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
45 /* AUX / UART1 */
46 object_initialize(&s->aux, sizeof(s->aux), TYPE_BCM2835_AUX);
47 object_property_add_child(obj, "aux", OBJECT(&s->aux), NULL);
48 qdev_set_parent_bus(DEVICE(&s->aux), sysbus_get_default());
50 /* System timer */
51 s->systimer = dev = SYS_BUS_DEVICE(object_new("bcm2835_st"));
52 object_property_add_child(obj, "systimer", OBJECT(dev), NULL);
53 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
55 /* ARM timer */
56 s->armtimer = dev = SYS_BUS_DEVICE(object_new("bcm2835_timer"));
57 object_property_add_child(obj, "armtimer", OBJECT(dev), NULL);
58 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
60 /* USB controller */
61 s->usb = dev = SYS_BUS_DEVICE(object_new("bcm2835_usb"));
62 object_property_add_child(obj, "usb", OBJECT(dev), NULL);
63 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
65 /* MPHI - Message-based Parallel Host Interface */
66 s->mphi = dev = SYS_BUS_DEVICE(object_new("bcm2835_mphi"));
67 object_property_add_child(obj, "mphi", OBJECT(dev), NULL);
68 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
70 /* Semaphores / Doorbells / Mailboxes */
71 s->sbm = dev = SYS_BUS_DEVICE(object_new("bcm2835_sbm"));
72 object_property_add_child(obj, "sbm", OBJECT(dev), NULL);
73 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
75 object_property_add_const_link(OBJECT(dev), "mbox_mr",
76 OBJECT(&s->mbox_mr), &error_abort);
78 /* Power management */
79 s->power = dev = SYS_BUS_DEVICE(object_new("bcm2835_power"));
80 object_property_add_child(obj, "power", OBJECT(dev), NULL);
81 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
83 /* Framebuffer */
84 object_initialize(&s->fb, sizeof(s->fb), TYPE_BCM2835_FB);
85 object_property_add_child(obj, "fb", OBJECT(&s->fb), NULL);
86 object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size",
87 &error_abort);
88 qdev_set_parent_bus(DEVICE(&s->fb), sysbus_get_default());
90 object_property_add_const_link(OBJECT(&s->fb), "dma_mr",
91 OBJECT(&s->gpu_bus_mr), &error_abort);
93 /* Property channel */
94 s->property = dev = SYS_BUS_DEVICE(object_new("bcm2835_property"));
95 object_property_add_child(obj, "property", OBJECT(dev), NULL);
96 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
98 object_property_add_const_link(OBJECT(dev), "bcm2835_fb",
99 OBJECT(&s->fb), &error_abort);
100 object_property_add_const_link(OBJECT(dev), "dma_mr",
101 OBJECT(&s->gpu_bus_mr), &error_abort);
103 /* VCHIQ */
104 s->vchiq = dev = SYS_BUS_DEVICE(object_new("bcm2835_vchiq"));
105 object_property_add_child(obj, "vchiq", OBJECT(dev), NULL);
106 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
108 /* Extended Mass Media Controller */
109 s->emmc = dev = SYS_BUS_DEVICE(object_new("bcm2835_emmc"));
110 object_property_add_child(obj, "emmc", OBJECT(dev), NULL);
111 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
113 /* DMA Channels */
114 object_initialize(&s->dma, sizeof(s->dma), TYPE_BCM2835_DMA);
115 object_property_add_child(obj, "dma", OBJECT(&s->dma), NULL);
116 qdev_set_parent_bus(DEVICE(&s->dma), sysbus_get_default());
118 object_property_add_const_link(OBJECT(&s->dma), "dma_mr",
119 OBJECT(&s->gpu_bus_mr), &error_abort);
123 static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
125 BCM2835PeripheralState *s = BCM2835_PERIPHERALS(dev);
126 MemoryRegion *ram;
127 qemu_irq pic[72];
128 qemu_irq mbox_irq[MBOX_CHAN_COUNT];
129 Error *err = NULL;
130 uint32_t ram_size, vcram_size;
131 int n;
133 /* Map peripherals and RAM into the GPU address space. */
134 memory_region_init_alias(&s->peri_mr_alias, OBJECT(s),
135 "bcm2835_peripherals", &s->peri_mr, 0,
136 memory_region_size(&s->peri_mr));
138 memory_region_add_subregion_overlap(&s->gpu_bus_mr, BCM2835_VC_PERI_BASE,
139 &s->peri_mr_alias, 1);
141 /* XXX: assume that RAM is contiguous and mapped at system address zero */
142 ram = memory_region_find(get_system_memory(), 0, 1).mr;
143 assert(ram != NULL && memory_region_size(ram) >= 128 * 1024 * 1024);
144 ram_size = memory_region_size(ram);
146 /* RAM is aliased four times (different cache configurations) on the GPU */
147 for (n = 0; n < 4; n++) {
148 memory_region_init_alias(&s->ram_alias[n], OBJECT(s),
149 "bcm2835_gpu_ram_alias[*]", ram, 0, ram_size);
150 memory_region_add_subregion_overlap(&s->gpu_bus_mr, (hwaddr)n << 30,
151 &s->ram_alias[n], 0);
154 /* Interrupt Controller */
155 object_property_set_bool(OBJECT(s->ic), true, "realized", &err);
156 if (err) {
157 error_propagate(errp, err);
158 return;
161 memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
162 sysbus_mmio_get_region(s->ic, 0));
163 sysbus_pass_irq(SYS_BUS_DEVICE(s), s->ic);
165 for (n = 0; n < 72; n++) {
166 pic[n] = qdev_get_gpio_in(DEVICE(s->ic), n);
169 /* UART0 */
170 object_property_set_bool(OBJECT(s->uart0), true, "realized", &err);
171 if (err) {
172 error_propagate(errp, err);
173 return;
176 memory_region_add_subregion(&s->peri_mr, UART0_OFFSET,
177 sysbus_mmio_get_region(s->uart0, 0));
178 sysbus_connect_irq(s->uart0, 0, pic[INTERRUPT_VC_UART]);
180 /* AUX / UART1 */
181 object_property_set_bool(OBJECT(&s->aux), true, "realized", &err);
182 if (err) {
183 error_propagate(errp, err);
184 return;
187 memory_region_add_subregion(&s->peri_mr, UART1_OFFSET,
188 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->aux), 0));
189 sysbus_connect_irq(SYS_BUS_DEVICE(&s->aux), 0, pic[INTERRUPT_AUX]);
191 /* System timer */
192 object_property_set_bool(OBJECT(s->systimer), true, "realized", &err);
193 if (err) {
194 error_propagate(errp, err);
195 return;
198 memory_region_add_subregion(&s->peri_mr, ST_OFFSET,
199 sysbus_mmio_get_region(s->systimer, 0));
200 sysbus_connect_irq(s->systimer, 0, pic[INTERRUPT_TIMER0]);
201 sysbus_connect_irq(s->systimer, 1, pic[INTERRUPT_TIMER1]);
202 sysbus_connect_irq(s->systimer, 2, pic[INTERRUPT_TIMER2]);
203 sysbus_connect_irq(s->systimer, 3, pic[INTERRUPT_TIMER3]);
205 /* ARM timer */
206 object_property_set_bool(OBJECT(s->armtimer), true, "realized", &err);
207 if (err) {
208 error_propagate(errp, err);
209 return;
212 memory_region_add_subregion(&s->peri_mr, ARMCTRL_TIMER0_1_OFFSET,
213 sysbus_mmio_get_region(s->armtimer, 0));
214 sysbus_connect_irq(s->armtimer, 0, pic[INTERRUPT_ARM_TIMER]);
216 /* USB controller */
217 object_property_set_bool(OBJECT(s->usb), true, "realized", &err);
218 if (err) {
219 error_propagate(errp, err);
220 return;
223 memory_region_add_subregion(&s->peri_mr, USB_OFFSET,
224 sysbus_mmio_get_region(s->usb, 0));
225 sysbus_connect_irq(s->usb, 0, pic[INTERRUPT_VC_USB]);
227 /* MPHI - Message-based Parallel Host Interface */
228 object_property_set_bool(OBJECT(s->mphi), true, "realized", &err);
229 if (err) {
230 error_propagate(errp, err);
231 return;
234 memory_region_add_subregion(&s->peri_mr, MPHI_OFFSET,
235 sysbus_mmio_get_region(s->mphi, 0));
236 sysbus_connect_irq(s->mphi, 0, pic[INTERRUPT_HOSTPORT]);
238 /* Semaphores / Doorbells / Mailboxes */
239 object_property_set_bool(OBJECT(s->sbm), true, "realized", &err);
240 if (err) {
241 error_propagate(errp, err);
242 return;
245 memory_region_add_subregion(&s->peri_mr, ARMCTRL_0_SBM_OFFSET,
246 sysbus_mmio_get_region(s->sbm, 0));
247 sysbus_connect_irq(s->sbm, 0, pic[INTERRUPT_ARM_MAILBOX]);
249 for (n = 0; n < MBOX_CHAN_COUNT; n++) {
250 mbox_irq[n] = qdev_get_gpio_in(DEVICE(s->sbm), n);
253 /* Mailbox-addressable peripherals use the private mbox_mr address space
254 * and pseudo-irqs to dispatch requests and responses. */
256 /* Power management */
257 object_property_set_bool(OBJECT(s->power), true, "realized", &err);
258 if (err) {
259 error_propagate(errp, err);
260 return;
263 memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_POWER<<4,
264 sysbus_mmio_get_region(s->power, 0));
265 sysbus_connect_irq(s->power, 0, mbox_irq[MBOX_CHAN_POWER]);
267 /* Framebuffer */
268 vcram_size = (uint32_t)object_property_get_int(OBJECT(s), "vcram-size",
269 &err);
270 if (err) {
271 error_propagate(errp, err);
272 return;
275 object_property_set_int(OBJECT(&s->fb), ram_size - vcram_size,
276 "vcram-base", &err);
278 object_property_set_bool(OBJECT(&s->fb), true, "realized", &err);
279 if (err) {
280 error_propagate(errp, err);
281 return;
284 memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_FB<<4,
285 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->fb), 0));
286 sysbus_connect_irq(SYS_BUS_DEVICE(&s->fb), 0, mbox_irq[MBOX_CHAN_FB]);
288 /* Property channel */
289 object_property_set_bool(OBJECT(s->property), true, "realized", &err);
290 if (err) {
291 error_propagate(errp, err);
292 return;
295 memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_PROPERTY<<4,
296 sysbus_mmio_get_region(s->property, 0));
297 sysbus_connect_irq(s->property, 0, mbox_irq[MBOX_CHAN_PROPERTY]);
299 /* VCHIQ */
300 object_property_set_bool(OBJECT(s->vchiq), true, "realized", &err);
301 if (err) {
302 error_propagate(errp, err);
303 return;
306 memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_VCHIQ<<4,
307 sysbus_mmio_get_region(s->vchiq, 0));
308 sysbus_connect_irq(s->vchiq, 0, mbox_irq[MBOX_CHAN_VCHIQ]);
310 /* Extended Mass Media Controller */
311 object_property_set_bool(OBJECT(s->emmc), true, "realized", &err);
312 if (err) {
313 error_propagate(errp, err);
314 return;
317 memory_region_add_subregion(&s->peri_mr, EMMC_OFFSET,
318 sysbus_mmio_get_region(s->emmc, 0));
319 sysbus_connect_irq(s->emmc, 0, pic[INTERRUPT_VC_ARASANSDIO]);
321 /* DMA Channels */
322 object_property_set_bool(OBJECT(&s->dma), true, "realized", &err);
323 if (err) {
324 error_propagate(errp, err);
325 return;
328 memory_region_add_subregion(&s->peri_mr, DMA_OFFSET,
329 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 0));
330 /* XXX: this address was in the original raspi port.
331 * It's unclear where it is derived from. */
332 memory_region_add_subregion(&s->peri_mr, 0xe05000,
333 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 1));
335 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 0, pic[INTERRUPT_DMA0]);
336 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 1, pic[INTERRUPT_DMA1]);
337 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 2, pic[INTERRUPT_VC_DMA2]);
338 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 3, pic[INTERRUPT_VC_DMA3]);
339 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 4, pic[INTERRUPT_DMA4]);
340 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 5, pic[INTERRUPT_DMA5]);
341 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 6, pic[INTERRUPT_DMA6]);
342 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 7, pic[INTERRUPT_DMA7]);
343 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 8, pic[INTERRUPT_DMA8]);
344 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 9, pic[INTERRUPT_DMA9]);
345 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 10, pic[INTERRUPT_DMA10]);
346 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 11, pic[INTERRUPT_DMA11]);
347 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), 12, pic[INTERRUPT_DMA12]);
350 static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
352 DeviceClass *dc = DEVICE_CLASS(oc);
354 dc->realize = bcm2835_peripherals_realize;
357 static const TypeInfo bcm2835_peripherals_type_info = {
358 .name = TYPE_BCM2835_PERIPHERALS,
359 .parent = TYPE_SYS_BUS_DEVICE,
360 .instance_size = sizeof(BCM2835PeripheralState),
361 .instance_init = bcm2835_peripherals_init,
362 .class_init = bcm2835_peripherals_class_init,
365 static void bcm2835_peripherals_register_types(void)
367 type_register_static(&bcm2835_peripherals_type_info);
370 type_init(bcm2835_peripherals_register_types)