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 "chardev/char.h"
  30#include "chardev/char-fe.h"
  31#include "hw/register-dep.h"
  32#include "qemu/log.h"
  33#include "sysemu/sysemu.h"
  34
  35#ifndef XILINX_IO_MODULE_UART_ERR_DEBUG
  36#define XILINX_IO_MODULE_UART_ERR_DEBUG 0
  37#endif
  38
  39#define TYPE_XILINX_IO_MODULE_UART "xlnx.io_uart"
  40
  41#define XILINX_IO_MODULE_UART(obj) \
  42     OBJECT_CHECK(XilinxUART, (obj), TYPE_XILINX_IO_MODULE_UART)
  43
  44#define R_IOM_UART_RX               (0x00 / 4)
  45#define R_IOM_UART_TX               (0x04 / 4)
  46#define R_IOM_UART_STATUS           (0x08 / 4)
  47#define IOM_UART_STATUS_RX_VALID    (1 << 0)
  48#define IOM_UART_STATUS_TX_USED     (1 << 3)
  49#define IOM_UART_STATUS_OVERRUN     (1 << 5)
  50#define IOM_UART_STATUS_FRAME_ERR   (1 << 6)
  51#define IOM_UART_STATUS_PARITY_ERR  (1 << 7)
  52#define R_MAX_0                     (R_IOM_UART_STATUS + 1)
  53
  54#define R_IOM_UART_BAUD             (0x00 / 4)
  55#define R_MAX_1                     (1)
  56
  57typedef struct XilinxUART {
  58    SysBusDevice parent_obj;
  59    MemoryRegion iomem[2];
  60    qemu_irq irq_rx;
  61    qemu_irq irq_tx;
  62    qemu_irq irq_err;
  63
  64    struct {
  65        bool use_rx;
  66        bool use_tx;
  67        bool rx_interrupt;
  68        bool tx_interrupt;
  69        bool err_interrupt;
  70    } cfg;
  71    CharBackend chr;
  72    uint32_t regs[R_MAX_0];
  73    uint32_t baud;
  74    DepRegisterInfo regs_info0[R_MAX_0];
  75    DepRegisterInfo regs_info1[R_MAX_1];
  76    DepRegisterInfo *regs_infos[2];
  77    const char *prefix;
  78} XilinxUART;
  79
  80static Property xlx_iom_properties[] = {
  81    DEFINE_PROP_BOOL("use-uart-rx", XilinxUART, cfg.use_rx, 0),
  82    DEFINE_PROP_BOOL("use-uart-tx", XilinxUART, cfg.use_tx, 0),
  83    DEFINE_PROP_BOOL("uart-rx-interrupt", XilinxUART, cfg.rx_interrupt, 0),
  84    DEFINE_PROP_BOOL("uart-tx-interrupt", XilinxUART, cfg.tx_interrupt, 0),
  85    DEFINE_PROP_BOOL("uart-error-interrupt", XilinxUART, cfg.err_interrupt, 0),
  86    DEFINE_PROP_CHR("chardev", XilinxUART, chr),
  87    DEFINE_PROP_END_OF_LIST(),
  88};
  89
  90static void uart_rx(void *opaque, const uint8_t *buf, int size)
  91{
  92    XilinxUART *s = opaque;
  93
  94    if (!s->cfg.use_rx) {
  95        return;
  96    }
  97
  98    if (s->regs[R_IOM_UART_STATUS] & IOM_UART_STATUS_RX_VALID) {
  99        s->regs[R_IOM_UART_STATUS] |= IOM_UART_STATUS_OVERRUN;
 100        if (s->cfg.err_interrupt) {
 101            qemu_irq_pulse(s->irq_err);
 102        }
 103        return;
 104    }
 105
 106    s->regs[R_IOM_UART_RX] = *buf;
 107    s->regs[R_IOM_UART_STATUS] |= IOM_UART_STATUS_RX_VALID;
 108    if (s->cfg.rx_interrupt) {
 109        qemu_irq_pulse(s->irq_rx);
 110    }
 111}
 112
 113static int uart_can_rx(void *opaque)
 114{
 115    XilinxUART *s = opaque;
 116    return s->cfg.use_rx;
 117}
 118
 119static void uart_event(void *opaque, int event)
 120{
 121}
 122
 123static uint64_t uart_rx_pr(DepRegisterInfo *reg, uint64_t val)
 124{
 125    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
 126    s->regs[R_IOM_UART_STATUS] &= ~IOM_UART_STATUS_OVERRUN;
 127    s->regs[R_IOM_UART_STATUS] &= ~IOM_UART_STATUS_RX_VALID;
 128    return s->regs[R_IOM_UART_RX];
 129}
 130
 131static uint64_t uart_sts_pr(DepRegisterInfo *reg, uint64_t val)
 132{
 133    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
 134    s->regs[R_IOM_UART_STATUS] &= ~IOM_UART_STATUS_OVERRUN;
 135    return val;
 136}
 137
 138static void uart_tx_pw(DepRegisterInfo *reg, uint64_t value)
 139{
 140    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
 141    if (s->cfg.use_tx) {
 142        unsigned char ch = value;
 143        qemu_chr_fe_write(&s->chr, &ch, 1);
 144        if (s->cfg.tx_interrupt) {
 145            qemu_irq_pulse(s->irq_tx);
 146        }
 147    }
 148}
 149
 150static const DepRegisterAccessInfo uart_regs_info0[] = {
 151    [R_IOM_UART_RX] = { .name = "UART_RX", .post_read = uart_rx_pr },
 152    [R_IOM_UART_TX] = { .name = "UART_TX", .post_write = uart_tx_pw },
 153    [R_IOM_UART_STATUS] = { .name = "UART_STATUS", .post_read = uart_sts_pr },
 154};
 155
 156static const DepRegisterAccessInfo uart_regs_info1[] = {
 157    [R_IOM_UART_BAUD] = { .name = "UART_BAUD" },
 158};
 159static const DepRegisterAccessInfo *uart_reginfos[] = {
 160    &uart_regs_info0[0], &uart_regs_info1[0]
 161};
 162
 163static const unsigned int uart_reginfo_sizes[] = {
 164    ARRAY_SIZE(uart_regs_info0),
 165    ARRAY_SIZE(uart_regs_info1),
 166};
 167
 168static const MemoryRegionOps iom_uart_ops = {
 169    .read = dep_register_read_memory_le,
 170    .write = dep_register_write_memory_le,
 171    .endianness = DEVICE_LITTLE_ENDIAN,
 172    .valid = {
 173        .min_access_size = 4,
 174        .max_access_size = 4,
 175    },
 176};
 177
 178static void iom_uart_reset(DeviceState *dev)
 179{
 180    XilinxUART *s = XILINX_IO_MODULE_UART(dev);
 181    unsigned int i;
 182    unsigned int rmap;
 183
 184    for (rmap = 0; rmap < ARRAY_SIZE(uart_reginfos); rmap++) {
 185        for (i = 0; i < uart_reginfo_sizes[rmap]; ++i) {
 186            dep_register_reset(&s->regs_infos[rmap][i]);
 187        }
 188    }
 189}
 190
 191static void xlx_iom_realize(DeviceState *dev, Error **errp)
 192{
 193    XilinxUART *s = XILINX_IO_MODULE_UART(dev);
 194    unsigned int i, rmap;
 195    uint32_t *regmaps[3] = { &s->regs[0], &s->baud };
 196
 197    s->prefix = object_get_canonical_path(OBJECT(dev));
 198
 199    for (rmap = 0; rmap < ARRAY_SIZE(uart_reginfos); rmap++) {
 200        for (i = 0; i < uart_reginfo_sizes[rmap]; ++i) {
 201            DepRegisterInfo *r = &s->regs_infos[rmap][i];
 202
 203            *r = (DepRegisterInfo) {
 204                .data = (uint8_t *)&regmaps[rmap][i],
 205                .data_size = sizeof(uint32_t),
 206                .access = &uart_reginfos[rmap][i],
 207                .debug = XILINX_IO_MODULE_UART_ERR_DEBUG,
 208                .prefix = s->prefix,
 209                .opaque = s,
 210            };
 211            memory_region_init_io(&r->mem, OBJECT(dev), &iom_uart_ops, r,
 212                                  r->access->name, 4);
 213            memory_region_add_subregion(&s->iomem[rmap], i * 4, &r->mem);
 214        }
 215    }
 216
 217    if (s->cfg.use_rx || s->cfg.use_tx) {
 218        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event,
 219                                 NULL, s, NULL, true);
 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