QEMU-Arm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Kyle Fox <kylefoxaustin.github@gmail.com>
To: qemu-devel@nongnu.org
Cc: "Kyle Fox" <kylefoxaustin.github@gmail.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	qemu-arm@nongnu.org (open list:i.MX31 (kzm))
Subject: [PATCH 05/16] hw/char: add i.MX LPUART
Date: Wed, 19 Aug 2026 21:48:23 -0500	[thread overview]
Message-ID: <20260820024834.3286721-6-kylefoxaustin.github@gmail.com> (raw)
In-Reply-To: <20260820024834.3286721-1-kylefoxaustin.github@gmail.com>

The i.MX Low-Power UART. Models the register subset the Linux fsl-lpuart
driver and the SM firmware drive (BAUD/CTRL/STAT/DATA plus the TX/RX
FIFOs) as an interrupt- and poll-capable serial device. On this machine
LPUART1 is the Linux console (ttyLP0), LPUART2 the SM debug monitor and
LPUART3 the M7 console.

Signed-off-by: Kyle Fox <kylefoxaustin.github@gmail.com>
---
 hw/char/Kconfig              |   3 +
 hw/char/imx_lpuart.c         | 382 +++++++++++++++++++++++++++++++++++
 hw/char/meson.build          |   1 +
 hw/char/trace-events         |   3 +
 include/hw/char/imx_lpuart.h | 123 +++++++++++
 5 files changed, 512 insertions(+)
 create mode 100644 hw/char/imx_lpuart.c
 create mode 100644 include/hw/char/imx_lpuart.h

diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 020c0a84bb6..51b4c3e00ce 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -95,3 +95,6 @@ config IP_OCTAL_232
     bool
     default y
     depends on IPACK
