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