diff mbox series

[08/16] hw/i3c/aspeed_i3c: Add IRQ MMIO behavior

Message ID 20230331010131.1412571-9-komlodi@google.com (mailing list archive)
State New, archived
Headers show
Series i3c: aspeed: Add I3C support | expand

Commit Message

Joe Komlodi March 31, 2023, 1:01 a.m. UTC
Signed-off-by: Joe Komlodi <komlodi@google.com>

Reviewed-by: Patrick Venture <venture@google.com>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
---
 hw/i3c/aspeed_i3c.c | 57 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
diff mbox series

Patch

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;