From nobody Tue May 26 03:33:44 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=git.sr.ht Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777565135710722.8700619090263; Thu, 30 Apr 2026 09:05:35 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wITsY-0001qt-EV; Thu, 30 Apr 2026 12:04:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrH-0007Vt-B4; Thu, 30 Apr 2026 12:03:24 -0400 Received: from mail-a.sr.ht ([46.23.81.152]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITr9-00078I-ED; Thu, 30 Apr 2026 12:03:21 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id D53B120C12; Thu, 30 Apr 2026 16:03:08 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=YhDv+BeemcjcIdD2m5tEK+3Y1VpySq+/sAQO/AJLmhg=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1777564988; v=1; b=oEPx33kVhirBmNivuEnZvlwWXHZy6BQvfpfMZe2qsZfFFXMh9To0ifwH1gWefCJ1kFDUfNF5 UFKNrKPGQyHbbqzM6wTc3frTJIItCZ/1mbP94hrius5Rp8Ik/GgZKKD5UgtU8I40wjjL9TjPXxX thRgaGquPwIvHoU41QUiCYJ7GuP0vUqB29ABDfsENRpssUr7GVXn11IqB6jaXnVAjI4F27ZJvTU rFYpu9jOs/C5WDmtsn6q0AgjRk3MOxouKiU/HcvawSITu/81d1XvYmgvCR7CKVrfmR61QY2F9Kp zm2cSQb2PpJB67NbiQrfxHcLz06pNBkJCKQ7KA8tWsWzQ== From: ~lexbaileylowrisc Date: Mon, 30 Mar 2026 15:34:56 +0100 Subject: [PATCH qemu v4 1/9] Rename ibex_uart to ot_uart Message-ID: <177756498815.8917.12449488721849651971-1@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177756498815.8917.12449488721849651971-0@git.sr.ht> To: qemu-riscv@nongnu.org, Alistair Francis Cc: Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9?= Lureau , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-devel@nongnu.org, Amit Kumar-Hermosillo , nabihestefan Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=46.23.81.152; envelope-from=outgoing@sr.ht; helo=mail-a.sr.ht X-Spam_score_int: 17 X-Spam_score: 1.7 X-Spam_bar: + X-Spam_report: (1.7 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_96_XX=3.405, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ~lexbaileylowrisc Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1777565139166154100 From: Lex Bailey This UART device is not specifically tied to ibex. Currently it is only use= d in the opentitan machine, which does use an ibex core, but an opentitan machine wi= th a different core would still use this UART, hence it should be considered a p= art of opentitan more than a part of ibex. Signed-off-by: Lex Bailey Reviewed-by: Alistair Francis --- MAINTAINERS | 1 + hw/char/Kconfig | 3 + hw/char/meson.build | 2 +- hw/char/{ibex_uart.c =3D> ot_uart.c} | 177 ++++++++++----------- hw/riscv/Kconfig | 1 + hw/riscv/opentitan.c | 2 +- include/hw/char/{ibex_uart.h =3D> ot_uart.h} | 20 +-- include/hw/riscv/opentitan.h | 4 +- 8 files changed, 107 insertions(+), 103 deletions(-) rename hw/char/{ibex_uart.c =3D> ot_uart.c} (75%) rename include/hw/char/{ibex_uart.h =3D> ot_uart.h} (84%) diff --git a/MAINTAINERS b/MAINTAINERS index e41f0eb92c..42abaa1ee3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1727,6 +1727,7 @@ L: qemu-riscv@nongnu.org S: Supported F: hw/riscv/opentitan.c F: hw/*/ibex_*.c +F: hw/*/ot_*.c F: include/hw/riscv/opentitan.h F: include/hw/*/ibex_*.h F: target/riscv/insn_trans/trans_xthead.c.inc diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 020c0a84bb..23ddab6b78 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -95,3 +95,6 @@ config IP_OCTAL_232 bool default y depends on IPACK + +config OT_UART + bool diff --git a/hw/char/meson.build b/hw/char/meson.build index fc3d7ee506..056153085f 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -2,7 +2,7 @@ system_ss.add(when: 'CONFIG_CADENCE', if_true: files('caden= ce_uart.c')) system_ss.add(when: 'CONFIG_CMSDK_APB_UART', if_true: files('cmsdk-apb-uar= t.c')) system_ss.add(when: 'CONFIG_ESCC', if_true: files('escc.c')) system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_apbuart.c')) -system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_uart.c')) +system_ss.add(when: 'CONFIG_OT_UART', if_true: files('ot_uart.c')) system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_serial.c')) system_ss.add(when: 'CONFIG_IP_OCTAL_232', if_true: files('ipoctal232.c')) system_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('parallel-isa.c')) diff --git a/hw/char/ibex_uart.c b/hw/char/ot_uart.c similarity index 75% rename from hw/char/ibex_uart.c rename to hw/char/ot_uart.c index 26ed1aea14..b3eb619641 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ot_uart.c @@ -1,5 +1,5 @@ /* - * QEMU lowRISC Ibex UART device + * QEMU OpenTitan UART device * * Copyright (c) 2020 Western Digital * @@ -26,7 +26,7 @@ */ =20 #include "qemu/osdep.h" -#include "hw/char/ibex_uart.h" +#include "hw/char/ot_uart.h" #include "hw/core/irq.h" #include "hw/core/qdev-clock.h" #include "hw/core/qdev-properties.h" @@ -74,7 +74,7 @@ REG32(OVRD, 0x28) REG32(VAL, 0x2C) REG32(TIMEOUT_CTRL, 0x30) =20 -static void ibex_uart_update_irqs(IbexUartState *s) +static void ot_uart_update_irqs(OtUARTState *s) { if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_WATERMA= RK_MASK) { qemu_set_irq(s->tx_watermark, 1); @@ -101,9 +101,9 @@ static void ibex_uart_update_irqs(IbexUartState *s) } } =20 -static int ibex_uart_can_receive(void *opaque) +static int ot_uart_can_receive(void *opaque) { - IbexUartState *s =3D opaque; + OtUARTState *s =3D opaque; =20 if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) && !(s->uart_status & R_STATUS_RXFULL_MASK)) { @@ -113,9 +113,9 @@ static int ibex_uart_can_receive(void *opaque) return 0; } =20 -static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size) +static void ot_uart_receive(void *opaque, const uint8_t *buf, int size) { - IbexUartState *s =3D opaque; + OtUARTState *s =3D opaque; uint8_t rx_fifo_level =3D (s->uart_fifo_ctrl & R_FIFO_CTRL_RXILVL_MASK) >> R_FIFO_CTRL_RXILVL_SHIFT; =20 @@ -133,13 +133,13 @@ static void ibex_uart_receive(void *opaque, const uin= t8_t *buf, int size) s->uart_intr_state |=3D R_INTR_STATE_RX_WATERMARK_MASK; } =20 - ibex_uart_update_irqs(s); + ot_uart_update_irqs(s); } =20 -static gboolean ibex_uart_xmit(void *do_not_use, GIOCondition cond, - void *opaque) +static gboolean ot_uart_xmit(void *do_not_use, GIOCondition cond, + void *opaque) { - IbexUartState *s =3D opaque; + OtUARTState *s =3D opaque; uint8_t tx_fifo_level =3D (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) >> R_FIFO_CTRL_TXILVL_SHIFT; int ret; @@ -155,7 +155,7 @@ static gboolean ibex_uart_xmit(void *do_not_use, GIOCon= dition cond, s->uart_status |=3D R_STATUS_TXEMPTY_MASK; s->uart_intr_state |=3D R_INTR_STATE_TX_EMPTY_MASK; s->uart_intr_state &=3D ~R_INTR_STATE_TX_WATERMARK_MASK; - ibex_uart_update_irqs(s); + ot_uart_update_irqs(s); return G_SOURCE_REMOVE; } =20 @@ -168,7 +168,7 @@ static gboolean ibex_uart_xmit(void *do_not_use, GIOCon= dition cond, =20 if (s->tx_level) { guint r =3D qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, - ibex_uart_xmit, s); + ot_uart_xmit, s); if (!r) { s->tx_level =3D 0; return G_SOURCE_REMOVE; @@ -176,7 +176,7 @@ static gboolean ibex_uart_xmit(void *do_not_use, GIOCon= dition cond, } =20 /* Clear the TX Full bit */ - if (s->tx_level !=3D IBEX_UART_TX_FIFO_SIZE) { + if (s->tx_level !=3D OT_UART_TX_FIFO_SIZE) { s->uart_status &=3D ~R_STATUS_TXFULL_MASK; } =20 @@ -191,20 +191,20 @@ static gboolean ibex_uart_xmit(void *do_not_use, GIOC= ondition cond, s->uart_intr_state |=3D R_INTR_STATE_TX_EMPTY_MASK; } =20 - ibex_uart_update_irqs(s); + ot_uart_update_irqs(s); return G_SOURCE_REMOVE; } =20 -static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf, +static void uart_write_tx_fifo(OtUARTState *s, const uint8_t *buf, int size) { uint64_t current_time =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); uint8_t tx_fifo_level =3D (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) >> R_FIFO_CTRL_TXILVL_SHIFT; =20 - if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) { - size =3D IBEX_UART_TX_FIFO_SIZE - s->tx_level; - qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow"); + if (size > OT_UART_TX_FIFO_SIZE - s->tx_level) { + size =3D OT_UART_TX_FIFO_SIZE - s->tx_level; + qemu_log_mask(LOG_GUEST_ERROR, "ot_uart: TX FIFO overflow"); } =20 memcpy(s->tx_fifo + s->tx_level, buf, size); @@ -216,10 +216,10 @@ static void uart_write_tx_fifo(IbexUartState *s, cons= t uint8_t *buf, =20 if (s->tx_level >=3D tx_fifo_level) { s->uart_intr_state |=3D R_INTR_STATE_TX_WATERMARK_MASK; - ibex_uart_update_irqs(s); + ot_uart_update_irqs(s); } =20 - if (s->tx_level =3D=3D IBEX_UART_TX_FIFO_SIZE) { + if (s->tx_level =3D=3D OT_UART_TX_FIFO_SIZE) { s->uart_status |=3D R_STATUS_TXFULL_MASK; } =20 @@ -227,9 +227,9 @@ static void uart_write_tx_fifo(IbexUartState *s, const = uint8_t *buf, (s->char_tx_time * 4)); } =20 -static void ibex_uart_reset(DeviceState *dev) +static void ot_uart_reset(DeviceState *dev) { - IbexUartState *s =3D IBEX_UART(dev); + OtUARTState *s =3D OT_UART(dev); =20 s->uart_intr_state =3D 0x00000000; s->uart_intr_state =3D 0x00000000; @@ -248,10 +248,10 @@ static void ibex_uart_reset(DeviceState *dev) =20 s->char_tx_time =3D (NANOSECONDS_PER_SECOND / 230400) * 10; =20 - ibex_uart_update_irqs(s); + ot_uart_update_irqs(s); } =20 -static uint64_t ibex_uart_get_baud(IbexUartState *s) +static uint64_t ot_uart_get_baud(OtUARTState *s) { uint64_t baud; =20 @@ -262,10 +262,9 @@ static uint64_t ibex_uart_get_baud(IbexUartState *s) return baud; } =20 -static uint64_t ibex_uart_read(void *opaque, hwaddr addr, - unsigned int size) +static uint64_t ot_uart_read(void *opaque, hwaddr addr, unsigned int size) { - IbexUartState *s =3D opaque; + OtUARTState *s =3D opaque; uint64_t retvalue =3D 0; =20 switch (addr >> 2) { @@ -342,25 +341,25 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr a= ddr, return retvalue; } =20 -static void ibex_uart_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) +static void ot_uart_write(void *opaque, hwaddr addr, uint64_t val64, + unsigned int size) { - IbexUartState *s =3D opaque; + OtUARTState *s =3D opaque; uint32_t value =3D val64; =20 switch (addr >> 2) { case R_INTR_STATE: /* Write 1 clear */ s->uart_intr_state &=3D ~value; - ibex_uart_update_irqs(s); + ot_uart_update_irqs(s); break; case R_INTR_ENABLE: s->uart_intr_enable =3D value; - ibex_uart_update_irqs(s); + ot_uart_update_irqs(s); break; case R_INTR_TEST: s->uart_intr_state |=3D value; - ibex_uart_update_irqs(s); + ot_uart_update_irqs(s); break; =20 case R_CTRL: @@ -393,7 +392,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr, "%s: UART_CTRL_RXBLVL is not supported\n", __fun= c__); } if (value & R_CTRL_NCO_MASK) { - uint64_t baud =3D ibex_uart_get_baud(s); + uint64_t baud =3D ot_uart_get_baud(s); =20 s->char_tx_time =3D (NANOSECONDS_PER_SECOND / baud) * 10; } @@ -448,122 +447,122 @@ static void ibex_uart_write(void *opaque, hwaddr ad= dr, } } =20 -static void ibex_uart_clk_update(void *opaque, ClockEvent event) +static void ot_uart_clk_update(void *opaque, ClockEvent event) { - IbexUartState *s =3D opaque; + OtUARTState *s =3D opaque; =20 /* recompute uart's speed on clock change */ - uint64_t baud =3D ibex_uart_get_baud(s); + uint64_t baud =3D ot_uart_get_baud(s); =20 s->char_tx_time =3D (NANOSECONDS_PER_SECOND / baud) * 10; } =20 static void fifo_trigger_update(void *opaque) { - IbexUartState *s =3D opaque; + OtUARTState *s =3D opaque; =20 if (s->uart_ctrl & R_CTRL_TX_ENABLE_MASK) { - ibex_uart_xmit(NULL, G_IO_OUT, s); + ot_uart_xmit(NULL, G_IO_OUT, s); } } =20 -static const MemoryRegionOps ibex_uart_ops =3D { - .read =3D ibex_uart_read, - .write =3D ibex_uart_write, +static const MemoryRegionOps ot_uart_ops =3D { + .read =3D ot_uart_read, + .write =3D ot_uart_write, .endianness =3D DEVICE_LITTLE_ENDIAN, .impl.min_access_size =3D 4, .impl.max_access_size =3D 4, }; =20 -static int ibex_uart_post_load(void *opaque, int version_id) +static int ot_uart_post_load(void *opaque, int version_id) { - IbexUartState *s =3D opaque; + OtUARTState *s =3D opaque; =20 - ibex_uart_update_irqs(s); + ot_uart_update_irqs(s); return 0; } =20 -static const VMStateDescription vmstate_ibex_uart =3D { - .name =3D TYPE_IBEX_UART, +static const VMStateDescription vmstate_ot_uart =3D { + .name =3D TYPE_OT_UART, .version_id =3D 1, .minimum_version_id =3D 1, - .post_load =3D ibex_uart_post_load, + .post_load =3D ot_uart_post_load, .fields =3D (const VMStateField[]) { - VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState, - IBEX_UART_TX_FIFO_SIZE), - VMSTATE_UINT32(tx_level, IbexUartState), - VMSTATE_UINT64(char_tx_time, IbexUartState), - VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState), - VMSTATE_UINT32(uart_intr_state, IbexUartState), - VMSTATE_UINT32(uart_intr_enable, IbexUartState), - VMSTATE_UINT32(uart_ctrl, IbexUartState), - VMSTATE_UINT32(uart_status, IbexUartState), - VMSTATE_UINT32(uart_rdata, IbexUartState), - VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState), - VMSTATE_UINT32(uart_fifo_status, IbexUartState), - VMSTATE_UINT32(uart_ovrd, IbexUartState), - VMSTATE_UINT32(uart_val, IbexUartState), - VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState), + VMSTATE_UINT8_ARRAY(tx_fifo, OtUARTState, + OT_UART_TX_FIFO_SIZE), + VMSTATE_UINT32(tx_level, OtUARTState), + VMSTATE_UINT64(char_tx_time, OtUARTState), + VMSTATE_TIMER_PTR(fifo_trigger_handle, OtUARTState), + VMSTATE_UINT32(uart_intr_state, OtUARTState), + VMSTATE_UINT32(uart_intr_enable, OtUARTState), + VMSTATE_UINT32(uart_ctrl, OtUARTState), + VMSTATE_UINT32(uart_status, OtUARTState), + VMSTATE_UINT32(uart_rdata, OtUARTState), + VMSTATE_UINT32(uart_fifo_ctrl, OtUARTState), + VMSTATE_UINT32(uart_fifo_status, OtUARTState), + VMSTATE_UINT32(uart_ovrd, OtUARTState), + VMSTATE_UINT32(uart_val, OtUARTState), + VMSTATE_UINT32(uart_timeout_ctrl, OtUARTState), VMSTATE_END_OF_LIST() } }; =20 -static const Property ibex_uart_properties[] =3D { - DEFINE_PROP_CHR("chardev", IbexUartState, chr), +static const Property ot_uart_properties[] =3D { + DEFINE_PROP_CHR("chardev", OtUARTState, chr), }; =20 -static void ibex_uart_init(Object *obj) +static void ot_uart_init(Object *obj) { - IbexUartState *s =3D IBEX_UART(obj); + OtUARTState *s =3D OT_UART(obj); =20 s->f_clk =3D qdev_init_clock_in(DEVICE(obj), "f_clock", - ibex_uart_clk_update, s, ClockUpdate); - clock_set_hz(s->f_clk, IBEX_UART_CLOCK); + ot_uart_clk_update, s, ClockUpdate); + clock_set_hz(s->f_clk, OT_UART_CLOCK); =20 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark); sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark); sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow); =20 - memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s, - TYPE_IBEX_UART, 0x400); + memory_region_init_io(&s->mmio, obj, &ot_uart_ops, s, + TYPE_OT_UART, 0x400); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); } =20 -static void ibex_uart_realize(DeviceState *dev, Error **errp) +static void ot_uart_realize(DeviceState *dev, Error **errp) { - IbexUartState *s =3D IBEX_UART(dev); + OtUARTState *s =3D OT_UART(dev); =20 s->fifo_trigger_handle =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, fifo_trigger_update, s); =20 - qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive, - ibex_uart_receive, NULL, NULL, + qemu_chr_fe_set_handlers(&s->chr, ot_uart_can_receive, + ot_uart_receive, NULL, NULL, s, NULL, true); } =20 -static void ibex_uart_class_init(ObjectClass *klass, const void *data) +static void ot_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc =3D DEVICE_CLASS(klass); =20 - device_class_set_legacy_reset(dc, ibex_uart_reset); - dc->realize =3D ibex_uart_realize; - dc->vmsd =3D &vmstate_ibex_uart; - device_class_set_props(dc, ibex_uart_properties); + device_class_set_legacy_reset(dc, ot_uart_reset); + dc->realize =3D ot_uart_realize; + dc->vmsd =3D &vmstate_ot_uart; + device_class_set_props(dc, ot_uart_properties); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } =20 -static const TypeInfo ibex_uart_info =3D { - .name =3D TYPE_IBEX_UART, +static const TypeInfo ot_uart_info =3D { + .name =3D TYPE_OT_UART, .parent =3D TYPE_SYS_BUS_DEVICE, - .instance_size =3D sizeof(IbexUartState), - .instance_init =3D ibex_uart_init, - .class_init =3D ibex_uart_class_init, + .instance_size =3D sizeof(OtUARTState), + .instance_init =3D ot_uart_init, + .class_init =3D ot_uart_class_init, }; =20 -static void ibex_uart_register_types(void) +static void ot_uart_register_types(void) { - type_register_static(&ibex_uart_info); + type_register_static(&ot_uart_info); } =20 -type_init(ibex_uart_register_types) +type_init(ot_uart_register_types) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 0222c93f87..cb4bb5f442 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -38,6 +38,7 @@ config OPENTITAN default y depends on RISCV32 select IBEX + select OT_UART select SIFIVE_PLIC select UNIMP =20 diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 309125e854..97c33d1b53 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -132,7 +132,7 @@ static void lowrisc_ibex_soc_init(Object *obj) =20 object_initialize_child(obj, "plic", &s->plic, TYPE_SIFIVE_PLIC); =20 - object_initialize_child(obj, "uart", &s->uart, TYPE_IBEX_UART); + object_initialize_child(obj, "uart", &s->uart, TYPE_OT_UART); =20 object_initialize_child(obj, "timer", &s->timer, TYPE_IBEX_TIMER); =20 diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ot_uart.h similarity index 84% rename from include/hw/char/ibex_uart.h rename to include/hw/char/ot_uart.h index 882796e0c6..517324b65d 100644 --- a/include/hw/char/ibex_uart.h +++ b/include/hw/char/ot_uart.h @@ -1,5 +1,5 @@ /* - * QEMU lowRISC Ibex UART device + * QEMU OpenTitan UART device * * Copyright (c) 2020 Western Digital * @@ -22,28 +22,28 @@ * THE SOFTWARE. */ =20 -#ifndef HW_IBEX_UART_H -#define HW_IBEX_UART_H +#ifndef HW_OT_UART_H +#define HW_OT_UART_H =20 #include "hw/core/sysbus.h" #include "chardev/char-fe.h" #include "qemu/timer.h" #include "qom/object.h" =20 -#define IBEX_UART_TX_FIFO_SIZE 16 -#define IBEX_UART_CLOCK 50000000 /* 50MHz clock */ +#define OT_UART_TX_FIFO_SIZE 16 +#define OT_UART_CLOCK 50000000 /* 50MHz clock */ =20 -#define TYPE_IBEX_UART "ibex-uart" -OBJECT_DECLARE_SIMPLE_TYPE(IbexUartState, IBEX_UART) +#define TYPE_OT_UART "ot-uart" +OBJECT_DECLARE_SIMPLE_TYPE(OtUARTState, OT_UART) =20 -struct IbexUartState { +struct OtUARTState { /* */ SysBusDevice parent_obj; =20 /* */ MemoryRegion mmio; =20 - uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE]; + uint8_t tx_fifo[OT_UART_TX_FIFO_SIZE]; uint32_t tx_level; =20 uint32_t rx_level; @@ -70,4 +70,4 @@ struct IbexUartState { qemu_irq tx_empty; qemu_irq rx_overflow; }; -#endif /* HW_IBEX_UART_H */ +#endif /* HW_OT_UART_H */ diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index 5b9016e1d8..f2b4bf3814 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -21,7 +21,7 @@ =20 #include "hw/riscv/riscv_hart.h" #include "hw/intc/sifive_plic.h" -#include "hw/char/ibex_uart.h" +#include "hw/char/ot_uart.h" #include "hw/timer/ibex_timer.h" #include "hw/ssi/ibex_spi_host.h" #include "hw/core/boards.h" @@ -43,7 +43,7 @@ struct LowRISCIbexSoCState { /*< public >*/ RISCVHartArrayState cpus; SiFivePLICState plic; - IbexUartState uart; + OtUARTState uart; IbexTimerState timer; IbexSPIHostState spi_host[OPENTITAN_NUM_SPI_HOSTS]; =20 --=20 2.49.1 From nobody Tue May 26 03:33:44 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=git.sr.ht Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777565169607873.3149984658446; Thu, 30 Apr 2026 09:06:09 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wITse-00028Q-Az; Thu, 30 Apr 2026 12:04:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrH-0007Vu-BP; Thu, 30 Apr 2026 12:03:24 -0400 Received: from mail-a.sr.ht ([46.23.81.152]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITr9-00078N-FN; Thu, 30 Apr 2026 12:03:19 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id EA5A020C13; Thu, 30 Apr 2026 16:03:11 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=Eb4E4n4zzzhOAaaGQsl9QPIPVsuIUn1rdNE7TxwA3Ns=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1777564992; v=1; b=Fa5oQedaRrs7htcamNd4pMa33Zr55MxcCLno49ApWcoLskawForC7G3QPH0S001GY+CrjXhS 5AeiGfDIV1qPML6LUIoBxGJ6asL+KsmrZo2wRQokS6viF3b1BlIDK/5J5iSLndpJdz+i04CXKkf zQbwHBJhMR6gseL+zd8meWqU9yLpNYQGbD3cgW14tgoCiELlydNOkVx5PStLzYs85AGkZYuZvEs w6sV7S4LmSKrm19TLsjE8yCcC7kofEbrjDSfXC/DDXSoGt+UHImQ+wBRW8yAJFocc2qxa8CpcD0 zam+0gZYSaVcJsPAv0nXyvJA6h6hc/aKXyVsJVoyodtXQ== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 10:43:43 +0100 Subject: [PATCH qemu v4 2/9] ot_uart: move to new reset API Message-ID: <177756498815.8917.12449488721849651971-2@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177756498815.8917.12449488721849651971-0@git.sr.ht> To: qemu-riscv@nongnu.org, Alistair Francis Cc: Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9?= Lureau , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-devel@nongnu.org, Amit Kumar-Hermosillo , nabihestefan Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=46.23.81.152; envelope-from=outgoing@sr.ht; helo=mail-a.sr.ht X-Spam_score_int: 17 X-Spam_score: 1.7 X-Spam_bar: + X-Spam_report: (1.7 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_96_XX=3.405, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ~lexbaileylowrisc Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1777565170740158500 From: Lex Bailey switch from legacy_reset to new ResettableClass for OpenTitan UART device Signed-off-by: Lex Bailey Reviewed-by: Alistair Francis --- hw/char/ot_uart.c | 16 +++++++++++++--- include/hw/char/ot_uart.h | 8 +++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index b3eb619641..9478af40f9 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -227,9 +227,14 @@ static void uart_write_tx_fifo(OtUARTState *s, const u= int8_t *buf, (s->char_tx_time * 4)); } =20 -static void ot_uart_reset(DeviceState *dev) +static void ot_uart_reset_enter(Object *obj, ResetType type) { - OtUARTState *s =3D OT_UART(dev); + OtUARTClass *c =3D OT_UART_GET_CLASS(obj); + OtUARTState *s =3D OT_UART(obj); + + if (c->parent_phases.enter) { + c->parent_phases.enter(obj, type); + } =20 s->uart_intr_state =3D 0x00000000; s->uart_intr_state =3D 0x00000000; @@ -544,12 +549,16 @@ static void ot_uart_realize(DeviceState *dev, Error *= *errp) static void ot_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc =3D DEVICE_CLASS(klass); + OtUARTClass *uc =3D OT_UART_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); =20 - device_class_set_legacy_reset(dc, ot_uart_reset); dc->realize =3D ot_uart_realize; dc->vmsd =3D &vmstate_ot_uart; device_class_set_props(dc, ot_uart_properties); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + + resettable_class_set_parent_phases(rc, &ot_uart_reset_enter, NULL, NUL= L, + &uc->parent_phases); } =20 static const TypeInfo ot_uart_info =3D { @@ -557,6 +566,7 @@ static const TypeInfo ot_uart_info =3D { .parent =3D TYPE_SYS_BUS_DEVICE, .instance_size =3D sizeof(OtUARTState), .instance_init =3D ot_uart_init, + .class_size =3D sizeof(OtUARTClass), .class_init =3D ot_uart_class_init, }; =20 diff --git a/include/hw/char/ot_uart.h b/include/hw/char/ot_uart.h index 517324b65d..fee2128f90 100644 --- a/include/hw/char/ot_uart.h +++ b/include/hw/char/ot_uart.h @@ -34,7 +34,7 @@ #define OT_UART_CLOCK 50000000 /* 50MHz clock */ =20 #define TYPE_OT_UART "ot-uart" -OBJECT_DECLARE_SIMPLE_TYPE(OtUARTState, OT_UART) +OBJECT_DECLARE_TYPE(OtUARTState, OtUARTClass, OT_UART) =20 struct OtUARTState { /* */ @@ -70,4 +70,10 @@ struct OtUARTState { qemu_irq tx_empty; qemu_irq rx_overflow; }; + +struct OtUARTClass { + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; +}; + #endif /* HW_OT_UART_H */ --=20 2.49.1 From nobody Tue May 26 03:33:44 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=git.sr.ht Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777565135650782.0545325507145; Thu, 30 Apr 2026 09:05:35 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wITrs-0000N5-Kz; Thu, 30 Apr 2026 12:04:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrH-0007Vv-Bx; Thu, 30 Apr 2026 12:03:24 -0400 Received: from mail-a.sr.ht ([46.23.81.152]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITr9-00078P-Cr; Thu, 30 Apr 2026 12:03:20 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 2020320C19; Thu, 30 Apr 2026 16:03:12 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=V52m1Fb2l3IIihP5FiYiKI6ZXzE5ABAlbcP+z2Dgx7c=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1777564992; v=1; b=JlQ7jFDTl4B/KYDUGl1Xlt5oSk4RBChHpLBajkHOKo768LkTjLvfHUs1E2CWZ1+EYRkqpt1P byMYZKRRm4LGnraZJ84I+N5UtDh0R5Iwi+3Pwletx2xSBKdFVLm3WZNkGyKex9rrpbj/HUCGdZ6 znjtebgWRfpIcNJxT5XdQLZjxVH5ZqkRYd4R4EGzCTCZrU48TXH0pP8Z2ij9pr+COrFQPOTOZS+ RdCr+9nMBM1pdAz47HX06JkneRzrdZD4THs4yEf3hrdE8DVgCX8tl878PggoUSGXRLFVoOBu6kD iBpXK5HPxRrAUIRmpbFhX02fcu9IbYFBMTQrFH19MT2FA== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 13:44:36 +0100 Subject: [PATCH qemu v4 3/9] ot_uart: update register defs, switch to Fifo8 for tx/rx buffers Message-ID: <177756498815.8917.12449488721849651971-3@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177756498815.8917.12449488721849651971-0@git.sr.ht> To: qemu-riscv@nongnu.org, Alistair Francis Cc: Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9?= Lureau , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-devel@nongnu.org, Amit Kumar-Hermosillo , nabihestefan Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=46.23.81.152; envelope-from=outgoing@sr.ht; helo=mail-a.sr.ht X-Spam_score_int: 17 X-Spam_score: 1.7 X-Spam_bar: + X-Spam_report: (1.7 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_96_XX=3.405, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ~lexbaileylowrisc Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1777565138651158500 From: Lex Bailey The register definitions for the UART device need to be updated to match the documentation at https://opentitan.org/book/hw/ip/uart/doc/registers.ht= ml This commit does that, and also switches to using Fifo8 for managing the transmit and receive buffers. Signed-off-by: Lex Bailey --- hw/char/ot_uart.c | 338 ++++++++++++++++++++++---------------- include/hw/char/ot_uart.h | 18 +- 2 files changed, 201 insertions(+), 155 deletions(-) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index 9478af40f9..3fe7c5efe5 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -27,6 +27,7 @@ =20 #include "qemu/osdep.h" #include "hw/char/ot_uart.h" +#include "qemu/fifo8.h" #include "hw/core/irq.h" #include "hw/core/qdev-clock.h" #include "hw/core/qdev-properties.h" @@ -37,16 +38,22 @@ #include "qemu/module.h" =20 REG32(INTR_STATE, 0x00) - FIELD(INTR_STATE, TX_WATERMARK, 0, 1) - FIELD(INTR_STATE, RX_WATERMARK, 1, 1) - FIELD(INTR_STATE, TX_EMPTY, 2, 1) - FIELD(INTR_STATE, RX_OVERFLOW, 3, 1) + SHARED_FIELD(INTR_TX_WATERMARK, 0, 1) + SHARED_FIELD(INTR_RX_WATERMARK, 1, 1) + SHARED_FIELD(INTR_TX_DONE, 2, 1) + SHARED_FIELD(INTR_RX_OVERFLOW, 3, 1) + SHARED_FIELD(INTR_RX_FRAME_ERR, 4, 1) + SHARED_FIELD(INTR_RX_BREAK_ERR, 5, 1) + SHARED_FIELD(INTR_RX_TIMEOUT, 6, 1) + SHARED_FIELD(INTR_RX_PARITY_ERR, 7, 1) + SHARED_FIELD(INTR_TX_EMPTY, 8, 1) REG32(INTR_ENABLE, 0x04) REG32(INTR_TEST, 0x08) REG32(ALERT_TEST, 0x0C) + FIELD(ALERT_TEST, FATAL_FAULT, 0, 1) REG32(CTRL, 0x10) - FIELD(CTRL, TX_ENABLE, 0, 1) - FIELD(CTRL, RX_ENABLE, 1, 1) + FIELD(CTRL, TX, 0, 1) + FIELD(CTRL, RX, 1, 1) FIELD(CTRL, NF, 2, 1) FIELD(CTRL, SLPBK, 4, 1) FIELD(CTRL, LLPBK, 5, 1) @@ -58,43 +65,74 @@ REG32(STATUS, 0x14) FIELD(STATUS, TXFULL, 0, 1) FIELD(STATUS, RXFULL, 1, 1) FIELD(STATUS, TXEMPTY, 2, 1) + FIELD(STATUS, TXIDLE, 3, 1) FIELD(STATUS, RXIDLE, 4, 1) FIELD(STATUS, RXEMPTY, 5, 1) REG32(RDATA, 0x18) + FIELD(RDATA, RDATA, 0, 8) REG32(WDATA, 0x1C) + FIELD(WDATA, WDATA, 0, 8) REG32(FIFO_CTRL, 0x20) FIELD(FIFO_CTRL, RXRST, 0, 1) FIELD(FIFO_CTRL, TXRST, 1, 1) FIELD(FIFO_CTRL, RXILVL, 2, 3) - FIELD(FIFO_CTRL, TXILVL, 5, 2) + FIELD(FIFO_CTRL, TXILVL, 5, 3) REG32(FIFO_STATUS, 0x24) - FIELD(FIFO_STATUS, TXLVL, 0, 5) - FIELD(FIFO_STATUS, RXLVL, 16, 5) + FIELD(FIFO_STATUS, TXLVL, 0, 8) + FIELD(FIFO_STATUS, RXLVL, 16, 8) REG32(OVRD, 0x28) + FIELD(OVRD, TXEN, 0, 1) + FIELD(OVRD, TXVAL, 1, 1) REG32(VAL, 0x2C) + FIELD(VAL, RX, 0, 16) REG32(TIMEOUT_CTRL, 0x30) + FIELD(TIMEOUT_CTRL, VAL, 0, 24) + FIELD(TIMEOUT_CTRL, EN, 31, 1) + +#define INTR_MASK \ + (INTR_TX_WATERMARK_MASK | INTR_RX_WATERMARK_MASK | INTR_TX_DONE_MASK |= \ + INTR_RX_OVERFLOW_MASK | INTR_RX_FRAME_ERR_MASK | INTR_RX_BREAK_ERR_MA= SK | \ + INTR_RX_TIMEOUT_MASK | INTR_RX_PARITY_ERR_MASK | INTR_TX_EMPTY_MASK) + +#define CTRL_MASK \ + (R_CTRL_TX_MASK | R_CTRL_RX_MASK | R_CTRL_NF_MASK | R_CTRL_SLPBK_MASK = | \ + R_CTRL_LLPBK_MASK | R_CTRL_PARITY_EN_MASK | R_CTRL_PARITY_ODD_MASK | \ + R_CTRL_RXBLVL_MASK | R_CTRL_NCO_MASK) + +#define OT_UART_NCO_BITS 16 +#define OT_UART_TX_FIFO_SIZE 128 +#define OT_UART_RX_FIFO_SIZE 128 + +#define R32_OFF(_r_) ((_r_) / sizeof(uint32_t)) + +#define R_LAST_REG (R_TIMEOUT_CTRL) +#define REGS_COUNT (R_LAST_REG + 1u) +#define REGS_SIZE (REGS_COUNT * sizeof(uint32_t)) =20 static void ot_uart_update_irqs(OtUARTState *s) { - if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_WATERMA= RK_MASK) { + if (s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE] + & INTR_TX_WATERMARK_MASK) { qemu_set_irq(s->tx_watermark, 1); } else { qemu_set_irq(s->tx_watermark, 0); } =20 - if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_WATERMA= RK_MASK) { + if (s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE] + & INTR_RX_WATERMARK_MASK) { qemu_set_irq(s->rx_watermark, 1); } else { qemu_set_irq(s->rx_watermark, 0); } =20 - if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_EMPTY_M= ASK) { + if (s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE] & INTR_TX_EMPTY_MAS= K) { qemu_set_irq(s->tx_empty, 1); } else { qemu_set_irq(s->tx_empty, 0); } =20 - if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_OVERFLO= W_MASK) { + if (s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE] + & INTR_RX_OVERFLOW_MASK) { qemu_set_irq(s->rx_overflow, 1); } else { qemu_set_irq(s->rx_overflow, 0); @@ -105,122 +143,133 @@ static int ot_uart_can_receive(void *opaque) { OtUARTState *s =3D opaque; =20 - if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) - && !(s->uart_status & R_STATUS_RXFULL_MASK)) { - return 1; + if (s->regs[R_CTRL] & R_CTRL_RX_MASK) { + return (int)fifo8_num_free(&s->rx_fifo); } =20 return 0; } =20 +static uint32_t ot_uart_get_rx_watermark_level(const OtUARTState *s) +{ + uint32_t rx_ilvl =3D FIELD_EX32(s->regs[R_FIFO_CTRL], FIFO_CTRL, RXILV= L); + + return rx_ilvl < 7 ? (1 << rx_ilvl) : 126; +} + static void ot_uart_receive(void *opaque, const uint8_t *buf, int size) { OtUARTState *s =3D opaque; - uint8_t rx_fifo_level =3D (s->uart_fifo_ctrl & R_FIFO_CTRL_RXILVL_MASK) - >> R_FIFO_CTRL_RXILVL_SHIFT; - - s->uart_rdata =3D *buf; + uint32_t rx_watermark_level; + size_t count =3D MIN(fifo8_num_free(&s->rx_fifo), (size_t)size); =20 - s->uart_status &=3D ~R_STATUS_RXIDLE_MASK; - s->uart_status &=3D ~R_STATUS_RXEMPTY_MASK; - /* The RXFULL is set after receiving a single byte - * as the FIFO buffers are not yet implemented. - */ - s->uart_status |=3D R_STATUS_RXFULL_MASK; - s->rx_level +=3D 1; + for (int index =3D 0; index < size; index++) { + fifo8_push(&s->rx_fifo, buf[index]); + } =20 - if (size > rx_fifo_level) { - s->uart_intr_state |=3D R_INTR_STATE_RX_WATERMARK_MASK; + /* update INTR_STATE */ + if (count !=3D size) { + s->regs[R_INTR_STATE] |=3D INTR_RX_OVERFLOW_MASK; + } + rx_watermark_level =3D ot_uart_get_rx_watermark_level(s); + if (rx_watermark_level && size >=3D rx_watermark_level) { + s->regs[R_INTR_STATE] |=3D INTR_RX_WATERMARK_MASK; } =20 ot_uart_update_irqs(s); } =20 -static gboolean ot_uart_xmit(void *do_not_use, GIOCondition cond, - void *opaque) +static void ot_uart_reset_tx_fifo(OtUARTState *s) { - OtUARTState *s =3D opaque; - uint8_t tx_fifo_level =3D (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) - >> R_FIFO_CTRL_TXILVL_SHIFT; - int ret; - - /* instant drain the fifo when there's no back-end */ - if (!qemu_chr_fe_backend_connected(&s->chr)) { - s->tx_level =3D 0; - return G_SOURCE_REMOVE; + fifo8_reset(&s->tx_fifo); + s->regs[R_INTR_STATE] |=3D INTR_TX_EMPTY_MASK; + s->regs[R_INTR_STATE] |=3D INTR_TX_DONE_MASK; + if (s->tx_watermark_level) { + s->regs[R_INTR_STATE] |=3D INTR_TX_WATERMARK_MASK; + s->tx_watermark_level =3D 0; } +} =20 - if (!s->tx_level) { - s->uart_status &=3D ~R_STATUS_TXFULL_MASK; - s->uart_status |=3D R_STATUS_TXEMPTY_MASK; - s->uart_intr_state |=3D R_INTR_STATE_TX_EMPTY_MASK; - s->uart_intr_state &=3D ~R_INTR_STATE_TX_WATERMARK_MASK; - ot_uart_update_irqs(s); - return G_SOURCE_REMOVE; +static void ot_uart_reset_rx_fifo(OtUARTState *s) +{ + fifo8_reset(&s->rx_fifo); + s->regs[R_INTR_STATE] &=3D ~INTR_RX_WATERMARK_MASK; + s->regs[R_INTR_STATE] &=3D ~INTR_RX_OVERFLOW_MASK; + if (FIELD_EX32(s->regs[R_CTRL], CTRL, RX)) { + qemu_chr_fe_accept_input(&s->chr); } +} =20 - ret =3D qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level); +static uint32_t ot_uart_get_tx_watermark_level(const OtUARTState *s) +{ + uint32_t tx_ilvl =3D FIELD_EX32(s->regs[R_FIFO_CTRL], FIFO_CTRL, TXILV= L); =20 - if (ret >=3D 0) { - s->tx_level -=3D ret; - memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level); - } + return tx_ilvl < 7 ? (1 << tx_ilvl) : 64; +} =20 - if (s->tx_level) { - guint r =3D qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, - ot_uart_xmit, s); - if (!r) { - s->tx_level =3D 0; - return G_SOURCE_REMOVE; - } +static void ot_uart_xmit(OtUARTState *s) +{ + const uint8_t *buf; + uint32_t size; + int ret; + + if (fifo8_is_empty(&s->tx_fifo)) { + return; } =20 - /* Clear the TX Full bit */ - if (s->tx_level !=3D OT_UART_TX_FIFO_SIZE) { - s->uart_status &=3D ~R_STATUS_TXFULL_MASK; + /* instant drain the fifo when there's no back-end */ + if (!qemu_chr_fe_backend_connected(&s->chr)) { + ot_uart_reset_tx_fifo(s); + ot_uart_update_irqs(s); + return; } =20 - /* Disable the TX_WATERMARK IRQ */ - if (s->tx_level < tx_fifo_level) { - s->uart_intr_state &=3D ~R_INTR_STATE_TX_WATERMARK_MASK; + /* get a continuous buffer from the FIFO */ + buf =3D + fifo8_peek_bufptr(&s->tx_fifo, fifo8_num_used(&s->tx_fifo), &size); + /* send as much as possible */ + ret =3D qemu_chr_fe_write(&s->chr, buf, (int)size); + /* if some characters where sent, remove them from the FIFO */ + if (ret >=3D 0) { + fifo8_drop(&s->tx_fifo, ret); } =20 - /* Set TX empty */ - if (s->tx_level =3D=3D 0) { - s->uart_status |=3D R_STATUS_TXEMPTY_MASK; - s->uart_intr_state |=3D R_INTR_STATE_TX_EMPTY_MASK; + /* update INTR_STATE */ + if (fifo8_is_empty(&s->tx_fifo)) { + s->regs[R_INTR_STATE] |=3D INTR_TX_EMPTY_MASK; + s->regs[R_INTR_STATE] |=3D INTR_TX_DONE_MASK; + } + if (s->tx_watermark_level && + fifo8_num_used(&s->tx_fifo) < s->tx_watermark_level) { + s->regs[R_INTR_STATE] |=3D INTR_TX_WATERMARK_MASK; + s->tx_watermark_level =3D 0; } =20 ot_uart_update_irqs(s); - return G_SOURCE_REMOVE; } =20 -static void uart_write_tx_fifo(OtUARTState *s, const uint8_t *buf, - int size) +static void uart_write_tx_fifo(OtUARTState *s, uint8_t val) { uint64_t current_time =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - uint8_t tx_fifo_level =3D (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) - >> R_FIFO_CTRL_TXILVL_SHIFT; - - if (size > OT_UART_TX_FIFO_SIZE - s->tx_level) { - size =3D OT_UART_TX_FIFO_SIZE - s->tx_level; + if (fifo8_is_full(&s->tx_fifo)) { qemu_log_mask(LOG_GUEST_ERROR, "ot_uart: TX FIFO overflow"); + return; } =20 - memcpy(s->tx_fifo + s->tx_level, buf, size); - s->tx_level +=3D size; + fifo8_push(&s->tx_fifo, val); =20 - if (s->tx_level > 0) { - s->uart_status &=3D ~R_STATUS_TXEMPTY_MASK; + s->tx_watermark_level =3D ot_uart_get_tx_watermark_level(s); + if (fifo8_num_used(&s->tx_fifo) < s->tx_watermark_level) { + /* + * TX watermark interrupt is raised when FIFO depth goes from above + * watermark to below. If we haven't reached watermark, reset cach= ed + * watermark level + */ + s->tx_watermark_level =3D 0; } =20 - if (s->tx_level >=3D tx_fifo_level) { - s->uart_intr_state |=3D R_INTR_STATE_TX_WATERMARK_MASK; - ot_uart_update_irqs(s); - } - - if (s->tx_level =3D=3D OT_UART_TX_FIFO_SIZE) { - s->uart_status |=3D R_STATUS_TXFULL_MASK; + if (FIELD_EX32(s->regs[R_CTRL], CTRL, TX)) { + ot_uart_xmit(s); } =20 timer_mod(s->fifo_trigger_handle, current_time + @@ -236,17 +285,13 @@ static void ot_uart_reset_enter(Object *obj, ResetTyp= e type) c->parent_phases.enter(obj, type); } =20 - s->uart_intr_state =3D 0x00000000; - s->uart_intr_state =3D 0x00000000; - s->uart_intr_enable =3D 0x00000000; - s->uart_ctrl =3D 0x00000000; - s->uart_status =3D 0x0000003c; - s->uart_rdata =3D 0x00000000; - s->uart_fifo_ctrl =3D 0x00000000; - s->uart_fifo_status =3D 0x00000000; - s->uart_ovrd =3D 0x00000000; - s->uart_val =3D 0x00000000; - s->uart_timeout_ctrl =3D 0x00000000; + memset(&s->regs[0], 0, sizeof(s->regs)); + + s->regs[R_STATUS] =3D 0x0000003c; + + s->tx_watermark_level =3D 0; + ot_uart_reset_tx_fifo(s); + ot_uart_reset_rx_fifo(s); =20 s->tx_level =3D 0; s->rx_level =3D 0; @@ -260,7 +305,7 @@ static uint64_t ot_uart_get_baud(OtUARTState *s) { uint64_t baud; =20 - baud =3D ((s->uart_ctrl & R_CTRL_NCO_MASK) >> 16); + baud =3D ((s->regs[R_CTRL] & R_CTRL_NCO_MASK) >> 16); baud *=3D clock_get_hz(s->f_clk); baud >>=3D 20; =20 @@ -274,10 +319,10 @@ static uint64_t ot_uart_read(void *opaque, hwaddr add= r, unsigned int size) =20 switch (addr >> 2) { case R_INTR_STATE: - retvalue =3D s->uart_intr_state; + retvalue =3D s->regs[R_INTR_STATE]; break; case R_INTR_ENABLE: - retvalue =3D s->uart_intr_enable; + retvalue =3D s->regs[R_INTR_ENABLE]; break; case R_INTR_TEST: qemu_log_mask(LOG_GUEST_ERROR, @@ -285,22 +330,22 @@ static uint64_t ot_uart_read(void *opaque, hwaddr add= r, unsigned int size) break; =20 case R_CTRL: - retvalue =3D s->uart_ctrl; + retvalue =3D s->regs[R_CTRL]; break; case R_STATUS: - retvalue =3D s->uart_status; + retvalue =3D s->regs[R_STATUS]; break; =20 case R_RDATA: - retvalue =3D s->uart_rdata; - if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) && (s->rx_level > 0)) { + retvalue =3D s->regs[R_RDATA]; + if ((s->regs[R_CTRL] & R_CTRL_RX_MASK) && (s->rx_level > 0)) { qemu_chr_fe_accept_input(&s->chr); =20 s->rx_level -=3D 1; - s->uart_status &=3D ~R_STATUS_RXFULL_MASK; + s->regs[R_STATUS] &=3D ~R_STATUS_RXFULL_MASK; if (s->rx_level =3D=3D 0) { - s->uart_status |=3D R_STATUS_RXIDLE_MASK; - s->uart_status |=3D R_STATUS_RXEMPTY_MASK; + s->regs[R_STATUS] |=3D R_STATUS_RXIDLE_MASK; + s->regs[R_STATUS] |=3D R_STATUS_RXEMPTY_MASK; } } break; @@ -310,10 +355,10 @@ static uint64_t ot_uart_read(void *opaque, hwaddr add= r, unsigned int size) break; =20 case R_FIFO_CTRL: - retvalue =3D s->uart_fifo_ctrl; + retvalue =3D s->regs[R_FIFO_CTRL]; break; case R_FIFO_STATUS: - retvalue =3D s->uart_fifo_status; + retvalue =3D s->regs[R_FIFO_STATUS]; =20 retvalue |=3D (s->rx_level & 0x1F) << R_FIFO_STATUS_RXLVL_SHIFT; retvalue |=3D (s->tx_level & 0x1F) << R_FIFO_STATUS_TXLVL_SHIFT; @@ -323,17 +368,17 @@ static uint64_t ot_uart_read(void *opaque, hwaddr add= r, unsigned int size) break; =20 case R_OVRD: - retvalue =3D s->uart_ovrd; + retvalue =3D s->regs[R_OVRD]; qemu_log_mask(LOG_UNIMP, "%s: ovrd is not supported\n", __func__); break; case R_VAL: - retvalue =3D s->uart_val; + retvalue =3D s->regs[R_VAL]; qemu_log_mask(LOG_UNIMP, "%s: val is not supported\n", __func__); break; case R_TIMEOUT_CTRL: - retvalue =3D s->uart_timeout_ctrl; + retvalue =3D s->regs[R_TIMEOUT_CTRL]; qemu_log_mask(LOG_UNIMP, "%s: timeout_ctrl is not supported\n", __func__); break; @@ -355,20 +400,23 @@ static void ot_uart_write(void *opaque, hwaddr addr, = uint64_t val64, switch (addr >> 2) { case R_INTR_STATE: /* Write 1 clear */ - s->uart_intr_state &=3D ~value; + value &=3D INTR_MASK; + s->regs[R_INTR_STATE] &=3D ~value; ot_uart_update_irqs(s); break; case R_INTR_ENABLE: - s->uart_intr_enable =3D value; + value &=3D INTR_MASK; + s->regs[R_INTR_ENABLE] =3D value; ot_uart_update_irqs(s); break; case R_INTR_TEST: - s->uart_intr_state |=3D value; + value &=3D INTR_MASK; + s->regs[R_INTR_STATE] |=3D value; ot_uart_update_irqs(s); break; =20 case R_CTRL: - s->uart_ctrl =3D value; + s->regs[R_CTRL] =3D value; =20 if (value & R_CTRL_NF_MASK) { qemu_log_mask(LOG_UNIMP, @@ -412,11 +460,11 @@ static void ot_uart_write(void *opaque, hwaddr addr, = uint64_t val64, "%s: rdata is read only\n", __func__); break; case R_WDATA: - uart_write_tx_fifo(s, (uint8_t *) &value, 1); + uart_write_tx_fifo(s, value); break; =20 case R_FIFO_CTRL: - s->uart_fifo_ctrl =3D value; + s->regs[R_FIFO_CTRL] =3D value; =20 if (value & R_FIFO_CTRL_RXRST_MASK) { s->rx_level =3D 0; @@ -431,18 +479,20 @@ static void ot_uart_write(void *opaque, hwaddr addr, = uint64_t val64, qemu_log_mask(LOG_GUEST_ERROR, "%s: fifo_status is read only\n", __func__); break; - case R_OVRD: - s->uart_ovrd =3D value; - qemu_log_mask(LOG_UNIMP, - "%s: ovrd is not supported\n", __func__); + if (value & R_OVRD_TXEN_MASK) { + qemu_log_mask(LOG_UNIMP, "%s: OVRD.TXEN is not supported\n", + __func__); + } + s->regs[R_OVRD] =3D value & R_OVRD_TXVAL_MASK; break; case R_VAL: qemu_log_mask(LOG_GUEST_ERROR, "%s: val is read only\n", __func__); break; case R_TIMEOUT_CTRL: - s->uart_timeout_ctrl =3D value; + s->regs[R_TIMEOUT_CTRL] =3D + value & (R_TIMEOUT_CTRL_EN_MASK | R_TIMEOUT_CTRL_VAL_MASK); qemu_log_mask(LOG_UNIMP, "%s: timeout_ctrl is not supported\n", __func__); break; @@ -466,8 +516,8 @@ static void fifo_trigger_update(void *opaque) { OtUARTState *s =3D opaque; =20 - if (s->uart_ctrl & R_CTRL_TX_ENABLE_MASK) { - ot_uart_xmit(NULL, G_IO_OUT, s); + if (s->regs[R_CTRL] & R_CTRL_TX_MASK) { + ot_uart_xmit(s); } } =20 @@ -489,25 +539,17 @@ static int ot_uart_post_load(void *opaque, int versio= n_id) =20 static const VMStateDescription vmstate_ot_uart =3D { .name =3D TYPE_OT_UART, - .version_id =3D 1, - .minimum_version_id =3D 1, + .version_id =3D 2, + .minimum_version_id =3D 2, .post_load =3D ot_uart_post_load, .fields =3D (const VMStateField[]) { - VMSTATE_UINT8_ARRAY(tx_fifo, OtUARTState, - OT_UART_TX_FIFO_SIZE), + VMSTATE_STRUCT(tx_fifo, OtUARTState, 1, vmstate_fifo8, Fifo8), + VMSTATE_STRUCT(rx_fifo, OtUARTState, 1, vmstate_fifo8, Fifo8), VMSTATE_UINT32(tx_level, OtUARTState), VMSTATE_UINT64(char_tx_time, OtUARTState), VMSTATE_TIMER_PTR(fifo_trigger_handle, OtUARTState), - VMSTATE_UINT32(uart_intr_state, OtUARTState), - VMSTATE_UINT32(uart_intr_enable, OtUARTState), - VMSTATE_UINT32(uart_ctrl, OtUARTState), - VMSTATE_UINT32(uart_status, OtUARTState), - VMSTATE_UINT32(uart_rdata, OtUARTState), - VMSTATE_UINT32(uart_fifo_ctrl, OtUARTState), - VMSTATE_UINT32(uart_fifo_status, OtUARTState), - VMSTATE_UINT32(uart_ovrd, OtUARTState), - VMSTATE_UINT32(uart_val, OtUARTState), - VMSTATE_UINT32(uart_timeout_ctrl, OtUARTState), + VMSTATE_ARRAY(regs, OtUARTState, REGS_COUNT, 1, vmstate_info_uint3= 2, + uint32_t), VMSTATE_END_OF_LIST() } }; @@ -529,9 +571,16 @@ static void ot_uart_init(Object *obj) sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow); =20 - memory_region_init_io(&s->mmio, obj, &ot_uart_ops, s, - TYPE_OT_UART, 0x400); + memory_region_init_io(&s->mmio, obj, &ot_uart_ops, s, TYPE_OT_UART, + REGS_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + + /* + * This array has a fixed size in the header. This assertion is used to + * check that it is consistent with the definition in this file. This = is + * ostensibly a runtime check, but may be optimised away by the compil= er. + */ + assert(REGS_SIZE =3D=3D sizeof(s->regs)); } =20 static void ot_uart_realize(DeviceState *dev, Error **errp) @@ -541,6 +590,9 @@ static void ot_uart_realize(DeviceState *dev, Error **e= rrp) s->fifo_trigger_handle =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, fifo_trigger_update, s); =20 + fifo8_create(&s->tx_fifo, OT_UART_TX_FIFO_SIZE); + fifo8_create(&s->rx_fifo, OT_UART_RX_FIFO_SIZE); + qemu_chr_fe_set_handlers(&s->chr, ot_uart_can_receive, ot_uart_receive, NULL, NULL, s, NULL, true); diff --git a/include/hw/char/ot_uart.h b/include/hw/char/ot_uart.h index fee2128f90..f489612700 100644 --- a/include/hw/char/ot_uart.h +++ b/include/hw/char/ot_uart.h @@ -26,11 +26,11 @@ #define HW_OT_UART_H =20 #include "hw/core/sysbus.h" +#include "qemu/fifo8.h" #include "chardev/char-fe.h" #include "qemu/timer.h" #include "qom/object.h" =20 -#define OT_UART_TX_FIFO_SIZE 16 #define OT_UART_CLOCK 50000000 /* 50MHz clock */ =20 #define TYPE_OT_UART "ot-uart" @@ -43,7 +43,6 @@ struct OtUARTState { /* */ MemoryRegion mmio; =20 - uint8_t tx_fifo[OT_UART_TX_FIFO_SIZE]; uint32_t tx_level; =20 uint32_t rx_level; @@ -51,16 +50,11 @@ struct OtUARTState { QEMUTimer *fifo_trigger_handle; uint64_t char_tx_time; =20 - uint32_t uart_intr_state; - uint32_t uart_intr_enable; - uint32_t uart_ctrl; - uint32_t uart_status; - uint32_t uart_rdata; - uint32_t uart_fifo_ctrl; - uint32_t uart_fifo_status; - uint32_t uart_ovrd; - uint32_t uart_val; - uint32_t uart_timeout_ctrl; + uint32_t regs[13]; /* Length must be updated if regs added or removed = */ + + Fifo8 tx_fifo; + Fifo8 rx_fifo; + uint32_t tx_watermark_level; =20 Clock *f_clk; =20 --=20 2.49.1 From nobody Tue May 26 03:33:44 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=git.sr.ht Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777565093327625.4309008344582; Thu, 30 Apr 2026 09:04:53 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wITs6-0001Ak-E2; Thu, 30 Apr 2026 12:04:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrC-0007UH-6g; Thu, 30 Apr 2026 12:03:24 -0400 Received: from mail-a.sr.ht ([46.23.81.152]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITr9-00078Z-DY; Thu, 30 Apr 2026 12:03:16 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 39C1A20C76; Thu, 30 Apr 2026 16:03:12 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=t4iQhUpFRyAgERtmsoOXchPum38b2rhvJCOxHACr+zY=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1777564992; v=1; b=hiGxLjjwYcuxq1HdNKItXQa8Wiq3k5QCvtyVhON95xkRarli+yHTsIESQt+lhMsj8mTXXDW+ LCnTzQGdJ5e9A42OGXJOPNwUftHuCl4n2R8jkJy2DNwroeRuvy/5JGvRLfawrORV6671QTJeyf1 FXMhmC754kd1B3mBkfgShPXi7JMSNH+lPXAP1ZbIYWj8vwwtF2ZX35S+pPVceX2Iei6eJwcNsU3 lg0xtDynnpFNoozENDdJdE7O/PM/tZwRclztzcPGiY1j7R3Atmx3HlR0DZyZSdKeESufgo6BkGP 6gDpBWUdQKHjNdMdiE0EmLfPSrbqvQI33MZEK8cYhM94g== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 14:38:47 +0100 Subject: [PATCH qemu v4 4/9] ot_uart: replace individual IRQ fields with array, add missing IRQs Message-ID: <177756498815.8917.12449488721849651971-4@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177756498815.8917.12449488721849651971-0@git.sr.ht> To: qemu-riscv@nongnu.org, Alistair Francis Cc: Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9?= Lureau , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-devel@nongnu.org, Amit Kumar-Hermosillo , nabihestefan Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=46.23.81.152; envelope-from=outgoing@sr.ht; helo=mail-a.sr.ht X-Spam_score_int: 17 X-Spam_score: 1.7 X-Spam_bar: + X-Spam_report: (1.7 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_96_XX=3.405, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ~lexbaileylowrisc Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1777565094357158500 From: Lex Bailey There are 9 interrupts in the OpenTitan UART device. These are documented here: https://opentitan.org/book/hw/ip/uart/doc/theory_of_operation.html#interrup= ts This commit removes the individually named interrupts (of which there was o= nly four) and replaces them with an array of 9 interrupts. Signed-off-by: Lex Bailey Reviewed-by: Alistair Francis --- hw/char/ot_uart.c | 44 +++++++++++++-------------------------- include/hw/char/ot_uart.h | 5 +---- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index 3fe7c5efe5..62c182cbed 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -102,6 +102,7 @@ REG32(TIMEOUT_CTRL, 0x30) #define OT_UART_NCO_BITS 16 #define OT_UART_TX_FIFO_SIZE 128 #define OT_UART_RX_FIFO_SIZE 128 +#define OT_UART_IRQ_NUM 9 =20 #define R32_OFF(_r_) ((_r_) / sizeof(uint32_t)) =20 @@ -111,31 +112,11 @@ REG32(TIMEOUT_CTRL, 0x30) =20 static void ot_uart_update_irqs(OtUARTState *s) { - if (s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE] - & INTR_TX_WATERMARK_MASK) { - qemu_set_irq(s->tx_watermark, 1); - } else { - qemu_set_irq(s->tx_watermark, 0); - } - - if (s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE] - & INTR_RX_WATERMARK_MASK) { - qemu_set_irq(s->rx_watermark, 1); - } else { - qemu_set_irq(s->rx_watermark, 0); - } + uint32_t state_masked =3D s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABL= E]; =20 - if (s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE] & INTR_TX_EMPTY_MAS= K) { - qemu_set_irq(s->tx_empty, 1); - } else { - qemu_set_irq(s->tx_empty, 0); - } - - if (s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABLE] - & INTR_RX_OVERFLOW_MASK) { - qemu_set_irq(s->rx_overflow, 1); - } else { - qemu_set_irq(s->rx_overflow, 0); + for (int index =3D 0; index < OT_UART_IRQ_NUM; index++) { + bool level =3D (state_masked & (1U << index)) !=3D 0; + qemu_set_irq(s->irqs[index], level); } } =20 @@ -290,6 +271,9 @@ static void ot_uart_reset_enter(Object *obj, ResetType = type) s->regs[R_STATUS] =3D 0x0000003c; =20 s->tx_watermark_level =3D 0; + for (unsigned index =3D 0; index < ARRAY_SIZE(s->irqs); index++) { + qemu_set_irq(s->irqs[index], 0); + } ot_uart_reset_tx_fifo(s); ot_uart_reset_rx_fifo(s); =20 @@ -566,21 +550,21 @@ static void ot_uart_init(Object *obj) ot_uart_clk_update, s, ClockUpdate); clock_set_hz(s->f_clk, OT_UART_CLOCK); =20 - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark); - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark); - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow); + for (unsigned index =3D 0; index < OT_UART_IRQ_NUM; index++) { + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irqs[index]); + } =20 memory_region_init_io(&s->mmio, obj, &ot_uart_ops, s, TYPE_OT_UART, REGS_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); =20 /* - * This array has a fixed size in the header. This assertion is used to - * check that it is consistent with the definition in this file. This = is + * These arrays have fixed sizes in the header. These assertions are u= sed to + * check that they are consistent with the definitions in this file. T= his is * ostensibly a runtime check, but may be optimised away by the compil= er. */ assert(REGS_SIZE =3D=3D sizeof(s->regs)); + assert(OT_UART_IRQ_NUM * sizeof(qemu_irq) =3D=3D sizeof(s->irqs)); } =20 static void ot_uart_realize(DeviceState *dev, Error **errp) diff --git a/include/hw/char/ot_uart.h b/include/hw/char/ot_uart.h index f489612700..a2c5ff8b33 100644 --- a/include/hw/char/ot_uart.h +++ b/include/hw/char/ot_uart.h @@ -42,6 +42,7 @@ struct OtUARTState { =20 /* */ MemoryRegion mmio; + qemu_irq irqs[9]; =20 uint32_t tx_level; =20 @@ -59,10 +60,6 @@ struct OtUARTState { Clock *f_clk; =20 CharFrontend chr; - qemu_irq tx_watermark; - qemu_irq rx_watermark; - qemu_irq tx_empty; - qemu_irq rx_overflow; }; =20 struct OtUARTClass { --=20 2.49.1 From nobody Tue May 26 03:33:44 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=git.sr.ht Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777565038230592.1692991558939; Thu, 30 Apr 2026 09:03:58 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wITrS-0007qA-TZ; Thu, 30 Apr 2026 12:03:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrI-0007Vx-9T; Thu, 30 Apr 2026 12:03:24 -0400 Received: from mail-a.sr.ht ([46.23.81.152]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrC-00078x-8S; Thu, 30 Apr 2026 12:03:23 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 548E920C7B; Thu, 30 Apr 2026 16:03:13 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=ywww7Nv5Qiuj7CAJWTkw1HmYKvkxUnqP3gKISLYCA3I=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1777564993; v=1; b=p6UWgn57Zlq//5wvy1aNHLraPrvq7c76HFHRyTje2Og8CPbiBDZWczt81riwt23EhWPN5C7S 4ELKdoKhWeB0E4EYYtNV6F8iurBT6n8EkpyF5ptKnl68h3CTrhh6yLhQ91iAYamcEAO2Ggfkfsu ArSQOXOXUt5K3uLARMHeG9MQrh18pTsQjJuHuR4jKY6OjppOlK77P0ZN1BL7hNbx/uV7DbnCdZD pJC1cDIu+JebKjrHngo5yolLnc+TdVJj9PTVlEOAFANVG93/RCIDaDkNBY6zFEJ0fKIlzLBpVL0 1xl9hl0jexdzpHT+XFAKval5OVdbSqxo4tLZ+xhT/kM5g== From: ~lexbaileylowrisc Date: Mon, 13 Apr 2026 17:27:19 +0100 Subject: [PATCH qemu v4 5/9] ot_uart: gather similar behaviours togeter in register read and write Message-ID: <177756498815.8917.12449488721849651971-5@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177756498815.8917.12449488721849651971-0@git.sr.ht> To: qemu-riscv@nongnu.org, Alistair Francis Cc: Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9?= Lureau , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-devel@nongnu.org, Amit Kumar-Hermosillo , nabihestefan Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=46.23.81.152; envelope-from=outgoing@sr.ht; helo=mail-a.sr.ht X-Spam_score_int: 17 X-Spam_score: 1.7 X-Spam_bar: + X-Spam_report: (1.7 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_96_XX=3.405, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ~lexbaileylowrisc Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1777565042461158500 From: Lex Bailey the register read and write functions are each a large switch statement with many similar behaviours in, this is mostly for enabling the use of specific register names inside of log messages. this commit adds a lookup table for register names and uses that instead, allowing much of the code in the regi= ster read and write functions to be deduplicated. the write function was also missing a switch case for R_ALERT_TEST, so I ad= ded that in this commit since it has a very simple implementation for now Signed-off-by: Lex Bailey --- hw/char/ot_uart.c | 103 ++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index 62c182cbed..2247db7110 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -109,6 +109,26 @@ REG32(TIMEOUT_CTRL, 0x30) #define R_LAST_REG (R_TIMEOUT_CTRL) #define REGS_COUNT (R_LAST_REG + 1u) #define REGS_SIZE (REGS_COUNT * sizeof(uint32_t)) +#define REG_NAME(_reg_) \ + ((((_reg_) < REGS_COUNT) && REG_NAMES[_reg_]) ? REG_NAMES[_reg_] : "?") + +#define REG_NAME_ENTRY(_reg_) [R_##_reg_] =3D stringify(_reg_) +static const char *REG_NAMES[REGS_COUNT] =3D { + REG_NAME_ENTRY(INTR_STATE), + REG_NAME_ENTRY(INTR_ENABLE), + REG_NAME_ENTRY(INTR_TEST), + REG_NAME_ENTRY(ALERT_TEST), + REG_NAME_ENTRY(CTRL), + REG_NAME_ENTRY(STATUS), + REG_NAME_ENTRY(RDATA), + REG_NAME_ENTRY(WDATA), + REG_NAME_ENTRY(FIFO_CTRL), + REG_NAME_ENTRY(FIFO_STATUS), + REG_NAME_ENTRY(OVRD), + REG_NAME_ENTRY(VAL), + REG_NAME_ENTRY(TIMEOUT_CTRL), +}; +#undef REG_NAME_ENTRY =20 static void ot_uart_update_irqs(OtUARTState *s) { @@ -301,23 +321,14 @@ static uint64_t ot_uart_read(void *opaque, hwaddr add= r, unsigned int size) OtUARTState *s =3D opaque; uint64_t retvalue =3D 0; =20 - switch (addr >> 2) { + hwaddr reg =3D R32_OFF(addr); + switch (reg) { case R_INTR_STATE: - retvalue =3D s->regs[R_INTR_STATE]; - break; case R_INTR_ENABLE: - retvalue =3D s->regs[R_INTR_ENABLE]; - break; - case R_INTR_TEST: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: wdata is write only\n", __func__); - break; - case R_CTRL: - retvalue =3D s->regs[R_CTRL]; - break; + case R_FIFO_CTRL: case R_STATUS: - retvalue =3D s->regs[R_STATUS]; + retvalue =3D s->regs[reg]; break; =20 case R_RDATA: @@ -333,14 +344,7 @@ static uint64_t ot_uart_read(void *opaque, hwaddr addr= , unsigned int size) } } break; - case R_WDATA: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: wdata is write only\n", __func__); - break; =20 - case R_FIFO_CTRL: - retvalue =3D s->regs[R_FIFO_CTRL]; - break; case R_FIFO_STATUS: retvalue =3D s->regs[R_FIFO_STATUS]; =20 @@ -351,21 +355,21 @@ static uint64_t ot_uart_read(void *opaque, hwaddr add= r, unsigned int size) "%s: RX fifos are not supported\n", __func__); break; =20 - case R_OVRD: - retvalue =3D s->regs[R_OVRD]; - qemu_log_mask(LOG_UNIMP, - "%s: ovrd is not supported\n", __func__); - break; case R_VAL: - retvalue =3D s->regs[R_VAL]; - qemu_log_mask(LOG_UNIMP, - "%s: val is not supported\n", __func__); - break; + case R_OVRD: case R_TIMEOUT_CTRL: - retvalue =3D s->regs[R_TIMEOUT_CTRL]; + retvalue =3D s->regs[reg]; qemu_log_mask(LOG_UNIMP, - "%s: timeout_ctrl is not supported\n", __func__); + "%s: %s is not supported\n", __func__, REG_NAME(reg)= ); + break; + + case R_ALERT_TEST: + case R_INTR_TEST: + case R_WDATA: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s is write only\n", __func__, REG_NAME(reg)); break; + default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); @@ -381,7 +385,9 @@ static void ot_uart_write(void *opaque, hwaddr addr, ui= nt64_t val64, OtUARTState *s =3D opaque; uint32_t value =3D val64; =20 - switch (addr >> 2) { + hwaddr reg =3D R32_OFF(addr); + + switch (reg) { case R_INTR_STATE: /* Write 1 clear */ value &=3D INTR_MASK; @@ -398,7 +404,11 @@ static void ot_uart_write(void *opaque, hwaddr addr, u= int64_t val64, s->regs[R_INTR_STATE] |=3D value; ot_uart_update_irqs(s); break; - + case R_ALERT_TEST: + value &=3D R_ALERT_TEST_FATAL_FAULT_MASK; + s->regs[reg] =3D value; + /* This will also set an IRQ once the alert handler is added */ + break; case R_CTRL: s->regs[R_CTRL] =3D value; =20 @@ -434,15 +444,6 @@ static void ot_uart_write(void *opaque, hwaddr addr, u= int64_t val64, s->char_tx_time =3D (NANOSECONDS_PER_SECOND / baud) * 10; } break; - case R_STATUS: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: status is read only\n", __func__); - break; - - case R_RDATA: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: rdata is read only\n", __func__); - break; case R_WDATA: uart_write_tx_fifo(s, value); break; @@ -459,10 +460,6 @@ static void ot_uart_write(void *opaque, hwaddr addr, u= int64_t val64, s->tx_level =3D 0; } break; - case R_FIFO_STATUS: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: fifo_status is read only\n", __func__); - break; case R_OVRD: if (value & R_OVRD_TXEN_MASK) { qemu_log_mask(LOG_UNIMP, "%s: OVRD.TXEN is not supported\n", @@ -470,16 +467,22 @@ static void ot_uart_write(void *opaque, hwaddr addr, = uint64_t val64, } s->regs[R_OVRD] =3D value & R_OVRD_TXVAL_MASK; break; - case R_VAL: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: val is read only\n", __func__); - break; + case R_TIMEOUT_CTRL: s->regs[R_TIMEOUT_CTRL] =3D value & (R_TIMEOUT_CTRL_EN_MASK | R_TIMEOUT_CTRL_VAL_MASK); qemu_log_mask(LOG_UNIMP, "%s: timeout_ctrl is not supported\n", __func__); break; + + case R_STATUS: + case R_RDATA: + case R_FIFO_STATUS: + case R_VAL: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s is read only\n", __func__, REG_NAME(reg)); + break; + default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); --=20 2.49.1 From nobody Tue May 26 03:33:44 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=git.sr.ht Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777565093050172.7136455449496; Thu, 30 Apr 2026 09:04:53 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wITrw-0000VT-VQ; Thu, 30 Apr 2026 12:04:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrK-0007c9-SY; Thu, 30 Apr 2026 12:03:30 -0400 Received: from mail-a.sr.ht ([46.23.81.152]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrC-00078y-9J; Thu, 30 Apr 2026 12:03:24 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 6D13920C7D; Thu, 30 Apr 2026 16:03:13 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=4eJ+HnMcX8p6InMQPVwB32zKkriVDrfCwoCMifz9Wxk=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1777564993; v=1; b=nYqM86HtlOBZzXGHMW9tDfq7lBL57+bN7udMVIx2jyngpa7jHAIG/VgVc52ABW2HLjr78nRE Oam/zhAOX6XXERoh/ROy362SJOiHMuSsV7uf3r0p6b89QuQiSntyDpt0+mPkl63MmNGDVV6zhev PxgReGM5TPlBSJ2O77lTZO91nQOyaPU8RV9GTImebp/MecNVqvuQDKPT0GYK37KkPQvI1df845u IAWvjsO5zIfqOMykUfS8BwCYARRLqL6tDSmjzWJlGUvTxTJsP8M4du7yt8JBJA1gnwIY2Q5Of8F lX8ofz4/NnSc9J83PJCU+rNoWv+b/V52LWNXaaZdka7nw== From: ~lexbaileylowrisc Date: Mon, 13 Apr 2026 19:01:26 +0100 Subject: [PATCH qemu v4 6/9] ot_uart: implement RX fifo and loopback Message-ID: <177756498815.8917.12449488721849651971-6@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177756498815.8917.12449488721849651971-0@git.sr.ht> To: qemu-riscv@nongnu.org, Alistair Francis Cc: Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9?= Lureau , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-devel@nongnu.org, Amit Kumar-Hermosillo , nabihestefan Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=46.23.81.152; envelope-from=outgoing@sr.ht; helo=mail-a.sr.ht X-Spam_score_int: 17 X-Spam_score: 1.7 X-Spam_bar: + X-Spam_report: (1.7 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_96_XX=3.405, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ~lexbaileylowrisc Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1777565094525154100 From: Lex Bailey The STATUS register value is now generated on every read instead of being tracked in memory since it has such a dynamic value. the receive fifo is now implemented, and the system loopback mode. (line loopback is not supported) Signed-off-by: Lex Bailey --- hw/char/ot_uart.c | 160 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 112 insertions(+), 48 deletions(-) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index 2247db7110..3511a42fbe 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -140,6 +140,21 @@ static void ot_uart_update_irqs(OtUARTState *s) } } =20 +static bool ot_uart_is_sys_loopack_enabled(const OtUARTState *s) +{ + return FIELD_EX32(s->regs[R_CTRL], CTRL, SLPBK); +} + +static bool ot_uart_is_tx_enabled(const OtUARTState *s) +{ + return FIELD_EX32(s->regs[R_CTRL], CTRL, TX); +} + +static bool ot_uart_is_rx_enabled(const OtUARTState *s) +{ + return FIELD_EX32(s->regs[R_CTRL], CTRL, RX); +} + static int ot_uart_can_receive(void *opaque) { OtUARTState *s =3D opaque; @@ -196,7 +211,7 @@ static void ot_uart_reset_rx_fifo(OtUARTState *s) fifo8_reset(&s->rx_fifo); s->regs[R_INTR_STATE] &=3D ~INTR_RX_WATERMARK_MASK; s->regs[R_INTR_STATE] &=3D ~INTR_RX_OVERFLOW_MASK; - if (FIELD_EX32(s->regs[R_CTRL], CTRL, RX)) { + if (ot_uart_is_rx_enabled(s)) { qemu_chr_fe_accept_input(&s->chr); } } @@ -218,21 +233,37 @@ static void ot_uart_xmit(OtUARTState *s) return; } =20 - /* instant drain the fifo when there's no back-end */ - if (!qemu_chr_fe_backend_connected(&s->chr)) { - ot_uart_reset_tx_fifo(s); - ot_uart_update_irqs(s); - return; - } + if (ot_uart_is_sys_loopack_enabled(s)) { + /* system loopback mode, just forward to RX FIFO */ + uint32_t count =3D fifo8_num_used(&s->tx_fifo); + buf =3D fifo8_pop_bufptr(&s->tx_fifo, count, &size); + ot_uart_receive(s, buf, (int)size); + count -=3D size; + /* + * there may be more data to send if data wraps around the end of = TX + * FIFO + */ + if (count) { + buf =3D fifo8_pop_bufptr(&s->tx_fifo, count, &size); + ot_uart_receive(s, buf, (int)size); + } + } else { + /* instant drain the fifo when there's no back-end */ + if (!qemu_chr_fe_backend_connected(&s->chr)) { + ot_uart_reset_tx_fifo(s); + ot_uart_update_irqs(s); + return; + } =20 - /* get a continuous buffer from the FIFO */ - buf =3D - fifo8_peek_bufptr(&s->tx_fifo, fifo8_num_used(&s->tx_fifo), &size); - /* send as much as possible */ - ret =3D qemu_chr_fe_write(&s->chr, buf, (int)size); - /* if some characters where sent, remove them from the FIFO */ - if (ret >=3D 0) { - fifo8_drop(&s->tx_fifo, ret); + /* get a continuous buffer from the FIFO */ + buf =3D + fifo8_peek_bufptr(&s->tx_fifo, fifo8_num_used(&s->tx_fifo), &s= ize); + /* send as much as possible */ + ret =3D qemu_chr_fe_write(&s->chr, buf, (int)size); + /* if some characters where sent, remove them from the FIFO */ + if (ret >=3D 0) { + fifo8_drop(&s->tx_fifo, ret); + } } =20 /* update INTR_STATE */ @@ -269,7 +300,7 @@ static void uart_write_tx_fifo(OtUARTState *s, uint8_t = val) s->tx_watermark_level =3D 0; } =20 - if (FIELD_EX32(s->regs[R_CTRL], CTRL, TX)) { + if (ot_uart_is_tx_enabled(s)) { ot_uart_xmit(s); } =20 @@ -288,8 +319,6 @@ static void ot_uart_reset_enter(Object *obj, ResetType = type) =20 memset(&s->regs[0], 0, sizeof(s->regs)); =20 - s->regs[R_STATUS] =3D 0x0000003c; - s->tx_watermark_level =3D 0; for (unsigned index =3D 0; index < ARRAY_SIZE(s->irqs); index++) { qemu_set_irq(s->irqs[index], 0); @@ -305,6 +334,27 @@ static void ot_uart_reset_enter(Object *obj, ResetType= type) ot_uart_update_irqs(s); } =20 +static uint8_t ot_uart_read_rx_fifo(OtUARTState *s) +{ + uint8_t val; + + if (!(s->regs[R_CTRL] & R_CTRL_RX_MASK)) { + return 0; + } + + if (fifo8_is_empty(&s->rx_fifo)) { + return 0; + } + + val =3D fifo8_pop(&s->rx_fifo); + + if (ot_uart_is_rx_enabled(s) && !ot_uart_is_sys_loopack_enabled(s)) { + qemu_chr_fe_accept_input(&s->chr); + } + + return val; +} + static uint64_t ot_uart_get_baud(OtUARTState *s) { uint64_t baud; @@ -327,32 +377,50 @@ static uint64_t ot_uart_read(void *opaque, hwaddr add= r, unsigned int size) case R_INTR_ENABLE: case R_CTRL: case R_FIFO_CTRL: - case R_STATUS: retvalue =3D s->regs[reg]; break; + case R_STATUS: + /* assume that UART always report RXIDLE */ + retvalue =3D R_STATUS_RXIDLE_MASK; + /* report RXEMPTY or RXFULL */ + switch (fifo8_num_used(&s->rx_fifo)) { + case 0: + retvalue |=3D R_STATUS_RXEMPTY_MASK; + break; + case OT_UART_RX_FIFO_SIZE: + retvalue |=3D R_STATUS_RXFULL_MASK; + break; + default: + break; + } + /* report TXEMPTY+TXIDLE or TXFULL */ + switch (fifo8_num_used(&s->tx_fifo)) { + case 0: + retvalue |=3D R_STATUS_TXEMPTY_MASK | R_STATUS_TXIDLE_MASK; + break; + case OT_UART_TX_FIFO_SIZE: + retvalue |=3D R_STATUS_TXFULL_MASK; + break; + default: + break; + } + if (!ot_uart_is_tx_enabled(s)) { + retvalue |=3D R_STATUS_TXIDLE_MASK; + } + if (!ot_uart_is_rx_enabled(s)) { + retvalue |=3D R_STATUS_RXIDLE_MASK; + } + break; =20 case R_RDATA: - retvalue =3D s->regs[R_RDATA]; - if ((s->regs[R_CTRL] & R_CTRL_RX_MASK) && (s->rx_level > 0)) { - qemu_chr_fe_accept_input(&s->chr); - - s->rx_level -=3D 1; - s->regs[R_STATUS] &=3D ~R_STATUS_RXFULL_MASK; - if (s->rx_level =3D=3D 0) { - s->regs[R_STATUS] |=3D R_STATUS_RXIDLE_MASK; - s->regs[R_STATUS] |=3D R_STATUS_RXEMPTY_MASK; - } - } + retvalue =3D (uint32_t)ot_uart_read_rx_fifo(s); break; =20 case R_FIFO_STATUS: - retvalue =3D s->regs[R_FIFO_STATUS]; - - retvalue |=3D (s->rx_level & 0x1F) << R_FIFO_STATUS_RXLVL_SHIFT; - retvalue |=3D (s->tx_level & 0x1F) << R_FIFO_STATUS_TXLVL_SHIFT; - - qemu_log_mask(LOG_UNIMP, - "%s: RX fifos are not supported\n", __func__); + retvalue =3D + (fifo8_num_used(&s->rx_fifo) & 0xffu) << R_FIFO_STATUS_RXLVL_S= HIFT; + retvalue |=3D + (fifo8_num_used(&s->tx_fifo) & 0xffu) << R_FIFO_STATUS_TXLVL_S= HIFT; break; =20 case R_VAL: @@ -416,10 +484,6 @@ static void ot_uart_write(void *opaque, hwaddr addr, u= int64_t val64, qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_NF is not supported\n", __func__); } - if (value & R_CTRL_SLPBK_MASK) { - qemu_log_mask(LOG_UNIMP, - "%s: UART_CTRL_SLPBK is not supported\n", __func= __); - } if (value & R_CTRL_LLPBK_MASK) { qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_LLPBK is not supported\n", __func= __); @@ -445,19 +509,19 @@ static void ot_uart_write(void *opaque, hwaddr addr, = uint64_t val64, } break; case R_WDATA: - uart_write_tx_fifo(s, value); + uart_write_tx_fifo(s, (uint8_t)(value & R_WDATA_WDATA_MASK)); break; =20 case R_FIFO_CTRL: - s->regs[R_FIFO_CTRL] =3D value; - + s->regs[R_FIFO_CTRL] =3D + value & (R_FIFO_CTRL_RXILVL_MASK | R_FIFO_CTRL_TXILVL_MASK); if (value & R_FIFO_CTRL_RXRST_MASK) { - s->rx_level =3D 0; - qemu_log_mask(LOG_UNIMP, - "%s: RX fifos are not supported\n", __func__); + ot_uart_reset_rx_fifo(s); + ot_uart_update_irqs(s); } if (value & R_FIFO_CTRL_TXRST_MASK) { - s->tx_level =3D 0; + ot_uart_reset_tx_fifo(s); + ot_uart_update_irqs(s); } break; case R_OVRD: --=20 2.49.1 From nobody Tue May 26 03:33:44 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=git.sr.ht Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777565032323396.06370167783757; Thu, 30 Apr 2026 09:03:52 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wITrS-0007qB-R6; Thu, 30 Apr 2026 12:03:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrK-0007cA-TJ; Thu, 30 Apr 2026 12:03:30 -0400 Received: from mail-a.sr.ht ([46.23.81.152]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrG-00079Y-7Q; Thu, 30 Apr 2026 12:03:26 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 83EF020C81; Thu, 30 Apr 2026 16:03:13 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=5CJSSplXBWzwOKftMniqF9csQcjNBZIZr2WVOB8vGes=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1777564993; v=1; b=mzAFVgt/+mLoRP9qs4hGPiYrWfzmWTn3uw3rBa0O9M7xxXAqJiTAyCxjFuvskJTlMP4j6PGs qe6ZUBHobGeKIc01aSVTY8JnxXaIWXbtLjjbDidaOLIjhGqy1AWhdxuYP2WW1DNigE8/5JRC+fB uOqLfddhXvrqmzMFuYYbb+8J7XTPQin5kZiljGiYAs/lbBNmvzB0oEJdFapTtSI6Eg/0xbZdWXN EdUMGGsyFDWEADdfhdW9CKLscN8/4tZ4C1LXP9lMZHLX8+pxlhRrOELZULTO3fRQuoIEXF2KHyz zMlI9lz3uVMiDJ70sjMLjCK7PAUMsNAEqiZKRnogRJ0dg== From: ~lexbaileylowrisc Date: Tue, 14 Apr 2026 13:45:41 +0100 Subject: [PATCH qemu v4 7/9] ot_uart: handle break condition Message-ID: <177756498815.8917.12449488721849651971-7@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177756498815.8917.12449488721849651971-0@git.sr.ht> To: qemu-riscv@nongnu.org, Alistair Francis Cc: Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9?= Lureau , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-devel@nongnu.org, Amit Kumar-Hermosillo , nabihestefan Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=46.23.81.152; envelope-from=outgoing@sr.ht; helo=mail-a.sr.ht X-Spam_score_int: 17 X-Spam_score: 1.7 X-Spam_bar: + X-Spam_report: (1.7 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_96_XX=3.405, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ~lexbaileylowrisc Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1777565036700154100 From: Lex Bailey What is a break event: Normally, a UART wire is held high by the transmitting device any time the communication channel is idle (nothing to transmit). If a receiver does not= see that its receive line is high, this means one of two things: 1. there is a transmission happening now 2. there is no transmitter connected, and the line is floating or pulled low, or the transmitting device is in a bad state or reset state and= so it has not yet asserted its TX output. In case 1, the line will go high again very soon. In case 2, it is sometimes useful to detect that this is the case and signa= l to the software that this has happened (normally by means of an interrupt) The ot_uart device does exactly this in case 2. It detects that this is happening by detecting when the RX pin stays low for an extended period. Th= is period can be configured to be 2, 4, 8, or 16 times a character period. The character period itself depends on the configuration of the device (baud ra= te, and parity bit) for more details about how this works, there is documentation about the UART break detection on this page: https://opentitan.org/book/hw/ip/uart/doc/theory_of_operation.html#rx_break= _err This commit adds a handler for the UART break event, and logic to emulate a break when oversampling is enabled and there is a break event. Signed-off-by: Lex Bailey --- docs/system/riscv/opentitan-uart.rst | 43 +++++++++++++ hw/char/ot_uart.c | 92 +++++++++++++++++++++++++++- include/hw/char/ot_uart.h | 4 ++ 3 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 docs/system/riscv/opentitan-uart.rst diff --git a/docs/system/riscv/opentitan-uart.rst b/docs/system/riscv/opent= itan-uart.rst new file mode 100644 index 0000000000..7ca596712d --- /dev/null +++ b/docs/system/riscv/opentitan-uart.rst @@ -0,0 +1,43 @@ +# OpenTitan UART Support + +## Connecting to the UART + +* `-serial mon:stdio`, used as the first `-serial` option, redirects the v= irtual UART0 to the + current console/shell. + +* `-chardev socket,id=3Dserial1,host=3Dlocalhost,port=3D8001,server=3Don,w= ait=3Doff` and + `-serial chardev:serial1` can be used to redirect UART1 (in this example= ) to a TCP socket. These + options are not specific to OpenTitan emulation, but are useful to commu= nicate over a UART. + Note that QEMU offers many `chardev` backends, please check QEMU documen= tation for details. + +## Sending Break Conditions + +Break conditions can be sent to the UART on select supported CharDev backe= nds (telnet, mux) +or by sending the `chardev-send-break` command with the CharDev ID via the= QEMU Monitor. +Break conditions are treated as transient events and the length of time of= a break condition +is not considered. + +## Oversampling + +OpenTitan's UART has a `VAL` register which oversamples the RX pin 16 time= s per bit. +This cannot be emulated by QEMU which uses a CharDev backend and does not = have a notion of +accurate sampling times. + +If software wishes to poll the `VAL` register to determine break condition= s, there are +some properties available to help with emulating this use case: + +* `-global ot-uart.oversample-break=3Dtrue` is used to enable UART break o= versampling. + This will attempt to display 16 samples of the last bit received in the = `VAL` register, + which will be 16 high bits after any UART frame is transmitted (as these= end with a stop + bit, which is high), or 16 low bits if the UART previously received a br= eak condition + and has not received any frames since. That is, enabling this property a= ssumes that + transmitted break conditions are "held" until the next UART transfer in = terms of what + is being shown in the oversampled `VAL` register. + +* `-global ot-uart.toggle-break=3Dtrue` is used to provide more control ov= er "holding" + the UART RX break condition like a GPIO strap, and changes the behavior = of a UART + such that received break condition events now *toggle* the break conditi= on state + rather than keeping it asserted until the next transfer. This allows any= device talking + to OpenTitan via UART to have more precise control over when the UART VA= L register + displays idle and when it displays a break condition, as it can precisel= y toggle the + break condition on or off like a GPIO strapping being held down. diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index 3511a42fbe..cdf02da62b 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -179,6 +179,11 @@ static void ot_uart_receive(void *opaque, const uint8_= t *buf, int size) uint32_t rx_watermark_level; size_t count =3D MIN(fifo8_num_free(&s->rx_fifo), (size_t)size); =20 + if (size && !s->toggle_break) { + /* no longer breaking, so emulate idle in oversampled VAL register= */ + s->in_break =3D false; + } + for (int index =3D 0; index < size; index++) { fifo8_push(&s->rx_fifo, buf[index]); } @@ -331,9 +336,40 @@ static void ot_uart_reset_enter(Object *obj, ResetType= type) =20 s->char_tx_time =3D (NANOSECONDS_PER_SECOND / 230400) * 10; =20 + /* + * do not reset `s->in_break`, as that tracks whether we are currently + * receiving a break condition over UART RX from some device talking + * to OpenTitan, which should survive resets. The QEMU CharDev only + * supports transient break events and not the notion of holding the + * UART in break, so remembering breaks like this is required to + * support mocking of break conditions in the oversampled `VAL` reg. + */ + if (s->in_break) { + /* ignore CTRL.RXBLVL as we have no notion of break "time" */ + s->regs[R_INTR_STATE] |=3D INTR_RX_BREAK_ERR_MASK; + } + ot_uart_update_irqs(s); } =20 +static void ot_uart_event_handler(void *opaque, QEMUChrEvent event) +{ + OtUARTState *s =3D opaque; + + if (event =3D=3D CHR_EVENT_BREAK) { + if (!s->in_break || !s->oversample_break) { + /* ignore CTRL.RXBLVL as we have no notion of break "time" */ + s->regs[R_INTR_STATE] |=3D INTR_RX_BREAK_ERR_MASK; + ot_uart_update_irqs(s); + /* emulate break in the oversampled VAL register */ + s->in_break =3D true; + } else if (s->toggle_break) { + /* emulate toggling break off in the oversampled VAL register = */ + s->in_break =3D false; + } + } +} + static uint8_t ot_uart_read_rx_fifo(OtUARTState *s) { uint8_t val; @@ -355,6 +391,17 @@ static uint8_t ot_uart_read_rx_fifo(OtUARTState *s) return val; } =20 +static gboolean ot_uart_watch_cb(void *do_not_use, GIOCondition cond, + void *opaque) +{ + OtUARTState *s =3D opaque; + + s->watch_tag =3D 0; + ot_uart_xmit(s); + + return FALSE; +} + static uint64_t ot_uart_get_baud(OtUARTState *s) { uint64_t baud; @@ -424,6 +471,26 @@ static uint64_t ot_uart_read(void *opaque, hwaddr addr= , unsigned int size) break; =20 case R_VAL: + /* + * This is not trivially implemented due to the QEMU UART + * interface. There is no way to reliably sample or oversample + * given our emulated interface, but some software might poll the + * value of this register to determine break conditions. + * + * As such, default to reporting 16 of the last sample received + * instead. This defaults to 16 idle high samples (as a stop bit is + * always the last received), except for when the `oversample-brea= k` + * property is set and a break condition is received over UART RX, + * where we then show 16 low samples until the next valid UART + * transmission is received (or break is toggled off with the + * `toggle-break` property enabled). This will not be accurate, but + * should be sufficient to support basic software flows that + * essentially use UART break as a strapping mechanism. + */ + retvalue =3D (s->in_break && s->oversample_break) ? 0u : UINT16_MA= X; + qemu_log_mask(LOG_UNIMP, "%s: VAL only shows idle%s\n", __func__, + (s->oversample_break ? "/break" : "")); + break; case R_OVRD: case R_TIMEOUT_CTRL: retvalue =3D s->regs[reg]; @@ -607,8 +674,27 @@ static const VMStateDescription vmstate_ot_uart =3D { =20 static const Property ot_uart_properties[] =3D { DEFINE_PROP_CHR("chardev", OtUARTState, chr), + DEFINE_PROP_BOOL("oversample-break", OtUARTState, oversample_break, fa= lse), + DEFINE_PROP_BOOL("toggle-break", OtUARTState, toggle_break, false), }; =20 +static int ot_uart_fe_change(void *opaque) +{ + OtUARTState *s =3D opaque; + + qemu_chr_fe_set_handlers(&s->chr, ot_uart_can_receive, ot_uart_receive, + ot_uart_event_handler, ot_uart_fe_change, s, = NULL, + true); + + if (s->watch_tag > 0) { + g_source_remove(s->watch_tag); + s->watch_tag =3D qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HU= P, + ot_uart_watch_cb, s); + } + + return 0; +} + static void ot_uart_init(Object *obj) { OtUARTState *s =3D OT_UART(obj); @@ -644,9 +730,9 @@ static void ot_uart_realize(DeviceState *dev, Error **e= rrp) fifo8_create(&s->tx_fifo, OT_UART_TX_FIFO_SIZE); fifo8_create(&s->rx_fifo, OT_UART_RX_FIFO_SIZE); =20 - qemu_chr_fe_set_handlers(&s->chr, ot_uart_can_receive, - ot_uart_receive, NULL, NULL, - s, NULL, true); + qemu_chr_fe_set_handlers(&s->chr, ot_uart_can_receive, ot_uart_receive, + ot_uart_event_handler, ot_uart_fe_change, s, = NULL, + true); } =20 static void ot_uart_class_init(ObjectClass *klass, const void *data) diff --git a/include/hw/char/ot_uart.h b/include/hw/char/ot_uart.h index a2c5ff8b33..997bf2f367 100644 --- a/include/hw/char/ot_uart.h +++ b/include/hw/char/ot_uart.h @@ -56,10 +56,14 @@ struct OtUARTState { Fifo8 tx_fifo; Fifo8 rx_fifo; uint32_t tx_watermark_level; + bool in_break; + guint watch_tag; =20 Clock *f_clk; =20 CharFrontend chr; + bool oversample_break; /* Should mock break in the oversampled VAL reg= ? */ + bool toggle_break; /* Are incoming breaks temporary or toggled? */ }; =20 struct OtUARTClass { --=20 2.49.1 From nobody Tue May 26 03:33:44 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=git.sr.ht Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777565050655831.696749103025; Thu, 30 Apr 2026 09:04:10 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wITry-0000k9-RD; Thu, 30 Apr 2026 12:04:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrM-0007cJ-KR; Thu, 30 Apr 2026 12:03:30 -0400 Received: from mail-a.sr.ht ([46.23.81.152]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrH-00079h-DN; Thu, 30 Apr 2026 12:03:26 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 9916620C84; Thu, 30 Apr 2026 16:03:13 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=PlhA+f2IZd8IcCVPTtjXpKLc7zQX/PWU3bGKcmfeaoo=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1777564993; v=1; b=pQQdb2k06FYgy9IGqQnCbg7pjLgbVLi9723KZHOIiIpL739wATBMN8yh/oXTwD134baElLu2 3Mj8dpUxnwfz3n2so0fiah333RyYyH7KPynSm8H540kaZKseeG9A4ur80M6IXLiAedy1VpM+bE/ ZZ6PxWlALzbQf0kdlTaOBhmLrskbMl7duLEV1zTFss4YG0xoYH+vsRJE8xHOfxBQGNunW0yncuv rs6bsjz57dFNXGQ0jnWHKiedhyM+cvHUDyggdtxBxfuDCkToFf/LI6h8qoWWld99NzsLe5dSYNC bLRFcNj9HV1DVxDaq3XISm7Ziuu/n/jyxJHy+vmvl4BUQ== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 15:11:43 +0100 Subject: [PATCH qemu v4 8/9] ot_uart: update file headers with new authorship and documentation URL Message-ID: <177756498815.8917.12449488721849651971-8@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177756498815.8917.12449488721849651971-0@git.sr.ht> To: qemu-riscv@nongnu.org, Alistair Francis Cc: Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9?= Lureau , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-devel@nongnu.org, Amit Kumar-Hermosillo , nabihestefan Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=46.23.81.152; envelope-from=outgoing@sr.ht; helo=mail-a.sr.ht X-Spam_score_int: 17 X-Spam_score: 1.7 X-Spam_bar: + X-Spam_report: (1.7 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_96_XX=3.405, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ~lexbaileylowrisc Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1777565054276154100 From: Lex Bailey The documentation has moved, URL updated. This file is now a combination of code from various people/organisations. Took the opportunity while editing this to switch to just using the SPDX ID. Signed-off-by: Lex Bailey --- hw/char/ot_uart.c | 24 ++++++++---------------- include/hw/char/ot_uart.h | 25 ++++++++++--------------- 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index cdf02da62b..d00f7bee66 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -2,27 +2,19 @@ * QEMU OpenTitan UART device * * Copyright (c) 2020 Western Digital + * Copyright (c) 2022-2025 Rivos, Inc. + * Copyright (c) 2025-2026 lowRISC contributors. * * For details check the documentation here: - * https://docs.opentitan.org/hw/ip/uart/doc/ + * https://opentitan.org/book/hw/ip/uart/doc/ * - * Permission is hereby granted, free of charge, to any person obtaining a= copy - * of this software and associated documentation files (the "Software"), t= o deal - * in the Software without restriction, including without limitation the r= ights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Author(s): + * Alistair Francis + * Lo=C3=AFc Lefort + * Lex Bailey * - * The above copyright notice and this permission notice shall be included= in - * all copies or substantial portions of the Software. + * SPDX-License-Identifier: MIT * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN - * THE SOFTWARE. */ =20 #include "qemu/osdep.h" diff --git a/include/hw/char/ot_uart.h b/include/hw/char/ot_uart.h index 997bf2f367..4dc51142f7 100644 --- a/include/hw/char/ot_uart.h +++ b/include/hw/char/ot_uart.h @@ -2,24 +2,19 @@ * QEMU OpenTitan UART device * * Copyright (c) 2020 Western Digital + * Copyright (c) 2022-2025 Rivos, Inc. + * Copyright (c) 2025-2026 lowRISC contributors. * - * Permission is hereby granted, free of charge, to any person obtaining a= copy - * of this software and associated documentation files (the "Software"), t= o deal - * in the Software without restriction, including without limitation the r= ights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * For details check the documentation here: + * https://opentitan.org/book/hw/ip/uart/doc/ * - * The above copyright notice and this permission notice shall be included= in - * all copies or substantial portions of the Software. + * Author(s): + * Alistair Francis + * Lo=C3=AFc Lefort + * Lex Bailey + * + * SPDX-License-Identifier: MIT * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN - * THE SOFTWARE. */ =20 #ifndef HW_OT_UART_H --=20 2.49.1 From nobody Tue May 26 03:33:44 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=git.sr.ht Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777565106732987.7799911103541; Thu, 30 Apr 2026 09:05:06 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wITrs-0000IW-8p; Thu, 30 Apr 2026 12:04:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrN-0007d4-RQ; Thu, 30 Apr 2026 12:03:31 -0400 Received: from mail-a.sr.ht ([46.23.81.152]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wITrJ-0007AP-8L; Thu, 30 Apr 2026 12:03:28 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id AC02320C85; Thu, 30 Apr 2026 16:03:18 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=KLpuStIUCtdEwm7bU4ULI48OBxTw38QY1td1/B8iSN4=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1777564998; v=1; b=qrAmmwkCK2sG/SJSdRG2EkRQd9MCIqv5FQ7dsX6fMzuhbkoIsohSAXpBVlSXdefJXwpCVBFn ViijwaFpcT37Znrp/lU8pT5EVYIBRvyeEQHV3qPnUWpofRftbCCDVK/5btn2oOWxDtOYqK3/qEE FLBxw3QWPY3kRjLK3QG7x/5xiZQd1DixznO9wQpxisEI3UAOri4AiUl5ZX3l8zm7NQTDJu2APFN BvmiQllMX5VbuAd3YBYR/Trw44JumcxXAsQN2Vq028ErLE2uh3/oNNYO9cYLdvueIsX3Tkkp02k u68FL9aADuy0QTSqR3dC5R7net1nZYkk5wFBCN2LdLevA== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 15:03:54 +0100 Subject: [PATCH qemu v4 9/9] ot_uart: add tracing Message-ID: <177756498815.8917.12449488721849651971-9@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177756498815.8917.12449488721849651971-0@git.sr.ht> To: qemu-riscv@nongnu.org, Alistair Francis Cc: Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9?= Lureau , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , qemu-devel@nongnu.org, Amit Kumar-Hermosillo , nabihestefan Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=46.23.81.152; envelope-from=outgoing@sr.ht; helo=mail-a.sr.ht X-Spam_score_int: 17 X-Spam_score: 1.7 X-Spam_bar: + X-Spam_report: (1.7 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_96_XX=3.405, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ~lexbaileylowrisc Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1777565108424158500 From: Lex Bailey Added some tracing to the OpenTitan UART for transparency when debugging Signed-off-by: Lex Bailey --- hw/char/ot_uart.c | 19 +++++++++++++++++++ hw/char/trace-events | 8 ++++++++ hw/riscv/opentitan.c | 1 + include/hw/char/ot_uart.h | 1 + 4 files changed, 29 insertions(+) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index d00f7bee66..910bef00f2 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "hw/char/ot_uart.h" #include "qemu/fifo8.h" +#include "hw/core/cpu.h" #include "hw/core/irq.h" #include "hw/core/qdev-clock.h" #include "hw/core/qdev-properties.h" @@ -28,6 +29,7 @@ #include "migration/vmstate.h" #include "qemu/log.h" #include "qemu/module.h" +#include "trace.h" =20 REG32(INTR_STATE, 0x00) SHARED_FIELD(INTR_TX_WATERMARK, 0, 1) @@ -126,6 +128,9 @@ static void ot_uart_update_irqs(OtUARTState *s) { uint32_t state_masked =3D s->regs[R_INTR_STATE] & s->regs[R_INTR_ENABL= E]; =20 + trace_ot_uart_irqs(s->ot_id, s->regs[R_INTR_STATE], s->regs[R_INTR_ENA= BLE], + state_masked); + for (int index =3D 0; index < OT_UART_IRQ_NUM; index++) { bool level =3D (state_masked & (1U << index)) !=3D 0; qemu_set_irq(s->irqs[index], level); @@ -402,6 +407,10 @@ static uint64_t ot_uart_get_baud(OtUARTState *s) baud *=3D clock_get_hz(s->f_clk); baud >>=3D 20; =20 + if (baud) { + trace_ot_uart_check_baudrate(s->ot_id, baud); + } + return baud; } =20 @@ -503,6 +512,10 @@ static uint64_t ot_uart_read(void *opaque, hwaddr addr= , unsigned int size) return 0; } =20 + uint32_t pc =3D current_cpu->cc->get_pc(current_cpu); + trace_ot_uart_io_read_out(s->ot_id, (uint32_t)addr, REG_NAME(reg), + retvalue, pc); + return retvalue; } =20 @@ -514,6 +527,9 @@ static void ot_uart_write(void *opaque, hwaddr addr, ui= nt64_t val64, =20 hwaddr reg =3D R32_OFF(addr); =20 + uint32_t pc =3D current_cpu->cc->get_pc(current_cpu); + trace_ot_uart_io_write(s->ot_id, (uint32_t)addr, REG_NAME(reg), value,= pc); + switch (reg) { case R_INTR_STATE: /* Write 1 clear */ @@ -665,6 +681,7 @@ static const VMStateDescription vmstate_ot_uart =3D { }; =20 static const Property ot_uart_properties[] =3D { + DEFINE_PROP_STRING("ot-id", OtUARTState, ot_id), DEFINE_PROP_CHR("chardev", OtUARTState, chr), DEFINE_PROP_BOOL("oversample-break", OtUARTState, oversample_break, fa= lse), DEFINE_PROP_BOOL("toggle-break", OtUARTState, toggle_break, false), @@ -716,6 +733,8 @@ static void ot_uart_realize(DeviceState *dev, Error **e= rrp) { OtUARTState *s =3D OT_UART(dev); =20 + g_assert(s->ot_id); + s->fifo_trigger_handle =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, fifo_trigger_update, s); =20 diff --git a/hw/char/trace-events b/hw/char/trace-events index a3fcc77287..17cc9ad2d5 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -141,3 +141,11 @@ stm32f2xx_usart_receive(char *id, uint8_t chr) " %s re= ceiving '%c'" # riscv_htif.c htif_uart_write_to_host(uint8_t device, uint8_t cmd, uint64_t payload) "de= vice: %u cmd: %02u payload: %016" PRIx64 htif_uart_unknown_device_command(uint8_t device, uint8_t cmd, uint64_t pay= load) "device: %u cmd: %02u payload: %016" PRIx64 + +# ot_uart.c +ot_uart_check_baudrate(const char *id, unsigned baud) "%s: %u bps" +ot_uart_connect_input_clock(const char *id, const char * srcname) "%s: %s" +ot_uart_debug(const char *id, const char *msg) "%s: %s" +ot_uart_io_read_out(const char *id, uint32_t addr, const char *regname, ui= nt32_t val, uint32_t pc) "%s: addr=3D0x%02x (%s), val=3D0x%x, pc=3D0x%x" +ot_uart_io_write(const char *id, uint32_t addr, const char *regname, uint3= 2_t val, uint32_t pc) "%s: addr=3D0x%02x (%s), val=3D0x%x, pc=3D0x%x" +ot_uart_irqs(const char *id, uint32_t active, uint32_t mask, uint32_t eff)= "%s: act:0x%08x msk:0x%08x eff:0x%08x" diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 97c33d1b53..163d3ac3d3 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -133,6 +133,7 @@ static void lowrisc_ibex_soc_init(Object *obj) object_initialize_child(obj, "plic", &s->plic, TYPE_SIFIVE_PLIC); =20 object_initialize_child(obj, "uart", &s->uart, TYPE_OT_UART); + object_property_set_str(OBJECT(&s->uart), "ot-id", "uart0", &error_fat= al); =20 object_initialize_child(obj, "timer", &s->timer, TYPE_IBEX_TIMER); =20 diff --git a/include/hw/char/ot_uart.h b/include/hw/char/ot_uart.h index 4dc51142f7..2f538e1f6f 100644 --- a/include/hw/char/ot_uart.h +++ b/include/hw/char/ot_uart.h @@ -54,6 +54,7 @@ struct OtUARTState { bool in_break; guint watch_tag; =20 + char *ot_id; Clock *f_clk; =20 CharFrontend chr; --=20 2.49.1