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/module.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 | |