From nobody Thu May 8 15:26:00 2025 Delivered-To: importer@patchew.org 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=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=pass; 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=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1579802424; cv=none; d=zohomail.com; s=zohoarc; b=UKqcQZHHDLV3X8QAPglXHXLWwn9P5/SayWo8aQMtlq80iNrx3JXQKrT0S1oXPROp2TDj1depdiqGPawgaNQ2xwD6cj4AJlUXagtYj291VrgDX16792jS/xLwfwjuUHbf2IfAwBdQWf19FJ9nr+cutcg/M80Ds8IvvwBxIVfVf+4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1579802424; h=Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=6T47eZ4vWB2mF6kI3SN4Zx+sefAzMAYpYuNqQIJE+Lc=; b=XZw/azHFSAUGDA9tCLhlZx22g37O27csGVJwM/uACiG7G3Rs119YXKBxau7X+MowzCkONWCGTHe76pD7iVop01L9AflVxQykSpJlzZfDsLiXgFua38j+y51Im9rf6oWaE8uItgL9p9YtnXt7rdJlXPVsjalSK4sRUgkNrnXQxAs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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=pass header.from=<peter.maydell@linaro.org> (p=none dis=none) header.from=<peter.maydell@linaro.org> Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org> Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1579802424677400.1480463134427; Thu, 23 Jan 2020 10:00:24 -0800 (PST) Received: from localhost ([::1]:34146 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <qemu-devel-bounces+importer=patchew.org@nongnu.org>) id 1iugmF-0000xQ-CL for importer@patchew.org; Thu, 23 Jan 2020 13:00:23 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:48511) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <peter.maydell@linaro.org>) id 1iueRo-0000W9-J7 for qemu-devel@nongnu.org; Thu, 23 Jan 2020 10:31:14 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from <peter.maydell@linaro.org>) id 1iueRl-0003yc-JC for qemu-devel@nongnu.org; Thu, 23 Jan 2020 10:31:07 -0500 Received: from mail-wm1-x336.google.com ([2a00:1450:4864:20::336]:40749) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from <peter.maydell@linaro.org>) id 1iueRk-0003wu-2H for qemu-devel@nongnu.org; Thu, 23 Jan 2020 10:31:05 -0500 Received: by mail-wm1-x336.google.com with SMTP id t14so2967526wmi.5 for <qemu-devel@nongnu.org>; Thu, 23 Jan 2020 07:31:03 -0800 (PST) Received: from orth.archaic.org.uk (orth.archaic.org.uk. [81.2.115.148]) by smtp.gmail.com with ESMTPSA id s139sm2903592wme.35.2020.01.23.07.31.01 for <qemu-devel@nongnu.org> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jan 2020 07:31:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=6T47eZ4vWB2mF6kI3SN4Zx+sefAzMAYpYuNqQIJE+Lc=; b=Cu3Kzr1Frz+eGQReEp/869Qizegwb0VG+Ej0QwZahzWiOuBuAo/+oyA26YHmT8uAK8 PfTdIZD8oYiswWnnxXkAHnmtsLk8HmvNZxAsITXil8D5SYQaF1tandPpeASpwHQ9N0Bn cUgT19ym3dCxd/VhYIzTwPAFKlvIMX2n8feXm1bsAS3/G10V61dCzaJKBgfiewybnLMq F6Jjlq/ARHhsLsWLbjxdVpkscsr8QOSPWC/Scl3ndfZcQE0lfE8POrcf01gcp9l2PbQJ Cp8/xULJvLSMzLCAbwt54N3YuLCERd/e1RtSiY/qP26k3LfpqSJKyTcA/MtdNeTB6iAq bXow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6T47eZ4vWB2mF6kI3SN4Zx+sefAzMAYpYuNqQIJE+Lc=; b=g74gZfoRTknxoGcVfW4BvBFgb4QGw63HVPq5UDA7TdK1eFjhTUbzMD6hQEgmQznGyq B13bcdn/N16wO76V0yeXoOXPk2QH8Yqz535YoOWFPsoWMoPaiRI6LuuWI1Iivm9HuSvB 7wa+9dXHW4hW6ERzh0y4g3JCGiYNyLPTJCFhs41a+P37Wx/927sj1VSbI48kg8m344OH y2gQ7CLbwb/a1XsscrEAY7HJrbBRmdjZ/cT2l4TGMTIhWuKpGK2XTOSqCr4rMW1/CHm5 ZjnKspZ6/u8IMxODDngTfgeAwUQZdIbG7MvcPshS4OyLTRKdWvZOWPa/Km70BR64BAKs NLtg== X-Gm-Message-State: APjAAAV5UvRL+mG4WpotYCvM/7utFzmJen5IQET6+six1pFid7ulUxOJ ZIkvVX4Gb00v0sdMk3PkNDp73x6rHR1Ucw== X-Google-Smtp-Source: APXvYqxpCLctWgIQ915fh5AZXlPHRtrym5KBXPZE74zgEC/8Uy35l6V8lnk8n/f/d+s9vYQ64I6vRw== X-Received: by 2002:a1c:7d93:: with SMTP id y141mr4706813wmc.111.1579793462794; Thu, 23 Jan 2020 07:31:02 -0800 (PST) From: Peter Maydell <peter.maydell@linaro.org> To: qemu-devel@nongnu.org Subject: [PULL 18/20] hw/char/exynos4210_uart: Implement Rx FIFO level triggers and timeouts Date: Thu, 23 Jan 2020 15:30:39 +0000 Message-Id: <20200123153041.4248-19-peter.maydell@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200123153041.4248-1-peter.maydell@linaro.org> References: <20200123153041.4248-1-peter.maydell@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::336 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: <qemu-devel.nongnu.org> List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>, <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe> List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel> List-Post: <mailto:qemu-devel@nongnu.org> List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help> List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>, <mailto:qemu-devel-request@nongnu.org?subject=subscribe> Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" <qemu-devel-bounces+importer=patchew.org@nongnu.org> X-ZohoMail-DKIM: pass (identity @linaro.org) Content-Type: text/plain; charset="utf-8" From: Guenter Roeck <linux@roeck-us.net> The driver already implements a receive FIFO, but it does not handle receive FIFO trigger levels and timeout. Implement the missing functionality. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Message-id: 20200123052540.6132-7-linux@roeck-us.net Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> --- hw/char/exynos4210_uart.c | 117 ++++++++++++++++++++++++++++++-------- hw/char/trace-events | 3 +- 2 files changed, 94 insertions(+), 26 deletions(-) diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index 6ffbaddfff1..363393cc753 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -24,6 +24,7 @@ #include "migration/vmstate.h" #include "qemu/error-report.h" #include "qemu/module.h" +#include "qemu/timer.h" #include "chardev/char-fe.h" #include "chardev/char-serial.h" =20 @@ -118,6 +119,7 @@ static const Exynos4210UartReg exynos4210_uart_regs[] = =3D { #define ULCON_STOP_BIT_SHIFT 1 =20 /* UART Tx/Rx Status */ +#define UTRSTAT_Rx_TIMEOUT 0x8 #define UTRSTAT_TRANSMITTER_EMPTY 0x4 #define UTRSTAT_Tx_BUFFER_EMPTY 0x2 #define UTRSTAT_Rx_BUFFER_DATA_READY 0x1 @@ -147,6 +149,9 @@ typedef struct Exynos4210UartState { Exynos4210UartFIFO rx; Exynos4210UartFIFO tx; =20 + QEMUTimer *fifo_timeout_timer; + uint64_t wordtime; /* word time in ns */ + CharBackend chr; qemu_irq irq; =20 @@ -209,15 +214,12 @@ static void fifo_reset(Exynos4210UartFIFO *q) q->rp =3D 0; } =20 -static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210Uart= State *s) +static uint32_t exynos4210_uart_FIFO_trigger_level(uint32_t channel, + uint32_t reg) { - uint32_t level =3D 0; - uint32_t reg; + uint32_t level; =20 - reg =3D (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >> - UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT; - - switch (s->channel) { + switch (channel) { case 0: level =3D reg * 32; break; @@ -231,12 +233,34 @@ static uint32_t exynos4210_uart_Tx_FIFO_trigger_level= (const Exynos4210UartState break; default: level =3D 0; - trace_exynos_uart_channel_error(s->channel); + trace_exynos_uart_channel_error(channel); + break; } - return level; } =20 +static uint32_t +exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState *s) +{ + uint32_t reg; + + reg =3D (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >> + UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT; + + return exynos4210_uart_FIFO_trigger_level(s->channel, reg); +} + +static uint32_t +exynos4210_uart_Rx_FIFO_trigger_level(const Exynos4210UartState *s) +{ + uint32_t reg; + + reg =3D ((s->reg[I_(UFCON)] & UFCON_Rx_FIFO_TRIGGER_LEVEL) >> + UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT) + 1; + + return exynos4210_uart_FIFO_trigger_level(s->channel, reg); +} + static void exynos4210_uart_update_irq(Exynos4210UartState *s) { /* @@ -244,13 +268,25 @@ static void exynos4210_uart_update_irq(Exynos4210Uart= State *s) * transmit FIFO is smaller than the trigger level. */ if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) { - uint32_t count =3D (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >> UFSTAT_Tx_FIFO_COUNT_SHIFT; =20 if (count <=3D exynos4210_uart_Tx_FIFO_trigger_level(s)) { s->reg[I_(UINTSP)] |=3D UINTSP_TXD; } + + /* + * Rx interrupt if trigger level is reached or if rx timeout + * interrupt is disabled and there is data in the receive buffer + */ + count =3D fifo_elements_number(&s->rx); + if ((count && !(s->reg[I_(UCON)] & 0x80)) || + count >=3D exynos4210_uart_Rx_FIFO_trigger_level(s)) { + s->reg[I_(UINTSP)] |=3D UINTSP_RXD; + timer_del(s->fifo_timeout_timer); + } + } else if (s->reg[I_(UTRSTAT)] & UTRSTAT_Rx_BUFFER_DATA_READY) { + s->reg[I_(UINTSP)] |=3D UINTSP_RXD; } =20 s->reg[I_(UINTP)] =3D s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)]; @@ -264,6 +300,21 @@ static void exynos4210_uart_update_irq(Exynos4210UartS= tate *s) } } =20 +static void exynos4210_uart_timeout_int(void *opaque) +{ + Exynos4210UartState *s =3D opaque; + + trace_exynos_uart_rx_timeout(s->channel, s->reg[I_(UTRSTAT)], + s->reg[I_(UINTSP)]); + + if ((s->reg[I_(UTRSTAT)] & UTRSTAT_Rx_BUFFER_DATA_READY) || + (s->reg[I_(UCON)] & (1 << 11))) { + s->reg[I_(UINTSP)] |=3D UINTSP_RXD; + s->reg[I_(UTRSTAT)] |=3D UTRSTAT_Rx_TIMEOUT; + exynos4210_uart_update_irq(s); + } +} + static void exynos4210_uart_update_parameters(Exynos4210UartState *s) { int speed, parity, data_bits, stop_bits; @@ -302,10 +353,24 @@ static void exynos4210_uart_update_parameters(Exynos4= 210UartState *s) ssp.data_bits =3D data_bits; ssp.stop_bits =3D stop_bits; =20 + s->wordtime =3D NANOSECONDS_PER_SECOND * (data_bits + stop_bits + 1) /= speed; + qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); =20 trace_exynos_uart_update_params( - s->channel, speed, parity, data_bits, stop_bits); + s->channel, speed, parity, data_bits, stop_bits, s->wordti= me); +} + +static void exynos4210_uart_rx_timeout_set(Exynos4210UartState *s) +{ + if (s->reg[I_(UCON)] & 0x80) { + uint32_t timeout =3D ((s->reg[I_(UCON)] >> 12) & 0x0f) * s->wordti= me; + + timer_mod(s->fifo_timeout_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout); + } else { + timer_del(s->fifo_timeout_timer); + } } =20 static void exynos4210_uart_write(void *opaque, hwaddr offset, @@ -361,6 +426,10 @@ static void exynos4210_uart_write(void *opaque, hwaddr= offset, exynos4210_uart_update_irq(s); break; case UTRSTAT: + if (val & UTRSTAT_Rx_TIMEOUT) { + s->reg[I_(UTRSTAT)] &=3D ~UTRSTAT_Rx_TIMEOUT; + } + break; case UERSTAT: case UFSTAT: case UMSTAT: @@ -382,6 +451,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr = offset, break; } } + static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset, unsigned size) { @@ -461,7 +531,6 @@ static int exynos4210_uart_can_receive(void *opaque) return fifo_empty_elements_number(&s->rx); } =20 - static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int = size) { Exynos4210UartState *s =3D (Exynos4210UartState *)opaque; @@ -469,24 +538,17 @@ static void exynos4210_uart_receive(void *opaque, con= st uint8_t *buf, int size) =20 if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) { if (fifo_empty_elements_number(&s->rx) < size) { - for (i =3D 0; i < fifo_empty_elements_number(&s->rx); i++) { - fifo_store(&s->rx, buf[i]); - } + size =3D fifo_empty_elements_number(&s->rx); s->reg[I_(UINTSP)] |=3D UINTSP_ERROR; - s->reg[I_(UTRSTAT)] |=3D UTRSTAT_Rx_BUFFER_DATA_READY; - } else { - for (i =3D 0; i < size; i++) { - fifo_store(&s->rx, buf[i]); - } - s->reg[I_(UTRSTAT)] |=3D UTRSTAT_Rx_BUFFER_DATA_READY; } - /* XXX: Around here we maybe should check Rx trigger level */ - s->reg[I_(UINTSP)] |=3D UINTSP_RXD; + for (i =3D 0; i < size; i++) { + fifo_store(&s->rx, buf[i]); + } + exynos4210_uart_rx_timeout_set(s); } else { s->reg[I_(URXH)] =3D buf[0]; - s->reg[I_(UINTSP)] |=3D UINTSP_RXD; - s->reg[I_(UTRSTAT)] |=3D UTRSTAT_Rx_BUFFER_DATA_READY; } + s->reg[I_(UTRSTAT)] |=3D UTRSTAT_Rx_BUFFER_DATA_READY; =20 exynos4210_uart_update_irq(s); } @@ -527,6 +589,7 @@ static int exynos4210_uart_post_load(void *opaque, int = version_id) Exynos4210UartState *s =3D (Exynos4210UartState *)opaque; =20 exynos4210_uart_update_parameters(s); + exynos4210_uart_rx_timeout_set(s); =20 return 0; } @@ -588,6 +651,10 @@ static void exynos4210_uart_init(Object *obj) SysBusDevice *dev =3D SYS_BUS_DEVICE(obj); Exynos4210UartState *s =3D EXYNOS4210_UART(dev); =20 + s->fifo_timeout_timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, + exynos4210_uart_timeout_int, s); + s->wordtime =3D NANOSECONDS_PER_SECOND * 10 / 9600; + /* memory mapping */ memory_region_init_io(&s->iomem, obj, &exynos4210_uart_ops, s, "exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE= ); diff --git a/hw/char/trace-events b/hw/char/trace-events index ba28b45b532..cb73fee6a9d 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -81,7 +81,7 @@ nrf51_uart_write(uint64_t addr, uint64_t value, unsigned = int size) "addr 0x%" PR # exynos4210_uart.c exynos_uart_irq_raised(uint32_t channel, uint32_t reg) "UART%d: IRQ raised= : 0x%08"PRIx32 exynos_uart_irq_lowered(uint32_t channel) "UART%d: IRQ lowered" -exynos_uart_update_params(uint32_t channel, int speed, uint8_t parity, int= data, int stop) "UART%d: speed: %d, parity: %c, data bits: %d, stop bits: = %d" +exynos_uart_update_params(uint32_t channel, int speed, uint8_t parity, int= data, int stop, uint64_t wordtime) "UART%d: speed: %d, parity: %c, data bi= ts: %d, stop bits: %d wordtime: %"PRId64"ns" exynos_uart_write(uint32_t channel, uint32_t offset, const char *name, uin= t64_t val) "UART%d: <0x%04x> %s <- 0x%" PRIx64 exynos_uart_read(uint32_t channel, uint32_t offset, const char *name, uint= 64_t val) "UART%d: <0x%04x> %s -> 0x%" PRIx64 exynos_uart_rx_fifo_reset(uint32_t channel) "UART%d: Rx FIFO Reset" @@ -94,3 +94,4 @@ exynos_uart_rx_error(uint32_t channel) "UART%d: Rx error" exynos_uart_wo_read(uint32_t channel, const char *name, uint32_t reg) "UAR= T%d: Trying to read from WO register: %s [0x%04"PRIx32"]" exynos_uart_rxsize(uint32_t channel, uint32_t size) "UART%d: Rx FIFO size:= %d" exynos_uart_channel_error(uint32_t channel) "Wrong UART channel number: %d" +exynos_uart_rx_timeout(uint32_t channel, uint32_t stat, uint32_t intsp) "U= ART%d: Rx timeout stat=3D0x%x intsp=3D0x%x" --=20 2.20.1