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