X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/71ffe1a01faa90fa08805e8030120b3be0efda25..ca4e667dbf431d4a2a5a619cde79d30dd2ac3eb2:/hw/char/pl011.c diff --git a/hw/char/pl011.c b/hw/char/pl011.c index a8ae6f4706..2aa277fc4f 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -7,8 +7,11 @@ * This code is licensed under the GPL. */ +#include "qemu/osdep.h" #include "hw/sysbus.h" -#include "sysemu/char.h" +#include "chardev/char-fe.h" +#include "qemu/log.h" +#include "trace.h" #define TYPE_PL011 "pl011" #define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011) @@ -20,6 +23,7 @@ typedef struct PL011State { uint32_t readbuff; uint32_t flags; uint32_t lcr; + uint32_t rsr; uint32_t cr; uint32_t dmacr; uint32_t int_enabled; @@ -32,7 +36,7 @@ typedef struct PL011State { int read_pos; int read_count; int read_trigger; - CharDriverState *chr; + CharBackend chr; qemu_irq irq; const unsigned char *id; } PL011State; @@ -55,6 +59,7 @@ static void pl011_update(PL011State *s) uint32_t flags; flags = s->int_level & s->int_enabled; + trace_pl011_irq_state(flags != 0); qemu_set_irq(s->irq, flags != 0); } @@ -63,10 +68,8 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, { PL011State *s = (PL011State *)opaque; uint32_t c; + uint64_t r; - if (offset >= 0xfe0 && offset < 0x1000) { - return s->id[(offset - 0xfe0) >> 2]; - } switch (offset >> 2) { case 0: /* UARTDR */ s->flags &= ~PL011_FLAG_RXFF; @@ -81,40 +84,60 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, } if (s->read_count == s->read_trigger - 1) s->int_level &= ~ PL011_INT_RX; + trace_pl011_read_fifo(s->read_count); + s->rsr = c >> 8; pl011_update(s); - if (s->chr) { - qemu_chr_accept_input(s->chr); - } - return c; - case 1: /* UARTCR */ - return 0; + qemu_chr_fe_accept_input(&s->chr); + r = c; + break; + case 1: /* UARTRSR */ + r = s->rsr; + break; case 6: /* UARTFR */ - return s->flags; + r = s->flags; + break; case 8: /* UARTILPR */ - return s->ilpr; + r = s->ilpr; + break; case 9: /* UARTIBRD */ - return s->ibrd; + r = s->ibrd; + break; case 10: /* UARTFBRD */ - return s->fbrd; + r = s->fbrd; + break; case 11: /* UARTLCR_H */ - return s->lcr; + r = s->lcr; + break; case 12: /* UARTCR */ - return s->cr; + r = s->cr; + break; case 13: /* UARTIFLS */ - return s->ifl; + r = s->ifl; + break; case 14: /* UARTIMSC */ - return s->int_enabled; + r = s->int_enabled; + break; case 15: /* UARTRIS */ - return s->int_level; + r = s->int_level; + break; case 16: /* UARTMIS */ - return s->int_level & s->int_enabled; + r = s->int_level & s->int_enabled; + break; case 18: /* UARTDMACR */ - return s->dmacr; + r = s->dmacr; + break; + case 0x3f8 ... 0x400: + r = s->id[(offset - 0xfe0) >> 2]; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset %x\n", (int)offset); - return 0; + r = 0; + break; } + + trace_pl011_read(offset, r); + return r; } static void pl011_set_read_trigger(PL011State *s) @@ -137,17 +160,20 @@ static void pl011_write(void *opaque, hwaddr offset, PL011State *s = (PL011State *)opaque; unsigned char ch; + trace_pl011_write(offset, value); + switch (offset >> 2) { case 0: /* UARTDR */ /* ??? Check if transmitter is enabled. */ ch = value; - if (s->chr) - qemu_chr_fe_write(s->chr, &ch, 1); + /* XXX this blocks entire thread. Rewrite to use + * qemu_chr_fe_write and background I/O callbacks */ + qemu_chr_fe_write_all(&s->chr, &ch, 1); s->int_level |= PL011_INT_TX; pl011_update(s); break; - case 1: /* UARTCR */ - s->cr = value; + case 1: /* UARTRSR/UARTECR */ + s->rsr = 0; break; case 6: /* UARTFR */ /* Writes to Flag register are ignored. */ @@ -162,6 +188,11 @@ static void pl011_write(void *opaque, hwaddr offset, s->fbrd = value; break; case 11: /* UARTLCR_H */ + /* Reset the FIFO state on FIFO enable or disable */ + if ((s->lcr ^ value) & 0x10) { + s->read_count = 0; + s->read_pos = 0; + } s->lcr = value; pl011_set_read_trigger(s); break; @@ -196,11 +227,15 @@ static void pl011_write(void *opaque, hwaddr offset, static int pl011_can_receive(void *opaque) { PL011State *s = (PL011State *)opaque; + int r; - if (s->lcr & 0x10) - return s->read_count < 16; - else - return s->read_count < 1; + if (s->lcr & 0x10) { + r = s->read_count < 16; + } else { + r = s->read_count < 1; + } + trace_pl011_can_receive(s->lcr, s->read_count, r); + return r; } static void pl011_put_fifo(void *opaque, uint32_t value) @@ -214,7 +249,9 @@ static void pl011_put_fifo(void *opaque, uint32_t value) s->read_fifo[slot] = value; s->read_count++; s->flags &= ~PL011_FLAG_RXFE; - if (s->cr & 0x10 || s->read_count == 16) { + trace_pl011_put_fifo(value, s->read_count); + if (!(s->lcr & 0x10) || s->read_count == 16) { + trace_pl011_put_fifo_full(); s->flags |= PL011_FLAG_RXFF; } if (s->read_count == s->read_trigger) { @@ -242,13 +279,13 @@ static const MemoryRegionOps pl011_ops = { static const VMStateDescription vmstate_pl011 = { .name = "pl011", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .version_id = 2, + .minimum_version_id = 2, + .fields = (VMStateField[]) { VMSTATE_UINT32(readbuff, PL011State), VMSTATE_UINT32(flags, PL011State), VMSTATE_UINT32(lcr, PL011State), + VMSTATE_UINT32(rsr, PL011State), VMSTATE_UINT32(cr, PL011State), VMSTATE_UINT32(dmacr, PL011State), VMSTATE_UINT32(int_enabled, PL011State), @@ -265,6 +302,11 @@ static const VMStateDescription vmstate_pl011 = { } }; +static Property pl011_properties[] = { + DEFINE_PROP_CHR("chardev", PL011State, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void pl011_init(Object *obj) { SysBusDevice *sbd = SYS_BUS_DEVICE(obj); @@ -286,12 +328,8 @@ static void pl011_realize(DeviceState *dev, Error **errp) { PL011State *s = PL011(dev); - s->chr = qemu_char_get_next_serial(); - - if (s->chr) { - qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, - pl011_event, s); - } + qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive, + pl011_event, NULL, s, NULL, true); } static void pl011_class_init(ObjectClass *oc, void *data) @@ -300,6 +338,7 @@ static void pl011_class_init(ObjectClass *oc, void *data) dc->realize = pl011_realize; dc->vmsd = &vmstate_pl011; + dc->props = pl011_properties; } static const TypeInfo pl011_arm_info = {