xref: /qemu/hw/arm/bcm2836.c (revision 5be5df72)
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-common.h"
14 #include "cpu.h"
15 #include "hw/arm/bcm2836.h"
16 #include "hw/arm/raspi_platform.h"
17 #include "hw/sysbus.h"
18 
19 /* Peripheral base address seen by the CPU */
20 #define BCM2836_PERI_BASE       0x3F000000
21 
22 /* "QA7" (Pi2) interrupt controller and mailboxes etc. */
23 #define BCM2836_CONTROL_BASE    0x40000000
24 
25 struct BCM283XInfo {
26     const char *name;
27     const char *cpu_type;
28     int clusterid;
29 };
30 
31 static const BCM283XInfo bcm283x_socs[] = {
32     {
33         .name = TYPE_BCM2836,
34         .cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"),
35         .clusterid = 0xf,
36     },
37 #ifdef TARGET_AARCH64
38     {
39         .name = TYPE_BCM2837,
40         .cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"),
41         .clusterid = 0x0,
42     },
43 #endif
44 };
45 
46 static void bcm2836_init(Object *obj)
47 {
48     BCM283XState *s = BCM283X(obj);
49     BCM283XClass *bc = BCM283X_GET_CLASS(obj);
50     const BCM283XInfo *info = bc->info;
51     int n;
52 
53     for (n = 0; n < BCM283X_NCPUS; n++) {
54         object_initialize_child(obj, "cpu[*]", &s->cpus[n], sizeof(s->cpus[n]),
55                                 info->cpu_type, &error_abort, NULL);
56     }
57 
58     sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control),
59                           TYPE_BCM2836_CONTROL);
60 
61     sysbus_init_child_obj(obj, "peripherals", &s->peripherals,
62                           sizeof(s->peripherals), TYPE_BCM2835_PERIPHERALS);
63     object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
64                               "board-rev", &error_abort);
65     object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
66                               "vcram-size", &error_abort);
67 }
68 
69 static void bcm2836_realize(DeviceState *dev, Error **errp)
70 {
71     BCM283XState *s = BCM283X(dev);
72     BCM283XClass *bc = BCM283X_GET_CLASS(dev);
73     const BCM283XInfo *info = bc->info;
74     Object *obj;
75     Error *err = NULL;
76     int n;
77 
78     /* common peripherals from bcm2835 */
79 
80     obj = object_property_get_link(OBJECT(dev), "ram", &err);
81     if (obj == NULL) {
82         error_setg(errp, "%s: required ram link not found: %s",
83                    __func__, error_get_pretty(err));
84         return;
85     }
86 
87     object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err);
88     if (err) {
89         error_propagate(errp, err);
90         return;
91     }
92 
93     object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err);
94     if (err) {
95         error_propagate(errp, err);
96         return;
97     }
98 
99     object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
100                               "sd-bus", &err);
101     if (err) {
102         error_propagate(errp, err);
103         return;
104     }
105 
106     sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
107                             BCM2836_PERI_BASE, 1);
108 
109     /* bcm2836 interrupt controller (and mailboxes, etc.) */
110     object_property_set_bool(OBJECT(&s->control), true, "realized", &err);
111     if (err) {
112         error_propagate(errp, err);
113         return;
114     }
115 
116     sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE);
117 
118     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
119         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
120     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
121         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
122 
123     for (n = 0; n < BCM283X_NCPUS; n++) {
124         /* TODO: this should be converted to a property of ARM_CPU */
125         s->cpus[n].mp_affinity = (info->clusterid << 8) | n;
126 
127         /* set periphbase/CBAR value for CPU-local registers */
128         object_property_set_int(OBJECT(&s->cpus[n]),
129                                 BCM2836_PERI_BASE + MCORE_OFFSET,
130                                 "reset-cbar", &err);
131         if (err) {
132             error_propagate(errp, err);
133             return;
134         }
135 
136         /* start powered off if not enabled */
137         object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus,
138                                  "start-powered-off", &err);
139         if (err) {
140             error_propagate(errp, err);
141             return;
142         }
143 
144         object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err);
145         if (err) {
146             error_propagate(errp, err);
147             return;
148         }
149 
150         /* Connect irq/fiq outputs from the interrupt controller. */
151         qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
152                 qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ));
153         qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n,
154                 qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ));
155 
156         /* Connect timers from the CPU to the interrupt controller */
157         qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS,
158                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n));
159         qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT,
160                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n));
161         qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP,
162                 qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n));
163         qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC,
164                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n));
165     }
166 }
167 
168 static Property bcm2836_props[] = {
169     DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus,
170                        BCM283X_NCPUS),
171     DEFINE_PROP_END_OF_LIST()
172 };
173 
174 static void bcm283x_class_init(ObjectClass *oc, void *data)
175 {
176     DeviceClass *dc = DEVICE_CLASS(oc);
177     BCM283XClass *bc = BCM283X_CLASS(oc);
178 
179     bc->info = data;
180     dc->realize = bcm2836_realize;
181     dc->props = bcm2836_props;
182     /* Reason: Must be wired up in code (see raspi_init() function) */
183     dc->user_creatable = false;
184 }
185 
186 static const TypeInfo bcm283x_type_info = {
187     .name = TYPE_BCM283X,
188     .parent = TYPE_DEVICE,
189     .instance_size = sizeof(BCM283XState),
190     .instance_init = bcm2836_init,
191     .class_size = sizeof(BCM283XClass),
192     .abstract = true,
193 };
194 
195 static void bcm2836_register_types(void)
196 {
197     int i;
198 
199     type_register_static(&bcm283x_type_info);
200     for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) {
201         TypeInfo ti = {
202             .name = bcm283x_socs[i].name,
203             .parent = TYPE_BCM283X,
204             .class_init = bcm283x_class_init,
205             .class_data = (void *) &bcm283x_socs[i],
206         };
207         type_register(&ti);
208     }
209 }
210 
211 type_init(bcm2836_register_types)
212