All of 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: 15+ 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

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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.