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