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 43 #define GICINT_STATUS_BASE R_GICINT128_STATUS 44 45 static void aspeed_intc_update(AspeedINTCState *s, int irq, int level) 46 { 47 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 48 49 if (irq >= aic->num_ints) { 50 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 51 __func__, irq); 52 return; 53 } 54 55 trace_aspeed_intc_update_irq(irq, level); 56 qemu_set_irq(s->output_pins[irq], level); 57 } 58 59 /* 60 * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804. 61 * Utilize "address & 0x0f00" to get the irq and irq output pin index 62 * The value of irq should be 0 to num_ints. 63 * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on. 64 */ 65 static void aspeed_intc_set_irq(void *opaque, int irq, int level) 66 { 67 AspeedINTCState *s = (AspeedINTCState *)opaque; 68 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 69 uint32_t status_reg = GICINT_STATUS_BASE + ((0x100 * irq) >> 2); 70 uint32_t select = 0; 71 uint32_t enable; 72 int i; 73 74 if (irq >= aic->num_ints) { 75 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 76 __func__, irq); 77 return; 78 } 79 80 trace_aspeed_intc_set_irq(irq, level); 81 enable = s->enable[irq]; 82 83 if (!level) { 84 return; 85 } 86 87 for (i = 0; i < aic->num_lines; i++) { 88 if (s->orgates[irq].levels[i]) { 89 if (enable & BIT(i)) { 90 select |= BIT(i); 91 } 92 } 93 } 94 95 if (!select) { 96 return; 97 } 98 99 trace_aspeed_intc_select(select); 100 101 if (s->mask[irq] || s->regs[status_reg]) { 102 /* 103 * a. mask is not 0 means in ISR mode 104 * sources interrupt routine are executing. 105 * b. status register value is not 0 means previous 106 * source interrupt does not be executed, yet. 107 * 108 * save source interrupt to pending variable. 109 */ 110 s->pending[irq] |= select; 111 trace_aspeed_intc_pending_irq(irq, s->pending[irq]); 112 } else { 113 /* 114 * notify firmware which source interrupt are coming 115 * by setting status register 116 */ 117 s->regs[status_reg] = select; 118 trace_aspeed_intc_trigger_irq(irq, s->regs[status_reg]); 119 aspeed_intc_update(s, irq, 1); 120 } 121 } 122 123 static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset, 124 uint64_t data) 125 { 126 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 127 uint32_t reg = offset >> 2; 128 uint32_t old_enable; 129 uint32_t change; 130 uint32_t irq; 131 132 irq = (offset & 0x0f00) >> 8; 133 134 if (irq >= aic->num_ints) { 135 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 136 __func__, irq); 137 return; 138 } 139 140 /* 141 * The enable registers are used to enable source interrupts. 142 * They also handle masking and unmasking of source interrupts 143 * during the execution of the source ISR. 144 */ 145 146 /* disable all source interrupt */ 147 if (!data && !s->enable[irq]) { 148 s->regs[reg] = data; 149 return; 150 } 151 152 old_enable = s->enable[irq]; 153 s->enable[irq] |= data; 154 155 /* enable new source interrupt */ 156 if (old_enable != s->enable[irq]) { 157 trace_aspeed_intc_enable(s->enable[irq]); 158 s->regs[reg] = data; 159 return; 160 } 161 162 /* mask and unmask source interrupt */ 163 change = s->regs[reg] ^ data; 164 if (change & data) { 165 s->mask[irq] &= ~change; 166 trace_aspeed_intc_unmask(change, s->mask[irq]); 167 } else { 168 s->mask[irq] |= change; 169 trace_aspeed_intc_mask(change, s->mask[irq]); 170 } 171 172 s->regs[reg] = data; 173 } 174 175 static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset, 176 uint64_t data) 177 { 178 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 179 uint32_t reg = offset >> 2; 180 uint32_t irq; 181 182 if (!data) { 183 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__); 184 return; 185 } 186 187 irq = (offset & 0x0f00) >> 8; 188 189 if (irq >= aic->num_ints) { 190 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 191 __func__, irq); 192 return; 193 } 194 195 /* clear status */ 196 s->regs[reg] &= ~data; 197 198 /* 199 * These status registers are used for notify sources ISR are executed. 200 * If one source ISR is executed, it will clear one bit. 201 * If it clear all bits, it means to initialize this register status 202 * rather than sources ISR are executed. 203 */ 204 if (data == 0xffffffff) { 205 return; 206 } 207 208 /* All source ISR execution are done */ 209 if (!s->regs[reg]) { 210 trace_aspeed_intc_all_isr_done(irq); 211 if (s->pending[irq]) { 212 /* 213 * handle pending source interrupt 214 * notify firmware which source interrupt are pending 215 * by setting status register 216 */ 217 s->regs[reg] = s->pending[irq]; 218 s->pending[irq] = 0; 219 trace_aspeed_intc_trigger_irq(irq, s->regs[reg]); 220 aspeed_intc_update(s, irq, 1); 221 } else { 222 /* clear irq */ 223 trace_aspeed_intc_clear_irq(irq, 0); 224 aspeed_intc_update(s, irq, 0); 225 } 226 } 227 } 228 229 static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size) 230 { 231 AspeedINTCState *s = ASPEED_INTC(opaque); 232 uint32_t reg = offset >> 2; 233 uint32_t value = 0; 234 235 value = s->regs[reg]; 236 trace_aspeed_intc_read(offset, size, value); 237 238 return value; 239 } 240 241 static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data, 242 unsigned size) 243 { 244 AspeedINTCState *s = ASPEED_INTC(opaque); 245 uint32_t reg = offset >> 2; 246 247 trace_aspeed_intc_write(offset, size, data); 248 249 switch (reg) { 250 case R_GICINT128_EN: 251 case R_GICINT129_EN: 252 case R_GICINT130_EN: 253 case R_GICINT131_EN: 254 case R_GICINT132_EN: 255 case R_GICINT133_EN: 256 case R_GICINT134_EN: 257 case R_GICINT135_EN: 258 case R_GICINT136_EN: 259 aspeed_intc_enable_handler(s, offset, data); 260 break; 261 case R_GICINT128_STATUS: 262 case R_GICINT129_STATUS: 263 case R_GICINT130_STATUS: 264 case R_GICINT131_STATUS: 265 case R_GICINT132_STATUS: 266 case R_GICINT133_STATUS: 267 case R_GICINT134_STATUS: 268 case R_GICINT135_STATUS: 269 case R_GICINT136_STATUS: 270 aspeed_intc_status_handler(s, offset, data); 271 break; 272 default: 273 s->regs[reg] = data; 274 break; 275 } 276 277 return; 278 } 279 280 static const MemoryRegionOps aspeed_intc_ops = { 281 .read = aspeed_intc_read, 282 .write = aspeed_intc_write, 283 .endianness = DEVICE_LITTLE_ENDIAN, 284 .valid = { 285 .min_access_size = 4, 286 .max_access_size = 4, 287 } 288 }; 289 290 static void aspeed_intc_instance_init(Object *obj) 291 { 292 AspeedINTCState *s = ASPEED_INTC(obj); 293 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 294 int i; 295 296 assert(aic->num_ints <= ASPEED_INTC_NR_INTS); 297 for (i = 0; i < aic->num_ints; i++) { 298 object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i], 299 TYPE_OR_IRQ); 300 object_property_set_int(OBJECT(&s->orgates[i]), "num-lines", 301 aic->num_lines, &error_abort); 302 } 303 } 304 305 static void aspeed_intc_reset(DeviceState *dev) 306 { 307 AspeedINTCState *s = ASPEED_INTC(dev); 308 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 309 310 memset(s->regs, 0, aic->nr_regs << 2); 311 memset(s->enable, 0, sizeof(s->enable)); 312 memset(s->mask, 0, sizeof(s->mask)); 313 memset(s->pending, 0, sizeof(s->pending)); 314 } 315 316 static void aspeed_intc_realize(DeviceState *dev, Error **errp) 317 { 318 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 319 AspeedINTCState *s = ASPEED_INTC(dev); 320 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 321 int i; 322 323 memory_region_init(&s->iomem_container, OBJECT(s), 324 TYPE_ASPEED_INTC ".container", aic->mem_size); 325 326 sysbus_init_mmio(sbd, &s->iomem_container); 327 328 s->regs = g_new(uint32_t, aic->nr_regs); 329 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s, 330 TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2); 331 332 memory_region_add_subregion(&s->iomem_container, aic->reg_offset, 333 &s->iomem); 334 335 qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_ints); 336 337 for (i = 0; i < aic->num_ints; i++) { 338 if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) { 339 return; 340 } 341 sysbus_init_irq(sbd, &s->output_pins[i]); 342 } 343 } 344 345 static void aspeed_intc_unrealize(DeviceState *dev) 346 { 347 AspeedINTCState *s = ASPEED_INTC(dev); 348 349 g_free(s->regs); 350 s->regs = NULL; 351 } 352 353 static void aspeed_intc_class_init(ObjectClass *klass, void *data) 354 { 355 DeviceClass *dc = DEVICE_CLASS(klass); 356 357 dc->desc = "ASPEED INTC Controller"; 358 dc->realize = aspeed_intc_realize; 359 dc->unrealize = aspeed_intc_unrealize; 360 device_class_set_legacy_reset(dc, aspeed_intc_reset); 361 dc->vmsd = NULL; 362 } 363 364 static const TypeInfo aspeed_intc_info = { 365 .name = TYPE_ASPEED_INTC, 366 .parent = TYPE_SYS_BUS_DEVICE, 367 .instance_init = aspeed_intc_instance_init, 368 .instance_size = sizeof(AspeedINTCState), 369 .class_init = aspeed_intc_class_init, 370 .class_size = sizeof(AspeedINTCClass), 371 .abstract = true, 372 }; 373 374 static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data) 375 { 376 DeviceClass *dc = DEVICE_CLASS(klass); 377 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); 378 379 dc->desc = "ASPEED 2700 INTC Controller"; 380 aic->num_lines = 32; 381 aic->num_ints = 9; 382 aic->mem_size = 0x4000; 383 aic->nr_regs = 0x808 >> 2; 384 aic->reg_offset = 0x1000; 385 } 386 387 static const TypeInfo aspeed_2700_intc_info = { 388 .name = TYPE_ASPEED_2700_INTC, 389 .parent = TYPE_ASPEED_INTC, 390 .class_init = aspeed_2700_intc_class_init, 391 }; 392 393 static void aspeed_intc_register_types(void) 394 { 395 type_register_static(&aspeed_intc_info); 396 type_register_static(&aspeed_2700_intc_info); 397 } 398 399 type_init(aspeed_intc_register_types); 400