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