From: Joe Komlodi <[email protected]> Adds functionality to the CTRL register.
Signed-off-by: Joe Komlodi <[email protected]> Reviewed-by: Titus Rwantare <[email protected]> Reviewed-by: Patrick Venture <[email protected]> Reviewed-by: Jamin Lin <[email protected]> --- 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 9a0460cf31..7a1f79e10d 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
