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.
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
);
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",
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 object_initialize(&s
->ic
, sizeof(s
->ic
), TYPE_BCM2835_IC
);
37 object_property_add_child(obj
, "ic", OBJECT(&s
->ic
), NULL
);
38 qdev_set_parent_bus(DEVICE(&s
->ic
), sysbus_get_default());
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());
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());
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());
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());
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 object_initialize(&s
->mphi
, sizeof(s
->mphi
), TYPE_BCM2835_MPHI
);
67 object_property_add_child(obj
, "mphi", OBJECT(&s
->mphi
), NULL
);
68 qdev_set_parent_bus(DEVICE(&s
->mphi
), sysbus_get_default());
70 /* Semaphores / Doorbells / Mailboxes */
71 object_initialize(&s
->sbm
, sizeof(s
->sbm
), TYPE_BCM2835_SBM
);
72 object_property_add_child(obj
, "sbm", OBJECT(&s
->sbm
), NULL
);
73 qdev_set_parent_bus(DEVICE(&s
->sbm
), sysbus_get_default());
75 object_property_add_const_link(OBJECT(&s
->sbm
), "mbox_mr",
76 OBJECT(&s
->mbox_mr
), &error_abort
);
78 /* Power management */
79 object_initialize(&s
->power
, sizeof(s
->power
), TYPE_BCM2835_POWER
);
80 object_property_add_child(obj
, "power", OBJECT(&s
->power
), NULL
);
81 qdev_set_parent_bus(DEVICE(&s
->power
), sysbus_get_default());
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",
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 object_initialize(&s
->property
, sizeof(s
->property
), TYPE_BCM2835_PROPERTY
);
95 object_property_add_child(obj
, "property", OBJECT(&s
->property
), NULL
);
96 qdev_set_parent_bus(DEVICE(&s
->property
), sysbus_get_default());
98 object_property_add_const_link(OBJECT(&s
->property
), "bcm2835_fb",
99 OBJECT(&s
->fb
), &error_abort
);
100 object_property_add_const_link(OBJECT(&s
->property
), "dma_mr",
101 OBJECT(&s
->gpu_bus_mr
), &error_abort
);
104 object_initialize(&s
->vchiq
, sizeof(s
->vchiq
), TYPE_BCM2835_VCHIQ
);
105 object_property_add_child(obj
, "vchiq", OBJECT(&s
->vchiq
), NULL
);
106 qdev_set_parent_bus(DEVICE(&s
->vchiq
), sysbus_get_default());
108 /* Extended Mass Media Controller */
109 object_initialize(&s
->emmc
, sizeof(s
->emmc
), TYPE_BCM2835_EMMC
);
110 object_property_add_child(obj
, "emmc", OBJECT(&s
->emmc
), NULL
);
111 qdev_set_parent_bus(DEVICE(&s
->emmc
), sysbus_get_default());
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
);
128 uint32_t ram_size
, vcram_size
;
131 /* Map peripherals and RAM into the GPU address space. */
132 memory_region_init_alias(&s
->peri_mr_alias
, OBJECT(s
),
133 "bcm2835_peripherals", &s
->peri_mr
, 0,
134 memory_region_size(&s
->peri_mr
));
136 memory_region_add_subregion_overlap(&s
->gpu_bus_mr
, BCM2835_VC_PERI_BASE
,
137 &s
->peri_mr_alias
, 1);
139 /* XXX: assume that RAM is contiguous and mapped at system address zero */
140 ram
= memory_region_find(get_system_memory(), 0, 1).mr
;
141 assert(ram
!= NULL
&& memory_region_size(ram
) >= 128 * 1024 * 1024);
142 ram_size
= memory_region_size(ram
);
144 /* RAM is aliased four times (different cache configurations) on the GPU */
145 for (n
= 0; n
< 4; n
++) {
146 memory_region_init_alias(&s
->ram_alias
[n
], OBJECT(s
),
147 "bcm2835_gpu_ram_alias[*]", ram
, 0, ram_size
);
148 memory_region_add_subregion_overlap(&s
->gpu_bus_mr
, (hwaddr
)n
<< 30,
149 &s
->ram_alias
[n
], 0);
152 /* Interrupt Controller */
153 object_property_set_bool(OBJECT(&s
->ic
), true, "realized", &err
);
155 error_propagate(errp
, err
);
159 memory_region_add_subregion(&s
->peri_mr
, ARMCTRL_IC_OFFSET
,
160 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->ic
), 0));
161 sysbus_pass_irq(SYS_BUS_DEVICE(s
), SYS_BUS_DEVICE(&s
->ic
));
164 object_property_set_bool(OBJECT(s
->uart0
), true, "realized", &err
);
166 error_propagate(errp
, err
);
170 memory_region_add_subregion(&s
->peri_mr
, UART0_OFFSET
,
171 sysbus_mmio_get_region(s
->uart0
, 0));
172 sysbus_connect_irq(s
->uart0
, 0,
173 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_VC_UART
));
176 object_property_set_bool(OBJECT(&s
->aux
), true, "realized", &err
);
178 error_propagate(errp
, err
);
182 memory_region_add_subregion(&s
->peri_mr
, UART1_OFFSET
,
183 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->aux
), 0));
184 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->aux
), 0,
185 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_AUX
));
188 object_property_set_bool(OBJECT(s
->systimer
), true, "realized", &err
);
190 error_propagate(errp
, err
);
194 memory_region_add_subregion(&s
->peri_mr
, ST_OFFSET
,
195 sysbus_mmio_get_region(s
->systimer
, 0));
196 sysbus_connect_irq(s
->systimer
, 0,
197 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_TIMER0
));
198 sysbus_connect_irq(s
->systimer
, 1,
199 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_TIMER1
));
200 sysbus_connect_irq(s
->systimer
, 2,
201 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_TIMER2
));
202 sysbus_connect_irq(s
->systimer
, 3,
203 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_TIMER3
));
206 object_property_set_bool(OBJECT(s
->armtimer
), true, "realized", &err
);
208 error_propagate(errp
, err
);
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,
215 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_ARM_TIMER
));
218 object_property_set_bool(OBJECT(s
->usb
), true, "realized", &err
);
220 error_propagate(errp
, err
);
224 memory_region_add_subregion(&s
->peri_mr
, USB_OFFSET
,
225 sysbus_mmio_get_region(s
->usb
, 0));
226 sysbus_connect_irq(s
->usb
, 0,
227 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_VC_USB
));
229 /* MPHI - Message-based Parallel Host Interface */
230 object_property_set_bool(OBJECT(&s
->mphi
), true, "realized", &err
);
232 error_propagate(errp
, err
);
236 memory_region_add_subregion(&s
->peri_mr
, MPHI_OFFSET
,
237 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->mphi
), 0));
238 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->mphi
), 0,
239 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_HOSTPORT
));
241 /* Semaphores / Doorbells / Mailboxes */
242 object_property_set_bool(OBJECT(&s
->sbm
), true, "realized", &err
);
244 error_propagate(errp
, err
);
248 memory_region_add_subregion(&s
->peri_mr
, ARMCTRL_0_SBM_OFFSET
,
249 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->sbm
), 0));
250 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->sbm
), 0,
251 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_ARM_MAILBOX
));
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
);
259 error_propagate(errp
, err
);
263 memory_region_add_subregion(&s
->mbox_mr
, MBOX_CHAN_POWER
<<4,
264 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->power
), 0));
265 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->power
), 0,
266 qdev_get_gpio_in(DEVICE(&s
->sbm
), MBOX_CHAN_POWER
));
269 vcram_size
= (uint32_t)object_property_get_int(OBJECT(s
), "vcram-size",
272 error_propagate(errp
, err
);
276 object_property_set_int(OBJECT(&s
->fb
), ram_size
- vcram_size
,
279 object_property_set_bool(OBJECT(&s
->fb
), true, "realized", &err
);
281 error_propagate(errp
, err
);
285 memory_region_add_subregion(&s
->mbox_mr
, MBOX_CHAN_FB
<<4,
286 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->fb
), 0));
287 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->fb
), 0,
288 qdev_get_gpio_in(DEVICE(&s
->sbm
), MBOX_CHAN_FB
));
290 /* Property channel */
291 object_property_set_bool(OBJECT(&s
->property
), true, "realized", &err
);
293 error_propagate(errp
, err
);
297 memory_region_add_subregion(&s
->mbox_mr
, MBOX_CHAN_PROPERTY
<<4,
298 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->property
), 0));
299 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->property
), 0,
300 qdev_get_gpio_in(DEVICE(&s
->sbm
), MBOX_CHAN_PROPERTY
));
303 object_property_set_bool(OBJECT(&s
->vchiq
), true, "realized", &err
);
305 error_propagate(errp
, err
);
309 memory_region_add_subregion(&s
->mbox_mr
, MBOX_CHAN_VCHIQ
<<4,
310 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->vchiq
), 0));
311 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->vchiq
), 0,
312 qdev_get_gpio_in(DEVICE(&s
->sbm
), MBOX_CHAN_VCHIQ
));
314 /* Extended Mass Media Controller */
315 object_property_set_bool(OBJECT(&s
->emmc
), true, "realized", &err
);
317 error_propagate(errp
, err
);
321 memory_region_add_subregion(&s
->peri_mr
, EMMC_OFFSET
,
322 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->emmc
), 0));
323 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->emmc
), 0,
324 qdev_get_gpio_in(DEVICE(&s
->ic
),
325 INTERRUPT_VC_ARASANSDIO
));
328 object_property_set_bool(OBJECT(&s
->dma
), true, "realized", &err
);
330 error_propagate(errp
, err
);
334 memory_region_add_subregion(&s
->peri_mr
, DMA_OFFSET
,
335 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->dma
), 0));
336 /* XXX: this address was in the original raspi port.
337 * It's unclear where it is derived from. */
338 memory_region_add_subregion(&s
->peri_mr
, 0xe05000,
339 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s
->dma
), 1));
341 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 0,
342 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA0
));
343 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 1,
344 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA1
));
345 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 2,
346 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_VC_DMA2
));
347 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 3,
348 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_VC_DMA3
));
349 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 4,
350 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA4
));
351 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 5,
352 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA5
));
353 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 6,
354 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA6
));
355 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 7,
356 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA7
));
357 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 8,
358 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA8
));
359 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 9,
360 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA9
));
361 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 10,
362 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA10
));
363 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 11,
364 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA11
));
365 sysbus_connect_irq(SYS_BUS_DEVICE(&s
->dma
), 12,
366 qdev_get_gpio_in(DEVICE(&s
->ic
), INTERRUPT_DMA12
));
369 static void bcm2835_peripherals_class_init(ObjectClass
*oc
, void *data
)
371 DeviceClass
*dc
= DEVICE_CLASS(oc
);
373 dc
->realize
= bcm2835_peripherals_realize
;
376 static const TypeInfo bcm2835_peripherals_type_info
= {
377 .name
= TYPE_BCM2835_PERIPHERALS
,
378 .parent
= TYPE_SYS_BUS_DEVICE
,
379 .instance_size
= sizeof(BCM2835PeripheralState
),
380 .instance_init
= bcm2835_peripherals_init
,
381 .class_init
= bcm2835_peripherals_class_init
,
384 static void bcm2835_peripherals_register_types(void)
386 type_register_static(&bcm2835_peripherals_type_info
);
389 type_init(bcm2835_peripherals_register_types
)