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.h"
  32#include "qemu/log.h"
  33#include "sysemu/sysemu.h"
  34#include "migration/vmstate.h"
  35#include "hw/qdev-properties.h"
  36#include "hw/irq.h"
  37
  38#ifndef XILINX_IO_MODULE_UART_ERR_DEBUG
  39#define XILINX_IO_MODULE_UART_ERR_DEBUG 0
  40#endif
  41
  42#define TYPE_XILINX_IO_MODULE_UART "xlnx.io_uart"
  43
  44#define XILINX_IO_MODULE_UART(obj) \
  45     OBJECT_CHECK(XilinxUART, (obj), TYPE_XILINX_IO_MODULE_UART)
  46
  47REG32(IOM_UART_RX, 0x0)
  48REG32(IOM_UART_TX, 0x4)
  49REG32(IOM_UART_STATUS, 0x8)
  50    FIELD(IOM_UART_STATUS, PARITY_ERR, 7, 1)
  51    FIELD(IOM_UART_STATUS, FRAME_ERR, 6, 1)
  52    FIELD(IOM_UART_STATUS, OVERRUN, 5, 1)
  53    FIELD(IOM_UART_STATUS, TX_USED, 3, 1)
  54    FIELD(IOM_UART_STATUS, RX_VALID, 0, 1)
  55
  56REG32(IOM_UART_BAUD, 0x0)
  57
  58#define R_MAX_0 (R_IOM_UART_STATUS + 1)
  59#define R_MAX_1 (R_IOM_UART_BAUD + 1)
  60
  61typedef struct XilinxUART {
  62    SysBusDevice parent_obj;
  63    MemoryRegion iomem[2];
  64    qemu_irq irq_rx;
  65    qemu_irq irq_tx;
  66    qemu_irq irq_err;
  67
  68    struct {
  69        bool use_rx;
  70        bool use_tx;
  71        bool rx_interrupt;
  72        bool tx_interrupt;
  73        bool err_interrupt;
  74    } cfg;
  75    CharBackend chr;
  76    uint32_t regs[R_MAX_0];
  77    uint32_t baud;
  78    RegisterInfo regs_info0[R_MAX_0];
  79    RegisterInfo regs_info1[R_MAX_1];
  80    RegisterInfo *regs_infos[2];
  81    const char *prefix;
  82} XilinxUART;
  83
  84static Property xlx_iom_properties[] = {
  85    DEFINE_PROP_BOOL("use-uart-rx", XilinxUART, cfg.use_rx, 0),
  86    DEFINE_PROP_BOOL("use-uart-tx", XilinxUART, cfg.use_tx, 0),
  87    DEFINE_PROP_BOOL("uart-rx-interrupt", XilinxUART, cfg.rx_interrupt, 0),
  88    DEFINE_PROP_BOOL("uart-tx-interrupt", XilinxUART, cfg.tx_interrupt, 0),
  89    DEFINE_PROP_BOOL("uart-error-interrupt", XilinxUART, cfg.err_interrupt, 0),
  90    DEFINE_PROP_CHR("chardev", XilinxUART, chr),
  91    DEFINE_PROP_END_OF_LIST(),
  92};
  93
  94static void uart_rx(void *opaque, const uint8_t *buf, int size)
  95{
  96    XilinxUART *s = opaque;
  97
  98    if (!s->cfg.use_rx) {
  99        return;
 100    }
 101
 102    if (s->regs[R_IOM_UART_STATUS] & R_IOM_UART_STATUS_RX_VALID_MASK) {
 103        s->regs[R_IOM_UART_STATUS] |= R_IOM_UART_STATUS_OVERRUN_MASK;
 104        if (s->cfg.err_interrupt) {
 105            qemu_irq_pulse(s->irq_err);
 106        }
 107        return;
 108    }
 109
 110    s->regs[R_IOM_UART_RX] = *buf;
 111    s->regs[R_IOM_UART_STATUS] |= R_IOM_UART_STATUS_RX_VALID_MASK;
 112    if (s->cfg.rx_interrupt) {
 113        qemu_irq_pulse(s->irq_rx);
 114    }
 115}
 116
 117static int uart_can_rx(void *opaque)
 118{
 119    XilinxUART *s = opaque;
 120    return s->cfg.use_rx;
 121}
 122
 123static void uart_event(void *opaque, int event)
 124{
 125}
 126
 127static uint64_t uart_rx_pr(RegisterInfo *reg, uint64_t val)
 128{
 129    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
 130    s->regs[R_IOM_UART_STATUS] &= ~R_IOM_UART_STATUS_OVERRUN_MASK;
 131    s->regs[R_IOM_UART_STATUS] &= ~R_IOM_UART_STATUS_RX_VALID_MASK;
 132    return s->regs[R_IOM_UART_RX];
 133}
 134
 135static uint64_t uart_sts_pr(RegisterInfo *reg, uint64_t val)
 136{
 137    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
 138    s->regs[R_IOM_UART_STATUS] &= ~R_IOM_UART_STATUS_OVERRUN_MASK;
 139    return val;
 140}
 141
 142static void uart_tx_pw(RegisterInfo *reg, uint64_t value)
 143{
 144    XilinxUART *s = XILINX_IO_MODULE_UART(reg->opaque);
 145    if (s->cfg.use_tx) {
 146        unsigned char ch = value;
 147        qemu_chr_fe_write(&s->chr, &ch, 1);
 148        if (s->cfg.tx_interrupt) {
 149            qemu_irq_pulse(s->irq_tx);
 150        }
 151    }
 152}
 153
 154static const RegisterAccessInfo uart_regs_info0[] = {
 155    [R_IOM_UART_RX] = { .name = "UART_RX", .addr = A_IOM_UART_RX,
 156                        .post_read = uart_rx_pr },
 157    [R_IOM_UART_TX] = { .name = "UART_TX", .addr = A_IOM_UART_TX,
 158                        .post_write = uart_tx_pw },
 159    [R_IOM_UART_STATUS] = { .name = "UART_STATUS", .addr = A_IOM_UART_STATUS,
 160                        .post_read = uart_sts_pr },
 161};
 162
 163static const RegisterAccessInfo uart_regs_info1[] = {
 164    [R_IOM_UART_BAUD] = { .name = "UART_BAUD", .addr = A_IOM_UART_BAUD},
 165};
 166static const RegisterAccessInfo *uart_reginfos[] = {
 167    &uart_regs_info0[0], &uart_regs_info1[0]
 168};
 169
 170static const unsigned int uart_reginfo_sizes[] = {
 171    ARRAY_SIZE(uart_regs_info0),
 172    ARRAY_SIZE(uart_regs_info1),
 173};
 174
 175static const unsigned int uart_rmax[] = {
 176    R_MAX_0,
 177    R_MAX_1
 178};
 179
 180static const MemoryRegionOps iom_uart_ops = {
 181    .read = register_read_memory,
 182    .write = register_write_memory,
 183    .endianness = DEVICE_LITTLE_ENDIAN,
 184    .valid = {
 185        .min_access_size = 4,
 186        .max_access_size = 4,
 187    },
 188};
 189
 190static void iom_uart_reset(DeviceState *dev)
 191{
 192    XilinxUART *s = XILINX_IO_MODULE_UART(dev);
 193    unsigned int i;
 194    unsigned int rmap;
 195
 196    for (rmap = 0; rmap < ARRAY_SIZE(uart_reginfos); rmap++) {
 197        for (i = 0; i < uart_reginfo_sizes[rmap]; ++i) {
 198            register_reset(&s->regs_infos[rmap][i]);
 199        }
 200    }
 201}
 202
 203static void xlx_iom_realize(DeviceState *dev, Error **errp)
 204{
 205    XilinxUART *s = XILINX_IO_MODULE_UART(dev);
 206
 207    if (s->cfg.use_rx || s->cfg.use_tx) {
 208        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event,
 209                                 NULL, s, NULL, true);
 210    }
 211}
 212
 213static void xlx_iom_init(Object *obj)
 214{
 215    XilinxUART *s = XILINX_IO_MODULE_UART(obj);
 216    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 217    unsigned int i;
 218    RegisterInfoArray *reg_array;
 219    uint32_t *regmaps[] = { s->regs, &s->baud };
 220
 221    s->regs_infos[0] = s->regs_info0;
 222    s->regs_infos[1] = s->regs_info1;
 223
 224    for (i = 0; i < ARRAY_SIZE(s->iomem); i++) {
 225        char *region_name = g_strdup_printf("%s-%d", TYPE_XILINX_IO_MODULE_UART,
 226                                            i);
 227        memory_region_init(&s->iomem[i], obj,
 228                              region_name, uart_rmax[i] * 4);
 229        reg_array =
 230            register_init_block32(DEVICE(obj), uart_reginfos[i],
 231                            uart_reginfo_sizes[i],
 232                            s->regs_infos[i], regmaps[i],
 233                            &iom_uart_ops,
 234                            XILINX_IO_MODULE_UART_ERR_DEBUG,
 235                            uart_rmax[i] * 4);
 236        memory_region_add_subregion(&s->iomem[i], 0, &reg_array->mem);
 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