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 /* 18 * INTC Registers 19 * 20 * values below are offset by - 0x1000 from datasheet 21 * because its memory region is start at 0x1000 22 * 23 */ 24 REG32(GICINT128_EN, 0x000) 25 REG32(GICINT128_STATUS, 0x004) 26 REG32(GICINT129_EN, 0x100) 27 REG32(GICINT129_STATUS, 0x104) 28 REG32(GICINT130_EN, 0x200) 29 REG32(GICINT130_STATUS, 0x204) 30 REG32(GICINT131_EN, 0x300) 31 REG32(GICINT131_STATUS, 0x304) 32 REG32(GICINT132_EN, 0x400) 33 REG32(GICINT132_STATUS, 0x404) 34 REG32(GICINT133_EN, 0x500) 35 REG32(GICINT133_STATUS, 0x504) 36 REG32(GICINT134_EN, 0x600) 37 REG32(GICINT134_STATUS, 0x604) 38 REG32(GICINT135_EN, 0x700) 39 REG32(GICINT135_STATUS, 0x704) 40 REG32(GICINT136_EN, 0x800) 41 REG32(GICINT136_STATUS, 0x804) 42 REG32(GICINT192_201_EN, 0xB00) 43 REG32(GICINT192_201_STATUS, 0xB04) 44 45 static const AspeedINTCIRQ *aspeed_intc_get_irq(AspeedINTCClass *aic, 46 uint32_t reg) 47 { 48 int i; 49 50 for (i = 0; i < aic->irq_table_count; i++) { 51 if (aic->irq_table[i].enable_reg == reg || 52 aic->irq_table[i].status_reg == reg) { 53 return &aic->irq_table[i]; 54 } 55 } 56 57 /* 58 * Invalid reg. 59 */ 60 g_assert_not_reached(); 61 } 62 63 /* 64 * Update the state of an interrupt controller pin by setting 65 * the specified output pin to the given level. 66 * The input pin index should be between 0 and the number of input pins. 67 * The output pin index should be between 0 and the number of output pins. 68 */ 69 static void aspeed_intc_update(AspeedINTCState *s, int inpin_idx, 70 int outpin_idx, int level) 71 { 72 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 73 const char *name = object_get_typename(OBJECT(s)); 74 75 assert((outpin_idx < aic->num_outpins) && (inpin_idx < aic->num_inpins)); 76 77 trace_aspeed_intc_update_irq(name, inpin_idx, outpin_idx, level); 78 qemu_set_irq(s->output_pins[outpin_idx], level); 79 } 80 81 static void aspeed_intc_set_irq_handler(AspeedINTCState *s, 82 const AspeedINTCIRQ *intc_irq, 83 uint32_t select) 84 { 85 const char *name = object_get_typename(OBJECT(s)); 86 uint32_t status_reg; 87 int outpin_idx; 88 int inpin_idx; 89 90 status_reg = intc_irq->status_reg; 91 outpin_idx = intc_irq->outpin_idx; 92 inpin_idx = intc_irq->inpin_idx; 93 94 if (s->mask[inpin_idx] || s->regs[status_reg]) { 95 /* 96 * a. mask is not 0 means in ISR mode 97 * sources interrupt routine are executing. 98 * b. status register value is not 0 means previous 99 * source interrupt does not be executed, yet. 100 * 101 * save source interrupt to pending variable. 102 */ 103 s->pending[inpin_idx] |= select; 104 trace_aspeed_intc_pending_irq(name, inpin_idx, s->pending[inpin_idx]); 105 } else { 106 /* 107 * notify firmware which source interrupt are coming 108 * by setting status register 109 */ 110 s->regs[status_reg] = select; 111 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx, 112 s->regs[status_reg]); 113 aspeed_intc_update(s, inpin_idx, outpin_idx, 1); 114 } 115 } 116 117 static void aspeed_intc_set_irq_handler_multi_outpins(AspeedINTCState *s, 118 const AspeedINTCIRQ *intc_irq, uint32_t select) 119 { 120 const char *name = object_get_typename(OBJECT(s)); 121 uint32_t status_reg; 122 int num_outpins; 123 int outpin_idx; 124 int inpin_idx; 125 int i; 126 127 num_outpins = intc_irq->num_outpins; 128 status_reg = intc_irq->status_reg; 129 outpin_idx = intc_irq->outpin_idx; 130 inpin_idx = intc_irq->inpin_idx; 131 132 for (i = 0; i < num_outpins; i++) { 133 if (select & BIT(i)) { 134 if (s->mask[inpin_idx] & BIT(i) || 135 s->regs[status_reg] & BIT(i)) { 136 /* 137 * a. mask bit is not 0 means in ISR mode sources interrupt 138 * routine are executing. 139 * b. status bit is not 0 means previous source interrupt 140 * does not be executed, yet. 141 * 142 * save source interrupt to pending bit. 143 */ 144 s->pending[inpin_idx] |= BIT(i); 145 trace_aspeed_intc_pending_irq(name, inpin_idx, 146 s->pending[inpin_idx]); 147 } else { 148 /* 149 * notify firmware which source interrupt are coming 150 * by setting status bit 151 */ 152 s->regs[status_reg] |= BIT(i); 153 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i, 154 s->regs[status_reg]); 155 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1); 156 } 157 } 158 } 159 } 160 161 /* 162 * GICINT192_201 maps 1:10 to input IRQ 0 and output IRQs 0 to 9. 163 * GICINT128 to GICINT136 map 1:1 to input IRQs 1 to 9 and output 164 * IRQs 10 to 18. The value of input IRQ should be between 0 and 165 * the number of input pins. 166 */ 167 static void aspeed_intc_set_irq(void *opaque, int irq, int level) 168 { 169 AspeedINTCState *s = (AspeedINTCState *)opaque; 170 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 171 const char *name = object_get_typename(OBJECT(s)); 172 const AspeedINTCIRQ *intc_irq; 173 uint32_t select = 0; 174 uint32_t enable; 175 int num_outpins; 176 int inpin_idx; 177 int i; 178 179 assert(irq < aic->num_inpins); 180 181 intc_irq = &aic->irq_table[irq]; 182 num_outpins = intc_irq->num_outpins; 183 inpin_idx = intc_irq->inpin_idx; 184 trace_aspeed_intc_set_irq(name, inpin_idx, level); 185 enable = s->enable[inpin_idx]; 186 187 if (!level) { 188 return; 189 } 190 191 for (i = 0; i < aic->num_lines; i++) { 192 if (s->orgates[inpin_idx].levels[i]) { 193 if (enable & BIT(i)) { 194 select |= BIT(i); 195 } 196 } 197 } 198 199 if (!select) { 200 return; 201 } 202 203 trace_aspeed_intc_select(name, select); 204 if (num_outpins > 1) { 205 aspeed_intc_set_irq_handler_multi_outpins(s, intc_irq, select); 206 } else { 207 aspeed_intc_set_irq_handler(s, intc_irq, select); 208 } 209 } 210 211 static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset, 212 uint64_t data) 213 { 214 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 215 const char *name = object_get_typename(OBJECT(s)); 216 const AspeedINTCIRQ *intc_irq; 217 uint32_t reg = offset >> 2; 218 uint32_t old_enable; 219 uint32_t change; 220 int inpin_idx; 221 222 intc_irq = aspeed_intc_get_irq(aic, reg); 223 inpin_idx = intc_irq->inpin_idx; 224 225 assert(inpin_idx < aic->num_inpins); 226 227 /* 228 * The enable registers are used to enable source interrupts. 229 * They also handle masking and unmasking of source interrupts 230 * during the execution of the source ISR. 231 */ 232 233 /* disable all source interrupt */ 234 if (!data && !s->enable[inpin_idx]) { 235 s->regs[reg] = data; 236 return; 237 } 238 239 old_enable = s->enable[inpin_idx]; 240 s->enable[inpin_idx] |= data; 241 242 /* enable new source interrupt */ 243 if (old_enable != s->enable[inpin_idx]) { 244 trace_aspeed_intc_enable(name, s->enable[inpin_idx]); 245 s->regs[reg] = data; 246 return; 247 } 248 249 /* mask and unmask source interrupt */ 250 change = s->regs[reg] ^ data; 251 if (change & data) { 252 s->mask[inpin_idx] &= ~change; 253 trace_aspeed_intc_unmask(name, change, s->mask[inpin_idx]); 254 } else { 255 s->mask[inpin_idx] |= change; 256 trace_aspeed_intc_mask(name, change, s->mask[inpin_idx]); 257 } 258 259 s->regs[reg] = data; 260 } 261 262 static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset, 263 uint64_t data) 264 { 265 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 266 const char *name = object_get_typename(OBJECT(s)); 267 const AspeedINTCIRQ *intc_irq; 268 uint32_t reg = offset >> 2; 269 int outpin_idx; 270 int inpin_idx; 271 272 if (!data) { 273 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__); 274 return; 275 } 276 277 intc_irq = aspeed_intc_get_irq(aic, reg); 278 outpin_idx = intc_irq->outpin_idx; 279 inpin_idx = intc_irq->inpin_idx; 280 281 assert(inpin_idx < aic->num_inpins); 282 283 /* clear status */ 284 s->regs[reg] &= ~data; 285 286 /* 287 * These status registers are used for notify sources ISR are executed. 288 * If one source ISR is executed, it will clear one bit. 289 * If it clear all bits, it means to initialize this register status 290 * rather than sources ISR are executed. 291 */ 292 if (data == 0xffffffff) { 293 return; 294 } 295 296 /* All source ISR execution are done */ 297 if (!s->regs[reg]) { 298 trace_aspeed_intc_all_isr_done(name, inpin_idx); 299 if (s->pending[inpin_idx]) { 300 /* 301 * handle pending source interrupt 302 * notify firmware which source interrupt are pending 303 * by setting status register 304 */ 305 s->regs[reg] = s->pending[inpin_idx]; 306 s->pending[inpin_idx] = 0; 307 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx, 308 s->regs[reg]); 309 aspeed_intc_update(s, inpin_idx, outpin_idx, 1); 310 } else { 311 /* clear irq */ 312 trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx, 0); 313 aspeed_intc_update(s, inpin_idx, outpin_idx, 0); 314 } 315 } 316 } 317 318 static void aspeed_intc_status_handler_multi_outpins(AspeedINTCState *s, 319 hwaddr offset, uint64_t data) 320 { 321 const char *name = object_get_typename(OBJECT(s)); 322 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 323 const AspeedINTCIRQ *intc_irq; 324 uint32_t reg = offset >> 2; 325 int num_outpins; 326 int outpin_idx; 327 int inpin_idx; 328 int i; 329 330 if (!data) { 331 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__); 332 return; 333 } 334 335 intc_irq = aspeed_intc_get_irq(aic, reg); 336 num_outpins = intc_irq->num_outpins; 337 outpin_idx = intc_irq->outpin_idx; 338 inpin_idx = intc_irq->inpin_idx; 339 assert(inpin_idx < aic->num_inpins); 340 341 /* clear status */ 342 s->regs[reg] &= ~data; 343 344 /* 345 * The status registers are used for notify sources ISR are executed. 346 * If one source ISR is executed, it will clear one bit. 347 * If it clear all bits, it means to initialize this register status 348 * rather than sources ISR are executed. 349 */ 350 if (data == 0xffffffff) { 351 return; 352 } 353 354 for (i = 0; i < num_outpins; i++) { 355 /* All source ISR executions are done from a specific bit */ 356 if (data & BIT(i)) { 357 trace_aspeed_intc_all_isr_done_bit(name, inpin_idx, i); 358 if (s->pending[inpin_idx] & BIT(i)) { 359 /* 360 * Handle pending source interrupt. 361 * Notify firmware which source interrupt is pending 362 * by setting the status bit. 363 */ 364 s->regs[reg] |= BIT(i); 365 s->pending[inpin_idx] &= ~BIT(i); 366 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i, 367 s->regs[reg]); 368 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1); 369 } else { 370 /* clear irq for the specific bit */ 371 trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx + i, 0); 372 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 0); 373 } 374 } 375 } 376 } 377 378 static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size) 379 { 380 AspeedINTCState *s = ASPEED_INTC(opaque); 381 const char *name = object_get_typename(OBJECT(s)); 382 uint32_t reg = offset >> 2; 383 uint32_t value = 0; 384 385 value = s->regs[reg]; 386 trace_aspeed_intc_read(name, offset, size, value); 387 388 return value; 389 } 390 391 static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data, 392 unsigned size) 393 { 394 AspeedINTCState *s = ASPEED_INTC(opaque); 395 const char *name = object_get_typename(OBJECT(s)); 396 uint32_t reg = offset >> 2; 397 398 trace_aspeed_intc_write(name, offset, size, data); 399 400 switch (reg) { 401 case R_GICINT128_EN: 402 case R_GICINT129_EN: 403 case R_GICINT130_EN: 404 case R_GICINT131_EN: 405 case R_GICINT132_EN: 406 case R_GICINT133_EN: 407 case R_GICINT134_EN: 408 case R_GICINT135_EN: 409 case R_GICINT136_EN: 410 case R_GICINT192_201_EN: 411 aspeed_intc_enable_handler(s, offset, data); 412 break; 413 case R_GICINT128_STATUS: 414 case R_GICINT129_STATUS: 415 case R_GICINT130_STATUS: 416 case R_GICINT131_STATUS: 417 case R_GICINT132_STATUS: 418 case R_GICINT133_STATUS: 419 case R_GICINT134_STATUS: 420 case R_GICINT135_STATUS: 421 case R_GICINT136_STATUS: 422 aspeed_intc_status_handler(s, offset, data); 423 break; 424 case R_GICINT192_201_STATUS: 425 aspeed_intc_status_handler_multi_outpins(s, offset, data); 426 break; 427 default: 428 s->regs[reg] = data; 429 break; 430 } 431 432 return; 433 } 434 435 static const MemoryRegionOps aspeed_intc_ops = { 436 .read = aspeed_intc_read, 437 .write = aspeed_intc_write, 438 .endianness = DEVICE_LITTLE_ENDIAN, 439 .valid = { 440 .min_access_size = 4, 441 .max_access_size = 4, 442 } 443 }; 444 445 static void aspeed_intc_instance_init(Object *obj) 446 { 447 AspeedINTCState *s = ASPEED_INTC(obj); 448 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 449 int i; 450 451 assert(aic->num_inpins <= ASPEED_INTC_MAX_INPINS); 452 for (i = 0; i < aic->num_inpins; i++) { 453 object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i], 454 TYPE_OR_IRQ); 455 object_property_set_int(OBJECT(&s->orgates[i]), "num-lines", 456 aic->num_lines, &error_abort); 457 } 458 } 459 460 static void aspeed_intc_reset(DeviceState *dev) 461 { 462 AspeedINTCState *s = ASPEED_INTC(dev); 463 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 464 465 memset(s->regs, 0, aic->nr_regs << 2); 466 memset(s->enable, 0, sizeof(s->enable)); 467 memset(s->mask, 0, sizeof(s->mask)); 468 memset(s->pending, 0, sizeof(s->pending)); 469 } 470 471 static void aspeed_intc_realize(DeviceState *dev, Error **errp) 472 { 473 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 474 AspeedINTCState *s = ASPEED_INTC(dev); 475 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 476 int i; 477 478 memory_region_init(&s->iomem_container, OBJECT(s), 479 TYPE_ASPEED_INTC ".container", aic->mem_size); 480 481 sysbus_init_mmio(sbd, &s->iomem_container); 482 483 s->regs = g_new(uint32_t, aic->nr_regs); 484 memory_region_init_io(&s->iomem, OBJECT(s), aic->reg_ops, s, 485 TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2); 486 487 memory_region_add_subregion(&s->iomem_container, aic->reg_offset, 488 &s->iomem); 489 490 qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_inpins); 491 492 for (i = 0; i < aic->num_inpins; i++) { 493 if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) { 494 return; 495 } 496 } 497 498 for (i = 0; i < aic->num_outpins; i++) { 499 sysbus_init_irq(sbd, &s->output_pins[i]); 500 } 501 } 502 503 static void aspeed_intc_unrealize(DeviceState *dev) 504 { 505 AspeedINTCState *s = ASPEED_INTC(dev); 506 507 g_free(s->regs); 508 s->regs = NULL; 509 } 510 511 static void aspeed_intc_class_init(ObjectClass *klass, void *data) 512 { 513 DeviceClass *dc = DEVICE_CLASS(klass); 514 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); 515 516 dc->desc = "ASPEED INTC Controller"; 517 dc->realize = aspeed_intc_realize; 518 dc->unrealize = aspeed_intc_unrealize; 519 device_class_set_legacy_reset(dc, aspeed_intc_reset); 520 dc->vmsd = NULL; 521 522 aic->reg_ops = &aspeed_intc_ops; 523 } 524 525 static const TypeInfo aspeed_intc_info = { 526 .name = TYPE_ASPEED_INTC, 527 .parent = TYPE_SYS_BUS_DEVICE, 528 .instance_init = aspeed_intc_instance_init, 529 .instance_size = sizeof(AspeedINTCState), 530 .class_init = aspeed_intc_class_init, 531 .class_size = sizeof(AspeedINTCClass), 532 .abstract = true, 533 }; 534 535 static AspeedINTCIRQ aspeed_2700_intc_irqs[ASPEED_INTC_MAX_INPINS] = { 536 {0, 0, 10, R_GICINT192_201_EN, R_GICINT192_201_STATUS}, 537 {1, 10, 1, R_GICINT128_EN, R_GICINT128_STATUS}, 538 {2, 11, 1, R_GICINT129_EN, R_GICINT129_STATUS}, 539 {3, 12, 1, R_GICINT130_EN, R_GICINT130_STATUS}, 540 {4, 13, 1, R_GICINT131_EN, R_GICINT131_STATUS}, 541 {5, 14, 1, R_GICINT132_EN, R_GICINT132_STATUS}, 542 {6, 15, 1, R_GICINT133_EN, R_GICINT133_STATUS}, 543 {7, 16, 1, R_GICINT134_EN, R_GICINT134_STATUS}, 544 {8, 17, 1, R_GICINT135_EN, R_GICINT135_STATUS}, 545 {9, 18, 1, R_GICINT136_EN, R_GICINT136_STATUS}, 546 }; 547 548 static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data) 549 { 550 DeviceClass *dc = DEVICE_CLASS(klass); 551 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); 552 553 dc->desc = "ASPEED 2700 INTC Controller"; 554 aic->num_lines = 32; 555 aic->num_inpins = 10; 556 aic->num_outpins = 19; 557 aic->mem_size = 0x4000; 558 aic->nr_regs = 0xB08 >> 2; 559 aic->reg_offset = 0x1000; 560 aic->irq_table = aspeed_2700_intc_irqs; 561 aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intc_irqs); 562 } 563 564 static const TypeInfo aspeed_2700_intc_info = { 565 .name = TYPE_ASPEED_2700_INTC, 566 .parent = TYPE_ASPEED_INTC, 567 .class_init = aspeed_2700_intc_class_init, 568 }; 569 570 static void aspeed_intc_register_types(void) 571 { 572 type_register_static(&aspeed_intc_info); 573 type_register_static(&aspeed_2700_intc_info); 574 } 575 576 type_init(aspeed_intc_register_types); 577