All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Chubb <peter.chubb@nicta.com.au>
To: Peter Maydell <peter.maydell@linaro.org>
Cc: "Hans Jang" <hsjang@ok-labs.com>,
	"Adam Clench" <adamc@ok-labs.com>,
	"Peter Chubb" <peter.chubb@nicta.com.au>,
	qemu-devel@nongnu.org, "Andreas Färber" <afaerber@suse.de>
Subject: [Qemu-devel] [PATCH V3 1/4] 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.
Date: Wed, 30 Nov 2011 14:36:29 +1100	[thread overview]
Message-ID: <20111130034234.403045191@nicta.com.au> (raw)
In-Reply-To: 20111130033628.097950901@nicta.com.au

[-- Attachment #1: imx-serial.patch --]
[-- Type: text/plain, Size: 9834 bytes --]

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>
---
 Makefile.target |    1 
 hw/imx_serial.c |  320 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 321 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-30 13:38:24.434778115 +1100
@@ -0,0 +1,320 @@
+/*
+ * IMX31 UARTS
+ *
+ * Copyright (c) 2008 OKL
+ * Originally Written by Hans Jiang
+ * Copyright (c) 2011 NICTA Pty Ltd.
+ *
+ * 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; we currently use a 1-char buffer
+ *  -- 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
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+#  define IPRINTF(fmt, args...) \
+    do  { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0)
+#else
+#  define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+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_INT32(readbuff, imx_state),
+        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_TXDC       (1<<3)    /* Transmission complete */
+#define USR2_RDR        (1<<0)    /* Receive data ready */
+
+#define UCR1_TRDYEN     (1<<13)
+#define UCR1_RRDYEN     (1<<9)
+#define UCR1_TXMPTYEN   (1<<6)
+#define UCR1_UARTEN     (1<<0)
+
+#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;
+    }
+
+    if (flags) {
+        DPRINTF("imx_serial: raising interrupt\n");
+    }
+
+    qemu_set_irq(s->irq, !!flags);
+}
+
+static void imx_serial_reset(DeviceState *dev)
+{
+    imx_state *s = container_of(dev, imx_state, busdev.qdev);
+
+    s->usr1 = USR1_TRDY;
+    s->usr2 = USR2_TXFE | USR2_TXDC;
+    s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY;
+    s->ubrm = 0;
+    s->ubrc = 0;
+    s->readbuff = 0;
+
+    imx_update(s);
+}
+
+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;
+        if (!(s->uts1 & UTS1_RXEMPTY)) {
+            /* Character is valid */
+            c |= URXD_CHARRDY;
+            s->usr1 &= ~USR1_RRDY;
+            s->usr2 &= ~USR2_RDR;
+            s->uts1 |= UTS1_RXEMPTY;
+            imx_update(s);
+            qemu_chr_accept_input(s->chr);
+        }
+        return c;
+
+    case 0x20: /* UCR1 */
+        return s->ucr1;
+
+    case 0x21: /* UCR2 */
+        return 1; /* reset complete */
+
+    case 0x25: /* USR1 */
+        return s->usr1;
+
+    case 0x26: /* USR2 */
+        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:
+        IPRINTF("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->busdev.qdev);
+        }
+        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:
+        IPRINTF("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);
+    /*
+     * enable the uart on boot, so messages from the linux decompresser
+     * are visible.  On real hardware this is done by the boot rom
+     * before anything else is loaded.
+     */
+    s->ucr1 = UCR1_UARTEN;
+
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
+                              imx_event, s);
+    }
+    return 0;
+}
+
+static SysBusDeviceInfo imx_serial_info = {
+    .qdev.name = "imx_serial",
+    .qdev.desc = "i.MX series UART",
+    .qdev.size = sizeof (imx_state),
+    .qdev.vmsd = &vmstate_imx_serial,
+    .qdev.reset = imx_serial_reset,
+    .init = imx_serial_init,
+};
+
+static void imx_serial_register_devices(void)
+{
+    sysbus_register_withprop(&imx_serial_info);
+}
+
+device_init(imx_serial_register_devices)
Index: qemu-working/Makefile.target
===================================================================
--- qemu-working.orig/Makefile.target	2011-11-30 13:38:19.886754597 +1100
+++ qemu-working/Makefile.target	2011-11-30 13:38:24.434778115 +1100
@@ -361,20 +361,21 @@ obj-arm-y += mst_fpga.o mainstone.o
 obj-arm-y += z2.o
 obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
 obj-arm-y += framebuffer.o
 obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
 obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
 obj-arm-y += syborg_virtio.o
 obj-arm-y += vexpress.o
 obj-arm-y += strongarm.o
 obj-arm-y += collie.o
 obj-arm-y += pl041.o lm4549.o
+obj-arm-y += imx_serial.o
 
 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
 obj-sh4-y += ide/mmio.o
 
 obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
 obj-m68k-y += m68k-semi.o dummy_m68k.o
 
 obj-s390x-y = s390-virtio-bus.o s390-virtio.o
 

  reply	other threads:[~2011-11-30  3:43 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-30  3:36 [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Peter Chubb
2011-11-30  3:36 ` Peter Chubb [this message]
2011-12-01 16:55   ` [Qemu-devel] [PATCH V3 1/4] 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 Peter Maydell
2011-12-01 16:56     ` Peter Maydell
2011-12-01 19:26       ` Peter Chubb
2011-12-06  1:03     ` Peter Chubb
2011-11-30  3:36 ` [Qemu-devel] [PATCH V3 2/4] Implement the timers on the FreeScale i.MX31 SoC. This is not a complete implementation, but gives enough for Linux to boot and run Peter Chubb
2011-12-01 17:11   ` Peter Maydell
2011-11-30  3:36 ` [Qemu-devel] [PATCH V3 3/4] Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least to the extent it is used by Linux 3.0.x Peter Chubb
2011-12-01 17:26   ` Peter Maydell
2011-12-06  1:05     ` Peter Chubb
2011-11-30  3:36 ` [Qemu-devel] [PATCH V3 4/4] Board support for Kyoto Micros KZM-ARM11-01, an evaluation board built around the FreeScale i.MX31 Peter Chubb
2011-11-30  6:15 ` [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Stefan Weil
2011-11-30  6:20   ` Peter Chubb

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=20111130034234.403045191@nicta.com.au \
    --to=peter.chubb@nicta.com.au \
    --cc=adamc@ok-labs.com \
    --cc=afaerber@suse.de \
    --cc=hsjang@ok-labs.com \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.