1 /* 2 * QEMU Xilinx OPB Interrupt Controller. 3 * 4 * Copyright (c) 2009 Edgar E. Iglesias. 5 * 6 * https://docs.amd.com/v/u/en-US/xps_intc 7 * DS572: LogiCORE IP XPS Interrupt Controller (v2.01a) 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a copy 10 * of this software and associated documentation files (the "Software"), to deal 11 * in the Software without restriction, including without limitation the rights 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 * copies of the Software, and to permit persons to whom the Software is 14 * furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 * THE SOFTWARE. 26 */ 27 28 #include "qemu/osdep.h" 29 #include "qapi/error.h" 30 #include "hw/sysbus.h" 31 #include "qemu/module.h" 32 #include "hw/irq.h" 33 #include "hw/qdev-properties.h" 34 #include "hw/qdev-properties-system.h" 35 #include "qom/object.h" 36 37 #define D(x) 38 39 #define R_ISR 0 40 #define R_IPR 1 41 #define R_IER 2 42 #define R_IAR 3 43 #define R_SIE 4 44 #define R_CIE 5 45 #define R_IVR 6 46 #define R_MER 7 47 #define R_MAX 8 48 49 #define TYPE_XILINX_INTC "xlnx.xps-intc" 50 typedef struct XpsIntc XpsIntc; 51 DECLARE_INSTANCE_CHECKER(XpsIntc, XILINX_INTC, TYPE_XILINX_INTC) 52 53 struct XpsIntc 54 { 55 SysBusDevice parent_obj; 56 57 EndianMode model_endianness; 58 MemoryRegion mmio; 59 qemu_irq parent_irq; 60 61 /* Configuration reg chosen at synthesis-time. QEMU populates 62 the bits at board-setup. */ 63 uint32_t c_kind_of_intr; 64 65 /* Runtime control registers. */ 66 uint32_t regs[R_MAX]; 67 /* state of the interrupt input pins */ 68 uint32_t irq_pin_state; 69 }; 70 71 static void update_irq(XpsIntc *p) 72 { 73 uint32_t i; 74 75 /* level triggered interrupt */ 76 if (p->regs[R_MER] & 2) { 77 p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr; 78 } 79 80 /* Update the pending register. */ 81 p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER]; 82 83 /* Update the vector register. */ 84 for (i = 0; i < 32; i++) { 85 if (p->regs[R_IPR] & (1U << i)) { 86 break; 87 } 88 } 89 if (i == 32) 90 i = ~0; 91 92 p->regs[R_IVR] = i; 93 qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]); 94 } 95 96 static uint64_t pic_read(void *opaque, hwaddr addr, unsigned int size) 97 { 98 XpsIntc *p = opaque; 99 uint32_t r = 0; 100 101 addr >>= 2; 102 switch (addr) 103 { 104 default: 105 if (addr < ARRAY_SIZE(p->regs)) 106 r = p->regs[addr]; 107 break; 108 109 } 110 D(printf("%s %x=%x\n", __func__, addr * 4, r)); 111 return r; 112 } 113 114 static void pic_write(void *opaque, hwaddr addr, 115 uint64_t val64, unsigned int size) 116 { 117 XpsIntc *p = opaque; 118 uint32_t value = val64; 119 120 addr >>= 2; 121 D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); 122 switch (addr) 123 { 124 case R_IAR: 125 p->regs[R_ISR] &= ~value; /* ACK. */ 126 break; 127 case R_SIE: 128 p->regs[R_IER] |= value; /* Atomic set ie. */ 129 break; 130 case R_CIE: 131 p->regs[R_IER] &= ~value; /* Atomic clear ie. */ 132 break; 133 case R_MER: 134 p->regs[R_MER] = value & 0x3; 135 break; 136 case R_ISR: 137 if ((p->regs[R_MER] & 2)) { 138 break; 139 } 140 /* fallthrough */ 141 default: 142 if (addr < ARRAY_SIZE(p->regs)) 143 p->regs[addr] = value; 144 break; 145 } 146 update_irq(p); 147 } 148 149 static const MemoryRegionOps pic_ops[2] = { 150 [0 ... 1] = { 151 .read = pic_read, 152 .write = pic_write, 153 .impl = { 154 .min_access_size = 4, 155 .max_access_size = 4, 156 }, 157 .valid = { 158 /* 159 * All XPS INTC registers are accessed through the PLB interface. 160 * The base address for these registers is provided by the 161 * configuration parameter, C_BASEADDR. Each register is 32 bits 162 * although some bits may be unused and is accessed on a 4-byte 163 * boundary offset from the base address. 164 */ 165 .min_access_size = 4, 166 .max_access_size = 4, 167 }, 168 }, 169 [0].endianness = DEVICE_LITTLE_ENDIAN, 170 [1].endianness = DEVICE_BIG_ENDIAN, 171 }; 172 173 static void irq_handler(void *opaque, int irq, int level) 174 { 175 XpsIntc *p = opaque; 176 177 /* edge triggered interrupt */ 178 if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) { 179 p->regs[R_ISR] |= (level << irq); 180 } 181 182 p->irq_pin_state &= ~(1 << irq); 183 p->irq_pin_state |= level << irq; 184 update_irq(p); 185 } 186 187 static void xilinx_intc_init(Object *obj) 188 { 189 XpsIntc *p = XILINX_INTC(obj); 190 191 qdev_init_gpio_in(DEVICE(obj), irq_handler, 32); 192 sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq); 193 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio); 194 } 195 196 static void xilinx_intc_realize(DeviceState *dev, Error **errp) 197 { 198 XpsIntc *p = XILINX_INTC(dev); 199 200 if (p->model_endianness == ENDIAN_MODE_UNSPECIFIED) { 201 error_setg(errp, TYPE_XILINX_INTC " property 'endianness'" 202 " must be set to 'big' or 'little'"); 203 return; 204 } 205 206 memory_region_init_io(&p->mmio, OBJECT(dev), 207 &pic_ops[p->model_endianness == ENDIAN_MODE_BIG], 208 p, "xlnx.xps-intc", 209 R_MAX * 4); 210 } 211 212 static const Property xilinx_intc_properties[] = { 213 DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XpsIntc, model_endianness), 214 DEFINE_PROP_UINT32("kind-of-intr", XpsIntc, c_kind_of_intr, 0), 215 }; 216 217 static void xilinx_intc_class_init(ObjectClass *klass, void *data) 218 { 219 DeviceClass *dc = DEVICE_CLASS(klass); 220 221 dc->realize = xilinx_intc_realize; 222 device_class_set_props(dc, xilinx_intc_properties); 223 } 224 225 static const TypeInfo xilinx_intc_info = { 226 .name = TYPE_XILINX_INTC, 227 .parent = TYPE_SYS_BUS_DEVICE, 228 .instance_size = sizeof(XpsIntc), 229 .instance_init = xilinx_intc_init, 230 .class_init = xilinx_intc_class_init, 231 }; 232 233 static void xilinx_intc_register_types(void) 234 { 235 type_register_static(&xilinx_intc_info); 236 } 237 238 type_init(xilinx_intc_register_types) 239