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