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"
14 #include "exec/address-spaces.h"
16 static void bcm2835_peripherals_init(Object
*obj
)
18 BCM2835PeripheralState
*s
= BCM2835_PERIPHERALS(obj
);
21 /* Memory region for peripheral devices, which we export to our parent */
22 memory_region_init_io(&s
->peri_mr
, OBJECT(s
), NULL
, s
,
23 "bcm2835_peripherals", 0x1000000);
24 object_property_add_child(obj
, "peripheral_io", OBJECT(&s
->peri_mr
), NULL
);
25 sysbus_init_mmio(SYS_BUS_DEVICE(s
), &s
->peri_mr
);
27 /* Internal memory region for peripheral bus addresses (not exported) */
28 memory_region_init_io(&s
->gpu_bus_mr
, OBJECT(s
), NULL
, s
, "bcm2835_gpu_bus",
30 object_property_add_child(obj
, "gpu_bus", OBJECT(&s
->gpu_bus_mr
), NULL
);
32 /* Internal memory region for communication of mailbox channel data */
33 memory_region_init_io(&s
->mbox_mr
, OBJECT(s
), NULL
, s
, "bcm2835_mbox",
34 MBOX_CHAN_COUNT
<< 4);
36 /* Interrupt Controller */
37 s
->ic
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_ic"));
38 object_property_add_child(obj
, "ic", OBJECT(dev
), NULL
);
39 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
42 s
->uart0
= dev
= SYS_BUS_DEVICE(object_new("pl011"));
43 object_property_add_child(obj
, "uart0", OBJECT(dev
), NULL
);
44 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
47 s
->uart1
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_aux"));
48 object_property_add_child(obj
, "uart1", OBJECT(dev
), NULL
);
49 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
52 s
->systimer
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_st"));
53 object_property_add_child(obj
, "systimer", OBJECT(dev
), NULL
);
54 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
57 s
->armtimer
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_timer"));
58 object_property_add_child(obj
, "armtimer", OBJECT(dev
), NULL
);
59 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
62 s
->usb
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_usb"));
63 object_property_add_child(obj
, "usb", OBJECT(dev
), NULL
);
64 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
66 /* MPHI - Message-based Parallel Host Interface */
67 s
->mphi
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_mphi"));
68 object_property_add_child(obj
, "mphi", OBJECT(dev
), NULL
);
69 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
71 /* Semaphores / Doorbells / Mailboxes */
72 s
->sbm
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_sbm"));
73 object_property_add_child(obj
, "sbm", OBJECT(dev
), NULL
);
74 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
76 object_property_add_const_link(OBJECT(dev
), "mbox_mr",
77 OBJECT(&s
->mbox_mr
), &error_abort
);
79 /* Power management */
80 s
->power
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_power"));
81 object_property_add_child(obj
, "power", OBJECT(dev
), NULL
);
82 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
85 s
->fb
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_fb"));
86 object_property_add_child(obj
, "fb", OBJECT(dev
), NULL
);
87 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
89 object_property_add_const_link(OBJECT(dev
), "dma_mr",
90 OBJECT(&s
->gpu_bus_mr
), &error_abort
);
92 /* Property channel */
93 s
->property
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_property"));
94 object_property_add_child(obj
, "property", OBJECT(dev
), NULL
);
95 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
97 object_property_add_const_link(OBJECT(dev
), "bcm2835_fb",
98 OBJECT(s
->fb
), &error_abort
);
99 object_property_add_const_link(OBJECT(dev
), "dma_mr",
100 OBJECT(&s
->gpu_bus_mr
), &error_abort
);
103 s
->vchiq
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_vchiq"));
104 object_property_add_child(obj
, "vchiq", OBJECT(dev
), NULL
);
105 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
107 /* Extended Mass Media Controller */
108 s
->emmc
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_emmc"));
109 object_property_add_child(obj
, "emmc", OBJECT(dev
), NULL
);
110 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
113 s
->dma
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_dma"));
114 object_property_add_child(obj
, "dma", OBJECT(dev
), NULL
);
115 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
117 object_property_add_const_link(OBJECT(dev
), "dma_mr",
118 OBJECT(&s
->gpu_bus_mr
), &error_abort
);
121 static void bcm2835_peripherals_realize(DeviceState
*dev
, Error
**errp
)
123 BCM2835PeripheralState
*s
= BCM2835_PERIPHERALS(dev
);
126 qemu_irq mbox_irq
[MBOX_CHAN_COUNT
];
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(s
->ic
, 0));
161 sysbus_pass_irq(SYS_BUS_DEVICE(s
), s
->ic
);
163 for (n
= 0; n
< 72; n
++) {
164 pic
[n
] = qdev_get_gpio_in(DEVICE(s
->ic
), n
);
168 object_property_set_bool(OBJECT(s
->uart0
), true, "realized", &err
);
170 error_propagate(errp
, err
);
174 memory_region_add_subregion(&s
->peri_mr
, UART0_OFFSET
,
175 sysbus_mmio_get_region(s
->uart0
, 0));
176 sysbus_connect_irq(s
->uart0
, 0, pic
[INTERRUPT_VC_UART
]);
179 object_property_set_bool(OBJECT(s
->uart1
), true, "realized", &err
);
181 error_propagate(errp
, err
);
185 memory_region_add_subregion(&s
->peri_mr
, UART1_OFFSET
,
186 sysbus_mmio_get_region(s
->uart1
, 0));
187 sysbus_connect_irq(s
->uart1
, 0, pic
[INTERRUPT_AUX
]);
190 object_property_set_bool(OBJECT(s
->systimer
), true, "realized", &err
);
192 error_propagate(errp
, err
);
196 memory_region_add_subregion(&s
->peri_mr
, ST_OFFSET
,
197 sysbus_mmio_get_region(s
->systimer
, 0));
198 sysbus_connect_irq(s
->systimer
, 0, pic
[INTERRUPT_TIMER0
]);
199 sysbus_connect_irq(s
->systimer
, 1, pic
[INTERRUPT_TIMER1
]);
200 sysbus_connect_irq(s
->systimer
, 2, pic
[INTERRUPT_TIMER2
]);
201 sysbus_connect_irq(s
->systimer
, 3, pic
[INTERRUPT_TIMER3
]);
204 object_property_set_bool(OBJECT(s
->armtimer
), true, "realized", &err
);
206 error_propagate(errp
, err
);
210 memory_region_add_subregion(&s
->peri_mr
, ARMCTRL_TIMER0_1_OFFSET
,
211 sysbus_mmio_get_region(s
->armtimer
, 0));
212 sysbus_connect_irq(s
->armtimer
, 0, pic
[INTERRUPT_ARM_TIMER
]);
215 object_property_set_bool(OBJECT(s
->usb
), true, "realized", &err
);
217 error_propagate(errp
, err
);
221 memory_region_add_subregion(&s
->peri_mr
, USB_OFFSET
,
222 sysbus_mmio_get_region(s
->usb
, 0));
223 sysbus_connect_irq(s
->usb
, 0, pic
[INTERRUPT_VC_USB
]);
225 /* MPHI - Message-based Parallel Host Interface */
226 object_property_set_bool(OBJECT(s
->mphi
), true, "realized", &err
);
228 error_propagate(errp
, err
);
232 memory_region_add_subregion(&s
->peri_mr
, MPHI_OFFSET
,
233 sysbus_mmio_get_region(s
->mphi
, 0));
234 sysbus_connect_irq(s
->mphi
, 0, pic
[INTERRUPT_HOSTPORT
]);
236 /* Semaphores / Doorbells / Mailboxes */
237 object_property_set_bool(OBJECT(s
->sbm
), true, "realized", &err
);
239 error_propagate(errp
, err
);
243 memory_region_add_subregion(&s
->peri_mr
, ARMCTRL_0_SBM_OFFSET
,
244 sysbus_mmio_get_region(s
->sbm
, 0));
245 sysbus_connect_irq(s
->sbm
, 0, pic
[INTERRUPT_ARM_MAILBOX
]);
247 for (n
= 0; n
< MBOX_CHAN_COUNT
; n
++) {
248 mbox_irq
[n
] = qdev_get_gpio_in(DEVICE(s
->sbm
), n
);
251 /* Mailbox-addressable peripherals use the private mbox_mr address space
252 * and pseudo-irqs to dispatch requests and responses. */
254 /* Power management */
255 object_property_set_bool(OBJECT(s
->power
), true, "realized", &err
);
257 error_propagate(errp
, err
);
261 memory_region_add_subregion(&s
->mbox_mr
, MBOX_CHAN_POWER
<<4,
262 sysbus_mmio_get_region(s
->power
, 0));
263 sysbus_connect_irq(s
->power
, 0, mbox_irq
[MBOX_CHAN_POWER
]);
266 object_property_set_int(OBJECT(s
->fb
), ram_size
- s
->vcram_size
,
268 object_property_set_int(OBJECT(s
->fb
), s
->vcram_size
, "vcram-size", &err
);
270 object_property_set_bool(OBJECT(s
->fb
), true, "realized", &err
);
272 error_propagate(errp
, err
);
276 memory_region_add_subregion(&s
->mbox_mr
, MBOX_CHAN_FB
<<4,
277 sysbus_mmio_get_region(s
->fb
, 0));
278 sysbus_connect_irq(s
->fb
, 0, mbox_irq
[MBOX_CHAN_FB
]);
280 /* Property channel */
281 object_property_set_bool(OBJECT(s
->property
), true, "realized", &err
);
283 error_propagate(errp
, err
);
287 memory_region_add_subregion(&s
->mbox_mr
, MBOX_CHAN_PROPERTY
<<4,
288 sysbus_mmio_get_region(s
->property
, 0));
289 sysbus_connect_irq(s
->property
, 0, mbox_irq
[MBOX_CHAN_PROPERTY
]);
292 object_property_set_bool(OBJECT(s
->vchiq
), true, "realized", &err
);
294 error_propagate(errp
, err
);
298 memory_region_add_subregion(&s
->mbox_mr
, MBOX_CHAN_VCHIQ
<<4,
299 sysbus_mmio_get_region(s
->vchiq
, 0));
300 sysbus_connect_irq(s
->vchiq
, 0, mbox_irq
[MBOX_CHAN_VCHIQ
]);
302 /* Extended Mass Media Controller */
303 object_property_set_bool(OBJECT(s
->emmc
), true, "realized", &err
);
305 error_propagate(errp
, err
);
309 memory_region_add_subregion(&s
->peri_mr
, EMMC_OFFSET
,
310 sysbus_mmio_get_region(s
->emmc
, 0));
311 sysbus_connect_irq(s
->emmc
, 0, pic
[INTERRUPT_VC_ARASANSDIO
]);
314 object_property_set_bool(OBJECT(s
->dma
), true, "realized", &err
);
316 error_propagate(errp
, err
);
320 memory_region_add_subregion(&s
->peri_mr
, DMA_OFFSET
,
321 sysbus_mmio_get_region(s
->dma
, 0));
322 /* XXX: this address was in the original raspi port.
323 * It's unclear where it is derived from. */
324 memory_region_add_subregion(&s
->peri_mr
, 0xe05000,
325 sysbus_mmio_get_region(s
->dma
, 1));
327 sysbus_connect_irq(s
->dma
, 0, pic
[INTERRUPT_DMA0
]);
328 sysbus_connect_irq(s
->dma
, 1, pic
[INTERRUPT_DMA1
]);
329 sysbus_connect_irq(s
->dma
, 2, pic
[INTERRUPT_VC_DMA2
]);
330 sysbus_connect_irq(s
->dma
, 3, pic
[INTERRUPT_VC_DMA3
]);
331 sysbus_connect_irq(s
->dma
, 4, pic
[INTERRUPT_DMA4
]);
332 sysbus_connect_irq(s
->dma
, 5, pic
[INTERRUPT_DMA5
]);
333 sysbus_connect_irq(s
->dma
, 6, pic
[INTERRUPT_DMA6
]);
334 sysbus_connect_irq(s
->dma
, 7, pic
[INTERRUPT_DMA7
]);
335 sysbus_connect_irq(s
->dma
, 8, pic
[INTERRUPT_DMA8
]);
336 sysbus_connect_irq(s
->dma
, 9, pic
[INTERRUPT_DMA9
]);
337 sysbus_connect_irq(s
->dma
, 10, pic
[INTERRUPT_DMA10
]);
338 sysbus_connect_irq(s
->dma
, 11, pic
[INTERRUPT_DMA11
]);
339 sysbus_connect_irq(s
->dma
, 12, pic
[INTERRUPT_DMA12
]);
342 static Property bcm2835_peripherals_props
[] = {
343 DEFINE_PROP_UINT32("vcram-size", BCM2835PeripheralState
, vcram_size
, 0),
344 DEFINE_PROP_END_OF_LIST()
347 static void bcm2835_peripherals_class_init(ObjectClass
*oc
, void *data
)
349 DeviceClass
*dc
= DEVICE_CLASS(oc
);
351 dc
->props
= bcm2835_peripherals_props
;
352 dc
->realize
= bcm2835_peripherals_realize
;
355 static const TypeInfo bcm2835_peripherals_type_info
= {
356 .name
= TYPE_BCM2835_PERIPHERALS
,
357 .parent
= TYPE_SYS_BUS_DEVICE
,
358 .instance_size
= sizeof(BCM2835PeripheralState
),
359 .instance_init
= bcm2835_peripherals_init
,
360 .class_init
= bcm2835_peripherals_class_init
,
363 static void bcm2835_peripherals_register_types(void)
365 type_register_static(&bcm2835_peripherals_type_info
);
368 type_init(bcm2835_peripherals_register_types
)