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 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());
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 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());
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 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
);
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());
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 qemu_irq mbox_irq
[MBOX_CHAN_COUNT
];
130 uint32_t ram_size
, vcram_size
;
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
);
157 error_propagate(errp
, err
);
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
);
170 object_property_set_bool(OBJECT(s
->uart0
), true, "realized", &err
);
172 error_propagate(errp
, err
);
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
]);
181 object_property_set_bool(OBJECT(&s
->aux
), true, "realized", &err
);
183 error_propagate(errp
, err
);
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
]);
192 object_property_set_bool(OBJECT(s
->systimer
), true, "realized", &err
);
194 error_propagate(errp
, err
);
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
]);
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, pic
[INTERRUPT_ARM_TIMER
]);
217 object_property_set_bool(OBJECT(s
->usb
), true, "realized", &err
);
219 error_propagate(errp
, err
);
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
);
230 error_propagate(errp
, err
);
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
);
241 error_propagate(errp
, err
);
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
);
259 error_propagate(errp
, err
);
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
]);
268 vcram_size
= (uint32_t)object_property_get_int(OBJECT(s
), "vcram-size",
271 error_propagate(errp
, err
);
275 object_property_set_int(OBJECT(&s
->fb
), ram_size
- vcram_size
,
278 object_property_set_bool(OBJECT(&s
->fb
), true, "realized", &err
);
280 error_propagate(errp
, err
);
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
);
291 error_propagate(errp
, err
);
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
]);
300 object_property_set_bool(OBJECT(s
->vchiq
), true, "realized", &err
);
302 error_propagate(errp
, err
);
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
);
313 error_propagate(errp
, err
);
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
]);
322 object_property_set_bool(OBJECT(&s
->dma
), true, "realized", &err
);
324 error_propagate(errp
, err
);
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
)