xref: /openbmc/qemu/hw/char/cadence_uart.c (revision 823dd48761a668c8e787cb9cf07234b656a05926)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * Device model for Cadence UART
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2010 Xilinx Inc.
549ab747fSPaolo Bonzini  * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
649ab747fSPaolo Bonzini  * Copyright (c) 2012 PetaLogix Pty Ltd.
749ab747fSPaolo Bonzini  * Written by Haibing Ma
849ab747fSPaolo Bonzini  *            M.Habib
949ab747fSPaolo Bonzini  *
1049ab747fSPaolo Bonzini  * This program is free software; you can redistribute it and/or
1149ab747fSPaolo Bonzini  * modify it under the terms of the GNU General Public License
1249ab747fSPaolo Bonzini  * as published by the Free Software Foundation; either version
1349ab747fSPaolo Bonzini  * 2 of the License, or (at your option) any later version.
1449ab747fSPaolo Bonzini  *
1549ab747fSPaolo Bonzini  * You should have received a copy of the GNU General Public License along
1649ab747fSPaolo Bonzini  * with this program; if not, see <http://www.gnu.org/licenses/>.
1749ab747fSPaolo Bonzini  */
1849ab747fSPaolo Bonzini 
1949ab747fSPaolo Bonzini #include "hw/sysbus.h"
20dccfcd0eSPaolo Bonzini #include "sysemu/char.h"
2149ab747fSPaolo Bonzini #include "qemu/timer.h"
2249ab747fSPaolo Bonzini 
2349ab747fSPaolo Bonzini #ifdef CADENCE_UART_ERR_DEBUG
2449ab747fSPaolo Bonzini #define DB_PRINT(...) do { \
2549ab747fSPaolo Bonzini     fprintf(stderr,  ": %s: ", __func__); \
2649ab747fSPaolo Bonzini     fprintf(stderr, ## __VA_ARGS__); \
2749ab747fSPaolo Bonzini     } while (0);
2849ab747fSPaolo Bonzini #else
2949ab747fSPaolo Bonzini     #define DB_PRINT(...)
3049ab747fSPaolo Bonzini #endif
3149ab747fSPaolo Bonzini 
3249ab747fSPaolo Bonzini #define UART_SR_INTR_RTRIG     0x00000001
3349ab747fSPaolo Bonzini #define UART_SR_INTR_REMPTY    0x00000002
3449ab747fSPaolo Bonzini #define UART_SR_INTR_RFUL      0x00000004
3549ab747fSPaolo Bonzini #define UART_SR_INTR_TEMPTY    0x00000008
3649ab747fSPaolo Bonzini #define UART_SR_INTR_TFUL      0x00000010
3749ab747fSPaolo Bonzini /* bits fields in CSR that correlate to CISR. If any of these bits are set in
3849ab747fSPaolo Bonzini  * SR, then the same bit in CISR is set high too */
3949ab747fSPaolo Bonzini #define UART_SR_TO_CISR_MASK   0x0000001F
4049ab747fSPaolo Bonzini 
4149ab747fSPaolo Bonzini #define UART_INTR_ROVR         0x00000020
4249ab747fSPaolo Bonzini #define UART_INTR_FRAME        0x00000040
4349ab747fSPaolo Bonzini #define UART_INTR_PARE         0x00000080
4449ab747fSPaolo Bonzini #define UART_INTR_TIMEOUT      0x00000100
4549ab747fSPaolo Bonzini #define UART_INTR_DMSI         0x00000200
4649ab747fSPaolo Bonzini 
4749ab747fSPaolo Bonzini #define UART_SR_RACTIVE    0x00000400
4849ab747fSPaolo Bonzini #define UART_SR_TACTIVE    0x00000800
4949ab747fSPaolo Bonzini #define UART_SR_FDELT      0x00001000
5049ab747fSPaolo Bonzini 
5149ab747fSPaolo Bonzini #define UART_CR_RXRST       0x00000001
5249ab747fSPaolo Bonzini #define UART_CR_TXRST       0x00000002
5349ab747fSPaolo Bonzini #define UART_CR_RX_EN       0x00000004
5449ab747fSPaolo Bonzini #define UART_CR_RX_DIS      0x00000008
5549ab747fSPaolo Bonzini #define UART_CR_TX_EN       0x00000010
5649ab747fSPaolo Bonzini #define UART_CR_TX_DIS      0x00000020
5749ab747fSPaolo Bonzini #define UART_CR_RST_TO      0x00000040
5849ab747fSPaolo Bonzini #define UART_CR_STARTBRK    0x00000080
5949ab747fSPaolo Bonzini #define UART_CR_STOPBRK     0x00000100
6049ab747fSPaolo Bonzini 
6149ab747fSPaolo Bonzini #define UART_MR_CLKS            0x00000001
6249ab747fSPaolo Bonzini #define UART_MR_CHRL            0x00000006
6349ab747fSPaolo Bonzini #define UART_MR_CHRL_SH         1
6449ab747fSPaolo Bonzini #define UART_MR_PAR             0x00000038
6549ab747fSPaolo Bonzini #define UART_MR_PAR_SH          3
6649ab747fSPaolo Bonzini #define UART_MR_NBSTOP          0x000000C0
6749ab747fSPaolo Bonzini #define UART_MR_NBSTOP_SH       6
6849ab747fSPaolo Bonzini #define UART_MR_CHMODE          0x00000300
6949ab747fSPaolo Bonzini #define UART_MR_CHMODE_SH       8
7049ab747fSPaolo Bonzini #define UART_MR_UCLKEN          0x00000400
7149ab747fSPaolo Bonzini #define UART_MR_IRMODE          0x00000800
7249ab747fSPaolo Bonzini 
7349ab747fSPaolo Bonzini #define UART_DATA_BITS_6       (0x3 << UART_MR_CHRL_SH)
7449ab747fSPaolo Bonzini #define UART_DATA_BITS_7       (0x2 << UART_MR_CHRL_SH)
7549ab747fSPaolo Bonzini #define UART_PARITY_ODD        (0x1 << UART_MR_PAR_SH)
7649ab747fSPaolo Bonzini #define UART_PARITY_EVEN       (0x0 << UART_MR_PAR_SH)
7749ab747fSPaolo Bonzini #define UART_STOP_BITS_1       (0x3 << UART_MR_NBSTOP_SH)
7849ab747fSPaolo Bonzini #define UART_STOP_BITS_2       (0x2 << UART_MR_NBSTOP_SH)
7949ab747fSPaolo Bonzini #define NORMAL_MODE            (0x0 << UART_MR_CHMODE_SH)
8049ab747fSPaolo Bonzini #define ECHO_MODE              (0x1 << UART_MR_CHMODE_SH)
8149ab747fSPaolo Bonzini #define LOCAL_LOOPBACK         (0x2 << UART_MR_CHMODE_SH)
8249ab747fSPaolo Bonzini #define REMOTE_LOOPBACK        (0x3 << UART_MR_CHMODE_SH)
8349ab747fSPaolo Bonzini 
8449ab747fSPaolo Bonzini #define RX_FIFO_SIZE           16
8549ab747fSPaolo Bonzini #define TX_FIFO_SIZE           16
8649ab747fSPaolo Bonzini #define UART_INPUT_CLK         50000000
8749ab747fSPaolo Bonzini 
8849ab747fSPaolo Bonzini #define R_CR       (0x00/4)
8949ab747fSPaolo Bonzini #define R_MR       (0x04/4)
9049ab747fSPaolo Bonzini #define R_IER      (0x08/4)
9149ab747fSPaolo Bonzini #define R_IDR      (0x0C/4)
9249ab747fSPaolo Bonzini #define R_IMR      (0x10/4)
9349ab747fSPaolo Bonzini #define R_CISR     (0x14/4)
9449ab747fSPaolo Bonzini #define R_BRGR     (0x18/4)
9549ab747fSPaolo Bonzini #define R_RTOR     (0x1C/4)
9649ab747fSPaolo Bonzini #define R_RTRIG    (0x20/4)
9749ab747fSPaolo Bonzini #define R_MCR      (0x24/4)
9849ab747fSPaolo Bonzini #define R_MSR      (0x28/4)
9949ab747fSPaolo Bonzini #define R_SR       (0x2C/4)
10049ab747fSPaolo Bonzini #define R_TX_RX    (0x30/4)
10149ab747fSPaolo Bonzini #define R_BDIV     (0x34/4)
10249ab747fSPaolo Bonzini #define R_FDEL     (0x38/4)
10349ab747fSPaolo Bonzini #define R_PMIN     (0x3C/4)
10449ab747fSPaolo Bonzini #define R_PWID     (0x40/4)
10549ab747fSPaolo Bonzini #define R_TTRIG    (0x44/4)
10649ab747fSPaolo Bonzini 
10749ab747fSPaolo Bonzini #define R_MAX (R_TTRIG + 1)
10849ab747fSPaolo Bonzini 
109534f6ff9SAndreas Färber #define TYPE_CADENCE_UART "cadence_uart"
110534f6ff9SAndreas Färber #define CADENCE_UART(obj) OBJECT_CHECK(UartState, (obj), TYPE_CADENCE_UART)
111534f6ff9SAndreas Färber 
11249ab747fSPaolo Bonzini typedef struct {
113059ca2bfSPeter Crosthwaite     /*< private >*/
114534f6ff9SAndreas Färber     SysBusDevice parent_obj;
115059ca2bfSPeter Crosthwaite     /*< public >*/
116534f6ff9SAndreas Färber 
11749ab747fSPaolo Bonzini     MemoryRegion iomem;
11849ab747fSPaolo Bonzini     uint32_t r[R_MAX];
11949ab747fSPaolo Bonzini     uint8_t r_fifo[RX_FIFO_SIZE];
12049ab747fSPaolo Bonzini     uint32_t rx_wpos;
12149ab747fSPaolo Bonzini     uint32_t rx_count;
12249ab747fSPaolo Bonzini     uint64_t char_tx_time;
12349ab747fSPaolo Bonzini     CharDriverState *chr;
12449ab747fSPaolo Bonzini     qemu_irq irq;
1251246b259SStefan Weil     QEMUTimer *fifo_trigger_handle;
1261246b259SStefan Weil     QEMUTimer *tx_time_handle;
12749ab747fSPaolo Bonzini } UartState;
12849ab747fSPaolo Bonzini 
12949ab747fSPaolo Bonzini static void uart_update_status(UartState *s)
13049ab747fSPaolo Bonzini {
13149ab747fSPaolo Bonzini     s->r[R_CISR] |= s->r[R_SR] & UART_SR_TO_CISR_MASK;
13249ab747fSPaolo Bonzini     qemu_set_irq(s->irq, !!(s->r[R_IMR] & s->r[R_CISR]));
13349ab747fSPaolo Bonzini }
13449ab747fSPaolo Bonzini 
13549ab747fSPaolo Bonzini static void fifo_trigger_update(void *opaque)
13649ab747fSPaolo Bonzini {
13749ab747fSPaolo Bonzini     UartState *s = (UartState *)opaque;
13849ab747fSPaolo Bonzini 
13949ab747fSPaolo Bonzini     s->r[R_CISR] |= UART_INTR_TIMEOUT;
14049ab747fSPaolo Bonzini 
14149ab747fSPaolo Bonzini     uart_update_status(s);
14249ab747fSPaolo Bonzini }
14349ab747fSPaolo Bonzini 
14449ab747fSPaolo Bonzini static void uart_tx_redo(UartState *s)
14549ab747fSPaolo Bonzini {
146bc72ad67SAlex Bligh     uint64_t new_tx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
14749ab747fSPaolo Bonzini 
148bc72ad67SAlex Bligh     timer_mod(s->tx_time_handle, new_tx_time + s->char_tx_time);
14949ab747fSPaolo Bonzini 
15049ab747fSPaolo Bonzini     s->r[R_SR] |= UART_SR_INTR_TEMPTY;
15149ab747fSPaolo Bonzini 
15249ab747fSPaolo Bonzini     uart_update_status(s);
15349ab747fSPaolo Bonzini }
15449ab747fSPaolo Bonzini 
15549ab747fSPaolo Bonzini static void uart_tx_write(void *opaque)
15649ab747fSPaolo Bonzini {
15749ab747fSPaolo Bonzini     UartState *s = (UartState *)opaque;
15849ab747fSPaolo Bonzini 
15949ab747fSPaolo Bonzini     uart_tx_redo(s);
16049ab747fSPaolo Bonzini }
16149ab747fSPaolo Bonzini 
16249ab747fSPaolo Bonzini static void uart_rx_reset(UartState *s)
16349ab747fSPaolo Bonzini {
16449ab747fSPaolo Bonzini     s->rx_wpos = 0;
16549ab747fSPaolo Bonzini     s->rx_count = 0;
1669121d02cSPeter Crosthwaite     if (s->chr) {
16749ab747fSPaolo Bonzini         qemu_chr_accept_input(s->chr);
1689121d02cSPeter Crosthwaite     }
16949ab747fSPaolo Bonzini 
17049ab747fSPaolo Bonzini     s->r[R_SR] |= UART_SR_INTR_REMPTY;
17149ab747fSPaolo Bonzini     s->r[R_SR] &= ~UART_SR_INTR_RFUL;
17249ab747fSPaolo Bonzini }
17349ab747fSPaolo Bonzini 
17449ab747fSPaolo Bonzini static void uart_tx_reset(UartState *s)
17549ab747fSPaolo Bonzini {
17649ab747fSPaolo Bonzini     s->r[R_SR] |= UART_SR_INTR_TEMPTY;
17749ab747fSPaolo Bonzini     s->r[R_SR] &= ~UART_SR_INTR_TFUL;
17849ab747fSPaolo Bonzini }
17949ab747fSPaolo Bonzini 
18049ab747fSPaolo Bonzini static void uart_send_breaks(UartState *s)
18149ab747fSPaolo Bonzini {
18249ab747fSPaolo Bonzini     int break_enabled = 1;
18349ab747fSPaolo Bonzini 
18449ab747fSPaolo Bonzini     qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
18549ab747fSPaolo Bonzini                                &break_enabled);
18649ab747fSPaolo Bonzini }
18749ab747fSPaolo Bonzini 
18849ab747fSPaolo Bonzini static void uart_parameters_setup(UartState *s)
18949ab747fSPaolo Bonzini {
19049ab747fSPaolo Bonzini     QEMUSerialSetParams ssp;
19149ab747fSPaolo Bonzini     unsigned int baud_rate, packet_size;
19249ab747fSPaolo Bonzini 
19349ab747fSPaolo Bonzini     baud_rate = (s->r[R_MR] & UART_MR_CLKS) ?
19449ab747fSPaolo Bonzini             UART_INPUT_CLK / 8 : UART_INPUT_CLK;
19549ab747fSPaolo Bonzini 
19649ab747fSPaolo Bonzini     ssp.speed = baud_rate / (s->r[R_BRGR] * (s->r[R_BDIV] + 1));
19749ab747fSPaolo Bonzini     packet_size = 1;
19849ab747fSPaolo Bonzini 
19949ab747fSPaolo Bonzini     switch (s->r[R_MR] & UART_MR_PAR) {
20049ab747fSPaolo Bonzini     case UART_PARITY_EVEN:
20149ab747fSPaolo Bonzini         ssp.parity = 'E';
20249ab747fSPaolo Bonzini         packet_size++;
20349ab747fSPaolo Bonzini         break;
20449ab747fSPaolo Bonzini     case UART_PARITY_ODD:
20549ab747fSPaolo Bonzini         ssp.parity = 'O';
20649ab747fSPaolo Bonzini         packet_size++;
20749ab747fSPaolo Bonzini         break;
20849ab747fSPaolo Bonzini     default:
20949ab747fSPaolo Bonzini         ssp.parity = 'N';
21049ab747fSPaolo Bonzini         break;
21149ab747fSPaolo Bonzini     }
21249ab747fSPaolo Bonzini 
21349ab747fSPaolo Bonzini     switch (s->r[R_MR] & UART_MR_CHRL) {
21449ab747fSPaolo Bonzini     case UART_DATA_BITS_6:
21549ab747fSPaolo Bonzini         ssp.data_bits = 6;
21649ab747fSPaolo Bonzini         break;
21749ab747fSPaolo Bonzini     case UART_DATA_BITS_7:
21849ab747fSPaolo Bonzini         ssp.data_bits = 7;
21949ab747fSPaolo Bonzini         break;
22049ab747fSPaolo Bonzini     default:
22149ab747fSPaolo Bonzini         ssp.data_bits = 8;
22249ab747fSPaolo Bonzini         break;
22349ab747fSPaolo Bonzini     }
22449ab747fSPaolo Bonzini 
22549ab747fSPaolo Bonzini     switch (s->r[R_MR] & UART_MR_NBSTOP) {
22649ab747fSPaolo Bonzini     case UART_STOP_BITS_1:
22749ab747fSPaolo Bonzini         ssp.stop_bits = 1;
22849ab747fSPaolo Bonzini         break;
22949ab747fSPaolo Bonzini     default:
23049ab747fSPaolo Bonzini         ssp.stop_bits = 2;
23149ab747fSPaolo Bonzini         break;
23249ab747fSPaolo Bonzini     }
23349ab747fSPaolo Bonzini 
23449ab747fSPaolo Bonzini     packet_size += ssp.data_bits + ssp.stop_bits;
23549ab747fSPaolo Bonzini     s->char_tx_time = (get_ticks_per_sec() / ssp.speed) * packet_size;
23649ab747fSPaolo Bonzini     qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
23749ab747fSPaolo Bonzini }
23849ab747fSPaolo Bonzini 
23949ab747fSPaolo Bonzini static int uart_can_receive(void *opaque)
24049ab747fSPaolo Bonzini {
24149ab747fSPaolo Bonzini     UartState *s = (UartState *)opaque;
24249ab747fSPaolo Bonzini 
24349ab747fSPaolo Bonzini     return RX_FIFO_SIZE - s->rx_count;
24449ab747fSPaolo Bonzini }
24549ab747fSPaolo Bonzini 
24649ab747fSPaolo Bonzini static void uart_ctrl_update(UartState *s)
24749ab747fSPaolo Bonzini {
24849ab747fSPaolo Bonzini     if (s->r[R_CR] & UART_CR_TXRST) {
24949ab747fSPaolo Bonzini         uart_tx_reset(s);
25049ab747fSPaolo Bonzini     }
25149ab747fSPaolo Bonzini 
25249ab747fSPaolo Bonzini     if (s->r[R_CR] & UART_CR_RXRST) {
25349ab747fSPaolo Bonzini         uart_rx_reset(s);
25449ab747fSPaolo Bonzini     }
25549ab747fSPaolo Bonzini 
25649ab747fSPaolo Bonzini     s->r[R_CR] &= ~(UART_CR_TXRST | UART_CR_RXRST);
25749ab747fSPaolo Bonzini 
25849ab747fSPaolo Bonzini     if ((s->r[R_CR] & UART_CR_TX_EN) && !(s->r[R_CR] & UART_CR_TX_DIS)) {
25949ab747fSPaolo Bonzini             uart_tx_redo(s);
26049ab747fSPaolo Bonzini     }
26149ab747fSPaolo Bonzini 
26249ab747fSPaolo Bonzini     if (s->r[R_CR] & UART_CR_STARTBRK && !(s->r[R_CR] & UART_CR_STOPBRK)) {
26349ab747fSPaolo Bonzini         uart_send_breaks(s);
26449ab747fSPaolo Bonzini     }
26549ab747fSPaolo Bonzini }
26649ab747fSPaolo Bonzini 
26749ab747fSPaolo Bonzini static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size)
26849ab747fSPaolo Bonzini {
26949ab747fSPaolo Bonzini     UartState *s = (UartState *)opaque;
270bc72ad67SAlex Bligh     uint64_t new_rx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
27149ab747fSPaolo Bonzini     int i;
27249ab747fSPaolo Bonzini 
27349ab747fSPaolo Bonzini     if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) {
27449ab747fSPaolo Bonzini         return;
27549ab747fSPaolo Bonzini     }
27649ab747fSPaolo Bonzini 
27749ab747fSPaolo Bonzini     s->r[R_SR] &= ~UART_SR_INTR_REMPTY;
27849ab747fSPaolo Bonzini 
27949ab747fSPaolo Bonzini     if (s->rx_count == RX_FIFO_SIZE) {
28049ab747fSPaolo Bonzini         s->r[R_CISR] |= UART_INTR_ROVR;
28149ab747fSPaolo Bonzini     } else {
28249ab747fSPaolo Bonzini         for (i = 0; i < size; i++) {
28349ab747fSPaolo Bonzini             s->r_fifo[s->rx_wpos] = buf[i];
28449ab747fSPaolo Bonzini             s->rx_wpos = (s->rx_wpos + 1) % RX_FIFO_SIZE;
28549ab747fSPaolo Bonzini             s->rx_count++;
28649ab747fSPaolo Bonzini 
28749ab747fSPaolo Bonzini             if (s->rx_count == RX_FIFO_SIZE) {
28849ab747fSPaolo Bonzini                 s->r[R_SR] |= UART_SR_INTR_RFUL;
28949ab747fSPaolo Bonzini                 break;
29049ab747fSPaolo Bonzini             }
29149ab747fSPaolo Bonzini 
29249ab747fSPaolo Bonzini             if (s->rx_count >= s->r[R_RTRIG]) {
29349ab747fSPaolo Bonzini                 s->r[R_SR] |= UART_SR_INTR_RTRIG;
29449ab747fSPaolo Bonzini             }
29549ab747fSPaolo Bonzini         }
296bc72ad67SAlex Bligh         timer_mod(s->fifo_trigger_handle, new_rx_time +
29749ab747fSPaolo Bonzini                                                 (s->char_tx_time * 4));
29849ab747fSPaolo Bonzini     }
29949ab747fSPaolo Bonzini     uart_update_status(s);
30049ab747fSPaolo Bonzini }
30149ab747fSPaolo Bonzini 
30249ab747fSPaolo Bonzini static void uart_write_tx_fifo(UartState *s, const uint8_t *buf, int size)
30349ab747fSPaolo Bonzini {
30449ab747fSPaolo Bonzini     if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) {
30549ab747fSPaolo Bonzini         return;
30649ab747fSPaolo Bonzini     }
30749ab747fSPaolo Bonzini 
308b52df465SEdgar E. Iglesias     qemu_chr_fe_write_all(s->chr, buf, size);
30949ab747fSPaolo Bonzini }
31049ab747fSPaolo Bonzini 
31149ab747fSPaolo Bonzini static void uart_receive(void *opaque, const uint8_t *buf, int size)
31249ab747fSPaolo Bonzini {
31349ab747fSPaolo Bonzini     UartState *s = (UartState *)opaque;
31449ab747fSPaolo Bonzini     uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
31549ab747fSPaolo Bonzini 
31649ab747fSPaolo Bonzini     if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
31749ab747fSPaolo Bonzini         uart_write_rx_fifo(opaque, buf, size);
31849ab747fSPaolo Bonzini     }
31949ab747fSPaolo Bonzini     if (ch_mode == REMOTE_LOOPBACK || ch_mode == ECHO_MODE) {
32049ab747fSPaolo Bonzini         uart_write_tx_fifo(s, buf, size);
32149ab747fSPaolo Bonzini     }
32249ab747fSPaolo Bonzini }
32349ab747fSPaolo Bonzini 
32449ab747fSPaolo Bonzini static void uart_event(void *opaque, int event)
32549ab747fSPaolo Bonzini {
32649ab747fSPaolo Bonzini     UartState *s = (UartState *)opaque;
32749ab747fSPaolo Bonzini     uint8_t buf = '\0';
32849ab747fSPaolo Bonzini 
32949ab747fSPaolo Bonzini     if (event == CHR_EVENT_BREAK) {
33049ab747fSPaolo Bonzini         uart_write_rx_fifo(opaque, &buf, 1);
33149ab747fSPaolo Bonzini     }
33249ab747fSPaolo Bonzini 
33349ab747fSPaolo Bonzini     uart_update_status(s);
33449ab747fSPaolo Bonzini }
33549ab747fSPaolo Bonzini 
33649ab747fSPaolo Bonzini static void uart_read_rx_fifo(UartState *s, uint32_t *c)
33749ab747fSPaolo Bonzini {
33849ab747fSPaolo Bonzini     if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) {
33949ab747fSPaolo Bonzini         return;
34049ab747fSPaolo Bonzini     }
34149ab747fSPaolo Bonzini 
34249ab747fSPaolo Bonzini     s->r[R_SR] &= ~UART_SR_INTR_RFUL;
34349ab747fSPaolo Bonzini 
34449ab747fSPaolo Bonzini     if (s->rx_count) {
34549ab747fSPaolo Bonzini         uint32_t rx_rpos =
34649ab747fSPaolo Bonzini                 (RX_FIFO_SIZE + s->rx_wpos - s->rx_count) % RX_FIFO_SIZE;
34749ab747fSPaolo Bonzini         *c = s->r_fifo[rx_rpos];
34849ab747fSPaolo Bonzini         s->rx_count--;
34949ab747fSPaolo Bonzini 
35049ab747fSPaolo Bonzini         if (!s->rx_count) {
35149ab747fSPaolo Bonzini             s->r[R_SR] |= UART_SR_INTR_REMPTY;
35249ab747fSPaolo Bonzini         }
35349ab747fSPaolo Bonzini         qemu_chr_accept_input(s->chr);
35449ab747fSPaolo Bonzini     } else {
35549ab747fSPaolo Bonzini         *c = 0;
35649ab747fSPaolo Bonzini         s->r[R_SR] |= UART_SR_INTR_REMPTY;
35749ab747fSPaolo Bonzini     }
35849ab747fSPaolo Bonzini 
35949ab747fSPaolo Bonzini     if (s->rx_count < s->r[R_RTRIG]) {
36049ab747fSPaolo Bonzini         s->r[R_SR] &= ~UART_SR_INTR_RTRIG;
36149ab747fSPaolo Bonzini     }
36249ab747fSPaolo Bonzini     uart_update_status(s);
36349ab747fSPaolo Bonzini }
36449ab747fSPaolo Bonzini 
36549ab747fSPaolo Bonzini static void uart_write(void *opaque, hwaddr offset,
36649ab747fSPaolo Bonzini                           uint64_t value, unsigned size)
36749ab747fSPaolo Bonzini {
36849ab747fSPaolo Bonzini     UartState *s = (UartState *)opaque;
36949ab747fSPaolo Bonzini 
37049ab747fSPaolo Bonzini     DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
37149ab747fSPaolo Bonzini     offset >>= 2;
37249ab747fSPaolo Bonzini     switch (offset) {
37349ab747fSPaolo Bonzini     case R_IER: /* ier (wts imr) */
37449ab747fSPaolo Bonzini         s->r[R_IMR] |= value;
37549ab747fSPaolo Bonzini         break;
37649ab747fSPaolo Bonzini     case R_IDR: /* idr (wtc imr) */
37749ab747fSPaolo Bonzini         s->r[R_IMR] &= ~value;
37849ab747fSPaolo Bonzini         break;
37949ab747fSPaolo Bonzini     case R_IMR: /* imr (read only) */
38049ab747fSPaolo Bonzini         break;
38149ab747fSPaolo Bonzini     case R_CISR: /* cisr (wtc) */
38249ab747fSPaolo Bonzini         s->r[R_CISR] &= ~value;
38349ab747fSPaolo Bonzini         break;
38449ab747fSPaolo Bonzini     case R_TX_RX: /* UARTDR */
38549ab747fSPaolo Bonzini         switch (s->r[R_MR] & UART_MR_CHMODE) {
38649ab747fSPaolo Bonzini         case NORMAL_MODE:
38749ab747fSPaolo Bonzini             uart_write_tx_fifo(s, (uint8_t *) &value, 1);
38849ab747fSPaolo Bonzini             break;
38949ab747fSPaolo Bonzini         case LOCAL_LOOPBACK:
39049ab747fSPaolo Bonzini             uart_write_rx_fifo(opaque, (uint8_t *) &value, 1);
39149ab747fSPaolo Bonzini             break;
39249ab747fSPaolo Bonzini         }
39349ab747fSPaolo Bonzini         break;
39449ab747fSPaolo Bonzini     default:
39549ab747fSPaolo Bonzini         s->r[offset] = value;
39649ab747fSPaolo Bonzini     }
39749ab747fSPaolo Bonzini 
39849ab747fSPaolo Bonzini     switch (offset) {
39949ab747fSPaolo Bonzini     case R_CR:
40049ab747fSPaolo Bonzini         uart_ctrl_update(s);
40149ab747fSPaolo Bonzini         break;
40249ab747fSPaolo Bonzini     case R_MR:
40349ab747fSPaolo Bonzini         uart_parameters_setup(s);
40449ab747fSPaolo Bonzini         break;
40549ab747fSPaolo Bonzini     }
406589bfb68SPeter Crosthwaite     uart_update_status(s);
40749ab747fSPaolo Bonzini }
40849ab747fSPaolo Bonzini 
40949ab747fSPaolo Bonzini static uint64_t uart_read(void *opaque, hwaddr offset,
41049ab747fSPaolo Bonzini         unsigned size)
41149ab747fSPaolo Bonzini {
41249ab747fSPaolo Bonzini     UartState *s = (UartState *)opaque;
41349ab747fSPaolo Bonzini     uint32_t c = 0;
41449ab747fSPaolo Bonzini 
41549ab747fSPaolo Bonzini     offset >>= 2;
41649ab747fSPaolo Bonzini     if (offset >= R_MAX) {
41749ab747fSPaolo Bonzini         c = 0;
41849ab747fSPaolo Bonzini     } else if (offset == R_TX_RX) {
41949ab747fSPaolo Bonzini         uart_read_rx_fifo(s, &c);
42049ab747fSPaolo Bonzini     } else {
42149ab747fSPaolo Bonzini        c = s->r[offset];
42249ab747fSPaolo Bonzini     }
42349ab747fSPaolo Bonzini 
42449ab747fSPaolo Bonzini     DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c);
42549ab747fSPaolo Bonzini     return c;
42649ab747fSPaolo Bonzini }
42749ab747fSPaolo Bonzini 
42849ab747fSPaolo Bonzini static const MemoryRegionOps uart_ops = {
42949ab747fSPaolo Bonzini     .read = uart_read,
43049ab747fSPaolo Bonzini     .write = uart_write,
43149ab747fSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
43249ab747fSPaolo Bonzini };
43349ab747fSPaolo Bonzini 
434*823dd487SPeter Crosthwaite static void cadence_uart_reset(DeviceState *dev)
43549ab747fSPaolo Bonzini {
436*823dd487SPeter Crosthwaite     UartState *s = CADENCE_UART(dev);
437*823dd487SPeter Crosthwaite 
43849ab747fSPaolo Bonzini     s->r[R_CR] = 0x00000128;
43949ab747fSPaolo Bonzini     s->r[R_IMR] = 0;
44049ab747fSPaolo Bonzini     s->r[R_CISR] = 0;
44149ab747fSPaolo Bonzini     s->r[R_RTRIG] = 0x00000020;
44249ab747fSPaolo Bonzini     s->r[R_BRGR] = 0x0000000F;
44349ab747fSPaolo Bonzini     s->r[R_TTRIG] = 0x00000020;
44449ab747fSPaolo Bonzini 
44549ab747fSPaolo Bonzini     uart_rx_reset(s);
44649ab747fSPaolo Bonzini     uart_tx_reset(s);
44749ab747fSPaolo Bonzini 
44849ab747fSPaolo Bonzini     s->rx_count = 0;
44949ab747fSPaolo Bonzini     s->rx_wpos = 0;
45049ab747fSPaolo Bonzini }
45149ab747fSPaolo Bonzini 
45249ab747fSPaolo Bonzini static int cadence_uart_init(SysBusDevice *dev)
45349ab747fSPaolo Bonzini {
454534f6ff9SAndreas Färber     UartState *s = CADENCE_UART(dev);
45549ab747fSPaolo Bonzini 
456300b1fc6SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &uart_ops, s, "uart", 0x1000);
45749ab747fSPaolo Bonzini     sysbus_init_mmio(dev, &s->iomem);
45849ab747fSPaolo Bonzini     sysbus_init_irq(dev, &s->irq);
45949ab747fSPaolo Bonzini 
460bc72ad67SAlex Bligh     s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
46149ab747fSPaolo Bonzini             (QEMUTimerCB *)fifo_trigger_update, s);
46249ab747fSPaolo Bonzini 
463bc72ad67SAlex Bligh     s->tx_time_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
46449ab747fSPaolo Bonzini             (QEMUTimerCB *)uart_tx_write, s);
46549ab747fSPaolo Bonzini 
46649ab747fSPaolo Bonzini     s->char_tx_time = (get_ticks_per_sec() / 9600) * 10;
46749ab747fSPaolo Bonzini 
46849ab747fSPaolo Bonzini     s->chr = qemu_char_get_next_serial();
46949ab747fSPaolo Bonzini 
47049ab747fSPaolo Bonzini     if (s->chr) {
47149ab747fSPaolo Bonzini         qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive,
47249ab747fSPaolo Bonzini                               uart_event, s);
47349ab747fSPaolo Bonzini     }
47449ab747fSPaolo Bonzini 
47549ab747fSPaolo Bonzini     return 0;
47649ab747fSPaolo Bonzini }
47749ab747fSPaolo Bonzini 
47849ab747fSPaolo Bonzini static int cadence_uart_post_load(void *opaque, int version_id)
47949ab747fSPaolo Bonzini {
48049ab747fSPaolo Bonzini     UartState *s = opaque;
48149ab747fSPaolo Bonzini 
48249ab747fSPaolo Bonzini     uart_parameters_setup(s);
48349ab747fSPaolo Bonzini     uart_update_status(s);
48449ab747fSPaolo Bonzini     return 0;
48549ab747fSPaolo Bonzini }
48649ab747fSPaolo Bonzini 
48749ab747fSPaolo Bonzini static const VMStateDescription vmstate_cadence_uart = {
48849ab747fSPaolo Bonzini     .name = "cadence_uart",
48949ab747fSPaolo Bonzini     .version_id = 1,
49049ab747fSPaolo Bonzini     .minimum_version_id = 1,
49149ab747fSPaolo Bonzini     .minimum_version_id_old = 1,
49249ab747fSPaolo Bonzini     .post_load = cadence_uart_post_load,
49349ab747fSPaolo Bonzini     .fields = (VMStateField[]) {
49449ab747fSPaolo Bonzini         VMSTATE_UINT32_ARRAY(r, UartState, R_MAX),
49549ab747fSPaolo Bonzini         VMSTATE_UINT8_ARRAY(r_fifo, UartState, RX_FIFO_SIZE),
49649ab747fSPaolo Bonzini         VMSTATE_UINT32(rx_count, UartState),
49749ab747fSPaolo Bonzini         VMSTATE_UINT32(rx_wpos, UartState),
49849ab747fSPaolo Bonzini         VMSTATE_TIMER(fifo_trigger_handle, UartState),
49949ab747fSPaolo Bonzini         VMSTATE_TIMER(tx_time_handle, UartState),
50049ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
50149ab747fSPaolo Bonzini     }
50249ab747fSPaolo Bonzini };
50349ab747fSPaolo Bonzini 
50449ab747fSPaolo Bonzini static void cadence_uart_class_init(ObjectClass *klass, void *data)
50549ab747fSPaolo Bonzini {
50649ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
50749ab747fSPaolo Bonzini     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
50849ab747fSPaolo Bonzini 
50949ab747fSPaolo Bonzini     sdc->init = cadence_uart_init;
51049ab747fSPaolo Bonzini     dc->vmsd = &vmstate_cadence_uart;
511*823dd487SPeter Crosthwaite     dc->reset = cadence_uart_reset;
51249ab747fSPaolo Bonzini }
51349ab747fSPaolo Bonzini 
51449ab747fSPaolo Bonzini static const TypeInfo cadence_uart_info = {
515534f6ff9SAndreas Färber     .name          = TYPE_CADENCE_UART,
51649ab747fSPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
51749ab747fSPaolo Bonzini     .instance_size = sizeof(UartState),
51849ab747fSPaolo Bonzini     .class_init    = cadence_uart_class_init,
51949ab747fSPaolo Bonzini };
52049ab747fSPaolo Bonzini 
52149ab747fSPaolo Bonzini static void cadence_uart_register_types(void)
52249ab747fSPaolo Bonzini {
52349ab747fSPaolo Bonzini     type_register_static(&cadence_uart_info);
52449ab747fSPaolo Bonzini }
52549ab747fSPaolo Bonzini 
52649ab747fSPaolo Bonzini type_init(cadence_uart_register_types)
527