1 #include "hw/arm/bcm2835_peripherals.h"
2 #include "hw/arm/bcm2835_common.h"
3 #include "hw/arm/raspi_platform.h"
4 #include "exec/address-spaces.h"
7 MemoryRegion
*bcm2835_peripheral_mr
;
8 AddressSpace
*bcm2835_peripheral_as
;
10 static void bcm2835_peripherals_init(Object
*obj
)
12 BCM2835PeripheralState
*s
= BCM2835_PERIPHERALS(obj
);
15 /* We track two memory regions. One, for the peripheral devices
16 * themselves, which we export to our parent soc device, and
17 * one for the bus addresses used by the peripherals, which is
18 * used internally. The latter requires an alias. */
19 memory_region_init_io(&s
->peri_mr
, OBJECT(s
), NULL
, s
,
20 "bcm2835_peripherals", 0x1000000);
21 sysbus_init_mmio(SYS_BUS_DEVICE(s
), &s
->peri_mr
);
23 memory_region_init_io(&s
->gpu_bus_mr
, OBJECT(s
), NULL
, s
, "bcm2835_gpu_bus",
26 address_space_init(&s
->gpu_bus_as
, &s
->gpu_bus_mr
, "bcm2835_gpu_bus");
27 bcm2835_peripheral_mr
= &s
->gpu_bus_mr
; // XXX
28 bcm2835_peripheral_as
= &s
->gpu_bus_as
; // XXX
30 /* Interrupt Controller */
31 s
->ic
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_ic"));
32 object_property_add_child(obj
, "ic", OBJECT(dev
), NULL
);
33 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
36 s
->uart0
= dev
= SYS_BUS_DEVICE(object_new("pl011"));
37 object_property_add_child(obj
, "uart0", OBJECT(dev
), NULL
);
38 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
41 s
->uart1
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_aux"));
42 object_property_add_child(obj
, "uart1", OBJECT(dev
), NULL
);
43 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
46 s
->systimer
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_st"));
47 object_property_add_child(obj
, "systimer", OBJECT(dev
), NULL
);
48 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
51 s
->armtimer
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_timer"));
52 object_property_add_child(obj
, "armtimer", OBJECT(dev
), NULL
);
53 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
56 s
->usb
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_usb"));
57 object_property_add_child(obj
, "usb", OBJECT(dev
), NULL
);
58 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
60 /* MPHI - Message-based Parallel Host Interface */
61 s
->mphi
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_mphi"));
62 object_property_add_child(obj
, "mphi", OBJECT(dev
), NULL
);
63 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
65 /* Semaphores / Doorbells / Mailboxes */
66 s
->sbm
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_sbm"));
67 object_property_add_child(obj
, "sbm", OBJECT(dev
), NULL
);
68 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
70 /* Power management */
71 s
->power
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_power"));
72 object_property_add_child(obj
, "power", OBJECT(dev
), NULL
);
73 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
76 s
->fb
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_fb"));
77 object_property_add_child(obj
, "fb", OBJECT(dev
), NULL
);
78 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
80 /* Property channel */
81 s
->property
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_property"));
82 object_property_add_child(obj
, "property", OBJECT(dev
), NULL
);
83 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
86 s
->vchiq
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_vchiq"));
87 object_property_add_child(obj
, "vchiq", OBJECT(dev
), NULL
);
88 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
90 /* Extended Mass Media Controller */
91 s
->emmc
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_emmc"));
92 object_property_add_child(obj
, "emmc", OBJECT(dev
), NULL
);
93 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
96 s
->dma
= dev
= SYS_BUS_DEVICE(object_new("bcm2835_dma"));
97 object_property_add_child(obj
, "dma", OBJECT(dev
), NULL
);
98 qdev_set_parent_bus(DEVICE(dev
), sysbus_get_default());
101 static void bcm2835_peripherals_realize(DeviceState
*dev
, Error
**errp
)
103 BCM2835PeripheralState
*s
= BCM2835_PERIPHERALS(dev
);
106 qemu_irq mbox_irq
[MBOX_CHAN_COUNT
];
111 /* Interrupt Controller */
112 object_property_set_bool(OBJECT(s
->ic
), true, "realized", &err
);
114 error_propagate(errp
, err
);
118 memory_region_add_subregion(&s
->peri_mr
, ARMCTRL_IC_OFFSET
,
119 sysbus_mmio_get_region(s
->ic
, 0));
120 sysbus_pass_irq(SYS_BUS_DEVICE(s
), s
->ic
);
122 for (n
= 0; n
< 72; n
++) {
123 pic
[n
] = qdev_get_gpio_in(DEVICE(s
->ic
), n
);
127 object_property_set_bool(OBJECT(s
->uart0
), true, "realized", &err
);
129 error_propagate(errp
, err
);
133 memory_region_add_subregion(&s
->peri_mr
, UART0_OFFSET
,
134 sysbus_mmio_get_region(s
->uart0
, 0));
135 sysbus_connect_irq(s
->uart0
, 0, pic
[INTERRUPT_VC_UART
]);
138 object_property_set_bool(OBJECT(s
->uart1
), true, "realized", &err
);
140 error_propagate(errp
, err
);
144 memory_region_add_subregion(&s
->peri_mr
, UART1_OFFSET
,
145 sysbus_mmio_get_region(s
->uart1
, 0));
146 sysbus_connect_irq(s
->uart1
, 0, pic
[INTERRUPT_AUX
]);
149 object_property_set_bool(OBJECT(s
->systimer
), true, "realized", &err
);
151 error_propagate(errp
, err
);
155 memory_region_add_subregion(&s
->peri_mr
, ST_OFFSET
,
156 sysbus_mmio_get_region(s
->systimer
, 0));
157 sysbus_connect_irq(s
->systimer
, 0, pic
[INTERRUPT_TIMER0
]);
158 sysbus_connect_irq(s
->systimer
, 1, pic
[INTERRUPT_TIMER1
]);
159 sysbus_connect_irq(s
->systimer
, 2, pic
[INTERRUPT_TIMER2
]);
160 sysbus_connect_irq(s
->systimer
, 3, pic
[INTERRUPT_TIMER3
]);
163 object_property_set_bool(OBJECT(s
->armtimer
), true, "realized", &err
);
165 error_propagate(errp
, err
);
169 memory_region_add_subregion(&s
->peri_mr
, ARMCTRL_TIMER0_1_OFFSET
,
170 sysbus_mmio_get_region(s
->armtimer
, 0));
171 sysbus_connect_irq(s
->armtimer
, 0, pic
[INTERRUPT_ARM_TIMER
]);
174 object_property_set_bool(OBJECT(s
->usb
), true, "realized", &err
);
176 error_propagate(errp
, err
);
180 memory_region_add_subregion(&s
->peri_mr
, USB_OFFSET
,
181 sysbus_mmio_get_region(s
->usb
, 0));
182 sysbus_connect_irq(s
->usb
, 0, pic
[INTERRUPT_VC_USB
]);
184 /* MPHI - Message-based Parallel Host Interface */
185 object_property_set_bool(OBJECT(s
->mphi
), true, "realized", &err
);
187 error_propagate(errp
, err
);
191 memory_region_add_subregion(&s
->peri_mr
, MPHI_OFFSET
,
192 sysbus_mmio_get_region(s
->mphi
, 0));
193 sysbus_connect_irq(s
->mphi
, 0, pic
[INTERRUPT_HOSTPORT
]);
195 /* Semaphores / Doorbells / Mailboxes */
196 object_property_set_bool(OBJECT(s
->sbm
), true, "realized", &err
);
198 error_propagate(errp
, err
);
202 memory_region_add_subregion(&s
->peri_mr
, ARMCTRL_0_SBM_OFFSET
,
203 sysbus_mmio_get_region(s
->sbm
, 0));
204 sysbus_connect_irq(s
->sbm
, 0, pic
[INTERRUPT_ARM_MAILBOX
]);
206 for (n
= 0; n
< MBOX_CHAN_COUNT
; n
++) {
207 mbox_irq
[n
] = qdev_get_gpio_in(DEVICE(s
->sbm
), n
);
210 /* Mailbox-addressable peripherals using (hopefully) free address space
211 * locations and pseudo-irqs to dispatch mailbox requests and responses
214 tmpoffset
= ARMCTRL_0_SBM_OFFSET
+ 0x400;
216 /* Power management */
217 object_property_set_bool(OBJECT(s
->power
), true, "realized", &err
);
219 error_propagate(errp
, err
);
223 memory_region_add_subregion(&s
->peri_mr
, tmpoffset
+ (MBOX_CHAN_POWER
<<4),
224 sysbus_mmio_get_region(s
->power
, 0));
225 sysbus_connect_irq(s
->power
, 0, mbox_irq
[MBOX_CHAN_POWER
]);
228 object_property_set_bool(OBJECT(s
->fb
), true, "realized", &err
);
230 error_propagate(errp
, err
);
234 memory_region_add_subregion(&s
->peri_mr
, tmpoffset
+ (MBOX_CHAN_FB
<<4),
235 sysbus_mmio_get_region(s
->fb
, 0));
236 sysbus_connect_irq(s
->fb
, 0, mbox_irq
[MBOX_CHAN_FB
]);
238 /* Property channel */
239 object_property_set_bool(OBJECT(s
->property
), true, "realized", &err
);
241 error_propagate(errp
, err
);
245 memory_region_add_subregion(&s
->peri_mr
, tmpoffset
+ (MBOX_CHAN_PROPERTY
<<4),
246 sysbus_mmio_get_region(s
->property
, 0));
247 sysbus_connect_irq(s
->property
, 0, mbox_irq
[MBOX_CHAN_PROPERTY
]);
250 object_property_set_bool(OBJECT(s
->vchiq
), true, "realized", &err
);
252 error_propagate(errp
, err
);
256 memory_region_add_subregion(&s
->peri_mr
, tmpoffset
+ (MBOX_CHAN_VCHIQ
<<4),
257 sysbus_mmio_get_region(s
->vchiq
, 0));
258 sysbus_connect_irq(s
->vchiq
, 0, mbox_irq
[MBOX_CHAN_VCHIQ
]);
260 /* Extended Mass Media Controller */
261 object_property_set_bool(OBJECT(s
->emmc
), true, "realized", &err
);
263 error_propagate(errp
, err
);
267 memory_region_add_subregion(&s
->peri_mr
, EMMC_OFFSET
,
268 sysbus_mmio_get_region(s
->emmc
, 0));
269 sysbus_connect_irq(s
->emmc
, 0, pic
[INTERRUPT_VC_ARASANSDIO
]);
272 object_property_set_bool(OBJECT(s
->dma
), true, "realized", &err
);
274 error_propagate(errp
, err
);
278 memory_region_add_subregion(&s
->peri_mr
, DMA_OFFSET
,
279 sysbus_mmio_get_region(s
->dma
, 0));
280 memory_region_add_subregion(&s
->peri_mr
, 0xe05000, // XXX
281 sysbus_mmio_get_region(s
->dma
, 1));
283 sysbus_connect_irq(s
->dma
, 0, pic
[INTERRUPT_DMA0
]);
284 sysbus_connect_irq(s
->dma
, 1, pic
[INTERRUPT_DMA1
]);
285 sysbus_connect_irq(s
->dma
, 2, pic
[INTERRUPT_VC_DMA2
]);
286 sysbus_connect_irq(s
->dma
, 3, pic
[INTERRUPT_VC_DMA3
]);
287 sysbus_connect_irq(s
->dma
, 4, pic
[INTERRUPT_DMA4
]);
288 sysbus_connect_irq(s
->dma
, 5, pic
[INTERRUPT_DMA5
]);
289 sysbus_connect_irq(s
->dma
, 6, pic
[INTERRUPT_DMA6
]);
290 sysbus_connect_irq(s
->dma
, 7, pic
[INTERRUPT_DMA7
]);
291 sysbus_connect_irq(s
->dma
, 8, pic
[INTERRUPT_DMA8
]);
292 sysbus_connect_irq(s
->dma
, 9, pic
[INTERRUPT_DMA9
]);
293 sysbus_connect_irq(s
->dma
, 10, pic
[INTERRUPT_DMA10
]);
294 sysbus_connect_irq(s
->dma
, 11, pic
[INTERRUPT_DMA11
]);
295 sysbus_connect_irq(s
->dma
, 12, pic
[INTERRUPT_DMA12
]);
297 /* Map peripherals and RAM into the GPU address space. */
298 memory_region_init_alias(&s
->peri_mr_alias
, OBJECT(s
),
299 "bcm2835_peripherals", &s
->peri_mr
, 0,
300 memory_region_size(&s
->peri_mr
));
302 memory_region_add_subregion_overlap(&s
->gpu_bus_mr
, BCM2835_VC_PERI_BASE
,
303 &s
->peri_mr_alias
, 1);
305 /* XXX: assume that RAM is contiguous and mapped at system address zero */
306 ram
= memory_region_find(get_system_memory(), 0, 1).mr
;
307 assert(ram
!= NULL
&& memory_region_size(ram
) >= 128 * 1024 * 1024);
309 /* RAM is aliased four times (different cache configurations) on the GPU */
310 for (n
= 0; n
< 4; n
++) {
311 memory_region_init_alias(&s
->ram_alias
[n
], OBJECT(s
),
312 "bcm2835_gpu_ram_alias[*]", ram
, 0,
313 memory_region_size(ram
));
314 memory_region_add_subregion_overlap(&s
->gpu_bus_mr
, (hwaddr
)n
<< 30,
315 &s
->ram_alias
[n
], 0);
319 static void bcm2835_peripherals_class_init(ObjectClass
*oc
, void *data
)
321 DeviceClass
*dc
= DEVICE_CLASS(oc
);
323 dc
->realize
= bcm2835_peripherals_realize
;
326 static const TypeInfo bcm2835_peripherals_type_info
= {
327 .name
= TYPE_BCM2835_PERIPHERALS
,
328 .parent
= TYPE_SYS_BUS_DEVICE
,
329 .instance_size
= sizeof(BCM2835PeripheralState
),
330 .instance_init
= bcm2835_peripherals_init
,
331 .class_init
= bcm2835_peripherals_class_init
,
334 static void bcm2835_peripherals_register_types(void)
336 type_register_static(&bcm2835_peripherals_type_info
);
339 type_init(bcm2835_peripherals_register_types
)