Signed-off-by: Joe Komlodi <koml...@google.com> Reviewed-by: Patrick Venture <vent...@google.com> Reviewed-by: Hao Wu <wuhao...@google.com> --- hw/i3c/aspeed_i3c.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+)
diff --git a/hw/i3c/aspeed_i3c.c b/hw/i3c/aspeed_i3c.c index 2ed09234ff..b9aa1367d8 100644 --- a/hw/i3c/aspeed_i3c.c +++ b/hw/i3c/aspeed_i3c.c @@ -17,6 +17,8 @@ #include "qapi/error.h" #include "migration/vmstate.h" #include "trace.h" +#include "hw/i3c/i3c.h" +#include "hw/irq.h" /* I3C Controller Registers */ REG32(I3C1_REG0, 0x10) @@ -412,6 +414,46 @@ static const uint32_t ast2600_i3c_device_ro[ASPEED_I3C_DEVICE_NR_REGS] = { [R_SLAVE_CONFIG] = 0xffffffff, }; +static void aspeed_i3c_device_update_irq(AspeedI3CDevice *s) +{ + bool level = !!(s->regs[R_INTR_SIGNAL_EN] & s->regs[R_INTR_STATUS]); + qemu_set_irq(s->irq, level); +} + +static uint32_t aspeed_i3c_device_intr_status_r(AspeedI3CDevice *s) +{ + /* Only return the status whose corresponding EN bits are set. */ + return s->regs[R_INTR_STATUS] & s->regs[R_INTR_STATUS_EN]; +} + +static void aspeed_i3c_device_intr_status_w(AspeedI3CDevice *s, uint32_t val) +{ + /* INTR_STATUS[13:5] is w1c, other bits are RO. */ + val &= 0x3fe0; + s->regs[R_INTR_STATUS] &= ~val; + + aspeed_i3c_device_update_irq(s); +} + +static void aspeed_i3c_device_intr_status_en_w(AspeedI3CDevice *s, uint32_t val) +{ + s->regs[R_INTR_STATUS_EN] = val; + aspeed_i3c_device_update_irq(s); +} + +static void aspeed_i3c_device_intr_signal_en_w(AspeedI3CDevice *s, uint32_t val) +{ + s->regs[R_INTR_SIGNAL_EN] = val; + aspeed_i3c_device_update_irq(s); +} + +static void aspeed_i3c_device_intr_force_w(AspeedI3CDevice *s, uint32_t val) +{ + /* INTR_FORCE is WO, just set the corresponding INTR_STATUS bits. */ + s->regs[R_INTR_STATUS] = val; + aspeed_i3c_device_update_irq(s); +} + static uint64_t aspeed_i3c_device_read(void *opaque, hwaddr offset, unsigned size) { @@ -426,6 +468,9 @@ static uint64_t aspeed_i3c_device_read(void *opaque, hwaddr offset, case R_INTR_FORCE: value = 0; break; + case R_INTR_STATUS: + value = aspeed_i3c_device_intr_status_r(s); + break; default: value = s->regs[addr]; break; @@ -470,6 +515,18 @@ static void aspeed_i3c_device_write(void *opaque, hwaddr offset, break; case R_RESET_CTRL: break; + case R_INTR_STATUS: + aspeed_i3c_device_intr_status_w(s, val32); + break; + case R_INTR_STATUS_EN: + aspeed_i3c_device_intr_status_en_w(s, val32); + break; + case R_INTR_SIGNAL_EN: + aspeed_i3c_device_intr_signal_en_w(s, val32); + break; + case R_INTR_FORCE: + aspeed_i3c_device_intr_force_w(s, val32); + break; default: s->regs[addr] = val32; break; -- 2.40.0.348.gf938b09366-goog