1*214652daSArnaud Minier /* 2*214652daSArnaud Minier * QTest testcase for STML4X5_USART 3*214652daSArnaud Minier * 4*214652daSArnaud Minier * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr> 5*214652daSArnaud Minier * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr> 6*214652daSArnaud Minier * 7*214652daSArnaud Minier * This work is licensed under the terms of the GNU GPL, version 2 or later. 8*214652daSArnaud Minier * See the COPYING file in the top-level directory. 9*214652daSArnaud Minier */ 10*214652daSArnaud Minier 11*214652daSArnaud Minier #include "qemu/osdep.h" 12*214652daSArnaud Minier #include "libqtest.h" 13*214652daSArnaud Minier #include "hw/misc/stm32l4x5_rcc_internals.h" 14*214652daSArnaud Minier #include "hw/registerfields.h" 15*214652daSArnaud Minier 16*214652daSArnaud Minier #define RCC_BASE_ADDR 0x40021000 17*214652daSArnaud Minier /* Use USART 1 ADDR, assume the others work the same */ 18*214652daSArnaud Minier #define USART1_BASE_ADDR 0x40013800 19*214652daSArnaud Minier 20*214652daSArnaud Minier /* See stm32l4x5_usart for definitions */ 21*214652daSArnaud Minier REG32(CR1, 0x00) 22*214652daSArnaud Minier FIELD(CR1, M1, 28, 1) 23*214652daSArnaud Minier FIELD(CR1, OVER8, 15, 1) 24*214652daSArnaud Minier FIELD(CR1, M0, 12, 1) 25*214652daSArnaud Minier FIELD(CR1, PCE, 10, 1) 26*214652daSArnaud Minier FIELD(CR1, TXEIE, 7, 1) 27*214652daSArnaud Minier FIELD(CR1, RXNEIE, 5, 1) 28*214652daSArnaud Minier FIELD(CR1, TE, 3, 1) 29*214652daSArnaud Minier FIELD(CR1, RE, 2, 1) 30*214652daSArnaud Minier FIELD(CR1, UE, 0, 1) 31*214652daSArnaud Minier REG32(CR2, 0x04) 32*214652daSArnaud Minier REG32(CR3, 0x08) 33*214652daSArnaud Minier FIELD(CR3, OVRDIS, 12, 1) 34*214652daSArnaud Minier REG32(BRR, 0x0C) 35*214652daSArnaud Minier REG32(GTPR, 0x10) 36*214652daSArnaud Minier REG32(RTOR, 0x14) 37*214652daSArnaud Minier REG32(RQR, 0x18) 38*214652daSArnaud Minier REG32(ISR, 0x1C) 39*214652daSArnaud Minier FIELD(ISR, TXE, 7, 1) 40*214652daSArnaud Minier FIELD(ISR, RXNE, 5, 1) 41*214652daSArnaud Minier FIELD(ISR, ORE, 3, 1) 42*214652daSArnaud Minier REG32(ICR, 0x20) 43*214652daSArnaud Minier REG32(RDR, 0x24) 44*214652daSArnaud Minier REG32(TDR, 0x28) 45*214652daSArnaud Minier 46*214652daSArnaud Minier #define NVIC_ISPR1 0XE000E204 47*214652daSArnaud Minier #define NVIC_ICPR1 0xE000E284 48*214652daSArnaud Minier #define USART1_IRQ 37 49*214652daSArnaud Minier 50*214652daSArnaud Minier static bool check_nvic_pending(QTestState *qts, unsigned int n) 51*214652daSArnaud Minier { 52*214652daSArnaud Minier /* No USART interrupts are less than 32 */ 53*214652daSArnaud Minier assert(n > 32); 54*214652daSArnaud Minier n -= 32; 55*214652daSArnaud Minier return qtest_readl(qts, NVIC_ISPR1) & (1 << n); 56*214652daSArnaud Minier } 57*214652daSArnaud Minier 58*214652daSArnaud Minier static bool clear_nvic_pending(QTestState *qts, unsigned int n) 59*214652daSArnaud Minier { 60*214652daSArnaud Minier /* No USART interrupts are less than 32 */ 61*214652daSArnaud Minier assert(n > 32); 62*214652daSArnaud Minier n -= 32; 63*214652daSArnaud Minier qtest_writel(qts, NVIC_ICPR1, (1 << n)); 64*214652daSArnaud Minier return true; 65*214652daSArnaud Minier } 66*214652daSArnaud Minier 67*214652daSArnaud Minier /* 68*214652daSArnaud Minier * Wait indefinitely for the flag to be updated. 69*214652daSArnaud Minier * If this is run on a slow CI runner, 70*214652daSArnaud Minier * the meson harness will timeout after 10 minutes for us. 71*214652daSArnaud Minier */ 72*214652daSArnaud Minier static bool usart_wait_for_flag(QTestState *qts, uint32_t event_addr, 73*214652daSArnaud Minier uint32_t flag) 74*214652daSArnaud Minier { 75*214652daSArnaud Minier while (true) { 76*214652daSArnaud Minier if ((qtest_readl(qts, event_addr) & flag)) { 77*214652daSArnaud Minier return true; 78*214652daSArnaud Minier } 79*214652daSArnaud Minier g_usleep(1000); 80*214652daSArnaud Minier } 81*214652daSArnaud Minier 82*214652daSArnaud Minier return false; 83*214652daSArnaud Minier } 84*214652daSArnaud Minier 85*214652daSArnaud Minier static void usart_receive_string(QTestState *qts, int sock_fd, const char *in, 86*214652daSArnaud Minier char *out) 87*214652daSArnaud Minier { 88*214652daSArnaud Minier int i, in_len = strlen(in); 89*214652daSArnaud Minier 90*214652daSArnaud Minier g_assert_true(send(sock_fd, in, in_len, 0) == in_len); 91*214652daSArnaud Minier for (i = 0; i < in_len; i++) { 92*214652daSArnaud Minier g_assert_true(usart_wait_for_flag(qts, 93*214652daSArnaud Minier USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK)); 94*214652daSArnaud Minier out[i] = qtest_readl(qts, USART1_BASE_ADDR + A_RDR); 95*214652daSArnaud Minier } 96*214652daSArnaud Minier out[i] = '\0'; 97*214652daSArnaud Minier } 98*214652daSArnaud Minier 99*214652daSArnaud Minier static void usart_send_string(QTestState *qts, const char *in) 100*214652daSArnaud Minier { 101*214652daSArnaud Minier int i, in_len = strlen(in); 102*214652daSArnaud Minier 103*214652daSArnaud Minier for (i = 0; i < in_len; i++) { 104*214652daSArnaud Minier qtest_writel(qts, USART1_BASE_ADDR + A_TDR, in[i]); 105*214652daSArnaud Minier g_assert_true(usart_wait_for_flag(qts, 106*214652daSArnaud Minier USART1_BASE_ADDR + A_ISR, R_ISR_TXE_MASK)); 107*214652daSArnaud Minier } 108*214652daSArnaud Minier } 109*214652daSArnaud Minier 110*214652daSArnaud Minier /* Init the RCC clocks to run at 80 MHz */ 111*214652daSArnaud Minier static void init_clocks(QTestState *qts) 112*214652daSArnaud Minier { 113*214652daSArnaud Minier uint32_t value; 114*214652daSArnaud Minier 115*214652daSArnaud Minier /* MSIRANGE can be set only when MSI is OFF or READY */ 116*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_CR), R_CR_MSION_MASK); 117*214652daSArnaud Minier 118*214652daSArnaud Minier /* Clocking from MSI, in case MSI was not the default source */ 119*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), 0); 120*214652daSArnaud Minier 121*214652daSArnaud Minier /* 122*214652daSArnaud Minier * Update PLL and set MSI as the source clock. 123*214652daSArnaud Minier * PLLM = 1 --> 000 124*214652daSArnaud Minier * PLLN = 40 --> 40 125*214652daSArnaud Minier * PPLLR = 2 --> 00 126*214652daSArnaud Minier * PLLDIV = unused, PLLP = unused (SAI3), PLLQ = unused (48M1) 127*214652daSArnaud Minier * SRC = MSI --> 01 128*214652daSArnaud Minier */ 129*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_PLLCFGR), R_PLLCFGR_PLLREN_MASK | 130*214652daSArnaud Minier (40 << R_PLLCFGR_PLLN_SHIFT) | 131*214652daSArnaud Minier (0b01 << R_PLLCFGR_PLLSRC_SHIFT)); 132*214652daSArnaud Minier 133*214652daSArnaud Minier /* PLL activation */ 134*214652daSArnaud Minier 135*214652daSArnaud Minier value = qtest_readl(qts, (RCC_BASE_ADDR + A_CR)); 136*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_CR), value | R_CR_PLLON_MASK); 137*214652daSArnaud Minier 138*214652daSArnaud Minier /* RCC_CFGR is OK by defaut */ 139*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), 0); 140*214652daSArnaud Minier 141*214652daSArnaud Minier /* CCIPR : no periph clock by default */ 142*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_CCIPR), 0); 143*214652daSArnaud Minier 144*214652daSArnaud Minier /* Switches on the PLL clock source */ 145*214652daSArnaud Minier value = qtest_readl(qts, (RCC_BASE_ADDR + A_CFGR)); 146*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_CFGR), (value & ~R_CFGR_SW_MASK) | 147*214652daSArnaud Minier (0b11 << R_CFGR_SW_SHIFT)); 148*214652daSArnaud Minier 149*214652daSArnaud Minier /* Enable SYSCFG clock enabled */ 150*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_APB2ENR), R_APB2ENR_SYSCFGEN_MASK); 151*214652daSArnaud Minier 152*214652daSArnaud Minier /* Enable the IO port B clock (See p.252) */ 153*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_AHB2ENR), R_AHB2ENR_GPIOBEN_MASK); 154*214652daSArnaud Minier 155*214652daSArnaud Minier /* Enable the clock for USART1 (cf p.259) */ 156*214652daSArnaud Minier /* We rewrite SYSCFGEN to not disable it */ 157*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_APB2ENR), 158*214652daSArnaud Minier R_APB2ENR_SYSCFGEN_MASK | R_APB2ENR_USART1EN_MASK); 159*214652daSArnaud Minier 160*214652daSArnaud Minier /* TODO: Enable usart via gpio */ 161*214652daSArnaud Minier 162*214652daSArnaud Minier /* Set PCLK as the clock for USART1(cf p.272) i.e. reset both bits */ 163*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_CCIPR), 0); 164*214652daSArnaud Minier 165*214652daSArnaud Minier /* Reset USART1 (see p.249) */ 166*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_APB2RSTR), 1 << 14); 167*214652daSArnaud Minier qtest_writel(qts, (RCC_BASE_ADDR + A_APB2RSTR), 0); 168*214652daSArnaud Minier } 169*214652daSArnaud Minier 170*214652daSArnaud Minier static void init_uart(QTestState *qts) 171*214652daSArnaud Minier { 172*214652daSArnaud Minier uint32_t cr1; 173*214652daSArnaud Minier 174*214652daSArnaud Minier init_clocks(qts); 175*214652daSArnaud Minier 176*214652daSArnaud Minier /* 177*214652daSArnaud Minier * For 115200 bauds, see p.1349. 178*214652daSArnaud Minier * The clock has a frequency of 80Mhz, 179*214652daSArnaud Minier * for 115200, we have to put a divider of 695 = 0x2B7. 180*214652daSArnaud Minier */ 181*214652daSArnaud Minier qtest_writel(qts, (USART1_BASE_ADDR + A_BRR), 0x2B7); 182*214652daSArnaud Minier 183*214652daSArnaud Minier /* 184*214652daSArnaud Minier * Set the oversampling by 16, 185*214652daSArnaud Minier * disable the parity control and 186*214652daSArnaud Minier * set the word length to 8. (cf p.1377) 187*214652daSArnaud Minier */ 188*214652daSArnaud Minier cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1)); 189*214652daSArnaud Minier cr1 &= ~(R_CR1_M1_MASK | R_CR1_M0_MASK | R_CR1_OVER8_MASK | R_CR1_PCE_MASK); 190*214652daSArnaud Minier qtest_writel(qts, (USART1_BASE_ADDR + A_CR1), cr1); 191*214652daSArnaud Minier 192*214652daSArnaud Minier /* Enable the transmitter, the receiver and the USART. */ 193*214652daSArnaud Minier qtest_writel(qts, (USART1_BASE_ADDR + A_CR1), 194*214652daSArnaud Minier R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK); 195*214652daSArnaud Minier } 196*214652daSArnaud Minier 197*214652daSArnaud Minier static void test_write_read(void) 198*214652daSArnaud Minier { 199*214652daSArnaud Minier QTestState *qts = qtest_init("-M b-l475e-iot01a"); 200*214652daSArnaud Minier 201*214652daSArnaud Minier /* Test that we can write and retrieve a value from the device */ 202*214652daSArnaud Minier qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 0xFFFFFFFF); 203*214652daSArnaud Minier const uint32_t tdr = qtest_readl(qts, USART1_BASE_ADDR + A_TDR); 204*214652daSArnaud Minier g_assert_cmpuint(tdr, ==, 0x000001FF); 205*214652daSArnaud Minier } 206*214652daSArnaud Minier 207*214652daSArnaud Minier static void test_receive_char(void) 208*214652daSArnaud Minier { 209*214652daSArnaud Minier int sock_fd; 210*214652daSArnaud Minier uint32_t cr1; 211*214652daSArnaud Minier QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd); 212*214652daSArnaud Minier 213*214652daSArnaud Minier init_uart(qts); 214*214652daSArnaud Minier 215*214652daSArnaud Minier /* Try without initializing IRQ */ 216*214652daSArnaud Minier g_assert_true(send(sock_fd, "a", 1, 0) == 1); 217*214652daSArnaud Minier usart_wait_for_flag(qts, USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK); 218*214652daSArnaud Minier g_assert_cmphex(qtest_readl(qts, USART1_BASE_ADDR + A_RDR), ==, 'a'); 219*214652daSArnaud Minier g_assert_false(check_nvic_pending(qts, USART1_IRQ)); 220*214652daSArnaud Minier 221*214652daSArnaud Minier /* Now with the IRQ */ 222*214652daSArnaud Minier cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1)); 223*214652daSArnaud Minier cr1 |= R_CR1_RXNEIE_MASK; 224*214652daSArnaud Minier qtest_writel(qts, USART1_BASE_ADDR + A_CR1, cr1); 225*214652daSArnaud Minier g_assert_true(send(sock_fd, "b", 1, 0) == 1); 226*214652daSArnaud Minier usart_wait_for_flag(qts, USART1_BASE_ADDR + A_ISR, R_ISR_RXNE_MASK); 227*214652daSArnaud Minier g_assert_cmphex(qtest_readl(qts, USART1_BASE_ADDR + A_RDR), ==, 'b'); 228*214652daSArnaud Minier g_assert_true(check_nvic_pending(qts, USART1_IRQ)); 229*214652daSArnaud Minier clear_nvic_pending(qts, USART1_IRQ); 230*214652daSArnaud Minier 231*214652daSArnaud Minier close(sock_fd); 232*214652daSArnaud Minier 233*214652daSArnaud Minier qtest_quit(qts); 234*214652daSArnaud Minier } 235*214652daSArnaud Minier 236*214652daSArnaud Minier static void test_send_char(void) 237*214652daSArnaud Minier { 238*214652daSArnaud Minier int sock_fd; 239*214652daSArnaud Minier char s[1]; 240*214652daSArnaud Minier uint32_t cr1; 241*214652daSArnaud Minier QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd); 242*214652daSArnaud Minier 243*214652daSArnaud Minier init_uart(qts); 244*214652daSArnaud Minier 245*214652daSArnaud Minier /* Try without initializing IRQ */ 246*214652daSArnaud Minier qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 'c'); 247*214652daSArnaud Minier g_assert_true(recv(sock_fd, s, 1, 0) == 1); 248*214652daSArnaud Minier g_assert_cmphex(s[0], ==, 'c'); 249*214652daSArnaud Minier g_assert_false(check_nvic_pending(qts, USART1_IRQ)); 250*214652daSArnaud Minier 251*214652daSArnaud Minier /* Now with the IRQ */ 252*214652daSArnaud Minier cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1)); 253*214652daSArnaud Minier cr1 |= R_CR1_TXEIE_MASK; 254*214652daSArnaud Minier qtest_writel(qts, USART1_BASE_ADDR + A_CR1, cr1); 255*214652daSArnaud Minier qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 'd'); 256*214652daSArnaud Minier g_assert_true(recv(sock_fd, s, 1, 0) == 1); 257*214652daSArnaud Minier g_assert_cmphex(s[0], ==, 'd'); 258*214652daSArnaud Minier g_assert_true(check_nvic_pending(qts, USART1_IRQ)); 259*214652daSArnaud Minier clear_nvic_pending(qts, USART1_IRQ); 260*214652daSArnaud Minier 261*214652daSArnaud Minier close(sock_fd); 262*214652daSArnaud Minier 263*214652daSArnaud Minier qtest_quit(qts); 264*214652daSArnaud Minier } 265*214652daSArnaud Minier 266*214652daSArnaud Minier static void test_receive_str(void) 267*214652daSArnaud Minier { 268*214652daSArnaud Minier int sock_fd; 269*214652daSArnaud Minier char s[10]; 270*214652daSArnaud Minier QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd); 271*214652daSArnaud Minier 272*214652daSArnaud Minier init_uart(qts); 273*214652daSArnaud Minier 274*214652daSArnaud Minier usart_receive_string(qts, sock_fd, "hello", s); 275*214652daSArnaud Minier g_assert_true(memcmp(s, "hello", 5) == 0); 276*214652daSArnaud Minier 277*214652daSArnaud Minier close(sock_fd); 278*214652daSArnaud Minier 279*214652daSArnaud Minier qtest_quit(qts); 280*214652daSArnaud Minier } 281*214652daSArnaud Minier 282*214652daSArnaud Minier static void test_send_str(void) 283*214652daSArnaud Minier { 284*214652daSArnaud Minier int sock_fd; 285*214652daSArnaud Minier char s[10]; 286*214652daSArnaud Minier QTestState *qts = qtest_init_with_serial("-M b-l475e-iot01a", &sock_fd); 287*214652daSArnaud Minier 288*214652daSArnaud Minier init_uart(qts); 289*214652daSArnaud Minier 290*214652daSArnaud Minier usart_send_string(qts, "world"); 291*214652daSArnaud Minier g_assert_true(recv(sock_fd, s, 10, 0) == 5); 292*214652daSArnaud Minier g_assert_true(memcmp(s, "world", 5) == 0); 293*214652daSArnaud Minier 294*214652daSArnaud Minier close(sock_fd); 295*214652daSArnaud Minier 296*214652daSArnaud Minier qtest_quit(qts); 297*214652daSArnaud Minier } 298*214652daSArnaud Minier 299*214652daSArnaud Minier int main(int argc, char **argv) 300*214652daSArnaud Minier { 301*214652daSArnaud Minier int ret; 302*214652daSArnaud Minier 303*214652daSArnaud Minier g_test_init(&argc, &argv, NULL); 304*214652daSArnaud Minier g_test_set_nonfatal_assertions(); 305*214652daSArnaud Minier 306*214652daSArnaud Minier qtest_add_func("stm32l4x5/usart/write_read", test_write_read); 307*214652daSArnaud Minier qtest_add_func("stm32l4x5/usart/receive_char", test_receive_char); 308*214652daSArnaud Minier qtest_add_func("stm32l4x5/usart/send_char", test_send_char); 309*214652daSArnaud Minier qtest_add_func("stm32l4x5/usart/receive_str", test_receive_str); 310*214652daSArnaud Minier qtest_add_func("stm32l4x5/usart/send_str", test_send_str); 311*214652daSArnaud Minier ret = g_test_run(); 312*214652daSArnaud Minier 313*214652daSArnaud Minier return ret; 314*214652daSArnaud Minier } 315*214652daSArnaud Minier 316