1 /* 2 * ASPEED INTC Controller 3 * 4 * Copyright (C) 2024 ASPEED Technology Inc. 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9 #include "qemu/osdep.h" 10 #include "hw/intc/aspeed_intc.h" 11 #include "hw/irq.h" 12 #include "qemu/log.h" 13 #include "trace.h" 14 #include "hw/registerfields.h" 15 #include "qapi/error.h" 16 17 /* INTC Registers */ 18 REG32(GICINT128_EN, 0x1000) 19 REG32(GICINT128_STATUS, 0x1004) 20 REG32(GICINT129_EN, 0x1100) 21 REG32(GICINT129_STATUS, 0x1104) 22 REG32(GICINT130_EN, 0x1200) 23 REG32(GICINT130_STATUS, 0x1204) 24 REG32(GICINT131_EN, 0x1300) 25 REG32(GICINT131_STATUS, 0x1304) 26 REG32(GICINT132_EN, 0x1400) 27 REG32(GICINT132_STATUS, 0x1404) 28 REG32(GICINT133_EN, 0x1500) 29 REG32(GICINT133_STATUS, 0x1504) 30 REG32(GICINT134_EN, 0x1600) 31 REG32(GICINT134_STATUS, 0x1604) 32 REG32(GICINT135_EN, 0x1700) 33 REG32(GICINT135_STATUS, 0x1704) 34 REG32(GICINT136_EN, 0x1800) 35 REG32(GICINT136_STATUS, 0x1804) 36 37 #define GICINT_STATUS_BASE R_GICINT128_STATUS 38 39 static void aspeed_intc_update(AspeedINTCState *s, int irq, int level) 40 { 41 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 42 43 if (irq >= aic->num_ints) { 44 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 45 __func__, irq); 46 return; 47 } 48 49 trace_aspeed_intc_update_irq(irq, level); 50 qemu_set_irq(s->output_pins[irq], level); 51 } 52 53 /* 54 * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804. 55 * Utilize "address & 0x0f00" to get the irq and irq output pin index 56 * The value of irq should be 0 to num_ints. 57 * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on. 58 */ 59 static void aspeed_intc_set_irq(void *opaque, int irq, int level) 60 { 61 AspeedINTCState *s = (AspeedINTCState *)opaque; 62 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 63 uint32_t status_addr = GICINT_STATUS_BASE + ((0x100 * irq) >> 2); 64 uint32_t select = 0; 65 uint32_t enable; 66 int i; 67 68 if (irq >= aic->num_ints) { 69 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 70 __func__, irq); 71 return; 72 } 73 74 trace_aspeed_intc_set_irq(irq, level); 75 enable = s->enable[irq]; 76 77 if (!level) { 78 return; 79 } 80 81 for (i = 0; i < aic->num_lines; i++) { 82 if (s->orgates[irq].levels[i]) { 83 if (enable & BIT(i)) { 84 select |= BIT(i); 85 } 86 } 87 } 88 89 if (!select) { 90 return; 91 } 92 93 trace_aspeed_intc_select(select); 94 95 if (s->mask[irq] || s->regs[status_addr]) { 96 /* 97 * a. mask is not 0 means in ISR mode 98 * sources interrupt routine are executing. 99 * b. status register value is not 0 means previous 100 * source interrupt does not be executed, yet. 101 * 102 * save source interrupt to pending variable. 103 */ 104 s->pending[irq] |= select; 105 trace_aspeed_intc_pending_irq(irq, s->pending[irq]); 106 } else { 107 /* 108 * notify firmware which source interrupt are coming 109 * by setting status register 110 */ 111 s->regs[status_addr] = select; 112 trace_aspeed_intc_trigger_irq(irq, s->regs[status_addr]); 113 aspeed_intc_update(s, irq, 1); 114 } 115 } 116 117 static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size) 118 { 119 AspeedINTCState *s = ASPEED_INTC(opaque); 120 uint32_t addr = offset >> 2; 121 uint32_t value = 0; 122 123 if (addr >= ASPEED_INTC_NR_REGS) { 124 qemu_log_mask(LOG_GUEST_ERROR, 125 "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 126 __func__, offset); 127 return 0; 128 } 129 130 value = s->regs[addr]; 131 trace_aspeed_intc_read(offset, size, value); 132 133 return value; 134 } 135 136 static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data, 137 unsigned size) 138 { 139 AspeedINTCState *s = ASPEED_INTC(opaque); 140 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 141 uint32_t addr = offset >> 2; 142 uint32_t old_enable; 143 uint32_t change; 144 uint32_t irq; 145 146 if (addr >= ASPEED_INTC_NR_REGS) { 147 qemu_log_mask(LOG_GUEST_ERROR, 148 "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 149 __func__, offset); 150 return; 151 } 152 153 trace_aspeed_intc_write(offset, size, data); 154 155 switch (addr) { 156 case R_GICINT128_EN: 157 case R_GICINT129_EN: 158 case R_GICINT130_EN: 159 case R_GICINT131_EN: 160 case R_GICINT132_EN: 161 case R_GICINT133_EN: 162 case R_GICINT134_EN: 163 case R_GICINT135_EN: 164 case R_GICINT136_EN: 165 irq = (offset & 0x0f00) >> 8; 166 167 if (irq >= aic->num_ints) { 168 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 169 __func__, irq); 170 return; 171 } 172 173 /* 174 * These registers are used for enable sources interrupt and 175 * mask and unmask source interrupt while executing source ISR. 176 */ 177 178 /* disable all source interrupt */ 179 if (!data && !s->enable[irq]) { 180 s->regs[addr] = data; 181 return; 182 } 183 184 old_enable = s->enable[irq]; 185 s->enable[irq] |= data; 186 187 /* enable new source interrupt */ 188 if (old_enable != s->enable[irq]) { 189 trace_aspeed_intc_enable(s->enable[irq]); 190 s->regs[addr] = data; 191 return; 192 } 193 194 /* mask and unmask source interrupt */ 195 change = s->regs[addr] ^ data; 196 if (change & data) { 197 s->mask[irq] &= ~change; 198 trace_aspeed_intc_unmask(change, s->mask[irq]); 199 } else { 200 s->mask[irq] |= change; 201 trace_aspeed_intc_mask(change, s->mask[irq]); 202 } 203 s->regs[addr] = data; 204 break; 205 case R_GICINT128_STATUS: 206 case R_GICINT129_STATUS: 207 case R_GICINT130_STATUS: 208 case R_GICINT131_STATUS: 209 case R_GICINT132_STATUS: 210 case R_GICINT133_STATUS: 211 case R_GICINT134_STATUS: 212 case R_GICINT135_STATUS: 213 case R_GICINT136_STATUS: 214 irq = (offset & 0x0f00) >> 8; 215 216 if (irq >= aic->num_ints) { 217 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 218 __func__, irq); 219 return; 220 } 221 222 /* clear status */ 223 s->regs[addr] &= ~data; 224 225 /* 226 * These status registers are used for notify sources ISR are executed. 227 * If one source ISR is executed, it will clear one bit. 228 * If it clear all bits, it means to initialize this register status 229 * rather than sources ISR are executed. 230 */ 231 if (data == 0xffffffff) { 232 return; 233 } 234 235 /* All source ISR execution are done */ 236 if (!s->regs[addr]) { 237 trace_aspeed_intc_all_isr_done(irq); 238 if (s->pending[irq]) { 239 /* 240 * handle pending source interrupt 241 * notify firmware which source interrupt are pending 242 * by setting status register 243 */ 244 s->regs[addr] = s->pending[irq]; 245 s->pending[irq] = 0; 246 trace_aspeed_intc_trigger_irq(irq, s->regs[addr]); 247 aspeed_intc_update(s, irq, 1); 248 } else { 249 /* clear irq */ 250 trace_aspeed_intc_clear_irq(irq, 0); 251 aspeed_intc_update(s, irq, 0); 252 } 253 } 254 break; 255 default: 256 s->regs[addr] = data; 257 break; 258 } 259 260 return; 261 } 262 263 static const MemoryRegionOps aspeed_intc_ops = { 264 .read = aspeed_intc_read, 265 .write = aspeed_intc_write, 266 .endianness = DEVICE_LITTLE_ENDIAN, 267 .valid = { 268 .min_access_size = 4, 269 .max_access_size = 4, 270 } 271 }; 272 273 static void aspeed_intc_instance_init(Object *obj) 274 { 275 AspeedINTCState *s = ASPEED_INTC(obj); 276 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 277 int i; 278 279 assert(aic->num_ints <= ASPEED_INTC_NR_INTS); 280 for (i = 0; i < aic->num_ints; i++) { 281 object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i], 282 TYPE_OR_IRQ); 283 object_property_set_int(OBJECT(&s->orgates[i]), "num-lines", 284 aic->num_lines, &error_abort); 285 } 286 } 287 288 static void aspeed_intc_reset(DeviceState *dev) 289 { 290 AspeedINTCState *s = ASPEED_INTC(dev); 291 292 memset(s->regs, 0, sizeof(s->regs)); 293 memset(s->enable, 0, sizeof(s->enable)); 294 memset(s->mask, 0, sizeof(s->mask)); 295 memset(s->pending, 0, sizeof(s->pending)); 296 } 297 298 static void aspeed_intc_realize(DeviceState *dev, Error **errp) 299 { 300 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 301 AspeedINTCState *s = ASPEED_INTC(dev); 302 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 303 int i; 304 305 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s, 306 TYPE_ASPEED_INTC ".regs", ASPEED_INTC_NR_REGS << 2); 307 308 sysbus_init_mmio(sbd, &s->iomem); 309 qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_ints); 310 311 for (i = 0; i < aic->num_ints; i++) { 312 if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) { 313 return; 314 } 315 sysbus_init_irq(sbd, &s->output_pins[i]); 316 } 317 } 318 319 static void aspeed_intc_class_init(ObjectClass *klass, void *data) 320 { 321 DeviceClass *dc = DEVICE_CLASS(klass); 322 323 dc->desc = "ASPEED INTC Controller"; 324 dc->realize = aspeed_intc_realize; 325 dc->reset = aspeed_intc_reset; 326 dc->vmsd = NULL; 327 } 328 329 static const TypeInfo aspeed_intc_info = { 330 .name = TYPE_ASPEED_INTC, 331 .parent = TYPE_SYS_BUS_DEVICE, 332 .instance_init = aspeed_intc_instance_init, 333 .instance_size = sizeof(AspeedINTCState), 334 .class_init = aspeed_intc_class_init, 335 .class_size = sizeof(AspeedINTCClass), 336 .abstract = true, 337 }; 338 339 static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data) 340 { 341 DeviceClass *dc = DEVICE_CLASS(klass); 342 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); 343 344 dc->desc = "ASPEED 2700 INTC Controller"; 345 aic->num_lines = 32; 346 aic->num_ints = 9; 347 } 348 349 static const TypeInfo aspeed_2700_intc_info = { 350 .name = TYPE_ASPEED_2700_INTC, 351 .parent = TYPE_ASPEED_INTC, 352 .class_init = aspeed_2700_intc_class_init, 353 }; 354 355 static void aspeed_intc_register_types(void) 356 { 357 type_register_static(&aspeed_intc_info); 358 type_register_static(&aspeed_2700_intc_info); 359 } 360 361 type_init(aspeed_intc_register_types); 362