xref: /qemu/hw/arm/bcm2836.c (revision 7d04d630ba7ada8a9530d8c45f4b0840f557bf31)
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"
18d780d056SPhilippe Mathieu-Daudé #include "target/arm/cpu-qom.h"
19f4f318b4SPhilippe Mathieu-Daudé #include "target/arm/gtimer.h"
20bad56236SAndrew Baumann 
21a91179e7SPhilippe Mathieu-Daudé struct BCM283XClass {
2258b35028SPhilippe Mathieu-Daudé     /*< private >*/
2358b35028SPhilippe Mathieu-Daudé     DeviceClass parent_class;
2458b35028SPhilippe Mathieu-Daudé     /*< public >*/
250fd74f03SPeter Maydell     const char *name;
26210f4784SPeter Maydell     const char *cpu_type;
2725ea2884SPhilippe Mathieu-Daudé     unsigned core_count;
28d0567e94SPhilippe Mathieu-Daudé     hwaddr peri_base; /* Peripheral base address seen by the CPU */
29d0567e94SPhilippe Mathieu-Daudé     hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
301bcb4d16SPeter Maydell     int clusterid;
31a91179e7SPhilippe Mathieu-Daudé };
3258b35028SPhilippe Mathieu-Daudé 
3396c741d7SPhilippe Mathieu-Daudé static Property bcm2836_enabled_cores_property =
34f932093aSSergey Kambalin     DEFINE_PROP_UINT32("enabled-cpus", BCM283XBaseState, enabled_cpus, 0);
3596c741d7SPhilippe Mathieu-Daudé 
36f932093aSSergey Kambalin static void bcm283x_base_init(Object *obj)
37bad56236SAndrew Baumann {
38f932093aSSergey Kambalin     BCM283XBaseState *s = BCM283X_BASE(obj);
39f932093aSSergey Kambalin     BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(obj);
40210f4784SPeter Maydell     int n;
41210f4784SPeter Maydell 
4225ea2884SPhilippe Mathieu-Daudé     for (n = 0; n < bc->core_count; n++) {
435e5e9ed6SPhilippe Mathieu-Daudé         object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
4434d1a4f5SPhilippe Mathieu-Daudé                                 bc->cpu_type);
45210f4784SPeter Maydell     }
4696c741d7SPhilippe Mathieu-Daudé     if (bc->core_count > 1) {
4796c741d7SPhilippe Mathieu-Daudé         qdev_property_add_static(DEVICE(obj), &bcm2836_enabled_cores_property);
4896c741d7SPhilippe Mathieu-Daudé         qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
4996c741d7SPhilippe Mathieu-Daudé     }
50bad56236SAndrew Baumann 
51f5600924SPhilippe Mathieu-Daudé     if (bc->ctrl_base) {
52f5600924SPhilippe Mathieu-Daudé         object_initialize_child(obj, "control", &s->control,
53f5600924SPhilippe Mathieu-Daudé                                 TYPE_BCM2836_CONTROL);
54f5600924SPhilippe Mathieu-Daudé     }
55f932093aSSergey Kambalin }
56f932093aSSergey Kambalin 
57f932093aSSergey Kambalin static void bcm283x_init(Object *obj)
58f932093aSSergey Kambalin {
59f932093aSSergey Kambalin     BCM283XState *s = BCM283X(obj);
60bad56236SAndrew Baumann 
61db873cc5SMarkus Armbruster     object_initialize_child(obj, "peripherals", &s->peripherals,
62db873cc5SMarkus Armbruster                             TYPE_BCM2835_PERIPHERALS);
63f0afa731SStephen Warren     object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
64d2623129SMarkus Armbruster                               "board-rev");
65f802ff1eSDaniel Bertalan     object_property_add_alias(obj, "command-line", OBJECT(&s->peripherals),
66f802ff1eSDaniel Bertalan                               "command-line");
675e9c2a8dSGrégory ESTRADE     object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
68d2623129SMarkus Armbruster                               "vcram-size");
69bad56236SAndrew Baumann }
70bad56236SAndrew Baumann 
71*7d04d630SSergey Kambalin bool bcm283x_common_realize(DeviceState *dev, BCMSocPeripheralBaseState *ps,
72*7d04d630SSergey Kambalin                             Error **errp)
73bad56236SAndrew Baumann {
74*7d04d630SSergey Kambalin     BCM283XBaseState *s = BCM283X_BASE(dev);
75f932093aSSergey Kambalin     BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(dev);
76bad56236SAndrew Baumann     Object *obj;
77bad56236SAndrew Baumann 
78bad56236SAndrew Baumann     /* common peripherals from bcm2835 */
79bad56236SAndrew Baumann 
804d21fcd5SMarkus Armbruster     obj = object_property_get_link(OBJECT(dev), "ram", &error_abort);
81bad56236SAndrew Baumann 
82*7d04d630SSergey Kambalin     object_property_add_const_link(OBJECT(ps), "ram", obj);
83bad56236SAndrew Baumann 
84*7d04d630SSergey Kambalin     if (!sysbus_realize(SYS_BUS_DEVICE(ps), errp)) {
85f5600924SPhilippe Mathieu-Daudé         return false;
86bad56236SAndrew Baumann     }
87bad56236SAndrew Baumann 
88*7d04d630SSergey Kambalin     object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(ps), "sd-bus");
89a55b53a2SAndrew Baumann 
90*7d04d630SSergey Kambalin     sysbus_mmio_map_overlap(SYS_BUS_DEVICE(ps), 0, bc->peri_base, 1);
91f5600924SPhilippe Mathieu-Daudé     return true;
92f5600924SPhilippe Mathieu-Daudé }
93f5600924SPhilippe Mathieu-Daudé 
94df6cf08dSPhilippe Mathieu-Daudé static void bcm2835_realize(DeviceState *dev, Error **errp)
95df6cf08dSPhilippe Mathieu-Daudé {
96df6cf08dSPhilippe Mathieu-Daudé     BCM283XState *s = BCM283X(dev);
97f932093aSSergey Kambalin     BCM283XBaseState *s_base = BCM283X_BASE(dev);
98*7d04d630SSergey Kambalin     BCMSocPeripheralBaseState *ps_base
99*7d04d630SSergey Kambalin         = BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
100df6cf08dSPhilippe Mathieu-Daudé 
101*7d04d630SSergey Kambalin     if (!bcm283x_common_realize(dev, ps_base, errp)) {
102df6cf08dSPhilippe Mathieu-Daudé         return;
103df6cf08dSPhilippe Mathieu-Daudé     }
104df6cf08dSPhilippe Mathieu-Daudé 
105f932093aSSergey Kambalin     if (!qdev_realize(DEVICE(&s_base->cpu[0].core), NULL, errp)) {
106df6cf08dSPhilippe Mathieu-Daudé         return;
107df6cf08dSPhilippe Mathieu-Daudé     }
108df6cf08dSPhilippe Mathieu-Daudé 
109df6cf08dSPhilippe Mathieu-Daudé     /* Connect irq/fiq outputs from the interrupt controller. */
110df6cf08dSPhilippe Mathieu-Daudé     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
111f932093aSSergey Kambalin             qdev_get_gpio_in(DEVICE(&s_base->cpu[0].core), ARM_CPU_IRQ));
112df6cf08dSPhilippe Mathieu-Daudé     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
113f932093aSSergey Kambalin             qdev_get_gpio_in(DEVICE(&s_base->cpu[0].core), ARM_CPU_FIQ));
114df6cf08dSPhilippe Mathieu-Daudé }
115df6cf08dSPhilippe Mathieu-Daudé 
116f5600924SPhilippe Mathieu-Daudé static void bcm2836_realize(DeviceState *dev, Error **errp)
117f5600924SPhilippe Mathieu-Daudé {
118f5600924SPhilippe Mathieu-Daudé     int n;
119f932093aSSergey Kambalin     BCM283XState *s = BCM283X(dev);
120f932093aSSergey Kambalin     BCM283XBaseState *s_base = BCM283X_BASE(dev);
121f932093aSSergey Kambalin     BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(dev);
122*7d04d630SSergey Kambalin     BCMSocPeripheralBaseState *ps_base
123*7d04d630SSergey Kambalin         = BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
124f5600924SPhilippe Mathieu-Daudé 
125*7d04d630SSergey Kambalin     if (!bcm283x_common_realize(dev, ps_base, errp)) {
126f5600924SPhilippe Mathieu-Daudé         return;
127f5600924SPhilippe Mathieu-Daudé     }
128bad56236SAndrew Baumann 
129bad56236SAndrew Baumann     /* bcm2836 interrupt controller (and mailboxes, etc.) */
130f932093aSSergey Kambalin     if (!sysbus_realize(SYS_BUS_DEVICE(&s_base->control), errp)) {
131bad56236SAndrew Baumann         return;
132bad56236SAndrew Baumann     }
133bad56236SAndrew Baumann 
134f932093aSSergey Kambalin     sysbus_mmio_map(SYS_BUS_DEVICE(&s_base->control), 0, bc->ctrl_base);
135bad56236SAndrew Baumann 
136bad56236SAndrew Baumann     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
137f932093aSSergey Kambalin         qdev_get_gpio_in_named(DEVICE(&s_base->control), "gpu-irq", 0));
138bad56236SAndrew Baumann     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
139f932093aSSergey Kambalin         qdev_get_gpio_in_named(DEVICE(&s_base->control), "gpu-fiq", 0));
140bad56236SAndrew Baumann 
141926dcdf0SPeter Maydell     for (n = 0; n < BCM283X_NCPUS; n++) {
142f932093aSSergey Kambalin         object_property_set_int(OBJECT(&s_base->cpu[n].core), "mp-affinity",
14379f51695SPhilippe Mathieu-Daudé                                 (bc->clusterid << 8) | n, &error_abort);
144bad56236SAndrew Baumann 
145bad56236SAndrew Baumann         /* set periphbase/CBAR value for CPU-local registers */
146f932093aSSergey Kambalin         object_property_set_int(OBJECT(&s_base->cpu[n].core), "reset-cbar",
147ca1d323cSPhilippe Mathieu-Daudé                                 bc->peri_base, &error_abort);
148bad56236SAndrew Baumann 
149bad56236SAndrew Baumann         /* start powered off if not enabled */
150f932093aSSergey Kambalin         object_property_set_bool(OBJECT(&s_base->cpu[n].core),
151f932093aSSergey Kambalin                                  "start-powered-off",
152f932093aSSergey Kambalin                                  n >= s_base->enabled_cpus, &error_abort);
153bad56236SAndrew Baumann 
154f932093aSSergey Kambalin         if (!qdev_realize(DEVICE(&s_base->cpu[n].core), NULL, errp)) {
155bad56236SAndrew Baumann             return;
156bad56236SAndrew Baumann         }
157bad56236SAndrew Baumann 
158bad56236SAndrew Baumann         /* Connect irq/fiq outputs from the interrupt controller. */
159f932093aSSergey Kambalin         qdev_connect_gpio_out_named(DEVICE(&s_base->control), "irq", n,
160f932093aSSergey Kambalin             qdev_get_gpio_in(DEVICE(&s_base->cpu[n].core), ARM_CPU_IRQ));
161f932093aSSergey Kambalin         qdev_connect_gpio_out_named(DEVICE(&s_base->control), "fiq", n,
162f932093aSSergey Kambalin             qdev_get_gpio_in(DEVICE(&s_base->cpu[n].core), ARM_CPU_FIQ));
163bad56236SAndrew Baumann 
164bad56236SAndrew Baumann         /* Connect timers from the CPU to the interrupt controller */
165f932093aSSergey Kambalin         qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_PHYS,
166f932093aSSergey Kambalin             qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntpnsirq", n));
167f932093aSSergey Kambalin         qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_VIRT,
168f932093aSSergey Kambalin             qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntvirq", n));
169f932093aSSergey Kambalin         qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_HYP,
170f932093aSSergey Kambalin             qdev_get_gpio_in_named(DEVICE(&s_base->control), "cnthpirq", n));
171f932093aSSergey Kambalin         qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_SEC,
172f932093aSSergey Kambalin             qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntpsirq", n));
173bad56236SAndrew Baumann     }
174bad56236SAndrew Baumann }
175bad56236SAndrew Baumann 
176f932093aSSergey Kambalin static void bcm283x_base_class_init(ObjectClass *oc, void *data)
177bad56236SAndrew Baumann {
178bad56236SAndrew Baumann     DeviceClass *dc = DEVICE_CLASS(oc);
179bad56236SAndrew Baumann 
180cccf96c3SThomas Huth     /* Reason: Must be wired up in code (see raspi_init() function) */
181cccf96c3SThomas Huth     dc->user_creatable = false;
182bad56236SAndrew Baumann }
183bad56236SAndrew Baumann 
184df6cf08dSPhilippe Mathieu-Daudé static void bcm2835_class_init(ObjectClass *oc, void *data)
185df6cf08dSPhilippe Mathieu-Daudé {
186df6cf08dSPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(oc);
187f932093aSSergey Kambalin     BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
188df6cf08dSPhilippe Mathieu-Daudé 
189df6cf08dSPhilippe Mathieu-Daudé     bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
190df6cf08dSPhilippe Mathieu-Daudé     bc->core_count = 1;
191df6cf08dSPhilippe Mathieu-Daudé     bc->peri_base = 0x20000000;
192df6cf08dSPhilippe Mathieu-Daudé     dc->realize = bcm2835_realize;
193df6cf08dSPhilippe Mathieu-Daudé };
194df6cf08dSPhilippe Mathieu-Daudé 
19534d1a4f5SPhilippe Mathieu-Daudé static void bcm2836_class_init(ObjectClass *oc, void *data)
19634d1a4f5SPhilippe Mathieu-Daudé {
19734d1a4f5SPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(oc);
198f932093aSSergey Kambalin     BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
19934d1a4f5SPhilippe Mathieu-Daudé 
20034d1a4f5SPhilippe Mathieu-Daudé     bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
20125ea2884SPhilippe Mathieu-Daudé     bc->core_count = BCM283X_NCPUS;
20234d1a4f5SPhilippe Mathieu-Daudé     bc->peri_base = 0x3f000000;
20334d1a4f5SPhilippe Mathieu-Daudé     bc->ctrl_base = 0x40000000;
20434d1a4f5SPhilippe Mathieu-Daudé     bc->clusterid = 0xf;
20534d1a4f5SPhilippe Mathieu-Daudé     dc->realize = bcm2836_realize;
20634d1a4f5SPhilippe Mathieu-Daudé };
20734d1a4f5SPhilippe Mathieu-Daudé 
20834d1a4f5SPhilippe Mathieu-Daudé #ifdef TARGET_AARCH64
20934d1a4f5SPhilippe Mathieu-Daudé static void bcm2837_class_init(ObjectClass *oc, void *data)
21034d1a4f5SPhilippe Mathieu-Daudé {
21134d1a4f5SPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(oc);
212f932093aSSergey Kambalin     BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
21334d1a4f5SPhilippe Mathieu-Daudé 
21434d1a4f5SPhilippe Mathieu-Daudé     bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
21525ea2884SPhilippe Mathieu-Daudé     bc->core_count = BCM283X_NCPUS;
21634d1a4f5SPhilippe Mathieu-Daudé     bc->peri_base = 0x3f000000;
21734d1a4f5SPhilippe Mathieu-Daudé     bc->ctrl_base = 0x40000000;
21834d1a4f5SPhilippe Mathieu-Daudé     bc->clusterid = 0x0;
21934d1a4f5SPhilippe Mathieu-Daudé     dc->realize = bcm2836_realize;
22034d1a4f5SPhilippe Mathieu-Daudé };
22134d1a4f5SPhilippe Mathieu-Daudé #endif
22234d1a4f5SPhilippe Mathieu-Daudé 
22334d1a4f5SPhilippe Mathieu-Daudé static const TypeInfo bcm283x_types[] = {
22434d1a4f5SPhilippe Mathieu-Daudé     {
225df6cf08dSPhilippe Mathieu-Daudé         .name           = TYPE_BCM2835,
226df6cf08dSPhilippe Mathieu-Daudé         .parent         = TYPE_BCM283X,
227df6cf08dSPhilippe Mathieu-Daudé         .class_init     = bcm2835_class_init,
228df6cf08dSPhilippe Mathieu-Daudé     }, {
22934d1a4f5SPhilippe Mathieu-Daudé         .name           = TYPE_BCM2836,
23034d1a4f5SPhilippe Mathieu-Daudé         .parent         = TYPE_BCM283X,
23134d1a4f5SPhilippe Mathieu-Daudé         .class_init     = bcm2836_class_init,
23234d1a4f5SPhilippe Mathieu-Daudé #ifdef TARGET_AARCH64
23334d1a4f5SPhilippe Mathieu-Daudé     }, {
23434d1a4f5SPhilippe Mathieu-Daudé         .name           = TYPE_BCM2837,
23534d1a4f5SPhilippe Mathieu-Daudé         .parent         = TYPE_BCM283X,
23634d1a4f5SPhilippe Mathieu-Daudé         .class_init     = bcm2837_class_init,
23734d1a4f5SPhilippe Mathieu-Daudé #endif
23834d1a4f5SPhilippe Mathieu-Daudé     }, {
239926dcdf0SPeter Maydell         .name           = TYPE_BCM283X,
240f932093aSSergey Kambalin         .parent         = TYPE_BCM283X_BASE,
241926dcdf0SPeter Maydell         .instance_size  = sizeof(BCM283XState),
242f932093aSSergey Kambalin         .instance_init  = bcm283x_init,
243f932093aSSergey Kambalin         .abstract       = true,
244f932093aSSergey Kambalin     }, {
245f932093aSSergey Kambalin         .name           = TYPE_BCM283X_BASE,
246f932093aSSergey Kambalin         .parent         = TYPE_DEVICE,
247f932093aSSergey Kambalin         .instance_size  = sizeof(BCM283XBaseState),
248f932093aSSergey Kambalin         .instance_init  = bcm283x_base_init,
249f932093aSSergey Kambalin         .class_size     = sizeof(BCM283XBaseClass),
250f932093aSSergey Kambalin         .class_init     = bcm283x_base_class_init,
25134d1a4f5SPhilippe Mathieu-Daudé         .abstract       = true,
25234d1a4f5SPhilippe Mathieu-Daudé     }
2530fd74f03SPeter Maydell };
254bad56236SAndrew Baumann 
25534d1a4f5SPhilippe Mathieu-Daudé DEFINE_TYPES(bcm283x_types)
256