From nobody Thu Apr 30 00:42:21 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 1776187375550434.1205911714462; Tue, 14 Apr 2026 10:22:55 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSJ-0005v6-19; Tue, 14 Apr 2026 13:21:43 -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 1wChS9-0005s2-OM; Tue, 14 Apr 2026 13:21:33 -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 1wChS5-0007I3-QJ; Tue, 14 Apr 2026 13:21:33 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id BE7F020A34; Tue, 14 Apr 2026 17:21:25 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=ZA2+dmzCQ47DoV5d7urmI6Q6z1RsJBnCE0wafplIIgI=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1776187285; v=1; b=DbBVw8TSWJPcv8+JcNXXBNl7Ei0O5zYVu2zFHhUaNxVOJ7bHcKF+DCtDbwfrsB49W8uiQQn2 5hxAvm3ok8+GCDp/M3kMxJDCpF1k3JADoKlUzHa+DQiF4w5Q2aPd1nUN3jF9v0FOgxNcfBH41eC K4g+p8354YU4cfTQwZRXXRqhuI8MNPm3Een/npueSm045y2m/ogu5TlZI3xb2TC3s0ycoZTObxR M1sz73q0uDfAS0kOEdYPIUm4zWwJu0sO/8dNzfYDMk95ZuVwm/p1ljj8xHIfGhB4V5J1s/cRSYc 5xTlX2t29/7WmWoGFSq+rjRh1oPF/2kajI6LsKrcznH6g== From: ~lexbaileylowrisc Date: Mon, 30 Mar 2026 15:34:56 +0100 Subject: [PATCH qemu v3 01/10] Rename ibex_uart to ot_uart Message-ID: <177618728515.4917.14466194789826252277-1@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187377689158500 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 --- 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 ad215eced8..9bd0b98f09 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1719,6 +1719,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 =20 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 Thu Apr 30 00:42:21 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 1776187399837485.7189346391415; Tue, 14 Apr 2026 10:23:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSJ-0005v8-9v; Tue, 14 Apr 2026 13:21:43 -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 1wChSB-0005sG-Er; Tue, 14 Apr 2026 13:21:38 -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 1wChS7-0007IE-RH; Tue, 14 Apr 2026 13:21:34 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id EF3CC20A36; Tue, 14 Apr 2026 17:21:25 +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=1776187286; v=1; b=WjQoEXMzIxRhob6xDzTR2EhdBMRyfvz43O14h2fYV/Vy16RY1eTicZngdrDwIRv4rBLi6ctY ZREiNkzog98vqSjPUgsL1bTH32DOcQZKak1VE2tQAT07M4U/2s44g52ix7NGfMONbp/o/UOcvd3 1Y89X/dYWGcStjJlQIprYHe2fvD/8zSxZFKsWPqqAYJf5OSa5gCyUCGJBsPPKLXZfJGwPVDkgM1 bmySpZ4UiS0xcYPVifGnakIkMsrPwBbOIq6n0aTN9yqxLKbcwF7nYYqVkAdNK0pYrJ4XvrrSp5t J1R95oZg7ZK2RMAu2f+NM16y+jmSIUCQHSGq3HNmVXl6A== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 10:43:43 +0100 Subject: [PATCH qemu v3 02/10] ot_uart: move to new reset API Message-ID: <177618728515.4917.14466194789826252277-2@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187401776158500 From: Lex Bailey switch from legacy_reset to new ResettableClass for OpenTitan UART device Signed-off-by: Lex Bailey --- 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 Thu Apr 30 00:42:21 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 1776187407057713.1501473547405; Tue, 14 Apr 2026 10:23:27 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSI-0005v4-C9; Tue, 14 Apr 2026 13:21: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 1wChSC-0005sL-0N; Tue, 14 Apr 2026 13:21:39 -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 1wChS7-0007IL-Rl; Tue, 14 Apr 2026 13:21:35 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 11B0B20A37; Tue, 14 Apr 2026 17:21:26 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=L548TnJxm58Fbtg4+28DfgQ8tMJlCEjAJLwHHUWMcbY=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1776187286; v=1; b=DLIodnxPlLo2NWvcbNrJHXyVRoHl98pJD2CQXm/BBZsi94Y7zsSo39qKwdllVTOWqEu/Vys5 ste6Oep22Pk8N6thbBPA/33xf2fDX3bFUo9fGyhItbGOFIQNDknjlMNNs/pmRq2Zp6kKe0/rttY 2ZkBEiQmmsRqb8/mO1JjgMr+XyEUmHrvd2KEt/k7f85b9j+0yJzL/3ccM4RomnwP7IjzENvGkQ+ 2xo5sMb7PH/yWgt30KDo+EBlbWaue2Gf5YjTPMnsJIsGIBGkRCuPHJOjB5yf2xDDyHGtpUbAtXZ mHmrahxLTxEZgK8dxR6QMisy9E9vLT5dHckEIi3O6fVGg== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 13:44:36 +0100 Subject: [PATCH qemu v3 03/10] ot_uart: update register defs, switch to Fifo8 for tx/rx buffers Message-ID: <177618728515.4917.14466194789826252277-3@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187407894158500 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 | 341 ++++++++++++++++++++++---------------- include/hw/char/ot_uart.h | 18 +- 2 files changed, 204 insertions(+), 155 deletions(-) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index 9478af40f9..08f8f1915e 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,77 @@ 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 CTRL_SUP_MASK \ + (R_CTRL_RX_MASK | R_CTRL_TX_MASK | R_CTRL_SLPBK_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 +146,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; + uint32_t rx_watermark_level; + size_t count =3D MIN(fifo8_num_free(&s->rx_fifo), (size_t)size); =20 - s->uart_rdata =3D *buf; - - 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 +288,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 +308,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 +322,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 +333,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 +358,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 +371,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 +403,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 +463,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 +482,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 +519,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 +542,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 +574,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 +593,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 Thu Apr 30 00:42:21 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 1776187337400148.688998255255; Tue, 14 Apr 2026 10:22:17 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSI-0005v5-Ps; Tue, 14 Apr 2026 13:21: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 1wChSB-0005sF-EV; Tue, 14 Apr 2026 13:21:35 -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 1wChS7-0007IP-Qf; Tue, 14 Apr 2026 13:21:34 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 2CECE20A38; Tue, 14 Apr 2026 17:21:26 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=iRYiq58mQ0ADGgQHXRQDEvU7mCJBel/gXy9Lrg7D/Fg=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1776187286; v=1; b=N/OzlJonLeLDeNLwSoUvNQ+WZUr0x8gTEE4fjS7RNXUig/pg5EHyF2p1t51zGP5RordXz9eU v4DsLLAGFr3iuOow0VFoMR8a7J3wRjgel5e+Jz+da3ZNCvcwePAkqZR7N28zXbafiJbLUkGhUTz Nku4wQxUg2NV7k0V137HzCgL1X8r2UzCgz+4qbWkSBeZQYlhWIXCHbGpoc2e3oY9wiDPGM0TNMg N0LAIFvXGnhWpaEb4znh+qWgByrauQd1tlNan5nDUQt09WCtDa0A+vtF4E4rYdH50pUmkii09nG 69vyq7cV1QOBwRCEphyRmIKrCoAxFAbIU5mn7UbBQ5guQ== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 14:38:47 +0100 Subject: [PATCH qemu v3 04/10] ot_uart: replace individual IRQ fields with array, add missing IRQs Message-ID: <177618728515.4917.14466194789826252277-4@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187340362158500 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 --- 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 08f8f1915e..f621fd3eae 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -105,6 +105,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 @@ -114,31 +115,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 @@ -293,6 +274,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 @@ -569,21 +553,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 Thu Apr 30 00:42:21 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 1776187410171293.4190383141564; Tue, 14 Apr 2026 10:23:30 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSK-0005va-7I; Tue, 14 Apr 2026 13:21:44 -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 1wChSE-0005sV-8t; Tue, 14 Apr 2026 13:21:40 -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 1wChSB-0007Kc-HL; Tue, 14 Apr 2026 13:21:37 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 46FD920A39; Tue, 14 Apr 2026 17:21:26 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=bpoRrUp4pyhuvp+Q79o5fEv94I7SFuni9yO5BtCXukE=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1776187286; v=1; b=V8hSqag8a/UdhnMNak+X3IsUuqiWjVwl2E2Slf4oxj3SRa+FBY1JzRLIiOShtMdCev9Ia3Ku knlEHvL73PKlXlGLcmNsepUkjtpXRUreXp7AbyEr7/1W+bh/Rs31RoHP/t1jNf1eM4BB0gtaVAT QwWN/dwgp40LLQlqPHky4TqshQUmdYYsP6f50kHHOX2LDT+4qxdpxav9LQ52Vep/iq+yv8ki65Z EfPVbZu4gOD2N2Z4FS9Gx01EK/Eoz1uaGaPJbsR7OqARXCcoxlHOz5Y1xnSrYpF4CvOLfGzCB7Z 1nyxYfS4e2NS5QkovMJxX7KI2U4NCMpxud8/4e/UQZReQ== From: ~lexbaileylowrisc Date: Mon, 13 Apr 2026 17:27:19 +0100 Subject: [PATCH qemu v3 05/10] ot_uart: gather similar behaviours togeter in register read and write Message-ID: <177618728515.4917.14466194789826252277-5@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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: -3 X-Spam_score: -0.4 X-Spam_bar: / X-Spam_report: (-0.4 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_24_48=1.34, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187411512154100 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 | 106 +++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index f621fd3eae..2247db7110 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -99,9 +99,6 @@ REG32(TIMEOUT_CTRL, 0x30) R_CTRL_LLPBK_MASK | R_CTRL_PARITY_EN_MASK | R_CTRL_PARITY_ODD_MASK | \ R_CTRL_RXBLVL_MASK | R_CTRL_NCO_MASK) =20 -#define CTRL_SUP_MASK \ - (R_CTRL_RX_MASK | R_CTRL_TX_MASK | R_CTRL_SLPBK_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 @@ -112,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) { @@ -304,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: @@ -336,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 @@ -354,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); @@ -384,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; @@ -401,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 @@ -437,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; @@ -462,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", @@ -473,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 Thu Apr 30 00:42:21 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 1776187411362606.7856903356171; Tue, 14 Apr 2026 10:23:31 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSK-0005wA-LV; Tue, 14 Apr 2026 13:21:44 -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 1wChSE-0005sX-9B; Tue, 14 Apr 2026 13:21:40 -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 1wChSB-0007Kd-HC; Tue, 14 Apr 2026 13:21:37 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 5BF7D20A3A; Tue, 14 Apr 2026 17:21:26 +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=1776187286; v=1; b=G7p6Ue+L+EiCXLw/Z2u42bGGayDw8T0AwqeYzg8a6Aj9FOJVxEWJVHcc5J+V0Ph3GP25TgzQ C+2uGzA4c2I8UcRWz+eu52QNhqoCnnWQih6NnDhT133hK7bMmdRLkA1dqPeJFvltPyCG/S87ORo rnvyEZQVaUEduhPbrL3gr9kkryYdn6ub94yWzM/pjKRHiOPRpCxuIUFDk5Dgw7ktt+cz6jzOWe6 2SZQKX4L97LDZs9E62t1tHJCuS3J/+lA+PPUUepUYGR8lls1W8+iiJU/OcE3lt8P15N+YjFX8l0 GKpULKxRiXPRFdPxVhPNIUn+q1gF1/82yW8iWow1T6K+Q== From: ~lexbaileylowrisc Date: Mon, 13 Apr 2026 19:01:26 +0100 Subject: [PATCH qemu v3 06/10] ot_uart: implement RX fifo and loopback Message-ID: <177618728515.4917.14466194789826252277-6@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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: -5 X-Spam_score: -0.6 X-Spam_bar: / X-Spam_report: (-0.6 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_12_24=1.049, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187411743158500 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 Thu Apr 30 00:42:21 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 1776187424860176.30256870231642; Tue, 14 Apr 2026 10:23:44 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSL-0005xE-SG; Tue, 14 Apr 2026 13:21:45 -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 1wChSE-0005sW-92; Tue, 14 Apr 2026 13:21:40 -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 1wChSB-0007Kn-Hd; Tue, 14 Apr 2026 13:21:37 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 6F99420A3B; Tue, 14 Apr 2026 17:21:26 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=xYiqsFO1CpF379rzC+qC6atuSvv1f1B7+qpGDOgv7VA=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1776187286; v=1; b=Dy7/DM9qouTfnwasfx6eBwfuAUQ3FuVmcT5+X2jUAPbJlTSI3fxcOw1PkhLMHpZagCgr2gX9 jxYeHBip3456eXTdEcgyWb7xRHfGLk/w5pvQy/k3PQvLUxIEDz+6w1EsfpETwPdwDzVvIrc/oAx rrpuIIDZDA/CtZAasiGjsR5iYdR5ovWqlddPY7grlNGW6aZVNFmQL1FZN1/cDuhKCIH1sQF1X7i 9dJB7zZ9wSsymM1mhXgY+QGv5Al8BCs9R8FpDL0hAbzDTpokLUJWK0ZOi5L26HWyRBIbrYf1RGE V1qlgFGHP+Nr+fybeRFacXf6Lpog+rU7O7HIbg+GANA+Q== From: ~lexbaileylowrisc Date: Tue, 14 Apr 2026 13:45:41 +0100 Subject: [PATCH qemu v3 07/10] ot_uart: handle break condition Message-ID: <177618728515.4917.14466194789826252277-7@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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: 0 X-Spam_score: -0.1 X-Spam_bar: / X-Spam_report: (-0.1 / 5.0 requ) BAYES_00=-1.9, DATE_IN_PAST_03_06=1.592, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187427602154100 From: Lex Bailey This 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 --- hw/char/ot_uart.c | 92 +++++++++++++++++++++++++++++++++++++-- include/hw/char/ot_uart.h | 4 ++ 2 files changed, 93 insertions(+), 3 deletions(-) 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 Thu Apr 30 00:42:21 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 177618739753926.386050228855765; Tue, 14 Apr 2026 10:23:17 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSJ-0005v9-MO; Tue, 14 Apr 2026 13:21:43 -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 1wChSE-0005sU-8r; Tue, 14 Apr 2026 13:21:40 -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 1wChSB-0007Km-IP; Tue, 14 Apr 2026 13:21:37 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id 8565520A3C; Tue, 14 Apr 2026 17:21:26 +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=1776187286; v=1; b=bONWszH4bPsmkZVggR2/HXX05iKpe0UN7E0iR4Dq/8dfunv6piZavjwbkYsxRYYLEMDI9W1I v35X92xmujPsSghdaOC50PpOiOY6uSCGuZqbAFnW6/d8l629NzzV1ikLcboOv9XExjNUKoK3or3 dmMnL4kqva+WUgv4iv/f7jriFQW02pBCRmYplne+O3ikgDaMmxtVqaZWpWB/fcIxqguM19LsksD c3xwYjoIPL0m/eVK/j4j8H/Ky4GQktf7zDtHDflGiKjvYI0bxuTJ8qspL5m3nu/GaCq01/12B7M RZa9kvQMWHG6QXHoH8naavRZaWmWkCNQYJNWAP7bwjMvA== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 15:11:43 +0100 Subject: [PATCH qemu v3 08/10] ot_uart: update file headers with new authorship and documentation URL Message-ID: <177618728515.4917.14466194789826252277-8@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187402691154100 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 Thu Apr 30 00:42:21 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 1776187409346659.2306443052742; Tue, 14 Apr 2026 10:23:29 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSL-0005x7-JH; Tue, 14 Apr 2026 13:21:45 -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 1wChSE-0005sY-He; Tue, 14 Apr 2026 13:21:40 -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 1wChSC-0007LG-Ie; Tue, 14 Apr 2026 13:21:38 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id B43F220A3D; Tue, 14 Apr 2026 17:21:26 +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=1776187286; v=1; b=b9MLvEGndhNeWJrtb/X660IC5s7kKSBsc2VnKodQ/wVhadUZe72jwJsPuYr6AWA5pnkcHpq1 LXgEcNv2MTtLdA9jE7zs2RYyY7KBvP3hs4jQ+c01wojqWJ+qzL1s6sH916/cRn8fp2CdTFuWrTw VY14E2+SxDb38VB07pRoz0HU8zZDt7iWZ1d1boclAuB+6w5lbG+wnVwTyVOTNea8CtQFiBBnRxG /kTAc4LTlqYrsOP6eGYTm+JeYPAvhZycYQmnZUPXal09Ye/mpFHrqcNP2vbnn+SGAEGxCQ+o66c ecAqnDZK/rHbRErVDsoW7GmntUbn95PK3CAoKVc0gxuTg== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 15:03:54 +0100 Subject: [PATCH qemu v3 09/10] ot_uart: add tracing Message-ID: <177618728515.4917.14466194789826252277-9@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187409796158500 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 From nobody Thu Apr 30 00:42:21 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 1776187430201583.0006505829853; Tue, 14 Apr 2026 10:23:50 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wChSa-00061S-6t; Tue, 14 Apr 2026 13:22: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 1wChSY-00060m-Ct; Tue, 14 Apr 2026 13:21:58 -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 1wChSW-0007LI-Ks; Tue, 14 Apr 2026 13:21:58 -0400 Received: from git.sr.ht (unknown [46.23.81.155]) by mail-a.sr.ht (Postfix) with ESMTPSA id CD3DE20A3E; Tue, 14 Apr 2026 17:21:26 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=9Kniq8FRhqulospfv3oew3dMKhVcy/wDzgbPCpJAV3k=; c=simple/simple; d=git.sr.ht; h=From:Date:Subject:Reply-to:In-Reply-To:To:Cc; q=dns/txt; s=20240113; t=1776187286; v=1; b=TfH4BReaEuw7JvG36OdP/16JYcvxw9FhXFOyDe9P/t+rqvTapO3kdlScz8/CIwHXgopSHEif 8O5igK7UfTmdvrXW29rnHpvWrAODittNo1wY9FpjpeQWfyxzAqKiP270pujNWTeXN0XRO+acppu TWLokM6I0AX7SdvcG0trDvp57bWZJHL14W7Pd9HyFGxL6ENbu6G8qMwrMrLiQBNt0xKcmtJvOam V8PwbH7dC2AlD+Cj9gKhm2KRxUU8mFERrt9orjNPhEa0ywkyC10EMgjHmy3aKSs9hMFmpYXuy0P qgkKDQKjeRmCUOoXVt1BcO6/7Ov24fpuslGEvRXGDb2SQ== From: ~lexbaileylowrisc Date: Tue, 07 Apr 2026 10:47:17 +0100 Subject: [PATCH qemu v3 10/10] ot_uart: switch from clock driven transmission to reg R/W driven transmission Message-ID: <177618728515.4917.14466194789826252277-10@git.sr.ht> X-Mailer: git.sr.ht In-Reply-To: <177618728515.4917.14466194789826252277-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, qemu-riscv@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, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 1776187431894158500 From: Lex Bailey this commit removes the need for the timer by instead transmitting from the= TX fifo any time it has data in it and it is enabled. This case can only arise from a write to one of the registers in the UART, so the device will still = work fully without the timer. Signed-off-by: Lex Bailey --- hw/char/ot_uart.c | 91 ++++++++++++++++----------------------- hw/char/trace-events | 2 +- include/hw/char/ot_uart.h | 15 ++----- 3 files changed, 40 insertions(+), 68 deletions(-) diff --git a/hw/char/ot_uart.c b/hw/char/ot_uart.c index 910bef00f2..af0cf9ee1a 100644 --- a/hw/char/ot_uart.c +++ b/hw/char/ot_uart.c @@ -20,9 +20,10 @@ #include "qemu/osdep.h" #include "hw/char/ot_uart.h" #include "qemu/fifo8.h" +#include "qapi/error.h" +#include "chardev/char-fe.h" #include "hw/core/cpu.h" #include "hw/core/irq.h" -#include "hw/core/qdev-clock.h" #include "hw/core/qdev-properties.h" #include "hw/core/qdev-properties-system.h" #include "hw/core/registerfields.h" @@ -152,6 +153,18 @@ static bool ot_uart_is_rx_enabled(const OtUARTState *s) return FIELD_EX32(s->regs[R_CTRL], CTRL, RX); } =20 +static void ot_uart_check_baudrate(const OtUARTState *s) +{ + uint32_t nco =3D FIELD_EX32(s->regs[R_CTRL], CTRL, NCO); + + unsigned baudrate =3D (unsigned)(((uint64_t)nco * (uint64_t)s->pclk) >> + (R_CTRL_NCO_LENGTH + 4)); + + if (baudrate) { + trace_ot_uart_check_baudrate(s->ot_id, s->pclk, baudrate); + } +} + static int ot_uart_can_receive(void *opaque) { OtUARTState *s =3D opaque; @@ -284,7 +297,6 @@ static void ot_uart_xmit(OtUARTState *s) =20 static void uart_write_tx_fifo(OtUARTState *s, uint8_t val) { - uint64_t current_time =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (fifo8_is_full(&s->tx_fifo)) { qemu_log_mask(LOG_GUEST_ERROR, "ot_uart: TX FIFO overflow"); return; @@ -305,9 +317,6 @@ static void uart_write_tx_fifo(OtUARTState *s, uint8_t = val) if (ot_uart_is_tx_enabled(s)) { ot_uart_xmit(s); } - - timer_mod(s->fifo_trigger_handle, current_time + - (s->char_tx_time * 4)); } =20 static void ot_uart_reset_enter(Object *obj, ResetType type) @@ -328,11 +337,6 @@ static void ot_uart_reset_enter(Object *obj, ResetType= type) ot_uart_reset_tx_fifo(s); ot_uart_reset_rx_fifo(s); =20 - s->tx_level =3D 0; - s->rx_level =3D 0; - - s->char_tx_time =3D (NANOSECONDS_PER_SECOND / 230400) * 10; - /* * do not reset `s->in_break`, as that tracks whether we are currently * receiving a break condition over UART RX from some device talking @@ -399,19 +403,16 @@ static gboolean ot_uart_watch_cb(void *do_not_use, GI= OCondition cond, return FALSE; } =20 -static uint64_t ot_uart_get_baud(OtUARTState *s) +static void ot_uart_clock_input(void *opaque, int irq, int level) { - uint64_t baud; + OtUARTState *s =3D opaque; =20 - baud =3D ((s->regs[R_CTRL] & R_CTRL_NCO_MASK) >> 16); - baud *=3D clock_get_hz(s->f_clk); - baud >>=3D 20; + g_assert(irq =3D=3D 0); =20 - if (baud) { - trace_ot_uart_check_baudrate(s->ot_id, baud); - } + s->pclk =3D (unsigned)level; =20 - return baud; + /* TODO: disable UART transfer when PCLK is 0 */ + ot_uart_check_baudrate(s); } =20 static uint64_t ot_uart_read(void *opaque, hwaddr addr, unsigned int size) @@ -553,8 +554,6 @@ static void ot_uart_write(void *opaque, hwaddr addr, ui= nt64_t val64, /* This will also set an IRQ once the alert handler is added */ break; case R_CTRL: - s->regs[R_CTRL] =3D value; - if (value & R_CTRL_NF_MASK) { qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_NF is not supported\n", __func__); @@ -577,10 +576,19 @@ static void ot_uart_write(void *opaque, hwaddr addr, = uint64_t val64, qemu_log_mask(LOG_UNIMP, "%s: UART_CTRL_RXBLVL is not supported\n", __fun= c__); } - if (value & R_CTRL_NCO_MASK) { - uint64_t baud =3D ot_uart_get_baud(s); - - s->char_tx_time =3D (NANOSECONDS_PER_SECOND / baud) * 10; + uint32_t prev =3D s->regs[R_CTRL]; + s->regs[R_CTRL] =3D value & CTRL_MASK; + uint32_t change =3D prev ^ s->regs[R_CTRL]; + if (change & R_CTRL_NCO_MASK) { + ot_uart_check_baudrate(s); + } + if ((change & R_CTRL_RX_MASK) && ot_uart_is_rx_enabled(s) && + !ot_uart_is_sys_loopack_enabled(s)) { + qemu_chr_fe_accept_input(&s->chr); + } + if ((change & R_CTRL_TX_MASK) && ot_uart_is_tx_enabled(s)) { + /* try sending pending data from TX FIFO if any */ + ot_uart_xmit(s); } break; case R_WDATA: @@ -628,25 +636,6 @@ static void ot_uart_write(void *opaque, hwaddr addr, u= int64_t val64, } } =20 -static void ot_uart_clk_update(void *opaque, ClockEvent event) -{ - OtUARTState *s =3D opaque; - - /* recompute uart's speed on clock change */ - uint64_t baud =3D ot_uart_get_baud(s); - - s->char_tx_time =3D (NANOSECONDS_PER_SECOND / baud) * 10; -} - -static void fifo_trigger_update(void *opaque) -{ - OtUARTState *s =3D opaque; - - if (s->regs[R_CTRL] & R_CTRL_TX_MASK) { - ot_uart_xmit(s); - } -} - static const MemoryRegionOps ot_uart_ops =3D { .read =3D ot_uart_read, .write =3D ot_uart_write, @@ -665,15 +654,12 @@ 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 2, - .minimum_version_id =3D 2, + .version_id =3D 3, + .minimum_version_id =3D 3, .post_load =3D ot_uart_post_load, .fields =3D (const VMStateField[]) { 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_ARRAY(regs, OtUARTState, REGS_COUNT, 1, vmstate_info_uint3= 2, uint32_t), VMSTATE_END_OF_LIST() @@ -708,10 +694,6 @@ static void ot_uart_init(Object *obj) { OtUARTState *s =3D OT_UART(obj); =20 - s->f_clk =3D qdev_init_clock_in(DEVICE(obj), "f_clock", - ot_uart_clk_update, s, ClockUpdate); - clock_set_hz(s->f_clk, OT_UART_CLOCK); - for (unsigned index =3D 0; index < OT_UART_IRQ_NUM; index++) { sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irqs[index]); } @@ -735,8 +717,7 @@ static void ot_uart_realize(DeviceState *dev, Error **e= rrp) =20 g_assert(s->ot_id); =20 - s->fifo_trigger_handle =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, - fifo_trigger_update, s); + qdev_init_gpio_in_named(DEVICE(s), &ot_uart_clock_input, "clock-in", 1= ); =20 fifo8_create(&s->tx_fifo, OT_UART_TX_FIFO_SIZE); fifo8_create(&s->rx_fifo, OT_UART_RX_FIFO_SIZE); diff --git a/hw/char/trace-events b/hw/char/trace-events index 17cc9ad2d5..c859d8af4e 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -143,7 +143,7 @@ htif_uart_write_to_host(uint8_t device, uint8_t cmd, ui= nt64_t payload) "device: htif_uart_unknown_device_command(uint8_t device, uint8_t cmd, uint64_t pay= load) "device: %u cmd: %02u payload: %016" PRIx64 =20 # ot_uart.c -ot_uart_check_baudrate(const char *id, unsigned baud) "%s: %u bps" +ot_uart_check_baudrate(const char *id, unsigned pclk, unsigned baud) "%s: = @ %u Hz: %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" diff --git a/include/hw/char/ot_uart.h b/include/hw/char/ot_uart.h index 2f538e1f6f..7c2b5f3457 100644 --- a/include/hw/char/ot_uart.h +++ b/include/hw/char/ot_uart.h @@ -23,11 +23,8 @@ #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_CLOCK 50000000 /* 50MHz clock */ - #define TYPE_OT_UART "ot-uart" OBJECT_DECLARE_TYPE(OtUARTState, OtUARTClass, OT_UART) =20 @@ -39,13 +36,6 @@ struct OtUARTState { MemoryRegion mmio; qemu_irq irqs[9]; =20 - uint32_t tx_level; - - uint32_t rx_level; - - QEMUTimer *fifo_trigger_handle; - uint64_t char_tx_time; - uint32_t regs[13]; /* Length must be updated if regs added or removed = */ =20 Fifo8 tx_fifo; @@ -53,10 +43,11 @@ struct OtUARTState { uint32_t tx_watermark_level; bool in_break; guint watch_tag; + unsigned pclk; /* Current input clock */ + const char *clock_src_name; /* IRQ name once connected */ =20 char *ot_id; - Clock *f_clk; - + DeviceState *clock_src; CharFrontend chr; bool oversample_break; /* Should mock break in the oversampled VAL reg= ? */ bool toggle_break; /* Are incoming breaks temporary or toggled? */ --=20 2.49.1