xref: /qemu/tests/qtest/stm32l4x5_usart-test.c (revision 6cce0dcc6f7aaaeb7f17577776da510b04f67c99)
1214652daSArnaud Minier /*
2214652daSArnaud Minier  * QTest testcase for STML4X5_USART
3214652daSArnaud Minier  *
4214652daSArnaud Minier  * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
5214652daSArnaud Minier  * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
6214652daSArnaud Minier  *
7214652daSArnaud Minier  * This work is licensed under the terms of the GNU GPL, version 2 or later.
8214652daSArnaud Minier  * See the COPYING file in the top-level directory.
9214652daSArnaud Minier  */
10214652daSArnaud Minier 
11214652daSArnaud Minier #include "qemu/osdep.h"
12214652daSArnaud Minier #include "libqtest.h"
13214652daSArnaud Minier #include "hw/misc/stm32l4x5_rcc_internals.h"
14214652daSArnaud Minier #include "hw/registerfields.h"
15214652daSArnaud Minier 
16214652daSArnaud Minier #define RCC_BASE_ADDR 0x40021000
17214652daSArnaud Minier /* Use USART 1 ADDR, assume the others work the same */
18214652daSArnaud Minier #define USART1_BASE_ADDR 0x40013800
19214652daSArnaud Minier 
20214652daSArnaud Minier /* See stm32l4x5_usart for definitions */
21214652daSArnaud Minier REG32(CR1, 0x00)
22214652daSArnaud Minier     FIELD(CR1, M1, 28, 1)
23214652daSArnaud Minier     FIELD(CR1, OVER8, 15, 1)
24214652daSArnaud Minier     FIELD(CR1, M0, 12, 1)
25214652daSArnaud Minier     FIELD(CR1, PCE, 10, 1)
26214652daSArnaud Minier     FIELD(CR1, TXEIE, 7, 1)
27214652daSArnaud Minier     FIELD(CR1, RXNEIE, 5, 1)
28214652daSArnaud Minier     FIELD(CR1, TE, 3, 1)
29214652daSArnaud Minier     FIELD(CR1, RE, 2, 1)
30214652daSArnaud Minier     FIELD(CR1, UE, 0, 1)
31214652daSArnaud Minier REG32(CR2, 0x04)
32214652daSArnaud Minier REG32(CR3, 0x08)
33214652daSArnaud Minier     FIELD(CR3, OVRDIS, 12, 1)
34214652daSArnaud Minier REG32(BRR, 0x0C)
35214652daSArnaud Minier REG32(GTPR, 0x10)
36214652daSArnaud Minier REG32(RTOR, 0x14)
37214652daSArnaud Minier REG32(RQR, 0x18)
38214652daSArnaud Minier REG32(ISR, 0x1C)
39*6cce0dccSJacob Abrams     FIELD(ISR, REACK, 22, 1)
40*6cce0dccSJacob Abrams     FIELD(ISR, TEACK, 21, 1)
41214652daSArnaud Minier     FIELD(ISR, TXE, 7, 1)
42214652daSArnaud Minier     FIELD(ISR, RXNE, 5, 1)
43214652daSArnaud Minier     FIELD(ISR, ORE, 3, 1)
44214652daSArnaud Minier REG32(ICR, 0x20)
45214652daSArnaud Minier REG32(RDR, 0x24)
46214652daSArnaud Minier REG32(TDR, 0x28)
47214652daSArnaud Minier 
48214652daSArnaud Minier #define NVIC_ISPR1 0XE000E204
49214652daSArnaud Minier #define NVIC_ICPR1 0xE000E284
50214652daSArnaud Minier #define USART1_IRQ 37
51214652daSArnaud Minier 
52214652daSArnaud Minier static bool check_nvic_pending(QTestState *qts, unsigned int n)
53214652daSArnaud Minier {
54214652daSArnaud Minier     /* No USART interrupts are less than 32 */
55214652daSArnaud Minier     assert(n > 32);
56214652daSArnaud Minier     n -= 32;
57214652daSArnaud Minier     return qtest_readl(qts, NVIC_ISPR1) & (1 << n);
58214652daSArnaud Minier }
59214652daSArnaud Minier 
60214652daSArnaud Minier static bool clear_nvic_pending(QTestState *qts, unsigned int n)
61214652daSArnaud Minier {
62214652daSArnaud Minier     /* No USART interrupts are less than 32 */
63214652daSArnaud Minier     assert(n > 32);
64214652daSArnaud Minier     n -= 32;
65214652daSArnaud Minier     qtest_writel(qts, NVIC_ICPR1, (1 << n));
66214652daSArnaud Minier     return true;
67214652daSArnaud Minier }
68214652daSArnaud Minier 
69214652daSArnaud Minier /*
70214652daSArnaud Minier  * Wait indefinitely for the flag to be updated.
71214652daSArnaud Minier  * If this is run on a slow CI runner,
72214652daSArnaud Minier  * the meson harness will timeout after 10 minutes for us.
73214652daSArnaud Minier  */
74214652daSArnaud Minier static bool usart_wait_for_flag(QTestState *qts, uint32_t event_addr,
75214652daSArnaud Minier                                 uint32_t flag)
76214652daSArnaud Minier {
77214652daSArnaud Minier     while (true) {
78214652daSArnaud Minier         if ((qtest_readl(qts, event_addr) & flag)) {
79214652daSArnaud Minier             return true;
80214652daSArnaud Minier         }
81214652daSArnaud Minier         g_usleep(1000);
82214652daSArnaud Minier     }
83214652daSArnaud Minier 
84214652daSArnaud Minier     return false;
85214652daSArnaud Minier }
86214652daSArnaud Minier 
87214652daSArnaud Minier static void usart_receive_string(QTestState *qts, int sock_fd, const char *in,
88214652daSArnaud Minier                                  char *out)
89214652daSArnaud Minier {
90214652daSArnaud Minier     int i, in_len = strlen(in);
91214652daSArnaud Minier 
92214652daSArnaud Minier     g_assert_true(send(sock_fd, in, in_len, 0) == in_len);
93214652daSArnaud Minier     for (i = 0; i < in_len; i++) {
94214652daSArnaud Minier         g_assert_true(usart_wait_for_flag(qts,
95214652daSArnaud Minier             USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK));
96214652daSArnaud Minier         out[i] = qtest_readl(qts, USART1_BASE_ADDR + A_RDR);
97214652daSArnaud Minier     }
98214652daSArnaud Minier     out[i] = '\0';
99214652daSArnaud Minier }
100214652daSArnaud Minier 
101214652daSArnaud Minier static void usart_send_string(QTestState *qts, const char *in)
102214652daSArnaud Minier {
103214652daSArnaud Minier     int i, in_len = strlen(in);
104214652daSArnaud Minier 
105214652daSArnaud Minier     for (i = 0; i < in_len; i++) {
106214652daSArnaud Minier         qtest_writel(qts, USART1_BASE_ADDR + A_TDR, in[i]);
107214652daSArnaud Minier         g_assert_true(usart_wait_for_flag(qts,
108214652daSArnaud Minier             USART1_BASE_ADDR + A_ISR, R_ISR_TXE_MASK));
109214652daSArnaud Minier     }
110214652daSArnaud Minier }
111214652daSArnaud Minier 
112214652daSArnaud Minier /* Init the RCC clocks to run at 80 MHz */
113214652daSArnaud Minier static void init_clocks(QTestState *qts)
114214652daSArnaud Minier {
115214652daSArnaud Minier     uint32_t value;
116214652daSArnaud Minier 
117214652daSArnaud Minier     /* MSIRANGE can be set only when MSI is OFF or READY */
118214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CR), R_CR_MSION_MASK);
119214652daSArnaud Minier 
120214652daSArnaud Minier     /* Clocking from MSI, in case MSI was not the default source */
121214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), 0);
122214652daSArnaud Minier 
123214652daSArnaud Minier     /*
124214652daSArnaud Minier      * Update PLL and set MSI as the source clock.
125214652daSArnaud Minier      * PLLM = 1 --> 000
126214652daSArnaud Minier      * PLLN = 40 --> 40
127214652daSArnaud Minier      * PPLLR = 2 --> 00
128214652daSArnaud Minier      * PLLDIV = unused, PLLP = unused (SAI3), PLLQ = unused (48M1)
129214652daSArnaud Minier      * SRC = MSI --> 01
130214652daSArnaud Minier      */
131214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_PLLCFGR), R_PLLCFGR_PLLREN_MASK |
132214652daSArnaud Minier             (40 << R_PLLCFGR_PLLN_SHIFT) |
133214652daSArnaud Minier             (0b01 << R_PLLCFGR_PLLSRC_SHIFT));
134214652daSArnaud Minier 
135214652daSArnaud Minier     /* PLL activation */
136214652daSArnaud Minier 
137214652daSArnaud Minier     value = qtest_readl(qts, (RCC_BASE_ADDR + A_CR));
138214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CR), value | R_CR_PLLON_MASK);
139214652daSArnaud Minier 
140214652daSArnaud Minier     /* RCC_CFGR is OK by defaut */
141214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), 0);
142214652daSArnaud Minier 
143214652daSArnaud Minier     /* CCIPR : no periph clock by default */
144214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CCIPR), 0);
145214652daSArnaud Minier 
146214652daSArnaud Minier     /* Switches on the PLL clock source */
147214652daSArnaud Minier     value = qtest_readl(qts, (RCC_BASE_ADDR + A_CFGR));
148214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), (value & ~R_CFGR_SW_MASK) |
149214652daSArnaud Minier         (0b11 << R_CFGR_SW_SHIFT));
150214652daSArnaud Minier 
151214652daSArnaud Minier     /* Enable SYSCFG clock enabled */
152214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_APB2ENR), R_APB2ENR_SYSCFGEN_MASK);
153214652daSArnaud Minier 
154214652daSArnaud Minier     /* Enable the IO port B clock (See p.252) */
155214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_AHB2ENR), R_AHB2ENR_GPIOBEN_MASK);
156214652daSArnaud Minier 
157214652daSArnaud Minier     /* Enable the clock for USART1 (cf p.259) */
158214652daSArnaud Minier     /* We rewrite SYSCFGEN to not disable it */
159214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_APB2ENR),
160214652daSArnaud Minier                  R_APB2ENR_SYSCFGEN_MASK | R_APB2ENR_USART1EN_MASK);
161214652daSArnaud Minier 
162214652daSArnaud Minier     /* TODO: Enable usart via gpio */
163214652daSArnaud Minier 
164214652daSArnaud Minier     /* Set PCLK as the clock for USART1(cf p.272) i.e. reset both bits */
165214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CCIPR), 0);
166214652daSArnaud Minier 
167214652daSArnaud Minier     /* Reset USART1 (see p.249) */
168214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_APB2RSTR), 1 << 14);
169214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_APB2RSTR), 0);
170214652daSArnaud Minier }
171214652daSArnaud Minier 
172214652daSArnaud Minier static void init_uart(QTestState *qts)
173214652daSArnaud Minier {
174214652daSArnaud Minier     uint32_t cr1;
175214652daSArnaud Minier 
176214652daSArnaud Minier     init_clocks(qts);
177214652daSArnaud Minier 
178214652daSArnaud Minier     /*
179214652daSArnaud Minier      * For 115200 bauds, see p.1349.
180214652daSArnaud Minier      * The clock has a frequency of 80Mhz,
181214652daSArnaud Minier      * for 115200, we have to put a divider of 695 = 0x2B7.
182214652daSArnaud Minier      */
183214652daSArnaud Minier     qtest_writel(qts, (USART1_BASE_ADDR + A_BRR), 0x2B7);
184214652daSArnaud Minier 
185214652daSArnaud Minier     /*
186214652daSArnaud Minier      * Set the oversampling by 16,
187214652daSArnaud Minier      * disable the parity control and
188214652daSArnaud Minier      * set the word length to 8. (cf p.1377)
189214652daSArnaud Minier      */
190214652daSArnaud Minier     cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
191214652daSArnaud Minier     cr1 &= ~(R_CR1_M1_MASK | R_CR1_M0_MASK | R_CR1_OVER8_MASK | R_CR1_PCE_MASK);
192214652daSArnaud Minier     qtest_writel(qts, (USART1_BASE_ADDR + A_CR1), cr1);
193214652daSArnaud Minier 
194214652daSArnaud Minier     /* Enable the transmitter, the receiver and the USART. */
195214652daSArnaud Minier     qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
196*6cce0dccSJacob Abrams         cr1 | R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK);
197214652daSArnaud Minier }
198214652daSArnaud Minier 
199214652daSArnaud Minier static void test_write_read(void)
200214652daSArnaud Minier {
201214652daSArnaud Minier     QTestState *qts = qtest_init("-M b-l475e-iot01a");
202214652daSArnaud Minier 
203214652daSArnaud Minier     /* Test that we can write and retrieve a value from the device */
204214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 0xFFFFFFFF);
205214652daSArnaud Minier     const uint32_t tdr = qtest_readl(qts, USART1_BASE_ADDR + A_TDR);
206214652daSArnaud Minier     g_assert_cmpuint(tdr, ==, 0x000001FF);
207d1e8bea9SPeter Maydell 
208d1e8bea9SPeter Maydell     qtest_quit(qts);
209214652daSArnaud Minier }
210214652daSArnaud Minier 
211214652daSArnaud Minier static void test_receive_char(void)
212214652daSArnaud Minier {
213214652daSArnaud Minier     int sock_fd;
214214652daSArnaud Minier     uint32_t cr1;
215214652daSArnaud Minier     QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
216214652daSArnaud Minier 
217214652daSArnaud Minier     init_uart(qts);
218214652daSArnaud Minier 
219214652daSArnaud Minier     /* Try without initializing IRQ */
220214652daSArnaud Minier     g_assert_true(send(sock_fd, "a", 1, 0) == 1);
221214652daSArnaud Minier     usart_wait_for_flag(qts, USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK);
222214652daSArnaud Minier     g_assert_cmphex(qtest_readl(qts, USART1_BASE_ADDR + A_RDR), ==, 'a');
223214652daSArnaud Minier     g_assert_false(check_nvic_pending(qts, USART1_IRQ));
224214652daSArnaud Minier 
225214652daSArnaud Minier     /* Now with the IRQ */
226214652daSArnaud Minier     cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
227214652daSArnaud Minier     cr1 |= R_CR1_RXNEIE_MASK;
228214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_CR1, cr1);
229214652daSArnaud Minier     g_assert_true(send(sock_fd, "b", 1, 0) == 1);
230214652daSArnaud Minier     usart_wait_for_flag(qts, USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK);
231214652daSArnaud Minier     g_assert_cmphex(qtest_readl(qts, USART1_BASE_ADDR + A_RDR), ==, 'b');
232214652daSArnaud Minier     g_assert_true(check_nvic_pending(qts, USART1_IRQ));
233214652daSArnaud Minier     clear_nvic_pending(qts, USART1_IRQ);
234214652daSArnaud Minier 
235214652daSArnaud Minier     close(sock_fd);
236214652daSArnaud Minier 
237214652daSArnaud Minier     qtest_quit(qts);
238214652daSArnaud Minier }
239214652daSArnaud Minier 
240214652daSArnaud Minier static void test_send_char(void)
241214652daSArnaud Minier {
242214652daSArnaud Minier     int sock_fd;
243214652daSArnaud Minier     char s[1];
244214652daSArnaud Minier     uint32_t cr1;
245214652daSArnaud Minier     QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
246214652daSArnaud Minier 
247214652daSArnaud Minier     init_uart(qts);
248214652daSArnaud Minier 
249214652daSArnaud Minier     /* Try without initializing IRQ */
250214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 'c');
251214652daSArnaud Minier     g_assert_true(recv(sock_fd, s, 1, 0) == 1);
252214652daSArnaud Minier     g_assert_cmphex(s[0], ==, 'c');
253214652daSArnaud Minier     g_assert_false(check_nvic_pending(qts, USART1_IRQ));
254214652daSArnaud Minier 
255214652daSArnaud Minier     /* Now with the IRQ */
256214652daSArnaud Minier     cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
257214652daSArnaud Minier     cr1 |= R_CR1_TXEIE_MASK;
258214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_CR1, cr1);
259214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 'd');
260214652daSArnaud Minier     g_assert_true(recv(sock_fd, s, 1, 0) == 1);
261214652daSArnaud Minier     g_assert_cmphex(s[0], ==, 'd');
262214652daSArnaud Minier     g_assert_true(check_nvic_pending(qts, USART1_IRQ));
263214652daSArnaud Minier     clear_nvic_pending(qts, USART1_IRQ);
264214652daSArnaud Minier 
265214652daSArnaud Minier     close(sock_fd);
266214652daSArnaud Minier 
267214652daSArnaud Minier     qtest_quit(qts);
268214652daSArnaud Minier }
269214652daSArnaud Minier 
270214652daSArnaud Minier static void test_receive_str(void)
271214652daSArnaud Minier {
272214652daSArnaud Minier     int sock_fd;
273214652daSArnaud Minier     char s[10];
274214652daSArnaud Minier     QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
275214652daSArnaud Minier 
276214652daSArnaud Minier     init_uart(qts);
277214652daSArnaud Minier 
278214652daSArnaud Minier     usart_receive_string(qts, sock_fd, "hello", s);
279214652daSArnaud Minier     g_assert_true(memcmp(s, "hello", 5) == 0);
280214652daSArnaud Minier 
281214652daSArnaud Minier     close(sock_fd);
282214652daSArnaud Minier 
283214652daSArnaud Minier     qtest_quit(qts);
284214652daSArnaud Minier }
285214652daSArnaud Minier 
286214652daSArnaud Minier static void test_send_str(void)
287214652daSArnaud Minier {
288214652daSArnaud Minier     int sock_fd;
289214652daSArnaud Minier     char s[10];
290214652daSArnaud Minier     QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
291214652daSArnaud Minier 
292214652daSArnaud Minier     init_uart(qts);
293214652daSArnaud Minier 
294214652daSArnaud Minier     usart_send_string(qts, "world");
295214652daSArnaud Minier     g_assert_true(recv(sock_fd, s, 10, 0) == 5);
296214652daSArnaud Minier     g_assert_true(memcmp(s, "world", 5) == 0);
297214652daSArnaud Minier 
298214652daSArnaud Minier     close(sock_fd);
299214652daSArnaud Minier 
300214652daSArnaud Minier     qtest_quit(qts);
301214652daSArnaud Minier }
302214652daSArnaud Minier 
303*6cce0dccSJacob Abrams static void test_ack(void)
304*6cce0dccSJacob Abrams {
305*6cce0dccSJacob Abrams     uint32_t cr1;
306*6cce0dccSJacob Abrams     uint32_t isr;
307*6cce0dccSJacob Abrams     QTestState *qts = qtest_init("-M b-l475e-iot01a");
308*6cce0dccSJacob Abrams 
309*6cce0dccSJacob Abrams     init_uart(qts);
310*6cce0dccSJacob Abrams 
311*6cce0dccSJacob Abrams     cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
312*6cce0dccSJacob Abrams 
313*6cce0dccSJacob Abrams     /* Disable the transmitter and receiver. */
314*6cce0dccSJacob Abrams     qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
315*6cce0dccSJacob Abrams         cr1 & ~(R_CR1_RE_MASK | R_CR1_TE_MASK));
316*6cce0dccSJacob Abrams 
317*6cce0dccSJacob Abrams     /* Test ISR ACK for transmitter and receiver disabled */
318*6cce0dccSJacob Abrams     isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR));
319*6cce0dccSJacob Abrams     g_assert_false(isr & R_ISR_TEACK_MASK);
320*6cce0dccSJacob Abrams     g_assert_false(isr & R_ISR_REACK_MASK);
321*6cce0dccSJacob Abrams 
322*6cce0dccSJacob Abrams     /* Enable the transmitter and receiver. */
323*6cce0dccSJacob Abrams     qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
324*6cce0dccSJacob Abrams         cr1 | (R_CR1_RE_MASK | R_CR1_TE_MASK));
325*6cce0dccSJacob Abrams 
326*6cce0dccSJacob Abrams     /* Test ISR ACK for transmitter and receiver disabled */
327*6cce0dccSJacob Abrams     isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR));
328*6cce0dccSJacob Abrams     g_assert_true(isr & R_ISR_TEACK_MASK);
329*6cce0dccSJacob Abrams     g_assert_true(isr & R_ISR_REACK_MASK);
330*6cce0dccSJacob Abrams 
331*6cce0dccSJacob Abrams     qtest_quit(qts);
332*6cce0dccSJacob Abrams }
333*6cce0dccSJacob Abrams 
334214652daSArnaud Minier int main(int argc, char **argv)
335214652daSArnaud Minier {
336214652daSArnaud Minier     int ret;
337214652daSArnaud Minier 
338214652daSArnaud Minier     g_test_init(&argc, &argv, NULL);
339214652daSArnaud Minier     g_test_set_nonfatal_assertions();
340214652daSArnaud Minier 
341214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/write_read", test_write_read);
342214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/receive_char", test_receive_char);
343214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/send_char", test_send_char);
344214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/receive_str", test_receive_str);
345214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/send_str", test_send_str);
346*6cce0dccSJacob Abrams     qtest_add_func("stm32l4x5/usart/ack", test_ack);
347214652daSArnaud Minier     ret = g_test_run();
348214652daSArnaud Minier 
349214652daSArnaud Minier     return ret;
350214652daSArnaud Minier }
351214652daSArnaud Minier 
352