+
+config IMX_LPUART
+    bool
diff --git a/hw/char/imx_lpuart.c b/hw/char/imx_lpuart.c
new file mode 100644
index 00000000000..714bc3e52a4
--- /dev/null
+++ b/hw/char/imx_lpuart.c
@@ -0,0 +1,382 @@
+/*
+ * NXP i.MX LPUART (Low-Power UART) device model
+ *
+ * Copyright (c) 2026, Kyle Fox
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Modelled on hw/char/imx_serial.c for structural conventions but with
+ * the LPUART register set and semantics. TX bytes are pushed through the
+ * chardev backend synchronously; RX bytes are buffered one-deep and
+ * surface in DATA, with an interrupt raised when CTRL.RIE is set.
+ * FIFO depth is reported as 1; no DMA, no baud-rate timing, no flow
+ * control are modelled.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/char/imx_lpuart.h"
+#include "hw/core/irq.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/qdev-properties-system.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+static void imx_lpuart_update_irq(IMXLPUARTState *s);
+
+static int imx_lpuart_post_load(void *opaque, int version_id)
+{
+    /* Recompute the IRQ line level from the restored register state. */
+    imx_lpuart_update_irq(opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_imx_lpuart = {
+    .name = TYPE_IMX_LPUART,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = imx_lpuart_post_load,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32(baud, IMXLPUARTState),
+        VMSTATE_UINT32(stat, IMXLPUARTState),
+        VMSTATE_UINT32(ctrl, IMXLPUARTState),
+        VMSTATE_UINT32(match, IMXLPUARTState),
+        VMSTATE_UINT32(modir, IMXLPUARTState),
+        VMSTATE_UINT32(fifo, IMXLPUARTState),
+        VMSTATE_UINT32(water, IMXLPUARTState),
+        VMSTATE_UINT32(pincfg, IMXLPUARTState),
+        VMSTATE_UINT8(rx_byte, IMXLPUARTState),
+        VMSTATE_BOOL(rx_full, IMXLPUARTState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+/* Recompute the IRQ line from STAT & CTRL interrupt-enable bits. */
+static void imx_lpuart_update_irq(IMXLPUARTState *s)
+{
+    bool level =
+        ((s->stat & LPUART_STAT_RDRF) && (s->ctrl & LPUART_CTRL_RIE)) ||
+        ((s->stat & LPUART_STAT_TDRE) && (s->ctrl & LPUART_CTRL_TIE)) ||
+        ((s->stat & LPUART_STAT_TC)   && (s->ctrl & LPUART_CTRL_TCIE)) ||
+        ((s->stat & LPUART_STAT_IDLE) && (s->ctrl & LPUART_CTRL_ILIE));
+
+    qemu_set_irq(s->irq, level);
+}
+
+static void imx_lpuart_reset(IMXLPUARTState *s)
+{
+    /*
+     * Power-on reset values per the i.MX LPUART chapter. STAT comes up
+     * with TDRE and TC set because the FIFO is empty.
+     */
+    s->baud   = 0x0F000004;     /* default OSR = 4 + SBR field */
+    s->stat   = LPUART_STAT_TDRE | LPUART_STAT_TC;
+    s->ctrl   = 0;
+    s->match  = 0;
+    s->modir  = 0;
+    s->fifo   = 0;
+    s->water  = 0;
+    s->pincfg = 0;
+    s->rx_byte = 0;
+    s->rx_full = false;
+}
+
+static void imx_lpuart_reset_at_boot_hold(Object *obj, ResetType type)
+{
+    IMXLPUARTState *s = IMX_LPUART(obj);
+
+    imx_lpuart_reset(s);
+    imx_lpuart_update_irq(s);
+}
+
+static uint64_t imx_lpuart_read(void *opaque, hwaddr offset, unsigned size)
+{
+    IMXLPUARTState *s = opaque;
+    uint32_t value = 0;
+    uint32_t c;
+
+    switch (offset) {
+    case LPUART_VERID:
+        value = LPUART_VERID_VALUE;
+        break;
+
+    case LPUART_PARAM:
+        /* TXFIFO and RXFIFO size fields both zero -> depth = 1. */
+        value = 0;
+        break;
+
+    case LPUART_GLOBAL:
+        value = 0;
+        break;
+
+    case LPUART_PINCFG:
+        value = s->pincfg;
+        break;
+
+    case LPUART_BAUD:
+        value = s->baud;
+        break;
+
+    case LPUART_STAT:
+        value = s->stat;
+        break;
+
+    case LPUART_CTRL:
+        value = s->ctrl;
+        break;
+
+    case LPUART_DATA:
+        if (s->rx_full) {
+            c = s->rx_byte;
+            s->rx_full = false;
+            s->stat &= ~LPUART_STAT_RDRF;
+            value = c & LPUART_DATA_MASK;
+            imx_lpuart_update_irq(s);
+            qemu_chr_fe_accept_input(&s->chr);
+        } else {
+            value = LPUART_DATA_RXEMPT;
+        }
+        break;
+
+    case LPUART_MATCH:
+        value = s->match;
+        break;
+
+    case LPUART_MODIR:
+        value = s->modir;
+        break;
+
+    case LPUART_FIFO:
+        /*
+         * Report the FIFO control bits the guest set, plus the read-only
+         * TXEMPT/RXEMPT status computed from our 1-deep model. The status
+         * bits must be derived fresh, never returned from s->fifo: the Linux
+         * driver read-modify-writes UARTFIFO during setup, so a stored RXEMPT
+         * would stick set and make its RX drain loop (while !(FIFO & RXEMPT))
+         * believe the RX FIFO is always empty - it would never read DATA, RDRF
+         * would never clear, and the RX interrupt would storm.
+         */
+        value = s->fifo & ~(LPUART_FIFO_TXEMPT | LPUART_FIFO_RXEMPT);
+        value |= LPUART_FIFO_TXEMPT;  /* we drain TX instantly */
+        if (!s->rx_full) {
+            value |= LPUART_FIFO_RXEMPT;
+        }
+        break;
+
+    case LPUART_WATER:
+        /*
+         * Reflect the current fifo state in the RX/TX count fields
+         * (bits[31:24] RXCOUNT, bits[15:8] TXCOUNT). U-Boot's
+         * _lpuart32_serial_tstc() polls (water >> 24) for incoming-
+         * char detection, so RXCOUNT must update when imx_lpuart_receive
+         * stashes a byte. We are 1-deep: 0 or 1 in either slot.
+         * Preserve the guest-written watermark bits unchanged.
+         */
+        value = (s->water & 0x00ff00ffu)
+              | ((uint32_t)(s->rx_full ? 1 : 0) << 24)
+              | 0u;  /* TXCOUNT always 0 - we drain TR writes instantly */
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+                      __func__, offset);
+        break;
+    }
+
+    return value;
+}
+
+static void imx_lpuart_write(void *opaque, hwaddr offset,
+                             uint64_t value, unsigned size)
+{
+    IMXLPUARTState *s = opaque;
+    uint8_t ch;
+
+    switch (offset) {
+    case LPUART_VERID:
+    case LPUART_PARAM:
+        /* Read-only registers; silently ignore writes (HW behavior). */
+        break;
+
+    case LPUART_GLOBAL:
+        if (value & LPUART_GLOBAL_RST) {
+            imx_lpuart_reset(s);
+            imx_lpuart_update_irq(s);
+        }
+        break;
+
+    case LPUART_PINCFG:
+        s->pincfg = value;
+        break;
+
+    case LPUART_BAUD:
+        /*
+         * Baud-rate timing isn't modelled, but the driver reads back what
+         * it wrote. Preserve DMA-enable and other configuration bits.
+         */
+        s->baud = value;
+        trace_imx_lpuart_baud(s->baud);
+        break;
+
+    case LPUART_STAT:
+        /*
+         * STAT bits IDLE and OR are W1C; the rest are read-only status
+         * managed by the model.
+         */
+        s->stat &= ~(value & LPUART_STAT_W1C_MASK);
+        imx_lpuart_update_irq(s);
+        break;
+
+    case LPUART_CTRL:
+        s->ctrl = value;
+        imx_lpuart_update_irq(s);
+        break;
+
+    case LPUART_DATA:
+        ch = value & LPUART_DATA_MASK;
+        /*
+         * Always push the byte through the chardev backend, even if
+         * CTRL_TE is currently 0. Real silicon would queue or drop the
+         * byte until TE is enabled; in emulation we don't model that
+         * gating because some consumers (notably the Linux earlycon
+         * path under -kernel direct boot, which assumes firmware
+         * already set TE before the kernel runs) write to DATA without
+         * first enabling TE themselves. Without this, kernel console
+         * output vanishes silently and earlycon appears broken.
+         */
+        trace_imx_lpuart_tx(ch);
+        qemu_chr_fe_write_all(&s->chr, &ch, 1);
+        /*
+         * TDRE and TC are pinned high; the byte goes out instantly. A
+         * future model would clear them for one host tick, then set TC
+         * when the line goes idle.
+         */
+        s->stat |= LPUART_STAT_TDRE | LPUART_STAT_TC;
+        imx_lpuart_update_irq(s);
+        break;
+
+    case LPUART_MATCH:
+        s->match = value;
+        break;
+
+    case LPUART_MODIR:
+        s->modir = value;
+        break;
+
+    case LPUART_FIFO:
+        /*
+         * Store only the writable configuration bits. The read-only status
+         * bits (TXEMPT/RXEMPT/TXOF/RXUF) and the self-clearing flush commands
+         * (TXFLUSH/RXFLUSH) must NOT be latched: the driver read-modify-writes
+         * UARTFIFO, so latching RXEMPT would make it stick set and break the
+         * RX drain loop (see the FIFO read).
+         */
+        s->fifo = value & ~LPUART_FIFO_RO_MASK;
+        if (value & LPUART_FIFO_RXFLUSH) {
+            s->rx_full = false;
+            s->stat &= ~LPUART_STAT_RDRF;
+        }
+        imx_lpuart_update_irq(s);
+        break;
+
+    case LPUART_WATER:
+        s->water = value;
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: bad write offset 0x%" HWADDR_PRIx
+                      " value 0x%" PRIx64 "\n",
+                      __func__, offset, value);
+        break;
+    }
+}
+
+static int imx_lpuart_can_receive(void *opaque)
+{
+    IMXLPUARTState *s = opaque;
+
+    return ((s->ctrl & LPUART_CTRL_RE) && !s->rx_full) ? 1 : 0;
+}
+
+static void imx_lpuart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    IMXLPUARTState *s = opaque;
+
+    if (size <= 0 || s->rx_full) {
+        return;
+    }
+
+    s->rx_byte = buf[0];
+    s->rx_full = true;
+    trace_imx_lpuart_rx(s->rx_byte);
+    s->stat |= LPUART_STAT_RDRF;
+    imx_lpuart_update_irq(s);
+}
+
+static const MemoryRegionOps imx_lpuart_ops = {
+    .read = imx_lpuart_read,
+    .write = imx_lpuart_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void imx_lpuart_realize(DeviceState *dev, Error **errp)
+{
+    IMXLPUARTState *s = IMX_LPUART(dev);
+
+    qemu_chr_fe_set_handlers(&s->chr, imx_lpuart_can_receive,
+                             imx_lpuart_receive, NULL, NULL, s, NULL, true);
+}
+
+static void imx_lpuart_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    IMXLPUARTState *s = IMX_LPUART(obj);
+
+    memory_region_init_io(&s->iomem, obj, &imx_lpuart_ops, s,
+                          TYPE_IMX_LPUART, IMX_LPUART_REG_SIZE);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq);
+}
+
+static const Property imx_lpuart_properties[] = {
+    DEFINE_PROP_CHR("chardev", IMXLPUARTState, chr),
+};
+
+static void imx_lpuart_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+    dc->realize = imx_lpuart_realize;
+    dc->vmsd = &vmstate_imx_lpuart;
+    rc->phases.hold = imx_lpuart_reset_at_boot_hold;
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+    dc->desc = "NXP i.MX LPUART";
+    device_class_set_props(dc, imx_lpuart_properties);
+}
+
+static const TypeInfo imx_lpuart_info = {
+    .name           = TYPE_IMX_LPUART,
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(IMXLPUARTState),
+    .instance_init  = imx_lpuart_init,
+    .class_init     = imx_lpuart_class_init,
+};
+
+static void imx_lpuart_register_types(void)
+{
+    type_register_static(&imx_lpuart_info);
+}
+
+type_init(imx_lpuart_register_types)
diff --git a/hw/char/meson.build b/hw/char/meson.build
index fc3d7ee506f..440142ae803 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -41,3 +41,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_TTY', if_true: files('goldfish_tty.c'))
 
 specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c'))
 specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_vty.c'))
