From nobody Sat Oct 4 19:27:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1570468785; cv=none; d=zoho.com; s=zohoarc; b=AJL47mnxImqw9MMWb8kSeXjnM4CE/nHeToGh1+juo0IBoSChcrHFQuWT3q8mWha8rF+XX2U7DzVE5Kf5rHqLkfCi9o44t/DzToqfs0+JbATosRiAmuUHCO93UvlTwniVIyg87N81Uj39zxHbjeU5FXEECesV/OPYR6MrMwfYcEI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1570468785; h=Content-Type:Content-Transfer-Encoding:Cc: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:ARC-Authentication-Results; bh=e1Snfw54qByhFem85dbkNaD4L+dqPgwwgdg4e/O7Ibc=; b=Q9cysU5TTzHdUqJwmNrO6Rnmbc9qW3BDUZgi2HZyvrfxSQYb06VAshxoQs4dPjbA0ec8gaOaZvk6TQ8vamjfTaeH/KI1dTDkQviCGvFvMZxQTWk9ZsHI8xjy8qLGdLNkZrIpx1dNs6MetCooIdQB48PLMjrw55wguNNyMztONwg= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1570468785711130.20765888193853; Mon, 7 Oct 2019 10:19:45 -0700 (PDT) Received: from localhost ([::1]:48048 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iHWfg-00021e-4C for importer@patchew.org; Mon, 07 Oct 2019 13:19:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:36999) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iHWTH-0006k5-Sj for qemu-devel@nongnu.org; Mon, 07 Oct 2019 13:06:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iHWTF-0004ut-Rm for qemu-devel@nongnu.org; Mon, 07 Oct 2019 13:06:55 -0400 Received: from mail-wm1-x342.google.com ([2a00:1450:4864:20::342]:38709) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iHWTF-0004uZ-KI; Mon, 07 Oct 2019 13:06:53 -0400 Received: by mail-wm1-x342.google.com with SMTP id 3so262871wmi.3; Mon, 07 Oct 2019 10:06:53 -0700 (PDT) Received: from x1w.redhat.com (46.red-83-42-66.dynamicip.rima-tde.net. [83.42.66.46]) by smtp.gmail.com with ESMTPSA id x5sm14036603wrt.75.2019.10.07.10.06.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Oct 2019 10:06:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=e1Snfw54qByhFem85dbkNaD4L+dqPgwwgdg4e/O7Ibc=; b=NAXJKlWYcUB/LUYRANjRSqPjRaIn6iB91jdJl5Xn029Mzo9UqXjpN0UKY+bqOPoL17 mDU71Jz2bhdQZMdprLFbZ4HU9AXSxf34KnPkmo9ifbRwN0jBp/wTrg55/RtSOHvXHj4N FTLJ+LEdwecQzWl8L1geTErpY5hi6a5l2GENUOm6mJJYhxGpnNtL5u4RGoSQo7YXo36N E/NJhKcKyZAElzb3Uq1E/KGJhtnLg3OEGIV2O58/TFZDxcJidujtXQtbGlXdOVXGuprB U4+HeBQPO1t7VU+c62OPlJRr/uwKWs4zG+UmjEHTfMTyf3iiHnzX31/XdDHmtLazaRE9 7adg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=e1Snfw54qByhFem85dbkNaD4L+dqPgwwgdg4e/O7Ibc=; b=UD5kklZB/+YIfSq+rBvGatWOhf36YHp52PLR+wwJQq2T00NA5f+00ik/qtE9l41Oh0 rWVno911dSDIrX+M8kzOrZK3HQa+eLECI4HAQdw1P9WSs6X/O4AzXWLs0wNTZ1olUkQf 9Sw/h+tfI08cHnj20vw5ObbBBo/0CUBoBcaJXPa9qGpoMXd1HbFHDdezt0zKPk8Kbkv1 gRiaQoOYMDqdkYBx4i8vZaPnJn7ZsBPZLfmPmdOVxUB2PLaq0HUZNrTX8rjPsWIYKK5v BsX7CJyeZZj/y/SiNih5qcUYGwfP6b+IRXU90myv90nUaNU24jFtwOkIFIzFPPUUQJ8l n9Bw== X-Gm-Message-State: APjAAAWDqq3HbxIj739N2vxEIcFWn1nOYmXIRZr73ZTBvoy29vWXU+4i 11EchpzJWyb5zDiAkovuOJfgknojCmM= X-Google-Smtp-Source: APXvYqyBu9Iat3kMycK9D9B9YrRS+adpZ1OjfNu7j1QNJ5nvfADvKaTt+XP9CyqowNp6Sx15TKPIug== X-Received: by 2002:a1c:1b0b:: with SMTP id b11mr249281wmb.82.1570468012040; Mon, 07 Oct 2019 10:06:52 -0700 (PDT) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Subject: [PATCH 1/3] hw/char: Add the BCM2835 miniuart Date: Mon, 7 Oct 2019 19:06:44 +0200 Message-Id: <20191007170646.14961-2-f4bug@amsat.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191007170646.14961-1-f4bug@amsat.org> References: <20191007170646.14961-1-f4bug@amsat.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset="utf-8" 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::342 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Alistair Francis , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Andrew Baumann , qemu-arm@nongnu.org, Paolo Bonzini , Marc-Andre Lureau , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) The miniuart code is already present in the multi-device hw/char/bcm2835_aux.c. Simply extracting it does not generate patch easy to review. Instead, add it again, rename the function names accordingly, use the "hw/registerfields.h" API. This is roughtly a copy of commit 97398d900caacc. Signed-off-by: Philippe Mathieu-Daud=C3=A9 Acked-by: Alistair Francis --- hw/char/Makefile.objs | 1 + hw/char/bcm2835_miniuart.c | 327 +++++++++++++++++++++++++++++ hw/char/trace-events | 4 + include/hw/char/bcm2835_miniuart.h | 37 ++++ 4 files changed, 369 insertions(+) create mode 100644 hw/char/bcm2835_miniuart.c create mode 100644 include/hw/char/bcm2835_miniuart.h diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs index 02d8a66925..5bd93bde9f 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -22,6 +22,7 @@ obj-$(CONFIG_DIGIC) +=3D digic-uart.o obj-$(CONFIG_STM32F2XX_USART) +=3D stm32f2xx_usart.o obj-$(CONFIG_RASPI) +=3D bcm2835_aux.o =20 +common-obj-$(CONFIG_RASPI) +=3D bcm2835_miniuart.o common-obj-$(CONFIG_CMSDK_APB_UART) +=3D cmsdk-apb-uart.o common-obj-$(CONFIG_ETRAXFS) +=3D etraxfs_ser.o common-obj-$(CONFIG_ISA_DEBUG) +=3D debugcon.o diff --git a/hw/char/bcm2835_miniuart.c b/hw/char/bcm2835_miniuart.c new file mode 100644 index 0000000000..0e99cecce7 --- /dev/null +++ b/hw/char/bcm2835_miniuart.c @@ -0,0 +1,327 @@ +/* + * BCM2835 (Raspberry Pi) mini UART block. + * + * Copyright (c) 2015, Microsoft + * Written by Andrew Baumann + * Based on pl011.c. + * + * This code is licensed under the GPL. + * + * At present only the core UART functions (data path for tx/rx) are + * implemented. The following features/registers are unimplemented: + * - Line/modem control + * - Scratch register + * - Extra control + * - Baudrate + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/char/bcm2835_miniuart.h" +#include "hw/qdev-properties.h" +#include "hw/registerfields.h" +#include "migration/vmstate.h" +#include "trace.h" + +REG32(MU_IO, 0x00) +REG32(MU_IER, 0x04) +REG32(MU_IIR, 0x08) +REG32(MU_LCR, 0x0c) +REG32(MU_MCR, 0x10) +REG32(MU_LSR, 0x14) +REG32(MU_MSR, 0x18) +REG32(MU_SCRATCH, 0x1c) +REG32(MU_CNTL, 0x20) +REG32(MU_STAT, 0x24) +REG32(MU_BAUD, 0x28) + +/* bits in IER/IIR registers */ +#define RX_INT 0x1 +#define TX_INT 0x2 + +static void bcm2835_miniuart_update(BCM2835MiniUartState *s) +{ + /* + * Signal an interrupt if either: + * + * 1. rx interrupt is enabled and we have a non-empty rx fifo, or + * 2. the tx interrupt is enabled (since we instantly drain the tx fif= o) + */ + s->iir =3D 0; + if ((s->ier & RX_INT) && s->read_count !=3D 0) { + s->iir |=3D RX_INT; + } + if (s->ier & TX_INT) { + s->iir |=3D TX_INT; + } + qemu_set_irq(s->irq, s->iir !=3D 0); +} + +static bool is_16650(hwaddr offset) +{ + return offset < A_MU_CNTL; +} + +static uint64_t bcm2835_miniuart_read(void *opaque, hwaddr offset, + unsigned size) +{ + BCM2835MiniUartState *s =3D opaque; + uint32_t c, res =3D 0; + + switch (offset) { + case A_MU_IO: + /* "DLAB bit set means access baudrate register" is NYI */ + c =3D s->read_fifo[s->read_pos]; + if (s->read_count > 0) { + s->read_count--; + if (++s->read_pos =3D=3D BCM2835_MINIUART_RX_FIFO_LEN) { + s->read_pos =3D 0; + } + } + qemu_chr_fe_accept_input(&s->chr); + bcm2835_miniuart_update(s); + res =3D c; + break; + + case A_MU_IER: + /* "DLAB bit set means access baudrate register" is NYI */ + res =3D 0xc0 | s->ier; /* FIFO enables always read 1 */ + break; + + case A_MU_IIR: + res =3D 0xc0; /* FIFO enables */ + /* + * The spec is unclear on what happens when both tx and rx + * interrupts are active, besides that this cannot occur. At + * present, we choose to prioritise the rx interrupt, since + * the tx fifo is always empty. + */ + if (s->read_count !=3D 0) { + res |=3D 0x4; + } else { + res |=3D 0x2; + } + if (s->iir =3D=3D 0) { + res |=3D 0x1; + } + break; + + case A_MU_LCR: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_LCR_REG unsupported\n", __func_= _); + break; + + case A_MU_MCR: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_MCR_REG unsupported\n", __func_= _); + break; + + case A_MU_LSR: + res =3D 0x60; /* tx idle, empty */ + if (s->read_count !=3D 0) { + res |=3D 0x1; + } + break; + + case A_MU_MSR: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_MSR_REG unsupported\n", __func_= _); + break; + + case A_MU_SCRATCH: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_SCRATCH unsupported\n", __func_= _); + break; + + case A_MU_CNTL: + res =3D 0x3; /* tx, rx enabled */ + break; + + case A_MU_STAT: + res =3D 0x30e; /* space in the output buffer, empty tx fifo, idle = tx/rx */ + if (s->read_count > 0) { + res |=3D 0x1; /* data in input buffer */ + assert(s->read_count < BCM2835_MINIUART_RX_FIFO_LEN); + res |=3D ((uint32_t)s->read_count) << 16; /* rx fifo fill leve= l */ + } + break; + + case A_MU_BAUD: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_BAUD_REG unsupported\n", __func= __); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", + __func__, offset); + break; + } + + if (is_16650(offset)) { + trace_serial_ioport_read((offset & 0x1f) >> 2, res); + } else { + trace_bcm2835_miniuart_read(offset, res); + } + + return res; +} + +static void bcm2835_miniuart_write(void *opaque, hwaddr offset, uint64_t v= alue, + unsigned size) +{ + BCM2835MiniUartState *s =3D opaque; + unsigned char ch; + + if (is_16650(offset)) { + trace_serial_ioport_write((offset & 0x1f) >> 2, value); + } else { + trace_bcm2835_miniuart_write(offset, value); + } + + switch (offset) { + case A_MU_IO: + /* "DLAB bit set means access baudrate register" is NYI */ + ch =3D value; + /* + * XXX this blocks entire thread. Rewrite to use + * qemu_chr_fe_write and background I/O callbacks + */ + qemu_chr_fe_write_all(&s->chr, &ch, 1); + break; + + case A_MU_IER: + /* "DLAB bit set means access baudrate register" is NYI */ + s->ier =3D value & (TX_INT | RX_INT); + bcm2835_miniuart_update(s); + break; + + case A_MU_IIR: + if (value & 0x2) { + s->read_count =3D 0; + } + break; + + case A_MU_LCR: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_LCR_REG unsupported\n", __func_= _); + break; + + case A_MU_MCR: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_MCR_REG unsupported\n", __func_= _); + break; + + case A_MU_SCRATCH: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_SCRATCH unsupported\n", __func_= _); + break; + + case A_MU_CNTL: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_CNTL_REG unsupported\n", __func= __); + break; + + case A_MU_BAUD: + qemu_log_mask(LOG_UNIMP, "%s: A_MU_BAUD_REG unsupported\n", __func= __); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", + __func__, offset); + } + + bcm2835_miniuart_update(s); +} + +static int bcm2835_miniuart_can_receive(void *opaque) +{ + BCM2835MiniUartState *s =3D opaque; + + return s->read_count < BCM2835_MINIUART_RX_FIFO_LEN; +} + +static void bcm2835_miniuart_put_fifo(void *opaque, uint8_t value) +{ + BCM2835MiniUartState *s =3D opaque; + int slot; + + slot =3D s->read_pos + s->read_count; + if (slot >=3D BCM2835_MINIUART_RX_FIFO_LEN) { + slot -=3D BCM2835_MINIUART_RX_FIFO_LEN; + } + s->read_fifo[slot] =3D value; + s->read_count++; + if (s->read_count =3D=3D BCM2835_MINIUART_RX_FIFO_LEN) { + /* buffer full */ + } + bcm2835_miniuart_update(s); +} + +static void bcm2835_miniuart_receive(void *opaque, const uint8_t *buf, int= size) +{ + bcm2835_miniuart_put_fifo(opaque, *buf); +} + +static const MemoryRegionOps bcm2835_miniuart_ops =3D { + .read =3D bcm2835_miniuart_read, + .write =3D bcm2835_miniuart_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .valid.min_access_size =3D 4, + .valid.max_access_size =3D 4, +}; + +static const VMStateDescription vmstate_bcm2835_aux =3D { + .name =3D TYPE_BCM2835_MINIUART, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT8_ARRAY(read_fifo, BCM2835MiniUartState, + BCM2835_MINIUART_RX_FIFO_LEN), + VMSTATE_UINT8(read_pos, BCM2835MiniUartState), + VMSTATE_UINT8(read_count, BCM2835MiniUartState), + VMSTATE_UINT8(ier, BCM2835MiniUartState), + VMSTATE_UINT8(iir, BCM2835MiniUartState), + VMSTATE_END_OF_LIST() + } +}; + +static void bcm2835_miniuart_init(Object *obj) +{ + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + BCM2835MiniUartState *s =3D BCM2835_MINIUART(obj); + + memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_miniuart_ops, s, + TYPE_BCM2835_MINIUART, 0x40); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +static void bcm2835_miniuart_realize(DeviceState *dev, Error **errp) +{ + BCM2835MiniUartState *s =3D BCM2835_MINIUART(dev); + + qemu_chr_fe_set_handlers(&s->chr, bcm2835_miniuart_can_receive, + bcm2835_miniuart_receive, NULL, NULL, + s, NULL, true); +} + +static Property bcm2835_miniuart_props[] =3D { + DEFINE_PROP_CHR("chardev", BCM2835MiniUartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void bcm2835_miniuart_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + + dc->realize =3D bcm2835_miniuart_realize; + dc->vmsd =3D &vmstate_bcm2835_aux; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + dc->props =3D bcm2835_miniuart_props; +} + +static const TypeInfo bcm2835_miniuart_info =3D { + .name =3D TYPE_BCM2835_MINIUART, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(BCM2835MiniUartState), + .instance_init =3D bcm2835_miniuart_init, + .class_init =3D bcm2835_miniuart_class_init, +}; + +static void bcm2835_miniuart_register_types(void) +{ + type_register_static(&bcm2835_miniuart_info); +} + +type_init(bcm2835_miniuart_register_types) diff --git a/hw/char/trace-events b/hw/char/trace-events index 2ce7f2f998..f1e6dd9918 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -1,5 +1,9 @@ # See docs/devel/tracing.txt for syntax documentation. =20 +# bcm2835_miniuart.c +bcm2835_miniuart_read(uint64_t addr, uint32_t value) "read addr 0x%"PRIx64= " value 0x%x" +bcm2835_miniuart_write(uint64_t addr, uint32_t value) "read addr 0x%"PRIx6= 4" value 0x%x" + # parallel.c parallel_ioport_read(const char *desc, uint16_t addr, uint8_t value) "read= [%s] addr 0x%02x val 0x%02x" parallel_ioport_write(const char *desc, uint16_t addr, uint8_t value) "wri= te [%s] addr 0x%02x val 0x%02x" diff --git a/include/hw/char/bcm2835_miniuart.h b/include/hw/char/bcm2835_m= iniuart.h new file mode 100644 index 0000000000..54d3b622ed --- /dev/null +++ b/include/hw/char/bcm2835_miniuart.h @@ -0,0 +1,37 @@ +/* + * BCM2835 (Raspberry Pi) mini UART block. + * + * Copyright (c) 2015, Microsoft + * Written by Andrew Baumann + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_CHAR_BCM2835_MINIUART_H +#define HW_CHAR_BCM2835_MINIUART_H + +#include "chardev/char-fe.h" +#include "hw/sysbus.h" +#include "hw/irq.h" + +#define TYPE_BCM2835_MINIUART "bcm2835-miniuart" +#define BCM2835_MINIUART(obj) \ + OBJECT_CHECK(BCM2835MiniUartState, (obj), TYPE_BCM2835_MINIUAR= T) + +#define BCM2835_MINIUART_RX_FIFO_LEN 8 + +typedef struct { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion iomem; + CharBackend chr; + qemu_irq irq; + + uint8_t read_fifo[BCM2835_MINIUART_RX_FIFO_LEN]; + uint8_t read_pos, read_count; + uint8_t ier, iir; +} BCM2835MiniUartState; + +#endif --=20 2.21.0