From: Peter Maydell <peter.maydell@linaro.org>
To: Jacob Abrams <satur9nine@gmail.com>
Cc: qemu-devel@nongnu.org, philmd@linaro.org
Subject: Re: [PATCH] hw/char/stm32l4x5_usart.c: Fix ACK and min access size
Date: Fri, 6 Sep 2024 17:12:44 +0100 [thread overview]
Message-ID: <CAFEAcA9wP7f_yPYNJmaTDe1bB8cPifErAGpjtsNPKsR0s_65Sg@mail.gmail.com> (raw)
In-Reply-To: <20240902061944.526873-1-satur9nine@gmail.com>
On Mon, 2 Sept 2024 at 14:38, Jacob Abrams <satur9nine@gmail.com> wrote:
>
> These changes allow the official STM32L4xx HAL UART driver to function
> properly with the b-l475e-iot01a machine.
>
> Modifying USART_CR1 TE bit should alter USART_ISR TEACK bit, and
> likewise for RE and REACK bit.
>
> USART registers may be accessed via 16-bit instructions.
>
> Reseting USART_CR1 UE bit should restore ISR to default value.
>
> Fixes: 87b77e6e01ca ("hw/char/stm32l4x5_usart: Enable serial read and write")
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2540
> Signed-off-by: Jacob Abrams <satur9nine@gmail.com>
Thanks for this patch. I have one question below, and one
minor nit.
> ---
> hw/char/stm32l4x5_usart.c | 29 +++++++++++++++++++---
> tests/qtest/stm32l4x5_usart-test.c | 39 +++++++++++++++++++++++++++++-
> 2 files changed, 64 insertions(+), 4 deletions(-)
>
> diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
> index fc5dcac0c4..859fc6236a 100644
> --- a/hw/char/stm32l4x5_usart.c
> +++ b/hw/char/stm32l4x5_usart.c
> @@ -154,6 +154,28 @@ REG32(RDR, 0x24)
> REG32(TDR, 0x28)
> FIELD(TDR, TDR, 0, 9)
>
> +#define ISR_RESET_VALUE (0x020000C0)
> +
> +static void stm32l4x5_update_isr(Stm32l4x5UsartBaseState *s)
> +{
> + if (!(s->cr1 & R_CR1_UE_MASK)) {
> + s->isr = ISR_RESET_VALUE;
> + return;
> + }
> +
> + if (s->cr1 & R_CR1_TE_MASK) {
> + s->isr |= R_ISR_TEACK_MASK;
> + } else {
> + s->isr &= ~R_ISR_TEACK_MASK;
> + }
> +
> + if (s->cr1 & R_CR1_RE_MASK) {
> + s->isr |= R_ISR_REACK_MASK;
> + } else {
> + s->isr &= ~R_ISR_REACK_MASK;
> + }
> +}
Should we be doing these things based on the value of
the CR1 bits (as this code does), or instead do them
when the bit changes from 0 to 1 (or 1 to 0)?
The wording in the datasheet seems unclear to me; my
impression is that hardware designers often like to
do these things on transitions rather than level based,
but of course you can design h/w both ways...
I guess it could be tested on real hardware:
* write CR1.TE = 1
* wait for ISR.TEACK = 1
* write ISR.TEACK = 0
* write CR1.TE = 1 (i.e. write again to the register
without changing its value)
* does ISR.TEACK go to 1 again, or does it stay 0?
> +
> static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s)
> {
> if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK)) ||
> @@ -367,7 +389,7 @@ static void stm32l4x5_usart_base_reset_hold(Object *obj, ResetType type)
> s->brr = 0x00000000;
> s->gtpr = 0x00000000;
> s->rtor = 0x00000000;
> - s->isr = 0x020000C0;
> + s->isr = ISR_RESET_VALUE;
> s->rdr = 0x00000000;
> s->tdr = 0x00000000;
>
> @@ -456,6 +478,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
> case A_CR1:
> s->cr1 = value;
> stm32l4x5_update_params(s);
> + stm32l4x5_update_isr(s);
> stm32l4x5_update_irq(s);
> return;
> case A_CR2:
> @@ -508,12 +531,12 @@ static const MemoryRegionOps stm32l4x5_usart_base_ops = {
> .endianness = DEVICE_NATIVE_ENDIAN,
> .valid = {
> .max_access_size = 4,
> - .min_access_size = 4,
> + .min_access_size = 2,
> .unaligned = false
> },
> .impl = {
> .max_access_size = 4,
> - .min_access_size = 4,
> + .min_access_size = 2,
> .unaligned = false
> },
The effect of these is that a 16-bit write not aligned
to a (4-aligned) register offset will generate a GUEST_ERROR
logged message, and a 16-bit write aligned to a 4-aligned
register offset will write the value zero-extended to 32 bits.
That seems reasonable to me.
> };
> diff --git a/tests/qtest/stm32l4x5_usart-test.c b/tests/qtest/stm32l4x5_usart-test.c
> index 8902518233..ef886074c0 100644
> --- a/tests/qtest/stm32l4x5_usart-test.c
> +++ b/tests/qtest/stm32l4x5_usart-test.c
> @@ -36,6 +36,8 @@ REG32(GTPR, 0x10)
> REG32(RTOR, 0x14)
> REG32(RQR, 0x18)
> REG32(ISR, 0x1C)
> + FIELD(ISR, REACK, 22, 1)
> + FIELD(ISR, TEACK, 21, 1)
> FIELD(ISR, TXE, 7, 1)
> FIELD(ISR, RXNE, 5, 1)
> FIELD(ISR, ORE, 3, 1)
> @@ -191,7 +193,7 @@ static void init_uart(QTestState *qts)
>
> /* Enable the transmitter, the receiver and the USART. */
> qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
> - R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK);
> + cr1 | R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK);
> }
>
> static void test_write_read(void)
> @@ -202,6 +204,11 @@ static void test_write_read(void)
> qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 0xFFFFFFFF);
> const uint32_t tdr = qtest_readl(qts, USART1_BASE_ADDR + A_TDR);
> g_assert_cmpuint(tdr, ==, 0x000001FF);
> +
> + /* Official STM HAL uses uint16_t for TDR */
> + qtest_writew(qts, USART1_BASE_ADDR + A_TDR, 0xFFFF);
> + const uint16_t tdr16 = qtest_readw(qts, USART1_BASE_ADDR + A_TDR);
> + g_assert_cmpuint(tdr16, ==, 0x000001FF);
> }
>
> static void test_receive_char(void)
> @@ -296,6 +303,35 @@ static void test_send_str(void)
> qtest_quit(qts);
> }
>
> +static void test_ack(void)
> +{
> + uint32_t cr1;
> + uint32_t isr;
> + QTestState *qts = qtest_init("-M b-l475e-iot01a");
> +
> + init_uart(qts);
> +
> + cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
> +
> + /* Disable the transmitter and receiver. */
> + qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
> + cr1 & ~(R_CR1_RE_MASK | R_CR1_TE_MASK));
> +
> + /* Test ISR ACK for transmitter and receiver disabled */
> + isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR));
> + g_assert_false(isr & R_ISR_TEACK_MASK);
> + g_assert_false(isr & R_ISR_REACK_MASK);
> +
> + /* Enable the transmitter and receiver. */
> + qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
> + cr1 | (R_CR1_RE_MASK | R_CR1_TE_MASK));
> +
> + /* Test ISR ACK for transmitter and receiver disabled */
> + isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR));
> + g_assert_true(isr & R_ISR_TEACK_MASK);
> + g_assert_true(isr & R_ISR_REACK_MASK);
This is missing a
qtest_quit(qts);
at the end of the function. Without it, on non-Linux
hosts the QEMU process-under-tests will not be properly
killed. We were also missing one at the end of
test_write_read() in this file, which we just fixed
this week in commit d1e8bea9c9c186.
> +}
> +
> int main(int argc, char **argv)
> {
> int ret;
> @@ -308,6 +344,7 @@ int main(int argc, char **argv)
> qtest_add_func("stm32l4x5/usart/send_char", test_send_char);
> qtest_add_func("stm32l4x5/usart/receive_str", test_receive_str);
> qtest_add_func("stm32l4x5/usart/send_str", test_send_str);
> + qtest_add_func("stm32l4x5/usart/ack", test_ack);
> ret = g_test_run();
>
> return ret;
> --
> 2.43.0
thanks
-- PMM
next prev parent reply other threads:[~2024-09-06 16:13 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-02 6:19 [PATCH] hw/char/stm32l4x5_usart.c: Fix ACK and min access size Jacob Abrams
2024-09-06 16:12 ` Peter Maydell [this message]
2024-09-07 20:26 ` Jacob Abrams
2024-09-09 17:40 ` Philippe Mathieu-Daudé
2024-09-10 4:34 ` Jacob Abrams
2024-09-10 6:28 ` Philippe Mathieu-Daudé
2024-09-10 9:34 ` Peter Maydell
2024-09-11 6:26 ` Jacob Abrams
2024-09-11 10:28 ` Peter Maydell
2024-09-14 3:42 ` Jacob Abrams
2024-10-08 13:45 ` Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAFEAcA9wP7f_yPYNJmaTDe1bB8cPifErAGpjtsNPKsR0s_65Sg@mail.gmail.com \
--to=peter.maydell@linaro.org \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=satur9nine@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).