1 /* 2 * i.MX31 Vectored Interrupt Controller 3 * 4 * Note this is NOT the PL192 provided by ARM, but 5 * a custom implementation by Freescale. 6 * 7 * Copyright (c) 2008 OKL 8 * Copyright (c) 2011 NICTA Pty Ltd 9 * Originally written by Hans Jiang 10 * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> 11 * 12 * This code is licensed under the GPL version 2 or later. See 13 * the COPYING file in the top-level directory. 14 * 15 * TODO: implement vectors. 16 */ 17 18 #include "qemu/osdep.h" 19 #include "hw/intc/imx_avic.h" 20 21 #ifndef DEBUG_IMX_AVIC 22 #define DEBUG_IMX_AVIC 0 23 #endif 24 25 #define DPRINTF(fmt, args...) \ 26 do { \ 27 if (DEBUG_IMX_AVIC) { \ 28 fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_AVIC, \ 29 __func__, ##args); \ 30 } \ 31 } while (0) 32 33 static const VMStateDescription vmstate_imx_avic = { 34 .name = TYPE_IMX_AVIC, 35 .version_id = 1, 36 .minimum_version_id = 1, 37 .fields = (VMStateField[]) { 38 VMSTATE_UINT64(pending, IMXAVICState), 39 VMSTATE_UINT64(enabled, IMXAVICState), 40 VMSTATE_UINT64(is_fiq, IMXAVICState), 41 VMSTATE_UINT32(intcntl, IMXAVICState), 42 VMSTATE_UINT32(intmask, IMXAVICState), 43 VMSTATE_UINT32_ARRAY(prio, IMXAVICState, PRIO_WORDS), 44 VMSTATE_END_OF_LIST() 45 }, 46 }; 47 48 static inline int imx_avic_prio(IMXAVICState *s, int irq) 49 { 50 uint32_t word = irq / PRIO_PER_WORD; 51 uint32_t part = 4 * (irq % PRIO_PER_WORD); 52 return 0xf & (s->prio[word] >> part); 53 } 54 55 /* Update interrupts. */ 56 static void imx_avic_update(IMXAVICState *s) 57 { 58 int i; 59 uint64_t new = s->pending & s->enabled; 60 uint64_t flags; 61 62 flags = new & s->is_fiq; 63 qemu_set_irq(s->fiq, !!flags); 64 65 flags = new & ~s->is_fiq; 66 if (!flags || (s->intmask == 0x1f)) { 67 qemu_set_irq(s->irq, !!flags); 68 return; 69 } 70 71 /* 72 * Take interrupt if there's a pending interrupt with 73 * priority higher than the value of intmask 74 */ 75 for (i = 0; i < IMX_AVIC_NUM_IRQS; i++) { 76 if (flags & (1UL << i)) { 77 if (imx_avic_prio(s, i) > s->intmask) { 78 qemu_set_irq(s->irq, 1); 79 return; 80 } 81 } 82 } 83 qemu_set_irq(s->irq, 0); 84 } 85 86 static void imx_avic_set_irq(void *opaque, int irq, int level) 87 { 88 IMXAVICState *s = (IMXAVICState *)opaque; 89 90 if (level) { 91 DPRINTF("Raising IRQ %d, prio %d\n", 92 irq, imx_avic_prio(s, irq)); 93 s->pending |= (1ULL << irq); 94 } else { 95 DPRINTF("Clearing IRQ %d, prio %d\n", 96 irq, imx_avic_prio(s, irq)); 97 s->pending &= ~(1ULL << irq); 98 } 99 100 imx_avic_update(s); 101 } 102 103 104 static uint64_t imx_avic_read(void *opaque, 105 hwaddr offset, unsigned size) 106 { 107 IMXAVICState *s = (IMXAVICState *)opaque; 108 109 DPRINTF("read(offset = 0x%" HWADDR_PRIx ")\n", offset); 110 111 switch (offset >> 2) { 112 case 0: /* INTCNTL */ 113 return s->intcntl; 114 115 case 1: /* Normal Interrupt Mask Register, NIMASK */ 116 return s->intmask; 117 118 case 2: /* Interrupt Enable Number Register, INTENNUM */ 119 case 3: /* Interrupt Disable Number Register, INTDISNUM */ 120 return 0; 121 122 case 4: /* Interrupt Enabled Number Register High */ 123 return s->enabled >> 32; 124 125 case 5: /* Interrupt Enabled Number Register Low */ 126 return s->enabled & 0xffffffffULL; 127 128 case 6: /* Interrupt Type Register High */ 129 return s->is_fiq >> 32; 130 131 case 7: /* Interrupt Type Register Low */ 132 return s->is_fiq & 0xffffffffULL; 133 134 case 8: /* Normal Interrupt Priority Register 7 */ 135 case 9: /* Normal Interrupt Priority Register 6 */ 136 case 10:/* Normal Interrupt Priority Register 5 */ 137 case 11:/* Normal Interrupt Priority Register 4 */ 138 case 12:/* Normal Interrupt Priority Register 3 */ 139 case 13:/* Normal Interrupt Priority Register 2 */ 140 case 14:/* Normal Interrupt Priority Register 1 */ 141 case 15:/* Normal Interrupt Priority Register 0 */ 142 return s->prio[15-(offset>>2)]; 143 144 case 16: /* Normal interrupt vector and status register */ 145 { 146 /* 147 * This returns the highest priority 148 * outstanding interrupt. Where there is more than 149 * one pending IRQ with the same priority, 150 * take the highest numbered one. 151 */ 152 uint64_t flags = s->pending & s->enabled & ~s->is_fiq; 153 int i; 154 int prio = -1; 155 int irq = -1; 156 for (i = 63; i >= 0; --i) { 157 if (flags & (1ULL<<i)) { 158 int irq_prio = imx_avic_prio(s, i); 159 if (irq_prio > prio) { 160 irq = i; 161 prio = irq_prio; 162 } 163 } 164 } 165 if (irq >= 0) { 166 imx_avic_set_irq(s, irq, 0); 167 return irq << 16 | prio; 168 } 169 return 0xffffffffULL; 170 } 171 case 17:/* Fast Interrupt vector and status register */ 172 { 173 uint64_t flags = s->pending & s->enabled & s->is_fiq; 174 int i = ctz64(flags); 175 if (i < 64) { 176 imx_avic_set_irq(opaque, i, 0); 177 return i; 178 } 179 return 0xffffffffULL; 180 } 181 case 18:/* Interrupt source register high */ 182 return s->pending >> 32; 183 184 case 19:/* Interrupt source register low */ 185 return s->pending & 0xffffffffULL; 186 187 case 20:/* Interrupt Force Register high */ 188 case 21:/* Interrupt Force Register low */ 189 return 0; 190 191 case 22:/* Normal Interrupt Pending Register High */ 192 return (s->pending & s->enabled & ~s->is_fiq) >> 32; 193 194 case 23:/* Normal Interrupt Pending Register Low */ 195 return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL; 196 197 case 24: /* Fast Interrupt Pending Register High */ 198 return (s->pending & s->enabled & s->is_fiq) >> 32; 199 200 case 25: /* Fast Interrupt Pending Register Low */ 201 return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL; 202 203 case 0x40: /* AVIC vector 0, use for WFI WAR */ 204 return 0x4; 205 206 default: 207 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 208 HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset); 209 return 0; 210 } 211 } 212 213 static void imx_avic_write(void *opaque, hwaddr offset, 214 uint64_t val, unsigned size) 215 { 216 IMXAVICState *s = (IMXAVICState *)opaque; 217 218 /* Vector Registers not yet supported */ 219 if (offset >= 0x100 && offset <= 0x2fc) { 220 qemu_log_mask(LOG_UNIMP, "[%s]%s: vector %d ignored\n", 221 TYPE_IMX_AVIC, __func__, (int)((offset - 0x100) >> 2)); 222 return; 223 } 224 225 DPRINTF("(0x%" HWADDR_PRIx ") = 0x%x\n", offset, (unsigned int)val); 226 227 switch (offset >> 2) { 228 case 0: /* Interrupt Control Register, INTCNTL */ 229 s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM); 230 if (s->intcntl & ABFEN) { 231 s->intcntl &= ~(val & ABFLAG); 232 } 233 break; 234 235 case 1: /* Normal Interrupt Mask Register, NIMASK */ 236 s->intmask = val & 0x1f; 237 break; 238 239 case 2: /* Interrupt Enable Number Register, INTENNUM */ 240 DPRINTF("enable(%d)\n", (int)val); 241 val &= 0x3f; 242 s->enabled |= (1ULL << val); 243 break; 244 245 case 3: /* Interrupt Disable Number Register, INTDISNUM */ 246 DPRINTF("disable(%d)\n", (int)val); 247 val &= 0x3f; 248 s->enabled &= ~(1ULL << val); 249 break; 250 251 case 4: /* Interrupt Enable Number Register High */ 252 s->enabled = (s->enabled & 0xffffffffULL) | (val << 32); 253 break; 254 255 case 5: /* Interrupt Enable Number Register Low */ 256 s->enabled = (s->enabled & 0xffffffff00000000ULL) | val; 257 break; 258 259 case 6: /* Interrupt Type Register High */ 260 s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32); 261 break; 262 263 case 7: /* Interrupt Type Register Low */ 264 s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val; 265 break; 266 267 case 8: /* Normal Interrupt Priority Register 7 */ 268 case 9: /* Normal Interrupt Priority Register 6 */ 269 case 10:/* Normal Interrupt Priority Register 5 */ 270 case 11:/* Normal Interrupt Priority Register 4 */ 271 case 12:/* Normal Interrupt Priority Register 3 */ 272 case 13:/* Normal Interrupt Priority Register 2 */ 273 case 14:/* Normal Interrupt Priority Register 1 */ 274 case 15:/* Normal Interrupt Priority Register 0 */ 275 s->prio[15-(offset>>2)] = val; 276 break; 277 278 /* Read-only registers, writes ignored */ 279 case 16:/* Normal Interrupt Vector and Status register */ 280 case 17:/* Fast Interrupt vector and status register */ 281 case 18:/* Interrupt source register high */ 282 case 19:/* Interrupt source register low */ 283 return; 284 285 case 20:/* Interrupt Force Register high */ 286 s->pending = (s->pending & 0xffffffffULL) | (val << 32); 287 break; 288 289 case 21:/* Interrupt Force Register low */ 290 s->pending = (s->pending & 0xffffffff00000000ULL) | val; 291 break; 292 293 case 22:/* Normal Interrupt Pending Register High */ 294 case 23:/* Normal Interrupt Pending Register Low */ 295 case 24: /* Fast Interrupt Pending Register High */ 296 case 25: /* Fast Interrupt Pending Register Low */ 297 return; 298 299 default: 300 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 301 HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset); 302 } 303 imx_avic_update(s); 304 } 305 306 static const MemoryRegionOps imx_avic_ops = { 307 .read = imx_avic_read, 308 .write = imx_avic_write, 309 .endianness = DEVICE_NATIVE_ENDIAN, 310 }; 311 312 static void imx_avic_reset(DeviceState *dev) 313 { 314 IMXAVICState *s = IMX_AVIC(dev); 315 316 s->pending = 0; 317 s->enabled = 0; 318 s->is_fiq = 0; 319 s->intmask = 0x1f; 320 s->intcntl = 0; 321 memset(s->prio, 0, sizeof s->prio); 322 } 323 324 static void imx_avic_init(Object *obj) 325 { 326 DeviceState *dev = DEVICE(obj); 327 IMXAVICState *s = IMX_AVIC(obj); 328 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 329 330 memory_region_init_io(&s->iomem, obj, &imx_avic_ops, s, 331 TYPE_IMX_AVIC, 0x1000); 332 sysbus_init_mmio(sbd, &s->iomem); 333 334 qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS); 335 sysbus_init_irq(sbd, &s->irq); 336 sysbus_init_irq(sbd, &s->fiq); 337 } 338 339 340 static void imx_avic_class_init(ObjectClass *klass, void *data) 341 { 342 DeviceClass *dc = DEVICE_CLASS(klass); 343 344 dc->vmsd = &vmstate_imx_avic; 345 dc->reset = imx_avic_reset; 346 dc->desc = "i.MX Advanced Vector Interrupt Controller"; 347 } 348 349 static const TypeInfo imx_avic_info = { 350 .name = TYPE_IMX_AVIC, 351 .parent = TYPE_SYS_BUS_DEVICE, 352 .instance_size = sizeof(IMXAVICState), 353 .instance_init = imx_avic_init, 354 .class_init = imx_avic_class_init, 355 }; 356 357 static void imx_avic_register_types(void) 358 { 359 type_register_static(&imx_avic_info); 360 } 361 362 type_init(imx_avic_register_types) 363