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