[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 4/6] hw/char/stm32l4x5_usart: Add options for serial parameter
From: |
Arnaud Minier |
Subject: |
[PATCH v2 4/6] hw/char/stm32l4x5_usart: Add options for serial parameters setting |
Date: |
Sun, 24 Mar 2024 17:55:44 +0100 |
Add a function to change the settings of the
serial connection.
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 | 98 +++++++++++++++++++++++++++++++++++++++
hw/char/trace-events | 1 +
2 files changed, 99 insertions(+)
diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
index ec8c2f6e63..b4d11dd826 100644
--- a/hw/char/stm32l4x5_usart.c
+++ b/hw/char/stm32l4x5_usart.c
@@ -267,6 +267,92 @@ static void usart_cancel_transmit(Stm32l4x5UsartBaseState
*s)
}
}
+static void stm32l4x5_update_params(Stm32l4x5UsartBaseState *s)
+{
+ int speed, parity, data_bits, stop_bits;
+ uint32_t value, usart_div;
+ QEMUSerialSetParams ssp;
+
+ /* Select the parity type */
+ if (s->cr1 & R_CR1_PCE_MASK) {
+ if (s->cr1 & R_CR1_PS_MASK) {
+ parity = 'O';
+ } else {
+ parity = 'E';
+ }
+ } else {
+ parity = 'N';
+ }
+
+ /* Select the number of stop bits */
+ switch (FIELD_EX32(s->cr2, CR2, STOP)) {
+ case 0:
+ stop_bits = 1;
+ break;
+ case 2:
+ stop_bits = 2;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "UNIMPLEMENTED: fractionnal stop bits; CR2[13:12] = %x",
+ FIELD_EX32(s->cr2, CR2, STOP));
+ return;
+ }
+
+ /* Select the length of the word */
+ switch ((FIELD_EX32(s->cr1, CR1, M1) << 1) | FIELD_EX32(s->cr1, CR1, M0)) {
+ case 0:
+ data_bits = 8;
+ break;
+ case 1:
+ data_bits = 9;
+ break;
+ case 2:
+ data_bits = 7;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "UNDEFINED: invalid word length, CR1.M = 0b11");
+ return;
+ }
+
+ /* Select the baud rate */
+ value = FIELD_EX32(s->brr, BRR, BRR);
+ if (value < 16) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "UNDEFINED: BRR lesser than 16: %u", value);
+ return;
+ }
+
+ if (FIELD_EX32(s->cr1, CR1, OVER8) == 0) {
+ /*
+ * Oversampling by 16
+ * BRR = USARTDIV
+ */
+ usart_div = value;
+ } else {
+ /*
+ * Oversampling by 8
+ * - BRR[2:0] = USARTDIV[3:0] shifted 1 bit to the right.
+ * - BRR[3] must be kept cleared.
+ * - BRR[15:4] = USARTDIV[15:4]
+ * - The frequency is multiplied by 2
+ */
+ usart_div = ((value & 0xFFF0) | ((value & 0x0007) << 1)) / 2;
+ }
+
+ speed = clock_get_hz(s->clk) / usart_div;
+
+ ssp.speed = speed;
+ ssp.parity = parity;
+ ssp.data_bits = data_bits;
+ ssp.stop_bits = stop_bits;
+
+ qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+
+ trace_stm32l4x5_usart_update_params(speed, parity, data_bits, stop_bits);
+}
+
static void stm32l4x5_usart_base_reset_hold(Object *obj)
{
Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj);
@@ -365,16 +451,19 @@ static void stm32l4x5_usart_base_write(void *opaque,
hwaddr addr,
switch (addr) {
case A_CR1:
s->cr1 = value;
+ stm32l4x5_update_params(s);
stm32l4x5_update_irq(s);
return;
case A_CR2:
s->cr2 = value;
+ stm32l4x5_update_params(s);
return;
case A_CR3:
s->cr3 = value;
return;
case A_BRR:
s->brr = value;
+ stm32l4x5_update_params(s);
return;
case A_GTPR:
s->gtpr = value;
@@ -443,10 +532,19 @@ static void stm32l4x5_usart_base_init(Object *obj)
s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
}
+static int stm32l4x5_usart_base_post_load(void *opaque, int version_id)
+{
+ Stm32l4x5UsartBaseState *s = (Stm32l4x5UsartBaseState *)opaque;
+
+ stm32l4x5_update_params(s);
+ return 0;
+}
+
static const VMStateDescription vmstate_stm32l4x5_usart_base = {
.name = TYPE_STM32L4X5_USART_BASE,
.version_id = 1,
.minimum_version_id = 1,
+ .post_load = stm32l4x5_usart_base_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(cr1, Stm32l4x5UsartBaseState),
VMSTATE_UINT32(cr2, Stm32l4x5UsartBaseState),
diff --git a/hw/char/trace-events b/hw/char/trace-events
index f22f0ee2bc..8875758076 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -116,6 +116,7 @@ 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_receiver_not_enabled(uint8_t ue_bit, uint8_t re_bit) "USART:
Receiver not enabled, UE=0x%x, RE=0x%x"
+stm32l4x5_usart_update_params(int speed, uint8_t parity, int data, int stop)
"USART: speed: %d, parity: %c, data bits: %d, stop bits: %d"
# xen_console.c
xen_console_connect(unsigned int idx, unsigned int ring_ref, unsigned int
port, unsigned int limit) "idx %u ring_ref %u port %u limit %u"
--
2.34.1
- [PATCH v2 0/6] hw/char: Implement the STM32L4x5 USART, UART and LPUART, Arnaud Minier, 2024/03/24
- [PATCH v2 1/6] hw/misc/stm32l4x5_rcc: Propagate period when enabling a clock, Arnaud Minier, 2024/03/24
- [PATCH v2 2/6] hw/char: Implement STM32L4x5 USART skeleton, Arnaud Minier, 2024/03/24
- [PATCH v2 3/6] hw/char/stm32l4x5_usart: Enable serial read and write, Arnaud Minier, 2024/03/24
- [PATCH v2 4/6] hw/char/stm32l4x5_usart: Add options for serial parameters setting,
Arnaud Minier <=
- [PATCH v2 5/6] hw/arm: Add the USART to the stm32l4x5 SoC, Arnaud Minier, 2024/03/24
- [PATCH v2 6/6] tests/qtest: Add tests for the STM32L4x5 USART, Arnaud Minier, 2024/03/24
- Re: [PATCH v2 0/6] hw/char: Implement the STM32L4x5 USART, UART and LPUART, Peter Maydell, 2024/03/28