[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 4/7] hw/char/stm32l4x5_usart: Enable serial read and write
From: |
Arnaud Minier |
Subject: |
[PATCH 4/7] hw/char/stm32l4x5_usart: Enable serial read and write |
Date: |
Sun, 17 Mar 2024 11:39:15 +0100 |
Implement the ability to read and write characters to the
usart using the serial port.
Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
---
hw/char/stm32l4x5_usart.c | 105 +++++++++++++++++++++++++++++++++++++-
hw/char/trace-events | 1 +
2 files changed, 105 insertions(+), 1 deletion(-)
diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
index f58bd56875..958d05a56d 100644
--- a/hw/char/stm32l4x5_usart.c
+++ b/hw/char/stm32l4x5_usart.c
@@ -154,6 +154,71 @@ REG32(RDR, 0x24)
REG32(TDR, 0x28)
FIELD(TDR, TDR, 0, 8)
+static int stm32l4x5_usart_base_can_receive(void *opaque)
+{
+ Stm32l4x5UsartBaseState *s = opaque;
+
+ if (!(s->isr & R_ISR_RXNE_MASK)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s)
+{
+ if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK)) ||
+ ((s->isr & R_ISR_CMF_MASK) && (s->cr1 & R_CR1_CMIE_MASK)) ||
+ ((s->isr & R_ISR_ABRF_MASK) && (s->cr1 & R_CR1_RXNEIE_MASK)) ||
+ ((s->isr & R_ISR_EOBF_MASK) && (s->cr1 & R_CR1_EOBIE_MASK)) ||
+ ((s->isr & R_ISR_RTOF_MASK) && (s->cr1 & R_CR1_RTOIE_MASK)) ||
+ ((s->isr & R_ISR_CTSIF_MASK) && (s->cr3 & R_CR3_CTSIE_MASK)) ||
+ ((s->isr & R_ISR_LBDF_MASK) && (s->cr2 & R_CR2_LBDIE_MASK)) ||
+ ((s->isr & R_ISR_TXE_MASK) && (s->cr1 & R_CR1_TXEIE_MASK)) ||
+ ((s->isr & R_ISR_TC_MASK) && (s->cr1 & R_CR1_TCIE_MASK)) ||
+ ((s->isr & R_ISR_RXNE_MASK) && (s->cr1 & R_CR1_RXNEIE_MASK)) ||
+ ((s->isr & R_ISR_IDLE_MASK) && (s->cr1 & R_CR1_IDLEIE_MASK)) ||
+ ((s->isr & R_ISR_ORE_MASK) &&
+ ((s->cr1 & R_CR1_RXNEIE_MASK) || (s->cr3 & R_CR3_EIE_MASK))) ||
+ /* TODO: Handle NF ? */
+ ((s->isr & R_ISR_FE_MASK) && (s->cr3 & R_CR3_EIE_MASK)) ||
+ ((s->isr & R_ISR_PE_MASK) && (s->cr1 & R_CR1_PEIE_MASK))) {
+ qemu_irq_raise(s->irq);
+ trace_stm32l4x5_usart_irq_raised(s->isr);
+ } else {
+ qemu_irq_lower(s->irq);
+ trace_stm32l4x5_usart_irq_lowered();
+ }
+}
+
+static void stm32l4x5_usart_base_receive(void *opaque, const uint8_t *buf, int
size)
+{
+ Stm32l4x5UsartBaseState *s = opaque;
+
+ if (!((s->cr1 & R_CR1_UE_MASK) && (s->cr1 & R_CR1_RE_MASK))) {
+ /* USART not enabled - drop the chars */
+ trace_stm32l4x5_usart_error("Dropping the chars\n");
+ return;
+ }
+
+ /* Check if overrun detection is enabled and if there is an overrun */
+ if (!(s->cr3 & R_CR3_OVRDIS_MASK) && (s->isr & R_ISR_RXNE_MASK)) {
+ /*
+ * A character has been received while
+ * the previous has not been read = Overrun.
+ */
+ s->isr |= R_ISR_ORE_MASK;
+ trace_stm32l4x5_usart_overrun_detected(s->rdr, *buf);
+ } else {
+ /* No overrun */
+ s->rdr = *buf;
+ s->isr |= R_ISR_RXNE_MASK;
+ trace_stm32l4x5_usart_rx(s->rdr);
+ }
+
+ stm32l4x5_update_irq(s);
+}
+
static void stm32l4x5_usart_base_reset_hold(Object *obj)
{
Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj);
@@ -168,6 +233,21 @@ static void stm32l4x5_usart_base_reset_hold(Object *obj)
s->isr = 0x020000C0 | R_ISR_TXE_MASK;
s->rdr = 0x00000000;
s->tdr = 0x00000000;
+
+ stm32l4x5_update_irq(s);
+}
+
+static void usart_update_rqr(Stm32l4x5UsartBaseState *s, uint32_t value)
+{
+ /* TXFRQ */
+ /* Reset RXNE flag */
+ if (value & R_RQR_RXFRQ_MASK) {
+ s->isr &= ~R_ISR_RXNE_MASK;
+ }
+ /* MMRQ */
+ /* SBKRQ */
+ /* ABRRQ */
+ stm32l4x5_update_irq(s);
}
static uint64_t stm32l4x5_usart_base_read(void *opaque, hwaddr addr,
@@ -209,7 +289,8 @@ static uint64_t stm32l4x5_usart_base_read(void *opaque,
hwaddr addr,
case A_RDR:
retvalue = FIELD_EX32(s->rdr, RDR, RDR);
/* Reset RXNE flag */
- s->isr &= ~USART_ISR_RXNE;
+ s->isr &= ~R_ISR_RXNE_MASK;
+ stm32l4x5_update_irq(s);
break;
case A_TDR:
retvalue = FIELD_EX32(s->tdr, TDR, TDR);
@@ -237,6 +318,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr
addr,
switch (addr) {
case A_CR1:
s->cr1 = value;
+ stm32l4x5_update_irq(s);
return;
case A_CR2:
s->cr2 = value;
@@ -254,6 +336,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr
addr,
s->rtor = value;
return;
case A_RQR:
+ usart_update_rqr(s, value);
return;
case A_ISR:
qemu_log_mask(LOG_GUEST_ERROR,
@@ -262,6 +345,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr
addr,
case A_ICR:
/* Clear the status flags */
s->isr &= ~value;
+ stm32l4x5_update_irq(s);
return;
case A_RDR:
qemu_log_mask(LOG_GUEST_ERROR,
@@ -269,6 +353,21 @@ static void stm32l4x5_usart_base_write(void *opaque,
hwaddr addr,
return;
case A_TDR:
s->tdr = value;
+ ch = value & R_TDR_TDR_MASK;
+ /*
+ * 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);
+ /*
+ * XXX I/O are currently synchronous, making it impossible for
+ * software to observe transient states where TXE or TC aren't
+ * set. Unlike TXE however, which is read-only, software may
+ * clear TC by writing 0 to the ISR register, so set it again
+ * on each write.
+ */
+ s->isr |= R_ISR_TC_MASK;
+ stm32l4x5_update_irq(s);
return;
default:
qemu_log_mask(LOG_GUEST_ERROR,
@@ -338,6 +437,10 @@ static void stm32l4x5_usart_base_realize(DeviceState *dev,
Error **errp)
error_setg(errp, "USART clock must be wired up by SoC code");
return;
}
+
+ qemu_chr_fe_set_handlers(&s->chr, stm32l4x5_usart_base_can_receive,
+ stm32l4x5_usart_base_receive, NULL, NULL,
+ s, NULL, true);
}
static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 9f5fda0eb8..0cda3dfed0 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -114,6 +114,7 @@ stm32l4x5_usart_rx(uint8_t c) "USART: got character 0x%x
from backend"
stm32l4x5_usart_tx(uint8_t c) "USART: character 0x%x sent to backend"
stm32l4x5_usart_irq_raised(uint32_t reg) "USART: IRQ raised: 0x%08"PRIx32
stm32l4x5_usart_irq_lowered(void) "USART: IRQ lowered"
+stm32l4x5_usart_overrun_detected(uint8_t current, uint8_t received) "USART:
Overrun detected, RDR='0x%x', received 0x%x"
stm32l4x5_usart_error(const char* error) "USART Error: %s"
# xen_console.c
--
2.34.1
- [PATCH 0/7] hw/char: Implement the STM32L4x5 USART, UART and LPUART, Arnaud Minier, 2024/03/17
- [PATCH 2/7] hw/char: Implement STM32L4x5 USART skeleton, Arnaud Minier, 2024/03/17
- [PATCH 1/7] hw/misc/stm32l4x5_rcc: Propagate period when enabling a clock, Arnaud Minier, 2024/03/17
- [PATCH 3/7] hw/char/stm32l4x5_usart: Add USART, UART, LPUART types, Arnaud Minier, 2024/03/17
- [PATCH 5/7] hw/char/stm32l4x5_usart: Add options for serial parameters setting, Arnaud Minier, 2024/03/17
- [PATCH 4/7] hw/char/stm32l4x5_usart: Enable serial read and write,
Arnaud Minier <=
- [PATCH 6/7] hw/arm: Add the USART to the stm32l4x5 SoC, Arnaud Minier, 2024/03/17
- [PATCH 7/7] tests/qtest: Add tests for the STM32L4x5 USART, Arnaud Minier, 2024/03/17