+system_ss.add(when: 'CONFIG_IMX_LPUART', if_true: files('imx_lpuart.c'))
diff --git a/hw/char/trace-events b/hw/char/trace-events
index a3fcc772877..6d9b71961e5 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -141,3 +141,6 @@ stm32f2xx_usart_receive(char *id, uint8_t chr) " %s receiving '%c'"
 # riscv_htif.c
 htif_uart_write_to_host(uint8_t device, uint8_t cmd, uint64_t payload) "device: %u cmd: %02u payload: %016" PRIx64
 htif_uart_unknown_device_command(uint8_t device, uint8_t cmd, uint64_t payload) "device: %u cmd: %02u payload: %016" PRIx64
+imx_lpuart_tx(uint8_t ch) "tx 0x%02x"
+imx_lpuart_rx(uint8_t ch) "rx 0x%02x"
+imx_lpuart_baud(uint32_t baud) "baud <- 0x%08x"
diff --git a/include/hw/char/imx_lpuart.h b/include/hw/char/imx_lpuart.h
new file mode 100644
index 00000000000..a18809c432f
--- /dev/null
+++ b/include/hw/char/imx_lpuart.h
@@ -0,0 +1,123 @@
+/*
+ * NXP i.MX LPUART (Low-Power UART) device model
+ *
+ * Copyright (c) 2026, Kyle Fox
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Models the LPUART IP found in i.MX 7ULP / 8ULP / 8QXP / 95 and other
+ * recent NXP SoCs. Register layout matches the
+ * "fsl,imx95-lpuart" / "fsl,imx8ulp-lpuart" / "fsl,imx7ulp-lpuart"
+ * compatible string in the Linux fsl_lpuart driver.
+ */
+
+#ifndef IMX_LPUART_H
+#define IMX_LPUART_H
+
+#include "hw/core/sysbus.h"
+#include "chardev/char-fe.h"
+#include "qom/object.h"
+
+#define TYPE_IMX_LPUART "imx.lpuart"
+OBJECT_DECLARE_SIMPLE_TYPE(IMXLPUARTState, IMX_LPUART)
+
+/* MMIO size of one LPUART instance (from the device tree). */
+#define IMX_LPUART_REG_SIZE     0x1000
+
+/*
+ * Register offsets. The first four 32-bit words (VERID/PARAM/GLOBAL/
+ * PINCFG) sit before the UART register block proper, which starts at
+ * BAUD = 0x10. The Linux driver compensates with sport->reg_off = 0x10
+ * on i.MX variants; the model exposes the absolute offsets directly.
+ */
+#define LPUART_VERID            0x00
+#define LPUART_PARAM            0x04
+#define LPUART_GLOBAL           0x08
+#define LPUART_PINCFG           0x0C
+#define LPUART_BAUD             0x10
+#define LPUART_STAT             0x14
+#define LPUART_CTRL             0x18
+#define LPUART_DATA             0x1C
+#define LPUART_MATCH            0x20
+#define LPUART_MODIR            0x24
+#define LPUART_FIFO             0x28
+#define LPUART_WATER            0x2C
+
+/* GLOBAL: write GLOBAL_RST to trigger a software reset of the IP. */
+#define LPUART_GLOBAL_RST       0x00000002
+
+/* STAT bits the model implements. */
+#define LPUART_STAT_TDRE        0x00800000  /* TX data register empty */
+#define LPUART_STAT_TC          0x00400000  /* TX complete */
+#define LPUART_STAT_RDRF        0x00200000  /* RX data register full */
+#define LPUART_STAT_IDLE        0x00100000  /* RX line idle */
+#define LPUART_STAT_OR          0x00080000  /* RX overrun */
+/* RW1C mask: writing 1 to these bits clears them. */
+#define LPUART_STAT_W1C_MASK    (LPUART_STAT_IDLE | LPUART_STAT_OR)
+
+/* CTRL bits the model implements. */
+#define LPUART_CTRL_TIE         0x00800000  /* TDRE IRQ enable */
+#define LPUART_CTRL_TCIE        0x00400000  /* TC IRQ enable */
+#define LPUART_CTRL_RIE         0x00200000  /* RDRF IRQ enable */
+#define LPUART_CTRL_ILIE        0x00100000  /* IDLE IRQ enable */
+#define LPUART_CTRL_TE          0x00080000  /* Transmitter enable */
+#define LPUART_CTRL_RE          0x00040000  /* Receiver enable */
+
+/* DATA: bits [7:0] carry the actual character; upper bits are status. */
+#define LPUART_DATA_MASK        0x000000FF
+#define LPUART_DATA_RXEMPT      0x00001000  /* RX buffer was empty */
+
+/*
+ * FIFO bits. TXEMPT/RXEMPT/TXOF/RXUF are read-only (status) and must never be
+ * latched from a guest write - the Linux driver read-modify-writes UARTFIFO,
+ * so a stored RXEMPT would stick and break its RX drain loop. TXFLUSH/RXFLUSH
+ * are write-1 self-clearing commands.
+ */
+#define LPUART_FIFO_TXEMPT      0x00800000
+#define LPUART_FIFO_RXEMPT      0x00400000
+#define LPUART_FIFO_TXOF        0x00020000  /* TX overflow (W1C) */
+#define LPUART_FIFO_RXUF        0x00010000  /* RX underflow (W1C) */
+#define LPUART_FIFO_TXFLUSH     0x00008000  /* self-clearing */
+#define LPUART_FIFO_RXFLUSH     0x00004000  /* self-clearing */
+#define LPUART_FIFO_RO_MASK     (LPUART_FIFO_TXEMPT | LPUART_FIFO_RXEMPT | \
+                                 LPUART_FIFO_TXOF | LPUART_FIFO_RXUF | \
+                                 LPUART_FIFO_TXFLUSH | LPUART_FIFO_RXFLUSH)
+
+/*
+ * PARAM: FIFO depth is encoded as 1 << (field + 1) when nonzero, else 1.
+ * The model implements a single-byte TX path and a 1-deep RX buffer, so
+ * both TX and RX fields read back zero (depth = 1).
+ */
+#define LPUART_PARAM_TXFIFO_SHIFT   0
+#define LPUART_PARAM_RXFIFO_SHIFT   8
+
+/*
+ * VERID: report an i.MX 95-style version. The Linux driver
+ * does not branch on this field for any of the imx*ulp variants, so the
+ * exact value is not load-bearing.
+ */
+#define LPUART_VERID_VALUE      0x04040007
+
+struct IMXLPUARTState {
+    SysBusDevice    parent_obj;
+
+    MemoryRegion    iomem;
+    CharFrontend    chr;
+    qemu_irq        irq;
+
+    /* Register state. Only the writable bits are tracked. */
+    uint32_t        baud;
+    uint32_t        stat;
+    uint32_t        ctrl;
+    uint32_t        match;
+    uint32_t        modir;
+    uint32_t        fifo;
+    uint32_t        water;
+    uint32_t        pincfg;
+
+    /* Single-byte RX buffer (1-deep). */
+    uint8_t         rx_byte;
+    bool            rx_full;
+};
+
+#endif /* IMX_LPUART_H */
-- 
2.34.1



  parent reply	other threads:[~2026-08-20  2:51 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20260820024834.3286721-1-kylefoxaustin.github@gmail.com>
2026-08-20  2:48 ` [PATCH 02/16] hw/arm/boot: let a board preset initrd_start Kyle Fox
2026-08-20  2:48 ` [PATCH 03/16] target/arm: opt-in align-down for a misaligned PMSAv7 MPU RBAR Kyle Fox
2026-08-20  2:48 ` [PATCH 04/16] hw/arm/armv7m: forward pmsav7-rbar-align-down to the CPU Kyle Fox
2026-08-20  2:48 ` Kyle Fox [this message]
2026-08-20  2:48 ` [PATCH 06/16] hw/i2c: add i.MX LPI2C Kyle Fox
2026-08-20  2:48 ` [PATCH 07/16] hw/misc: add i.MX Messaging Unit (MU v2) Kyle Fox
2026-08-20  2:48 ` [PATCH 08/16] hw/misc: add NXP EdgeLock Enclave (ELE) responder Kyle Fox
2026-08-20  2:48 ` [PATCH 09/16] hw/timer: add i.MX 95 system counter Kyle Fox
2026-08-20  2:48 ` [PATCH 10/16] hw/misc: add i.MX 95 watchdog Kyle Fox
2026-08-20  2:48 ` [PATCH 11/16] hw/misc: add i.MX 95 ANATOP/AONMIX/GPC/SRC power and clock blocks Kyle Fox
2026-08-20  2:48 ` [PATCH 12/16] hw/misc: add i.MX 95 PMIC (PF09/PF53/PCAL6408A) and xcache controllers Kyle Fox
2026-08-20  2:48 ` [PATCH 13/16] hw/misc: add i.MX 95 DPU command-sequencer stub (headless) Kyle Fox
2026-08-20  2:48 ` [PATCH 14/16] hw/arm: add i.MX 95 SoC container (fsl-imx95) Kyle Fox
2026-08-20  2:48 ` [PATCH 15/16] hw/arm: add i.MX 95 19x19 EVK board Kyle Fox
2026-08-20  2:48 ` [PATCH 16/16] docs, MAINTAINERS, tests/functional: add i.MX 95 EVK Kyle Fox

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=20260820024834.3286721-6-kylefoxaustin.github@gmail.com \
    --to=kylefoxaustin.github@gmail.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --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