xref: /qemu/hw/arm/bcm2836.c (revision 0fd74f03ed7e8c95279a9af2b684dd65713ca03f)
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  *
8bad56236SAndrew Baumann  * This code is licensed under the GNU GPLv2 and later.
9bad56236SAndrew Baumann  */
10bad56236SAndrew Baumann 
11c964b660SPeter Maydell #include "qemu/osdep.h"
12da34e65cSMarkus Armbruster #include "qapi/error.h"
134771d756SPaolo Bonzini #include "qemu-common.h"
144771d756SPaolo Bonzini #include "cpu.h"
15bad56236SAndrew Baumann #include "hw/arm/bcm2836.h"
16bad56236SAndrew Baumann #include "hw/arm/raspi_platform.h"
17bad56236SAndrew Baumann #include "hw/sysbus.h"
18bad56236SAndrew Baumann #include "exec/address-spaces.h"
19bad56236SAndrew Baumann 
20bad56236SAndrew Baumann /* Peripheral base address seen by the CPU */
21bad56236SAndrew Baumann #define BCM2836_PERI_BASE       0x3F000000
22bad56236SAndrew Baumann 
23bad56236SAndrew Baumann /* "QA7" (Pi2) interrupt controller and mailboxes etc. */
24bad56236SAndrew Baumann #define BCM2836_CONTROL_BASE    0x40000000
25bad56236SAndrew Baumann 
26*0fd74f03SPeter Maydell struct BCM283XInfo {
27*0fd74f03SPeter Maydell     const char *name;
28*0fd74f03SPeter Maydell };
29*0fd74f03SPeter Maydell 
30*0fd74f03SPeter Maydell static const BCM283XInfo bcm283x_socs[] = {
31*0fd74f03SPeter Maydell     {
32*0fd74f03SPeter Maydell         .name = TYPE_BCM2836,
33*0fd74f03SPeter Maydell     },
34*0fd74f03SPeter Maydell     {
35*0fd74f03SPeter Maydell         .name = TYPE_BCM2837,
36*0fd74f03SPeter Maydell     },
37*0fd74f03SPeter Maydell };
38*0fd74f03SPeter Maydell 
39bad56236SAndrew Baumann static void bcm2836_init(Object *obj)
40bad56236SAndrew Baumann {
41926dcdf0SPeter Maydell     BCM283XState *s = BCM283X(obj);
42bad56236SAndrew Baumann 
43bad56236SAndrew Baumann     object_initialize(&s->control, sizeof(s->control), TYPE_BCM2836_CONTROL);
44bad56236SAndrew Baumann     object_property_add_child(obj, "control", OBJECT(&s->control), NULL);
45bad56236SAndrew Baumann     qdev_set_parent_bus(DEVICE(&s->control), sysbus_get_default());
46bad56236SAndrew Baumann 
47bad56236SAndrew Baumann     object_initialize(&s->peripherals, sizeof(s->peripherals),
48bad56236SAndrew Baumann                       TYPE_BCM2835_PERIPHERALS);
49bad56236SAndrew Baumann     object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals),
50bad56236SAndrew Baumann                               &error_abort);
51f0afa731SStephen Warren     object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
52f0afa731SStephen Warren                               "board-rev", &error_abort);
535e9c2a8dSGrégory ESTRADE     object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
545e9c2a8dSGrégory ESTRADE                               "vcram-size", &error_abort);
55bad56236SAndrew Baumann     qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default());
56bad56236SAndrew Baumann }
57bad56236SAndrew Baumann 
58bad56236SAndrew Baumann static void bcm2836_realize(DeviceState *dev, Error **errp)
59bad56236SAndrew Baumann {
60926dcdf0SPeter Maydell     BCM283XState *s = BCM283X(dev);
61bad56236SAndrew Baumann     Object *obj;
62bad56236SAndrew Baumann     Error *err = NULL;
63bad56236SAndrew Baumann     int n;
64bad56236SAndrew Baumann 
65bad56236SAndrew Baumann     /* common peripherals from bcm2835 */
66bad56236SAndrew Baumann 
67d9f8bbd8SPekka Enberg     obj = OBJECT(dev);
68926dcdf0SPeter Maydell     for (n = 0; n < BCM283X_NCPUS; n++) {
69d9f8bbd8SPekka Enberg         object_initialize(&s->cpus[n], sizeof(s->cpus[n]),
70d9f8bbd8SPekka Enberg                           s->cpu_type);
71d9f8bbd8SPekka Enberg         object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]),
72d9f8bbd8SPekka Enberg                                   &error_abort);
73d9f8bbd8SPekka Enberg     }
74d9f8bbd8SPekka Enberg 
75bad56236SAndrew Baumann     obj = object_property_get_link(OBJECT(dev), "ram", &err);
76bad56236SAndrew Baumann     if (obj == NULL) {
77bad56236SAndrew Baumann         error_setg(errp, "%s: required ram link not found: %s",
78bad56236SAndrew Baumann                    __func__, error_get_pretty(err));
79bad56236SAndrew Baumann         return;
80bad56236SAndrew Baumann     }
81bad56236SAndrew Baumann 
82bad56236SAndrew Baumann     object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err);
83bad56236SAndrew Baumann     if (err) {
84bad56236SAndrew Baumann         error_propagate(errp, err);
85bad56236SAndrew Baumann         return;
86bad56236SAndrew Baumann     }
87bad56236SAndrew Baumann 
88bad56236SAndrew Baumann     object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err);
89bad56236SAndrew Baumann     if (err) {
90bad56236SAndrew Baumann         error_propagate(errp, err);
91bad56236SAndrew Baumann         return;
92bad56236SAndrew Baumann     }
93bad56236SAndrew Baumann 
94a55b53a2SAndrew Baumann     object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
95a55b53a2SAndrew Baumann                               "sd-bus", &err);
96a55b53a2SAndrew Baumann     if (err) {
97a55b53a2SAndrew Baumann         error_propagate(errp, err);
98a55b53a2SAndrew Baumann         return;
99a55b53a2SAndrew Baumann     }
100a55b53a2SAndrew Baumann 
101bad56236SAndrew Baumann     sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
102bad56236SAndrew Baumann                             BCM2836_PERI_BASE, 1);
103bad56236SAndrew Baumann 
104bad56236SAndrew Baumann     /* bcm2836 interrupt controller (and mailboxes, etc.) */
105bad56236SAndrew Baumann     object_property_set_bool(OBJECT(&s->control), true, "realized", &err);
106bad56236SAndrew Baumann     if (err) {
107bad56236SAndrew Baumann         error_propagate(errp, err);
108bad56236SAndrew Baumann         return;
109bad56236SAndrew Baumann     }
110bad56236SAndrew Baumann 
111bad56236SAndrew Baumann     sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE);
112bad56236SAndrew Baumann 
113bad56236SAndrew Baumann     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
114bad56236SAndrew Baumann         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
115bad56236SAndrew Baumann     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
116bad56236SAndrew Baumann         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
117bad56236SAndrew Baumann 
118926dcdf0SPeter Maydell     for (n = 0; n < BCM283X_NCPUS; n++) {
119bad56236SAndrew Baumann         /* Mirror bcm2836, which has clusterid set to 0xf
120bad56236SAndrew Baumann          * TODO: this should be converted to a property of ARM_CPU
121bad56236SAndrew Baumann          */
122bad56236SAndrew Baumann         s->cpus[n].mp_affinity = 0xF00 | n;
123bad56236SAndrew Baumann 
124bad56236SAndrew Baumann         /* set periphbase/CBAR value for CPU-local registers */
125bad56236SAndrew Baumann         object_property_set_int(OBJECT(&s->cpus[n]),
126bad56236SAndrew Baumann                                 BCM2836_PERI_BASE + MCORE_OFFSET,
127bad56236SAndrew Baumann                                 "reset-cbar", &err);
128bad56236SAndrew Baumann         if (err) {
129bad56236SAndrew Baumann             error_propagate(errp, err);
130bad56236SAndrew Baumann             return;
131bad56236SAndrew Baumann         }
132bad56236SAndrew Baumann 
133bad56236SAndrew Baumann         /* start powered off if not enabled */
134bad56236SAndrew Baumann         object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus,
135bad56236SAndrew Baumann                                  "start-powered-off", &err);
136bad56236SAndrew Baumann         if (err) {
137bad56236SAndrew Baumann             error_propagate(errp, err);
138bad56236SAndrew Baumann             return;
139bad56236SAndrew Baumann         }
140bad56236SAndrew Baumann 
141bad56236SAndrew Baumann         object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err);
142bad56236SAndrew Baumann         if (err) {
143bad56236SAndrew Baumann             error_propagate(errp, err);
144bad56236SAndrew Baumann             return;
145bad56236SAndrew Baumann         }
146bad56236SAndrew Baumann 
147bad56236SAndrew Baumann         /* Connect irq/fiq outputs from the interrupt controller. */
148bad56236SAndrew Baumann         qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
149bad56236SAndrew Baumann                 qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ));
150bad56236SAndrew Baumann         qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n,
151bad56236SAndrew Baumann                 qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ));
152bad56236SAndrew Baumann 
153bad56236SAndrew Baumann         /* Connect timers from the CPU to the interrupt controller */
154bad56236SAndrew Baumann         qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS,
1550dc19823SPeter Maydell                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n));
156bad56236SAndrew Baumann         qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT,
157bad56236SAndrew Baumann                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n));
1580dc19823SPeter Maydell         qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP,
1590dc19823SPeter Maydell                 qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n));
1600dc19823SPeter Maydell         qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC,
1610dc19823SPeter Maydell                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n));
162bad56236SAndrew Baumann     }
163bad56236SAndrew Baumann }
164bad56236SAndrew Baumann 
165bad56236SAndrew Baumann static Property bcm2836_props[] = {
166926dcdf0SPeter Maydell     DEFINE_PROP_STRING("cpu-type", BCM283XState, cpu_type),
167926dcdf0SPeter Maydell     DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus,
168926dcdf0SPeter Maydell                        BCM283X_NCPUS),
169bad56236SAndrew Baumann     DEFINE_PROP_END_OF_LIST()
170bad56236SAndrew Baumann };
171bad56236SAndrew Baumann 
172*0fd74f03SPeter Maydell static void bcm283x_class_init(ObjectClass *oc, void *data)
173bad56236SAndrew Baumann {
174bad56236SAndrew Baumann     DeviceClass *dc = DEVICE_CLASS(oc);
175*0fd74f03SPeter Maydell     BCM283XClass *bc = BCM283X_CLASS(oc);
176bad56236SAndrew Baumann 
177*0fd74f03SPeter Maydell     bc->info = data;
178bad56236SAndrew Baumann     dc->realize = bcm2836_realize;
179*0fd74f03SPeter Maydell     dc->props = bcm2836_props;
180bad56236SAndrew Baumann }
181bad56236SAndrew Baumann 
182*0fd74f03SPeter Maydell static const TypeInfo bcm283x_type_info = {
183926dcdf0SPeter Maydell     .name = TYPE_BCM283X,
1843d260cf3SPeter Maydell     .parent = TYPE_DEVICE,
185926dcdf0SPeter Maydell     .instance_size = sizeof(BCM283XState),
186bad56236SAndrew Baumann     .instance_init = bcm2836_init,
187*0fd74f03SPeter Maydell     .class_size = sizeof(BCM283XClass),
188*0fd74f03SPeter Maydell     .abstract = true,
189bad56236SAndrew Baumann };
190bad56236SAndrew Baumann 
191bad56236SAndrew Baumann static void bcm2836_register_types(void)
192bad56236SAndrew Baumann {
193*0fd74f03SPeter Maydell     int i;
194*0fd74f03SPeter Maydell 
195*0fd74f03SPeter Maydell     type_register_static(&bcm283x_type_info);
196*0fd74f03SPeter Maydell     for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) {
197*0fd74f03SPeter Maydell         TypeInfo ti = {
198*0fd74f03SPeter Maydell             .name = bcm283x_socs[i].name,
199*0fd74f03SPeter Maydell             .parent = TYPE_BCM283X,
200*0fd74f03SPeter Maydell             .class_init = bcm283x_class_init,
201*0fd74f03SPeter Maydell             .class_data = (void *) &bcm283x_socs[i],
202*0fd74f03SPeter Maydell         };
203*0fd74f03SPeter Maydell         type_register(&ti);
204*0fd74f03SPeter Maydell     }
205bad56236SAndrew Baumann }
206bad56236SAndrew Baumann 
207bad56236SAndrew Baumann type_init(bcm2836_register_types)
208