[PATCH v7 15/22] hw/i3c/dw-i3c: Add ctrl MMIO handling

Jamin Lin
2026-02-25T02:14:03Z

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>
---
hw/i3c/dw-i3c.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)

diff --git a/hw/i3c/dw-i3c.c b/hw/i3c/dw-i3c.c
index 832fcf326a..b6ec0d9579 100644
--- a/hw/i3c/dw-i3c.c
+++ b/hw/i3c/dw-i3c.c
@@ -344,6 +344,8 @@ static const uint32_t dw_i3c_ro[DW_I3C_NR_REGS] = {
[R_SLAVE_CONFIG] = 0xffffffff,
};

+static void dw_i3c_cmd_queue_execute(DWI3C *s);
+
static inline bool dw_i3c_has_hdr_ts(DWI3C *s)
{
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,
return ret;
}

+static void dw_i3c_ctrl_w(DWI3C *s, uint32_t val)
+{
+ /*
+ * If the user is setting I3C_RESUME, the controller was halted.
+ * Try and resume execution and leave the bit cleared.
+ */
+ if (FIELD_EX32(val, DEVICE_CTRL, I3C_RESUME)) {
+ dw_i3c_cmd_queue_execute(s);
+ val = FIELD_DP32(val, DEVICE_CTRL, I3C_RESUME, 0);
+ }
+ /*
+ * I3C_ABORT being set sends an I3C STOP. It's cleared when the STOP is
+ * sent.
+ */
+ if (FIELD_EX32(val, DEVICE_CTRL, I3C_ABORT)) {
+ dw_i3c_end_transfer(s, /*is_i2c=*/true);
+ dw_i3c_end_transfer(s, /*is_i2c=*/false);
+ val = FIELD_DP32(val, DEVICE_CTRL, I3C_ABORT, 0);
+ ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ABORT, 1);
+ dw_i3c_update_irq(s);
+ }
+ /* Update present state. */
+ ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS,
+ DW_I3C_TRANSFER_STATE_IDLE);
+ ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS,
+ DW_I3C_TRANSFER_STATUS_IDLE);
+
+ s->regs[R_DEVICE_CTRL] = val;
+}
+
static inline bool dw_i3c_target_is_i2c(DWI3C *s, uint16_t offset)
{
/* / 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,
"] = 0x%08" PRIx64 "\n",
__func__, offset, value);
break;
+ case R_DEVICE_CTRL:
+ dw_i3c_ctrl_w(s, val32);
+ break;
case R_RX_TX_DATA_PORT:
dw_i3c_push_tx(s, val32);
break;
--
2.43.0