xref: /qemu/tests/qtest/stm32l4x5_usart-test.c (revision d1e8bea9c9c1869bfbb28b7a3e9d8e3b6f8aca46)
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)
39214652daSArnaud Minier     FIELD(ISR, TXE, 7, 1)
40214652daSArnaud Minier     FIELD(ISR, RXNE, 5, 1)
41214652daSArnaud Minier     FIELD(ISR, ORE, 3, 1)
42214652daSArnaud Minier REG32(ICR, 0x20)
43214652daSArnaud Minier REG32(RDR, 0x24)
44214652daSArnaud Minier REG32(TDR, 0x28)
45214652daSArnaud Minier 
46214652daSArnaud Minier #define NVIC_ISPR1 0XE000E204
47214652daSArnaud Minier #define NVIC_ICPR1 0xE000E284
48214652daSArnaud Minier #define USART1_IRQ 37
49214652daSArnaud Minier 
50214652daSArnaud Minier static bool check_nvic_pending(QTestState *qts, unsigned int n)
51214652daSArnaud Minier {
52214652daSArnaud Minier     /* No USART interrupts are less than 32 */
53214652daSArnaud Minier     assert(n > 32);
54214652daSArnaud Minier     n -= 32;
55214652daSArnaud Minier     return qtest_readl(qts, NVIC_ISPR1) & (1 << n);
56214652daSArnaud Minier }
57214652daSArnaud Minier 
58214652daSArnaud Minier static bool clear_nvic_pending(QTestState *qts, unsigned int n)
59214652daSArnaud Minier {
60214652daSArnaud Minier     /* No USART interrupts are less than 32 */
61214652daSArnaud Minier     assert(n > 32);
62214652daSArnaud Minier     n -= 32;
63214652daSArnaud Minier     qtest_writel(qts, NVIC_ICPR1, (1 << n));
64214652daSArnaud Minier     return true;
65214652daSArnaud Minier }
66214652daSArnaud Minier 
67214652daSArnaud Minier /*
68214652daSArnaud Minier  * Wait indefinitely for the flag to be updated.
69214652daSArnaud Minier  * If this is run on a slow CI runner,
70214652daSArnaud Minier  * the meson harness will timeout after 10 minutes for us.
71214652daSArnaud Minier  */
72214652daSArnaud Minier static bool usart_wait_for_flag(QTestState *qts, uint32_t event_addr,
73214652daSArnaud Minier                                 uint32_t flag)
74214652daSArnaud Minier {
75214652daSArnaud Minier     while (true) {
76214652daSArnaud Minier         if ((qtest_readl(qts, event_addr) & flag)) {
77214652daSArnaud Minier             return true;
78214652daSArnaud Minier         }
79214652daSArnaud Minier         g_usleep(1000);
80214652daSArnaud Minier     }
81214652daSArnaud Minier 
82214652daSArnaud Minier     return false;
83214652daSArnaud Minier }
84214652daSArnaud Minier 
85214652daSArnaud Minier static void usart_receive_string(QTestState *qts, int sock_fd, const char *in,
86214652daSArnaud Minier                                  char *out)
87214652daSArnaud Minier {
88214652daSArnaud Minier     int i, in_len = strlen(in);
89214652daSArnaud Minier 
90214652daSArnaud Minier     g_assert_true(send(sock_fd, in, in_len, 0) == in_len);
91214652daSArnaud Minier     for (i = 0; i < in_len; i++) {
92214652daSArnaud Minier         g_assert_true(usart_wait_for_flag(qts,
93214652daSArnaud Minier             USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK));
94214652daSArnaud Minier         out[i] = qtest_readl(qts, USART1_BASE_ADDR + A_RDR);
95214652daSArnaud Minier     }
96214652daSArnaud Minier     out[i] = '\0';
97214652daSArnaud Minier }
98214652daSArnaud Minier 
99214652daSArnaud Minier static void usart_send_string(QTestState *qts, const char *in)
100214652daSArnaud Minier {
101214652daSArnaud Minier     int i, in_len = strlen(in);
102214652daSArnaud Minier 
103214652daSArnaud Minier     for (i = 0; i < in_len; i++) {
104214652daSArnaud Minier         qtest_writel(qts, USART1_BASE_ADDR + A_TDR, in[i]);
105214652daSArnaud Minier         g_assert_true(usart_wait_for_flag(qts,
106214652daSArnaud Minier             USART1_BASE_ADDR + A_ISR, R_ISR_TXE_MASK));
107214652daSArnaud Minier     }
108214652daSArnaud Minier }
109214652daSArnaud Minier 
110214652daSArnaud Minier /* Init the RCC clocks to run at 80 MHz */
111214652daSArnaud Minier static void init_clocks(QTestState *qts)
112214652daSArnaud Minier {
113214652daSArnaud Minier     uint32_t value;
114214652daSArnaud Minier 
115214652daSArnaud Minier     /* MSIRANGE can be set only when MSI is OFF or READY */
116214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CR), R_CR_MSION_MASK);
117214652daSArnaud Minier 
118214652daSArnaud Minier     /* Clocking from MSI, in case MSI was not the default source */
119214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), 0);
120214652daSArnaud Minier 
121214652daSArnaud Minier     /*
122214652daSArnaud Minier      * Update PLL and set MSI as the source clock.
123214652daSArnaud Minier      * PLLM = 1 --> 000
124214652daSArnaud Minier      * PLLN = 40 --> 40
125214652daSArnaud Minier      * PPLLR = 2 --> 00
126214652daSArnaud Minier      * PLLDIV = unused, PLLP = unused (SAI3), PLLQ = unused (48M1)
127214652daSArnaud Minier      * SRC = MSI --> 01
128214652daSArnaud Minier      */
129214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_PLLCFGR), R_PLLCFGR_PLLREN_MASK |
130214652daSArnaud Minier             (40 << R_PLLCFGR_PLLN_SHIFT) |
131214652daSArnaud Minier             (0b01 << R_PLLCFGR_PLLSRC_SHIFT));
132214652daSArnaud Minier 
133214652daSArnaud Minier     /* PLL activation */
134214652daSArnaud Minier 
135214652daSArnaud Minier     value = qtest_readl(qts, (RCC_BASE_ADDR + A_CR));
136214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CR), value | R_CR_PLLON_MASK);
137214652daSArnaud Minier 
138214652daSArnaud Minier     /* RCC_CFGR is OK by defaut */
139214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), 0);
140214652daSArnaud Minier 
141214652daSArnaud Minier     /* CCIPR : no periph clock by default */
142214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CCIPR), 0);
143214652daSArnaud Minier 
144214652daSArnaud Minier     /* Switches on the PLL clock source */
145214652daSArnaud Minier     value = qtest_readl(qts, (RCC_BASE_ADDR + A_CFGR));
146214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), (value & ~R_CFGR_SW_MASK) |
147214652daSArnaud Minier         (0b11 << R_CFGR_SW_SHIFT));
148214652daSArnaud Minier 
149214652daSArnaud Minier     /* Enable SYSCFG clock enabled */
150214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_APB2ENR), R_APB2ENR_SYSCFGEN_MASK);
151214652daSArnaud Minier 
152214652daSArnaud Minier     /* Enable the IO port B clock (See p.252) */
153214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_AHB2ENR), R_AHB2ENR_GPIOBEN_MASK);
154214652daSArnaud Minier 
155214652daSArnaud Minier     /* Enable the clock for USART1 (cf p.259) */
156214652daSArnaud Minier     /* We rewrite SYSCFGEN to not disable it */
157214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_APB2ENR),
158214652daSArnaud Minier                  R_APB2ENR_SYSCFGEN_MASK | R_APB2ENR_USART1EN_MASK);
159214652daSArnaud Minier 
160214652daSArnaud Minier     /* TODO: Enable usart via gpio */
161214652daSArnaud Minier 
162214652daSArnaud Minier     /* Set PCLK as the clock for USART1(cf p.272) i.e. reset both bits */
163214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_CCIPR), 0);
164214652daSArnaud Minier 
165214652daSArnaud Minier     /* Reset USART1 (see p.249) */
166214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_APB2RSTR), 1 << 14);
167214652daSArnaud Minier     qtest_writel(qts, (RCC_BASE_ADDR + A_APB2RSTR), 0);
168214652daSArnaud Minier }
169214652daSArnaud Minier 
170214652daSArnaud Minier static void init_uart(QTestState *qts)
171214652daSArnaud Minier {
172214652daSArnaud Minier     uint32_t cr1;
173214652daSArnaud Minier 
174214652daSArnaud Minier     init_clocks(qts);
175214652daSArnaud Minier 
176214652daSArnaud Minier     /*
177214652daSArnaud Minier      * For 115200 bauds, see p.1349.
178214652daSArnaud Minier      * The clock has a frequency of 80Mhz,
179214652daSArnaud Minier      * for 115200, we have to put a divider of 695 = 0x2B7.
180214652daSArnaud Minier      */
181214652daSArnaud Minier     qtest_writel(qts, (USART1_BASE_ADDR + A_BRR), 0x2B7);
182214652daSArnaud Minier 
183214652daSArnaud Minier     /*
184214652daSArnaud Minier      * Set the oversampling by 16,
185214652daSArnaud Minier      * disable the parity control and
186214652daSArnaud Minier      * set the word length to 8. (cf p.1377)
187214652daSArnaud Minier      */
188214652daSArnaud Minier     cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
189214652daSArnaud Minier     cr1 &= ~(R_CR1_M1_MASK | R_CR1_M0_MASK | R_CR1_OVER8_MASK | R_CR1_PCE_MASK);
190214652daSArnaud Minier     qtest_writel(qts, (USART1_BASE_ADDR + A_CR1), cr1);
191214652daSArnaud Minier 
192214652daSArnaud Minier     /* Enable the transmitter, the receiver and the USART. */
193214652daSArnaud Minier     qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
194214652daSArnaud Minier         R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK);
195214652daSArnaud Minier }
196214652daSArnaud Minier 
197214652daSArnaud Minier static void test_write_read(void)
198214652daSArnaud Minier {
199214652daSArnaud Minier     QTestState *qts = qtest_init("-M b-l475e-iot01a");
200214652daSArnaud Minier 
201214652daSArnaud Minier     /* Test that we can write and retrieve a value from the device */
202214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 0xFFFFFFFF);
203214652daSArnaud Minier     const uint32_t tdr = qtest_readl(qts, USART1_BASE_ADDR + A_TDR);
204214652daSArnaud Minier     g_assert_cmpuint(tdr, ==, 0x000001FF);
205*d1e8bea9SPeter Maydell 
206*d1e8bea9SPeter Maydell     qtest_quit(qts);
207214652daSArnaud Minier }
208214652daSArnaud Minier 
209214652daSArnaud Minier static void test_receive_char(void)
210214652daSArnaud Minier {
211214652daSArnaud Minier     int sock_fd;
212214652daSArnaud Minier     uint32_t cr1;
213214652daSArnaud Minier     QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
214214652daSArnaud Minier 
215214652daSArnaud Minier     init_uart(qts);
216214652daSArnaud Minier 
217214652daSArnaud Minier     /* Try without initializing IRQ */
218214652daSArnaud Minier     g_assert_true(send(sock_fd, "a", 1, 0) == 1);
219214652daSArnaud Minier     usart_wait_for_flag(qts, USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK);
220214652daSArnaud Minier     g_assert_cmphex(qtest_readl(qts, USART1_BASE_ADDR + A_RDR), ==, 'a');
221214652daSArnaud Minier     g_assert_false(check_nvic_pending(qts, USART1_IRQ));
222214652daSArnaud Minier 
223214652daSArnaud Minier     /* Now with the IRQ */
224214652daSArnaud Minier     cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
225214652daSArnaud Minier     cr1 |= R_CR1_RXNEIE_MASK;
226214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_CR1, cr1);
227214652daSArnaud Minier     g_assert_true(send(sock_fd, "b", 1, 0) == 1);
228214652daSArnaud Minier     usart_wait_for_flag(qts, USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK);
229214652daSArnaud Minier     g_assert_cmphex(qtest_readl(qts, USART1_BASE_ADDR + A_RDR), ==, 'b');
230214652daSArnaud Minier     g_assert_true(check_nvic_pending(qts, USART1_IRQ));
231214652daSArnaud Minier     clear_nvic_pending(qts, USART1_IRQ);
232214652daSArnaud Minier 
233214652daSArnaud Minier     close(sock_fd);
234214652daSArnaud Minier 
235214652daSArnaud Minier     qtest_quit(qts);
236214652daSArnaud Minier }
237214652daSArnaud Minier 
238214652daSArnaud Minier static void test_send_char(void)
239214652daSArnaud Minier {
240214652daSArnaud Minier     int sock_fd;
241214652daSArnaud Minier     char s[1];
242214652daSArnaud Minier     uint32_t cr1;
243214652daSArnaud Minier     QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
244214652daSArnaud Minier 
245214652daSArnaud Minier     init_uart(qts);
246214652daSArnaud Minier 
247214652daSArnaud Minier     /* Try without initializing IRQ */
248214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 'c');
249214652daSArnaud Minier     g_assert_true(recv(sock_fd, s, 1, 0) == 1);
250214652daSArnaud Minier     g_assert_cmphex(s[0], ==, 'c');
251214652daSArnaud Minier     g_assert_false(check_nvic_pending(qts, USART1_IRQ));
252214652daSArnaud Minier 
253214652daSArnaud Minier     /* Now with the IRQ */
254214652daSArnaud Minier     cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
255214652daSArnaud Minier     cr1 |= R_CR1_TXEIE_MASK;
256214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_CR1, cr1);
257214652daSArnaud Minier     qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 'd');
258214652daSArnaud Minier     g_assert_true(recv(sock_fd, s, 1, 0) == 1);
259214652daSArnaud Minier     g_assert_cmphex(s[0], ==, 'd');
260214652daSArnaud Minier     g_assert_true(check_nvic_pending(qts, USART1_IRQ));
261214652daSArnaud Minier     clear_nvic_pending(qts, USART1_IRQ);
262214652daSArnaud Minier 
263214652daSArnaud Minier     close(sock_fd);
264214652daSArnaud Minier 
265214652daSArnaud Minier     qtest_quit(qts);
266214652daSArnaud Minier }
267214652daSArnaud Minier 
268214652daSArnaud Minier static void test_receive_str(void)
269214652daSArnaud Minier {
270214652daSArnaud Minier     int sock_fd;
271214652daSArnaud Minier     char s[10];
272214652daSArnaud Minier     QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
273214652daSArnaud Minier 
274214652daSArnaud Minier     init_uart(qts);
275214652daSArnaud Minier 
276214652daSArnaud Minier     usart_receive_string(qts, sock_fd, "hello", s);
277214652daSArnaud Minier     g_assert_true(memcmp(s, "hello", 5) == 0);
278214652daSArnaud Minier 
279214652daSArnaud Minier     close(sock_fd);
280214652daSArnaud Minier 
281214652daSArnaud Minier     qtest_quit(qts);
282214652daSArnaud Minier }
283214652daSArnaud Minier 
284214652daSArnaud Minier static void test_send_str(void)
285214652daSArnaud Minier {
286214652daSArnaud Minier     int sock_fd;
287214652daSArnaud Minier     char s[10];
288214652daSArnaud Minier     QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd);
289214652daSArnaud Minier 
290214652daSArnaud Minier     init_uart(qts);
291214652daSArnaud Minier 
292214652daSArnaud Minier     usart_send_string(qts, "world");
293214652daSArnaud Minier     g_assert_true(recv(sock_fd, s, 10, 0) == 5);
294214652daSArnaud Minier     g_assert_true(memcmp(s, "world", 5) == 0);
295214652daSArnaud Minier 
296214652daSArnaud Minier     close(sock_fd);
297214652daSArnaud Minier 
298214652daSArnaud Minier     qtest_quit(qts);
299214652daSArnaud Minier }
300214652daSArnaud Minier 
301214652daSArnaud Minier int main(int argc, char **argv)
302214652daSArnaud Minier {
303214652daSArnaud Minier     int ret;
304214652daSArnaud Minier 
305214652daSArnaud Minier     g_test_init(&argc, &argv, NULL);
306214652daSArnaud Minier     g_test_set_nonfatal_assertions();
307214652daSArnaud Minier 
308214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/write_read", test_write_read);
309214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/receive_char", test_receive_char);
310214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/send_char", test_send_char);
311214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/receive_str", test_receive_str);
312214652daSArnaud Minier     qtest_add_func("stm32l4x5/usart/send_str", test_send_str);
313214652daSArnaud Minier     ret = g_test_run();
314214652daSArnaud Minier 
315214652daSArnaud Minier     return ret;
316214652daSArnaud Minier }
317214652daSArnaud Minier 
318