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