2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
3 * This code is licensed under the GNU GPLv2 and later.
6 /* Heavily based on pl190.c, copyright terms below. */
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"
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
{
32 uint32_t irq_enable
[3];
39 /* Update interrupts. */
40 static void bcm2835_ic_update(bcm2835_ic_state
*s
)
47 set
= s
->level
[s
->fiq_select
>> 5] & (1u << (s
->fiq_select
& 0x1f));
49 qemu_set_irq(s
->fiq
, set
);
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) {
65 s
->level
[irq
>> 5] |= 1u << (irq
& 0x1f);
67 s
->level
[irq
>> 5] &= ~(1u << (irq
& 0x1f));
70 qemu_log_mask(LOG_GUEST_ERROR
,
71 "bcm2835_ic_set_irq: Bad irq %d\n", irq
);
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
,
82 bcm2835_ic_state
*s
= (bcm2835_ic_state
*)opaque
;
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
));
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)));
108 case 0x04: /* IRQ pending 1 */
109 res
= s
->level
[IR_1
] & s
->irq_enable
[IR_1
];
111 case 0x08: /* IRQ pending 2 */
112 res
= s
->level
[IR_2
] & s
->irq_enable
[IR_2
];
114 case 0x0C: /* FIQ register */
115 res
= (s
->fiq_enable
<< 7) | s
->fiq_select
;
117 case 0x10: /* Interrupt enable register 1 */
118 res
= s
->irq_enable
[IR_1
];
120 case 0x14: /* Interrupt enable register 2 */
121 res
= s
->irq_enable
[IR_2
];
123 case 0x18: /* Base interrupt enable register */
124 res
= s
->irq_enable
[IR_B
];
126 case 0x1C: /* Interrupt disable register 1 */
127 res
= ~s
->irq_enable
[IR_1
];
129 case 0x20: /* Interrupt disable register 2 */
130 res
= ~s
->irq_enable
[IR_2
];
132 case 0x24: /* Base interrupt disable register */
133 res
= ~s
->irq_enable
[IR_B
];
136 qemu_log_mask(LOG_GUEST_ERROR
,
137 "bcm2835_ic_read: Bad offset %x\n", (int)offset
);
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
;
150 case 0x0C: /* FIQ register */
151 s
->fiq_select
= (val
& 0x7f);
152 s
->fiq_enable
= (val
>> 7) & 0x1;
154 case 0x10: /* Interrupt enable register 1 */
155 s
->irq_enable
[IR_1
] |= val
;
157 case 0x14: /* Interrupt enable register 2 */
158 s
->irq_enable
[IR_2
] |= val
;
160 case 0x18: /* Base interrupt enable register */
161 s
->irq_enable
[IR_B
] |= (val
& 0xff);
163 case 0x1C: /* Interrupt disable register 1 */
164 s
->irq_enable
[IR_1
] &= ~val
;
166 case 0x20: /* Interrupt disable register 2 */
167 s
->irq_enable
[IR_2
] &= ~val
;
169 case 0x24: /* Base interrupt disable register */
170 s
->irq_enable
[IR_B
] &= (~val
& 0xff);
173 qemu_log_mask(LOG_GUEST_ERROR
,
174 "bcm2835_ic_write: Bad offset %x\n", (int)offset
);
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
);
191 for (i
= 0; i
< 3; i
++) {
192 s
->irq_enable
[i
] = 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
);
213 static const VMStateDescription vmstate_bcm2835_ic
= {
214 .name
= TYPE_BCM2835_IC
,
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
)