Improve log message for unaligned i/o
[qemu/ar7.git] / hw / intc / bcm2835_ic.c
blob1de2c539c14f0a6efcff48dbc10094b93204e1cf
1 /*
2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
3 * This code is licensed under the GNU GPLv2 and later.
4 */
6 /* Heavily based on pl190.c, copyright terms below. */
8 /*
9 * Arm PrimeCell PL190 Vector Interrupt Controller
11 * Copyright (c) 2006 CodeSourcery.
12 * Written by Paul Brook
14 * This code is licensed under the GPL.
17 #include "hw/sysbus.h"
19 #define IR_B 2
20 #define IR_1 0
21 #define IR_2 1
23 #define TYPE_BCM2835_IC "bcm2835_ic"
24 #define BCM2835_IC(obj) OBJECT_CHECK(bcm2835_ic_state, (obj), TYPE_BCM2835_IC)
27 typedef struct bcm2835_ic_state {
28 SysBusDevice busdev;
29 MemoryRegion iomem;
31 uint32_t level[3];
32 uint32_t irq_enable[3];
33 int fiq_enable;
34 int fiq_select;
35 qemu_irq irq;
36 qemu_irq fiq;
37 } bcm2835_ic_state;
39 /* Update interrupts. */
40 static void bcm2835_ic_update(bcm2835_ic_state *s)
42 int set;
43 int i;
45 set = 0;
46 if (s->fiq_enable) {
47 set = s->level[s->fiq_select >> 5] & (1u << (s->fiq_select & 0x1f));
49 qemu_set_irq(s->fiq, set);
51 set = 0;
52 for (i = 0; i < 3; i++) {
53 set |= (s->level[i] & s->irq_enable[i]);
55 qemu_set_irq(s->irq, set);
59 static void bcm2835_ic_set_irq(void *opaque, int irq, int level)
61 bcm2835_ic_state *s = (bcm2835_ic_state *)opaque;
63 if (irq >= 0 && irq <= 71) {
64 if (level) {
65 s->level[irq >> 5] |= 1u << (irq & 0x1f);
66 } else {
67 s->level[irq >> 5] &= ~(1u << (irq & 0x1f));
69 } else {
70 qemu_log_mask(LOG_GUEST_ERROR,
71 "bcm2835_ic_set_irq: Bad irq %d\n", irq);
74 bcm2835_ic_update(s);
77 static const int irq_dups[] = { 7, 9, 10, 18, 19, 53, 54, 55, 56, 57, 62, -1 };
79 static uint64_t bcm2835_ic_read(void *opaque, hwaddr offset,
80 unsigned size)
82 bcm2835_ic_state *s = (bcm2835_ic_state *)opaque;
83 int i;
84 int p = 0;
85 uint32_t res = 0;
87 switch (offset) {
88 case 0x00: /* IRQ basic pending */
89 /* bits 0-7 - ARM irqs */
90 res = (s->level[IR_B] & s->irq_enable[IR_B]) & 0xff;
91 for (i = 0; i < 64; i++) {
92 if (i == irq_dups[p]) {
93 /* bits 10-20 - selected GPU irqs */
94 if (s->level[i >> 5] & s->irq_enable[i >> 5]
95 & (1u << (i & 0x1f))) {
96 res |= (1u << (10 + p));
98 p++;
99 } else {
100 /* bits 8-9 - one or more bits set in pending registers 1-2 */
101 if (s->level[i >> 5] & s->irq_enable[i >> 5]
102 & (1u << (i & 0x1f))) {
103 res |= (1u << (8 + (i >> 5)));
107 break;
108 case 0x04: /* IRQ pending 1 */
109 res = s->level[IR_1] & s->irq_enable[IR_1];
110 break;
111 case 0x08: /* IRQ pending 2 */
112 res = s->level[IR_2] & s->irq_enable[IR_2];
113 break;
114 case 0x0C: /* FIQ register */
115 res = (s->fiq_enable << 7) | s->fiq_select;
116 break;
117 case 0x10: /* Interrupt enable register 1 */
118 res = s->irq_enable[IR_1];
119 break;
120 case 0x14: /* Interrupt enable register 2 */
121 res = s->irq_enable[IR_2];
122 break;
123 case 0x18: /* Base interrupt enable register */
124 res = s->irq_enable[IR_B];
125 break;
126 case 0x1C: /* Interrupt disable register 1 */
127 res = ~s->irq_enable[IR_1];
128 break;
129 case 0x20: /* Interrupt disable register 2 */
130 res = ~s->irq_enable[IR_2];
131 break;
132 case 0x24: /* Base interrupt disable register */
133 res = ~s->irq_enable[IR_B];
134 break;
135 default:
136 qemu_log_mask(LOG_GUEST_ERROR,
137 "bcm2835_ic_read: Bad offset %x\n", (int)offset);
138 return 0;
141 return res;
144 static void bcm2835_ic_write(void *opaque, hwaddr offset,
145 uint64_t val, unsigned size)
147 bcm2835_ic_state *s = (bcm2835_ic_state *)opaque;
149 switch (offset) {
150 case 0x0C: /* FIQ register */
151 s->fiq_select = (val & 0x7f);
152 s->fiq_enable = (val >> 7) & 0x1;
153 break;
154 case 0x10: /* Interrupt enable register 1 */
155 s->irq_enable[IR_1] |= val;
156 break;
157 case 0x14: /* Interrupt enable register 2 */
158 s->irq_enable[IR_2] |= val;
159 break;
160 case 0x18: /* Base interrupt enable register */
161 s->irq_enable[IR_B] |= (val & 0xff);
162 break;
163 case 0x1C: /* Interrupt disable register 1 */
164 s->irq_enable[IR_1] &= ~val;
165 break;
166 case 0x20: /* Interrupt disable register 2 */
167 s->irq_enable[IR_2] &= ~val;
168 break;
169 case 0x24: /* Base interrupt disable register */
170 s->irq_enable[IR_B] &= (~val & 0xff);
171 break;
172 default:
173 qemu_log_mask(LOG_GUEST_ERROR,
174 "bcm2835_ic_write: Bad offset %x\n", (int)offset);
175 return;
177 bcm2835_ic_update(s);
180 static const MemoryRegionOps bcm2835_ic_ops = {
181 .read = bcm2835_ic_read,
182 .write = bcm2835_ic_write,
183 .endianness = DEVICE_NATIVE_ENDIAN,
186 static void bcm2835_ic_reset(DeviceState *d)
188 bcm2835_ic_state *s = BCM2835_IC(d);
189 int i;
191 for (i = 0; i < 3; i++) {
192 s->irq_enable[i] = 0;
194 s->fiq_enable = 0;
195 s->fiq_select = 0;
198 static int bcm2835_ic_init(SysBusDevice *sbd)
200 DeviceState *dev = DEVICE(sbd);
201 bcm2835_ic_state *s = BCM2835_IC(dev);
203 memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_ic_ops, s,
204 TYPE_BCM2835_IC, 0x200);
205 sysbus_init_mmio(sbd, &s->iomem);
207 qdev_init_gpio_in(dev, bcm2835_ic_set_irq, 72);
208 sysbus_init_irq(sbd, &s->irq);
209 sysbus_init_irq(sbd, &s->fiq);
210 return 0;
213 static const VMStateDescription vmstate_bcm2835_ic = {
214 .name = TYPE_BCM2835_IC,
215 .version_id = 1,
216 .minimum_version_id = 1,
217 .fields = (VMStateField[]) {
218 VMSTATE_UINT32_ARRAY(level, bcm2835_ic_state, 3),
219 VMSTATE_UINT32_ARRAY(irq_enable, bcm2835_ic_state, 3),
220 VMSTATE_INT32(fiq_enable, bcm2835_ic_state),
221 VMSTATE_INT32(fiq_select, bcm2835_ic_state),
222 VMSTATE_END_OF_LIST()
226 static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
228 DeviceClass *dc = DEVICE_CLASS(klass);
229 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
231 k->init = bcm2835_ic_init;
232 dc->reset = bcm2835_ic_reset;
233 dc->vmsd = &vmstate_bcm2835_ic;
236 static TypeInfo bcm2835_ic_info = {
237 .name = TYPE_BCM2835_IC,
238 .parent = TYPE_SYS_BUS_DEVICE,
239 .instance_size = sizeof(bcm2835_ic_state),
240 .class_init = bcm2835_ic_class_init,
243 static void bcm2835_ic_register_types(void)
245 type_register_static(&bcm2835_ic_info);
248 type_init(bcm2835_ic_register_types)