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