master
c 1,026 lines 30.3 KB
Raw
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/core/irq.h"
12 #include "qemu/log.h"
13 #include "trace.h"
14 #include "hw/core/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(GICINT192_201_EN, 0xB00)
25 REG32(GICINT192_201_STATUS, 0xB04)
26
27 /*
28 * INTCIO Registers
29 *
30 * values below are offset by - 0x100 from datasheet
31 * because its memory region is start at 0x100
32 *
33 */
34 REG32(GICINT192_EN, 0x00)
35 REG32(GICINT192_STATUS, 0x04)
36 REG32(GICINT193_EN, 0x10)
37 REG32(GICINT193_STATUS, 0x14)
38 REG32(GICINT194_EN, 0x20)
39 REG32(GICINT194_STATUS, 0x24)
40 REG32(GICINT195_EN, 0x30)
41 REG32(GICINT195_STATUS, 0x34)
42 REG32(GICINT196_EN, 0x40)
43 REG32(GICINT196_STATUS, 0x44)
44 REG32(GICINT197_EN, 0x50)
45 REG32(GICINT197_STATUS, 0x54)
46
47 /*
48 * SSP INTC Registers
49 */
50 REG32(SSPINT160_169_EN, 0x2B00)
51 REG32(SSPINT160_169_STATUS, 0x2B04)
52
53 /*
54 * SSP INTCIO Registers
55 */
56 REG32(SSPINT160_EN, 0x180)
57 REG32(SSPINT160_STATUS, 0x184)
58 REG32(SSPINT161_EN, 0x190)
59 REG32(SSPINT161_STATUS, 0x194)
60 REG32(SSPINT162_EN, 0x1A0)
61 REG32(SSPINT162_STATUS, 0x1A4)
62 REG32(SSPINT163_EN, 0x1B0)
63 REG32(SSPINT163_STATUS, 0x1B4)
64 REG32(SSPINT164_EN, 0x1C0)
65 REG32(SSPINT164_STATUS, 0x1C4)
66 REG32(SSPINT165_EN, 0x1D0)
67 REG32(SSPINT165_STATUS, 0x1D4)
68
69 /*
70 * TSP INTC Registers
71 */
72 REG32(TSPINT160_169_EN, 0x3B00)
73 REG32(TSPINT160_169_STATUS, 0x3B04)
74
75 /*
76 * TSP INTCIO Registers
77 */
78
79 REG32(TSPINT160_EN, 0x200)
80 REG32(TSPINT160_STATUS, 0x204)
81 REG32(TSPINT161_EN, 0x210)
82 REG32(TSPINT161_STATUS, 0x214)
83 REG32(TSPINT162_EN, 0x220)
84 REG32(TSPINT162_STATUS, 0x224)
85 REG32(TSPINT163_EN, 0x230)
86 REG32(TSPINT163_STATUS, 0x234)
87 REG32(TSPINT164_EN, 0x240)
88 REG32(TSPINT164_STATUS, 0x244)
89 REG32(TSPINT165_EN, 0x250)
90 REG32(TSPINT165_STATUS, 0x254)
91
92 static const AspeedINTCIRQ *aspeed_intc_get_irq(AspeedINTCClass *aic,
93 uint32_t reg)
94 {
95 int i;
96
97 for (i = 0; i < aic->irq_table_count; i++) {
98 if (aic->irq_table[i].enable_reg == reg ||
99 aic->irq_table[i].status_reg == reg) {
100 return &aic->irq_table[i];
101 }
102 }
103
104 /*
105 * Invalid reg.
106 */
107 g_assert_not_reached();
108 }
109
110 static uint32_t aspeed_intc_orgate_levels(AspeedINTCState *s, int inpin_idx)
111 {
112 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
113 uint32_t levels = 0;
114 int i;
115
116 for (i = 0; i < aic->num_lines && i < 32; i++) {
117 if (s->orgates[inpin_idx].levels[i]) {
118 levels |= BIT(i);
119 }
120 }
121
122 return levels;
123 }
124
125 static void aspeed_intc_drop_stale_pending(AspeedINTCState *s, int inpin_idx)
126 {
127 s->pending[inpin_idx] &= aspeed_intc_orgate_levels(s, inpin_idx) &
128 s->enable[inpin_idx];
129 }
130
131 /*
132 * Update the state of an interrupt controller pin by setting
133 * the specified output pin to the given level.
134 * The input pin index should be between 0 and the number of input pins.
135 * The output pin index should be between 0 and the number of output pins.
136 */
137 static void aspeed_intc_update(AspeedINTCState *s, int inpin_idx,
138 int outpin_idx, int level)
139 {
140 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
141 const char *name = object_get_typename(OBJECT(s));
142
143 assert((outpin_idx < aic->num_outpins) && (inpin_idx < aic->num_inpins));
144
145 trace_aspeed_intc_update_irq(name, inpin_idx, outpin_idx, level);
146 qemu_set_irq(s->output_pins[outpin_idx], level);
147 }
148
149 static void aspeed_intc_set_irq_handler(AspeedINTCState *s,
150 const AspeedINTCIRQ *intc_irq,
151 uint32_t select)
152 {
153 const char *name = object_get_typename(OBJECT(s));
154 uint32_t status_reg;
155 int outpin_idx;
156 int inpin_idx;
157
158 status_reg = intc_irq->status_reg;
159 outpin_idx = intc_irq->outpin_idx;
160 inpin_idx = intc_irq->inpin_idx;
161
162 if ((s->mask[inpin_idx] & select) || (s->regs[status_reg] & select)) {
163 /*
164 * a. mask is not 0 means in ISR mode
165 * sources interrupt routine are executing.
166 * b. status register value is not 0 means previous
167 * source interrupt does not be executed, yet.
168 *
169 * save source interrupt to pending variable.
170 */
171 s->pending[inpin_idx] |= select;
172 trace_aspeed_intc_pending_irq(name, inpin_idx, s->pending[inpin_idx]);
173 } else {
174 /*
175 * notify firmware which source interrupt are coming
176 * by setting status register
177 */
178 s->regs[status_reg] = select;
179 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
180 s->regs[status_reg]);
181 aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
182 }
183 }
184
185 static void aspeed_intc_set_irq_handler_multi_outpins(AspeedINTCState *s,
186 const AspeedINTCIRQ *intc_irq, uint32_t select)
187 {
188 const char *name = object_get_typename(OBJECT(s));
189 uint32_t status_reg;
190 int num_outpins;
191 int outpin_idx;
192 int inpin_idx;
193 int i;
194
195 num_outpins = intc_irq->num_outpins;
196 status_reg = intc_irq->status_reg;
197 outpin_idx = intc_irq->outpin_idx;
198 inpin_idx = intc_irq->inpin_idx;
199
200 for (i = 0; i < num_outpins; i++) {
201 if (select & BIT(i)) {
202 if (s->mask[inpin_idx] & BIT(i) ||
203 s->regs[status_reg] & BIT(i)) {
204 /*
205 * a. mask bit is not 0 means in ISR mode sources interrupt
206 * routine are executing.
207 * b. status bit is not 0 means previous source interrupt
208 * does not be executed, yet.
209 *
210 * save source interrupt to pending bit.
211 */
212 s->pending[inpin_idx] |= BIT(i);
213 trace_aspeed_intc_pending_irq(name, inpin_idx,
214 s->pending[inpin_idx]);
215 } else {
216 /*
217 * notify firmware which source interrupt are coming
218 * by setting status bit
219 */
220 s->regs[status_reg] |= BIT(i);
221 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i,
222 s->regs[status_reg]);
223 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1);
224 }
225 }
226 }
227 }
228
229 /*
230 * GICINT192_201 maps 1:10 to input IRQ 0 and output IRQs 0 to 9.
231 * GICINT128 to GICINT136 map 1:1 to input IRQs 1 to 9 and output
232 * IRQs 10 to 18. The value of input IRQ should be between 0 and
233 * the number of input pins.
234 */
235 static void aspeed_intc_set_irq(void *opaque, int irq, int level)
236 {
237 AspeedINTCState *s = (AspeedINTCState *)opaque;
238 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
239 const char *name = object_get_typename(OBJECT(s));
240 const AspeedINTCIRQ *intc_irq;
241 uint32_t select = 0;
242 uint32_t enable;
243 int num_outpins;
244 int inpin_idx;
245 int i;
246
247 assert(irq < aic->num_inpins);
248
249 intc_irq = &aic->irq_table[irq];
250 num_outpins = intc_irq->num_outpins;
251 inpin_idx = intc_irq->inpin_idx;
252 trace_aspeed_intc_set_irq(name, inpin_idx, level);
253 enable = s->enable[inpin_idx];
254
255 aspeed_intc_drop_stale_pending(s, inpin_idx);
256
257 if (!level) {
258 return;
259 }
260
261 for (i = 0; i < aic->num_lines; i++) {
262 if (s->orgates[inpin_idx].levels[i]) {
263 if (enable & BIT(i)) {
264 select |= BIT(i);
265 }
266 }
267 }
268
269 if (!select) {
270 return;
271 }
272
273 trace_aspeed_intc_select(name, select);
274 if (num_outpins > 1) {
275 aspeed_intc_set_irq_handler_multi_outpins(s, intc_irq, select);
276 } else {
277 aspeed_intc_set_irq_handler(s, intc_irq, select);
278 }
279 }
280
281 static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset,
282 uint64_t data)
283 {
284 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
285 const char *name = object_get_typename(OBJECT(s));
286 const AspeedINTCIRQ *intc_irq;
287 uint32_t reg = offset >> 2;
288 uint32_t old_enable;
289 uint32_t change;
290 int inpin_idx;
291
292 intc_irq = aspeed_intc_get_irq(aic, reg);
293 inpin_idx = intc_irq->inpin_idx;
294
295 assert(inpin_idx < aic->num_inpins);
296
297 /*
298 * The enable registers are used to enable source interrupts.
299 * They also handle masking and unmasking of source interrupts
300 * during the execution of the source ISR.
301 */
302
303 /* disable all source interrupt */
304 if (!data && !s->enable[inpin_idx]) {
305 s->regs[reg] = data;
306 return;
307 }
308
309 old_enable = s->enable[inpin_idx];
310 s->enable[inpin_idx] |= data;
311
312 /* enable new source interrupt */
313 if (old_enable != s->enable[inpin_idx]) {
314 trace_aspeed_intc_enable(name, s->enable[inpin_idx]);
315 s->regs[reg] = data;
316 return;
317 }
318
319 /* mask and unmask source interrupt */
320 change = s->regs[reg] ^ data;
321 if (change & data) {
322 s->mask[inpin_idx] &= ~change;
323 trace_aspeed_intc_unmask(name, change, s->mask[inpin_idx]);
324 } else {
325 s->mask[inpin_idx] |= change;
326 trace_aspeed_intc_mask(name, change, s->mask[inpin_idx]);
327 }
328
329 s->regs[reg] = data;
330 }
331
332 static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset,
333 uint64_t data)
334 {
335 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
336 const char *name = object_get_typename(OBJECT(s));
337 const AspeedINTCIRQ *intc_irq;
338 uint32_t reg = offset >> 2;
339 int outpin_idx;
340 int inpin_idx;
341
342 if (!data) {
343 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
344 return;
345 }
346
347 intc_irq = aspeed_intc_get_irq(aic, reg);
348 outpin_idx = intc_irq->outpin_idx;
349 inpin_idx = intc_irq->inpin_idx;
350
351 assert(inpin_idx < aic->num_inpins);
352
353 /* clear status */
354 s->regs[reg] &= ~data;
355
356 /*
357 * These status registers are used for notify sources ISR are executed.
358 * If one source ISR is executed, it will clear one bit.
359 * If it clear all bits, it means to initialize this register status
360 * rather than sources ISR are executed.
361 */
362 if (data == 0xffffffff) {
363 return;
364 }
365
366 /* All source ISR execution are done */
367 if (!s->regs[reg]) {
368 trace_aspeed_intc_all_isr_done(name, inpin_idx);
369 aspeed_intc_drop_stale_pending(s, inpin_idx);
370 if (s->pending[inpin_idx]) {
371 /*
372 * handle pending source interrupt
373 * notify firmware which source interrupt are pending
374 * by setting status register
375 */
376 s->regs[reg] = s->pending[inpin_idx];
377 s->pending[inpin_idx] = 0;
378 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
379 s->regs[reg]);
380 aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
381 } else {
382 /* clear irq */
383 trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx, 0);
384 aspeed_intc_update(s, inpin_idx, outpin_idx, 0);
385 }
386 }
387 }
388
389 static void aspeed_intc_status_handler_multi_outpins(AspeedINTCState *s,
390 hwaddr offset, uint64_t data)
391 {
392 const char *name = object_get_typename(OBJECT(s));
393 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
394 const AspeedINTCIRQ *intc_irq;
395 uint32_t reg = offset >> 2;
396 int num_outpins;
397 int outpin_idx;
398 int inpin_idx;
399 int i;
400
401 if (!data) {
402 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
403 return;
404 }
405
406 intc_irq = aspeed_intc_get_irq(aic, reg);
407 num_outpins = intc_irq->num_outpins;
408 outpin_idx = intc_irq->outpin_idx;
409 inpin_idx = intc_irq->inpin_idx;
410 assert(inpin_idx < aic->num_inpins);
411
412 /* clear status */
413 s->regs[reg] &= ~data;
414
415 /*
416 * The status registers are used for notify sources ISR are executed.
417 * If one source ISR is executed, it will clear one bit.
418 * If it clear all bits, it means to initialize this register status
419 * rather than sources ISR are executed.
420 */
421 if (data == 0xffffffff) {
422 return;
423 }
424
425 for (i = 0; i < num_outpins; i++) {
426 /* All source ISR executions are done from a specific bit */
427 if (data & BIT(i)) {
428 trace_aspeed_intc_all_isr_done_bit(name, inpin_idx, i);
429 aspeed_intc_drop_stale_pending(s, inpin_idx);
430 if (s->pending[inpin_idx] & BIT(i)) {
431 /*
432 * Handle pending source interrupt.
433 * Notify firmware which source interrupt is pending
434 * by setting the status bit.
435 */
436 s->regs[reg] |= BIT(i);
437 s->pending[inpin_idx] &= ~BIT(i);
438 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i,
439 s->regs[reg]);
440 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1);
441 } else {
442 /* clear irq for the specific bit */
443 trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx + i, 0);
444 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 0);
445 }
446 }
447 }
448 }
449
450 static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
451 {
452 AspeedINTCState *s = ASPEED_INTC(opaque);
453 const char *name = object_get_typename(OBJECT(s));
454 uint32_t reg = offset >> 2;
455 uint32_t value = 0;
456
457 value = s->regs[reg];
458 trace_aspeed_intc_read(name, offset, size, value);
459
460 return value;
461 }
462
463 static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
464 unsigned size)
465 {
466 AspeedINTCState *s = ASPEED_INTC(opaque);
467 const char *name = object_get_typename(OBJECT(s));
468 uint32_t reg = offset >> 2;
469
470 trace_aspeed_intc_write(name, offset, size, data);
471
472 switch (reg) {
473 case R_GICINT192_201_EN:
474 aspeed_intc_enable_handler(s, offset, data);
475 break;
476 case R_GICINT192_201_STATUS:
477 aspeed_intc_status_handler_multi_outpins(s, offset, data);
478 break;
479 default:
480 s->regs[reg] = data;
481 break;
482 }
483 }
484
485 static void aspeed_ssp_intc_write(void *opaque, hwaddr offset, uint64_t data,
486 unsigned size)
487 {
488 AspeedINTCState *s = ASPEED_INTC(opaque);
489 const char *name = object_get_typename(OBJECT(s));
490 uint32_t reg = offset >> 2;
491
492 trace_aspeed_intc_write(name, offset, size, data);
493
494 switch (reg) {
495 case R_SSPINT160_169_EN:
496 aspeed_intc_enable_handler(s, offset, data);
497 break;
498 case R_SSPINT160_169_STATUS:
499 aspeed_intc_status_handler_multi_outpins(s, offset, data);
500 break;
501 default:
502 s->regs[reg] = data;
503 break;
504 }
505 }
506
507 static void aspeed_tsp_intc_write(void *opaque, hwaddr offset, uint64_t data,
508 unsigned size)
509 {
510 AspeedINTCState *s = ASPEED_INTC(opaque);
511 const char *name = object_get_typename(OBJECT(s));
512 uint32_t reg = offset >> 2;
513
514 trace_aspeed_intc_write(name, offset, size, data);
515
516 switch (reg) {
517 case R_TSPINT160_169_EN:
518 aspeed_intc_enable_handler(s, offset, data);
519 break;
520 case R_TSPINT160_169_STATUS:
521 aspeed_intc_status_handler_multi_outpins(s, offset, data);
522 break;
523 default:
524 s->regs[reg] = data;
525 break;
526 }
527 }
528
529 static uint64_t aspeed_intcio_read(void *opaque, hwaddr offset,
530 unsigned int size)
531 {
532 AspeedINTCState *s = ASPEED_INTC(opaque);
533 const char *name = object_get_typename(OBJECT(s));
534 uint32_t reg = offset >> 2;
535 uint32_t value = 0;
536
537 value = s->regs[reg];
538 trace_aspeed_intc_read(name, offset, size, value);
539
540 return value;
541 }
542
543 static void aspeed_intcio_write(void *opaque, hwaddr offset, uint64_t data,
544 unsigned size)
545 {
546 AspeedINTCState *s = ASPEED_INTC(opaque);
547 const char *name = object_get_typename(OBJECT(s));
548 uint32_t reg = offset >> 2;
549
550 trace_aspeed_intc_write(name, offset, size, data);
551
552 switch (reg) {
553 case R_GICINT192_EN:
554 case R_GICINT193_EN:
555 case R_GICINT194_EN:
556 case R_GICINT195_EN:
557 case R_GICINT196_EN:
558 case R_GICINT197_EN:
559 aspeed_intc_enable_handler(s, offset, data);
560 break;
561 case R_GICINT192_STATUS:
562 case R_GICINT193_STATUS:
563 case R_GICINT194_STATUS:
564 case R_GICINT195_STATUS:
565 case R_GICINT196_STATUS:
566 case R_GICINT197_STATUS:
567 aspeed_intc_status_handler(s, offset, data);
568 break;
569 default:
570 s->regs[reg] = data;
571 break;
572 }
573 }
574
575 static void aspeed_ssp_intcio_write(void *opaque, hwaddr offset, uint64_t data,
576 unsigned size)
577 {
578 AspeedINTCState *s = ASPEED_INTC(opaque);
579 const char *name = object_get_typename(OBJECT(s));
580 uint32_t reg = offset >> 2;
581
582 trace_aspeed_intc_write(name, offset, size, data);
583
584 switch (reg) {
585 case R_SSPINT160_EN:
586 case R_SSPINT161_EN:
587 case R_SSPINT162_EN:
588 case R_SSPINT163_EN:
589 case R_SSPINT164_EN:
590 case R_SSPINT165_EN:
591 aspeed_intc_enable_handler(s, offset, data);
592 break;
593 case R_SSPINT160_STATUS:
594 case R_SSPINT161_STATUS:
595 case R_SSPINT162_STATUS:
596 case R_SSPINT163_STATUS:
597 case R_SSPINT164_STATUS:
598 case R_SSPINT165_STATUS:
599 aspeed_intc_status_handler(s, offset, data);
600 break;
601 default:
602 s->regs[reg] = data;
603 break;
604 }
605 }
606
607 static void aspeed_tsp_intcio_write(void *opaque, hwaddr offset, uint64_t data,
608 unsigned size)
609 {
610 AspeedINTCState *s = ASPEED_INTC(opaque);
611 const char *name = object_get_typename(OBJECT(s));
612 uint32_t reg = offset >> 2;
613
614 trace_aspeed_intc_write(name, offset, size, data);
615
616 switch (reg) {
617 case R_TSPINT160_EN:
618 case R_TSPINT161_EN:
619 case R_TSPINT162_EN:
620 case R_TSPINT163_EN:
621 case R_TSPINT164_EN:
622 case R_TSPINT165_EN:
623 aspeed_intc_enable_handler(s, offset, data);
624 break;
625 case R_TSPINT160_STATUS:
626 case R_TSPINT161_STATUS:
627 case R_TSPINT162_STATUS:
628 case R_TSPINT163_STATUS:
629 case R_TSPINT164_STATUS:
630 case R_TSPINT165_STATUS:
631 aspeed_intc_status_handler(s, offset, data);
632 break;
633 default:
634 s->regs[reg] = data;
635 break;
636 }
637 }
638
639 static const MemoryRegionOps aspeed_intc_ops = {
640 .read = aspeed_intc_read,
641 .write = aspeed_intc_write,
642 .endianness = DEVICE_LITTLE_ENDIAN,
643 .impl.min_access_size = 4,
644 .valid = {
645 .min_access_size = 4,
646 .max_access_size = 4,
647 }
648 };
649
650 static const MemoryRegionOps aspeed_intcio_ops = {
651 .read = aspeed_intcio_read,
652 .write = aspeed_intcio_write,
653 .endianness = DEVICE_LITTLE_ENDIAN,
654 .impl.min_access_size = 4,
655 .valid = {
656 .min_access_size = 4,
657 .max_access_size = 4,
658 }
659 };
660
661 static const MemoryRegionOps aspeed_ssp_intc_ops = {
662 .read = aspeed_intc_read,
663 .write = aspeed_ssp_intc_write,
664 .endianness = DEVICE_LITTLE_ENDIAN,
665 .impl.min_access_size = 4,
666 .valid = {
667 .min_access_size = 4,
668 .max_access_size = 4,
669 }
670 };
671
672 static const MemoryRegionOps aspeed_ssp_intcio_ops = {
673 .read = aspeed_intcio_read,
674 .write = aspeed_ssp_intcio_write,
675 .endianness = DEVICE_LITTLE_ENDIAN,
676 .impl.min_access_size = 4,
677 .valid = {
678 .min_access_size = 4,
679 .max_access_size = 4,
680 }
681 };
682
683 static const MemoryRegionOps aspeed_tsp_intc_ops = {
684 .read = aspeed_intc_read,
685 .write = aspeed_tsp_intc_write,
686 .endianness = DEVICE_LITTLE_ENDIAN,
687 .impl.min_access_size = 4,
688 .valid = {
689 .min_access_size = 4,
690 .max_access_size = 4,
691 }
692 };
693
694 static const MemoryRegionOps aspeed_tsp_intcio_ops = {
695 .read = aspeed_intcio_read,
696 .write = aspeed_tsp_intcio_write,
697 .endianness = DEVICE_LITTLE_ENDIAN,
698 .impl.min_access_size = 4,
699 .valid = {
700 .min_access_size = 4,
701 .max_access_size = 4,
702 }
703 };
704
705 static void aspeed_intc_instance_init(Object *obj)
706 {
707 AspeedINTCState *s = ASPEED_INTC(obj);
708 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
709 int i;
710
711 assert(aic->num_inpins <= ASPEED_INTC_MAX_INPINS);
712 for (i = 0; i < aic->num_inpins; i++) {
713 object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
714 TYPE_OR_IRQ);
715 object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
716 aic->num_lines, &error_abort);
717 }
718 }
719
720 static void aspeed_intc_reset_hold(Object *obj, ResetType type)
721 {
722 AspeedINTCState *s = ASPEED_INTC(obj);
723 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
724
725 memset(s->regs, 0, aic->nr_regs << 2);
726 memset(s->enable, 0, sizeof(s->enable));
727 memset(s->mask, 0, sizeof(s->mask));
728 memset(s->pending, 0, sizeof(s->pending));
729 }
730
731 static void aspeed_intc_realize(DeviceState *dev, Error **errp)
732 {
733 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
734 AspeedINTCState *s = ASPEED_INTC(dev);
735 AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
736 int i;
737
738 memory_region_init(&s->iomem_container, OBJECT(s),
739 TYPE_ASPEED_INTC ".container", aic->mem_size);
740
741 sysbus_init_mmio(sbd, &s->iomem_container);
742
743 s->regs = g_new(uint32_t, aic->nr_regs);
744 memory_region_init_io(&s->iomem, OBJECT(s), aic->reg_ops, s,
745 TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2);
746
747 memory_region_add_subregion(&s->iomem_container, aic->reg_offset,
748 &s->iomem);
749
750 qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_inpins);
751
752 for (i = 0; i < aic->num_inpins; i++) {
753 if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
754 return;
755 }
756 }
757
758 for (i = 0; i < aic->num_outpins; i++) {
759 sysbus_init_irq(sbd, &s->output_pins[i]);
760 }
761 }
762
763 static void aspeed_intc_unrealize(DeviceState *dev)
764 {
765 AspeedINTCState *s = ASPEED_INTC(dev);
766
767 g_free(s->regs);
768 s->regs = NULL;
769 }
770
771 static void aspeed_intc_class_init(ObjectClass *klass, const void *data)
772 {
773 DeviceClass *dc = DEVICE_CLASS(klass);
774 ResettableClass *rc = RESETTABLE_CLASS(klass);
775 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
776
777 dc->desc = "ASPEED INTC Controller";
778 dc->realize = aspeed_intc_realize;
779 dc->unrealize = aspeed_intc_unrealize;
780 rc->phases.hold = aspeed_intc_reset_hold;
781 dc->vmsd = NULL;
782
783 aic->reg_ops = &aspeed_intc_ops;
784 }
785
786 static AspeedINTCIRQ aspeed_2700_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
787 {0, 0, 10, R_GICINT192_201_EN, R_GICINT192_201_STATUS},
788 };
789
790 static void aspeed_2700_intc_class_init(ObjectClass *klass, const void *data)
791 {
792 DeviceClass *dc = DEVICE_CLASS(klass);
793 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
794
795 dc->desc = "ASPEED 2700 INTC Controller";
796 aic->num_lines = 32;
797 aic->num_inpins = 1;
798 aic->num_outpins = 10;
799 aic->mem_size = 0x4000;
800 aic->nr_regs = 0xB08 >> 2;
801 aic->reg_offset = 0x1000;
802 aic->irq_table = aspeed_2700_intc_irqs;
803 aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intc_irqs);
804 }
805
806 static AspeedINTCIRQ aspeed_2700_intcioexp2_irqs[ASPEED_INTC_MAX_INPINS] = {
807 {0, 8, 1, R_GICINT192_EN, R_GICINT192_STATUS},
808 {1, 9, 1, R_GICINT193_EN, R_GICINT193_STATUS},
809 };
810
811 static void aspeed_2700_intcioexp2_class_init(ObjectClass *klass,
812 const void *data)
813 {
814 DeviceClass *dc = DEVICE_CLASS(klass);
815 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
816
817 dc->desc = "ASPEED 2700 IOEXP2 INTC Controller";
818 aic->num_lines = 32;
819 aic->num_inpins = 2;
820 aic->num_outpins = 10;
821 aic->mem_size = 0x400;
822 aic->nr_regs = 0x58 >> 2;
823 aic->reg_offset = 0x100;
824 aic->reg_ops = &aspeed_intcio_ops;
825 aic->irq_table = aspeed_2700_intcioexp2_irqs;
826 aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intcioexp2_irqs);
827 }
828
829 static AspeedINTCIRQ aspeed_2700_intcioexp1_irqs[ASPEED_INTC_MAX_INPINS] = {
830 {0, 6, 1, R_GICINT192_EN, R_GICINT192_STATUS},
831 {1, 7, 1, R_GICINT193_EN, R_GICINT193_STATUS},
832 };
833
834 static void aspeed_2700_intcioexp1_class_init(ObjectClass *klass,
835 const void *data)
836 {
837 DeviceClass *dc = DEVICE_CLASS(klass);
838 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
839
840 dc->desc = "ASPEED 2700 IOEXP1 INTC Controller";
841 aic->num_lines = 32;
842 aic->num_inpins = 2;
843 aic->num_outpins = 10;
844 aic->mem_size = 0x400;
845 aic->nr_regs = 0x58 >> 2;
846 aic->reg_offset = 0x100;
847 aic->reg_ops = &aspeed_intcio_ops;
848 aic->irq_table = aspeed_2700_intcioexp1_irqs;
849 aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intcioexp1_irqs);
850 }
851
852 static AspeedINTCIRQ aspeed_2700_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
853 {0, 0, 1, R_GICINT192_EN, R_GICINT192_STATUS},
854 {1, 1, 1, R_GICINT193_EN, R_GICINT193_STATUS},
855 {2, 2, 1, R_GICINT194_EN, R_GICINT194_STATUS},
856 {3, 3, 1, R_GICINT195_EN, R_GICINT195_STATUS},
857 {4, 4, 1, R_GICINT196_EN, R_GICINT196_STATUS},
858 {5, 5, 1, R_GICINT197_EN, R_GICINT197_STATUS},
859 };
860
861 static void aspeed_2700_intcio_class_init(ObjectClass *klass, const void *data)
862 {
863 DeviceClass *dc = DEVICE_CLASS(klass);
864 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
865
866 dc->desc = "ASPEED 2700 INTC IO Controller";
867 aic->num_lines = 32;
868 aic->num_inpins = 6;
869 aic->num_outpins = 6;
870 aic->mem_size = 0x400;
871 aic->nr_regs = 0x58 >> 2;
872 aic->reg_offset = 0x100;
873 aic->reg_ops = &aspeed_intcio_ops;
874 aic->irq_table = aspeed_2700_intcio_irqs;
875 aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intcio_irqs);
876 }
877
878 static AspeedINTCIRQ aspeed_2700ssp_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
879 {0, 0, 10, R_SSPINT160_169_EN, R_SSPINT160_169_STATUS},
880 };
881
882 static void aspeed_2700ssp_intc_class_init(ObjectClass *klass, const void *data)
883 {
884 DeviceClass *dc = DEVICE_CLASS(klass);
885 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
886
887 dc->desc = "ASPEED 2700 SSP INTC Controller";
888 aic->num_lines = 32;
889 aic->num_inpins = 1;
890 aic->num_outpins = 10;
891 aic->mem_size = 0x4000;
892 aic->nr_regs = 0x2B08 >> 2;
893 aic->reg_offset = 0x0;
894 aic->reg_ops = &aspeed_ssp_intc_ops;
895 aic->irq_table = aspeed_2700ssp_intc_irqs;
896 aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intc_irqs);
897 }
898
899 static AspeedINTCIRQ aspeed_2700ssp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
900 {0, 0, 1, R_SSPINT160_EN, R_SSPINT160_STATUS},
901 {1, 1, 1, R_SSPINT161_EN, R_SSPINT161_STATUS},
902 {2, 2, 1, R_SSPINT162_EN, R_SSPINT162_STATUS},
903 {3, 3, 1, R_SSPINT163_EN, R_SSPINT163_STATUS},
904 {4, 4, 1, R_SSPINT164_EN, R_SSPINT164_STATUS},
905 {5, 5, 1, R_SSPINT165_EN, R_SSPINT165_STATUS},
906 };
907
908 static void aspeed_2700ssp_intcio_class_init(ObjectClass *klass,
909 const void *data)
910 {
911 DeviceClass *dc = DEVICE_CLASS(klass);
912 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
913
914 dc->desc = "ASPEED 2700 SSP INTC IO Controller";
915 aic->num_lines = 32;
916 aic->num_inpins = 6;
917 aic->num_outpins = 6;
918 aic->mem_size = 0x400;
919 aic->nr_regs = 0x1d8 >> 2;
920 aic->reg_offset = 0;
921 aic->reg_ops = &aspeed_ssp_intcio_ops;
922 aic->irq_table = aspeed_2700ssp_intcio_irqs;
923 aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intcio_irqs);
924 }
925
926 static AspeedINTCIRQ aspeed_2700tsp_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
927 {0, 0, 10, R_TSPINT160_169_EN, R_TSPINT160_169_STATUS},
928 };
929
930 static void aspeed_2700tsp_intc_class_init(ObjectClass *klass, const void *data)
931 {
932 DeviceClass *dc = DEVICE_CLASS(klass);
933 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
934
935 dc->desc = "ASPEED 2700 TSP INTC Controller";
936 aic->num_lines = 32;
937 aic->num_inpins = 1;
938 aic->num_outpins = 10;
939 aic->mem_size = 0x4000;
940 aic->nr_regs = 0x3B08 >> 2;
941 aic->reg_offset = 0;
942 aic->reg_ops = &aspeed_tsp_intc_ops;
943 aic->irq_table = aspeed_2700tsp_intc_irqs;
944 aic->irq_table_count = ARRAY_SIZE(aspeed_2700tsp_intc_irqs);
945 }
946
947 static AspeedINTCIRQ aspeed_2700tsp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
948 {0, 0, 1, R_TSPINT160_EN, R_TSPINT160_STATUS},
949 {1, 1, 1, R_TSPINT161_EN, R_TSPINT161_STATUS},
950 {2, 2, 1, R_TSPINT162_EN, R_TSPINT162_STATUS},
951 {3, 3, 1, R_TSPINT163_EN, R_TSPINT163_STATUS},
952 {4, 4, 1, R_TSPINT164_EN, R_TSPINT164_STATUS},
953 {5, 5, 1, R_TSPINT165_EN, R_TSPINT165_STATUS},
954 };
955
956 static void aspeed_2700tsp_intcio_class_init(ObjectClass *klass,
957 const void *data)
958 {
959 DeviceClass *dc = DEVICE_CLASS(klass);
960 AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
961
962 dc->desc = "ASPEED 2700 TSP INTC IO Controller";
963 aic->num_lines = 32;
964 aic->num_inpins = 6;
965 aic->num_outpins = 6;
966 aic->mem_size = 0x400;
967 aic->nr_regs = 0x258 >> 2;
968 aic->reg_offset = 0x0;
969 aic->reg_ops = &aspeed_tsp_intcio_ops;
970 aic->irq_table = aspeed_2700tsp_intcio_irqs;
971 aic->irq_table_count = ARRAY_SIZE(aspeed_2700tsp_intcio_irqs);
972 }
973
974 static const TypeInfo aspeed_intc_types[] = {
975 {
976 .name = TYPE_ASPEED_INTC,
977 .parent = TYPE_SYS_BUS_DEVICE,
978 .instance_init = aspeed_intc_instance_init,
979 .instance_size = sizeof(AspeedINTCState),
980 .class_init = aspeed_intc_class_init,
981 .class_size = sizeof(AspeedINTCClass),
982 .abstract = true,
983 },
984 {
985 .name = TYPE_ASPEED_2700_INTC,
986 .parent = TYPE_ASPEED_INTC,
987 .class_init = aspeed_2700_intc_class_init,
988 },
989 {
990 .name = TYPE_ASPEED_2700_INTCIO,
991 .parent = TYPE_ASPEED_INTC,
992 .class_init = aspeed_2700_intcio_class_init,
993 },
994 {
995 .name = TYPE_ASPEED_2700SSP_INTC,
996 .parent = TYPE_ASPEED_INTC,
997 .class_init = aspeed_2700ssp_intc_class_init,
998 },
999 {
1000 .name = TYPE_ASPEED_2700SSP_INTCIO,
1001 .parent = TYPE_ASPEED_INTC,
1002 .class_init = aspeed_2700ssp_intcio_class_init,
1003 },
1004 {
1005 .name = TYPE_ASPEED_2700TSP_INTC,
1006 .parent = TYPE_ASPEED_INTC,
1007 .class_init = aspeed_2700tsp_intc_class_init,
1008 },
1009 {
1010 .name = TYPE_ASPEED_2700TSP_INTCIO,
1011 .parent = TYPE_ASPEED_INTC,
1012 .class_init = aspeed_2700tsp_intcio_class_init,
1013 },
1014 {
1015 .name = TYPE_ASPEED_2700_INTCIOEXP1,
1016 .parent = TYPE_ASPEED_INTC,
1017 .class_init = aspeed_2700_intcioexp1_class_init,
1018 },
1019 {
1020 .name = TYPE_ASPEED_2700_INTCIOEXP2,
1021 .parent = TYPE_ASPEED_INTC,
1022 .class_init = aspeed_2700_intcioexp2_class_init,
1023 }
1024 };
1025
1026 DEFINE_TYPES(aspeed_intc_types)