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