@samitouri / QOSamiQemu / commits / e6051fa61b

hw/char: sifive_uart: Implement txctrl.txen and rxctrl.rxen

Implement txctrl.txen and rxctrl.rxen as follows: * txctrl.txen The txen bit controls whether the Tx channel is active. When cleared, transmission of Tx FIFO contents is suppressed, and the txd pin is driven high. * rxctrl.rxen: The rxen bit controls whether the Rx channel is active. When cleared, the state of the rxd pin is ignored, and no characters will be enqueued into the Rx FIFO. Therefore, the Tx FIFO should not be dequeued when txctrl.txen is cleared, and the Rx FIFO should not be enqueued when rxctrl.rxen is cleared. Signed-off-by: Frank Chang <frank.chang@sifive.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260312033201.1619554-2-frank.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Frank Chang committed Mar 12, 2026 at 11:31 UTC e6051fa61b9f6fe9c40d8392b6da1f33e9d88332
2 files changed +22 -7
hw/char/sifive_uart.c
+20 -7
@@ -78,6 +78,11 @@ static gboolean sifive_uart_xmit(void *do_not_use, GIOCondition cond,
78 return G_SOURCE_REMOVE;
79 }
80
81 + /* Don't pop the FIFO if transmit is disabled. */
82 + if (!SIFIVE_UART_TXEN(s->txctrl)) {
83 + return G_SOURCE_REMOVE;
84 + }
85 +
86 /* Don't pop the FIFO in case the write fails */
87 characters = fifo8_peek_bufptr(&s->tx_fifo,
88 fifo8_num_used(&s->tx_fifo), &numptr);
@@ -106,11 +111,19 @@ static gboolean sifive_uart_xmit(void *do_not_use, GIOCondition cond,
111 return G_SOURCE_REMOVE;
112 }
113
109 -static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
110 - int size)
114 +static void sifive_uart_trigger_tx_fifo(SiFiveUARTState *s)
115 {
116 uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
117
118 + if (!timer_pending(s->fifo_trigger_handle)) {
119 + timer_mod(s->fifo_trigger_handle, current_time +
120 + TX_INTERRUPT_TRIGGER_DELAY_NS);
121 + }
122 +}
123 +
124 +static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
125 + int size)
126 +{
127 if (size > fifo8_num_free(&s->tx_fifo)) {
128 size = fifo8_num_free(&s->tx_fifo);
129 qemu_log_mask(LOG_GUEST_ERROR, "sifive_uart: TX FIFO overflow.\n");
@@ -124,10 +137,7 @@ static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
137 s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
138 }
139
127 - if (!timer_pending(s->fifo_trigger_handle)) {
128 - timer_mod(s->fifo_trigger_handle, current_time +
129 - TX_INTERRUPT_TRIGGER_DELAY_NS);
130 - }
140 + sifive_uart_trigger_tx_fifo(s);
141 }
142
143 static uint64_t
@@ -184,6 +194,9 @@ sifive_uart_write(void *opaque, hwaddr addr,
194 return;
195 case SIFIVE_UART_TXCTRL:
196 s->txctrl = val64;
197 + if (SIFIVE_UART_TXEN(s->txctrl) && !fifo8_is_empty(&s->tx_fifo)) {
198 + sifive_uart_trigger_tx_fifo(s);
199 + }
200 return;
201 case SIFIVE_UART_RXCTRL:
202 s->rxctrl = val64;
@@ -231,7 +244,7 @@ static int sifive_uart_can_rx(void *opaque)
244 {
245 SiFiveUARTState *s = opaque;
246
234 - return s->rx_fifo_len < sizeof(s->rx_fifo);
247 + return SIFIVE_UART_RXEN(s->rxctrl) && (s->rx_fifo_len < sizeof(s->rx_fifo));
248 }
249
250 static void sifive_uart_event(void *opaque, QEMUChrEvent event)
include/hw/char/sifive_uart.h
+2
@@ -51,6 +51,8 @@ enum {
51
52 #define SIFIVE_UART_TXFIFO_FULL 0x80000000
53
54 +#define SIFIVE_UART_TXEN(txctrl) (txctrl & 0x1)
55 +#define SIFIVE_UART_RXEN(rxctrl) (rxctrl & 0x1)
56 #define SIFIVE_UART_GET_TXCNT(txctrl) ((txctrl >> 16) & 0x7)
57 #define SIFIVE_UART_GET_RXCNT(rxctrl) ((rxctrl >> 16) & 0x7)
58