diff mbox

Fix TXE/TXEIE support in the STM32 USART model

Message ID 20160905204025.30922-1-wpaul@windriver.com (mailing list archive)
State New, archived
Headers show

Commit Message

Bill Paul Sept. 5, 2016, 8:40 p.m. UTC
This commit attempts to fix the behavior of the TX FIFO Empty bit in
the STM32 USART driver. The two changes are:

1) After wrtiting to the data register, don't clear the TXE
bit in the status register. The way this model works, the FIFO is
effectively always empty. This is because we dump each character to
qemu_chr_fe_write_all() right away and unlike real hardware we don't
have to wait for the appropriate bits to be written to the I/O pins.

2) Implement support for the TXEIE (TXE interrupt enable) bit in CR1. When
OS driver code unmasks this bit and TXE is set, this should trigger an
interrupt to let the OS know the channel is now empty and it can send again.

ChibiOS depends on the correct behavior of the TXE and the TXEIE interrupt.
It checks to see if the TXE bit is set before trying to write any
characters. however at the outset TXE is clear, so it blocks forever
(or until you press a key at the serial console, which causes an RX
interrupt that unjams in).

Also once a character has been written, it waits for a TXEIE interrupt
before sending the next character in a string. With these two fixes, it can
now write to the serial port sucessfully.

Signed-off-by: Bill Paul <wpaul@windriver.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/char/stm32f2xx_usart.c         | 7 ++++++-
 include/hw/char/stm32f2xx_usart.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 15657ab..5671a7d 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -156,7 +156,6 @@  static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
                 qemu_chr_fe_write_all(s->chr, &ch, 1);
             }
             s->usart_sr |= USART_SR_TC;
-            s->usart_sr &= ~USART_SR_TXE;
         }
         return;
     case USART_BRR:
@@ -168,6 +167,12 @@  static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
                 s->usart_sr & USART_SR_RXNE) {
                 qemu_set_irq(s->irq, 1);
             }
+
+            if (s->usart_cr1 & USART_CR1_TXEIE &&
+                s->usart_sr & USART_SR_TXE) {
+                qemu_set_irq(s->irq, 1);
+            }
+
         return;
     case USART_CR2:
         s->usart_cr2 = value;
diff --git a/include/hw/char/stm32f2xx_usart.h b/include/hw/char/stm32f2xx_usart.h
index b97f192..2820209 100644
--- a/include/hw/char/stm32f2xx_usart.h
+++ b/include/hw/char/stm32f2xx_usart.h
@@ -44,6 +44,7 @@ 
 #define USART_SR_RXNE (1 << 5)
 
 #define USART_CR1_UE  (1 << 13)
+#define USART_CR1_TXEIE (1 << 7)
 #define USART_CR1_RXNEIE  (1 << 5)
 #define USART_CR1_TE  (1 << 3)
 #define USART_CR1_RE  (1 << 2)