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