QEMU-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Wadim Mueller <wafgo01@gmail.com>
To: qemu-devel@nongnu.org
Cc: qemu-arm@nongnu.org, "Peter Maydell" <peter.maydell@linaro.org>,
	"Philippe Mathieu-Daudé" <philmd@mailo.com>,
	"Bin Meng" <bmeng.cn@gmail.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Fabiano Rosas" <farosas@suse.de>,
	"Wadim Mueller" <wafgo01@gmail.com>
Subject: [RFC PATCH v2 08/14] hw/misc: add TI mailbox (IPC) model
Date: Thu, 20 Aug 2026 14:48:08 +0200	[thread overview]
Message-ID: <20260820124824.618671-9-wafgo01@gmail.com> (raw)
In-Reply-To: <20260820124824.618671-1-wafgo01@gmail.com>

Add the K3 mailbox IP: per-mailbox message FIFOs and per-user interrupt
status/enable registers, used for inter-core IPC, for example between the
A53 cluster and the M4F.

Signed-off-by: Wadim Mueller <wafgo01@gmail.com>
---
 hw/misc/Kconfig              |   3 +
 hw/misc/meson.build          |   1 +
 hw/misc/ti-mailbox.c         | 566 +++++++++++++++++++++++++++++++++++
 hw/misc/trace-events         |  13 +
 include/hw/misc/ti-mailbox.h |  44 +++
 5 files changed, 627 insertions(+)
 create mode 100644 hw/misc/ti-mailbox.c
 create mode 100644 include/hw/misc/ti-mailbox.h

diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index c176d6d6c7..e80fdc3214 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -161,6 +161,9 @@ config TI_K3_SDHCI_PHY
 config TI_K3_TRNG
     bool
 
+config TI_MAILBOX
+    bool
+
 config TZ_MPC
     bool
 
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 952b7b7c2f..d190d8608a 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -129,6 +129,7 @@ system_ss.add(when: 'CONFIG_TI_K3_GTC', if_true: files('ti-k3-gtc.c'))
 system_ss.add(when: 'CONFIG_TI_K3_DDRSS', if_true: files('ti-k3-ddrss.c'))
 system_ss.add(when: 'CONFIG_TI_K3_SDHCI_PHY', if_true: files('ti-k3-sdhci-phy.c'))
 system_ss.add(when: 'CONFIG_TI_K3_TRNG', if_true: files('ti-k3-trng.c'))
+system_ss.add(when: 'CONFIG_TI_MAILBOX', if_true: files('ti-mailbox.c'))
 system_ss.add(when: 'CONFIG_TZ_MPC', if_true: files('tz-mpc.c'))
 system_ss.add(when: 'CONFIG_TZ_MSC', if_true: files('tz-msc.c'))
 system_ss.add(when: 'CONFIG_TZ_PPC', if_true: files('tz-ppc.c'))
