[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 5/7] hw/char/stm32l4x5_usart: Add options for serial paramete
From: |
Peter Maydell |
Subject: |
Re: [PATCH 5/7] hw/char/stm32l4x5_usart: Add options for serial parameters setting |
Date: |
Fri, 22 Mar 2024 18:25:45 +0000 |
On Sun, 17 Mar 2024 at 10:41, Arnaud Minier
<arnaud.minier@telecom-paris.fr> wrote:
>
> 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 | 97 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 97 insertions(+)
>
> diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
> index 958d05a56d..95e792d09d 100644
> --- a/hw/char/stm32l4x5_usart.c
> +++ b/hw/char/stm32l4x5_usart.c
> @@ -165,6 +165,91 @@ static int stm32l4x5_usart_base_can_receive(void *opaque)
> return 0;
> }
>
> +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 */
> + value = FIELD_EX32(s->cr2, CR2, STOP);
> + if (value == 0b00) {
> + stop_bits = 1;
> + } else if (value == 0b10) {
> + stop_bits = 2;
> + } else {
I think this would read a little more clearly as
switch (FIELD_EX32(s->cr2, CR2, STOP)) {
case 0:
stop_bits = 1;
break;
case 2:
stop_bits = 2;
break;
default:
[error case code]
}
rather than using an if-else ladder. Similarly below.
> + /* TODO: raise an error here */
> + stop_bits = 1;
> + error_report(
> + "UNIMPLEMENTED: fractionnal stop bits; CR2[13:12] = %x",
> + value);
We generally use qemu_log_mask(LOG_UNIMP, ...) for
"this was a valid thing for the guest to do but our implementation
doesn't handle it", and qemu_log_mask(LOG_GUEST_ERROR, ...) for
"this was an invalid thing for the guest to do" (eg programming register
fields to reserved/undefined values), rather than using error_report().
> + return;
> + }
> +
> + /* Select the length of the word */
> + value = (FIELD_EX32(s->cr1, CR1, M1) << 1) | FIELD_EX32(s->cr1, CR1, M0);
> + if (value == 0b00) {
> + data_bits = 8;
> + } else if (value == 0b01) {
> + data_bits = 9;
> + } else if (value == 0b01) {
> + data_bits = 7;
These two arms both check against the same value, so one of them
must be wrong...
> + } else {
> + /* TODO: Raise an error here */
> + data_bits = 8;
> + error_report("UNDEFINED: invalid word length, CR1.M = 0b11");
> + return;
> + }
> +
> + /* Select the baud rate */
> + value = FIELD_EX32(s->brr, BRR, BRR);
> + if (value < 16) {
> + /* TODO: Raise an error here */
> + error_report("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, 0);
This is slightly weird indentation.
> +}
> +
> static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s)
> {
> if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK)) ||
> @@ -318,16 +403,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;
> @@ -409,10 +497,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),
> --
thanks
-- PMM
- [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
- Re: [PATCH 5/7] hw/char/stm32l4x5_usart: Add options for serial parameters setting,
Peter Maydell <=
- [PATCH 4/7] hw/char/stm32l4x5_usart: Enable serial read and write, Arnaud Minier, 2024/03/17
- [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