2 * Rasperry Pi 2 emulation ARM control logic module.
3 * Copyright (c) 2015, Microsoft
4 * Written by Andrew Baumann
6 * Based on bcm2835_ic.c (Raspberry Pi emulation) (c) 2012 Gregory Estrade
8 * At present, only implements interrupt routing, and mailboxes (i.e.,
9 * not PMU interrupt, or AXI counters).
11 * ARM Local Timer IRQ Copyright (c) 2019. Zoltán Baldaszti
14 * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
16 * This work is licensed under the terms of the GNU GPL, version 2 or later.
17 * See the COPYING file in the top-level directory.
20 #include "qemu/osdep.h"
21 #include "hw/intc/bcm2836_control.h"
23 #include "migration/vmstate.h"
25 #include "qemu/module.h"
27 #define REG_GPU_ROUTE 0x0c
28 #define REG_LOCALTIMERROUTING 0x24
29 #define REG_LOCALTIMERCONTROL 0x34
30 #define REG_LOCALTIMERACK 0x38
31 #define REG_TIMERCONTROL 0x40
32 #define REG_MBOXCONTROL 0x50
33 #define REG_IRQSRC 0x60
34 #define REG_FIQSRC 0x70
35 #define REG_MBOX0_WR 0x80
36 #define REG_MBOX0_RDCLR 0xc0
37 #define REG_LIMIT 0x100
39 #define IRQ_BIT(cntrl, num) (((cntrl) & (1 << (num))) != 0)
40 #define FIQ_BIT(cntrl, num) (((cntrl) & (1 << ((num) + 4))) != 0)
42 #define IRQ_CNTPSIRQ 0
43 #define IRQ_CNTPNSIRQ 1
44 #define IRQ_CNTHPIRQ 2
46 #define IRQ_MAILBOX0 4
47 #define IRQ_MAILBOX1 5
48 #define IRQ_MAILBOX2 6
49 #define IRQ_MAILBOX3 7
54 #define IRQ_MAX IRQ_TIMER
56 #define LOCALTIMER_FREQ 38400000
57 #define LOCALTIMER_INTFLAG (1 << 31)
58 #define LOCALTIMER_RELOAD (1 << 30)
59 #define LOCALTIMER_INTENABLE (1 << 29)
60 #define LOCALTIMER_ENABLE (1 << 28)
61 #define LOCALTIMER_VALUE(x) ((x) & 0xfffffff)
63 static void deliver_local(BCM2836ControlState
*s
, uint8_t core
, uint8_t irq
,
64 uint32_t controlreg
, uint8_t controlidx
)
66 if (FIQ_BIT(controlreg
, controlidx
)) {
68 s
->fiqsrc
[core
] |= (uint32_t)1 << irq
;
69 } else if (IRQ_BIT(controlreg
, controlidx
)) {
71 s
->irqsrc
[core
] |= (uint32_t)1 << irq
;
73 /* the interrupt is masked */
77 /* Update interrupts. */
78 static void bcm2836_control_update(BCM2836ControlState
*s
)
82 /* reset pending IRQs/FIQs */
83 for (i
= 0; i
< BCM2836_NCORES
; i
++) {
84 s
->irqsrc
[i
] = s
->fiqsrc
[i
] = 0;
87 /* apply routing logic, update status regs */
89 assert(s
->route_gpu_irq
< BCM2836_NCORES
);
90 s
->irqsrc
[s
->route_gpu_irq
] |= (uint32_t)1 << IRQ_GPU
;
94 assert(s
->route_gpu_fiq
< BCM2836_NCORES
);
95 s
->fiqsrc
[s
->route_gpu_fiq
] |= (uint32_t)1 << IRQ_GPU
;
99 * handle the control module 'local timer' interrupt for one of the
100 * cores' IRQ/FIQ; this is distinct from the per-CPU timer
101 * interrupts handled below.
103 if ((s
->local_timer_control
& LOCALTIMER_INTENABLE
) &&
104 (s
->local_timer_control
& LOCALTIMER_INTFLAG
)) {
105 if (s
->route_localtimer
& 4) {
106 s
->fiqsrc
[(s
->route_localtimer
& 3)] |= (uint32_t)1 << IRQ_TIMER
;
108 s
->irqsrc
[(s
->route_localtimer
& 3)] |= (uint32_t)1 << IRQ_TIMER
;
112 for (i
= 0; i
< BCM2836_NCORES
; i
++) {
113 /* handle local timer interrupts for this core */
114 if (s
->timerirqs
[i
]) {
115 assert(s
->timerirqs
[i
] < (1 << (IRQ_CNTVIRQ
+ 1))); /* sane mask? */
116 for (j
= 0; j
<= IRQ_CNTVIRQ
; j
++) {
117 if ((s
->timerirqs
[i
] & (1 << j
)) != 0) {
118 /* local interrupt j is set */
119 deliver_local(s
, i
, j
, s
->timercontrol
[i
], j
);
124 /* handle mailboxes for this core */
125 for (j
= 0; j
< BCM2836_MBPERCORE
; j
++) {
126 if (s
->mailboxes
[i
* BCM2836_MBPERCORE
+ j
] != 0) {
127 /* mailbox j is set */
128 deliver_local(s
, i
, j
+ IRQ_MAILBOX0
, s
->mailboxcontrol
[i
], j
);
133 /* call set_irq appropriately for each output */
134 for (i
= 0; i
< BCM2836_NCORES
; i
++) {
135 qemu_set_irq(s
->irq
[i
], s
->irqsrc
[i
] != 0);
136 qemu_set_irq(s
->fiq
[i
], s
->fiqsrc
[i
] != 0);
140 static void bcm2836_control_set_local_irq(void *opaque
, int core
, int local_irq
,
143 BCM2836ControlState
*s
= opaque
;
145 assert(core
>= 0 && core
< BCM2836_NCORES
);
146 assert(local_irq
>= 0 && local_irq
<= IRQ_CNTVIRQ
);
148 s
->timerirqs
[core
] = deposit32(s
->timerirqs
[core
], local_irq
, 1, !!level
);
150 bcm2836_control_update(s
);
153 /* XXX: the following wrapper functions are a kludgy workaround,
154 * needed because I can't seem to pass useful information in the "irq"
155 * parameter when using named interrupts. Feel free to clean this up!
158 static void bcm2836_control_set_local_irq0(void *opaque
, int core
, int level
)
160 bcm2836_control_set_local_irq(opaque
, core
, IRQ_CNTPSIRQ
, level
);
163 static void bcm2836_control_set_local_irq1(void *opaque
, int core
, int level
)
165 bcm2836_control_set_local_irq(opaque
, core
, IRQ_CNTPNSIRQ
, level
);
168 static void bcm2836_control_set_local_irq2(void *opaque
, int core
, int level
)
170 bcm2836_control_set_local_irq(opaque
, core
, IRQ_CNTHPIRQ
, level
);
173 static void bcm2836_control_set_local_irq3(void *opaque
, int core
, int level
)
175 bcm2836_control_set_local_irq(opaque
, core
, IRQ_CNTVIRQ
, level
);
178 static void bcm2836_control_set_gpu_irq(void *opaque
, int irq
, int level
)
180 BCM2836ControlState
*s
= opaque
;
184 bcm2836_control_update(s
);
187 static void bcm2836_control_set_gpu_fiq(void *opaque
, int irq
, int level
)
189 BCM2836ControlState
*s
= opaque
;
193 bcm2836_control_update(s
);
196 static void bcm2836_control_local_timer_set_next(void *opaque
)
198 BCM2836ControlState
*s
= opaque
;
201 assert(LOCALTIMER_VALUE(s
->local_timer_control
) > 0);
203 next_event
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) +
204 muldiv64(LOCALTIMER_VALUE(s
->local_timer_control
),
205 NANOSECONDS_PER_SECOND
, LOCALTIMER_FREQ
);
206 timer_mod(&s
->timer
, next_event
);
209 static void bcm2836_control_local_timer_tick(void *opaque
)
211 BCM2836ControlState
*s
= opaque
;
213 bcm2836_control_local_timer_set_next(s
);
215 s
->local_timer_control
|= LOCALTIMER_INTFLAG
;
216 bcm2836_control_update(s
);
219 static void bcm2836_control_local_timer_control(void *opaque
, uint32_t val
)
221 BCM2836ControlState
*s
= opaque
;
223 s
->local_timer_control
= val
;
224 if (val
& LOCALTIMER_ENABLE
) {
225 bcm2836_control_local_timer_set_next(s
);
227 timer_del(&s
->timer
);
231 static void bcm2836_control_local_timer_ack(void *opaque
, uint32_t val
)
233 BCM2836ControlState
*s
= opaque
;
235 if (val
& LOCALTIMER_INTFLAG
) {
236 s
->local_timer_control
&= ~LOCALTIMER_INTFLAG
;
238 if ((val
& LOCALTIMER_RELOAD
) &&
239 (s
->local_timer_control
& LOCALTIMER_ENABLE
)) {
240 bcm2836_control_local_timer_set_next(s
);
244 static uint64_t bcm2836_control_read(void *opaque
, hwaddr offset
, unsigned size
)
246 BCM2836ControlState
*s
= opaque
;
248 if (offset
== REG_GPU_ROUTE
) {
249 assert(s
->route_gpu_fiq
< BCM2836_NCORES
250 && s
->route_gpu_irq
< BCM2836_NCORES
);
251 return ((uint32_t)s
->route_gpu_fiq
<< 2) | s
->route_gpu_irq
;
252 } else if (offset
== REG_LOCALTIMERROUTING
) {
253 return s
->route_localtimer
;
254 } else if (offset
== REG_LOCALTIMERCONTROL
) {
255 return s
->local_timer_control
;
256 } else if (offset
== REG_LOCALTIMERACK
) {
258 } else if (offset
>= REG_TIMERCONTROL
&& offset
< REG_MBOXCONTROL
) {
259 return s
->timercontrol
[(offset
- REG_TIMERCONTROL
) >> 2];
260 } else if (offset
>= REG_MBOXCONTROL
&& offset
< REG_IRQSRC
) {
261 return s
->mailboxcontrol
[(offset
- REG_MBOXCONTROL
) >> 2];
262 } else if (offset
>= REG_IRQSRC
&& offset
< REG_FIQSRC
) {
263 return s
->irqsrc
[(offset
- REG_IRQSRC
) >> 2];
264 } else if (offset
>= REG_FIQSRC
&& offset
< REG_MBOX0_WR
) {
265 return s
->fiqsrc
[(offset
- REG_FIQSRC
) >> 2];
266 } else if (offset
>= REG_MBOX0_RDCLR
&& offset
< REG_LIMIT
) {
267 return s
->mailboxes
[(offset
- REG_MBOX0_RDCLR
) >> 2];
269 qemu_log_mask(LOG_UNIMP
, "%s: Unsupported offset 0x%"HWADDR_PRIx
"\n",
275 static void bcm2836_control_write(void *opaque
, hwaddr offset
,
276 uint64_t val
, unsigned size
)
278 BCM2836ControlState
*s
= opaque
;
280 if (offset
== REG_GPU_ROUTE
) {
281 s
->route_gpu_irq
= val
& 0x3;
282 s
->route_gpu_fiq
= (val
>> 2) & 0x3;
283 } else if (offset
== REG_LOCALTIMERROUTING
) {
284 s
->route_localtimer
= val
& 7;
285 } else if (offset
== REG_LOCALTIMERCONTROL
) {
286 bcm2836_control_local_timer_control(s
, val
);
287 } else if (offset
== REG_LOCALTIMERACK
) {
288 bcm2836_control_local_timer_ack(s
, val
);
289 } else if (offset
>= REG_TIMERCONTROL
&& offset
< REG_MBOXCONTROL
) {
290 s
->timercontrol
[(offset
- REG_TIMERCONTROL
) >> 2] = val
& 0xff;
291 } else if (offset
>= REG_MBOXCONTROL
&& offset
< REG_IRQSRC
) {
292 s
->mailboxcontrol
[(offset
- REG_MBOXCONTROL
) >> 2] = val
& 0xff;
293 } else if (offset
>= REG_MBOX0_WR
&& offset
< REG_MBOX0_RDCLR
) {
294 s
->mailboxes
[(offset
- REG_MBOX0_WR
) >> 2] |= val
;
295 } else if (offset
>= REG_MBOX0_RDCLR
&& offset
< REG_LIMIT
) {
296 s
->mailboxes
[(offset
- REG_MBOX0_RDCLR
) >> 2] &= ~val
;
298 qemu_log_mask(LOG_UNIMP
, "%s: Unsupported offset 0x%"HWADDR_PRIx
299 " value 0x%"PRIx64
"\n",
300 __func__
, offset
, val
);
304 bcm2836_control_update(s
);
307 static const MemoryRegionOps bcm2836_control_ops
= {
308 .read
= bcm2836_control_read
,
309 .write
= bcm2836_control_write
,
310 .endianness
= DEVICE_NATIVE_ENDIAN
,
311 .valid
.min_access_size
= 4,
312 .valid
.max_access_size
= 4,
315 static void bcm2836_control_reset(DeviceState
*d
)
317 BCM2836ControlState
*s
= BCM2836_CONTROL(d
);
320 s
->route_gpu_irq
= s
->route_gpu_fiq
= 0;
322 timer_del(&s
->timer
);
323 s
->route_localtimer
= 0;
324 s
->local_timer_control
= 0;
326 for (i
= 0; i
< BCM2836_NCORES
; i
++) {
327 s
->timercontrol
[i
] = 0;
328 s
->mailboxcontrol
[i
] = 0;
331 for (i
= 0; i
< BCM2836_NCORES
* BCM2836_MBPERCORE
; i
++) {
336 static void bcm2836_control_init(Object
*obj
)
338 BCM2836ControlState
*s
= BCM2836_CONTROL(obj
);
339 DeviceState
*dev
= DEVICE(obj
);
341 memory_region_init_io(&s
->iomem
, obj
, &bcm2836_control_ops
, s
,
342 TYPE_BCM2836_CONTROL
, REG_LIMIT
);
343 sysbus_init_mmio(SYS_BUS_DEVICE(s
), &s
->iomem
);
345 /* inputs from each CPU core */
346 qdev_init_gpio_in_named(dev
, bcm2836_control_set_local_irq0
, "cntpsirq",
348 qdev_init_gpio_in_named(dev
, bcm2836_control_set_local_irq1
, "cntpnsirq",
350 qdev_init_gpio_in_named(dev
, bcm2836_control_set_local_irq2
, "cnthpirq",
352 qdev_init_gpio_in_named(dev
, bcm2836_control_set_local_irq3
, "cntvirq",
355 /* IRQ and FIQ inputs from upstream bcm2835 controller */
356 qdev_init_gpio_in_named(dev
, bcm2836_control_set_gpu_irq
, "gpu-irq", 1);
357 qdev_init_gpio_in_named(dev
, bcm2836_control_set_gpu_fiq
, "gpu-fiq", 1);
359 /* outputs to CPU cores */
360 qdev_init_gpio_out_named(dev
, s
->irq
, "irq", BCM2836_NCORES
);
361 qdev_init_gpio_out_named(dev
, s
->fiq
, "fiq", BCM2836_NCORES
);
363 /* create a qemu virtual timer */
364 timer_init_ns(&s
->timer
, QEMU_CLOCK_VIRTUAL
,
365 bcm2836_control_local_timer_tick
, s
);
368 static const VMStateDescription vmstate_bcm2836_control
= {
369 .name
= TYPE_BCM2836_CONTROL
,
371 .minimum_version_id
= 1,
372 .fields
= (const VMStateField
[]) {
373 VMSTATE_UINT32_ARRAY(mailboxes
, BCM2836ControlState
,
374 BCM2836_NCORES
* BCM2836_MBPERCORE
),
375 VMSTATE_UINT8(route_gpu_irq
, BCM2836ControlState
),
376 VMSTATE_UINT8(route_gpu_fiq
, BCM2836ControlState
),
377 VMSTATE_UINT32_ARRAY(timercontrol
, BCM2836ControlState
, BCM2836_NCORES
),
378 VMSTATE_UINT32_ARRAY(mailboxcontrol
, BCM2836ControlState
,
380 VMSTATE_TIMER_V(timer
, BCM2836ControlState
, 2),
381 VMSTATE_UINT32_V(local_timer_control
, BCM2836ControlState
, 2),
382 VMSTATE_UINT8_V(route_localtimer
, BCM2836ControlState
, 2),
383 VMSTATE_END_OF_LIST()
387 static void bcm2836_control_class_init(ObjectClass
*klass
, void *data
)
389 DeviceClass
*dc
= DEVICE_CLASS(klass
);
391 dc
->reset
= bcm2836_control_reset
;
392 dc
->vmsd
= &vmstate_bcm2836_control
;
395 static const TypeInfo bcm2836_control_info
= {
396 .name
= TYPE_BCM2836_CONTROL
,
397 .parent
= TYPE_SYS_BUS_DEVICE
,
398 .instance_size
= sizeof(BCM2836ControlState
),
399 .class_init
= bcm2836_control_class_init
,
400 .instance_init
= bcm2836_control_init
,
403 static void bcm2836_control_register_types(void)
405 type_register_static(&bcm2836_control_info
);
408 type_init(bcm2836_control_register_types
)