xref: /openbmc/qemu/hw/intc/bcm2836_control.c (revision 7d87775f)
1 /*
2  * Rasperry Pi 2 emulation ARM control logic module.
3  * Copyright (c) 2015, Microsoft
4  * Written by Andrew Baumann
5  *
6  * Based on bcm2835_ic.c (Raspberry Pi emulation) (c) 2012 Gregory Estrade
7  *
8  * At present, only implements interrupt routing, and mailboxes (i.e.,
9  * not PMU interrupt, or AXI counters).
10  *
11  * ARM Local Timer IRQ Copyright (c) 2019. Zoltán Baldaszti
12  *
13  * Ref:
14  * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
15  *
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.
18  */
19 
20 #include "qemu/osdep.h"
21 #include "hw/intc/bcm2836_control.h"
22 #include "hw/irq.h"
23 #include "migration/vmstate.h"
24 #include "qemu/log.h"
25 #include "qemu/module.h"
26 
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
38 
39 #define IRQ_BIT(cntrl, num) (((cntrl) & (1 << (num))) != 0)
40 #define FIQ_BIT(cntrl, num) (((cntrl) & (1 << ((num) + 4))) != 0)
41 
42 #define IRQ_CNTPSIRQ    0
43 #define IRQ_CNTPNSIRQ   1
44 #define IRQ_CNTHPIRQ    2
45 #define IRQ_CNTVIRQ     3
46 #define IRQ_MAILBOX0    4
47 #define IRQ_MAILBOX1    5
48 #define IRQ_MAILBOX2    6
49 #define IRQ_MAILBOX3    7
50 #define IRQ_GPU         8
51 #define IRQ_PMU         9
52 #define IRQ_AXI         10
53 #define IRQ_TIMER       11
54 #define IRQ_MAX         IRQ_TIMER
55 
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)
62 
63 static void deliver_local(BCM2836ControlState *s, uint8_t core, uint8_t irq,
64                           uint32_t controlreg, uint8_t controlidx)
65 {
66     if (FIQ_BIT(controlreg, controlidx)) {
67         /* deliver a FIQ */
68         s->fiqsrc[core] |= (uint32_t)1 << irq;
69     } else if (IRQ_BIT(controlreg, controlidx)) {
70         /* deliver an IRQ */
71         s->irqsrc[core] |= (uint32_t)1 << irq;
72     } else {
73         /* the interrupt is masked */
74     }
75 }
76 
77 /* Update interrupts.  */
78 static void bcm2836_control_update(BCM2836ControlState *s)
79 {
80     int i, j;
81 
82     /* reset pending IRQs/FIQs */
83     for (i = 0; i < BCM2836_NCORES; i++) {
84         s->irqsrc[i] = s->fiqsrc[i] = 0;
85     }
86 
87     /* apply routing logic, update status regs */
88     if (s->gpu_irq) {
89         assert(s->route_gpu_irq < BCM2836_NCORES);
90         s->irqsrc[s->route_gpu_irq] |= (uint32_t)1 << IRQ_GPU;
91     }
92 
93     if (s->gpu_fiq) {
94         assert(s->route_gpu_fiq < BCM2836_NCORES);
95         s->fiqsrc[s->route_gpu_fiq] |= (uint32_t)1 << IRQ_GPU;
96     }
97 
98     /*
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.
102      */
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;
107         } else {
108             s->irqsrc[(s->route_localtimer & 3)] |= (uint32_t)1 << IRQ_TIMER;
109         }
110     }
111 
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);
120                 }
121             }
122         }
123 
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);
129             }
130         }
131     }
132 
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);
137     }
138 }
139 
140 static void bcm2836_control_set_local_irq(void *opaque, int core, int local_irq,
141                                           int level)
142 {
143     BCM2836ControlState *s = opaque;
144 
145     assert(core >= 0 && core < BCM2836_NCORES);
146     assert(local_irq >= 0 && local_irq <= IRQ_CNTVIRQ);
147 
148     s->timerirqs[core] = deposit32(s->timerirqs[core], local_irq, 1, !!level);
149 
150     bcm2836_control_update(s);
151 }
152 
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!
156  */
157 
158 static void bcm2836_control_set_local_irq0(void *opaque, int core, int level)
159 {
160     bcm2836_control_set_local_irq(opaque, core, IRQ_CNTPSIRQ, level);
161 }
162 
163 static void bcm2836_control_set_local_irq1(void *opaque, int core, int level)
164 {
165     bcm2836_control_set_local_irq(opaque, core, IRQ_CNTPNSIRQ, level);
166 }
167 
168 static void bcm2836_control_set_local_irq2(void *opaque, int core, int level)
169 {
170     bcm2836_control_set_local_irq(opaque, core, IRQ_CNTHPIRQ, level);
171 }
172 
173 static void bcm2836_control_set_local_irq3(void *opaque, int core, int level)
174 {
175     bcm2836_control_set_local_irq(opaque, core, IRQ_CNTVIRQ, level);
176 }
177 
178 static void bcm2836_control_set_gpu_irq(void *opaque, int irq, int level)
179 {
180     BCM2836ControlState *s = opaque;
181 
182     s->gpu_irq = level;
183 
184     bcm2836_control_update(s);
185 }
186 
187 static void bcm2836_control_set_gpu_fiq(void *opaque, int irq, int level)
188 {
189     BCM2836ControlState *s = opaque;
190 
191     s->gpu_fiq = level;
192 
193     bcm2836_control_update(s);
194 }
195 
196 static void bcm2836_control_local_timer_set_next(void *opaque)
197 {
198     BCM2836ControlState *s = opaque;
199     uint64_t next_event;
200 
201     assert(LOCALTIMER_VALUE(s->local_timer_control) > 0);
202 
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);
207 }
208 
209 static void bcm2836_control_local_timer_tick(void *opaque)
210 {
211     BCM2836ControlState *s = opaque;
212 
213     bcm2836_control_local_timer_set_next(s);
214 
215     s->local_timer_control |= LOCALTIMER_INTFLAG;
216     bcm2836_control_update(s);
217 }
218 
219 static void bcm2836_control_local_timer_control(void *opaque, uint32_t val)
220 {
221     BCM2836ControlState *s = opaque;
222 
223     s->local_timer_control = val;
224     if (val & LOCALTIMER_ENABLE) {
225         bcm2836_control_local_timer_set_next(s);
226     } else {
227         timer_del(&s->timer);
228     }
229 }
230 
231 static void bcm2836_control_local_timer_ack(void *opaque, uint32_t val)
232 {
233     BCM2836ControlState *s = opaque;
234 
235     if (val & LOCALTIMER_INTFLAG) {
236         s->local_timer_control &= ~LOCALTIMER_INTFLAG;
237     }
238     if ((val & LOCALTIMER_RELOAD) &&
239         (s->local_timer_control & LOCALTIMER_ENABLE)) {
240             bcm2836_control_local_timer_set_next(s);
241     }
242 }
243 
244 static uint64_t bcm2836_control_read(void *opaque, hwaddr offset, unsigned size)
245 {
246     BCM2836ControlState *s = opaque;
247 
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) {
257         return 0;
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];
268     } else {
269         qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx"\n",
270                       __func__, offset);
271         return 0;
272     }
273 }
274 
275 static void bcm2836_control_write(void *opaque, hwaddr offset,
276                                   uint64_t val, unsigned size)
277 {
278     BCM2836ControlState *s = opaque;
279 
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;
297     } else {
298         qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx
299                                  " value 0x%"PRIx64"\n",
300                       __func__, offset, val);
301         return;
302     }
303 
304     bcm2836_control_update(s);
305 }
306 
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,
313 };
314 
315 static void bcm2836_control_reset(DeviceState *d)
316 {
317     BCM2836ControlState *s = BCM2836_CONTROL(d);
318     int i;
319 
320     s->route_gpu_irq = s->route_gpu_fiq = 0;
321 
322     timer_del(&s->timer);
323     s->route_localtimer = 0;
324     s->local_timer_control = 0;
325 
326     for (i = 0; i < BCM2836_NCORES; i++) {
327         s->timercontrol[i] = 0;
328         s->mailboxcontrol[i] = 0;
329     }
330 
331     for (i = 0; i < BCM2836_NCORES * BCM2836_MBPERCORE; i++) {
332         s->mailboxes[i] = 0;
333     }
334 }
335 
336 static void bcm2836_control_init(Object *obj)
337 {
338     BCM2836ControlState *s = BCM2836_CONTROL(obj);
339     DeviceState *dev = DEVICE(obj);
340 
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);
344 
345     /* inputs from each CPU core */
346     qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq0, "cntpsirq",
347                             BCM2836_NCORES);
348     qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq1, "cntpnsirq",
349                             BCM2836_NCORES);
350     qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq2, "cnthpirq",
351                             BCM2836_NCORES);
352     qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq3, "cntvirq",
353                             BCM2836_NCORES);
354 
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);
358 
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);
362 
363     /* create a qemu virtual timer */
364     timer_init_ns(&s->timer, QEMU_CLOCK_VIRTUAL,
365                   bcm2836_control_local_timer_tick, s);
366 }
367 
368 static const VMStateDescription vmstate_bcm2836_control = {
369     .name = TYPE_BCM2836_CONTROL,
370     .version_id = 2,
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,
379                              BCM2836_NCORES),
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()
384     }
385 };
386 
387 static void bcm2836_control_class_init(ObjectClass *klass, void *data)
388 {
389     DeviceClass *dc = DEVICE_CLASS(klass);
390 
391     device_class_set_legacy_reset(dc, bcm2836_control_reset);
392     dc->vmsd = &vmstate_bcm2836_control;
393 }
394 
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,
401 };
402 
403 static void bcm2836_control_register_types(void)
404 {
405     type_register_static(&bcm2836_control_info);
406 }
407 
408 type_init(bcm2836_control_register_types)
409