From nobody Wed May 8 14:46:21 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1504280406810577.3535668959576; Fri, 1 Sep 2017 08:40:06 -0700 (PDT) Received: from localhost ([::1]:46301 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dno3B-0007vD-GJ for importer@patchew.org; Fri, 01 Sep 2017 11:40:05 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50572) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dnnyy-0004Lz-UC for qemu-devel@nongnu.org; Fri, 01 Sep 2017 11:35:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dnnyv-00008Q-Go for qemu-devel@nongnu.org; Fri, 01 Sep 2017 11:35:44 -0400 Received: from mail.zhinst.com ([212.126.164.98]:40554) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dnnyu-000051-Vl for qemu-devel@nongnu.org; Fri, 01 Sep 2017 11:35:41 -0400 Received: from ziws08.zhinst.com ([10.42.0.7]) by mail.zhinst.com (Kerio Connect 9.2.4) with ESMTP; Fri, 1 Sep 2017 17:35:35 +0200 From: Tobias Klauser To: qemu-devel@nongnu.org Date: Fri, 1 Sep 2017 17:35:35 +0200 Message-Id: <20170901153535.30680-1-tklauser@distanz.ch> X-Mailer: git-send-email 2.13.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.126.164.98 Subject: [Qemu-devel] [PATCH v7] nios2: Add Altera JTAG UART emulation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Marek Vasut , Paolo Bonzini , Juro Bystricky Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Juro Bystricky Add the Altera JTAG UART model. Hardware emulation based on: https://www.altera.com/en_US/pdfs/literature/ug/ug_embedded_ip.pdf (Please see "Register Map" on page 65) Signed-off-by: Juro Bystricky Acked-by: Marek Vasut Tested-by: Tobias Klauser [tk: updated to compile with latest qemu master] Signed-off-by: Tobias Klauser --- v7: - resending with changes needed to compile with latest qemu master default-configs/nios2-softmmu.mak | 1 + hw/char/Makefile.objs | 1 + hw/char/altera_juart.c | 286 ++++++++++++++++++++++++++++++++++= ++++ include/hw/char/altera_juart.h | 46 ++++++ 4 files changed, 334 insertions(+) create mode 100644 hw/char/altera_juart.c create mode 100644 include/hw/char/altera_juart.h diff --git a/default-configs/nios2-softmmu.mak b/default-configs/nios2-soft= mmu.mak index 74dc70caaef0..61598465c11d 100644 --- a/default-configs/nios2-softmmu.mak +++ b/default-configs/nios2-softmmu.mak @@ -4,3 +4,4 @@ CONFIG_NIOS2=3Dy CONFIG_SERIAL=3Dy CONFIG_PTIMER=3Dy CONFIG_ALTERA_TIMER=3Dy +CONFIG_ALTERA_JUART=3Dy diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs index 1bcd37e98d9c..adb0e3ebc36a 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -28,6 +28,7 @@ common-obj-$(CONFIG_LM32) +=3D lm32_juart.o common-obj-$(CONFIG_LM32) +=3D lm32_uart.o common-obj-$(CONFIG_MILKYMIST) +=3D milkymist-uart.o common-obj-$(CONFIG_SCLPCONSOLE) +=3D sclpconsole.o sclpconsole-lm.o +common-obj-$(CONFIG_ALTERA_JUART) +=3D altera_juart.o =20 obj-$(CONFIG_VIRTIO) +=3D virtio-serial-bus.o obj-$(CONFIG_TERMINAL3270) +=3D terminal3270.o diff --git a/hw/char/altera_juart.c b/hw/char/altera_juart.c new file mode 100644 index 000000000000..66adbd261f4c --- /dev/null +++ b/hw/char/altera_juart.c @@ -0,0 +1,286 @@ +/* + * QEMU model of the Altera JTAG UART. + * + * Copyright (c) 2016-2017 Intel Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * The Altera JTAG UART hardware registers are described in: + * https://www.altera.com/en_US/pdfs/literature/ug/ug_embedded_ip.pdf + * (In particular "Register Map" on page 65) + */ + +#include "qemu/osdep.h" +#include "chardev/char-serial.h" +#include "hw/char/altera_juart.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" + +/* Data register */ +#define OFFSET_R_DATA 0 +#define DATA_RVALID BIT(15) +#define DATA_RAVAIL 0xFFFF0000 + +/* Control register */ +#define OFFSET_R_CONTROL 4 +#define CONTROL_RE BIT(0) +#define CONTROL_WE BIT(1) +#define CONTROL_RI BIT(8) +#define CONTROL_WI BIT(9) +#define CONTROL_AC BIT(10) +#define CONTROL_WSPACE 0xFFFF0000 + +#define CONTROL_WMASK (CONTROL_RE | CONTROL_WE | CONTROL_AC) + +#define TYPE_ALTERA_JUART "altera-juart" +#define ALTERA_JUART(obj) \ + OBJECT_CHECK(AlteraJUARTState, (obj), TYPE_ALTERA_JUART) + +/* Two registers 4 bytes wide each */ +#define ALTERA_JTAG_UART_REGS_MEM_SIZE (2 * 4) + +/* + * The JTAG UART core generates an interrupt when either of the individual + * interrupt conditions is pending and enabled. + */ +static void altera_juart_update_irq(AlteraJUARTState *s) +{ + unsigned int irq; + + irq =3D ((s->jcontrol & CONTROL_WE) && (s->jcontrol & CONTROL_WI)) || + ((s->jcontrol & CONTROL_RE) && (s->jcontrol & CONTROL_RI)); + + qemu_set_irq(s->irq, irq); +} + +static uint64_t altera_juart_read(void *opaque, hwaddr addr, unsigned int = size) +{ + AlteraJUARTState *s =3D opaque; + uint32_t r; + + switch (addr) { + case OFFSET_R_DATA: + r =3D s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & (s->rx_fifo_s= ize - 1)]; + if (s->rx_fifo_len) { + s->rx_fifo_len--; + qemu_chr_fe_accept_input(&s->chr); + s->jdata =3D r | DATA_RVALID | (s->rx_fifo_len << 16); + s->jcontrol |=3D CONTROL_RI; + } else { + s->jdata =3D 0; + s->jcontrol &=3D ~CONTROL_RI; + } + + altera_juart_update_irq(s); + return s->jdata; + + case OFFSET_R_CONTROL: + return s->jcontrol; + } + + return 0; +} + +static void altera_juart_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + AlteraJUARTState *s =3D opaque; + unsigned char c; + + switch (addr) { + case OFFSET_R_DATA: + c =3D value & 0xFF; + s->jcontrol |=3D CONTROL_WI; + s->jdata =3D c; + qemu_chr_fe_write(&s->chr, &c, 1); + altera_juart_update_irq(s); + break; + + case OFFSET_R_CONTROL: + /* Only RE and WE are writable */ + value &=3D CONTROL_WMASK; + s->jcontrol &=3D ~CONTROL_WMASK; + s->jcontrol |=3D value; + + /* Writing 1 to AC clears it to 0 */ + if (value & CONTROL_AC) { + s->jcontrol &=3D ~CONTROL_AC; + } + altera_juart_update_irq(s); + break; + } +} + +static int altera_juart_can_receive(void *opaque) +{ + AlteraJUARTState *s =3D opaque; + return s->rx_fifo_size - s->rx_fifo_len; +} + +static void altera_juart_receive(void *opaque, const uint8_t *buf, int siz= e) +{ + int i; + AlteraJUARTState *s =3D opaque; + + for (i =3D 0; i < size; i++) { + s->rx_fifo[s->rx_fifo_pos] =3D buf[i]; + s->rx_fifo_pos++; + s->rx_fifo_pos &=3D (s->rx_fifo_size - 1); + s->rx_fifo_len++; + } + s->jcontrol |=3D CONTROL_RI; + altera_juart_update_irq(s); +} + +static void altera_juart_event(void *opaque, int event) +{ +} + +static void altera_juart_reset(DeviceState *d) +{ + AlteraJUARTState *s =3D ALTERA_JUART(d); + + s->jdata =3D 0; + + /* The number of spaces available in the write FIFO */ + s->jcontrol =3D s->rx_fifo_size << 16; + s->rx_fifo_pos =3D 0; + s->rx_fifo_len =3D 0; +} + +static const MemoryRegionOps juart_ops =3D { + .read =3D altera_juart_read, + .write =3D altera_juart_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 4 + } +}; + +static void altera_juart_init(Object *obj) +{ + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + AlteraJUARTState *s =3D ALTERA_JUART(obj); + + memory_region_init_io(&s->mmio, OBJECT(s), &juart_ops, s, + TYPE_ALTERA_JUART, ALTERA_JTAG_UART_REGS_MEM_SIZE); + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_irq(sbd, &s->irq); +} + +void altera_juart_create(int channel, const hwaddr addr, qemu_irq irq, uin= t32_t fifo_sz) +{ + DeviceState *dev; + SysBusDevice *bus; + Chardev *chr; + const char chr_name[] =3D "juart"; + char label[ARRAY_SIZE(chr_name) + 1]; + + dev =3D qdev_create(NULL, TYPE_ALTERA_JUART); + + if (channel >=3D MAX_SERIAL_PORTS) { + error_report("Only %d serial ports are supported by QEMU", + MAX_SERIAL_PORTS); + exit(1); + } + + chr =3D serial_hds[channel]; + if (!chr) { + snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel); + chr =3D qemu_chr_new(label, "null"); + if (!chr) { + error_report("Failed to assign serial port to altera %s", labe= l); + exit(1); + } + } + qdev_prop_set_chr(dev, "chardev", chr); + + /* + * FIFO size can be set from 8 to 32,768 bytes. + * Only powers of two are allowed. + */ + if (fifo_sz < 8 || fifo_sz > 32768 || (fifo_sz & ~(1 << ctz32(fifo_sz)= ))) { + error_report("juart%d: Invalid FIFO size. [%u]", channel, fifo_sz); + exit(1); + } + + qdev_prop_set_uint32(dev, "fifo-size", fifo_sz); + bus =3D SYS_BUS_DEVICE(dev); + qdev_init_nofail(dev); + + if (addr !=3D (hwaddr)-1) { + sysbus_mmio_map(bus, 0, addr); + } + + sysbus_connect_irq(bus, 0, irq); +} + +static const VMStateDescription vmstate_altera_juart =3D { + .name =3D "altera-juart" , + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32(jdata, AlteraJUARTState), + VMSTATE_UINT32(jcontrol, AlteraJUARTState), + VMSTATE_VBUFFER_UINT32(rx_fifo, AlteraJUARTState, 1, NULL, rx_fifo= _size), + VMSTATE_END_OF_LIST() + } +}; + +static void altera_juart_realize(DeviceState *dev, Error **errp) +{ + AlteraJUARTState *s =3D ALTERA_JUART(dev); + qemu_chr_fe_set_handlers(&s->chr, + altera_juart_can_receive, + altera_juart_receive, + altera_juart_event, + NULL, s, NULL, true); + s->rx_fifo =3D g_malloc(s->rx_fifo_size); +} + +static void altera_juart_unrealize(DeviceState *dev, Error **errp) +{ + AlteraJUARTState *s =3D ALTERA_JUART(dev); + g_free(s->rx_fifo); +} + +static Property altera_juart_props[] =3D { + DEFINE_PROP_CHR("chardev", AlteraJUARTState, chr), + DEFINE_PROP_UINT32("fifo-size", AlteraJUARTState, rx_fifo_size, + ALTERA_JUART_DEFAULT_FIFO_SIZE), + DEFINE_PROP_END_OF_LIST(), +}; + +static void altera_juart_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + + dc->realize =3D altera_juart_realize; + dc->unrealize =3D altera_juart_unrealize; + dc->props =3D altera_juart_props; + dc->vmsd =3D &vmstate_altera_juart; + dc->reset =3D altera_juart_reset; + dc->desc =3D "Altera JTAG UART"; +} + +static const TypeInfo altera_juart_info =3D { + .name =3D TYPE_ALTERA_JUART, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(AlteraJUARTState), + .instance_init =3D altera_juart_init, + .class_init =3D altera_juart_class_init, +}; + +static void altera_juart_register(void) +{ + type_register_static(&altera_juart_info); +} + +type_init(altera_juart_register) diff --git a/include/hw/char/altera_juart.h b/include/hw/char/altera_juart.h new file mode 100644 index 000000000000..fcf7a602523d --- /dev/null +++ b/include/hw/char/altera_juart.h @@ -0,0 +1,46 @@ +/* + * Altera JTAG UART emulation + * + * Copyright (c) 2016-2017 Intel Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef ALTERA_JUART_H +#define ALTERA_JUART_H + +#include "chardev/char-fe.h" +#include "hw/sysbus.h" + +/* + * The read and write FIFO depths can be set from 8 to 32,768 bytes. + * Only powers of two are allowed. A depth of 64 is generally optimal for + * performance, and larger values are rarely necessary. + */ + +#define ALTERA_JUART_DEFAULT_FIFO_SIZE 64 + +typedef struct AlteraJUARTState { + SysBusDevice busdev; + MemoryRegion mmio; + CharBackend chr; + qemu_irq irq; + + unsigned int rx_fifo_size; + unsigned int rx_fifo_pos; + unsigned int rx_fifo_len; + uint32_t jdata; + uint32_t jcontrol; + uint8_t *rx_fifo; +} AlteraJUARTState; + +void altera_juart_create(int channel, const hwaddr addr, qemu_irq irq, + uint32_t fifo_size); + +#endif /* ALTERA_JUART_H */ --=20 2.13.0