149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * Arm PrimeCell PL011 UART
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Copyright (c) 2006 CodeSourcery.
549ab747fSPaolo Bonzini * Written by Paul Brook
649ab747fSPaolo Bonzini *
749ab747fSPaolo Bonzini * This code is licensed under the GPL.
849ab747fSPaolo Bonzini */
949ab747fSPaolo Bonzini
10a3c1ca56SPeter Maydell /*
11a3c1ca56SPeter Maydell * QEMU interface:
12a3c1ca56SPeter Maydell * + sysbus MMIO region 0: device registers
13a3c1ca56SPeter Maydell * + sysbus IRQ 0: UARTINTR (combined interrupt line)
14a3c1ca56SPeter Maydell * + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line)
15a3c1ca56SPeter Maydell * + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line)
16a3c1ca56SPeter Maydell * + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line)
17a3c1ca56SPeter Maydell * + sysbus IRQ 4: UARTMSINTR (momem status interrupt line)
18a3c1ca56SPeter Maydell * + sysbus IRQ 5: UARTEINTR (error interrupt line)
19a3c1ca56SPeter Maydell */
20a3c1ca56SPeter Maydell
218ef94f0bSPeter Maydell #include "qemu/osdep.h"
2211f2ee1dSPhilippe Mathieu-Daudé #include "qapi/error.h"
23694cf209SPeter Maydell #include "hw/char/pl011.h"
2464552b6bSMarkus Armbruster #include "hw/irq.h"
2549ab747fSPaolo Bonzini #include "hw/sysbus.h"
26aac63e0eSLuc Michel #include "hw/qdev-clock.h"
2711f2ee1dSPhilippe Mathieu-Daudé #include "hw/qdev-properties.h"
28ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
29d6454270SMarkus Armbruster #include "migration/vmstate.h"
304d43a603SMarc-André Lureau #include "chardev/char-fe.h"
31d60af909SJan Luebbe #include "chardev/char-serial.h"
3203dd024fSPaolo Bonzini #include "qemu/log.h"
330b8fa32fSMarkus Armbruster #include "qemu/module.h"
34041ac056SPeter Maydell #include "trace.h"
3549ab747fSPaolo Bonzini
pl011_create(hwaddr addr,qemu_irq irq,Chardev * chr)3611f2ee1dSPhilippe Mathieu-Daudé DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr)
3711f2ee1dSPhilippe Mathieu-Daudé {
3811f2ee1dSPhilippe Mathieu-Daudé DeviceState *dev;
3911f2ee1dSPhilippe Mathieu-Daudé SysBusDevice *s;
4011f2ee1dSPhilippe Mathieu-Daudé
4111f2ee1dSPhilippe Mathieu-Daudé dev = qdev_new("pl011");
4211f2ee1dSPhilippe Mathieu-Daudé s = SYS_BUS_DEVICE(dev);
4311f2ee1dSPhilippe Mathieu-Daudé qdev_prop_set_chr(dev, "chardev", chr);
4411f2ee1dSPhilippe Mathieu-Daudé sysbus_realize_and_unref(s, &error_fatal);
4511f2ee1dSPhilippe Mathieu-Daudé sysbus_mmio_map(s, 0, addr);
4611f2ee1dSPhilippe Mathieu-Daudé sysbus_connect_irq(s, 0, irq);
4711f2ee1dSPhilippe Mathieu-Daudé
4811f2ee1dSPhilippe Mathieu-Daudé return dev;
4911f2ee1dSPhilippe Mathieu-Daudé }
5011f2ee1dSPhilippe Mathieu-Daudé
5151141cabSPhilippe Mathieu-Daudé /* Flag Register, UARTFR */
52f576e073STong Ho #define PL011_FLAG_RI 0x100
5349ab747fSPaolo Bonzini #define PL011_FLAG_TXFE 0x80
5449ab747fSPaolo Bonzini #define PL011_FLAG_RXFF 0x40
5549ab747fSPaolo Bonzini #define PL011_FLAG_TXFF 0x20
5649ab747fSPaolo Bonzini #define PL011_FLAG_RXFE 0x10
57f576e073STong Ho #define PL011_FLAG_DCD 0x04
58f576e073STong Ho #define PL011_FLAG_DSR 0x02
59f576e073STong Ho #define PL011_FLAG_CTS 0x01
6049ab747fSPaolo Bonzini
6107738852SPhilippe Mathieu-Daudé /* Data Register, UARTDR */
6207738852SPhilippe Mathieu-Daudé #define DR_BE (1 << 10)
6307738852SPhilippe Mathieu-Daudé
64a3c1ca56SPeter Maydell /* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
65a3c1ca56SPeter Maydell #define INT_OE (1 << 10)
66a3c1ca56SPeter Maydell #define INT_BE (1 << 9)
67a3c1ca56SPeter Maydell #define INT_PE (1 << 8)
68a3c1ca56SPeter Maydell #define INT_FE (1 << 7)
69a3c1ca56SPeter Maydell #define INT_RT (1 << 6)
70a3c1ca56SPeter Maydell #define INT_TX (1 << 5)
71a3c1ca56SPeter Maydell #define INT_RX (1 << 4)
72a3c1ca56SPeter Maydell #define INT_DSR (1 << 3)
73a3c1ca56SPeter Maydell #define INT_DCD (1 << 2)
74a3c1ca56SPeter Maydell #define INT_CTS (1 << 1)
75a3c1ca56SPeter Maydell #define INT_RI (1 << 0)
76a3c1ca56SPeter Maydell #define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
77a3c1ca56SPeter Maydell #define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
78a3c1ca56SPeter Maydell
7907738852SPhilippe Mathieu-Daudé /* Line Control Register, UARTLCR_H */
8007738852SPhilippe Mathieu-Daudé #define LCR_FEN (1 << 4)
8107738852SPhilippe Mathieu-Daudé #define LCR_BRK (1 << 0)
8207738852SPhilippe Mathieu-Daudé
83f576e073STong Ho /* Control Register, UARTCR */
84f576e073STong Ho #define CR_OUT2 (1 << 13)
85f576e073STong Ho #define CR_OUT1 (1 << 12)
86f576e073STong Ho #define CR_RTS (1 << 11)
87f576e073STong Ho #define CR_DTR (1 << 10)
88f576e073STong Ho #define CR_TXE (1 << 8)
89f576e073STong Ho #define CR_LBE (1 << 7)
90b88cfee9SZheyu Ma #define CR_UARTEN (1 << 0)
91*10e3edd9SPeter Maydell
92b88cfee9SZheyu Ma /* Integer Baud Rate Divider, UARTIBRD */
93b88cfee9SZheyu Ma #define IBRD_MASK 0xffff
94*10e3edd9SPeter Maydell
95b88cfee9SZheyu Ma /* Fractional Baud Rate Divider, UARTFBRD */
9649ab747fSPaolo Bonzini #define FBRD_MASK 0x3f
9749ab747fSPaolo Bonzini
9849ab747fSPaolo Bonzini static const unsigned char pl011_id_arm[8] =
9949ab747fSPaolo Bonzini { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
10049ab747fSPaolo Bonzini static const unsigned char pl011_id_luminary[8] =
10151141cabSPhilippe Mathieu-Daudé { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
10251141cabSPhilippe Mathieu-Daudé
pl011_regname(hwaddr offset)10351141cabSPhilippe Mathieu-Daudé static const char *pl011_regname(hwaddr offset)
10451141cabSPhilippe Mathieu-Daudé {
10551141cabSPhilippe Mathieu-Daudé static const char *const rname[] = {
10651141cabSPhilippe Mathieu-Daudé [0] = "DR", [1] = "RSR", [6] = "FR", [8] = "ILPR", [9] = "IBRD",
10751141cabSPhilippe Mathieu-Daudé [10] = "FBRD", [11] = "LCRH", [12] = "CR", [13] = "IFLS", [14] = "IMSC",
10851141cabSPhilippe Mathieu-Daudé [15] = "RIS", [16] = "MIS", [17] = "ICR", [18] = "DMACR",
10951141cabSPhilippe Mathieu-Daudé };
11051141cabSPhilippe Mathieu-Daudé unsigned idx = offset >> 2;
11151141cabSPhilippe Mathieu-Daudé
11251141cabSPhilippe Mathieu-Daudé if (idx < ARRAY_SIZE(rname) && rname[idx]) {
11351141cabSPhilippe Mathieu-Daudé return rname[idx];
11451141cabSPhilippe Mathieu-Daudé }
11551141cabSPhilippe Mathieu-Daudé if (idx >= 0x3f8 && idx <= 0x400) {
11651141cabSPhilippe Mathieu-Daudé return "ID";
11751141cabSPhilippe Mathieu-Daudé }
11851141cabSPhilippe Mathieu-Daudé return "UNKN";
119a3c1ca56SPeter Maydell }
120a3c1ca56SPeter Maydell
121a3c1ca56SPeter Maydell /* Which bits in the interrupt status matter for each outbound IRQ line ? */
122a3c1ca56SPeter Maydell static const uint32_t irqmask[] = {
123a3c1ca56SPeter Maydell INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
124a3c1ca56SPeter Maydell INT_RX,
125a3c1ca56SPeter Maydell INT_TX,
126a3c1ca56SPeter Maydell INT_RT,
127a3c1ca56SPeter Maydell INT_MS,
128a3c1ca56SPeter Maydell INT_E,
129ab640bfcSAndreas Färber };
13049ab747fSPaolo Bonzini
pl011_update(PL011State * s)13149ab747fSPaolo Bonzini static void pl011_update(PL011State *s)
132a3c1ca56SPeter Maydell {
13349ab747fSPaolo Bonzini uint32_t flags;
13449ab747fSPaolo Bonzini int i;
135041ac056SPeter Maydell
136a3c1ca56SPeter Maydell flags = s->int_level & s->int_enabled;
137a3c1ca56SPeter Maydell trace_pl011_irq_state(flags != 0);
138a3c1ca56SPeter Maydell for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
13949ab747fSPaolo Bonzini qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
14049ab747fSPaolo Bonzini }
1419d88935cSEvgeny Iakovlev }
1429d88935cSEvgeny Iakovlev
pl011_loopback_enabled(PL011State * s)14307738852SPhilippe Mathieu-Daudé static bool pl011_loopback_enabled(PL011State *s)
1449d88935cSEvgeny Iakovlev {
1459d88935cSEvgeny Iakovlev return !!(s->cr & CR_LBE);
1469d88935cSEvgeny Iakovlev }
1479d88935cSEvgeny Iakovlev
pl011_is_fifo_enabled(PL011State * s)1489d88935cSEvgeny Iakovlev static bool pl011_is_fifo_enabled(PL011State *s)
1499d88935cSEvgeny Iakovlev {
1509d88935cSEvgeny Iakovlev return (s->lcr & LCR_FEN) != 0;
1519d88935cSEvgeny Iakovlev }
15223dcbfc0SEvgeny Iakovlev
pl011_get_fifo_depth(PL011State * s)15323dcbfc0SEvgeny Iakovlev static inline unsigned pl011_get_fifo_depth(PL011State *s)
15423dcbfc0SEvgeny Iakovlev {
15523dcbfc0SEvgeny Iakovlev /* Note: FIFO depth is expected to be power-of-2 */
15623dcbfc0SEvgeny Iakovlev return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1;
15723dcbfc0SEvgeny Iakovlev }
15823dcbfc0SEvgeny Iakovlev
pl011_reset_rx_fifo(PL011State * s)15923dcbfc0SEvgeny Iakovlev static inline void pl011_reset_rx_fifo(PL011State *s)
16023dcbfc0SEvgeny Iakovlev {
16123dcbfc0SEvgeny Iakovlev s->read_count = 0;
16249ab747fSPaolo Bonzini s->read_pos = 0;
16349ab747fSPaolo Bonzini
16449ab747fSPaolo Bonzini /* Reset FIFO flags */
165ab640bfcSAndreas Färber s->flags &= ~PL011_FLAG_RXFF;
16649ab747fSPaolo Bonzini s->flags |= PL011_FLAG_RXFE;
167041ac056SPeter Maydell }
16849ab747fSPaolo Bonzini
pl011_reset_tx_fifo(PL011State * s)16949ab747fSPaolo Bonzini static inline void pl011_reset_tx_fifo(PL011State *s)
17049ab747fSPaolo Bonzini {
17149ab747fSPaolo Bonzini /* Reset FIFO flags */
17249ab747fSPaolo Bonzini s->flags &= ~PL011_FLAG_TXFF;
17349ab747fSPaolo Bonzini s->flags |= PL011_FLAG_TXFE;
17449ab747fSPaolo Bonzini }
1759d88935cSEvgeny Iakovlev
pl011_fifo_rx_put(void * opaque,uint32_t value)17649ab747fSPaolo Bonzini static void pl011_fifo_rx_put(void *opaque, uint32_t value)
17749ab747fSPaolo Bonzini {
17849ab747fSPaolo Bonzini PL011State *s = (PL011State *)opaque;
17949ab747fSPaolo Bonzini int slot;
18049ab747fSPaolo Bonzini unsigned pipe_depth;
18122f7ff7fSPhilippe Mathieu-Daudé
182041ac056SPeter Maydell pipe_depth = pl011_get_fifo_depth(s);
183ce8f0905SRob Herring slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
18449ab747fSPaolo Bonzini s->read_fifo[slot] = value;
1855345fdb4SMarc-André Lureau s->read_count++;
186041ac056SPeter Maydell s->flags &= ~PL011_FLAG_RXFE;
187041ac056SPeter Maydell trace_pl011_fifo_rx_put(value, s->read_count);
188ce8f0905SRob Herring if (s->read_count == pipe_depth) {
189041ac056SPeter Maydell trace_pl011_fifo_rx_full();
190041ac056SPeter Maydell s->flags |= PL011_FLAG_RXFF;
19149ab747fSPaolo Bonzini }
192041ac056SPeter Maydell if (s->read_count == s->read_trigger) {
193041ac056SPeter Maydell s->int_level |= INT_RX;
19449ab747fSPaolo Bonzini pl011_update(s);
195041ac056SPeter Maydell }
196041ac056SPeter Maydell }
19749ab747fSPaolo Bonzini
pl011_loopback_tx(PL011State * s,uint32_t value)198041ac056SPeter Maydell static void pl011_loopback_tx(PL011State *s, uint32_t value)
199041ac056SPeter Maydell {
20049ab747fSPaolo Bonzini if (!pl011_loopback_enabled(s)) {
201041ac056SPeter Maydell return;
202041ac056SPeter Maydell }
20349ab747fSPaolo Bonzini
204041ac056SPeter Maydell /*
205041ac056SPeter Maydell * Caveat:
20649ab747fSPaolo Bonzini *
207041ac056SPeter Maydell * In real hardware, TX loopback happens at the serial-bit level
208041ac056SPeter Maydell * and then reassembled by the RX logics back into bytes and placed
20949ab747fSPaolo Bonzini * into the RX fifo. That is, loopback happens after TX fifo.
210041ac056SPeter Maydell *
211041ac056SPeter Maydell * Because the real hardware TX fifo is time-drained at the frame
21249ab747fSPaolo Bonzini * rate governed by the configured serial format, some loopback
213041ac056SPeter Maydell * bytes in TX fifo may still be able to get into the RX fifo
214041ac056SPeter Maydell * that could be full at times while being drained at software
21549ab747fSPaolo Bonzini * pace.
216041ac056SPeter Maydell *
217041ac056SPeter Maydell * In such scenario, the RX draining pace is the major factor
21849ab747fSPaolo Bonzini * deciding which loopback bytes get into the RX fifo, unless
219041ac056SPeter Maydell * hardware flow-control is enabled.
220041ac056SPeter Maydell *
22149ab747fSPaolo Bonzini * For simplicity, the above described is not emulated.
222041ac056SPeter Maydell */
223041ac056SPeter Maydell pl011_fifo_rx_put(s, value);
224041ac056SPeter Maydell }
225041ac056SPeter Maydell
pl011_write_txdata(PL011State * s,uint8_t data)226041ac056SPeter Maydell static void pl011_write_txdata(PL011State *s, uint8_t data)
22749ab747fSPaolo Bonzini {
22849ab747fSPaolo Bonzini if (!(s->cr & CR_UARTEN)) {
22976b09fafSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
230041ac056SPeter Maydell "PL011 data written to disabled UART\n");
231041ac056SPeter Maydell }
23249ab747fSPaolo Bonzini if (!(s->cr & CR_TXE)) {
233041ac056SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
23451141cabSPhilippe Mathieu-Daudé "PL011 data written to disabled TX UART\n");
235041ac056SPeter Maydell }
23649ab747fSPaolo Bonzini
23749ab747fSPaolo Bonzini /*
238ab640bfcSAndreas Färber * XXX this blocks entire thread. Rewrite to use
23949ab747fSPaolo Bonzini * qemu_chr_fe_write and background I/O callbacks
24049ab747fSPaolo Bonzini */
24149ab747fSPaolo Bonzini qemu_chr_fe_write_all(&s->chr, &data, 1);
24249ab747fSPaolo Bonzini pl011_loopback_tx(s, data);
24349ab747fSPaolo Bonzini s->int_level |= INT_TX;
24449ab747fSPaolo Bonzini pl011_update(s);
24507738852SPhilippe Mathieu-Daudé }
24649ab747fSPaolo Bonzini
pl011_read_rxdata(PL011State * s)24749ab747fSPaolo Bonzini static uint32_t pl011_read_rxdata(PL011State *s)
24849ab747fSPaolo Bonzini {
24949ab747fSPaolo Bonzini uint32_t c;
25049ab747fSPaolo Bonzini
25149ab747fSPaolo Bonzini s->flags &= ~PL011_FLAG_RXFF;
252aac63e0eSLuc Michel c = s->read_fifo[s->read_pos];
253aac63e0eSLuc Michel if (s->read_count > 0) {
254aac63e0eSLuc Michel s->read_count--;
255aac63e0eSLuc Michel s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1);
25631cb769cSBaruch Siach }
257aac63e0eSLuc Michel if (s->read_count == 0) {
258aac63e0eSLuc Michel s->flags |= PL011_FLAG_RXFE;
259aac63e0eSLuc Michel }
260aac63e0eSLuc Michel if (s->read_count == s->read_trigger - 1) {
261aac63e0eSLuc Michel s->int_level &= ~INT_RX;
262aac63e0eSLuc Michel }
263aac63e0eSLuc Michel trace_pl011_read_fifo(s->read_count);
264aac63e0eSLuc Michel s->rsr = c >> 8;
265aac63e0eSLuc Michel pl011_update(s);
266aac63e0eSLuc Michel qemu_chr_fe_accept_input(&s->chr);
267aac63e0eSLuc Michel return c;
268aac63e0eSLuc Michel }
269aac63e0eSLuc Michel
pl011_read(void * opaque,hwaddr offset,unsigned size)270aac63e0eSLuc Michel static uint64_t pl011_read(void *opaque, hwaddr offset,
271f576e073STong Ho unsigned size)
272f576e073STong Ho {
273f576e073STong Ho PL011State *s = (PL011State *)opaque;
274f576e073STong Ho uint64_t r;
275f576e073STong Ho
276f576e073STong Ho switch (offset >> 2) {
277f576e073STong Ho case 0: /* UARTDR */
278f576e073STong Ho r = pl011_read_rxdata(s);
279f576e073STong Ho break;
280f576e073STong Ho case 1: /* UARTRSR */
281f576e073STong Ho r = s->rsr;
282f576e073STong Ho break;
283f576e073STong Ho case 6: /* UARTFR */
284f576e073STong Ho r = s->flags;
285f576e073STong Ho break;
286f576e073STong Ho case 8: /* UARTILPR */
287f576e073STong Ho r = s->ilpr;
288f576e073STong Ho break;
289f576e073STong Ho case 9: /* UARTIBRD */
290f576e073STong Ho r = s->ibrd;
291f576e073STong Ho break;
292f576e073STong Ho case 10: /* UARTFBRD */
293f576e073STong Ho r = s->fbrd;
294f576e073STong Ho break;
295f576e073STong Ho case 11: /* UARTLCR_H */
296f576e073STong Ho r = s->lcr;
297f576e073STong Ho break;
298f576e073STong Ho case 12: /* UARTCR */
299f576e073STong Ho r = s->cr;
300f576e073STong Ho break;
301f576e073STong Ho case 13: /* UARTIFLS */
302f576e073STong Ho r = s->ifl;
303f576e073STong Ho break;
304f576e073STong Ho case 14: /* UARTIMSC */
305f576e073STong Ho r = s->int_enabled;
306f576e073STong Ho break;
307f576e073STong Ho case 15: /* UARTRIS */
308f576e073STong Ho r = s->int_level;
309f576e073STong Ho break;
310f576e073STong Ho case 16: /* UARTMIS */
311f576e073STong Ho r = s->int_level & s->int_enabled;
312f576e073STong Ho break;
313f576e073STong Ho case 18: /* UARTDMACR */
314f576e073STong Ho r = s->dmacr;
315f576e073STong Ho break;
316f576e073STong Ho case 0x3f8 ... 0x400:
317f576e073STong Ho r = s->id[(offset - 0xfe0) >> 2];
318f576e073STong Ho break;
319f576e073STong Ho default:
320f576e073STong Ho qemu_log_mask(LOG_GUEST_ERROR,
321f576e073STong Ho "pl011_read: Bad offset 0x%x\n", (int)offset);
322f576e073STong Ho r = 0;
323f576e073STong Ho break;
324f576e073STong Ho }
325f576e073STong Ho
326f576e073STong Ho trace_pl011_read(offset, r, pl011_regname(offset));
327f576e073STong Ho return r;
328f576e073STong Ho }
329f576e073STong Ho
pl011_set_read_trigger(PL011State * s)330f576e073STong Ho static void pl011_set_read_trigger(PL011State *s)
331f576e073STong Ho {
332f576e073STong Ho #if 0
333f576e073STong Ho /* The docs say the RX interrupt is triggered when the FIFO exceeds
334f576e073STong Ho the threshold. However linux only reads the FIFO in response to an
335f576e073STong Ho interrupt. Triggering the interrupt when the FIFO is non-empty seems
336f576e073STong Ho to make things work. */
337f576e073STong Ho if (s->lcr & LCR_FEN)
338f576e073STong Ho s->read_trigger = (s->ifl >> 1) & 0x1c;
339f576e073STong Ho else
340f576e073STong Ho #endif
341f576e073STong Ho s->read_trigger = 1;
342f576e073STong Ho }
343f576e073STong Ho
pl011_get_baudrate(const PL011State * s)344f576e073STong Ho static unsigned int pl011_get_baudrate(const PL011State *s)
345f576e073STong Ho {
346f576e073STong Ho uint64_t clk;
347f576e073STong Ho
348f576e073STong Ho if (s->ibrd == 0) {
349f576e073STong Ho return 0;
350f576e073STong Ho }
351f576e073STong Ho
352f576e073STong Ho clk = clock_get_hz(s->clk);
353f576e073STong Ho return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
35449ab747fSPaolo Bonzini }
35549ab747fSPaolo Bonzini
pl011_trace_baudrate_change(const PL011State * s)35649ab747fSPaolo Bonzini static void pl011_trace_baudrate_change(const PL011State *s)
357ab640bfcSAndreas Färber {
35849ab747fSPaolo Bonzini trace_pl011_baudrate_change(pl011_get_baudrate(s),
35949ab747fSPaolo Bonzini clock_get_hz(s->clk),
36051141cabSPhilippe Mathieu-Daudé s->ibrd, s->fbrd);
361041ac056SPeter Maydell }
36249ab747fSPaolo Bonzini
pl011_loopback_mdmctrl(PL011State * s)36349ab747fSPaolo Bonzini static void pl011_loopback_mdmctrl(PL011State *s)
36449ab747fSPaolo Bonzini {
36549ab747fSPaolo Bonzini uint32_t cr, fr, il;
3666ab3fc32SDaniel P. Berrange
3676ab3fc32SDaniel P. Berrange if (!pl011_loopback_enabled(s)) {
3685345fdb4SMarc-André Lureau return;
369f576e073STong Ho }
37022f7ff7fSPhilippe Mathieu-Daudé
37149ab747fSPaolo Bonzini /*
37249ab747fSPaolo Bonzini * Loopback software-driven modem control outputs to modem status inputs:
373ce8f0905SRob Herring * FR.RI <= CR.Out2
374ce8f0905SRob Herring * FR.DCD <= CR.Out1
37549ab747fSPaolo Bonzini * FR.CTS <= CR.RTS
37649ab747fSPaolo Bonzini * FR.DSR <= CR.DTR
37749ab747fSPaolo Bonzini *
37849ab747fSPaolo Bonzini * The loopback happens immediately even if this call is triggered
37951141cabSPhilippe Mathieu-Daudé * by setting only CR.LBE.
38049ab747fSPaolo Bonzini *
38149ab747fSPaolo Bonzini * CTS/RTS updates due to enabled hardware flow controls are not
38249ab747fSPaolo Bonzini * dealt with here.
383b88cfee9SZheyu Ma */
384aac63e0eSLuc Michel cr = s->cr;
38549ab747fSPaolo Bonzini fr = s->flags & ~(PL011_FLAG_RI | PL011_FLAG_DCD |
38649ab747fSPaolo Bonzini PL011_FLAG_DSR | PL011_FLAG_CTS);
387b88cfee9SZheyu Ma fr |= (cr & CR_OUT2) ? PL011_FLAG_RI : 0;
388aac63e0eSLuc Michel fr |= (cr & CR_OUT1) ? PL011_FLAG_DCD : 0;
38949ab747fSPaolo Bonzini fr |= (cr & CR_RTS) ? PL011_FLAG_CTS : 0;
39049ab747fSPaolo Bonzini fr |= (cr & CR_DTR) ? PL011_FLAG_DSR : 0;
39122709e90SRob Herring
39207738852SPhilippe Mathieu-Daudé /* Change interrupts based on updated FR */
39323dcbfc0SEvgeny Iakovlev il = s->int_level & ~(INT_DSR | INT_DCD | INT_CTS | INT_RI);
39422709e90SRob Herring il |= (fr & PL011_FLAG_DSR) ? INT_DSR : 0;
39507738852SPhilippe Mathieu-Daudé il |= (fr & PL011_FLAG_DCD) ? INT_DCD : 0;
39607738852SPhilippe Mathieu-Daudé il |= (fr & PL011_FLAG_CTS) ? INT_CTS : 0;
397d60af909SJan Luebbe il |= (fr & PL011_FLAG_RI) ? INT_RI : 0;
398d60af909SJan Luebbe
399f576e073STong Ho s->flags = fr;
400d60af909SJan Luebbe s->int_level = il;
40149ab747fSPaolo Bonzini pl011_update(s);
40249ab747fSPaolo Bonzini }
40349ab747fSPaolo Bonzini
pl011_loopback_break(PL011State * s,int brk_enable)40449ab747fSPaolo Bonzini static void pl011_loopback_break(PL011State *s, int brk_enable)
405f576e073STong Ho {
40649ab747fSPaolo Bonzini if (brk_enable) {
407f576e073STong Ho pl011_loopback_tx(s, DR_BE);
40849ab747fSPaolo Bonzini }
40949ab747fSPaolo Bonzini }
41049ab747fSPaolo Bonzini
pl011_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)41149ab747fSPaolo Bonzini static void pl011_write(void *opaque, hwaddr offset,
41249ab747fSPaolo Bonzini uint64_t value, unsigned size)
41349ab747fSPaolo Bonzini {
41449ab747fSPaolo Bonzini PL011State *s = (PL011State *)opaque;
41549ab747fSPaolo Bonzini unsigned char ch;
41649ab747fSPaolo Bonzini
41749ab747fSPaolo Bonzini trace_pl011_write(offset, value, pl011_regname(offset));
41849ab747fSPaolo Bonzini
41949ab747fSPaolo Bonzini switch (offset >> 2) {
42049ab747fSPaolo Bonzini case 0: /* UARTDR */
42149ab747fSPaolo Bonzini ch = value;
42249ab747fSPaolo Bonzini pl011_write_txdata(s, ch);
42349ab747fSPaolo Bonzini break;
42449ab747fSPaolo Bonzini case 1: /* UARTRSR/UARTECR */
42549ab747fSPaolo Bonzini s->rsr = 0;
42649ab747fSPaolo Bonzini break;
42749ab747fSPaolo Bonzini case 6: /* UARTFR */
42849ab747fSPaolo Bonzini /* Writes to Flag register are ignored. */
42976b09fafSPeter Maydell break;
43049ab747fSPaolo Bonzini case 8: /* UARTILPR */
43149ab747fSPaolo Bonzini s->ilpr = value;
43249ab747fSPaolo Bonzini break;
43349ab747fSPaolo Bonzini case 9: /* UARTIBRD */
43449ab747fSPaolo Bonzini s->ibrd = value & IBRD_MASK;
435ab640bfcSAndreas Färber pl011_trace_baudrate_change(s);
436041ac056SPeter Maydell break;
43749ab747fSPaolo Bonzini case 10: /* UARTFBRD */
4389d88935cSEvgeny Iakovlev s->fbrd = value & FBRD_MASK;
439041ac056SPeter Maydell pl011_trace_baudrate_change(s);
440041ac056SPeter Maydell break;
44149ab747fSPaolo Bonzini case 11: /* UARTLCR_H */
44249ab747fSPaolo Bonzini /* Reset the FIFO state on FIFO enable or disable */
44349ab747fSPaolo Bonzini if ((s->lcr ^ value) & LCR_FEN) {
44449ab747fSPaolo Bonzini pl011_reset_rx_fifo(s);
445ab640bfcSAndreas Färber pl011_reset_tx_fifo(s);
44649ab747fSPaolo Bonzini }
4479d88935cSEvgeny Iakovlev if ((s->lcr ^ value) & LCR_BRK) {
44849ab747fSPaolo Bonzini int break_enable = value & LCR_BRK;
4499d88935cSEvgeny Iakovlev qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
4509d88935cSEvgeny Iakovlev &break_enable);
45149ab747fSPaolo Bonzini pl011_loopback_break(s, break_enable);
45249ab747fSPaolo Bonzini }
45349ab747fSPaolo Bonzini s->lcr = value;
454041ac056SPeter Maydell pl011_set_read_trigger(s);
4559d88935cSEvgeny Iakovlev break;
456041ac056SPeter Maydell case 12: /* UARTCR */
45749ab747fSPaolo Bonzini /* ??? Need to implement the enable bit. */
45849ab747fSPaolo Bonzini s->cr = value;
45949ab747fSPaolo Bonzini pl011_loopback_mdmctrl(s);
46022f7ff7fSPhilippe Mathieu-Daudé break;
46149ab747fSPaolo Bonzini case 13: /* UARTIFS */
46249ab747fSPaolo Bonzini s->ifl = value;
46349ab747fSPaolo Bonzini pl011_set_read_trigger(s);
46449ab747fSPaolo Bonzini break;
46549ab747fSPaolo Bonzini case 14: /* UARTIMSC */
46649ab747fSPaolo Bonzini s->int_enabled = value;
467f576e073STong Ho pl011_update(s);
468f576e073STong Ho break;
469f576e073STong Ho case 17: /* UARTICR */
470f576e073STong Ho s->int_level &= ~value;
471f576e073STong Ho pl011_update(s);
472f576e073STong Ho break;
473f576e073STong Ho case 18: /* UARTDMACR */
474f576e073STong Ho s->dmacr = value;
475f576e073STong Ho if (value & 3) {
47649ab747fSPaolo Bonzini qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
47749ab747fSPaolo Bonzini }
47849ab747fSPaolo Bonzini break;
479083b266fSPhilippe Mathieu-Daudé default:
48049ab747fSPaolo Bonzini qemu_log_mask(LOG_GUEST_ERROR,
481f576e073STong Ho "pl011_write: Bad offset 0x%x\n", (int)offset);
48207738852SPhilippe Mathieu-Daudé }
48307738852SPhilippe Mathieu-Daudé }
48449ab747fSPaolo Bonzini
pl011_can_receive(void * opaque)48549ab747fSPaolo Bonzini static int pl011_can_receive(void *opaque)
4865ee0abedSPeter Maydell {
487aac63e0eSLuc Michel PL011State *s = (PL011State *)opaque;
488aac63e0eSLuc Michel int r;
489aac63e0eSLuc Michel
490aac63e0eSLuc Michel r = s->read_count < pl011_get_fifo_depth(s);
491aac63e0eSLuc Michel trace_pl011_can_receive(s->lcr, s->read_count, r);
492aac63e0eSLuc Michel return r;
49349ab747fSPaolo Bonzini }
49449ab747fSPaolo Bonzini
pl011_receive(void * opaque,const uint8_t * buf,int size)49549ab747fSPaolo Bonzini static void pl011_receive(void *opaque, const uint8_t *buf, int size)
49649ab747fSPaolo Bonzini {
4977e66d52bSPhilippe Mathieu-Daudé /*
4987e66d52bSPhilippe Mathieu-Daudé * In loopback mode, the RX input signal is internally disconnected
49949ab747fSPaolo Bonzini * from the entire receiving logics; thus, all inputs are ignored,
50049ab747fSPaolo Bonzini * and BREAK detection on RX input signal is also not performed.
501e6fa978dSGavin Shan */
502e6fa978dSGavin Shan if (pl011_loopback_enabled(opaque)) {
503e6fa978dSGavin Shan return;
504e6fa978dSGavin Shan }
505e6fa978dSGavin Shan
506e6fa978dSGavin Shan pl011_fifo_rx_put(opaque, *buf);
507e6fa978dSGavin Shan }
508aac63e0eSLuc Michel
pl011_event(void * opaque,QEMUChrEvent event)509aac63e0eSLuc Michel static void pl011_event(void *opaque, QEMUChrEvent event)
510aac63e0eSLuc Michel {
511aac63e0eSLuc Michel if (event == CHR_EVENT_BREAK && !pl011_loopback_enabled(opaque)) {
512e6fa978dSGavin Shan pl011_fifo_rx_put(opaque, DR_BE);
5132f6cab05SRichard Henderson }
514aac63e0eSLuc Michel }
515aac63e0eSLuc Michel
pl011_clock_update(void * opaque,ClockEvent event)516aac63e0eSLuc Michel static void pl011_clock_update(void *opaque, ClockEvent event)
517aac63e0eSLuc Michel {
518aac63e0eSLuc Michel PL011State *s = PL011(opaque);
51913ea96faSEvgeny Iakovlev
52013ea96faSEvgeny Iakovlev pl011_trace_baudrate_change(s);
52113ea96faSEvgeny Iakovlev }
52213ea96faSEvgeny Iakovlev
52313ea96faSEvgeny Iakovlev static const MemoryRegionOps pl011_ops = {
52413ea96faSEvgeny Iakovlev .read = pl011_read,
52513ea96faSEvgeny Iakovlev .write = pl011_write,
52613ea96faSEvgeny Iakovlev .endianness = DEVICE_NATIVE_ENDIAN,
52713ea96faSEvgeny Iakovlev .impl.min_access_size = 4,
52813ea96faSEvgeny Iakovlev .impl.max_access_size = 4,
52913ea96faSEvgeny Iakovlev };
53013ea96faSEvgeny Iakovlev
pl011_clock_needed(void * opaque)53113ea96faSEvgeny Iakovlev static bool pl011_clock_needed(void *opaque)
53213ea96faSEvgeny Iakovlev {
53313ea96faSEvgeny Iakovlev PL011State *s = PL011(opaque);
53413ea96faSEvgeny Iakovlev
53513ea96faSEvgeny Iakovlev return s->migrate_clk;
53613ea96faSEvgeny Iakovlev }
53713ea96faSEvgeny Iakovlev
53813ea96faSEvgeny Iakovlev static const VMStateDescription vmstate_pl011_clock = {
53913ea96faSEvgeny Iakovlev .name = "pl011/clock",
540b88cfee9SZheyu Ma .version_id = 1,
541b88cfee9SZheyu Ma .minimum_version_id = 1,
542b88cfee9SZheyu Ma .needed = pl011_clock_needed,
54313ea96faSEvgeny Iakovlev .fields = (const VMStateField[]) {
54413ea96faSEvgeny Iakovlev VMSTATE_CLOCK(clk, PL011State),
54513ea96faSEvgeny Iakovlev VMSTATE_END_OF_LIST()
54649ab747fSPaolo Bonzini }
54749ab747fSPaolo Bonzini };
548ce8f0905SRob Herring
pl011_post_load(void * opaque,int version_id)549ce8f0905SRob Herring static int pl011_post_load(void *opaque, int version_id)
55013ea96faSEvgeny Iakovlev {
5512f6cab05SRichard Henderson PL011State* s = opaque;
552ab640bfcSAndreas Färber
553ab640bfcSAndreas Färber /* Sanity-check input state */
554ab640bfcSAndreas Färber if (s->read_pos >= ARRAY_SIZE(s->read_fifo) ||
555ce8f0905SRob Herring s->read_count > ARRAY_SIZE(s->read_fifo)) {
556ab640bfcSAndreas Färber return -1;
557ab640bfcSAndreas Färber }
558ab640bfcSAndreas Färber
559ab640bfcSAndreas Färber if (!pl011_is_fifo_enabled(s) && s->read_count > 0 && s->read_pos > 0) {
5609d88935cSEvgeny Iakovlev /*
561ab640bfcSAndreas Färber * Older versions of PL011 didn't ensure that the single
562ab640bfcSAndreas Färber * character in the FIFO in FIFO-disabled mode is in
563ab640bfcSAndreas Färber * element 0 of the array; convert to follow the current
564ab640bfcSAndreas Färber * code's assumptions.
565ab640bfcSAndreas Färber */
566ab640bfcSAndreas Färber s->read_fifo[0] = s->read_fifo[s->read_pos];
567ab640bfcSAndreas Färber s->read_pos = 0;
56849ab747fSPaolo Bonzini }
569aac63e0eSLuc Michel
5702f6cab05SRichard Henderson s->ibrd &= IBRD_MASK;
571aac63e0eSLuc Michel s->fbrd &= FBRD_MASK;
572aac63e0eSLuc Michel
57349ab747fSPaolo Bonzini return 0;
57449ab747fSPaolo Bonzini }
57549ab747fSPaolo Bonzini
576f0d1d2c1Sxiaoqiang zhao static const VMStateDescription vmstate_pl011 = {
577f0d1d2c1Sxiaoqiang zhao .name = "pl011",
578e6fa978dSGavin Shan .version_id = 2,
579f0d1d2c1Sxiaoqiang zhao .minimum_version_id = 2,
580f0d1d2c1Sxiaoqiang zhao .post_load = pl011_post_load,
581f0d1d2c1Sxiaoqiang zhao .fields = (const VMStateField[]) {
58271ffe1a0SAndreas Färber VMSTATE_UNUSED(sizeof(uint32_t)),
58349ab747fSPaolo Bonzini VMSTATE_UINT32(flags, PL011State),
58471ffe1a0SAndreas Färber VMSTATE_UINT32(lcr, PL011State),
58571ffe1a0SAndreas Färber VMSTATE_UINT32(rsr, PL011State),
586a3c1ca56SPeter Maydell VMSTATE_UINT32(cr, PL011State),
58749ab747fSPaolo Bonzini VMSTATE_UINT32(dmacr, PL011State),
588300b1fc6SPaolo Bonzini VMSTATE_UINT32(int_enabled, PL011State),
58971ffe1a0SAndreas Färber VMSTATE_UINT32(int_level, PL011State),
590a3c1ca56SPeter Maydell VMSTATE_UINT32_ARRAY(read_fifo, PL011State, PL011_FIFO_DEPTH),
591a3c1ca56SPeter Maydell VMSTATE_UINT32(ilpr, PL011State),
592a3c1ca56SPeter Maydell VMSTATE_UINT32(ibrd, PL011State),
59349ab747fSPaolo Bonzini VMSTATE_UINT32(fbrd, PL011State),
5945ee0abedSPeter Maydell VMSTATE_UINT32(ifl, PL011State),
5955ee0abedSPeter Maydell VMSTATE_INT32(read_pos, PL011State),
596aac63e0eSLuc Michel VMSTATE_INT32(read_count, PL011State),
59771ffe1a0SAndreas Färber VMSTATE_INT32(read_trigger, PL011State),
59871ffe1a0SAndreas Färber VMSTATE_END_OF_LIST()
59971ffe1a0SAndreas Färber },
60071ffe1a0SAndreas Färber .subsections = (const VMStateDescription * const []) {
60171ffe1a0SAndreas Färber &vmstate_pl011_clock,
60271ffe1a0SAndreas Färber NULL
60371ffe1a0SAndreas Färber }
6045345fdb4SMarc-André Lureau };
60581517ba3SAnton Nefedov
60649ab747fSPaolo Bonzini static Property pl011_properties[] = {
60749ab747fSPaolo Bonzini DEFINE_PROP_CHR("chardev", PL011State, chr),
6083b7a165eSEvgeny Iakovlev DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true),
6093b7a165eSEvgeny Iakovlev DEFINE_PROP_END_OF_LIST(),
6103b7a165eSEvgeny Iakovlev };
6113b7a165eSEvgeny Iakovlev
pl011_init(Object * obj)6123b7a165eSEvgeny Iakovlev static void pl011_init(Object *obj)
6133b7a165eSEvgeny Iakovlev {
6143b7a165eSEvgeny Iakovlev SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
6153b7a165eSEvgeny Iakovlev PL011State *s = PL011(obj);
6163b7a165eSEvgeny Iakovlev int i;
6173b7a165eSEvgeny Iakovlev
6183b7a165eSEvgeny Iakovlev memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
6193b7a165eSEvgeny Iakovlev sysbus_init_mmio(sbd, &s->iomem);
6203b7a165eSEvgeny Iakovlev for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
6213b7a165eSEvgeny Iakovlev sysbus_init_irq(sbd, &s->irq[i]);
6223b7a165eSEvgeny Iakovlev }
62323dcbfc0SEvgeny Iakovlev
62423dcbfc0SEvgeny Iakovlev s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
6253b7a165eSEvgeny Iakovlev ClockUpdate);
6263b7a165eSEvgeny Iakovlev
62771ffe1a0SAndreas Färber s->id = pl011_id_arm;
62849ab747fSPaolo Bonzini }
62971ffe1a0SAndreas Färber
pl011_realize(DeviceState * dev,Error ** errp)63049ab747fSPaolo Bonzini static void pl011_realize(DeviceState *dev, Error **errp)
63171ffe1a0SAndreas Färber {
6323b7a165eSEvgeny Iakovlev PL011State *s = PL011(dev);
63371ffe1a0SAndreas Färber
6344f67d30bSMarc-André Lureau qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
63549ab747fSPaolo Bonzini pl011_event, NULL, s, NULL, true);
63649ab747fSPaolo Bonzini }
63749ab747fSPaolo Bonzini
pl011_reset(DeviceState * dev)63871ffe1a0SAndreas Färber static void pl011_reset(DeviceState *dev)
63949ab747fSPaolo Bonzini {
640ab640bfcSAndreas Färber PL011State *s = PL011(dev);
64171ffe1a0SAndreas Färber
64271ffe1a0SAndreas Färber s->lcr = 0;
64349ab747fSPaolo Bonzini s->rsr = 0;
64449ab747fSPaolo Bonzini s->dmacr = 0;
64571ffe1a0SAndreas Färber s->int_enabled = 0;
64649ab747fSPaolo Bonzini s->int_level = 0;
64771ffe1a0SAndreas Färber s->ilpr = 0;
64849ab747fSPaolo Bonzini s->ibrd = 0;
64971ffe1a0SAndreas Färber s->fbrd = 0;
65049ab747fSPaolo Bonzini s->read_trigger = 1;
65149ab747fSPaolo Bonzini s->ifl = 0x12;
65249ab747fSPaolo Bonzini s->cr = 0x300;
653694cf209SPeter Maydell s->flags = 0;
65471ffe1a0SAndreas Färber pl011_reset_rx_fifo(s);
65571ffe1a0SAndreas Färber pl011_reset_tx_fifo(s);
65649ab747fSPaolo Bonzini }
65749ab747fSPaolo Bonzini
pl011_class_init(ObjectClass * oc,void * data)65849ab747fSPaolo Bonzini static void pl011_class_init(ObjectClass *oc, void *data)
65949ab747fSPaolo Bonzini {
66049ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(oc);
66149ab747fSPaolo Bonzini
66249ab747fSPaolo Bonzini dc->realize = pl011_realize;
66349ab747fSPaolo Bonzini device_class_set_legacy_reset(dc, pl011_reset);
66449ab747fSPaolo Bonzini dc->vmsd = &vmstate_pl011;
665 device_class_set_props(dc, pl011_properties);
666 }
667
668 static const TypeInfo pl011_arm_info = {
669 .name = TYPE_PL011,
670 .parent = TYPE_SYS_BUS_DEVICE,
671 .instance_size = sizeof(PL011State),
672 .instance_init = pl011_init,
673 .class_init = pl011_class_init,
674 };
675
pl011_luminary_init(Object * obj)676 static void pl011_luminary_init(Object *obj)
677 {
678 PL011State *s = PL011(obj);
679
680 s->id = pl011_id_luminary;
681 }
682
683 static const TypeInfo pl011_luminary_info = {
684 .name = TYPE_PL011_LUMINARY,
685 .parent = TYPE_PL011,
686 .instance_init = pl011_luminary_init,
687 };
688
pl011_register_types(void)689 static void pl011_register_types(void)
690 {
691 type_register_static(&pl011_arm_info);
692 type_register_static(&pl011_luminary_info);
693 }
694
695 type_init(pl011_register_types)
696