1 /* 2 * ASPEED Interrupt Controller (New) 3 * 4 * Andrew Jeffery <andrew@aj.id.au> 5 * 6 * Copyright 2015, 2016 IBM Corp. 7 * 8 * This code is licensed under the GPL version 2 or later. See 9 * the COPYING file in the top-level directory. 10 */ 11 12 /* The hardware exposes two register sets, a legacy set and a 'new' set. The 13 * model implements the 'new' register set, and logs warnings on accesses to 14 * the legacy IO space. 15 * 16 * The hardware uses 32bit registers to manage 51 IRQs, with low and high 17 * registers for each conceptual register. The device model's implementation 18 * uses 64bit data types to store both low and high register values (in the one 19 * member), but must cope with access offset values in multiples of 4 passed to 20 * the callbacks. As such the read() and write() implementations process the 21 * provided offset to understand whether the access is requesting the lower or 22 * upper 32 bits of the 64bit member. 23 * 24 * Additionally, the "Interrupt Enable", "Edge Status" and "Software Interrupt" 25 * fields have separate "enable"/"status" and "clear" registers, where set bits 26 * are written to one or the other to change state (avoiding a 27 * read-modify-write sequence). 28 */ 29 30 #include "qemu/osdep.h" 31 #include "hw/intc/aspeed_vic.h" 32 #include "hw/irq.h" 33 #include "qemu/bitops.h" 34 #include "qemu/log.h" 35 #include "qemu/module.h" 36 #include "trace.h" 37 38 #define AVIC_NEW_BASE_OFFSET 0x80 39 40 #define AVIC_L_MASK 0xFFFFFFFFU 41 #define AVIC_H_MASK 0x0007FFFFU 42 #define AVIC_EVENT_W_MASK (0x78000ULL << 32) 43 44 static void aspeed_vic_update(AspeedVICState *s) 45 { 46 uint64_t new = (s->raw & s->enable); 47 uint64_t flags; 48 49 flags = new & s->select; 50 trace_aspeed_vic_update_fiq(!!flags); 51 qemu_set_irq(s->fiq, !!flags); 52 53 flags = new & ~s->select; 54 trace_aspeed_vic_update_irq(!!flags); 55 qemu_set_irq(s->irq, !!flags); 56 } 57 58 static void aspeed_vic_set_irq(void *opaque, int irq, int level) 59 { 60 uint64_t irq_mask; 61 bool raise; 62 AspeedVICState *s = (AspeedVICState *)opaque; 63 64 if (irq > ASPEED_VIC_NR_IRQS) { 65 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 66 __func__, irq); 67 return; 68 } 69 70 trace_aspeed_vic_set_irq(irq, level); 71 72 irq_mask = BIT(irq); 73 if (s->sense & irq_mask) { 74 /* level-triggered */ 75 if (s->event & irq_mask) { 76 /* high-sensitive */ 77 raise = level; 78 } else { 79 /* low-sensitive */ 80 raise = !level; 81 } 82 s->raw = deposit64(s->raw, irq, 1, raise); 83 } else { 84 uint64_t old_level = s->level & irq_mask; 85 86 /* edge-triggered */ 87 if (s->dual_edge & irq_mask) { 88 raise = (!!old_level) != (!!level); 89 } else { 90 if (s->event & irq_mask) { 91 /* rising-sensitive */ 92 raise = !old_level && level; 93 } else { 94 /* falling-sensitive */ 95 raise = old_level && !level; 96 } 97 } 98 if (raise) { 99 s->raw = deposit64(s->raw, irq, 1, raise); 100 } 101 } 102 s->level = deposit64(s->level, irq, 1, level); 103 aspeed_vic_update(s); 104 } 105 106 static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size) 107 { 108 AspeedVICState *s = (AspeedVICState *)opaque; 109 hwaddr n_offset; 110 uint64_t val; 111 bool high; 112 113 if (offset < AVIC_NEW_BASE_OFFSET) { 114 high = false; 115 n_offset = offset; 116 } else { 117 high = !!(offset & 0x4); 118 n_offset = (offset & ~0x4); 119 } 120 121 switch (n_offset) { 122 case 0x80: /* IRQ Status */ 123 case 0x00: 124 val = s->raw & ~s->select & s->enable; 125 break; 126 case 0x88: /* FIQ Status */ 127 case 0x04: 128 val = s->raw & s->select & s->enable; 129 break; 130 case 0x90: /* Raw Interrupt Status */ 131 case 0x08: 132 val = s->raw; 133 break; 134 case 0x98: /* Interrupt Selection */ 135 case 0x0c: 136 val = s->select; 137 break; 138 case 0xa0: /* Interrupt Enable */ 139 case 0x10: 140 val = s->enable; 141 break; 142 case 0xb0: /* Software Interrupt */ 143 case 0x18: 144 val = s->trigger; 145 break; 146 case 0xc0: /* Interrupt Sensitivity */ 147 case 0x24: 148 val = s->sense; 149 break; 150 case 0xc8: /* Interrupt Both Edge Trigger Control */ 151 case 0x28: 152 val = s->dual_edge; 153 break; 154 case 0xd0: /* Interrupt Event */ 155 case 0x2c: 156 val = s->event; 157 break; 158 case 0xe0: /* Edge Triggered Interrupt Status */ 159 val = s->raw & ~s->sense; 160 break; 161 /* Illegal */ 162 case 0xa8: /* Interrupt Enable Clear */ 163 case 0xb8: /* Software Interrupt Clear */ 164 case 0xd8: /* Edge Triggered Interrupt Clear */ 165 qemu_log_mask(LOG_GUEST_ERROR, 166 "%s: Read of write-only register with offset 0x%" 167 HWADDR_PRIx "\n", __func__, offset); 168 val = 0; 169 break; 170 default: 171 qemu_log_mask(LOG_GUEST_ERROR, 172 "%s: Bad register at offset 0x%" HWADDR_PRIx "\n", 173 __func__, offset); 174 val = 0; 175 break; 176 } 177 if (high) { 178 val = extract64(val, 32, 19); 179 } else { 180 val = extract64(val, 0, 32); 181 } 182 trace_aspeed_vic_read(offset, size, val); 183 return val; 184 } 185 186 static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data, 187 unsigned size) 188 { 189 AspeedVICState *s = (AspeedVICState *)opaque; 190 hwaddr n_offset; 191 bool high; 192 193 if (offset < AVIC_NEW_BASE_OFFSET) { 194 high = false; 195 n_offset = offset; 196 } else { 197 high = !!(offset & 0x4); 198 n_offset = (offset & ~0x4); 199 } 200 201 trace_aspeed_vic_write(offset, size, data); 202 203 /* Given we have members using separate enable/clear registers, deposit64() 204 * isn't quite the tool for the job. Instead, relocate the incoming bits to 205 * the required bit offset based on the provided access address 206 */ 207 if (high) { 208 data &= AVIC_H_MASK; 209 data <<= 32; 210 } else { 211 data &= AVIC_L_MASK; 212 } 213 214 switch (n_offset) { 215 case 0x98: /* Interrupt Selection */ 216 case 0x0c: 217 /* Register has deposit64() semantics - overwrite requested 32 bits */ 218 if (high) { 219 s->select &= AVIC_L_MASK; 220 } else { 221 s->select &= ((uint64_t) AVIC_H_MASK) << 32; 222 } 223 s->select |= data; 224 break; 225 case 0xa0: /* Interrupt Enable */ 226 case 0x10: 227 s->enable |= data; 228 break; 229 case 0xa8: /* Interrupt Enable Clear */ 230 case 0x14: 231 s->enable &= ~data; 232 break; 233 case 0xb0: /* Software Interrupt */ 234 case 0x18: 235 qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. " 236 "IRQs requested: 0x%016" PRIx64 "\n", __func__, data); 237 break; 238 case 0xb8: /* Software Interrupt Clear */ 239 case 0x1c: 240 qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. " 241 "IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data); 242 break; 243 case 0xd0: /* Interrupt Event */ 244 /* Register has deposit64() semantics - overwrite the top four valid 245 * IRQ bits, as only the top four IRQs (GPIOs) can change their event 246 * type */ 247 if (high) { 248 s->event &= ~AVIC_EVENT_W_MASK; 249 s->event |= (data & AVIC_EVENT_W_MASK); 250 } else { 251 qemu_log_mask(LOG_GUEST_ERROR, 252 "Ignoring invalid write to interrupt event register"); 253 } 254 break; 255 case 0xd8: /* Edge Triggered Interrupt Clear */ 256 case 0x38: 257 s->raw &= ~(data & ~s->sense); 258 break; 259 case 0x80: /* IRQ Status */ 260 case 0x00: 261 case 0x88: /* FIQ Status */ 262 case 0x04: 263 case 0x90: /* Raw Interrupt Status */ 264 case 0x08: 265 case 0xc0: /* Interrupt Sensitivity */ 266 case 0x24: 267 case 0xc8: /* Interrupt Both Edge Trigger Control */ 268 case 0x28: 269 case 0xe0: /* Edge Triggered Interrupt Status */ 270 qemu_log_mask(LOG_GUEST_ERROR, 271 "%s: Write of read-only register with offset 0x%" 272 HWADDR_PRIx "\n", __func__, offset); 273 break; 274 275 default: 276 qemu_log_mask(LOG_GUEST_ERROR, 277 "%s: Bad register at offset 0x%" HWADDR_PRIx "\n", 278 __func__, offset); 279 break; 280 } 281 aspeed_vic_update(s); 282 } 283 284 static const MemoryRegionOps aspeed_vic_ops = { 285 .read = aspeed_vic_read, 286 .write = aspeed_vic_write, 287 .endianness = DEVICE_LITTLE_ENDIAN, 288 .valid.min_access_size = 4, 289 .valid.max_access_size = 4, 290 .valid.unaligned = false, 291 }; 292 293 static void aspeed_vic_reset(DeviceState *dev) 294 { 295 AspeedVICState *s = ASPEED_VIC(dev); 296 297 s->level = 0; 298 s->raw = 0; 299 s->select = 0; 300 s->enable = 0; 301 s->trigger = 0; 302 s->sense = 0x1F07FFF8FFFFULL; 303 s->dual_edge = 0xF800070000ULL; 304 s->event = 0x5F07FFF8FFFFULL; 305 } 306 307 #define AVIC_IO_REGION_SIZE 0x20000 308 309 static void aspeed_vic_realize(DeviceState *dev, Error **errp) 310 { 311 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 312 AspeedVICState *s = ASPEED_VIC(dev); 313 314 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_vic_ops, s, 315 TYPE_ASPEED_VIC, AVIC_IO_REGION_SIZE); 316 317 sysbus_init_mmio(sbd, &s->iomem); 318 319 qdev_init_gpio_in(dev, aspeed_vic_set_irq, ASPEED_VIC_NR_IRQS); 320 sysbus_init_irq(sbd, &s->irq); 321 sysbus_init_irq(sbd, &s->fiq); 322 } 323 324 static const VMStateDescription vmstate_aspeed_vic = { 325 .name = "aspeed.new-vic", 326 .version_id = 1, 327 .minimum_version_id = 1, 328 .fields = (VMStateField[]) { 329 VMSTATE_UINT64(level, AspeedVICState), 330 VMSTATE_UINT64(raw, AspeedVICState), 331 VMSTATE_UINT64(select, AspeedVICState), 332 VMSTATE_UINT64(enable, AspeedVICState), 333 VMSTATE_UINT64(trigger, AspeedVICState), 334 VMSTATE_UINT64(sense, AspeedVICState), 335 VMSTATE_UINT64(dual_edge, AspeedVICState), 336 VMSTATE_UINT64(event, AspeedVICState), 337 VMSTATE_END_OF_LIST() 338 } 339 }; 340 341 static void aspeed_vic_class_init(ObjectClass *klass, void *data) 342 { 343 DeviceClass *dc = DEVICE_CLASS(klass); 344 dc->realize = aspeed_vic_realize; 345 dc->reset = aspeed_vic_reset; 346 dc->desc = "ASPEED Interrupt Controller (New)"; 347 dc->vmsd = &vmstate_aspeed_vic; 348 } 349 350 static const TypeInfo aspeed_vic_info = { 351 .name = TYPE_ASPEED_VIC, 352 .parent = TYPE_SYS_BUS_DEVICE, 353 .instance_size = sizeof(AspeedVICState), 354 .class_init = aspeed_vic_class_init, 355 }; 356 357 static void aspeed_vic_register_types(void) 358 { 359 type_register_static(&aspeed_vic_info); 360 } 361 362 type_init(aspeed_vic_register_types); 363