xref: /openbmc/qemu/hw/arm/bcm2836.c (revision 29318db1)
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 work is licensed under the terms of the GNU GPL, version 2 or later.
9  * See the COPYING file in the top-level directory.
10  */
11 
12 #include "qemu/osdep.h"
13 #include "qapi/error.h"
14 #include "qemu/module.h"
15 #include "hw/arm/bcm2836.h"
16 #include "hw/arm/raspi_platform.h"
17 #include "hw/sysbus.h"
18 #include "target/arm/cpu-qom.h"
19 #include "target/arm/gtimer.h"
20 
21 static Property bcm2836_enabled_cores_property =
22     DEFINE_PROP_UINT32("enabled-cpus", BCM283XBaseState, enabled_cpus, 0);
23 
24 static void bcm283x_base_init(Object *obj)
25 {
26     BCM283XBaseState *s = BCM283X_BASE(obj);
27     BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(obj);
28     int n;
29 
30     for (n = 0; n < bc->core_count; n++) {
31         object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
32                                 bc->cpu_type);
33     }
34     if (bc->core_count > 1) {
35         qdev_property_add_static(DEVICE(obj), &bcm2836_enabled_cores_property);
36         qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
37     }
38 
39     if (bc->ctrl_base) {
40         object_initialize_child(obj, "control", &s->control,
41                                 TYPE_BCM2836_CONTROL);
42     }
43 }
44 
45 static void bcm283x_init(Object *obj)
46 {
47     BCM283XState *s = BCM283X(obj);
48 
49     object_initialize_child(obj, "peripherals", &s->peripherals,
50                             TYPE_BCM2835_PERIPHERALS);
51     object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
52                               "board-rev");
53     object_property_add_alias(obj, "command-line", OBJECT(&s->peripherals),
54                               "command-line");
55     object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
56                               "vcram-size");
57     object_property_add_alias(obj, "vcram-base", OBJECT(&s->peripherals),
58                               "vcram-base");
59 }
60 
61 bool bcm283x_common_realize(DeviceState *dev, BCMSocPeripheralBaseState *ps,
62                             Error **errp)
63 {
64     BCM283XBaseState *s = BCM283X_BASE(dev);
65     BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(dev);
66     Object *obj;
67 
68     /* common peripherals from bcm2835 */
69 
70     obj = object_property_get_link(OBJECT(dev), "ram", &error_abort);
71 
72     object_property_add_const_link(OBJECT(ps), "ram", obj);
73 
74     if (!sysbus_realize(SYS_BUS_DEVICE(ps), errp)) {
75         return false;
76     }
77 
78     object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(ps), "sd-bus");
79 
80     sysbus_mmio_map_overlap(SYS_BUS_DEVICE(ps), 0, bc->peri_base, 1);
81     return true;
82 }
83 
84 static void bcm2835_realize(DeviceState *dev, Error **errp)
85 {
86     BCM283XState *s = BCM283X(dev);
87     BCM283XBaseState *s_base = BCM283X_BASE(dev);
88     BCMSocPeripheralBaseState *ps_base
89         = BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
90 
91     if (!bcm283x_common_realize(dev, ps_base, errp)) {
92         return;
93     }
94 
95     if (!qdev_realize(DEVICE(&s_base->cpu[0].core), NULL, errp)) {
96         return;
97     }
98 
99     /* Connect irq/fiq outputs from the interrupt controller. */
100     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
101             qdev_get_gpio_in(DEVICE(&s_base->cpu[0].core), ARM_CPU_IRQ));
102     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
103             qdev_get_gpio_in(DEVICE(&s_base->cpu[0].core), ARM_CPU_FIQ));
104 }
105 
106 static void bcm2836_realize(DeviceState *dev, Error **errp)
107 {
108     int n;
109     BCM283XState *s = BCM283X(dev);
110     BCM283XBaseState *s_base = BCM283X_BASE(dev);
111     BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(dev);
112     BCMSocPeripheralBaseState *ps_base
113         = BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
114 
115     if (!bcm283x_common_realize(dev, ps_base, errp)) {
116         return;
117     }
118 
119     /* bcm2836 interrupt controller (and mailboxes, etc.) */
120     if (!sysbus_realize(SYS_BUS_DEVICE(&s_base->control), errp)) {
121         return;
122     }
123 
124     sysbus_mmio_map(SYS_BUS_DEVICE(&s_base->control), 0, bc->ctrl_base);
125 
126     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
127         qdev_get_gpio_in_named(DEVICE(&s_base->control), "gpu-irq", 0));
128     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
129         qdev_get_gpio_in_named(DEVICE(&s_base->control), "gpu-fiq", 0));
130 
131     for (n = 0; n < BCM283X_NCPUS; n++) {
132         object_property_set_int(OBJECT(&s_base->cpu[n].core), "mp-affinity",
133                                 (bc->clusterid << 8) | n, &error_abort);
134 
135         /* set periphbase/CBAR value for CPU-local registers */
136         object_property_set_int(OBJECT(&s_base->cpu[n].core), "reset-cbar",
137                                 bc->peri_base, &error_abort);
138 
139         /* start powered off if not enabled */
140         object_property_set_bool(OBJECT(&s_base->cpu[n].core),
141                                  "start-powered-off",
142                                  n >= s_base->enabled_cpus, &error_abort);
143 
144         if (!qdev_realize(DEVICE(&s_base->cpu[n].core), NULL, errp)) {
145             return;
146         }
147 
148         /* Connect irq/fiq outputs from the interrupt controller. */
149         qdev_connect_gpio_out_named(DEVICE(&s_base->control), "irq", n,
150             qdev_get_gpio_in(DEVICE(&s_base->cpu[n].core), ARM_CPU_IRQ));
151         qdev_connect_gpio_out_named(DEVICE(&s_base->control), "fiq", n,
152             qdev_get_gpio_in(DEVICE(&s_base->cpu[n].core), ARM_CPU_FIQ));
153 
154         /* Connect timers from the CPU to the interrupt controller */
155         qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_PHYS,
156             qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntpnsirq", n));
157         qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_VIRT,
158             qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntvirq", n));
159         qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_HYP,
160             qdev_get_gpio_in_named(DEVICE(&s_base->control), "cnthpirq", n));
161         qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_SEC,
162             qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntpsirq", n));
163     }
164 }
165 
166 static void bcm283x_base_class_init(ObjectClass *oc, void *data)
167 {
168     DeviceClass *dc = DEVICE_CLASS(oc);
169 
170     /* Reason: Must be wired up in code (see raspi_init() function) */
171     dc->user_creatable = false;
172 }
173 
174 static void bcm2835_class_init(ObjectClass *oc, void *data)
175 {
176     DeviceClass *dc = DEVICE_CLASS(oc);
177     BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
178 
179     bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
180     bc->core_count = 1;
181     bc->peri_base = 0x20000000;
182     dc->realize = bcm2835_realize;
183 };
184 
185 static void bcm2836_class_init(ObjectClass *oc, void *data)
186 {
187     DeviceClass *dc = DEVICE_CLASS(oc);
188     BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
189 
190     bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
191     bc->core_count = BCM283X_NCPUS;
192     bc->peri_base = 0x3f000000;
193     bc->ctrl_base = 0x40000000;
194     bc->clusterid = 0xf;
195     dc->realize = bcm2836_realize;
196 };
197 
198 #ifdef TARGET_AARCH64
199 static void bcm2837_class_init(ObjectClass *oc, void *data)
200 {
201     DeviceClass *dc = DEVICE_CLASS(oc);
202     BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
203 
204     bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
205     bc->core_count = BCM283X_NCPUS;
206     bc->peri_base = 0x3f000000;
207     bc->ctrl_base = 0x40000000;
208     bc->clusterid = 0x0;
209     dc->realize = bcm2836_realize;
210 };
211 #endif
212 
213 static const TypeInfo bcm283x_types[] = {
214     {
215         .name           = TYPE_BCM2835,
216         .parent         = TYPE_BCM283X,
217         .class_init     = bcm2835_class_init,
218     }, {
219         .name           = TYPE_BCM2836,
220         .parent         = TYPE_BCM283X,
221         .class_init     = bcm2836_class_init,
222 #ifdef TARGET_AARCH64
223     }, {
224         .name           = TYPE_BCM2837,
225         .parent         = TYPE_BCM283X,
226         .class_init     = bcm2837_class_init,
227 #endif
228     }, {
229         .name           = TYPE_BCM283X,
230         .parent         = TYPE_BCM283X_BASE,
231         .instance_size  = sizeof(BCM283XState),
232         .instance_init  = bcm283x_init,
233         .abstract       = true,
234     }, {
235         .name           = TYPE_BCM283X_BASE,
236         .parent         = TYPE_DEVICE,
237         .instance_size  = sizeof(BCM283XBaseState),
238         .instance_init  = bcm283x_base_init,
239         .class_size     = sizeof(BCM283XBaseClass),
240         .class_init     = bcm283x_base_class_init,
241         .abstract       = true,
242     }
243 };
244 
245 DEFINE_TYPES(bcm283x_types)
246