diff options
Diffstat (limited to 'hw/char/pl011.c')
| -rw-r--r-- | hw/char/pl011.c | 58 |
1 files changed, 42 insertions, 16 deletions
diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 77bbc2a982..58edeb9ddb 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -48,14 +48,15 @@ DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr) return dev; } -#define PL011_INT_TX 0x20 -#define PL011_INT_RX 0x10 - +/* Flag Register, UARTFR */ #define PL011_FLAG_TXFE 0x80 #define PL011_FLAG_RXFF 0x40 #define PL011_FLAG_TXFF 0x20 #define PL011_FLAG_RXFE 0x10 +/* Data Register, UARTDR */ +#define DR_BE (1 << 10) + /* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */ #define INT_OE (1 << 10) #define INT_BE (1 << 9) @@ -71,11 +72,33 @@ DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr) #define INT_E (INT_OE | INT_BE | INT_PE | INT_FE) #define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS) +/* Line Control Register, UARTLCR_H */ +#define LCR_FEN (1 << 4) +#define LCR_BRK (1 << 0) + static const unsigned char pl011_id_arm[8] = { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; static const unsigned char pl011_id_luminary[8] = { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }; +static const char *pl011_regname(hwaddr offset) +{ + static const char *const rname[] = { + [0] = "DR", [1] = "RSR", [6] = "FR", [8] = "ILPR", [9] = "IBRD", + [10] = "FBRD", [11] = "LCRH", [12] = "CR", [13] = "IFLS", [14] = "IMSC", + [15] = "RIS", [16] = "MIS", [17] = "ICR", [18] = "DMACR", + }; + unsigned idx = offset >> 2; + + if (idx < ARRAY_SIZE(rname) && rname[idx]) { + return rname[idx]; + } + if (idx >= 0x3f8 && idx <= 0x400) { + return "ID"; + } + return "UNKN"; +} + /* Which bits in the interrupt status matter for each outbound IRQ line ? */ static const uint32_t irqmask[] = { INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */ @@ -100,7 +123,7 @@ static void pl011_update(PL011State *s) static bool pl011_is_fifo_enabled(PL011State *s) { - return (s->lcr & 0x10) != 0; + return (s->lcr & LCR_FEN) != 0; } static inline unsigned pl011_get_fifo_depth(PL011State *s) @@ -138,7 +161,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, s->flags |= PL011_FLAG_RXFE; } if (s->read_count == s->read_trigger - 1) - s->int_level &= ~ PL011_INT_RX; + s->int_level &= ~ INT_RX; trace_pl011_read_fifo(s->read_count); s->rsr = c >> 8; pl011_update(s); @@ -191,7 +214,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, break; } - trace_pl011_read(offset, r); + trace_pl011_read(offset, r, pl011_regname(offset)); return r; } @@ -202,7 +225,7 @@ static void pl011_set_read_trigger(PL011State *s) the threshold. However linux only reads the FIFO in response to an interrupt. Triggering the interrupt when the FIFO is non-empty seems to make things work. */ - if (s->lcr & 0x10) + if (s->lcr & LCR_FEN) s->read_trigger = (s->ifl >> 1) & 0x1c; else #endif @@ -234,7 +257,7 @@ static void pl011_write(void *opaque, hwaddr offset, PL011State *s = (PL011State *)opaque; unsigned char ch; - trace_pl011_write(offset, value); + trace_pl011_write(offset, value, pl011_regname(offset)); switch (offset >> 2) { case 0: /* UARTDR */ @@ -243,7 +266,7 @@ static void pl011_write(void *opaque, hwaddr offset, /* 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; + s->int_level |= INT_TX; pl011_update(s); break; case 1: /* UARTRSR/UARTECR */ @@ -252,7 +275,7 @@ static void pl011_write(void *opaque, hwaddr offset, case 6: /* UARTFR */ /* Writes to Flag register are ignored. */ break; - case 8: /* UARTUARTILPR */ + case 8: /* UARTILPR */ s->ilpr = value; break; case 9: /* UARTIBRD */ @@ -265,11 +288,11 @@ static void pl011_write(void *opaque, hwaddr offset, break; case 11: /* UARTLCR_H */ /* Reset the FIFO state on FIFO enable or disable */ - if ((s->lcr ^ value) & 0x10) { + if ((s->lcr ^ value) & LCR_FEN) { pl011_reset_fifo(s); } - if ((s->lcr ^ value) & 0x1) { - int break_enable = value & 0x1; + if ((s->lcr ^ value) & LCR_BRK) { + int break_enable = value & LCR_BRK; qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK, &break_enable); } @@ -331,7 +354,7 @@ static void pl011_put_fifo(void *opaque, uint32_t value) s->flags |= PL011_FLAG_RXFF; } if (s->read_count == s->read_trigger) { - s->int_level |= PL011_INT_RX; + s->int_level |= INT_RX; pl011_update(s); } } @@ -343,8 +366,9 @@ static void pl011_receive(void *opaque, const uint8_t *buf, int size) static void pl011_event(void *opaque, QEMUChrEvent event) { - if (event == CHR_EVENT_BREAK) - pl011_put_fifo(opaque, 0x400); + if (event == CHR_EVENT_BREAK) { + pl011_put_fifo(opaque, DR_BE); + } } static void pl011_clock_update(void *opaque, ClockEvent event) @@ -358,6 +382,8 @@ static const MemoryRegionOps pl011_ops = { .read = pl011_read, .write = pl011_write, .endianness = DEVICE_NATIVE_ENDIAN, + .impl.min_access_size = 4, + .impl.max_access_size = 4, }; static bool pl011_clock_needed(void *opaque) |