@samitouri / QOSamiQemu / commits / 1a7105014b

hw/i3c/dw-i3c: Add IRQ MMIO behavior

Signed-off-by: Joe Komlodi <komlodi@google.com> Reviewed-by: Patrick Venture <venture@google.com> Reviewed-by: Hao Wu <wuhaotsh@google.com> Reviewed-by: Jamin Lin <jamin_lin@aspeedtech.com> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com> Tested-by: Jithu Joseph <jithu.joseph@oss.qualcomm.com> Link: https://lore.kernel.org/qemu-devel/20260225021158.1586584-13-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Jamin Lin committed Feb 25, 2026 at 02:12 UTC 1a7105014b30f19afae1df1173fe8e14760d3abb
1 file changed +56
hw/i3c/dw-i3c.c
+56
@@ -17,6 +17,7 @@
17 #include "qapi/error.h"
18 #include "migration/vmstate.h"
19 #include "trace.h"
20 +#include "hw/core/irq.h"
21
22 REG32(DEVICE_CTRL, 0x00)
23 FIELD(DEVICE_CTRL, I3C_BROADCAST_ADDR_INC, 0, 1)
@@ -335,6 +336,46 @@ static const uint32_t dw_i3c_ro[DW_I3C_NR_REGS] = {
336 [R_SLAVE_CONFIG] = 0xffffffff,
337 };
338
339 +static void dw_i3c_update_irq(DWI3C *s)
340 +{
341 + bool level = !!(s->regs[R_INTR_SIGNAL_EN] & s->regs[R_INTR_STATUS]);
342 + qemu_set_irq(s->irq, level);
343 +}
344 +
345 +static uint32_t dw_i3c_intr_status_r(DWI3C *s)
346 +{
347 + /* Only return the status whose corresponding EN bits are set. */
348 + return s->regs[R_INTR_STATUS] & s->regs[R_INTR_STATUS_EN];
349 +}
350 +
351 +static void dw_i3c_intr_status_w(DWI3C *s, uint32_t val)
352 +{
353 + /* INTR_STATUS[13:5] is w1c, other bits are RO. */
354 + val &= 0x3fe0;
355 + s->regs[R_INTR_STATUS] &= ~val;
356 +
357 + dw_i3c_update_irq(s);
358 +}
359 +
360 +static void dw_i3c_intr_status_en_w(DWI3C *s, uint32_t val)
361 +{
362 + s->regs[R_INTR_STATUS_EN] = val;
363 + dw_i3c_update_irq(s);
364 +}
365 +
366 +static void dw_i3c_intr_signal_en_w(DWI3C *s, uint32_t val)
367 +{
368 + s->regs[R_INTR_SIGNAL_EN] = val;
369 + dw_i3c_update_irq(s);
370 +}
371 +
372 +static void dw_i3c_intr_force_w(DWI3C *s, uint32_t val)
373 +{
374 + /* INTR_FORCE is WO, just set the corresponding INTR_STATUS bits. */
375 + s->regs[R_INTR_STATUS] = val;
376 + dw_i3c_update_irq(s);
377 +}
378 +
379 static uint64_t dw_i3c_read(void *opaque, hwaddr offset, unsigned size)
380 {
381 DWI3C *s = DW_I3C(opaque);
@@ -348,6 +389,9 @@ static uint64_t dw_i3c_read(void *opaque, hwaddr offset, unsigned size)
389 case R_INTR_FORCE:
390 value = 0;
391 break;
392 + case R_INTR_STATUS:
393 + value = dw_i3c_intr_status_r(s);
394 + break;
395 default:
396 value = s->regs[addr];
397 break;
@@ -392,6 +436,18 @@ static void dw_i3c_write(void *opaque, hwaddr offset, uint64_t value,
436 break;
437 case R_RESET_CTRL:
438 break;
439 + case R_INTR_STATUS:
440 + dw_i3c_intr_status_w(s, val32);
441 + break;
442 + case R_INTR_STATUS_EN:
443 + dw_i3c_intr_status_en_w(s, val32);
444 + break;
445 + case R_INTR_SIGNAL_EN:
446 + dw_i3c_intr_signal_en_w(s, val32);
447 + break;
448 + case R_INTR_FORCE:
449 + dw_i3c_intr_force_w(s, val32);
450 + break;
451 default:
452 s->regs[addr] = val32;
453 break;