xref: /openbmc/qemu/hw/arm/bcm2835_peripherals.c (revision 438c78da)
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 0x52134b4
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     uint64_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_hd(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_hd(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 = object_property_get_uint(OBJECT(s), "vcram-size", &err);
211     if (err) {
212         error_propagate(errp, err);
213         return;
214     }
215 
216     object_property_set_uint(OBJECT(&s->fb), ram_size - vcram_size,
217                              "vcram-base", &err);
218     if (err) {
219         error_propagate(errp, err);
220         return;
221     }
222 
223     object_property_set_bool(OBJECT(&s->fb), true, "realized", &err);
224     if (err) {
225         error_propagate(errp, err);
226         return;
227     }
228 
229     memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_FB << MBOX_AS_CHAN_SHIFT,
230                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->fb), 0));
231     sysbus_connect_irq(SYS_BUS_DEVICE(&s->fb), 0,
232                        qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB));
233 
234     /* Property channel */
235     object_property_set_bool(OBJECT(&s->property), true, "realized", &err);
236     if (err) {
237         error_propagate(errp, err);
238         return;
239     }
240 
241     memory_region_add_subregion(&s->mbox_mr,
242                 MBOX_CHAN_PROPERTY << MBOX_AS_CHAN_SHIFT,
243                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->property), 0));
244     sysbus_connect_irq(SYS_BUS_DEVICE(&s->property), 0,
245                       qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY));
246 
247     /* Random Number Generator */
248     object_property_set_bool(OBJECT(&s->rng), true, "realized", &err);
249     if (err) {
250         error_propagate(errp, err);
251         return;
252     }
253 
254     memory_region_add_subregion(&s->peri_mr, RNG_OFFSET,
255                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rng), 0));
256 
257     /* Extended Mass Media Controller
258      *
259      * Compatible with:
260      * - SD Host Controller Specification Version 3.0 Draft 1.0
261      * - SDIO Specification Version 3.0
262      * - MMC Specification Version 4.4
263      *
264      * For the exact details please refer to the Arasan documentation:
265      *   SD3.0_Host_AHB_eMMC4.4_Usersguide_ver5.9_jan11_10.pdf
266      */
267     object_property_set_uint(OBJECT(&s->sdhci), 3, "sd-spec-version", &err);
268     object_property_set_uint(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg",
269                              &err);
270     object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk",
271                              &err);
272     if (err) {
273         error_propagate(errp, err);
274         return;
275     }
276 
277     object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err);
278     if (err) {
279         error_propagate(errp, err);
280         return;
281     }
282 
283     memory_region_add_subregion(&s->peri_mr, EMMC_OFFSET,
284                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhci), 0));
285     sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
286         qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
287                                INTERRUPT_ARASANSDIO));
288 
289     /* SDHOST */
290     object_property_set_bool(OBJECT(&s->sdhost), true, "realized", &err);
291     if (err) {
292         error_propagate(errp, err);
293         return;
294     }
295 
296     memory_region_add_subregion(&s->peri_mr, MMCI0_OFFSET,
297                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhost), 0));
298     sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhost), 0,
299         qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
300                                INTERRUPT_SDIO));
301 
302     /* DMA Channels */
303     object_property_set_bool(OBJECT(&s->dma), true, "realized", &err);
304     if (err) {
305         error_propagate(errp, err);
306         return;
307     }
308 
309     memory_region_add_subregion(&s->peri_mr, DMA_OFFSET,
310                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 0));
311     memory_region_add_subregion(&s->peri_mr, DMA15_OFFSET,
312                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 1));
313 
314     for (n = 0; n <= 12; n++) {
315         sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), n,
316                            qdev_get_gpio_in_named(DEVICE(&s->ic),
317                                                   BCM2835_IC_GPU_IRQ,
318                                                   INTERRUPT_DMA0 + n));
319     }
320 
321     /* GPIO */
322     object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err);
323     if (err) {
324         error_propagate(errp, err);
325         return;
326     }
327 
328     memory_region_add_subregion(&s->peri_mr, GPIO_OFFSET,
329                 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0));
330 
331     object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus",
332                               &err);
333     if (err) {
334         error_propagate(errp, err);
335         return;
336     }
337 }
338 
339 static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
340 {
341     DeviceClass *dc = DEVICE_CLASS(oc);
342 
343     dc->realize = bcm2835_peripherals_realize;
344 }
345 
346 static const TypeInfo bcm2835_peripherals_type_info = {
347     .name = TYPE_BCM2835_PERIPHERALS,
348     .parent = TYPE_SYS_BUS_DEVICE,
349     .instance_size = sizeof(BCM2835PeripheralState),
350     .instance_init = bcm2835_peripherals_init,
351     .class_init = bcm2835_peripherals_class_init,
352 };
353 
354 static void bcm2835_peripherals_register_types(void)
355 {
356     type_register_static(&bcm2835_peripherals_type_info);
357 }
358 
359 type_init(bcm2835_peripherals_register_types)
360