qemu/hw/char/mcf_uart.c
<<
>>
Prefs
   1/*
   2 * ColdFire UART emulation.
   3 *
   4 * Copyright (c) 2007 CodeSourcery.
   5 *
   6 * This code is licensed under the GPL
   7 */
   8
   9#include "qemu/osdep.h"
  10#include "hw/irq.h"
  11#include "hw/sysbus.h"
  12#include "qemu/module.h"
  13#include "qapi/error.h"
  14#include "hw/m68k/mcf.h"
  15#include "hw/qdev-properties.h"
  16#include "hw/qdev-properties-system.h"
  17#include "chardev/char-fe.h"
  18#include "qom/object.h"
  19
  20struct mcf_uart_state {
  21    SysBusDevice parent_obj;
  22
  23    MemoryRegion iomem;
  24    uint8_t mr[2];
  25    uint8_t sr;
  26    uint8_t isr;
  27    uint8_t imr;
  28    uint8_t bg1;
  29    uint8_t bg2;
  30    uint8_t fifo[4];
  31    uint8_t tb;
  32    int current_mr;
  33    int fifo_len;
  34    int tx_enabled;
  35    int rx_enabled;
  36    qemu_irq irq;
  37    CharBackend chr;
  38};
  39
  40#define TYPE_MCF_UART "mcf-uart"
  41OBJECT_DECLARE_SIMPLE_TYPE(mcf_uart_state, MCF_UART)
  42
  43/* UART Status Register bits.  */
  44#define MCF_UART_RxRDY  0x01
  45#define MCF_UART_FFULL  0x02
  46#define MCF_UART_TxRDY  0x04
  47#define MCF_UART_TxEMP  0x08
  48#define MCF_UART_OE     0x10
  49#define MCF_UART_PE     0x20
  50#define MCF_UART_FE     0x40
  51#define MCF_UART_RB     0x80
  52
  53/* Interrupt flags.  */
  54#define MCF_UART_TxINT  0x01
  55#define MCF_UART_RxINT  0x02
  56#define MCF_UART_DBINT  0x04
  57#define MCF_UART_COSINT 0x80
  58
  59/* UMR1 flags.  */
  60#define MCF_UART_BC0    0x01
  61#define MCF_UART_BC1    0x02
  62#define MCF_UART_PT     0x04
  63#define MCF_UART_PM0    0x08
  64#define MCF_UART_PM1    0x10
  65#define MCF_UART_ERR    0x20
  66#define MCF_UART_RxIRQ  0x40
  67#define MCF_UART_RxRTS  0x80
  68
  69static void mcf_uart_update(mcf_uart_state *s)
  70{
  71    s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
  72    if (s->sr & MCF_UART_TxRDY)
  73        s->isr |= MCF_UART_TxINT;
  74    if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
  75                  ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
  76        s->isr |= MCF_UART_RxINT;
  77
  78    qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
  79}
  80
  81uint64_t mcf_uart_read(void *opaque, hwaddr addr,
  82                       unsigned size)
  83{
  84    mcf_uart_state *s = (mcf_uart_state *)opaque;
  85    switch (addr & 0x3f) {
  86    case 0x00:
  87        return s->mr[s->current_mr];
  88    case 0x04:
  89        return s->sr;
  90    case 0x0c:
  91        {
  92            uint8_t val;
  93            int i;
  94
  95            if (s->fifo_len == 0)
  96                return 0;
  97
  98            val = s->fifo[0];
  99            s->fifo_len--;
 100            for (i = 0; i < s->fifo_len; i++)
 101                s->fifo[i] = s->fifo[i + 1];
 102            s->sr &= ~MCF_UART_FFULL;
 103            if (s->fifo_len == 0)
 104                s->sr &= ~MCF_UART_RxRDY;
 105            mcf_uart_update(s);
 106            qemu_chr_fe_accept_input(&s->chr);
 107            return val;
 108        }
 109    case 0x10:
 110        /* TODO: Implement IPCR.  */
 111        return 0;
 112    case 0x14:
 113        return s->isr;
 114    case 0x18:
 115        return s->bg1;
 116    case 0x1c:
 117        return s->bg2;
 118    default:
 119        return 0;
 120    }
 121}
 122
 123/* Update TxRDY flag and set data if present and enabled.  */
 124static void mcf_uart_do_tx(mcf_uart_state *s)
 125{
 126    if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
 127        /* XXX this blocks entire thread. Rewrite to use
 128         * qemu_chr_fe_write and background I/O callbacks */
 129        qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1);
 130        s->sr |= MCF_UART_TxEMP;
 131    }
 132    if (s->tx_enabled) {
 133        s->sr |= MCF_UART_TxRDY;
 134    } else {
 135        s->sr &= ~MCF_UART_TxRDY;
 136    }
 137}
 138
 139static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
 140{
 141    /* Misc command.  */
 142    switch ((cmd >> 4) & 7) {
 143    case 0: /* No-op.  */
 144        break;
 145    case 1: /* Reset mode register pointer.  */
 146        s->current_mr = 0;
 147        break;
 148    case 2: /* Reset receiver.  */
 149        s->rx_enabled = 0;
 150        s->fifo_len = 0;
 151        s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
 152        break;
 153    case 3: /* Reset transmitter.  */
 154        s->tx_enabled = 0;
 155        s->sr |= MCF_UART_TxEMP;
 156        s->sr &= ~MCF_UART_TxRDY;
 157        break;
 158    case 4: /* Reset error status.  */
 159        break;
 160    case 5: /* Reset break-change interrupt.  */
 161        s->isr &= ~MCF_UART_DBINT;
 162        break;
 163    case 6: /* Start break.  */
 164    case 7: /* Stop break.  */
 165        break;
 166    }
 167
 168    /* Transmitter command.  */
 169    switch ((cmd >> 2) & 3) {
 170    case 0: /* No-op.  */
 171        break;
 172    case 1: /* Enable.  */
 173        s->tx_enabled = 1;
 174        mcf_uart_do_tx(s);
 175        break;
 176    case 2: /* Disable.  */
 177        s->tx_enabled = 0;
 178        mcf_uart_do_tx(s);
 179        break;
 180    case 3: /* Reserved.  */
 181        fprintf(stderr, "mcf_uart: Bad TX command\n");
 182        break;
 183    }
 184
 185    /* Receiver command.  */
 186    switch (cmd & 3) {
 187    case 0: /* No-op.  */
 188        break;
 189    case 1: /* Enable.  */
 190        s->rx_enabled = 1;
 191        break;
 192    case 2:
 193        s->rx_enabled = 0;
 194        break;
 195    case 3: /* Reserved.  */
 196        fprintf(stderr, "mcf_uart: Bad RX command\n");
 197        break;
 198    }
 199}
 200
 201void mcf_uart_write(void *opaque, hwaddr addr,
 202                    uint64_t val, unsigned size)
 203{
 204    mcf_uart_state *s = (mcf_uart_state *)opaque;
 205    switch (addr & 0x3f) {
 206    case 0x00:
 207        s->mr[s->current_mr] = val;
 208        s->current_mr = 1;
 209        break;
 210    case 0x04:
 211        /* CSR is ignored.  */
 212        break;
 213    case 0x08: /* Command Register.  */
 214        mcf_do_command(s, val);
 215        break;
 216    case 0x0c: /* Transmit Buffer.  */
 217        s->sr &= ~MCF_UART_TxEMP;
 218        s->tb = val;
 219        mcf_uart_do_tx(s);
 220        break;
 221    case 0x10:
 222        /* ACR is ignored.  */
 223        break;
 224    case 0x14:
 225        s->imr = val;
 226        break;
 227    default:
 228        break;
 229    }
 230    mcf_uart_update(s);
 231}
 232
 233static void mcf_uart_reset(DeviceState *dev)
 234{
 235    mcf_uart_state *s = MCF_UART(dev);
 236
 237    s->fifo_len = 0;
 238    s->mr[0] = 0;
 239    s->mr[1] = 0;
 240    s->sr = MCF_UART_TxEMP;
 241    s->tx_enabled = 0;
 242    s->rx_enabled = 0;
 243    s->isr = 0;
 244    s->imr = 0;
 245}
 246
 247static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
 248{
 249    /* Break events overwrite the last byte if the fifo is full.  */
 250    if (s->fifo_len == 4)
 251        s->fifo_len--;
 252
 253    s->fifo[s->fifo_len] = data;
 254    s->fifo_len++;
 255    s->sr |= MCF_UART_RxRDY;
 256    if (s->fifo_len == 4)
 257        s->sr |= MCF_UART_FFULL;
 258
 259    mcf_uart_update(s);
 260}
 261
 262static void mcf_uart_event(void *opaque, QEMUChrEvent event)
 263{
 264    mcf_uart_state *s = (mcf_uart_state *)opaque;
 265
 266    switch (event) {
 267    case CHR_EVENT_BREAK:
 268        s->isr |= MCF_UART_DBINT;
 269        mcf_uart_push_byte(s, 0);
 270        break;
 271    default:
 272        break;
 273    }
 274}
 275
 276static int mcf_uart_can_receive(void *opaque)
 277{
 278    mcf_uart_state *s = (mcf_uart_state *)opaque;
 279
 280    return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
 281}
 282
 283static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
 284{
 285    mcf_uart_state *s = (mcf_uart_state *)opaque;
 286
 287    mcf_uart_push_byte(s, buf[0]);
 288}
 289
 290static const MemoryRegionOps mcf_uart_ops = {
 291    .read = mcf_uart_read,
 292    .write = mcf_uart_write,
 293    .endianness = DEVICE_NATIVE_ENDIAN,
 294};
 295
 296static void mcf_uart_instance_init(Object *obj)
 297{
 298    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 299    mcf_uart_state *s = MCF_UART(dev);
 300
 301    memory_region_init_io(&s->iomem, obj, &mcf_uart_ops, s, "uart", 0x40);
 302    sysbus_init_mmio(dev, &s->iomem);
 303
 304    sysbus_init_irq(dev, &s->irq);
 305}
 306
 307static void mcf_uart_realize(DeviceState *dev, Error **errp)
 308{
 309    mcf_uart_state *s = MCF_UART(dev);
 310
 311    qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive,
 312                             mcf_uart_event, NULL, s, NULL, true);
 313}
 314
 315static Property mcf_uart_properties[] = {
 316    DEFINE_PROP_CHR("chardev", mcf_uart_state, chr),
 317    DEFINE_PROP_END_OF_LIST(),
 318};
 319
 320static void mcf_uart_class_init(ObjectClass *oc, void *data)
 321{
 322    DeviceClass *dc = DEVICE_CLASS(oc);
 323
 324    dc->realize = mcf_uart_realize;
 325    dc->reset = mcf_uart_reset;
 326    device_class_set_props(dc, mcf_uart_properties);
 327    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 328}
 329
 330static const TypeInfo mcf_uart_info = {
 331    .name          = TYPE_MCF_UART,
 332    .parent        = TYPE_SYS_BUS_DEVICE,
 333    .instance_size = sizeof(mcf_uart_state),
 334    .instance_init = mcf_uart_instance_init,
 335    .class_init    = mcf_uart_class_init,
 336};
 337
 338static void mcf_uart_register(void)
 339{
 340    type_register_static(&mcf_uart_info);
 341}
 342
 343type_init(mcf_uart_register)
 344
 345void *mcf_uart_init(qemu_irq irq, Chardev *chrdrv)
 346{
 347    DeviceState  *dev;
 348
 349    dev = qdev_new(TYPE_MCF_UART);
 350    if (chrdrv) {
 351        qdev_prop_set_chr(dev, "chardev", chrdrv);
 352    }
 353    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
 354
 355    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
 356
 357    return dev;
 358}
 359
 360void mcf_uart_mm_init(hwaddr base, qemu_irq irq, Chardev *chrdrv)
 361{
 362    DeviceState  *dev;
 363
 364    dev = mcf_uart_init(irq, chrdrv);
 365    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
 366}
 367