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