qemu/hw/char/pl011.c
<<
>>
Prefs
   1/*
   2 * Arm PrimeCell PL011 UART
   3 *
   4 * Copyright (c) 2006 CodeSourcery.
   5 * Written by Paul Brook
   6 *
   7 * This code is licensed under the GPL.
   8 */
   9
  10/*
  11 * QEMU interface:
  12 *  + sysbus MMIO region 0: device registers
  13 *  + sysbus IRQ 0: UARTINTR (combined interrupt line)
  14 *  + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line)
  15 *  + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line)
  16 *  + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line)
  17 *  + sysbus IRQ 4: UARTMSINTR (momem status interrupt line)
  18 *  + sysbus IRQ 5: UARTEINTR (error interrupt line)
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "hw/char/pl011.h"
  23#include "hw/sysbus.h"
  24#include "chardev/char-fe.h"
  25#include "qemu/log.h"
  26#include "trace.h"
  27
  28#define PL011_INT_TX 0x20
  29#define PL011_INT_RX 0x10
  30
  31#define PL011_FLAG_TXFE 0x80
  32#define PL011_FLAG_RXFF 0x40
  33#define PL011_FLAG_TXFF 0x20
  34#define PL011_FLAG_RXFE 0x10
  35
  36/* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
  37#define INT_OE (1 << 10)
  38#define INT_BE (1 << 9)
  39#define INT_PE (1 << 8)
  40#define INT_FE (1 << 7)
  41#define INT_RT (1 << 6)
  42#define INT_TX (1 << 5)
  43#define INT_RX (1 << 4)
  44#define INT_DSR (1 << 3)
  45#define INT_DCD (1 << 2)
  46#define INT_CTS (1 << 1)
  47#define INT_RI (1 << 0)
  48#define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
  49#define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
  50
  51static const unsigned char pl011_id_arm[8] =
  52  { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
  53static const unsigned char pl011_id_luminary[8] =
  54  { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
  55
  56/* Which bits in the interrupt status matter for each outbound IRQ line ? */
  57static const uint32_t irqmask[] = {
  58    INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
  59    INT_RX,
  60    INT_TX,
  61    INT_RT,
  62    INT_MS,
  63    INT_E,
  64};
  65
  66static void pl011_update(PL011State *s)
  67{
  68    uint32_t flags;
  69    int i;
  70
  71    flags = s->int_level & s->int_enabled;
  72    trace_pl011_irq_state(flags != 0);
  73    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
  74        qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
  75    }
  76}
  77
  78static uint64_t pl011_read(void *opaque, hwaddr offset,
  79                           unsigned size)
  80{
  81    PL011State *s = (PL011State *)opaque;
  82    uint32_t c;
  83    uint64_t r;
  84
  85    switch (offset >> 2) {
  86    case 0: /* UARTDR */
  87        s->flags &= ~PL011_FLAG_RXFF;
  88        c = s->read_fifo[s->read_pos];
  89        if (s->read_count > 0) {
  90            s->read_count--;
  91            if (++s->read_pos == 16)
  92                s->read_pos = 0;
  93        }
  94        if (s->read_count == 0) {
  95            s->flags |= PL011_FLAG_RXFE;
  96        }
  97        if (s->read_count == s->read_trigger - 1)
  98            s->int_level &= ~ PL011_INT_RX;
  99        trace_pl011_read_fifo(s->read_count);
 100        s->rsr = c >> 8;
 101        pl011_update(s);
 102        qemu_chr_fe_accept_input(&s->chr);
 103        r = c;
 104        break;
 105    case 1: /* UARTRSR */
 106        r = s->rsr;
 107        break;
 108    case 6: /* UARTFR */
 109        r = s->flags;
 110        break;
 111    case 8: /* UARTILPR */
 112        r = s->ilpr;
 113        break;
 114    case 9: /* UARTIBRD */
 115        r = s->ibrd;
 116        break;
 117    case 10: /* UARTFBRD */
 118        r = s->fbrd;
 119        break;
 120    case 11: /* UARTLCR_H */
 121        r = s->lcr;
 122        break;
 123    case 12: /* UARTCR */
 124        r = s->cr;
 125        break;
 126    case 13: /* UARTIFLS */
 127        r = s->ifl;
 128        break;
 129    case 14: /* UARTIMSC */
 130        r = s->int_enabled;
 131        break;
 132    case 15: /* UARTRIS */
 133        r = s->int_level;
 134        break;
 135    case 16: /* UARTMIS */
 136        r = s->int_level & s->int_enabled;
 137        break;
 138    case 18: /* UARTDMACR */
 139        r = s->dmacr;
 140        break;
 141    case 0x3f8 ... 0x400:
 142        r = s->id[(offset - 0xfe0) >> 2];
 143        break;
 144    default:
 145        qemu_log_mask(LOG_GUEST_ERROR,
 146                      "pl011_read: Bad offset 0x%x\n", (int)offset);
 147        r = 0;
 148        break;
 149    }
 150
 151    trace_pl011_read(offset, r);
 152    return r;
 153}
 154
 155static void pl011_set_read_trigger(PL011State *s)
 156{
 157#if 0
 158    /* The docs say the RX interrupt is triggered when the FIFO exceeds
 159       the threshold.  However linux only reads the FIFO in response to an
 160       interrupt.  Triggering the interrupt when the FIFO is non-empty seems
 161       to make things work.  */
 162    if (s->lcr & 0x10)
 163        s->read_trigger = (s->ifl >> 1) & 0x1c;
 164    else
 165#endif
 166        s->read_trigger = 1;
 167}
 168
 169static void pl011_write(void *opaque, hwaddr offset,
 170                        uint64_t value, unsigned size)
 171{
 172    PL011State *s = (PL011State *)opaque;
 173    unsigned char ch;
 174
 175    trace_pl011_write(offset, value);
 176
 177    switch (offset >> 2) {
 178    case 0: /* UARTDR */
 179        /* ??? Check if transmitter is enabled.  */
 180        ch = value;
 181        /* XXX this blocks entire thread. Rewrite to use
 182         * qemu_chr_fe_write and background I/O callbacks */
 183        qemu_chr_fe_write_all(&s->chr, &ch, 1);
 184        s->int_level |= PL011_INT_TX;
 185        pl011_update(s);
 186        break;
 187    case 1: /* UARTRSR/UARTECR */
 188        s->rsr = 0;
 189        break;
 190    case 6: /* UARTFR */
 191        /* Writes to Flag register are ignored.  */
 192        break;
 193    case 8: /* UARTUARTILPR */
 194        s->ilpr = value;
 195        break;
 196    case 9: /* UARTIBRD */
 197        s->ibrd = value;
 198        break;
 199    case 10: /* UARTFBRD */
 200        s->fbrd = value;
 201        break;
 202    case 11: /* UARTLCR_H */
 203        /* Reset the FIFO state on FIFO enable or disable */
 204        if ((s->lcr ^ value) & 0x10) {
 205            s->read_count = 0;
 206            s->read_pos = 0;
 207        }
 208        s->lcr = value;
 209        pl011_set_read_trigger(s);
 210        break;
 211    case 12: /* UARTCR */
 212        /* ??? Need to implement the enable and loopback bits.  */
 213        s->cr = value;
 214        break;
 215    case 13: /* UARTIFS */
 216        s->ifl = value;
 217        pl011_set_read_trigger(s);
 218        break;
 219    case 14: /* UARTIMSC */
 220        s->int_enabled = value;
 221        pl011_update(s);
 222        break;
 223    case 17: /* UARTICR */
 224        s->int_level &= ~value;
 225        pl011_update(s);
 226        break;
 227    case 18: /* UARTDMACR */
 228        s->dmacr = value;
 229        if (value & 3) {
 230            qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
 231        }
 232        break;
 233    default:
 234        qemu_log_mask(LOG_GUEST_ERROR,
 235                      "pl011_write: Bad offset 0x%x\n", (int)offset);
 236    }
 237}
 238
 239static int pl011_can_receive(void *opaque)
 240{
 241    PL011State *s = (PL011State *)opaque;
 242    int r;
 243
 244    if (s->lcr & 0x10) {
 245        r = s->read_count < 16;
 246    } else {
 247        r = s->read_count < 1;
 248    }
 249    trace_pl011_can_receive(s->lcr, s->read_count, r);
 250    return r;
 251}
 252
 253static void pl011_put_fifo(void *opaque, uint32_t value)
 254{
 255    PL011State *s = (PL011State *)opaque;
 256    int slot;
 257
 258    slot = s->read_pos + s->read_count;
 259    if (slot >= 16)
 260        slot -= 16;
 261    s->read_fifo[slot] = value;
 262    s->read_count++;
 263    s->flags &= ~PL011_FLAG_RXFE;
 264    trace_pl011_put_fifo(value, s->read_count);
 265    if (!(s->lcr & 0x10) || s->read_count == 16) {
 266        trace_pl011_put_fifo_full();
 267        s->flags |= PL011_FLAG_RXFF;
 268    }
 269    if (s->read_count == s->read_trigger) {
 270        s->int_level |= PL011_INT_RX;
 271        pl011_update(s);
 272    }
 273}
 274
 275static void pl011_receive(void *opaque, const uint8_t *buf, int size)
 276{
 277    pl011_put_fifo(opaque, *buf);
 278}
 279
 280static void pl011_event(void *opaque, int event)
 281{
 282    if (event == CHR_EVENT_BREAK)
 283        pl011_put_fifo(opaque, 0x400);
 284}
 285
 286static const MemoryRegionOps pl011_ops = {
 287    .read = pl011_read,
 288    .write = pl011_write,
 289    .endianness = DEVICE_NATIVE_ENDIAN,
 290};
 291
 292static const VMStateDescription vmstate_pl011 = {
 293    .name = "pl011",
 294    .version_id = 2,
 295    .minimum_version_id = 2,
 296    .fields = (VMStateField[]) {
 297        VMSTATE_UINT32(readbuff, PL011State),
 298        VMSTATE_UINT32(flags, PL011State),
 299        VMSTATE_UINT32(lcr, PL011State),
 300        VMSTATE_UINT32(rsr, PL011State),
 301        VMSTATE_UINT32(cr, PL011State),
 302        VMSTATE_UINT32(dmacr, PL011State),
 303        VMSTATE_UINT32(int_enabled, PL011State),
 304        VMSTATE_UINT32(int_level, PL011State),
 305        VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
 306        VMSTATE_UINT32(ilpr, PL011State),
 307        VMSTATE_UINT32(ibrd, PL011State),
 308        VMSTATE_UINT32(fbrd, PL011State),
 309        VMSTATE_UINT32(ifl, PL011State),
 310        VMSTATE_INT32(read_pos, PL011State),
 311        VMSTATE_INT32(read_count, PL011State),
 312        VMSTATE_INT32(read_trigger, PL011State),
 313        VMSTATE_END_OF_LIST()
 314    }
 315};
 316
 317static Property pl011_properties[] = {
 318    DEFINE_PROP_CHR("chardev", PL011State, chr),
 319    DEFINE_PROP_END_OF_LIST(),
 320};
 321
 322static void pl011_init(Object *obj)
 323{
 324    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 325    PL011State *s = PL011(obj);
 326    int i;
 327
 328    memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
 329    sysbus_init_mmio(sbd, &s->iomem);
 330    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
 331        sysbus_init_irq(sbd, &s->irq[i]);
 332    }
 333
 334    s->read_trigger = 1;
 335    s->ifl = 0x12;
 336    s->cr = 0x300;
 337    s->flags = 0x90;
 338
 339    s->id = pl011_id_arm;
 340}
 341
 342static void pl011_realize(DeviceState *dev, Error **errp)
 343{
 344    PL011State *s = PL011(dev);
 345
 346    qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
 347                             pl011_event, NULL, s, NULL, true);
 348}
 349
 350static void pl011_class_init(ObjectClass *oc, void *data)
 351{
 352    DeviceClass *dc = DEVICE_CLASS(oc);
 353
 354    dc->realize = pl011_realize;
 355    dc->vmsd = &vmstate_pl011;
 356    dc->props = pl011_properties;
 357}
 358
 359static const TypeInfo pl011_arm_info = {
 360    .name          = TYPE_PL011,
 361    .parent        = TYPE_SYS_BUS_DEVICE,
 362    .instance_size = sizeof(PL011State),
 363    .instance_init = pl011_init,
 364    .class_init    = pl011_class_init,
 365};
 366
 367static void pl011_luminary_init(Object *obj)
 368{
 369    PL011State *s = PL011(obj);
 370
 371    s->id = pl011_id_luminary;
 372}
 373
 374static const TypeInfo pl011_luminary_info = {
 375    .name          = TYPE_PL011_LUMINARY,
 376    .parent        = TYPE_PL011,
 377    .instance_init = pl011_luminary_init,
 378};
 379
 380static void pl011_register_types(void)
 381{
 382    type_register_static(&pl011_arm_info);
 383    type_register_static(&pl011_luminary_info);
 384}
 385
 386type_init(pl011_register_types)
 387