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