qemu/hw/char/xilinx_iomod_uart.c
<<
>>
Prefs
   1/*
   2 * QEMU model of Xilinx I/O Module UART
   3 *
   4 * Copyright (c) 2013 Xilinx Inc
   5 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25
  26#include "qemu/osdep.h"
  27#include "hw/sysbus.h"
  28#include "hw/ptimer.h"
  29#include "sysemu/char.h"
  30#include "hw/register.h"
  31#include "qemu/log.h"
  32
  33#ifndef XILINX_IO_MODULE_UART_ERR_DEBUG
  34#define XILINX_IO_MODULE_UART_ERR_DEBUG 0
  35#endif
  36
  37#define TYPE_XILINX_IO_MODULE_UART "xlnx.io_uart"
  38
  39#define XILINX_IO_MODULE_UART(obj) \
  40     OBJECT_CHECK(XilinxUART, (obj), TYPE_XILINX_IO_MODULE_UART)
  41
  42#define R_IOM_UART_RX               (0x00 / 4)
  43#define R_IOM_UART_TX               (0x04 / 4)
  44#define R_IOM_UART_STATUS           (0x08 / 4)
  45#define IOM_UART_STATUS_RX_VALID    (1 << 0)
  46#define IOM_UART_STATUS_TX_USED     (1 << 3)
  47#define IOM_UART_STATUS_OVERRUN     (1 << 5)
  48#define IOM_UART_STATUS_FRAME_ERR   (1 << 6)
  49#define IOM_UART_STATUS_PARITY_ERR  (1 << 7)
  50#define R_MAX_0                     (R_IOM_UART_STATUS + 1)
  51
  52#define R_IOM_UART_BAUD             (0x00 / 4)
  53#define R_MAX_1                     (1)
  54
  55typedef struct XilinxUART {
  56    SysBusDevice parent_obj;
  57    MemoryRegion iomem[2];
  58    qemu_irq irq_rx;
  59    qemu_irq irq_tx;
  60    qemu_irq irq_err;
  61
  62    struct {
  63        bool use_rx;
  64        bool use_tx;
  65        bool rx_interrupt;
  66        bool tx_interrupt;
  67        bool err_interrupt;
  68    } cfg;
  69    CharDriverState *chr;
  70    uint32_t regs[R_MAX_0];
  71    uint32_t baud;
  72    RegisterInfo regs_info0[R_MAX_0];
  73    RegisterInfo regs_info1[R_MAX_1];
  74    RegisterInfo *regs_infos[2];
  75    const char *prefix;
  76} XilinxUART;
  77
  78static Property xlx_iom_properties[] = {
  79    DEFINE_PROP_BOOL("use-uart-rx", XilinxUART, cfg.use_rx, 0),
  80    DEFINE_PROP_BOOL("use-uart-tx", XilinxUART, cfg.use_tx, 0),
  81    DEFINE_PROP_BOOL("uart-rx-interrupt", XilinxUART, cfg.rx_interrupt, 0),
  82    DEFINE_PROP_BOOL("uart-tx-interrupt", XilinxUART, cfg.tx_interrupt, 0),
  83    DEFINE_PROP_BOOL("uart-error-interrupt", XilinxUART, cfg.err_interrupt, 0),
  84    DEFINE_PROP_END_OF_LIST(),
  85};
  86
  87static void uart_rx(void *opaque, const uint8_t *buf, int size)
  88{
  89    XilinxUART *s = opaque;
  90
  91    if (!s->cfg.use_rx) {
  92        return;
  93    }
  94
  95    if (s->regs[R_IOM_UART_STATUS] & IOM_UART_STATUS_RX_VALID) {
  96        s->regs[R_IOM_UART_STATUS] |= IOM_UART_STATUS_OVERRUN;
  97        if (s->cfg.err_interrupt) {
  98            qemu_irq_pulse(s->irq_err);
  99        }
 100        return;
 101    }
 102
 103    s->regs[R_IOM_UART_RX] = *buf;
 104    s->regs[R_IOM_UART_STATUS] |= IOM_UART_STATUS_RX_VALID;
 105    if (s->cfg.rx_interrupt) {
 106        qemu_irq_pulse(s->irq_rx);
 107    }
 108}
 109
 110static int uart_can_rx(void *opaque)
 111{
 112    XilinxUART *s = opaque;
 113    return s->cfg.use_rx;
 114}
 115
 116static void uart_event(void *opaque, int event)
 117{
 118}
 119
 120static uint64_t uart_rx_pr(RegisterInfo *reg, uint64_t val)
 121{
 122    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
 123    s->regs[R_IOM_UART_STATUS] &= ~IOM_UART_STATUS_OVERRUN;
 124    s->regs[R_IOM_UART_STATUS] &= ~IOM_UART_STATUS_RX_VALID;
 125    return s->regs[R_IOM_UART_RX];
 126}
 127
 128static uint64_t uart_sts_pr(RegisterInfo *reg, uint64_t val)
 129{
 130    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
 131    s->regs[R_IOM_UART_STATUS] &= ~IOM_UART_STATUS_OVERRUN;
 132    return val;
 133}
 134
 135static void uart_tx_pw(RegisterInfo *reg, uint64_t value)
 136{
 137    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
 138    if (s->cfg.use_tx && s->chr) {
 139        unsigned char ch = value;
 140        qemu_chr_fe_write(s->chr, &ch, 1);
 141        if (s->cfg.tx_interrupt) {
 142            qemu_irq_pulse(s->irq_tx);
 143        }
 144    }
 145}
 146
 147static const RegisterAccessInfo uart_regs_info0[] = {
 148    [R_IOM_UART_RX] = { .name = "UART_RX", .post_read = uart_rx_pr },
 149    [R_IOM_UART_TX] = { .name = "UART_TX", .post_write = uart_tx_pw },
 150    [R_IOM_UART_STATUS] = { .name = "UART_STATUS", .post_read = uart_sts_pr },
 151};
 152
 153static const RegisterAccessInfo uart_regs_info1[] = {
 154    [R_IOM_UART_BAUD] = { .name = "UART_BAUD" },
 155};
 156static const RegisterAccessInfo *uart_reginfos[] = {
 157    &uart_regs_info0[0], &uart_regs_info1[0]
 158};
 159
 160static const unsigned int uart_reginfo_sizes[] = {
 161    ARRAY_SIZE(uart_regs_info0),
 162    ARRAY_SIZE(uart_regs_info1),
 163};
 164
 165static const MemoryRegionOps iom_uart_ops = {
 166    .read = register_read_memory_le,
 167    .write = register_write_memory_le,
 168    .endianness = DEVICE_LITTLE_ENDIAN,
 169    .valid = {
 170        .min_access_size = 4,
 171        .max_access_size = 4,
 172    },
 173};
 174
 175static void iom_uart_reset(DeviceState *dev)
 176{
 177    XilinxUART *s = XILINX_IO_MODULE_UART(dev);
 178    unsigned int i;
 179    unsigned int rmap;
 180
 181    for (rmap = 0; rmap < ARRAY_SIZE(uart_reginfos); rmap++) {
 182        for (i = 0; i < uart_reginfo_sizes[rmap]; ++i) {
 183            register_reset(&s->regs_infos[rmap][i]);
 184        }
 185    }
 186}
 187
 188static void xlx_iom_realize(DeviceState *dev, Error **errp)
 189{
 190    XilinxUART *s = XILINX_IO_MODULE_UART(dev);
 191    unsigned int i, rmap;
 192    uint32_t *regmaps[3] = { &s->regs[0], &s->baud };
 193
 194    s->prefix = object_get_canonical_path(OBJECT(dev));
 195
 196    for (rmap = 0; rmap < ARRAY_SIZE(uart_reginfos); rmap++) {
 197        for (i = 0; i < uart_reginfo_sizes[rmap]; ++i) {
 198            RegisterInfo *r = &s->regs_infos[rmap][i];
 199
 200            *r = (RegisterInfo) {
 201                .data = (uint8_t *)&regmaps[rmap][i],
 202                .data_size = sizeof(uint32_t),
 203                .access = &uart_reginfos[rmap][i],
 204                .debug = XILINX_IO_MODULE_UART_ERR_DEBUG,
 205                .prefix = s->prefix,
 206                .opaque = s,
 207            };
 208            memory_region_init_io(&r->mem, OBJECT(dev), &iom_uart_ops, r,
 209                                  r->access->name, 4);
 210            memory_region_add_subregion(&s->iomem[rmap], i * 4, &r->mem);
 211        }
 212    }
 213
 214    if (s->cfg.use_rx || s->cfg.use_tx) {
 215        s->chr = qemu_char_get_next_serial();
 216        if (s->chr) {
 217            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx,
 218                                  uart_event, s);
 219        }
 220    }
 221}
 222
 223static void xlx_iom_init(Object *obj)
 224{
 225    XilinxUART *s = XILINX_IO_MODULE_UART(obj);
 226    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 227    unsigned int i;
 228
 229    s->regs_infos[0] = s->regs_info0;
 230    s->regs_infos[1] = s->regs_info1;
 231
 232    for (i = 0; i < ARRAY_SIZE(s->iomem); i++) {
 233        char *region_name = g_strdup_printf("%s-%d", TYPE_XILINX_IO_MODULE_UART,
 234                                            i);
 235        memory_region_init_io(&s->iomem[i], obj, &iom_uart_ops, s,
 236                              region_name, uart_reginfo_sizes[i] * 4);
 237        g_free(region_name);
 238        sysbus_init_mmio(sbd, &s->iomem[i]);
 239    }
 240    sysbus_init_irq(sbd, &s->irq_err);
 241    sysbus_init_irq(sbd, &s->irq_tx);
 242    sysbus_init_irq(sbd, &s->irq_rx);
 243}
 244
 245static const VMStateDescription vmstate_xlx_iom = {
 246    .name = TYPE_XILINX_IO_MODULE_UART,
 247    .version_id = 1,
 248    .minimum_version_id = 1,
 249    .minimum_version_id_old = 1,
 250    .fields = (VMStateField[]) {
 251        VMSTATE_END_OF_LIST(),
 252    }
 253};
 254
 255static void xlx_iom_class_init(ObjectClass *klass, void *data)
 256{
 257    DeviceClass *dc = DEVICE_CLASS(klass);
 258
 259    dc->reset = iom_uart_reset;
 260    dc->realize = xlx_iom_realize;
 261    dc->props = xlx_iom_properties;
 262    dc->vmsd = &vmstate_xlx_iom;
 263}
 264
 265static const TypeInfo xlx_iom_info = {
 266    .name          = TYPE_XILINX_IO_MODULE_UART,
 267    .parent        = TYPE_SYS_BUS_DEVICE,
 268    .instance_size = sizeof(XilinxUART),
 269    .class_init    = xlx_iom_class_init,
 270    .instance_init = xlx_iom_init,
 271};
 272
 273static void xlx_iom_register_types(void)
 274{
 275    type_register_static(&xlx_iom_info);
 276}
 277
 278type_init(xlx_iom_register_types)
 279