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