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
2196c741d7SPhilippe Mathieu-Daudé static Property bcm2836_enabled_cores_property =
22f932093aSSergey Kambalin DEFINE_PROP_UINT32("enabled-cpus", BCM283XBaseState, enabled_cpus, 0);
2396c741d7SPhilippe Mathieu-Daudé
bcm283x_base_init(Object * obj)24f932093aSSergey Kambalin static void bcm283x_base_init(Object *obj)
25bad56236SAndrew Baumann {
26f932093aSSergey Kambalin BCM283XBaseState *s = BCM283X_BASE(obj);
27f932093aSSergey Kambalin BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(obj);
28210f4784SPeter Maydell int n;
29210f4784SPeter Maydell
3025ea2884SPhilippe Mathieu-Daudé for (n = 0; n < bc->core_count; n++) {
315e5e9ed6SPhilippe Mathieu-Daudé object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
3234d1a4f5SPhilippe Mathieu-Daudé bc->cpu_type);
33210f4784SPeter Maydell }
3496c741d7SPhilippe Mathieu-Daudé if (bc->core_count > 1) {
3596c741d7SPhilippe Mathieu-Daudé qdev_property_add_static(DEVICE(obj), &bcm2836_enabled_cores_property);
3696c741d7SPhilippe Mathieu-Daudé qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
3796c741d7SPhilippe Mathieu-Daudé }
38bad56236SAndrew Baumann
39f5600924SPhilippe Mathieu-Daudé if (bc->ctrl_base) {
40f5600924SPhilippe Mathieu-Daudé object_initialize_child(obj, "control", &s->control,
41f5600924SPhilippe Mathieu-Daudé TYPE_BCM2836_CONTROL);
42f5600924SPhilippe Mathieu-Daudé }
43f932093aSSergey Kambalin }
44f932093aSSergey Kambalin
bcm283x_init(Object * obj)45f932093aSSergey Kambalin static void bcm283x_init(Object *obj)
46f932093aSSergey Kambalin {
47f932093aSSergey Kambalin BCM283XState *s = BCM283X(obj);
48bad56236SAndrew Baumann
49db873cc5SMarkus Armbruster object_initialize_child(obj, "peripherals", &s->peripherals,
50db873cc5SMarkus Armbruster TYPE_BCM2835_PERIPHERALS);
51f0afa731SStephen Warren object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
52d2623129SMarkus Armbruster "board-rev");
53f802ff1eSDaniel Bertalan object_property_add_alias(obj, "command-line", OBJECT(&s->peripherals),
54f802ff1eSDaniel Bertalan "command-line");
555e9c2a8dSGrégory ESTRADE object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
56d2623129SMarkus Armbruster "vcram-size");
57*7785e8eaSSergey Kambalin object_property_add_alias(obj, "vcram-base", OBJECT(&s->peripherals),
58*7785e8eaSSergey Kambalin "vcram-base");
59bad56236SAndrew Baumann }
60bad56236SAndrew Baumann
bcm283x_common_realize(DeviceState * dev,BCMSocPeripheralBaseState * ps,Error ** errp)617d04d630SSergey Kambalin bool bcm283x_common_realize(DeviceState *dev, BCMSocPeripheralBaseState *ps,
627d04d630SSergey Kambalin Error **errp)
63bad56236SAndrew Baumann {
647d04d630SSergey Kambalin BCM283XBaseState *s = BCM283X_BASE(dev);
65f932093aSSergey Kambalin BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(dev);
66bad56236SAndrew Baumann Object *obj;
67bad56236SAndrew Baumann
68bad56236SAndrew Baumann /* common peripherals from bcm2835 */
69bad56236SAndrew Baumann
704d21fcd5SMarkus Armbruster obj = object_property_get_link(OBJECT(dev), "ram", &error_abort);
71bad56236SAndrew Baumann
727d04d630SSergey Kambalin object_property_add_const_link(OBJECT(ps), "ram", obj);
73bad56236SAndrew Baumann
747d04d630SSergey Kambalin if (!sysbus_realize(SYS_BUS_DEVICE(ps), errp)) {
75f5600924SPhilippe Mathieu-Daudé return false;
76bad56236SAndrew Baumann }
77bad56236SAndrew Baumann
787d04d630SSergey Kambalin object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(ps), "sd-bus");
79a55b53a2SAndrew Baumann
807d04d630SSergey Kambalin sysbus_mmio_map_overlap(SYS_BUS_DEVICE(ps), 0, bc->peri_base, 1);
81f5600924SPhilippe Mathieu-Daudé return true;
82f5600924SPhilippe Mathieu-Daudé }
83f5600924SPhilippe Mathieu-Daudé
bcm2835_realize(DeviceState * dev,Error ** errp)84df6cf08dSPhilippe Mathieu-Daudé static void bcm2835_realize(DeviceState *dev, Error **errp)
85df6cf08dSPhilippe Mathieu-Daudé {
86df6cf08dSPhilippe Mathieu-Daudé BCM283XState *s = BCM283X(dev);
87f932093aSSergey Kambalin BCM283XBaseState *s_base = BCM283X_BASE(dev);
887d04d630SSergey Kambalin BCMSocPeripheralBaseState *ps_base
897d04d630SSergey Kambalin = BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
90df6cf08dSPhilippe Mathieu-Daudé
917d04d630SSergey Kambalin if (!bcm283x_common_realize(dev, ps_base, errp)) {
92df6cf08dSPhilippe Mathieu-Daudé return;
93df6cf08dSPhilippe Mathieu-Daudé }
94df6cf08dSPhilippe Mathieu-Daudé
95f932093aSSergey Kambalin if (!qdev_realize(DEVICE(&s_base->cpu[0].core), NULL, errp)) {
96df6cf08dSPhilippe Mathieu-Daudé return;
97df6cf08dSPhilippe Mathieu-Daudé }
98df6cf08dSPhilippe Mathieu-Daudé
99df6cf08dSPhilippe Mathieu-Daudé /* Connect irq/fiq outputs from the interrupt controller. */
100df6cf08dSPhilippe Mathieu-Daudé sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
101f932093aSSergey Kambalin qdev_get_gpio_in(DEVICE(&s_base->cpu[0].core), ARM_CPU_IRQ));
102df6cf08dSPhilippe Mathieu-Daudé sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
103f932093aSSergey Kambalin qdev_get_gpio_in(DEVICE(&s_base->cpu[0].core), ARM_CPU_FIQ));
104df6cf08dSPhilippe Mathieu-Daudé }
105df6cf08dSPhilippe Mathieu-Daudé
bcm2836_realize(DeviceState * dev,Error ** errp)106f5600924SPhilippe Mathieu-Daudé static void bcm2836_realize(DeviceState *dev, Error **errp)
107f5600924SPhilippe Mathieu-Daudé {
108f5600924SPhilippe Mathieu-Daudé int n;
109f932093aSSergey Kambalin BCM283XState *s = BCM283X(dev);
110f932093aSSergey Kambalin BCM283XBaseState *s_base = BCM283X_BASE(dev);
111f932093aSSergey Kambalin BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(dev);
1127d04d630SSergey Kambalin BCMSocPeripheralBaseState *ps_base
1137d04d630SSergey Kambalin = BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
114f5600924SPhilippe Mathieu-Daudé
1157d04d630SSergey Kambalin if (!bcm283x_common_realize(dev, ps_base, errp)) {
116f5600924SPhilippe Mathieu-Daudé return;
117f5600924SPhilippe Mathieu-Daudé }
118bad56236SAndrew Baumann
119bad56236SAndrew Baumann /* bcm2836 interrupt controller (and mailboxes, etc.) */
120f932093aSSergey Kambalin if (!sysbus_realize(SYS_BUS_DEVICE(&s_base->control), errp)) {
121bad56236SAndrew Baumann return;
122bad56236SAndrew Baumann }
123bad56236SAndrew Baumann
124f932093aSSergey Kambalin sysbus_mmio_map(SYS_BUS_DEVICE(&s_base->control), 0, bc->ctrl_base);
125bad56236SAndrew Baumann
126bad56236SAndrew Baumann sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
127f932093aSSergey Kambalin qdev_get_gpio_in_named(DEVICE(&s_base->control), "gpu-irq", 0));
128bad56236SAndrew Baumann sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
129f932093aSSergey Kambalin qdev_get_gpio_in_named(DEVICE(&s_base->control), "gpu-fiq", 0));
130bad56236SAndrew Baumann
131926dcdf0SPeter Maydell for (n = 0; n < BCM283X_NCPUS; n++) {
132f932093aSSergey Kambalin object_property_set_int(OBJECT(&s_base->cpu[n].core), "mp-affinity",
13379f51695SPhilippe Mathieu-Daudé (bc->clusterid << 8) | n, &error_abort);
134bad56236SAndrew Baumann
135bad56236SAndrew Baumann /* set periphbase/CBAR value for CPU-local registers */
136f932093aSSergey Kambalin object_property_set_int(OBJECT(&s_base->cpu[n].core), "reset-cbar",
137ca1d323cSPhilippe Mathieu-Daudé bc->peri_base, &error_abort);
138bad56236SAndrew Baumann
139bad56236SAndrew Baumann /* start powered off if not enabled */
140f932093aSSergey Kambalin object_property_set_bool(OBJECT(&s_base->cpu[n].core),
141f932093aSSergey Kambalin "start-powered-off",
142f932093aSSergey Kambalin n >= s_base->enabled_cpus, &error_abort);
143bad56236SAndrew Baumann
144f932093aSSergey Kambalin if (!qdev_realize(DEVICE(&s_base->cpu[n].core), NULL, errp)) {
145bad56236SAndrew Baumann return;
146bad56236SAndrew Baumann }
147bad56236SAndrew Baumann
148bad56236SAndrew Baumann /* Connect irq/fiq outputs from the interrupt controller. */
149f932093aSSergey Kambalin qdev_connect_gpio_out_named(DEVICE(&s_base->control), "irq", n,
150f932093aSSergey Kambalin qdev_get_gpio_in(DEVICE(&s_base->cpu[n].core), ARM_CPU_IRQ));
151f932093aSSergey Kambalin qdev_connect_gpio_out_named(DEVICE(&s_base->control), "fiq", n,
152f932093aSSergey Kambalin qdev_get_gpio_in(DEVICE(&s_base->cpu[n].core), ARM_CPU_FIQ));
153bad56236SAndrew Baumann
154bad56236SAndrew Baumann /* Connect timers from the CPU to the interrupt controller */
155f932093aSSergey Kambalin qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_PHYS,
156f932093aSSergey Kambalin qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntpnsirq", n));
157f932093aSSergey Kambalin qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_VIRT,
158f932093aSSergey Kambalin qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntvirq", n));
159f932093aSSergey Kambalin qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_HYP,
160f932093aSSergey Kambalin qdev_get_gpio_in_named(DEVICE(&s_base->control), "cnthpirq", n));
161f932093aSSergey Kambalin qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_SEC,
162f932093aSSergey Kambalin qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntpsirq", n));
163bad56236SAndrew Baumann }
164bad56236SAndrew Baumann }
165bad56236SAndrew Baumann
bcm283x_base_class_init(ObjectClass * oc,void * data)166f932093aSSergey Kambalin static void bcm283x_base_class_init(ObjectClass *oc, void *data)
167bad56236SAndrew Baumann {
168bad56236SAndrew Baumann DeviceClass *dc = DEVICE_CLASS(oc);
169bad56236SAndrew Baumann
170cccf96c3SThomas Huth /* Reason: Must be wired up in code (see raspi_init() function) */
171cccf96c3SThomas Huth dc->user_creatable = false;
172bad56236SAndrew Baumann }
173bad56236SAndrew Baumann
bcm2835_class_init(ObjectClass * oc,void * data)174df6cf08dSPhilippe Mathieu-Daudé static void bcm2835_class_init(ObjectClass *oc, void *data)
175df6cf08dSPhilippe Mathieu-Daudé {
176df6cf08dSPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(oc);
177f932093aSSergey Kambalin BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
178df6cf08dSPhilippe Mathieu-Daudé
179df6cf08dSPhilippe Mathieu-Daudé bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
180df6cf08dSPhilippe Mathieu-Daudé bc->core_count = 1;
181df6cf08dSPhilippe Mathieu-Daudé bc->peri_base = 0x20000000;
182df6cf08dSPhilippe Mathieu-Daudé dc->realize = bcm2835_realize;
183df6cf08dSPhilippe Mathieu-Daudé };
184df6cf08dSPhilippe Mathieu-Daudé
bcm2836_class_init(ObjectClass * oc,void * data)18534d1a4f5SPhilippe Mathieu-Daudé static void bcm2836_class_init(ObjectClass *oc, void *data)
18634d1a4f5SPhilippe Mathieu-Daudé {
18734d1a4f5SPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(oc);
188f932093aSSergey Kambalin BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
18934d1a4f5SPhilippe Mathieu-Daudé
19034d1a4f5SPhilippe Mathieu-Daudé bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
19125ea2884SPhilippe Mathieu-Daudé bc->core_count = BCM283X_NCPUS;
19234d1a4f5SPhilippe Mathieu-Daudé bc->peri_base = 0x3f000000;
19334d1a4f5SPhilippe Mathieu-Daudé bc->ctrl_base = 0x40000000;
19434d1a4f5SPhilippe Mathieu-Daudé bc->clusterid = 0xf;
19534d1a4f5SPhilippe Mathieu-Daudé dc->realize = bcm2836_realize;
19634d1a4f5SPhilippe Mathieu-Daudé };
19734d1a4f5SPhilippe Mathieu-Daudé
19834d1a4f5SPhilippe Mathieu-Daudé #ifdef TARGET_AARCH64
bcm2837_class_init(ObjectClass * oc,void * data)19934d1a4f5SPhilippe Mathieu-Daudé static void bcm2837_class_init(ObjectClass *oc, void *data)
20034d1a4f5SPhilippe Mathieu-Daudé {
20134d1a4f5SPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(oc);
202f932093aSSergey Kambalin BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
20334d1a4f5SPhilippe Mathieu-Daudé
20434d1a4f5SPhilippe Mathieu-Daudé bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
20525ea2884SPhilippe Mathieu-Daudé bc->core_count = BCM283X_NCPUS;
20634d1a4f5SPhilippe Mathieu-Daudé bc->peri_base = 0x3f000000;
20734d1a4f5SPhilippe Mathieu-Daudé bc->ctrl_base = 0x40000000;
20834d1a4f5SPhilippe Mathieu-Daudé bc->clusterid = 0x0;
20934d1a4f5SPhilippe Mathieu-Daudé dc->realize = bcm2836_realize;
21034d1a4f5SPhilippe Mathieu-Daudé };
21134d1a4f5SPhilippe Mathieu-Daudé #endif
21234d1a4f5SPhilippe Mathieu-Daudé
21334d1a4f5SPhilippe Mathieu-Daudé static const TypeInfo bcm283x_types[] = {
21434d1a4f5SPhilippe Mathieu-Daudé {
215df6cf08dSPhilippe Mathieu-Daudé .name = TYPE_BCM2835,
216df6cf08dSPhilippe Mathieu-Daudé .parent = TYPE_BCM283X,
217df6cf08dSPhilippe Mathieu-Daudé .class_init = bcm2835_class_init,
218df6cf08dSPhilippe Mathieu-Daudé }, {
21934d1a4f5SPhilippe Mathieu-Daudé .name = TYPE_BCM2836,
22034d1a4f5SPhilippe Mathieu-Daudé .parent = TYPE_BCM283X,
22134d1a4f5SPhilippe Mathieu-Daudé .class_init = bcm2836_class_init,
22234d1a4f5SPhilippe Mathieu-Daudé #ifdef TARGET_AARCH64
22334d1a4f5SPhilippe Mathieu-Daudé }, {
22434d1a4f5SPhilippe Mathieu-Daudé .name = TYPE_BCM2837,
22534d1a4f5SPhilippe Mathieu-Daudé .parent = TYPE_BCM283X,
22634d1a4f5SPhilippe Mathieu-Daudé .class_init = bcm2837_class_init,
22734d1a4f5SPhilippe Mathieu-Daudé #endif
22834d1a4f5SPhilippe Mathieu-Daudé }, {
229926dcdf0SPeter Maydell .name = TYPE_BCM283X,
230f932093aSSergey Kambalin .parent = TYPE_BCM283X_BASE,
231926dcdf0SPeter Maydell .instance_size = sizeof(BCM283XState),
232f932093aSSergey Kambalin .instance_init = bcm283x_init,
233f932093aSSergey Kambalin .abstract = true,
234f932093aSSergey Kambalin }, {
235f932093aSSergey Kambalin .name = TYPE_BCM283X_BASE,
236f932093aSSergey Kambalin .parent = TYPE_DEVICE,
237f932093aSSergey Kambalin .instance_size = sizeof(BCM283XBaseState),
238f932093aSSergey Kambalin .instance_init = bcm283x_base_init,
239f932093aSSergey Kambalin .class_size = sizeof(BCM283XBaseClass),
240f932093aSSergey Kambalin .class_init = bcm283x_base_class_init,
24134d1a4f5SPhilippe Mathieu-Daudé .abstract = true,
24234d1a4f5SPhilippe Mathieu-Daudé }
2430fd74f03SPeter Maydell };
244bad56236SAndrew Baumann
24534d1a4f5SPhilippe Mathieu-Daudé DEFINE_TYPES(bcm283x_types)
246