diff --git a/hw/misc/ti-mailbox.c b/hw/misc/ti-mailbox.c
new file mode 100644
index 0000000000..ba4858a226
--- /dev/null
+++ b/hw/misc/ti-mailbox.c
@@ -0,0 +1,566 @@
+/*
+ * TI AM64x/OMAP mailbox
+ *
+ * Copyright (c) 2025 CMBLU Energy AG
+ * Author: Wadim Mueller <wafgo01@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/core/sysbus.h"
+#include "qemu/module.h"
+#include "qemu/bitops.h"
+#include "hw/core/cpu.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/misc/ti-mailbox.h"
+#include "trace.h"
+#include "qapi/error.h"
+#include "hw/core/irq.h"
+#include "qom/object.h"
+
+#define TI_MAILBOX_MMIO_SIZE 0x200
+
+#define MAILBOX_REVISION 0x00
+#define MAILBOX_SYSCONFIG 0x10
+#define MAILBOX_MESSAGE_BASE 0x40
+#define MAILBOX_FIFO_STATUS_BASE 0x80
+#define MAILBOX_MSG_STATUS_BASE 0xC0
+#define MAILBOX_IRQ_RAW_BASE 0x100
+#define MAILBOX_IRQ_CLR_BASE 0x104
+#define MAILBOX_IRQ_EN_SET_BASE 0x108
+#define MAILBOX_IRQ_EN_CLR_BASE 0x10C
+#define MAILBOX_IRQ_STRIDE 0x10
+#define MAILBOX_IRQ_EOI 0x140
+
+
+static uint32_t ti_mailbox_hw_raw_status(const TIMailboxState *s)
+{
+    uint32_t raw = 0;
+
+    for (int i = 0; i < TI_MAILBOX_NUM_MBOX; i++) {
+        const Fifo32 *f = &s->mbox[i];
+        uint32_t count = fifo32_num_used((Fifo32 *)f);
+
+        if (count > 0) {
+            raw |= BIT(i * 2);
+        }
+        if (count < s->fifo_depth) {
+            raw |= BIT(i * 2 + 1);
+        }
+    }
+
+    return raw;
+}
+
+static void ti_mailbox_update_irqs(TIMailboxState *s)
+{
+    uint32_t hw_raw = ti_mailbox_hw_raw_status(s);
+
+    for (int user = 0; user < s->num_users; user++) {
+        TIMailboxUser *u = &s->users[user];
+        uint32_t raw = (hw_raw & ~u->raw_clear_mask) | u->raw_set;
+        uint32_t masked = raw & u->irq_enable;
+        trace_ti_mailbox_irq_eval(s->mailbox_id, user, hw_raw, raw,
+                                  u->irq_enable, masked);
+        bool level = masked != 0;
+        if (level != u->irq_level) {
+            trace_ti_mailbox_irq(s->mailbox_id, user, level, raw, u->irq_enable,
+                                 masked);
+            u->irq_level = level;
+        }
+        qemu_set_irq(u->irq, level);
+    }
+}
+
+static bool ti_mailbox_fifo_push(TIMailboxState *s, int mb, uint32_t val)
+{
+    Fifo32 *f = &s->mbox[mb];
+    uint32_t used_before = fifo32_num_used(f);
+    bool ok = used_before < s->fifo_depth;
+
+    if (ok) {
+        fifo32_push(f, val);
+    }
+    trace_ti_mailbox_fifo_push(s->mailbox_id, mb, s->fifo_depth, used_before,
+                               val, ok);
+    return ok;
+}
+
+static bool ti_mailbox_fifo_pop(TIMailboxState *s, int mb, uint32_t *val)
+{
+    Fifo32 *f = &s->mbox[mb];
+    uint32_t used_before = fifo32_num_used(f);
+    bool ok = !fifo32_is_empty(f);
+    uint32_t out = 0;
+
+    if (ok) {
+        out = fifo32_pop(f);
+    }
+    if (val) {
+        *val = out;
+    }
+    trace_ti_mailbox_fifo_pop(s->mailbox_id, mb, s->fifo_depth, used_before,
+                              out, ok);
+    return ok;
+}
+
+static void ti_mailbox_fmt_opt_int(char *buf, size_t len, const char *key,
+                                   int value)
+{
+    if (value < 0) {
+        buf[0] = '\0';
+        return;
+    }
+
+    snprintf(buf, len, " %s=%d", key, value);
+}
+
+static void ti_mailbox_fmt_cpu(char *buf, size_t len)
+{
+    if (!current_cpu) {
+        snprintf(buf, len, " cpu=?");
+        return;
+    }
+
+    snprintf(buf, len, " cpu=%s:%d", object_get_typename(OBJECT(current_cpu)),
+             current_cpu->cpu_index);
+}
+
+static void ti_mailbox_irq_bits_to_str(uint32_t val, char *buf, size_t len)
+{
+    size_t pos = 0;
+    bool first = true;
+
+    for (int bit = 0; bit < TI_MAILBOX_NUM_MBOX * 2; bit++) {
+        if (!(val & BIT(bit))) {
+            continue;
+        }
+        if (pos < len) {
+            int mbox = bit / 2;
+            const char *event = (bit % 2 == 0) ? "newmsg" : "notfull";
+            int n = snprintf(buf + pos, len - pos, "%s%s:%d", first ? "" : ",",
+                             event, mbox);
+            if (n < 0 || (size_t)n >= len - pos) {
+                pos = len - 1;
+                break;
+            }
+            pos += n;
+            first = false;
+        }
+    }
+
+    if (first) {
+        g_strlcpy(buf, "-", len);
+    }
+}
+
+static const char *ti_mailbox_reg_name(hwaddr off, int *mbox, int *user)
+{
+    *mbox = -1;
+    *user = -1;
+
+    switch (off) {
+    case MAILBOX_REVISION:
+        return "MAILBOX_REVISION";
+    case MAILBOX_SYSCONFIG:
+        return "MAILBOX_SYSCONFIG";
+    case MAILBOX_IRQ_EOI:
+        return "MAILBOX_IRQ_EOI";
+    default:
+        break;
+    }
+
+    if (off >= MAILBOX_MESSAGE_BASE &&
+        off < MAILBOX_MESSAGE_BASE + TI_MAILBOX_NUM_MBOX * 4) {
+        *mbox = (off - MAILBOX_MESSAGE_BASE) / 4;
+        return "MAILBOX_MESSAGE_y";
+    }
+
+    if (off >= MAILBOX_FIFO_STATUS_BASE &&
+        off < MAILBOX_FIFO_STATUS_BASE + TI_MAILBOX_NUM_MBOX * 4) {
+        *mbox = (off - MAILBOX_FIFO_STATUS_BASE) / 4;
+        return "MAILBOX_FIFO_STATUS_y";
+    }
+
+    if (off >= MAILBOX_MSG_STATUS_BASE &&
+        off < MAILBOX_MSG_STATUS_BASE + TI_MAILBOX_NUM_MBOX * 4) {
+        *mbox = (off - MAILBOX_MSG_STATUS_BASE) / 4;
+        return "MAILBOX_MSG_STATUS_y";
+    }
+
+    if (off >= MAILBOX_IRQ_RAW_BASE &&
+        off < MAILBOX_IRQ_RAW_BASE +
+                  TI_MAILBOX_NUM_USERS_MAX * MAILBOX_IRQ_STRIDE) {
+        int rel;
+
+        *user = (off - MAILBOX_IRQ_RAW_BASE) / MAILBOX_IRQ_STRIDE;
+        rel = (off - MAILBOX_IRQ_RAW_BASE) % MAILBOX_IRQ_STRIDE;
+        switch (rel) {
+        case 0:
+            return "MAILBOX_IRQ_STATUS_RAW_j";
+        case 4:
+            return "MAILBOX_IRQ_STATUS_CLR_j";
+        case 8:
+            return "MAILBOX_IRQ_ENABLE_SET_j";
+        case 0x0C:
+            return "MAILBOX_IRQ_ENABLE_CLR_j";
+        default:
+            return "MAILBOX_IRQ_UNKNOWN";
+        }
+    }
+
+    return "UNKNOWN";
+}
+
+static uint64_t ti_mailbox_read(void *opaque, hwaddr off, unsigned size)
+{
+    TIMailboxState *s = opaque;
+    uint32_t hw_raw;
+    uint32_t raw;
+    uint32_t val;
+    int mb;
+    int user;
+
+    (void)size;
+
+#define TI_MAILBOX_TRACE_READ(_val)                                            \
+    do {                                                                       \
+        char irq_bits[64];                                                     \
+        char trace_cpu_str[64];                                                \
+        char trace_mbox_str[24];                                               \
+        char trace_user_str[24];                                               \
+        char trace_bits_str[96];                                               \
+        int trace_mbox;                                                        \
+        int trace_user;                                                        \
+        const char *trace_reg =                                                \
+            ti_mailbox_reg_name(off, &trace_mbox, &trace_user);                \
+        const char *trace_bits = "-";                                          \
+        const char *trace_bits_strp = "";                                      \
+        if (!strcmp(trace_reg, "MAILBOX_IRQ_STATUS_RAW_j") ||                  \
+            !strcmp(trace_reg, "MAILBOX_IRQ_STATUS_CLR_j") ||                  \
+            !strcmp(trace_reg, "MAILBOX_IRQ_ENABLE_SET_j") ||                  \
+            !strcmp(trace_reg, "MAILBOX_IRQ_ENABLE_CLR_j")) {                  \
+            ti_mailbox_irq_bits_to_str((uint32_t)(_val), irq_bits,             \
+                                       sizeof(irq_bits));                      \
+            trace_bits = irq_bits;                                             \
+            snprintf(trace_bits_str, sizeof(trace_bits_str), " irq_bits=%s",   \
+                     trace_bits);                                              \
+            trace_bits_strp = trace_bits_str;                                  \
+        }                                                                      \
+        ti_mailbox_fmt_cpu(trace_cpu_str, sizeof(trace_cpu_str));              \
+        ti_mailbox_fmt_opt_int(trace_mbox_str, sizeof(trace_mbox_str), "mbox", \
+                               trace_mbox);                                    \
+        ti_mailbox_fmt_opt_int(trace_user_str, sizeof(trace_user_str), "user", \
+                               trace_user);                                    \
+        trace_ti_mailbox_read(                                                 \
+            (uint64_t)off, (uint32_t)(_val), size, trace_reg, s->mailbox_id,   \
+            trace_cpu_str, trace_mbox_str, trace_user_str, trace_bits_strp);   \
+        return (_val);                                                         \
+    } while (0)
+
+    switch (off) {
+    case MAILBOX_REVISION:
+        TI_MAILBOX_TRACE_READ(0x66FC8900);
+    case MAILBOX_SYSCONFIG:
+        TI_MAILBOX_TRACE_READ(0);
+    case MAILBOX_IRQ_EOI:
+        TI_MAILBOX_TRACE_READ(0);
+    default:
+        break;
+    }
+
+    if (off >= MAILBOX_MESSAGE_BASE &&
+        off < MAILBOX_MESSAGE_BASE + TI_MAILBOX_NUM_MBOX * 4) {
+        mb = (off - MAILBOX_MESSAGE_BASE) / 4;
+        if (!ti_mailbox_fifo_pop(s, mb, &val)) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: read empty mailbox %d\n",
+                          TYPE_TI_MAILBOX, mb);
+            TI_MAILBOX_TRACE_READ(0);
+        }
+        ti_mailbox_update_irqs(s);
+        TI_MAILBOX_TRACE_READ(val);
+    }
+
+    if (off >= MAILBOX_FIFO_STATUS_BASE &&
+        off < MAILBOX_FIFO_STATUS_BASE + TI_MAILBOX_NUM_MBOX * 4) {
+        mb = (off - MAILBOX_FIFO_STATUS_BASE) / 4;
+        TI_MAILBOX_TRACE_READ(
+            fifo32_num_used(&s->mbox[mb]) >= s->fifo_depth ? 1 : 0);
+    }
+
+    if (off >= MAILBOX_MSG_STATUS_BASE &&
+        off < MAILBOX_MSG_STATUS_BASE + TI_MAILBOX_NUM_MBOX * 4) {
+        mb = (off - MAILBOX_MSG_STATUS_BASE) / 4;
+        TI_MAILBOX_TRACE_READ(fifo32_num_used(&s->mbox[mb]) & 0x7);
+    }
+
+    if (off >= MAILBOX_IRQ_RAW_BASE &&
+        off < MAILBOX_IRQ_RAW_BASE +
+                  TI_MAILBOX_NUM_USERS_MAX * MAILBOX_IRQ_STRIDE) {
+        user = (off - MAILBOX_IRQ_RAW_BASE) / MAILBOX_IRQ_STRIDE;
+        if (user >= s->num_users) {
+            TI_MAILBOX_TRACE_READ(0);
+        }
+        hw_raw = ti_mailbox_hw_raw_status(s);
+        raw =
+            (hw_raw & ~s->users[user].raw_clear_mask) | s->users[user].raw_set;
+        if ((off - MAILBOX_IRQ_RAW_BASE) % MAILBOX_IRQ_STRIDE == 0) {
+            TI_MAILBOX_TRACE_READ(raw);
+        }
+        if ((off - MAILBOX_IRQ_RAW_BASE) % MAILBOX_IRQ_STRIDE == 4) {
+            TI_MAILBOX_TRACE_READ(raw & s->users[user].irq_enable);
+        }
+        if ((off - MAILBOX_IRQ_RAW_BASE) % MAILBOX_IRQ_STRIDE == 8) {
+            TI_MAILBOX_TRACE_READ(s->users[user].irq_enable);
+        }
+        if ((off - MAILBOX_IRQ_RAW_BASE) % MAILBOX_IRQ_STRIDE == 0x0C) {
+            TI_MAILBOX_TRACE_READ(s->users[user].irq_enable);
+        }
+    }
+
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "%s: invalid read offset 0x%" HWADDR_PRIx "\n",
+                  TYPE_TI_MAILBOX, off);
+    TI_MAILBOX_TRACE_READ(0);
+
+#undef TI_MAILBOX_TRACE_READ
+}
+
+static void ti_mailbox_write(void *opaque, hwaddr off, uint64_t val,
+                             unsigned size)
+{
+    TIMailboxState *s = opaque;
+    int mb;
+    int user;
+    int rel;
+
+    (void)size;
+
+    {
+        char irq_bits[64];
+        char trace_cpu_str[64];
+        char trace_mbox_str[24];
+        char trace_user_str[24];
+        char trace_bits_str[96];
+        int trace_mbox;
+        int trace_user;
+        const char *trace_reg =
+            ti_mailbox_reg_name(off, &trace_mbox, &trace_user);
+        const char *trace_bits = "-";
+        const char *trace_bits_strp = "";
+
+        if (!strcmp(trace_reg, "MAILBOX_IRQ_STATUS_RAW_j") ||
+            !strcmp(trace_reg, "MAILBOX_IRQ_STATUS_CLR_j") ||
+            !strcmp(trace_reg, "MAILBOX_IRQ_ENABLE_SET_j") ||
+            !strcmp(trace_reg, "MAILBOX_IRQ_ENABLE_CLR_j")) {
+            ti_mailbox_irq_bits_to_str((uint32_t)val, irq_bits,
+                                       sizeof(irq_bits));
+            trace_bits = irq_bits;
+            snprintf(trace_bits_str, sizeof(trace_bits_str), " irq_bits=%s",
+                     trace_bits);
+            trace_bits_strp = trace_bits_str;
+        }
+
+        ti_mailbox_fmt_cpu(trace_cpu_str, sizeof(trace_cpu_str));
+        ti_mailbox_fmt_opt_int(trace_mbox_str, sizeof(trace_mbox_str), "mbox",
+                               trace_mbox);
+        ti_mailbox_fmt_opt_int(trace_user_str, sizeof(trace_user_str), "user",
+                               trace_user);
+        trace_ti_mailbox_write((uint64_t)off, (uint32_t)val, size, trace_reg,
+                               s->mailbox_id, trace_cpu_str, trace_mbox_str,
+                               trace_user_str, trace_bits_strp);
+    }
+
+    switch (off) {
+    case MAILBOX_SYSCONFIG:
+        if (val & 0x1) {
+            for (int i = 0; i < TI_MAILBOX_NUM_MBOX; i++) {
+                fifo32_reset(&s->mbox[i]);
+            }
+            for (int i = 0; i < s->num_users; i++) {
+                TIMailboxUser *u = &s->users[i];
+
+                u->irq_enable = 0;
+                u->raw_set = 0;
+                u->raw_clear_mask = 0;
+            }
+            ti_mailbox_update_irqs(s);
+        }
+        return;
+    case MAILBOX_IRQ_EOI:
+        return;
+    default:
+        break;
+    }
+
+    if (off >= MAILBOX_MESSAGE_BASE &&
+        off < MAILBOX_MESSAGE_BASE + TI_MAILBOX_NUM_MBOX * 4) {
+        mb = (off - MAILBOX_MESSAGE_BASE) / 4;
+        {
+            char trace_cpu_str[64];
+            uint64_t pc = current_cpu
+                              ? (uint64_t)current_cpu->cc->get_pc(current_cpu)
+                              : 0;
+
+            ti_mailbox_fmt_cpu(trace_cpu_str, sizeof(trace_cpu_str));
+            trace_ti_mailbox_msg_write_pc(s->mailbox_id, mb, pc, trace_cpu_str);
+        }
+        if (!ti_mailbox_fifo_push(s, mb, (uint32_t)val)) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: mailbox %d full\n",
+                          TYPE_TI_MAILBOX, mb);
+            return;
+        }
+        ti_mailbox_update_irqs(s);
+        return;
+    }
+
+    if (off >= MAILBOX_IRQ_RAW_BASE &&
+        off < MAILBOX_IRQ_RAW_BASE +
+                  TI_MAILBOX_NUM_USERS_MAX * MAILBOX_IRQ_STRIDE) {
+        user = (off - MAILBOX_IRQ_RAW_BASE) / MAILBOX_IRQ_STRIDE;
+        if (user >= s->num_users) {
+            return;
+        }
+        rel = (off - MAILBOX_IRQ_RAW_BASE) % MAILBOX_IRQ_STRIDE;
+        uint32_t mask = (uint32_t)val;
+
+        if (rel == 0) {
+            if (mask == 0) {
+                return;
+            }
+            s->users[user].raw_set |= mask;
+            trace_ti_mailbox_raw_set(s->mailbox_id, user, mask,
+                                     s->users[user].raw_set);
+            ti_mailbox_update_irqs(s);
+            return;
+        }
+        if (rel == 4) {
+            if (mask == 0) {
+                return;
+            }
+            s->users[user].raw_set &= ~mask;
+            s->users[user].raw_clear_mask &= ~mask;
+            trace_ti_mailbox_raw_clear(s->mailbox_id, user, mask,
+                                       s->users[user].raw_set,
+                                       s->users[user].raw_clear_mask);
+            ti_mailbox_update_irqs(s);
+            return;
+        }
+        if (rel == 8) {
+            s->users[user].irq_enable |= mask;
+            trace_ti_mailbox_irq_enable(s->mailbox_id, user, 1, mask,
+                                        s->users[user].irq_enable);
+            ti_mailbox_update_irqs(s);
+            return;
+        }
+        if (rel == 0x0C) {
+            s->users[user].irq_enable &= ~mask;
+            trace_ti_mailbox_irq_enable(s->mailbox_id, user, 0, mask,
+                                        s->users[user].irq_enable);
+            ti_mailbox_update_irqs(s);
+            return;
+        }
+    }
+
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "%s: invalid write offset 0x%" HWADDR_PRIx "\n",
+                  TYPE_TI_MAILBOX, off);
+}
+
+static const MemoryRegionOps ti_mailbox_ops = {
+    .read = ti_mailbox_read,
+    .write = ti_mailbox_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+};
+
+static void ti_mailbox_reset(DeviceState *dev)
+{
+    TIMailboxState *s = TI_MAILBOX(dev);
+
+    trace_ti_mailbox_reset_state(s->mailbox_id);
+    for (int i = 0; i < TI_MAILBOX_NUM_MBOX; i++) {
+        fifo32_reset(&s->mbox[i]);
+    }
+    for (int i = 0; i < s->num_users; i++) {
+        TIMailboxUser *u = &s->users[i];
+
+        u->irq_enable = 0;
+        u->raw_set = 0;
+        u->raw_clear_mask = 0;
+        u->irq_level = false;
+    }
+
+    ti_mailbox_update_irqs(s);
+}
+
+static void ti_mailbox_realize(DeviceState *dev, Error **errp)
+{
+    TIMailboxState *s = TI_MAILBOX(dev);
+
+    if (s->num_users == 0 || s->num_users > TI_MAILBOX_NUM_USERS_MAX) {
+        error_setg(errp, "num-users must be between 1 and %u",
+                   TI_MAILBOX_NUM_USERS_MAX);
+        return;
+    }
+
+    if (s->fifo_depth == 0 || s->fifo_depth > TI_MAILBOX_FIFO_DEPTH_MAX) {
+        error_setg(errp, "fifo-depth must be between 1 and %u",
+                   TI_MAILBOX_FIFO_DEPTH_MAX);
+        return;
+    }
+
+    for (int i = 0; i < TI_MAILBOX_NUM_MBOX; i++) {
+        fifo32_create(&s->mbox[i], s->fifo_depth);
+    }
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &ti_mailbox_ops, s,
+                          TYPE_TI_MAILBOX, TI_MAILBOX_MMIO_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+
+    for (int i = 0; i < s->num_users; i++) {
+        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->users[i].irq);
+    }
+}
+
+static void ti_mailbox_finalize(Object *obj)
+{
+    TIMailboxState *s = TI_MAILBOX(obj);
+
+    for (int i = 0; i < TI_MAILBOX_NUM_MBOX; i++) {
+        fifo32_destroy(&s->mbox[i]);
+    }
+}
+
+static const Property ti_mailbox_properties[] = {
+    DEFINE_PROP_UINT8("num-users", TIMailboxState, num_users,
+                      TI_MAILBOX_NUM_USERS_DEFAULT),
+    DEFINE_PROP_UINT8("fifo-depth", TIMailboxState, fifo_depth,
+                      TI_MAILBOX_FIFO_DEPTH_DEFAULT),
+    DEFINE_PROP_UINT8("mailbox-id", TIMailboxState, mailbox_id, 0),
+};
+
+static void ti_mailbox_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    device_class_set_legacy_reset(dc, ti_mailbox_reset);
+    dc->realize = ti_mailbox_realize;
+    dc->user_creatable = false;
+    device_class_set_props(dc, ti_mailbox_properties);
+}
+
+static const TypeInfo ti_mailbox_types[] = {
+    {
+    .name = TYPE_TI_MAILBOX,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TIMailboxState),
+    .class_init = ti_mailbox_class_init,
+    .instance_finalize = ti_mailbox_finalize,
+    }
+};
+
+DEFINE_TYPES(ti_mailbox_types)
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index fae1f90ee2..ea7cde021e 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -69,6 +69,19 @@ ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= 0x%0
 # empty_slot.c
 empty_slot_write(uint64_t addr, unsigned width, uint64_t value, unsigned size, const char *name) "wr addr:0x%04"PRIx64" data:0x%0*"PRIx64" size %u [%s]"
 
+# ti-mailbox.c
+ti_mailbox_read(uint64_t offset, uint32_t value, unsigned size, const char *reg, uint8_t mailbox_id, const char *cpu_str, const char *mbox_str, const char *user_str, const char *irq_bits_str) "off=0x%" PRIx64 " value=0x%08x size=%u reg=%s mailbox_id=%u%s%s%s%s"
+ti_mailbox_write(uint64_t offset, uint32_t value, unsigned size, const char *reg, uint8_t mailbox_id, const char *cpu_str, const char *mbox_str, const char *user_str, const char *irq_bits_str) "off=0x%" PRIx64 " value=0x%08x size=%u reg=%s mailbox_id=%u%s%s%s%s"
+ti_mailbox_irq(uint8_t mailbox_id, uint8_t user, int level, uint32_t raw, uint32_t enable, uint32_t masked) "mailbox_id=%u user=%u level=%d raw=0x%08x enable=0x%08x masked=0x%08x"
+ti_mailbox_irq_eval(uint8_t mailbox_id, uint8_t user, uint32_t hw_raw, uint32_t raw, uint32_t enable, uint32_t masked) "mailbox_id=%u user=%u hw_raw=0x%08x raw=0x%08x enable=0x%08x masked=0x%08x"
+ti_mailbox_fifo_push(uint8_t mailbox_id, int mbox, uint8_t depth, uint32_t used_before, uint32_t val, int ok) "mailbox_id=%u mbox=%d depth=%u used_before=%u val=0x%08x ok=%d"
+ti_mailbox_fifo_pop(uint8_t mailbox_id, int mbox, uint8_t depth, uint32_t used_before, uint32_t val, int ok) "mailbox_id=%u mbox=%d depth=%u used_before=%u val=0x%08x ok=%d"
+ti_mailbox_reset_state(uint8_t mailbox_id) "mailbox_id=%u reset"
+ti_mailbox_raw_set(uint8_t mailbox_id, uint8_t user, uint32_t mask, uint32_t raw_set) "mailbox_id=%u user=%u mask=0x%08x raw_set=0x%08x"
+ti_mailbox_raw_clear(uint8_t mailbox_id, uint8_t user, uint32_t mask, uint32_t raw_set, uint32_t raw_clear_mask) "mailbox_id=%u user=%u mask=0x%08x raw_set=0x%08x raw_clear_mask=0x%08x"
+ti_mailbox_irq_enable(uint8_t mailbox_id, uint8_t user, int set, uint32_t mask, uint32_t irq_enable) "mailbox_id=%u user=%u set=%d mask=0x%08x irq_enable=0x%08x"
+ti_mailbox_msg_write_pc(uint8_t mailbox_id, int mbox, uint64_t pc, const char *cpu_str) "mailbox_id=%u mbox=%d pc=0x%" PRIx64 "%s"
+
 # slavio_misc.c
 slavio_misc_update_irq_raise(void) "Raise IRQ"
 slavio_misc_update_irq_lower(void) "Lower IRQ"
diff --git a/include/hw/misc/ti-mailbox.h b/include/hw/misc/ti-mailbox.h
new file mode 100644
index 0000000000..9cfc3b8fc2
--- /dev/null
+++ b/include/hw/misc/ti-mailbox.h
@@ -0,0 +1,44 @@
+/*
+ * TI mailbox (IPC)
+ *
+ * Copyright (c) 2025 CMBLU Energy AG
+ * Author: Wadim Mueller <wafgo01@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef TI_MAILBOX_H
+#define TI_MAILBOX_H
+
+#include "qemu/fifo32.h"
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_TI_MAILBOX "ti-mailbox"
+OBJECT_DECLARE_SIMPLE_TYPE(TIMailboxState, TI_MAILBOX)
+
+#define TI_MAILBOX_NUM_MBOX 16
+#define TI_MAILBOX_NUM_USERS_MAX 4
+#define TI_MAILBOX_NUM_USERS_DEFAULT 4
+#define TI_MAILBOX_FIFO_DEPTH_MAX 4
+#define TI_MAILBOX_FIFO_DEPTH_DEFAULT 4
+
+typedef struct TIMailboxUser {
+    uint32_t irq_enable;
+    uint32_t raw_set;
+    uint32_t raw_clear_mask;
+    bool irq_level;
+    qemu_irq irq;
+} TIMailboxUser;
+
+struct TIMailboxState {
+    SysBusDevice parent_obj;
+    MemoryRegion iomem;
+    Fifo32 mbox[TI_MAILBOX_NUM_MBOX];
+    TIMailboxUser users[TI_MAILBOX_NUM_USERS_MAX];
+    uint8_t num_users;
+    uint8_t fifo_depth;
+    uint8_t mailbox_id;
+};
+
+#endif
-- 
2.43.0



  parent reply	other threads:[~2026-08-20 12:50 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-20 12:48 [RFC PATCH v2 00/14] hw/arm: add TI AM64x SoC and am64-virt machine Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 01/14] hw/i2c/omap_i2c: add a dedicated CONFIG_OMAP_I2C symbol Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 02/14] hw/i2c/omap_i2c: implement soft reset and NACK reporting Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 03/14] hw/sd/sdhci: complete non-interrupt ADMA descriptor chains in one pass Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 04/14] hw/char: add TI AM64x UART model Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 05/14] hw/timer: add TI K3 DMTimer model Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 06/14] hw/misc: add TI K3 CTRL_MMR, GTC, DDRSS, SDHCI PHY and TRNG models Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 07/14] hw/misc: add TI RAT (region address translation) model Wadim Mueller
2026-08-20 12:48 ` Wadim Mueller [this message]
2026-08-20 12:48 ` [RFC PATCH v2 09/14] hw/misc: add TI K3 secure proxy model Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 10/14] hw/misc: add TI DMSC (TI-SCI system controller) model Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 11/14] hw/arm: add TI K3 combined boot image parser Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 12/14] hw/arm: add TI AM64x SoC model Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 13/14] hw/arm: add the am64-virt machine Wadim Mueller
2026-08-20 12:48 ` [RFC PATCH v2 14/14] tests: add AM64x unit, qtest and functional tests Wadim Mueller
2026-08-20 16:25   ` Alex Bennée
2026-08-22 21:04     ` Wadim Mueller
2026-08-21 10:26 ` [RFC PATCH v2 00/14] hw/arm: add TI AM64x SoC and am64-virt machine Alex Bennée
2026-08-22 21:06   ` Wadim Mueller
2026-08-21 16:35 ` Nick Huang
2026-08-22 21:07   ` Wadim Mueller
2026-08-22  5:22 ` Bin Meng
2026-08-22 21:13   ` Wadim Mueller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260820124824.618671-9-wafgo01@gmail.com \
    --to=wafgo01@gmail.com \
    --cc=bmeng.cn@gmail.com \
    --cc=farosas@suse.de \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@mailo.com \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox