From: Peter Chubb <peter.chubb@nicta.com.au>
To: Peter Chubb <peter.chubb@nicta.com.au>
Cc: "Peter Maydell" <peter.maydell@linaro.org>,
"Andreas Färber" <andreas.faerber@web.de>,
qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support
Date: Tue, 22 Nov 2011 15:32:55 +1100 [thread overview]
Message-ID: <w462icbwug.wl%peter@chubb.wattle.id.au> (raw)
In-Reply-To: <w47h2sbwwt.wl%peter@chubb.wattle.id.au>
Implement the FreeScale i.MX UART. This uart is used in a variety of
SoCs, including some by Motorola, as well as in the FreeScale i.MX
series.
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Signed-off-by: Adam Clench <adamc@ok-labs.com>
Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
---
hw/imx_serial.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 307 insertions(+)
create mode 100644 hw/imx_serial.c
Index: qemu-working/hw/imx_serial.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu-working/hw/imx_serial.c 2011-11-22 14:47:09.242035743 +1100
@@ -0,0 +1,307 @@
+/*
+ * IMX31 UARTS
+ *
+ * Copyright (c) 2008 OKL
+ * Written by Hans
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * This is a `bare-bones' implementation of the IMX series serial ports.
+ * TODO:
+ * -- implement FIFOs. The real hardware has 32 word transmit
+ * and receive FIFOs
+ * -- implement DMA
+ * -- implement BAUD-rate and modem lines, for when the backend
+ * is a real serial device.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "qemu-char.h"
+
+//#define DEBUG_SERIAL 1
+
+#ifdef DEBUG_SERIAL
+#define DPRINTF(fmt, args...) \
+do { printf("imx_serial: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Print a message at most ten times.
+ */
+#define scream(fmt, args...) \
+ do { \
+ static int printable = 10;\
+ if (printable--) { \
+ fprintf(stderr, fmt, ##args); \
+ } \
+ } while (0)
+
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ int32_t readbuff;
+
+ uint32_t usr1;
+ uint32_t usr2;
+ uint32_t ucr1;
+ uint32_t uts1;
+
+ uint32_t ubrm;
+ uint32_t ubrc;
+
+ qemu_irq irq;
+ CharDriverState *chr;
+} imx_state;
+
+static const VMStateDescription vmstate_imx_serial = {
+ .name = "imx-serial",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(usr1, imx_state),
+ VMSTATE_UINT32(usr2, imx_state),
+ VMSTATE_UINT32(ucr1, imx_state),
+ VMSTATE_UINT32(uts1, imx_state),
+ VMSTATE_UINT32(ubrm, imx_state),
+ VMSTATE_UINT32(ubrc, imx_state),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+
+#define URXD_CHARRDY (1<<15) /* character read is valid */
+
+#define USR1_TRDY (1<<13) /* Xmitter ready */
+#define USR1_RRDY (1<<9) /* receiver ready */
+
+#define USR2_TXFE (1<<14) /* Transmit FIFO empty */
+#define USR2_RDR (1<<0) /* Receive data ready */
+#define USR2_TXDC (1<<3) /* Transmission complete */
+
+#define UCR1_UARTEN (1<<0)
+#define UCR1_RRDYEN (1<<9)
+#define UCR1_TRDYEN (1<<13)
+#define UCR1_TXMPTYEN (1<<6)
+
+#define UTS1_TXEMPTY (1<<6)
+#define UTS1_RXEMPTY (1<<5)
+#define UTS1_TXFULL (1<<4)
+#define UTS1_RXFULL (1<<3)
+
+static void imx_update(imx_state *s)
+{
+ uint32_t flags;
+
+ flags = ((s->usr1 & s->ucr1)) & (USR1_TRDY|USR1_RRDY);
+ if (!(s->ucr1 & UCR1_TXMPTYEN)) {
+ flags &= ~USR1_TRDY;
+ }
+
+ qemu_set_irq(s->irq, !!flags);
+}
+
+static void imx_serial_reset(imx_state *s)
+{
+ s->usr1 = USR1_TRDY;
+ s->usr2 = USR2_TXFE | USR2_TXDC;
+ s->uts1 = UTS1_RXEMPTY;
+ s->ubrm = 0;
+ s->ubrc = 0;
+ s->readbuff = 0;
+}
+
+static uint64_t imx_serial_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ imx_state *s = (imx_state *)opaque;
+ uint32_t c;
+
+ DPRINTF("read(offset=%x)\n", offset >> 2);
+ switch (offset >> 2) {
+ case 0x0: /* URXD */
+ c = s->readbuff;
+ s->usr1 &= ~USR1_RRDY;
+ s->usr2 &= ~USR2_RDR;
+ s->uts1 |= UTS1_RXEMPTY;
+ imx_update(s);
+ qemu_chr_accept_input(s->chr);
+ return c | URXD_CHARRDY;
+
+ case 0x20: /* UCR1 */
+ return s->ucr1;
+
+ case 0x21: /* UCR2 */
+ return 1; /* reset complete */
+
+ case 0x25: /* USR1 */
+ imx_update(s);
+ return s->usr1;
+
+ case 0x26: /* USR2 */
+ imx_update(s);
+ return s->usr2;
+
+
+ case 0x2A: /* BRM Modulator */
+ return s->ubrm;
+
+ case 0x2B: /* Baud Rate Count */
+ return s->ubrc;
+
+ case 0x2d: /* UTS1 */
+ return s->uts1;
+
+
+ case 0x22: /* UCR3 */
+ case 0x23: /* UCR4 */
+ case 0x24: /* UFCR */
+ case 0x29: /* BRM Incremental */
+ return 0x0; /* TODO */
+
+ default:
+ scream("imx_serial_read: bad offset: 0x%x\n", (int)offset);
+ return 0;
+ }
+}
+
+
+static void imx_serial_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ imx_state *s = (imx_state *)opaque;
+ unsigned char ch;
+
+ DPRINTF("write(offset=%x, value = %x)\n", offset >> 2, (unsigned int)value);
+ switch (offset >> 2) {
+ case 0x10: /* UTXD */
+ ch = value;
+ if (s->chr) {
+ qemu_chr_fe_write(s->chr, &ch, 1);
+ }
+ s->usr1 &= ~USR1_TRDY;
+ imx_update(s);
+ s->usr1 |= USR1_TRDY;
+ imx_update(s);
+
+ break;
+
+ case 0x20: /* UCR1 */
+ s->ucr1 = value;
+ DPRINTF("write(ucr1=%x)\n", (unsigned int)value);
+ imx_update(s);
+ break;
+
+ case 0x21: /* UCR2 */
+ if (!(value & 1)) {
+ imx_serial_reset(s);
+ }
+ break;
+
+ case 0x26: /* USR2 */
+ /*
+ * Writing 1 to some bits clears them; all other
+ * values are ignored
+ */
+ value &= (1<<15) | (1<<13) | (1<<12) | (1<<11) | (1<<10)|
+ (1<<8) | (1<<7) | (1<<6) | (1<<4) | (1<<2) | (1<<1);
+ s->usr2 &= ~value;
+ break;
+
+ /* Linux expects to see what it writes here. */
+ /* We don't currently alter the baud rate */
+ case 0x29: /* UBIR */
+ s->ubrc = value;
+ break;
+
+ case 0x2a: /* UBRM */
+ s->ubrm = value;
+ break;
+
+ case 0x2d: /* UTS1 */
+ case 0x22: /* UCR3 */
+ case 0x23: /* UCR4 */
+ case 0x24: /* UFCR */
+ case 0x25: /* USR1 */
+ case 0x2c: /* BIPR1 */
+ /* TODO */
+ break;
+
+ default:
+ scream("imx_serial_write: Bad offset 0x%x\n", (int)offset);
+ }
+}
+
+static int imx_can_receive(void *opaque)
+{
+ imx_state *s = (imx_state *)opaque;
+ return !(s->usr1 & USR1_RRDY);
+}
+
+static void imx_put_data(void *opaque, uint32_t value)
+{
+ imx_state *s = (imx_state *)opaque;
+
+ s->usr1 |= USR1_RRDY;
+ s->usr2 |= USR2_RDR;
+ s->uts1 &= ~UTS1_RXEMPTY;
+ s->readbuff = value;
+ imx_update(s);
+}
+
+static void imx_receive(void *opaque, const uint8_t *buf, int size)
+{
+ imx_put_data(opaque, *buf);
+}
+
+static void imx_event(void *opaque, int event)
+{
+ if (event == CHR_EVENT_BREAK) {
+ imx_put_data(opaque, 0x400);
+ }
+}
+
+
+static const struct MemoryRegionOps imx_serial_ops = {
+ .read = imx_serial_read,
+ .write = imx_serial_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int imx_serial_init(SysBusDevice *dev)
+{
+ imx_state *s = FROM_SYSBUS(imx_state, dev);
+
+ memory_region_init_io(&s->iomem, &imx_serial_ops, s, "imx-serial", 0x1000);
+ sysbus_init_mmio_region(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->irq);
+ s->chr = qdev_init_chardev(&dev->qdev);
+ imx_serial_reset(s);
+ /*
+ * enable the uart on boot, so messages from the linux decompresser
+ * are visible
+ */
+ s->ucr1 = UCR1_UARTEN;
+
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
+ imx_event, s);
+ }
+ vmstate_register(&dev->qdev, -1, &vmstate_imx_serial, s);
+ return 0;
+}
+
+
+static void imx_serial_register_devices(void)
+{
+ DPRINTF("imx_serial_register_devices\n");
+ sysbus_register_dev("imx_serial", sizeof(imx_state),
+ imx_serial_init);
+}
+
+device_init(imx_serial_register_devices)
--
Dr Peter Chubb http://www.gelato.unsw.edu.au peterc AT gelato.unsw.edu.au
http://www.ertos.nicta.com.au ERTOS within National ICT Australia
next prev parent reply other threads:[~2011-11-22 4:33 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-09-29 2:34 [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
2011-09-29 9:58 ` Peter Maydell
2011-09-30 0:20 ` Peter Chubb
2011-09-30 9:04 ` Peter Maydell
2011-09-30 9:23 ` Peter Chubb
2011-09-30 10:07 ` Peter Maydell
[not found] ` <w4y5x6g8gk.wl%peter@chubb.wattle.id.au>
[not found] ` <CAFEAcA8-iByH0xgjkMUo3hvkrLc8NV-Lq4GbHU-d7UoF8GSX-Q@mail.gmail.com>
2011-11-21 21:58 ` [Qemu-devel] [PATCH] imx.31 and KZM board support Peter Chubb
2011-11-21 22:45 ` Andreas Färber
2011-11-21 23:04 ` Peter Chubb
2011-11-21 23:10 ` Peter Maydell
2011-11-21 23:41 ` Peter Maydell
2011-11-21 23:54 ` Peter Chubb
2011-11-22 0:12 ` Peter Maydell
2011-11-22 0:27 ` Peter Chubb
2011-11-22 0:32 ` Peter Maydell
2011-11-22 4:31 ` [Qemu-devel] [PATCH V2 0/4] " Peter Chubb
2011-11-22 4:32 ` Peter Chubb [this message]
2011-11-24 18:53 ` [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support Peter Maydell
2011-11-24 22:18 ` Peter Chubb
2011-11-22 4:33 ` [Qemu-devel] [PATCH V2 2/4] imx.31 and KZM board support: Timer support Peter Chubb
2011-11-24 17:01 ` Peter Maydell
2011-11-24 19:06 ` Peter Maydell
2011-11-22 4:34 ` [Qemu-devel] [PATCH V2 3/4] imx.31 and KZM board support: interrupt controller Peter Chubb
2011-11-24 19:37 ` Peter Maydell
2011-11-22 4:34 ` [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board Peter Chubb
2011-11-24 19:41 ` Peter Maydell
2011-11-24 20:19 ` Andreas Färber
2011-11-24 21:31 ` Peter Maydell
2011-11-24 21:46 ` Andreas Färber
2011-11-24 21:52 ` Peter Maydell
2011-11-23 0:51 ` [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support Peter Chubb
2011-11-24 19:07 ` Andreas Färber
2011-11-26 5:21 ` Peter Chubb
2011-11-26 19:35 ` Peter Maydell
2011-11-22 11:06 ` [Qemu-devel] [PATCH] " Juan Quintela
2011-11-22 11:14 ` Peter Maydell
2011-11-23 14:24 ` Juan Quintela
2011-11-23 0:48 ` Peter Chubb
2011-11-21 22:05 ` [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
2011-11-21 23:01 ` Andreas Färber
2011-11-22 0:20 ` [Qemu-devel] [PATCH] [ARM] fix function names in error messages in arm_timer.c Peter Chubb
2011-11-22 3:20 ` [Qemu-devel] [PATCH] [ARM] Fix hw_error messages from arm_timer.c Peter Chubb
2011-12-05 19:53 ` andrzej zaborowski
2011-11-22 3:25 ` [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
2011-11-24 17:46 ` Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=w462icbwug.wl%peter@chubb.wattle.id.au \
--to=peter.chubb@nicta.com.au \
--cc=andreas.faerber@web.de \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).