xref: /qemu/hw/arm/bcm2836.c (revision d780d056f8acdee73a1c34d95733851d58aecd60)
1bad56236SAndrew Baumann /*
2bad56236SAndrew Baumann  * Raspberry Pi emulation (c) 2012 Gregory Estrade
3bad56236SAndrew Baumann  * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
4bad56236SAndrew Baumann  *
5bad56236SAndrew Baumann  * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
6bad56236SAndrew Baumann  * Written by Andrew Baumann
7bad56236SAndrew Baumann  *
86111a0c0SPhilippe Mathieu-Daudé  * This work is licensed under the terms of the GNU GPL, version 2 or later.
96111a0c0SPhilippe Mathieu-Daudé  * See the COPYING file in the top-level directory.
10bad56236SAndrew Baumann  */
11bad56236SAndrew Baumann 
12c964b660SPeter Maydell #include "qemu/osdep.h"
13da34e65cSMarkus Armbruster #include "qapi/error.h"
140b8fa32fSMarkus Armbruster #include "qemu/module.h"
15bad56236SAndrew Baumann #include "hw/arm/bcm2836.h"
16bad56236SAndrew Baumann #include "hw/arm/raspi_platform.h"
17bad56236SAndrew Baumann #include "hw/sysbus.h"
18*d780d056SPhilippe Mathieu-Daudé #include "target/arm/cpu-qom.h"
19bad56236SAndrew Baumann 
20a91179e7SPhilippe Mathieu-Daudé struct BCM283XClass {
2158b35028SPhilippe Mathieu-Daudé     /*< private >*/
2258b35028SPhilippe Mathieu-Daudé     DeviceClass parent_class;
2358b35028SPhilippe Mathieu-Daudé     /*< public >*/
240fd74f03SPeter Maydell     const char *name;
25210f4784SPeter Maydell     const char *cpu_type;
2625ea2884SPhilippe Mathieu-Daudé     unsigned core_count;
27d0567e94SPhilippe Mathieu-Daudé     hwaddr peri_base; /* Peripheral base address seen by the CPU */
28d0567e94SPhilippe Mathieu-Daudé     hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
291bcb4d16SPeter Maydell     int clusterid;
30a91179e7SPhilippe Mathieu-Daudé };
3158b35028SPhilippe Mathieu-Daudé 
3296c741d7SPhilippe Mathieu-Daudé static Property bcm2836_enabled_cores_property =
3396c741d7SPhilippe Mathieu-Daudé     DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 0);
3496c741d7SPhilippe Mathieu-Daudé 
35bad56236SAndrew Baumann static void bcm2836_init(Object *obj)
36bad56236SAndrew Baumann {
37926dcdf0SPeter Maydell     BCM283XState *s = BCM283X(obj);
38210f4784SPeter Maydell     BCM283XClass *bc = BCM283X_GET_CLASS(obj);
39210f4784SPeter Maydell     int n;
40210f4784SPeter Maydell 
4125ea2884SPhilippe Mathieu-Daudé     for (n = 0; n < bc->core_count; n++) {
425e5e9ed6SPhilippe Mathieu-Daudé         object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
4334d1a4f5SPhilippe Mathieu-Daudé                                 bc->cpu_type);
44210f4784SPeter Maydell     }
4596c741d7SPhilippe Mathieu-Daudé     if (bc->core_count > 1) {
4696c741d7SPhilippe Mathieu-Daudé         qdev_property_add_static(DEVICE(obj), &bcm2836_enabled_cores_property);
4796c741d7SPhilippe Mathieu-Daudé         qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
4896c741d7SPhilippe Mathieu-Daudé     }
49bad56236SAndrew Baumann 
50f5600924SPhilippe Mathieu-Daudé     if (bc->ctrl_base) {
51f5600924SPhilippe Mathieu-Daudé         object_initialize_child(obj, "control", &s->control,
52f5600924SPhilippe Mathieu-Daudé                                 TYPE_BCM2836_CONTROL);
53f5600924SPhilippe Mathieu-Daudé     }
54bad56236SAndrew Baumann 
55db873cc5SMarkus Armbruster     object_initialize_child(obj, "peripherals", &s->peripherals,
56db873cc5SMarkus Armbruster                             TYPE_BCM2835_PERIPHERALS);
57f0afa731SStephen Warren     object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
58d2623129SMarkus Armbruster                               "board-rev");
59f802ff1eSDaniel Bertalan     object_property_add_alias(obj, "command-line", OBJECT(&s->peripherals),
60f802ff1eSDaniel Bertalan                               "command-line");
615e9c2a8dSGrégory ESTRADE     object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
62d2623129SMarkus Armbruster                               "vcram-size");
63bad56236SAndrew Baumann }
64bad56236SAndrew Baumann 
65f5600924SPhilippe Mathieu-Daudé static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
66bad56236SAndrew Baumann {
67926dcdf0SPeter Maydell     BCM283XState *s = BCM283X(dev);
681bcb4d16SPeter Maydell     BCM283XClass *bc = BCM283X_GET_CLASS(dev);
69bad56236SAndrew Baumann     Object *obj;
70bad56236SAndrew Baumann 
71bad56236SAndrew Baumann     /* common peripherals from bcm2835 */
72bad56236SAndrew Baumann 
734d21fcd5SMarkus Armbruster     obj = object_property_get_link(OBJECT(dev), "ram", &error_abort);
74bad56236SAndrew Baumann 
75d2623129SMarkus Armbruster     object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj);
76bad56236SAndrew Baumann 
77668f62ecSMarkus Armbruster     if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), errp)) {
78f5600924SPhilippe Mathieu-Daudé         return false;
79bad56236SAndrew Baumann     }
80bad56236SAndrew Baumann 
81a55b53a2SAndrew Baumann     object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
82d2623129SMarkus Armbruster                               "sd-bus");
83a55b53a2SAndrew Baumann 
84bad56236SAndrew Baumann     sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
8534d1a4f5SPhilippe Mathieu-Daudé                             bc->peri_base, 1);
86f5600924SPhilippe Mathieu-Daudé     return true;
87f5600924SPhilippe Mathieu-Daudé }
88f5600924SPhilippe Mathieu-Daudé 
89df6cf08dSPhilippe Mathieu-Daudé static void bcm2835_realize(DeviceState *dev, Error **errp)
90df6cf08dSPhilippe Mathieu-Daudé {
91df6cf08dSPhilippe Mathieu-Daudé     BCM283XState *s = BCM283X(dev);
92df6cf08dSPhilippe Mathieu-Daudé 
93df6cf08dSPhilippe Mathieu-Daudé     if (!bcm283x_common_realize(dev, errp)) {
94df6cf08dSPhilippe Mathieu-Daudé         return;
95df6cf08dSPhilippe Mathieu-Daudé     }
96df6cf08dSPhilippe Mathieu-Daudé 
97df6cf08dSPhilippe Mathieu-Daudé     if (!qdev_realize(DEVICE(&s->cpu[0].core), NULL, errp)) {
98df6cf08dSPhilippe Mathieu-Daudé         return;
99df6cf08dSPhilippe Mathieu-Daudé     }
100df6cf08dSPhilippe Mathieu-Daudé 
101df6cf08dSPhilippe Mathieu-Daudé     /* Connect irq/fiq outputs from the interrupt controller. */
102df6cf08dSPhilippe Mathieu-Daudé     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
103df6cf08dSPhilippe Mathieu-Daudé             qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_IRQ));
104df6cf08dSPhilippe Mathieu-Daudé     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
105df6cf08dSPhilippe Mathieu-Daudé             qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_FIQ));
106df6cf08dSPhilippe Mathieu-Daudé }
107df6cf08dSPhilippe Mathieu-Daudé 
108f5600924SPhilippe Mathieu-Daudé static void bcm2836_realize(DeviceState *dev, Error **errp)
109f5600924SPhilippe Mathieu-Daudé {
110f5600924SPhilippe Mathieu-Daudé     BCM283XState *s = BCM283X(dev);
111f5600924SPhilippe Mathieu-Daudé     BCM283XClass *bc = BCM283X_GET_CLASS(dev);
112f5600924SPhilippe Mathieu-Daudé     int n;
113f5600924SPhilippe Mathieu-Daudé 
114f5600924SPhilippe Mathieu-Daudé     if (!bcm283x_common_realize(dev, errp)) {
115f5600924SPhilippe Mathieu-Daudé         return;
116f5600924SPhilippe Mathieu-Daudé     }
117bad56236SAndrew Baumann 
118bad56236SAndrew Baumann     /* bcm2836 interrupt controller (and mailboxes, etc.) */
119668f62ecSMarkus Armbruster     if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
120bad56236SAndrew Baumann         return;
121bad56236SAndrew Baumann     }
122bad56236SAndrew Baumann 
12334d1a4f5SPhilippe Mathieu-Daudé     sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, bc->ctrl_base);
124bad56236SAndrew Baumann 
125bad56236SAndrew Baumann     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
126bad56236SAndrew Baumann         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
127bad56236SAndrew Baumann     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
128bad56236SAndrew Baumann         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
129bad56236SAndrew Baumann 
130926dcdf0SPeter Maydell     for (n = 0; n < BCM283X_NCPUS; n++) {
13179f51695SPhilippe Mathieu-Daudé         object_property_set_int(OBJECT(&s->cpu[n].core), "mp-affinity",
13279f51695SPhilippe Mathieu-Daudé                                 (bc->clusterid << 8) | n, &error_abort);
133bad56236SAndrew Baumann 
134bad56236SAndrew Baumann         /* set periphbase/CBAR value for CPU-local registers */
135ca1d323cSPhilippe Mathieu-Daudé         object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar",
136ca1d323cSPhilippe Mathieu-Daudé                                 bc->peri_base, &error_abort);
137bad56236SAndrew Baumann 
138bad56236SAndrew Baumann         /* start powered off if not enabled */
139287fa323SPhilippe Mathieu-Daudé         object_property_set_bool(OBJECT(&s->cpu[n].core), "start-powered-off",
140287fa323SPhilippe Mathieu-Daudé                                  n >= s->enabled_cpus, &error_abort);
141bad56236SAndrew Baumann 
142668f62ecSMarkus Armbruster         if (!qdev_realize(DEVICE(&s->cpu[n].core), NULL, errp)) {
143bad56236SAndrew Baumann             return;
144bad56236SAndrew Baumann         }
145bad56236SAndrew Baumann 
146bad56236SAndrew Baumann         /* Connect irq/fiq outputs from the interrupt controller. */
147bad56236SAndrew Baumann         qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
1485e5e9ed6SPhilippe Mathieu-Daudé                 qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_IRQ));
149bad56236SAndrew Baumann         qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n,
1505e5e9ed6SPhilippe Mathieu-Daudé                 qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_FIQ));
151bad56236SAndrew Baumann 
152bad56236SAndrew Baumann         /* Connect timers from the CPU to the interrupt controller */
1535e5e9ed6SPhilippe Mathieu-Daudé         qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_PHYS,
1540dc19823SPeter Maydell                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n));
1555e5e9ed6SPhilippe Mathieu-Daudé         qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_VIRT,
156bad56236SAndrew Baumann                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n));
1575e5e9ed6SPhilippe Mathieu-Daudé         qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_HYP,
1580dc19823SPeter Maydell                 qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n));
1595e5e9ed6SPhilippe Mathieu-Daudé         qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_SEC,
1600dc19823SPeter Maydell                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n));
161bad56236SAndrew Baumann     }
162bad56236SAndrew Baumann }
163bad56236SAndrew Baumann 
1640fd74f03SPeter Maydell static void bcm283x_class_init(ObjectClass *oc, void *data)
165bad56236SAndrew Baumann {
166bad56236SAndrew Baumann     DeviceClass *dc = DEVICE_CLASS(oc);
167bad56236SAndrew Baumann 
168cccf96c3SThomas Huth     /* Reason: Must be wired up in code (see raspi_init() function) */
169cccf96c3SThomas Huth     dc->user_creatable = false;
170bad56236SAndrew Baumann }
171bad56236SAndrew Baumann 
172df6cf08dSPhilippe Mathieu-Daudé static void bcm2835_class_init(ObjectClass *oc, void *data)
173df6cf08dSPhilippe Mathieu-Daudé {
174df6cf08dSPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(oc);
175df6cf08dSPhilippe Mathieu-Daudé     BCM283XClass *bc = BCM283X_CLASS(oc);
176df6cf08dSPhilippe Mathieu-Daudé 
177df6cf08dSPhilippe Mathieu-Daudé     bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
178df6cf08dSPhilippe Mathieu-Daudé     bc->core_count = 1;
179df6cf08dSPhilippe Mathieu-Daudé     bc->peri_base = 0x20000000;
180df6cf08dSPhilippe Mathieu-Daudé     dc->realize = bcm2835_realize;
181df6cf08dSPhilippe Mathieu-Daudé };
182df6cf08dSPhilippe Mathieu-Daudé 
18334d1a4f5SPhilippe Mathieu-Daudé static void bcm2836_class_init(ObjectClass *oc, void *data)
18434d1a4f5SPhilippe Mathieu-Daudé {
18534d1a4f5SPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(oc);
18634d1a4f5SPhilippe Mathieu-Daudé     BCM283XClass *bc = BCM283X_CLASS(oc);
18734d1a4f5SPhilippe Mathieu-Daudé 
18834d1a4f5SPhilippe Mathieu-Daudé     bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
18925ea2884SPhilippe Mathieu-Daudé     bc->core_count = BCM283X_NCPUS;
19034d1a4f5SPhilippe Mathieu-Daudé     bc->peri_base = 0x3f000000;
19134d1a4f5SPhilippe Mathieu-Daudé     bc->ctrl_base = 0x40000000;
19234d1a4f5SPhilippe Mathieu-Daudé     bc->clusterid = 0xf;
19334d1a4f5SPhilippe Mathieu-Daudé     dc->realize = bcm2836_realize;
19434d1a4f5SPhilippe Mathieu-Daudé };
19534d1a4f5SPhilippe Mathieu-Daudé 
19634d1a4f5SPhilippe Mathieu-Daudé #ifdef TARGET_AARCH64
19734d1a4f5SPhilippe Mathieu-Daudé static void bcm2837_class_init(ObjectClass *oc, void *data)
19834d1a4f5SPhilippe Mathieu-Daudé {
19934d1a4f5SPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(oc);
20034d1a4f5SPhilippe Mathieu-Daudé     BCM283XClass *bc = BCM283X_CLASS(oc);
20134d1a4f5SPhilippe Mathieu-Daudé 
20234d1a4f5SPhilippe Mathieu-Daudé     bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
20325ea2884SPhilippe Mathieu-Daudé     bc->core_count = BCM283X_NCPUS;
20434d1a4f5SPhilippe Mathieu-Daudé     bc->peri_base = 0x3f000000;
20534d1a4f5SPhilippe Mathieu-Daudé     bc->ctrl_base = 0x40000000;
20634d1a4f5SPhilippe Mathieu-Daudé     bc->clusterid = 0x0;
20734d1a4f5SPhilippe Mathieu-Daudé     dc->realize = bcm2836_realize;
20834d1a4f5SPhilippe Mathieu-Daudé };
20934d1a4f5SPhilippe Mathieu-Daudé #endif
21034d1a4f5SPhilippe Mathieu-Daudé 
21134d1a4f5SPhilippe Mathieu-Daudé static const TypeInfo bcm283x_types[] = {
21234d1a4f5SPhilippe Mathieu-Daudé     {
213df6cf08dSPhilippe Mathieu-Daudé         .name           = TYPE_BCM2835,
214df6cf08dSPhilippe Mathieu-Daudé         .parent         = TYPE_BCM283X,
215df6cf08dSPhilippe Mathieu-Daudé         .class_init     = bcm2835_class_init,
216df6cf08dSPhilippe Mathieu-Daudé     }, {
21734d1a4f5SPhilippe Mathieu-Daudé         .name           = TYPE_BCM2836,
21834d1a4f5SPhilippe Mathieu-Daudé         .parent         = TYPE_BCM283X,
21934d1a4f5SPhilippe Mathieu-Daudé         .class_init     = bcm2836_class_init,
22034d1a4f5SPhilippe Mathieu-Daudé #ifdef TARGET_AARCH64
22134d1a4f5SPhilippe Mathieu-Daudé     }, {
22234d1a4f5SPhilippe Mathieu-Daudé         .name           = TYPE_BCM2837,
22334d1a4f5SPhilippe Mathieu-Daudé         .parent         = TYPE_BCM283X,
22434d1a4f5SPhilippe Mathieu-Daudé         .class_init     = bcm2837_class_init,
22534d1a4f5SPhilippe Mathieu-Daudé #endif
22634d1a4f5SPhilippe Mathieu-Daudé     }, {
227926dcdf0SPeter Maydell         .name           = TYPE_BCM283X,
2283d260cf3SPeter Maydell         .parent         = TYPE_DEVICE,
229926dcdf0SPeter Maydell         .instance_size  = sizeof(BCM283XState),
230bad56236SAndrew Baumann         .instance_init  = bcm2836_init,
2310fd74f03SPeter Maydell         .class_size     = sizeof(BCM283XClass),
2320fd74f03SPeter Maydell         .class_init     = bcm283x_class_init,
23334d1a4f5SPhilippe Mathieu-Daudé         .abstract       = true,
23434d1a4f5SPhilippe Mathieu-Daudé     }
2350fd74f03SPeter Maydell };
236bad56236SAndrew Baumann 
23734d1a4f5SPhilippe Mathieu-Daudé DEFINE_TYPES(bcm283x_types)
238