]>
Commit | Line | Data |
---|---|---|
bad56236 AB |
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 | ||
c964b660 | 11 | #include "qemu/osdep.h" |
da34e65c | 12 | #include "qapi/error.h" |
4771d756 PB |
13 | #include "qemu-common.h" |
14 | #include "cpu.h" | |
bad56236 AB |
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 | static void bcm2836_init(Object *obj) | |
27 | { | |
28 | BCM2836State *s = BCM2836(obj); | |
29 | int n; | |
30 | ||
31 | for (n = 0; n < BCM2836_NCPUS; n++) { | |
32 | object_initialize(&s->cpus[n], sizeof(s->cpus[n]), | |
33 | "cortex-a15-" TYPE_ARM_CPU); | |
34 | object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]), | |
35 | &error_abort); | |
36 | } | |
37 | ||
38 | object_initialize(&s->control, sizeof(s->control), TYPE_BCM2836_CONTROL); | |
39 | object_property_add_child(obj, "control", OBJECT(&s->control), NULL); | |
40 | qdev_set_parent_bus(DEVICE(&s->control), sysbus_get_default()); | |
41 | ||
42 | object_initialize(&s->peripherals, sizeof(s->peripherals), | |
43 | TYPE_BCM2835_PERIPHERALS); | |
44 | object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals), | |
45 | &error_abort); | |
f0afa731 SW |
46 | object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), |
47 | "board-rev", &error_abort); | |
5e9c2a8d GE |
48 | object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), |
49 | "vcram-size", &error_abort); | |
bad56236 AB |
50 | qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default()); |
51 | } | |
52 | ||
53 | static void bcm2836_realize(DeviceState *dev, Error **errp) | |
54 | { | |
55 | BCM2836State *s = BCM2836(dev); | |
56 | Object *obj; | |
57 | Error *err = NULL; | |
58 | int n; | |
59 | ||
60 | /* common peripherals from bcm2835 */ | |
61 | ||
62 | obj = object_property_get_link(OBJECT(dev), "ram", &err); | |
63 | if (obj == NULL) { | |
64 | error_setg(errp, "%s: required ram link not found: %s", | |
65 | __func__, error_get_pretty(err)); | |
66 | return; | |
67 | } | |
68 | ||
69 | object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err); | |
70 | if (err) { | |
71 | error_propagate(errp, err); | |
72 | return; | |
73 | } | |
74 | ||
75 | object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err); | |
76 | if (err) { | |
77 | error_propagate(errp, err); | |
78 | return; | |
79 | } | |
80 | ||
a55b53a2 AB |
81 | object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals), |
82 | "sd-bus", &err); | |
83 | if (err) { | |
84 | error_propagate(errp, err); | |
85 | return; | |
86 | } | |
87 | ||
bad56236 AB |
88 | sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0, |
89 | BCM2836_PERI_BASE, 1); | |
90 | ||
91 | /* bcm2836 interrupt controller (and mailboxes, etc.) */ | |
92 | object_property_set_bool(OBJECT(&s->control), true, "realized", &err); | |
93 | if (err) { | |
94 | error_propagate(errp, err); | |
95 | return; | |
96 | } | |
97 | ||
98 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE); | |
99 | ||
100 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0, | |
101 | qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0)); | |
102 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1, | |
103 | qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0)); | |
104 | ||
105 | for (n = 0; n < BCM2836_NCPUS; n++) { | |
106 | /* Mirror bcm2836, which has clusterid set to 0xf | |
107 | * TODO: this should be converted to a property of ARM_CPU | |
108 | */ | |
109 | s->cpus[n].mp_affinity = 0xF00 | n; | |
110 | ||
111 | /* set periphbase/CBAR value for CPU-local registers */ | |
112 | object_property_set_int(OBJECT(&s->cpus[n]), | |
113 | BCM2836_PERI_BASE + MCORE_OFFSET, | |
114 | "reset-cbar", &err); | |
115 | if (err) { | |
116 | error_propagate(errp, err); | |
117 | return; | |
118 | } | |
119 | ||
120 | /* start powered off if not enabled */ | |
121 | object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus, | |
122 | "start-powered-off", &err); | |
123 | if (err) { | |
124 | error_propagate(errp, err); | |
125 | return; | |
126 | } | |
127 | ||
128 | object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err); | |
129 | if (err) { | |
130 | error_propagate(errp, err); | |
131 | return; | |
132 | } | |
133 | ||
134 | /* Connect irq/fiq outputs from the interrupt controller. */ | |
135 | qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n, | |
136 | qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ)); | |
137 | qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n, | |
138 | qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ)); | |
139 | ||
140 | /* Connect timers from the CPU to the interrupt controller */ | |
141 | qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS, | |
0dc19823 | 142 | qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n)); |
bad56236 AB |
143 | qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT, |
144 | qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n)); | |
0dc19823 PM |
145 | qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP, |
146 | qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n)); | |
147 | qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC, | |
148 | qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n)); | |
bad56236 AB |
149 | } |
150 | } | |
151 | ||
152 | static Property bcm2836_props[] = { | |
153 | DEFINE_PROP_UINT32("enabled-cpus", BCM2836State, enabled_cpus, BCM2836_NCPUS), | |
154 | DEFINE_PROP_END_OF_LIST() | |
155 | }; | |
156 | ||
157 | static void bcm2836_class_init(ObjectClass *oc, void *data) | |
158 | { | |
159 | DeviceClass *dc = DEVICE_CLASS(oc); | |
160 | ||
161 | dc->props = bcm2836_props; | |
162 | dc->realize = bcm2836_realize; | |
163 | ||
164 | /* | |
165 | * Reason: creates an ARM CPU, thus use after free(), see | |
166 | * arm_cpu_class_init() | |
167 | */ | |
168 | dc->cannot_destroy_with_object_finalize_yet = true; | |
169 | } | |
170 | ||
171 | static const TypeInfo bcm2836_type_info = { | |
172 | .name = TYPE_BCM2836, | |
173 | .parent = TYPE_SYS_BUS_DEVICE, | |
174 | .instance_size = sizeof(BCM2836State), | |
175 | .instance_init = bcm2836_init, | |
176 | .class_init = bcm2836_class_init, | |
177 | }; | |
178 | ||
179 | static void bcm2836_register_types(void) | |
180 | { | |
181 | type_register_static(&bcm2836_type_info); | |
182 | } | |
183 | ||
184 | type_init(bcm2836_register_types) |