From nobody Sat Apr 27 09:28:49 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.zoho.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 148658976912127.229134576148226; Wed, 8 Feb 2017 13:36:09 -0800 (PST) Received: from localhost ([::1]:33330 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cbZuJ-0006cr-L2 for importer@patchew.org; Wed, 08 Feb 2017 16:36:07 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43674) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cbZqC-0003yG-6D for qemu-devel@nongnu.org; Wed, 08 Feb 2017 16:31:54 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cbZq8-0007Ns-V4 for qemu-devel@nongnu.org; Wed, 08 Feb 2017 16:31:52 -0500 Received: from mga11.intel.com ([192.55.52.93]:26147) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cbZq8-0007NY-K7 for qemu-devel@nongnu.org; Wed, 08 Feb 2017 16:31:48 -0500 Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga102.fm.intel.com with ESMTP; 08 Feb 2017 13:31:41 -0800 Received: from juro-precision-t5610.jf.intel.com ([10.7.198.149]) by orsmga003.jf.intel.com with ESMTP; 08 Feb 2017 13:31:40 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.35,348,1484035200"; d="scan'208";a="931682073" From: Juro Bystricky To: qemu-devel@nongnu.org Date: Wed, 8 Feb 2017 13:27:35 -0800 Message-Id: <1486589255-24577-1-git-send-email-juro.bystricky@intel.com> X-Mailer: git-send-email 2.7.4 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 192.55.52.93 Subject: [Qemu-devel] [PATCH] 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: marex@denx.de, jurobystricky@hotmail.com, crwulff@gmail.com, 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" Hardware emulation based on: https://www.altera.com/en_US/pdfs/literature/ug/ug_embedded_ip.pdf Signed-off-by: Juro Bystricky --- default-configs/nios2-softmmu.mak | 1 + hw/char/Makefile.objs | 1 + hw/char/altera_juart.c | 267 ++++++++++++++++++++++++++++++++++= ++++ include/hw/char/altera_juart.h | 44 +++++++ 4 files changed, 313 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 74dc70c..6159846 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 6ea76fe..f0d0e25 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -27,5 +27,6 @@ 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 diff --git a/hw/char/altera_juart.c b/hw/char/altera_juart.c new file mode 100644 index 0000000..886ded5 --- /dev/null +++ b/hw/char/altera_juart.c @@ -0,0 +1,267 @@ +/* + * 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.cn/content/dam/altera-www/global/zh_CN/pdfs/lite= rature/ug/ug_embedded_ip.pdf + */ + +#include "qemu/osdep.h" +#include "hw/char/altera_juart.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" + +/* Data register */ +#define R_DATA 0 +#define DATA_RVALID BIT(15) +#define DATA_RAVAIL 0xFFFF0000 + +/* Control register */ +#define R_CONTROL 1 +#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) + +/* + * 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; + + addr >>=3D 2; + + switch (addr) { + case R_DATA: + r =3D s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & (FIFO_LENGTH = - 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 R_CONTROL: + return s->jcontrol; + } + + return 0; +} + +static void altera_juart_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + AlteraJUARTState *s =3D opaque; + uint32_t value =3D val64; + unsigned char c; + + addr >>=3D 2; + + switch (addr) { + case R_DATA: + c =3D value & 0xFF; + /* + * We do not decrement the write fifo, + * we "tranmsmit" instanteniously, CONTROL_WI always asserted + */ + s->jcontrol |=3D CONTROL_WI; + s->jdata =3D c; + qemu_chr_fe_write(&s->chr, &c, 1); + altera_juart_update_irq(s); + break; + + case 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 void altera_juart_receive(void *opaque, const uint8_t *buf, int siz= e) +{ + int i; + AlteraJUARTState *s =3D opaque; + + if (s->rx_fifo_len >=3D FIFO_LENGTH) { + fprintf(stderr, "WARNING: UART dropped char.\n"); + return; + } + + 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 (FIFO_LENGTH - 1); + s->rx_fifo_len++; + } + s->jcontrol |=3D CONTROL_RI; + altera_juart_update_irq(s); +} + +static int altera_juart_can_receive(void *opaque) +{ + AlteraJUARTState *s =3D opaque; + return FIFO_LENGTH - s->rx_fifo_len; +} + +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 FIFO_LENGTH << 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, 2 * 4); + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_irq(sbd, &s->irq); +} + +void altera_juart_create(int channel, const hwaddr addr, qemu_irq irq) +{ + 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("Can't assign serial port to altera juart%d", cha= nnel); + exit(1); + } + } + + qdev_prop_set_chr(dev, "chardev", chr); + 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_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, NULL, s, NULL, true); +} + +static Property altera_juart_props[] =3D { + DEFINE_PROP_CHR("chardev", AlteraJUARTState, chr), + 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->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 0000000..8a9c892 --- /dev/null +++ b/include/hw/char/altera_juart.h @@ -0,0 +1,44 @@ +/* + * 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 "hw/sysbus.h" +#include "sysemu/char.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 FIFO_LENGTH 64 + +typedef struct AlteraJUARTState { + SysBusDevice busdev; + MemoryRegion mmio; + CharBackend chr; + qemu_irq irq; + + unsigned int rx_fifo_pos; + unsigned int rx_fifo_len; + uint32_t jdata; + uint32_t jcontrol; + uint8_t rx_fifo[FIFO_LENGTH]; +} AlteraJUARTState; + +void altera_juart_create(int channel, const hwaddr addr, qemu_irq irq); + +#endif /* ALTERA_JUART_H */ --=20 2.7.4