xref: /qemu/hw/arm/bcm2835_peripherals.c (revision 01b2ffce)
1 /*
2  * Raspberry Pi emulation (c) 2012 Gregory Estrade
3  * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
4  *
5  * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
6  * Written by Andrew Baumann
7  *
8  * This code is licensed under the GNU GPLv2 and later.
9  */
10 
11 #include "qemu/osdep.h"
12 #include "qapi/error.h"
13 #include "hw/arm/bcm2835_peripherals.h"
14 #include "hw/misc/bcm2835_mbox_defs.h"
15 #include "hw/arm/raspi_platform.h"
16 #include "sysemu/sysemu.h"
17 
18 /* Peripheral base address on the VC (GPU) system bus */
19 #define BCM2835_VC_PERI_BASE 0x7e000000
20 
21 /* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */
22 #define BCM2835_SDHC_CAPAREG 0x52034b4
23 
24 static void bcm2835_peripherals_init(Object *obj)
25 {
26     BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj);
27 
28     /* Memory region for peripheral devices, which we export to our parent */
29     memory_region_init(&s->peri_mr, obj,"bcm2835-peripherals", 0x1000000);
30     object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr), NULL);
31     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr);
32 
33     /* Internal memory region for peripheral bus addresses (not exported) */
34     memory_region_init(&s->gpu_bus_mr, obj, "bcm2835-gpu", (uint64_t)1 << 32);
35     object_property_add_child(obj, "gpu-bus", OBJECT(&s->gpu_bus_mr), NULL);
36 
37     /* Internal memory region for request/response communication with
38      * mailbox-addressable peripherals (not exported)
39      */
40     memory_region_init(&s->mbox_mr, obj, "bcm2835-mbox",
41                        MBOX_CHAN_COUNT << MBOX_AS_CHAN_SHIFT);
42 
43     /* Interrupt Controller */
44     object_initialize(&s->ic, sizeof(s->ic), TYPE_BCM2835_IC);
45     object_property_add_child(obj, "ic", OBJECT(&s->ic), NULL);
46     qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default());
47 
48     /* UART0 */
49     s->uart0 = SYS_BUS_DEVICE(object_new("pl011"));
50     object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL);
51     qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default());
52 
53     /* AUX / UART1 */
54     object_initialize(&s->aux, sizeof(s->aux), TYPE_BCM2835_AUX);
55     object_property_add_child(obj, "aux", OBJECT(&s->aux), NULL);
56     qdev_set_parent_bus(DEVICE(&s->aux), sysbus_get_default());
57 
58     /* Mailboxes */
59     object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX);
60     object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL);
61     qdev_set_parent_bus(DEVICE(&s->mboxes), sysbus_get_default());
62 
63     object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr",
64                                    OBJECT(&s->mbox_mr), &error_abort);
65 
66     /* Framebuffer */
67     object_initialize(&s->fb, sizeof(s->fb), TYPE_BCM2835_FB);
68     object_property_add_child(obj, "fb", OBJECT(&s->fb), NULL);
69     object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size",
70                               &error_abort);
71     qdev_set_parent_bus(DEVICE(&s->fb), sysbus_get_default());
72 
73     object_property_add_const_link(OBJECT(&s->fb), "dma-mr",
74                                    OBJECT(&s->gpu_bus_mr), &error_abort);
75 
76     /* Property channel */
77     object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY);
78     object_property_add_child(obj, "property", OBJECT(&s->property), NULL);
79     object_property_add_alias(obj, "board-rev", OBJECT(&s->property),
80                               "board-rev", &error_abort);
81     qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default());
82 
83     object_property_add_const_link(OBJECT(&s->property), "fb",
84                                    OBJECT(&s->fb), &error_abort);
85     object_property_add_const_link(OBJECT(&s->property), "dma-mr",
86                                    OBJECT(&s->gpu_bus_mr), &error_abort);
87 
88     /* Random Number Generator */
89     object_initialize(&s->rng, sizeof(s->rng), TYPE_BCM2835_RNG);
90     object_property_add_child(obj, "rng", OBJECT(&s->rng), NULL);
91     qdev_set_parent_bus(DEVICE(&s->rng), sysbus_get_default());
92 
93     /* Extended Mass Media Controller */
94     object_initialize(&s->sdhci, sizeof(s->sdhci), TYPE_SYSBUS_SDHCI);
95     object_property_add_child(obj, "sdhci", OBJECT(&s->sdhci), NULL);
96     qdev_set_parent_bus(DEVICE(&s->sdhci), sysbus_get_default());
97 
98     /* SDHOST */
99     object_initialize(&s->sdhost, sizeof(s->sdhost), TYPE_BCM2835_SDHOST);
100     object_property_add_child(obj, "sdhost", OBJECT(&s->sdhost), NULL);
101     qdev_set_parent_bus(DEVICE(&s->sdhost), sysbus_get_default());
102 
103     /* DMA Channels */
104     object_initialize(&s->dma, sizeof(s->dma), TYPE_BCM2835_DMA);
105     object_property_add_child(obj, "dma", OBJECT(&s->dma), NULL);
106     qdev_set_parent_bus(DEVICE(&s->dma), sysbus_get_default());
107 
108     object_property_add_const_link(OBJECT(&s->dma), "dma-mr",
109                                    OBJECT(&s->gpu_bus_mr), &error_abort);
110 
111     /* GPIO */
112     object_initialize(&s->gpio, sizeof(s->gpio), TYPE_BCM2835_GPIO);
113     object_property_add_child(obj, "gpio", OBJECT(&s->gpio), NULL);
114     qdev_set_parent_bus(DEVICE(&s->gpio), sysbus_get_default());
115 
116     object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhci",
117                                    OBJECT(&s->sdhci.sdbus), &error_abort);
118     object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost",
119                                    OBJECT(&s->sdhost.sdbus), &error_abort);
120 }
121 
122 static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
123 {
124     BCM2835PeripheralState *s = BCM2835_PERIPHERALS(dev);
125     Object *obj;
126     MemoryRegion *ram;
127     Error *err = NULL;
128     uint32_t ram_size, vcram_size;
129     int n;
130 
131     obj = object_property_get_link(OBJECT(dev), "ram", &err);
132     if (obj == NULL) {
133         error_setg(errp, "%s: required ram link not found: %s",
134                    __func__, error_get_pretty(err));
135         return;
136     }
137 
138     ram = MEMORY_REGION(obj);
139     ram_size = memory_region_size(ram);
140 
141     /* Map peripherals and RAM into the GPU address space. */
142     memory_region_init_alias(&s->peri_mr_alias, OBJECT(s),
143                              "bcm2835-peripherals", &s->peri_mr, 0,
144                              memory_region_size(&s->peri_mr));
145 
146     memory_region_add_subregion_overlap(&s->gpu_bus_mr, BCM2835_VC_PERI_BASE,
147                                         &s->peri_mr_alias, 1);
148 
149     /* RAM is aliased four times (different cache configurations) on the GPU */
150     for (n = 0; n < 4; n++) {
151         memory_region_init_alias(&s->ram_alias[n], OBJECT(s),
152                                  "bcm2835-gpu-ram-alias[*]", ram, 0, ram_size);
153         memory_region_add_subregion_overlap(&s->gpu_bus_mr, (hwaddr)n << 30,
154                                             &s->ram_alias[n], 0);
155     }
156 
157     /* Interrupt Controller */
158     object_property_set_bool(OBJECT(&s->ic), true, "realized", &err);
159     if (err) {
160         error_propagate(errp, err);
161         return;
162     }
163 
164     memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
165                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
166     sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));
167 
168     /* UART0 */
169     qdev_prop_set_chr(DEVICE(s->uart0), "chardev", serial_hds[0]);
170     object_property_set_bool(OBJECT(s->uart0), true, "realized", &err);
171     if (err) {
172         error_propagate(errp, err);
173         return;
174     }
175 
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,
179         qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
180                                INTERRUPT_UART));
181     /* AUX / UART1 */
182     qdev_prop_set_chr(DEVICE(&s->aux), "chardev", serial_hds[1]);
183 
184     object_property_set_bool(OBJECT(&s->aux), true, "realized", &err);
185     if (err) {
186         error_propagate(errp, err);
187         return;
188     }
189 
190     memory_region_add_subregion(&s->peri_mr, UART1_OFFSET,
191                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->aux), 0));
192     sysbus_connect_irq(SYS_BUS_DEVICE(&s->aux), 0,
193         qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
194                                INTERRUPT_AUX));
195 
196     /* Mailboxes */
197     object_property_set_bool(OBJECT(&s->mboxes), true, "realized", &err);
198     if (err) {
199         error_propagate(errp, err);
200         return;
201     }
202 
203     memory_region_add_subregion(&s->peri_mr, ARMCTRL_0_SBM_OFFSET,
204                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mboxes), 0));
205     sysbus_connect_irq(SYS_BUS_DEVICE(&s->mboxes), 0,
206         qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ,
207                                INTERRUPT_ARM_MAILBOX));
208 
209     /* Framebuffer */
210     vcram_size = (uint32_t)object_property_get_int(OBJECT(s), "vcram-size",
211                                                    &err);
212     if (err) {
213         error_propagate(errp, err);
214         return;
215     }
216 
217     object_property_set_int(OBJECT(&s->fb), ram_size - vcram_size,
218                             "vcram-base", &err);
219     if (err) {
220         error_propagate(errp, err);
221         return;
222     }
223 
224     object_property_set_bool(OBJECT(&s->fb), true, "realized", &err);
225     if (err) {
226         error_propagate(errp, err);
227         return;
228     }
229 
230     memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_FB << MBOX_AS_CHAN_SHIFT,
231                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->fb), 0));
232     sysbus_connect_irq(SYS_BUS_DEVICE(&s->fb), 0,
233                        qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB));
234 
235     /* Property channel */
236     object_property_set_bool(OBJECT(&s->property), true, "realized", &err);
237     if (err) {
238         error_propagate(errp, err);
239         return;
240     }
241 
242     memory_region_add_subregion(&s->mbox_mr,
243                 MBOX_CHAN_PROPERTY << MBOX_AS_CHAN_SHIFT,
244                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->property), 0));
245     sysbus_connect_irq(SYS_BUS_DEVICE(&s->property), 0,
246                       qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY));
247 
248     /* Random Number Generator */
249     object_property_set_bool(OBJECT(&s->rng), true, "realized", &err);
250     if (err) {
251         error_propagate(errp, err);
252         return;
253     }
254 
255     memory_region_add_subregion(&s->peri_mr, RNG_OFFSET,
256                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rng), 0));
257 
258     /* Extended Mass Media Controller */
259     object_property_set_int(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg",
260                             &err);
261     if (err) {
262         error_propagate(errp, err);
263         return;
264     }
265 
266     object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk",
267                              &err);
268     if (err) {
269         error_propagate(errp, err);
270         return;
271     }
272 
273     object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err);
274     if (err) {
275         error_propagate(errp, err);
276         return;
277     }
278 
279     memory_region_add_subregion(&s->peri_mr, EMMC_OFFSET,
280                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhci), 0));
281     sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
282         qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
283                                INTERRUPT_ARASANSDIO));
284 
285     /* SDHOST */
286     object_property_set_bool(OBJECT(&s->sdhost), true, "realized", &err);
287     if (err) {
288         error_propagate(errp, err);
289         return;
290     }
291 
292     memory_region_add_subregion(&s->peri_mr, MMCI0_OFFSET,
293                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhost), 0));
294     sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhost), 0,
295         qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
296                                INTERRUPT_SDIO));
297 
298     /* DMA Channels */
299     object_property_set_bool(OBJECT(&s->dma), true, "realized", &err);
300     if (err) {
301         error_propagate(errp, err);
302         return;
303     }
304 
305     memory_region_add_subregion(&s->peri_mr, DMA_OFFSET,
306                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 0));
307     memory_region_add_subregion(&s->peri_mr, DMA15_OFFSET,
308                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 1));
309 
310     for (n = 0; n <= 12; n++) {
311         sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), n,
312                            qdev_get_gpio_in_named(DEVICE(&s->ic),
313                                                   BCM2835_IC_GPU_IRQ,
314                                                   INTERRUPT_DMA0 + n));
315     }
316 
317     /* GPIO */
318     object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err);
319     if (err) {
320         error_propagate(errp, err);
321         return;
322     }
323 
324     memory_region_add_subregion(&s->peri_mr, GPIO_OFFSET,
325                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0));
326 
327     object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus",
328                               &err);
329     if (err) {
330         error_propagate(errp, err);
331         return;
332     }
333 }
334 
335 static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
336 {
337     DeviceClass *dc = DEVICE_CLASS(oc);
338 
339     dc->realize = bcm2835_peripherals_realize;
340 }
341 
342 static const TypeInfo bcm2835_peripherals_type_info = {
343     .name = TYPE_BCM2835_PERIPHERALS,
344     .parent = TYPE_SYS_BUS_DEVICE,
345     .instance_size = sizeof(BCM2835PeripheralState),
346     .instance_init = bcm2835_peripherals_init,
347     .class_init = bcm2835_peripherals_class_init,
348 };
349 
350 static void bcm2835_peripherals_register_types(void)
351 {
352     type_register_static(&bcm2835_peripherals_type_info);
353 }
354 
355 type_init(bcm2835_peripherals_register_types)
356