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