@samitouri / QOSamiQemu / commits / 61c2a72bbc

hw/i3c/dw-i3c: Add ctrl MMIO handling

Adds functionality to the CTRL register. Signed-off-by: Joe Komlodi <komlodi@google.com> Reviewed-by: Titus Rwantare <titusr@google.com> Reviewed-by: Patrick Venture <venture@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-16-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Jamin Lin committed Feb 25, 2026 at 02:12 UTC 61c2a72bbc1ba293e4b0121a30a4953371af22ab
1 file changed +35
hw/i3c/dw-i3c.c
+35
@@ -344,6 +344,8 @@ static const uint32_t dw_i3c_ro[DW_I3C_NR_REGS] = {
344 [R_SLAVE_CONFIG] = 0xffffffff,
345 };
346
347 +static void dw_i3c_cmd_queue_execute(DWI3C *s);
348 +
349 static inline bool dw_i3c_has_hdr_ts(DWI3C *s)
350 {
351 return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, HDR_TS);
@@ -503,6 +505,36 @@ static int dw_i3c_recv_data(DWI3C *s, bool is_i2c, uint8_t *data,
505 return ret;
506 }
507
508 +static void dw_i3c_ctrl_w(DWI3C *s, uint32_t val)
509 +{
510 + /*
511 + * If the user is setting I3C_RESUME, the controller was halted.
512 + * Try and resume execution and leave the bit cleared.
513 + */
514 + if (FIELD_EX32(val, DEVICE_CTRL, I3C_RESUME)) {
515 + dw_i3c_cmd_queue_execute(s);
516 + val = FIELD_DP32(val, DEVICE_CTRL, I3C_RESUME, 0);
517 + }
518 + /*
519 + * I3C_ABORT being set sends an I3C STOP. It's cleared when the STOP is
520 + * sent.
521 + */
522 + if (FIELD_EX32(val, DEVICE_CTRL, I3C_ABORT)) {
523 + dw_i3c_end_transfer(s, /*is_i2c=*/true);
524 + dw_i3c_end_transfer(s, /*is_i2c=*/false);
525 + val = FIELD_DP32(val, DEVICE_CTRL, I3C_ABORT, 0);
526 + ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ABORT, 1);
527 + dw_i3c_update_irq(s);
528 + }
529 + /* Update present state. */
530 + ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
531 + DW_I3C_TRANSFER_STATE_IDLE);
532 + ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS,
533 + DW_I3C_TRANSFER_STATUS_IDLE);
534 +
535 + s->regs[R_DEVICE_CTRL] = val;
536 +}
537 +
538 static inline bool dw_i3c_target_is_i2c(DWI3C *s, uint16_t offset)
539 {
540 /* / sizeof(uint32_t) because we're indexing into our 32-bit reg array. */
@@ -1575,6 +1607,9 @@ static void dw_i3c_write(void *opaque, hwaddr offset, uint64_t value,
1607 "] = 0x%08" PRIx64 "\n",
1608 __func__, offset, value);
1609 break;
1610 + case R_DEVICE_CTRL:
1611 + dw_i3c_ctrl_w(s, val32);
1612 + break;
1613 case R_RX_TX_DATA_PORT:
1614 dw_i3c_push_tx(s, val32);
1615 break;