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