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