xref: /openbmc/qemu/hw/intc/bcm2835_ic.c (revision 5a3be00c)
1 /*
2  * Raspberry Pi emulation (c) 2012 Gregory Estrade
3  * Refactoring for Pi2 Copyright (c) 2015, Microsoft. Written by Andrew Baumann.
4  * This code is licensed under the GNU GPLv2 and later.
5  * Heavily based on pl190.c, copyright terms below:
6  *
7  * Arm PrimeCell PL190 Vector Interrupt Controller
8  *
9  * Copyright (c) 2006 CodeSourcery.
10  * Written by Paul Brook
11  *
12  * This code is licensed under the GPL.
13  */
14 
15 #include "hw/intc/bcm2835_ic.h"
16 
17 #define GPU_IRQS 64
18 #define ARM_IRQS 8
19 
20 #define IRQ_PENDING_BASIC       0x00 /* IRQ basic pending */
21 #define IRQ_PENDING_1           0x04 /* IRQ pending 1 */
22 #define IRQ_PENDING_2           0x08 /* IRQ pending 2 */
23 #define FIQ_CONTROL             0x0C /* FIQ register */
24 #define IRQ_ENABLE_1            0x10 /* Interrupt enable register 1 */
25 #define IRQ_ENABLE_2            0x14 /* Interrupt enable register 2 */
26 #define IRQ_ENABLE_BASIC        0x18 /* Base interrupt enable register */
27 #define IRQ_DISABLE_1           0x1C /* Interrupt disable register 1 */
28 #define IRQ_DISABLE_2           0x20 /* Interrupt disable register 2 */
29 #define IRQ_DISABLE_BASIC       0x24 /* Base interrupt disable register */
30 
31 /* Update interrupts.  */
32 static void bcm2835_ic_update(BCM2835ICState *s)
33 {
34     bool set = false;
35 
36     if (s->fiq_enable) {
37         if (s->fiq_select >= GPU_IRQS) {
38             /* ARM IRQ */
39             set = extract32(s->arm_irq_level, s->fiq_select - GPU_IRQS, 1);
40         } else {
41             set = extract64(s->gpu_irq_level, s->fiq_select, 1);
42         }
43     }
44     qemu_set_irq(s->fiq, set);
45 
46     set = (s->gpu_irq_level & s->gpu_irq_enable)
47         || (s->arm_irq_level & s->arm_irq_enable);
48     qemu_set_irq(s->irq, set);
49 
50 }
51 
52 static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
53 {
54     BCM2835ICState *s = opaque;
55 
56     assert(irq >= 0 && irq < 64);
57     s->gpu_irq_level = deposit64(s->gpu_irq_level, irq, 1, level != 0);
58     bcm2835_ic_update(s);
59 }
60 
61 static void bcm2835_ic_set_arm_irq(void *opaque, int irq, int level)
62 {
63     BCM2835ICState *s = opaque;
64 
65     assert(irq >= 0 && irq < 8);
66     s->arm_irq_level = deposit32(s->arm_irq_level, irq, 1, level != 0);
67     bcm2835_ic_update(s);
68 }
69 
70 static const int irq_dups[] = { 7, 9, 10, 18, 19, 53, 54, 55, 56, 57, 62 };
71 
72 static uint64_t bcm2835_ic_read(void *opaque, hwaddr offset, unsigned size)
73 {
74     BCM2835ICState *s = opaque;
75     uint32_t res = 0;
76     uint64_t gpu_pending = s->gpu_irq_level & s->gpu_irq_enable;
77     int i;
78 
79     switch (offset) {
80     case IRQ_PENDING_BASIC:
81         /* bits 0-7: ARM irqs */
82         res = s->arm_irq_level & s->arm_irq_enable;
83 
84         /* bits 8 & 9: pending registers 1 & 2 */
85         res |= (((uint32_t)gpu_pending) != 0) << 8;
86         res |= ((gpu_pending >> 32) != 0) << 9;
87 
88         /* bits 10-20: selected GPU IRQs */
89         for (i = 0; i < ARRAY_SIZE(irq_dups); i++) {
90             res |= extract64(gpu_pending, irq_dups[i], 1) << (i + 10);
91         }
92         break;
93     case IRQ_PENDING_1:
94         res = gpu_pending;
95         break;
96     case IRQ_PENDING_2:
97         res = gpu_pending >> 32;
98         break;
99     case FIQ_CONTROL:
100         res = (s->fiq_enable << 7) | s->fiq_select;
101         break;
102     case IRQ_ENABLE_1:
103         res = s->gpu_irq_enable;
104         break;
105     case IRQ_ENABLE_2:
106         res = s->gpu_irq_enable >> 32;
107         break;
108     case IRQ_ENABLE_BASIC:
109         res = s->arm_irq_enable;
110         break;
111     case IRQ_DISABLE_1:
112         res = ~s->gpu_irq_enable;
113         break;
114     case IRQ_DISABLE_2:
115         res = ~s->gpu_irq_enable >> 32;
116         break;
117     case IRQ_DISABLE_BASIC:
118         res = ~s->arm_irq_enable;
119         break;
120     default:
121         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
122                       __func__, offset);
123         return 0;
124     }
125 
126     return res;
127 }
128 
129 static void bcm2835_ic_write(void *opaque, hwaddr offset, uint64_t val,
130                              unsigned size)
131 {
132     BCM2835ICState *s = opaque;
133 
134     switch (offset) {
135     case FIQ_CONTROL:
136         s->fiq_select = extract32(val, 0, 7);
137         s->fiq_enable = extract32(val, 7, 1);
138         break;
139     case IRQ_ENABLE_1:
140         s->gpu_irq_enable |= val;
141         break;
142     case IRQ_ENABLE_2:
143         s->gpu_irq_enable |= val << 32;
144         break;
145     case IRQ_ENABLE_BASIC:
146         s->arm_irq_enable |= val & 0xff;
147         break;
148     case IRQ_DISABLE_1:
149         s->gpu_irq_enable &= ~val;
150         break;
151     case IRQ_DISABLE_2:
152         s->gpu_irq_enable &= ~(val << 32);
153         break;
154     case IRQ_DISABLE_BASIC:
155         s->arm_irq_enable &= ~val & 0xff;
156         break;
157     default:
158         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
159                       __func__, offset);
160         return;
161     }
162     bcm2835_ic_update(s);
163 }
164 
165 static const MemoryRegionOps bcm2835_ic_ops = {
166     .read = bcm2835_ic_read,
167     .write = bcm2835_ic_write,
168     .endianness = DEVICE_NATIVE_ENDIAN,
169     .valid.min_access_size = 4,
170     .valid.max_access_size = 4,
171 };
172 
173 static void bcm2835_ic_reset(DeviceState *d)
174 {
175     BCM2835ICState *s = BCM2835_IC(d);
176 
177     s->gpu_irq_enable = 0;
178     s->arm_irq_enable = 0;
179     s->fiq_enable = false;
180     s->fiq_select = 0;
181 }
182 
183 static void bcm2835_ic_init(Object *obj)
184 {
185     BCM2835ICState *s = BCM2835_IC(obj);
186 
187     memory_region_init_io(&s->iomem, obj, &bcm2835_ic_ops, s, TYPE_BCM2835_IC,
188                           0x200);
189     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
190 
191     qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_gpu_irq,
192                             BCM2835_IC_GPU_IRQ, GPU_IRQS);
193     qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_arm_irq,
194                             BCM2835_IC_ARM_IRQ, ARM_IRQS);
195 
196     sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
197     sysbus_init_irq(SYS_BUS_DEVICE(s), &s->fiq);
198 }
199 
200 static const VMStateDescription vmstate_bcm2835_ic = {
201     .name = TYPE_BCM2835_IC,
202     .version_id = 1,
203     .minimum_version_id = 1,
204     .fields = (VMStateField[]) {
205         VMSTATE_UINT64(gpu_irq_level, BCM2835ICState),
206         VMSTATE_UINT64(gpu_irq_enable, BCM2835ICState),
207         VMSTATE_UINT8(arm_irq_level, BCM2835ICState),
208         VMSTATE_UINT8(arm_irq_enable, BCM2835ICState),
209         VMSTATE_BOOL(fiq_enable, BCM2835ICState),
210         VMSTATE_UINT8(fiq_select, BCM2835ICState),
211         VMSTATE_END_OF_LIST()
212     }
213 };
214 
215 static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
216 {
217     DeviceClass *dc = DEVICE_CLASS(klass);
218 
219     dc->reset = bcm2835_ic_reset;
220     dc->vmsd = &vmstate_bcm2835_ic;
221 }
222 
223 static TypeInfo bcm2835_ic_info = {
224     .name          = TYPE_BCM2835_IC,
225     .parent        = TYPE_SYS_BUS_DEVICE,
226     .instance_size = sizeof(BCM2835ICState),
227     .class_init    = bcm2835_ic_class_init,
228     .instance_init = bcm2835_ic_init,
229 };
230 
231 static void bcm2835_ic_register_types(void)
232 {
233     type_register_static(&bcm2835_ic_info);
234 }
235 
236 type_init(bcm2835_ic_register_types)
237