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_reg = 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_reg]) { 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_reg] = select; 112 trace_aspeed_intc_trigger_irq(irq, s->regs[status_reg]); 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 reg = offset >> 2; 121 uint32_t value = 0; 122 123 value = s->regs[reg]; 124 trace_aspeed_intc_read(offset, size, value); 125 126 return value; 127 } 128 129 static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data, 130 unsigned size) 131 { 132 AspeedINTCState *s = ASPEED_INTC(opaque); 133 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 134 uint32_t reg = offset >> 2; 135 uint32_t old_enable; 136 uint32_t change; 137 uint32_t irq; 138 139 trace_aspeed_intc_write(offset, size, data); 140 141 switch (reg) { 142 case R_GICINT128_EN: 143 case R_GICINT129_EN: 144 case R_GICINT130_EN: 145 case R_GICINT131_EN: 146 case R_GICINT132_EN: 147 case R_GICINT133_EN: 148 case R_GICINT134_EN: 149 case R_GICINT135_EN: 150 case R_GICINT136_EN: 151 irq = (offset & 0x0f00) >> 8; 152 153 if (irq >= aic->num_ints) { 154 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 155 __func__, irq); 156 return; 157 } 158 159 /* 160 * These registers are used for enable sources interrupt and 161 * mask and unmask source interrupt while executing source ISR. 162 */ 163 164 /* disable all source interrupt */ 165 if (!data && !s->enable[irq]) { 166 s->regs[reg] = data; 167 return; 168 } 169 170 old_enable = s->enable[irq]; 171 s->enable[irq] |= data; 172 173 /* enable new source interrupt */ 174 if (old_enable != s->enable[irq]) { 175 trace_aspeed_intc_enable(s->enable[irq]); 176 s->regs[reg] = data; 177 return; 178 } 179 180 /* mask and unmask source interrupt */ 181 change = s->regs[reg] ^ data; 182 if (change & data) { 183 s->mask[irq] &= ~change; 184 trace_aspeed_intc_unmask(change, s->mask[irq]); 185 } else { 186 s->mask[irq] |= change; 187 trace_aspeed_intc_mask(change, s->mask[irq]); 188 } 189 s->regs[reg] = data; 190 break; 191 case R_GICINT128_STATUS: 192 case R_GICINT129_STATUS: 193 case R_GICINT130_STATUS: 194 case R_GICINT131_STATUS: 195 case R_GICINT132_STATUS: 196 case R_GICINT133_STATUS: 197 case R_GICINT134_STATUS: 198 case R_GICINT135_STATUS: 199 case R_GICINT136_STATUS: 200 irq = (offset & 0x0f00) >> 8; 201 202 if (irq >= aic->num_ints) { 203 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 204 __func__, irq); 205 return; 206 } 207 208 /* clear status */ 209 s->regs[reg] &= ~data; 210 211 /* 212 * These status registers are used for notify sources ISR are executed. 213 * If one source ISR is executed, it will clear one bit. 214 * If it clear all bits, it means to initialize this register status 215 * rather than sources ISR are executed. 216 */ 217 if (data == 0xffffffff) { 218 return; 219 } 220 221 /* All source ISR execution are done */ 222 if (!s->regs[reg]) { 223 trace_aspeed_intc_all_isr_done(irq); 224 if (s->pending[irq]) { 225 /* 226 * handle pending source interrupt 227 * notify firmware which source interrupt are pending 228 * by setting status register 229 */ 230 s->regs[reg] = s->pending[irq]; 231 s->pending[irq] = 0; 232 trace_aspeed_intc_trigger_irq(irq, s->regs[reg]); 233 aspeed_intc_update(s, irq, 1); 234 } else { 235 /* clear irq */ 236 trace_aspeed_intc_clear_irq(irq, 0); 237 aspeed_intc_update(s, irq, 0); 238 } 239 } 240 break; 241 default: 242 s->regs[reg] = data; 243 break; 244 } 245 246 return; 247 } 248 249 static const MemoryRegionOps aspeed_intc_ops = { 250 .read = aspeed_intc_read, 251 .write = aspeed_intc_write, 252 .endianness = DEVICE_LITTLE_ENDIAN, 253 .valid = { 254 .min_access_size = 4, 255 .max_access_size = 4, 256 } 257 }; 258 259 static void aspeed_intc_instance_init(Object *obj) 260 { 261 AspeedINTCState *s = ASPEED_INTC(obj); 262 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 263 int i; 264 265 assert(aic->num_ints <= ASPEED_INTC_NR_INTS); 266 for (i = 0; i < aic->num_ints; i++) { 267 object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i], 268 TYPE_OR_IRQ); 269 object_property_set_int(OBJECT(&s->orgates[i]), "num-lines", 270 aic->num_lines, &error_abort); 271 } 272 } 273 274 static void aspeed_intc_reset(DeviceState *dev) 275 { 276 AspeedINTCState *s = ASPEED_INTC(dev); 277 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 278 279 memset(s->regs, 0, aic->nr_regs << 2); 280 memset(s->enable, 0, sizeof(s->enable)); 281 memset(s->mask, 0, sizeof(s->mask)); 282 memset(s->pending, 0, sizeof(s->pending)); 283 } 284 285 static void aspeed_intc_realize(DeviceState *dev, Error **errp) 286 { 287 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 288 AspeedINTCState *s = ASPEED_INTC(dev); 289 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s); 290 int i; 291 292 memory_region_init(&s->iomem_container, OBJECT(s), 293 TYPE_ASPEED_INTC ".container", aic->mem_size); 294 295 sysbus_init_mmio(sbd, &s->iomem_container); 296 297 s->regs = g_new(uint32_t, aic->nr_regs); 298 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s, 299 TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2); 300 301 memory_region_add_subregion(&s->iomem_container, 0x0, &s->iomem); 302 303 qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_ints); 304 305 for (i = 0; i < aic->num_ints; i++) { 306 if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) { 307 return; 308 } 309 sysbus_init_irq(sbd, &s->output_pins[i]); 310 } 311 } 312 313 static void aspeed_intc_unrealize(DeviceState *dev) 314 { 315 AspeedINTCState *s = ASPEED_INTC(dev); 316 317 g_free(s->regs); 318 s->regs = NULL; 319 } 320 321 static void aspeed_intc_class_init(ObjectClass *klass, void *data) 322 { 323 DeviceClass *dc = DEVICE_CLASS(klass); 324 325 dc->desc = "ASPEED INTC Controller"; 326 dc->realize = aspeed_intc_realize; 327 dc->unrealize = aspeed_intc_unrealize; 328 device_class_set_legacy_reset(dc, aspeed_intc_reset); 329 dc->vmsd = NULL; 330 } 331 332 static const TypeInfo aspeed_intc_info = { 333 .name = TYPE_ASPEED_INTC, 334 .parent = TYPE_SYS_BUS_DEVICE, 335 .instance_init = aspeed_intc_instance_init, 336 .instance_size = sizeof(AspeedINTCState), 337 .class_init = aspeed_intc_class_init, 338 .class_size = sizeof(AspeedINTCClass), 339 .abstract = true, 340 }; 341 342 static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data) 343 { 344 DeviceClass *dc = DEVICE_CLASS(klass); 345 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); 346 347 dc->desc = "ASPEED 2700 INTC Controller"; 348 aic->num_lines = 32; 349 aic->num_ints = 9; 350 aic->mem_size = 0x4000; 351 aic->nr_regs = 0x2000 >> 2; 352 } 353 354 static const TypeInfo aspeed_2700_intc_info = { 355 .name = TYPE_ASPEED_2700_INTC, 356 .parent = TYPE_ASPEED_INTC, 357 .class_init = aspeed_2700_intc_class_init, 358 }; 359 360 static void aspeed_intc_register_types(void) 361 { 362 type_register_static(&aspeed_intc_info); 363 type_register_static(&aspeed_2700_intc_info); 364 } 365 366 type_init(aspeed_intc_register_types); 367