bcm283* refactoring continues
[qemu/ar7.git] / hw / arm / bcm2835_peripherals.c
blobbbad3734ee244a61af16e49654e5172063fb26f1
1 #include "hw/arm/bcm2835_peripherals.h"
2 #include "hw/arm/bcm2835_common.h"
3 #include "hw/arm/raspi_platform.h"
4 #include "exec/address-spaces.h"
6 // XXX: FIXME:
7 MemoryRegion *bcm2835_peripheral_mr;
8 AddressSpace *bcm2835_peripheral_as;
10 static void bcm2835_peripherals_init(Object *obj)
12 BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj);
13 SysBusDevice *dev;
15 /* We track two memory regions. One, for the peripheral devices
16 * themselves, which we export to our parent soc device, and
17 * one for the bus addresses used by the peripherals, which is
18 * used internally. The latter requires an alias. */
19 memory_region_init_io(&s->peri_mr, OBJECT(s), NULL, s,
20 "bcm2835_peripherals", 0x1000000);
21 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr);
23 memory_region_init_io(&s->gpu_bus_mr, OBJECT(s), NULL, s, "bcm2835_gpu_bus",
24 (uint64_t)1 << 32);
26 address_space_init(&s->gpu_bus_as, &s->gpu_bus_mr, "bcm2835_gpu_bus");
27 bcm2835_peripheral_mr = &s->gpu_bus_mr; // XXX
28 bcm2835_peripheral_as = &s->gpu_bus_as; // XXX
30 /* Interrupt Controller */
31 s->ic = dev = SYS_BUS_DEVICE(object_new("bcm2835_ic"));
32 object_property_add_child(obj, "ic", OBJECT(dev), NULL);
33 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
35 /* UART0 */
36 s->uart0 = dev = SYS_BUS_DEVICE(object_new("pl011"));
37 object_property_add_child(obj, "uart0", OBJECT(dev), NULL);
38 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
40 /* UART1 */
41 s->uart1 = dev = SYS_BUS_DEVICE(object_new("bcm2835_aux"));
42 object_property_add_child(obj, "uart1", OBJECT(dev), NULL);
43 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
45 /* System timer */
46 s->systimer = dev = SYS_BUS_DEVICE(object_new("bcm2835_st"));
47 object_property_add_child(obj, "systimer", OBJECT(dev), NULL);
48 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
50 /* ARM timer */
51 s->armtimer = dev = SYS_BUS_DEVICE(object_new("bcm2835_timer"));
52 object_property_add_child(obj, "armtimer", OBJECT(dev), NULL);
53 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
55 /* USB controller */
56 s->usb = dev = SYS_BUS_DEVICE(object_new("bcm2835_usb"));
57 object_property_add_child(obj, "usb", OBJECT(dev), NULL);
58 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
60 /* MPHI - Message-based Parallel Host Interface */
61 s->mphi = dev = SYS_BUS_DEVICE(object_new("bcm2835_mphi"));
62 object_property_add_child(obj, "mphi", OBJECT(dev), NULL);
63 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
65 /* Semaphores / Doorbells / Mailboxes */
66 s->sbm = dev = SYS_BUS_DEVICE(object_new("bcm2835_sbm"));
67 object_property_add_child(obj, "sbm", OBJECT(dev), NULL);
68 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
70 /* Power management */
71 s->power = dev = SYS_BUS_DEVICE(object_new("bcm2835_power"));
72 object_property_add_child(obj, "power", OBJECT(dev), NULL);
73 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
75 /* Framebuffer */
76 s->fb = dev = SYS_BUS_DEVICE(object_new("bcm2835_fb"));
77 object_property_add_child(obj, "fb", OBJECT(dev), NULL);
78 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
80 /* Property channel */
81 s->property = dev = SYS_BUS_DEVICE(object_new("bcm2835_property"));
82 object_property_add_child(obj, "property", OBJECT(dev), NULL);
83 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
85 /* VCHIQ */
86 s->vchiq = dev = SYS_BUS_DEVICE(object_new("bcm2835_vchiq"));
87 object_property_add_child(obj, "vchiq", OBJECT(dev), NULL);
88 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
90 /* Extended Mass Media Controller */
91 s->emmc = dev = SYS_BUS_DEVICE(object_new("bcm2835_emmc"));
92 object_property_add_child(obj, "emmc", OBJECT(dev), NULL);
93 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
95 /* DMA Channels */
96 s->dma = dev = SYS_BUS_DEVICE(object_new("bcm2835_dma"));
97 object_property_add_child(obj, "dma", OBJECT(dev), NULL);
98 qdev_set_parent_bus(DEVICE(dev), sysbus_get_default());
101 static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
103 BCM2835PeripheralState *s = BCM2835_PERIPHERALS(dev);
104 MemoryRegion *ram;
105 qemu_irq pic[72];
106 qemu_irq mbox_irq[MBOX_CHAN_COUNT];
107 hwaddr tmpoffset;
108 Error *err = NULL;
109 int n;
111 /* Interrupt Controller */
112 object_property_set_bool(OBJECT(s->ic), true, "realized", &err);
113 if (err) {
114 error_propagate(errp, err);
115 return;
118 memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
119 sysbus_mmio_get_region(s->ic, 0));
120 sysbus_pass_irq(SYS_BUS_DEVICE(s), s->ic);
122 for (n = 0; n < 72; n++) {
123 pic[n] = qdev_get_gpio_in(DEVICE(s->ic), n);
126 /* UART0 */
127 object_property_set_bool(OBJECT(s->uart0), true, "realized", &err);
128 if (err) {
129 error_propagate(errp, err);
130 return;
133 memory_region_add_subregion(&s->peri_mr, UART0_OFFSET,
134 sysbus_mmio_get_region(s->uart0, 0));
135 sysbus_connect_irq(s->uart0, 0, pic[INTERRUPT_VC_UART]);
137 /* UART1 */
138 object_property_set_bool(OBJECT(s->uart1), true, "realized", &err);
139 if (err) {
140 error_propagate(errp, err);
141 return;
144 memory_region_add_subregion(&s->peri_mr, UART1_OFFSET,
145 sysbus_mmio_get_region(s->uart1, 0));
146 sysbus_connect_irq(s->uart1, 0, pic[INTERRUPT_AUX]);
148 /* System timer */
149 object_property_set_bool(OBJECT(s->systimer), true, "realized", &err);
150 if (err) {
151 error_propagate(errp, err);
152 return;
155 memory_region_add_subregion(&s->peri_mr, ST_OFFSET,
156 sysbus_mmio_get_region(s->systimer, 0));
157 sysbus_connect_irq(s->systimer, 0, pic[INTERRUPT_TIMER0]);
158 sysbus_connect_irq(s->systimer, 1, pic[INTERRUPT_TIMER1]);
159 sysbus_connect_irq(s->systimer, 2, pic[INTERRUPT_TIMER2]);
160 sysbus_connect_irq(s->systimer, 3, pic[INTERRUPT_TIMER3]);
162 /* ARM timer */
163 object_property_set_bool(OBJECT(s->armtimer), true, "realized", &err);
164 if (err) {
165 error_propagate(errp, err);
166 return;
169 memory_region_add_subregion(&s->peri_mr, ARMCTRL_TIMER0_1_OFFSET,
170 sysbus_mmio_get_region(s->armtimer, 0));
171 sysbus_connect_irq(s->armtimer, 0, pic[INTERRUPT_ARM_TIMER]);
173 /* USB controller */
174 object_property_set_bool(OBJECT(s->usb), true, "realized", &err);
175 if (err) {
176 error_propagate(errp, err);
177 return;
180 memory_region_add_subregion(&s->peri_mr, USB_OFFSET,
181 sysbus_mmio_get_region(s->usb, 0));
182 sysbus_connect_irq(s->usb, 0, pic[INTERRUPT_VC_USB]);
184 /* MPHI - Message-based Parallel Host Interface */
185 object_property_set_bool(OBJECT(s->mphi), true, "realized", &err);
186 if (err) {
187 error_propagate(errp, err);
188 return;
191 memory_region_add_subregion(&s->peri_mr, MPHI_OFFSET,
192 sysbus_mmio_get_region(s->mphi, 0));
193 sysbus_connect_irq(s->mphi, 0, pic[INTERRUPT_HOSTPORT]);
195 /* Semaphores / Doorbells / Mailboxes */
196 object_property_set_bool(OBJECT(s->sbm), true, "realized", &err);
197 if (err) {
198 error_propagate(errp, err);
199 return;
202 memory_region_add_subregion(&s->peri_mr, ARMCTRL_0_SBM_OFFSET,
203 sysbus_mmio_get_region(s->sbm, 0));
204 sysbus_connect_irq(s->sbm, 0, pic[INTERRUPT_ARM_MAILBOX]);
206 for (n = 0; n < MBOX_CHAN_COUNT; n++) {
207 mbox_irq[n] = qdev_get_gpio_in(DEVICE(s->sbm), n);
210 /* Mailbox-addressable peripherals using (hopefully) free address space
211 * locations and pseudo-irqs to dispatch mailbox requests and responses
212 * between them. */
214 tmpoffset = ARMCTRL_0_SBM_OFFSET + 0x400;
216 /* Power management */
217 object_property_set_bool(OBJECT(s->power), true, "realized", &err);
218 if (err) {
219 error_propagate(errp, err);
220 return;
223 memory_region_add_subregion(&s->peri_mr, tmpoffset + (MBOX_CHAN_POWER<<4),
224 sysbus_mmio_get_region(s->power, 0));
225 sysbus_connect_irq(s->power, 0, mbox_irq[MBOX_CHAN_POWER]);
227 /* Framebuffer */
228 object_property_set_bool(OBJECT(s->fb), true, "realized", &err);
229 if (err) {
230 error_propagate(errp, err);
231 return;
234 memory_region_add_subregion(&s->peri_mr, tmpoffset + (MBOX_CHAN_FB<<4),
235 sysbus_mmio_get_region(s->fb, 0));
236 sysbus_connect_irq(s->fb, 0, mbox_irq[MBOX_CHAN_FB]);
238 /* Property channel */
239 object_property_set_bool(OBJECT(s->property), true, "realized", &err);
240 if (err) {
241 error_propagate(errp, err);
242 return;
245 memory_region_add_subregion(&s->peri_mr, tmpoffset + (MBOX_CHAN_PROPERTY<<4),
246 sysbus_mmio_get_region(s->property, 0));
247 sysbus_connect_irq(s->property, 0, mbox_irq[MBOX_CHAN_PROPERTY]);
249 /* VCHIQ */
250 object_property_set_bool(OBJECT(s->vchiq), true, "realized", &err);
251 if (err) {
252 error_propagate(errp, err);
253 return;
256 memory_region_add_subregion(&s->peri_mr, tmpoffset + (MBOX_CHAN_VCHIQ<<4),
257 sysbus_mmio_get_region(s->vchiq, 0));
258 sysbus_connect_irq(s->vchiq, 0, mbox_irq[MBOX_CHAN_VCHIQ]);
260 /* Extended Mass Media Controller */
261 object_property_set_bool(OBJECT(s->emmc), true, "realized", &err);
262 if (err) {
263 error_propagate(errp, err);
264 return;
267 memory_region_add_subregion(&s->peri_mr, EMMC_OFFSET,
268 sysbus_mmio_get_region(s->emmc, 0));
269 sysbus_connect_irq(s->emmc, 0, pic[INTERRUPT_VC_ARASANSDIO]);
271 /* DMA Channels */
272 object_property_set_bool(OBJECT(s->dma), true, "realized", &err);
273 if (err) {
274 error_propagate(errp, err);
275 return;
278 memory_region_add_subregion(&s->peri_mr, DMA_OFFSET,
279 sysbus_mmio_get_region(s->dma, 0));
280 memory_region_add_subregion(&s->peri_mr, 0xe05000, // XXX
281 sysbus_mmio_get_region(s->dma, 1));
283 sysbus_connect_irq(s->dma, 0, pic[INTERRUPT_DMA0]);
284 sysbus_connect_irq(s->dma, 1, pic[INTERRUPT_DMA1]);
285 sysbus_connect_irq(s->dma, 2, pic[INTERRUPT_VC_DMA2]);
286 sysbus_connect_irq(s->dma, 3, pic[INTERRUPT_VC_DMA3]);
287 sysbus_connect_irq(s->dma, 4, pic[INTERRUPT_DMA4]);
288 sysbus_connect_irq(s->dma, 5, pic[INTERRUPT_DMA5]);
289 sysbus_connect_irq(s->dma, 6, pic[INTERRUPT_DMA6]);
290 sysbus_connect_irq(s->dma, 7, pic[INTERRUPT_DMA7]);
291 sysbus_connect_irq(s->dma, 8, pic[INTERRUPT_DMA8]);
292 sysbus_connect_irq(s->dma, 9, pic[INTERRUPT_DMA9]);
293 sysbus_connect_irq(s->dma, 10, pic[INTERRUPT_DMA10]);
294 sysbus_connect_irq(s->dma, 11, pic[INTERRUPT_DMA11]);
295 sysbus_connect_irq(s->dma, 12, pic[INTERRUPT_DMA12]);
297 /* Map peripherals and RAM into the GPU address space. */
298 memory_region_init_alias(&s->peri_mr_alias, OBJECT(s),
299 "bcm2835_peripherals", &s->peri_mr, 0,
300 memory_region_size(&s->peri_mr));
302 memory_region_add_subregion_overlap(&s->gpu_bus_mr, BCM2835_VC_PERI_BASE,
303 &s->peri_mr_alias, 1);
305 /* XXX: assume that RAM is contiguous and mapped at system address zero */
306 ram = memory_region_find(get_system_memory(), 0, 1).mr;
307 assert(ram != NULL && memory_region_size(ram) >= 128 * 1024 * 1024);
309 /* RAM is aliased four times (different cache configurations) on the GPU */
310 for (n = 0; n < 4; n++) {
311 memory_region_init_alias(&s->ram_alias[n], OBJECT(s),
312 "bcm2835_gpu_ram_alias[*]", ram, 0,
313 memory_region_size(ram));
314 memory_region_add_subregion_overlap(&s->gpu_bus_mr, (hwaddr)n << 30,
315 &s->ram_alias[n], 0);
319 static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
321 DeviceClass *dc = DEVICE_CLASS(oc);
323 dc->realize = bcm2835_peripherals_realize;
326 static const TypeInfo bcm2835_peripherals_type_info = {
327 .name = TYPE_BCM2835_PERIPHERALS,
328 .parent = TYPE_SYS_BUS_DEVICE,
329 .instance_size = sizeof(BCM2835PeripheralState),
330 .instance_init = bcm2835_peripherals_init,
331 .class_init = bcm2835_peripherals_class_init,
334 static void bcm2835_peripherals_register_types(void)
336 type_register_static(&bcm2835_peripherals_type_info);
339 type_init(bcm2835_peripherals_register_types)