117ff8e18SSteffen Görtz /* 217ff8e18SSteffen Görtz * QTest testcase for Microbit board using the Nordic Semiconductor nRF51 SoC. 317ff8e18SSteffen Görtz * 417ff8e18SSteffen Görtz * nRF51: 517ff8e18SSteffen Görtz * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf 617ff8e18SSteffen Görtz * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf 717ff8e18SSteffen Görtz * 817ff8e18SSteffen Görtz * Microbit Board: http://microbit.org/ 917ff8e18SSteffen Görtz * 1017ff8e18SSteffen Görtz * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de> 1117ff8e18SSteffen Görtz * 1217ff8e18SSteffen Görtz * This code is licensed under the GPL version 2 or later. See 1317ff8e18SSteffen Görtz * the COPYING file in the top-level directory. 1417ff8e18SSteffen Görtz */ 1517ff8e18SSteffen Görtz 1617ff8e18SSteffen Görtz 1717ff8e18SSteffen Görtz #include "qemu/osdep.h" 1817ff8e18SSteffen Görtz #include "exec/hwaddr.h" 19907b5105SMarc-André Lureau #include "libqtest.h" 2017ff8e18SSteffen Görtz 2117ff8e18SSteffen Görtz #include "hw/arm/nrf51.h" 2246a6603bSJulia Suvorova #include "hw/char/nrf51_uart.h" 2317ff8e18SSteffen Görtz #include "hw/gpio/nrf51_gpio.h" 247743b70fSSteffen Görtz #include "hw/nvram/nrf51_nvm.h" 257ec543e4SSteffen Görtz #include "hw/timer/nrf51_timer.h" 26b36356f6SStefan Hajnoczi #include "hw/i2c/microbit_i2c.h" 27b36356f6SStefan Hajnoczi 2846a6603bSJulia Suvorova static bool uart_wait_for_event(QTestState *qts, uint32_t event_addr) 2946a6603bSJulia Suvorova { 3046a6603bSJulia Suvorova time_t now, start = time(NULL); 3146a6603bSJulia Suvorova 3246a6603bSJulia Suvorova while (true) { 3346a6603bSJulia Suvorova if (qtest_readl(qts, event_addr) == 1) { 3446a6603bSJulia Suvorova qtest_writel(qts, event_addr, 0x00); 3546a6603bSJulia Suvorova return true; 3646a6603bSJulia Suvorova } 3746a6603bSJulia Suvorova 3846a6603bSJulia Suvorova /* Wait at most 10 minutes */ 3946a6603bSJulia Suvorova now = time(NULL); 4046a6603bSJulia Suvorova if (now - start > 600) { 4146a6603bSJulia Suvorova break; 4246a6603bSJulia Suvorova } 4346a6603bSJulia Suvorova g_usleep(10000); 4446a6603bSJulia Suvorova } 4546a6603bSJulia Suvorova 4646a6603bSJulia Suvorova return false; 4746a6603bSJulia Suvorova } 4846a6603bSJulia Suvorova 4946a6603bSJulia Suvorova static void uart_rw_to_rxd(QTestState *qts, int sock_fd, const char *in, 5046a6603bSJulia Suvorova char *out) 5146a6603bSJulia Suvorova { 5246a6603bSJulia Suvorova int i, in_len = strlen(in); 5346a6603bSJulia Suvorova 54e6f59e4cSBin Meng g_assert_true(send(sock_fd, in, in_len, 0) == in_len); 5546a6603bSJulia Suvorova for (i = 0; i < in_len; i++) { 5646a6603bSJulia Suvorova g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE + 5746a6603bSJulia Suvorova A_UART_RXDRDY)); 5846a6603bSJulia Suvorova out[i] = qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD); 5946a6603bSJulia Suvorova } 6046a6603bSJulia Suvorova out[i] = '\0'; 6146a6603bSJulia Suvorova } 6246a6603bSJulia Suvorova 6346a6603bSJulia Suvorova static void uart_w_to_txd(QTestState *qts, const char *in) 6446a6603bSJulia Suvorova { 6546a6603bSJulia Suvorova int i, in_len = strlen(in); 6646a6603bSJulia Suvorova 6746a6603bSJulia Suvorova for (i = 0; i < in_len; i++) { 6846a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_TXD, in[i]); 6946a6603bSJulia Suvorova g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE + 7046a6603bSJulia Suvorova A_UART_TXDRDY)); 7146a6603bSJulia Suvorova } 7246a6603bSJulia Suvorova } 7346a6603bSJulia Suvorova 7446a6603bSJulia Suvorova static void test_nrf51_uart(void) 7546a6603bSJulia Suvorova { 7646a6603bSJulia Suvorova int sock_fd; 7746a6603bSJulia Suvorova char s[10]; 7846a6603bSJulia Suvorova QTestState *qts = qtest_init_with_serial("-M microbit", &sock_fd); 7946a6603bSJulia Suvorova 80e6f59e4cSBin Meng g_assert_true(send(sock_fd, "c", 1, 0) == 1); 8146a6603bSJulia Suvorova g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD), ==, 0x00); 8246a6603bSJulia Suvorova 8346a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_ENABLE, 0x04); 8446a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTRX, 0x01); 8546a6603bSJulia Suvorova 8646a6603bSJulia Suvorova g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE + A_UART_RXDRDY)); 8746a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_RXDRDY, 0x00); 8846a6603bSJulia Suvorova g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD), ==, 'c'); 8946a6603bSJulia Suvorova 9046a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_INTENSET, 0x04); 9146a6603bSJulia Suvorova g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_INTEN), ==, 0x04); 9246a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_INTENCLR, 0x04); 9346a6603bSJulia Suvorova g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_INTEN), ==, 0x00); 9446a6603bSJulia Suvorova 9546a6603bSJulia Suvorova uart_rw_to_rxd(qts, sock_fd, "hello", s); 9646a6603bSJulia Suvorova g_assert_true(memcmp(s, "hello", 5) == 0); 9746a6603bSJulia Suvorova 9846a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTTX, 0x01); 9946a6603bSJulia Suvorova uart_w_to_txd(qts, "d"); 100e6f59e4cSBin Meng g_assert_true(recv(sock_fd, s, 10, 0) == 1); 10146a6603bSJulia Suvorova g_assert_cmphex(s[0], ==, 'd'); 10246a6603bSJulia Suvorova 10346a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_SUSPEND, 0x01); 10446a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_TXD, 'h'); 10546a6603bSJulia Suvorova qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTTX, 0x01); 10646a6603bSJulia Suvorova uart_w_to_txd(qts, "world"); 107e6f59e4cSBin Meng g_assert_true(recv(sock_fd, s, 10, 0) == 5); 10846a6603bSJulia Suvorova g_assert_true(memcmp(s, "world", 5) == 0); 10946a6603bSJulia Suvorova 110*25657fc6SMarc-André Lureau close(sock_fd); 11146a6603bSJulia Suvorova 11246a6603bSJulia Suvorova qtest_quit(qts); 11346a6603bSJulia Suvorova } 11446a6603bSJulia Suvorova 115b36356f6SStefan Hajnoczi /* Read a byte from I2C device at @addr from register @reg */ 1167cf19e73SJulia Suvorova static uint32_t i2c_read_byte(QTestState *qts, uint32_t addr, uint32_t reg) 117b36356f6SStefan Hajnoczi { 118b36356f6SStefan Hajnoczi uint32_t val; 119b36356f6SStefan Hajnoczi 1207cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_ADDRESS, addr); 1217cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STARTTX, 1); 1227cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_TXD, reg); 1237cf19e73SJulia Suvorova val = qtest_readl(qts, NRF51_TWI_BASE + NRF51_TWI_EVENT_TXDSENT); 124b36356f6SStefan Hajnoczi g_assert_cmpuint(val, ==, 1); 1257cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STOP, 1); 126b36356f6SStefan Hajnoczi 1277cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STARTRX, 1); 1287cf19e73SJulia Suvorova val = qtest_readl(qts, NRF51_TWI_BASE + NRF51_TWI_EVENT_RXDREADY); 129b36356f6SStefan Hajnoczi g_assert_cmpuint(val, ==, 1); 1307cf19e73SJulia Suvorova val = qtest_readl(qts, NRF51_TWI_BASE + NRF51_TWI_REG_RXD); 1317cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_TASK_STOP, 1); 132b36356f6SStefan Hajnoczi 133b36356f6SStefan Hajnoczi return val; 134b36356f6SStefan Hajnoczi } 135b36356f6SStefan Hajnoczi 136b36356f6SStefan Hajnoczi static void test_microbit_i2c(void) 137b36356f6SStefan Hajnoczi { 138b36356f6SStefan Hajnoczi uint32_t val; 1397cf19e73SJulia Suvorova QTestState *qts = qtest_init("-M microbit"); 140b36356f6SStefan Hajnoczi 141b36356f6SStefan Hajnoczi /* We don't program pins/irqs but at least enable the device */ 1427cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_ENABLE, 5); 143b36356f6SStefan Hajnoczi 144b36356f6SStefan Hajnoczi /* MMA8653 magnetometer detection */ 1457cf19e73SJulia Suvorova val = i2c_read_byte(qts, 0x3A, 0x0D); 146b36356f6SStefan Hajnoczi g_assert_cmpuint(val, ==, 0x5A); 147b36356f6SStefan Hajnoczi 1487cf19e73SJulia Suvorova val = i2c_read_byte(qts, 0x3A, 0x0D); 149b36356f6SStefan Hajnoczi g_assert_cmpuint(val, ==, 0x5A); 150b36356f6SStefan Hajnoczi 151b36356f6SStefan Hajnoczi /* LSM303 accelerometer detection */ 1527cf19e73SJulia Suvorova val = i2c_read_byte(qts, 0x3C, 0x4F); 153b36356f6SStefan Hajnoczi g_assert_cmpuint(val, ==, 0x40); 154b36356f6SStefan Hajnoczi 1557cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TWI_BASE + NRF51_TWI_REG_ENABLE, 0); 1567cf19e73SJulia Suvorova 1577cf19e73SJulia Suvorova qtest_quit(qts); 158b36356f6SStefan Hajnoczi } 15917ff8e18SSteffen Görtz 1607743b70fSSteffen Görtz #define FLASH_SIZE (256 * NRF51_PAGE_SIZE) 1617743b70fSSteffen Görtz 1627743b70fSSteffen Görtz static void fill_and_erase(QTestState *qts, hwaddr base, hwaddr size, 1637743b70fSSteffen Görtz uint32_t address_reg) 1647743b70fSSteffen Görtz { 1657743b70fSSteffen Görtz hwaddr i; 1667743b70fSSteffen Görtz 1677743b70fSSteffen Görtz /* Erase Page */ 1687743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02); 1697743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + address_reg, base); 1707743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); 1717743b70fSSteffen Görtz 1727743b70fSSteffen Görtz /* Check memory */ 1737743b70fSSteffen Görtz for (i = 0; i < size / 4; i++) { 1747743b70fSSteffen Görtz g_assert_cmpuint(qtest_readl(qts, base + i * 4), ==, 0xFFFFFFFF); 1757743b70fSSteffen Görtz } 1767743b70fSSteffen Görtz 1777743b70fSSteffen Görtz /* Fill memory */ 1787743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01); 1797743b70fSSteffen Görtz for (i = 0; i < size / 4; i++) { 1807743b70fSSteffen Görtz qtest_writel(qts, base + i * 4, i); 1817743b70fSSteffen Görtz g_assert_cmpuint(qtest_readl(qts, base + i * 4), ==, i); 1827743b70fSSteffen Görtz } 1837743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); 1847743b70fSSteffen Görtz } 1857743b70fSSteffen Görtz 1867743b70fSSteffen Görtz static void test_nrf51_nvmc(void) 1877743b70fSSteffen Görtz { 1887743b70fSSteffen Görtz uint32_t value; 1897743b70fSSteffen Görtz hwaddr i; 1907743b70fSSteffen Görtz QTestState *qts = qtest_init("-M microbit"); 1917743b70fSSteffen Görtz 1927743b70fSSteffen Görtz /* Test always ready */ 1937743b70fSSteffen Görtz value = qtest_readl(qts, NRF51_NVMC_BASE + NRF51_NVMC_READY); 1947743b70fSSteffen Görtz g_assert_cmpuint(value & 0x01, ==, 0x01); 1957743b70fSSteffen Görtz 1967743b70fSSteffen Görtz /* Test write-read config register */ 1977743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x03); 1987743b70fSSteffen Görtz g_assert_cmpuint(qtest_readl(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG), 1997743b70fSSteffen Görtz ==, 0x03); 2007743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); 2017743b70fSSteffen Görtz g_assert_cmpuint(qtest_readl(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG), 2027743b70fSSteffen Görtz ==, 0x00); 2037743b70fSSteffen Görtz 2047743b70fSSteffen Görtz /* Test PCR0 */ 2057743b70fSSteffen Görtz fill_and_erase(qts, NRF51_FLASH_BASE, NRF51_PAGE_SIZE, 2067743b70fSSteffen Görtz NRF51_NVMC_ERASEPCR0); 2077743b70fSSteffen Görtz fill_and_erase(qts, NRF51_FLASH_BASE + NRF51_PAGE_SIZE, 2087743b70fSSteffen Görtz NRF51_PAGE_SIZE, NRF51_NVMC_ERASEPCR0); 2097743b70fSSteffen Görtz 2107743b70fSSteffen Görtz /* Test PCR1 */ 2117743b70fSSteffen Görtz fill_and_erase(qts, NRF51_FLASH_BASE, NRF51_PAGE_SIZE, 2127743b70fSSteffen Görtz NRF51_NVMC_ERASEPCR1); 2137743b70fSSteffen Görtz fill_and_erase(qts, NRF51_FLASH_BASE + NRF51_PAGE_SIZE, 2147743b70fSSteffen Görtz NRF51_PAGE_SIZE, NRF51_NVMC_ERASEPCR1); 2157743b70fSSteffen Görtz 2167743b70fSSteffen Görtz /* Erase all */ 2177743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02); 2187743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEALL, 0x01); 2197743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); 2207743b70fSSteffen Görtz 2217743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01); 2227743b70fSSteffen Görtz for (i = 0; i < FLASH_SIZE / 4; i++) { 2237743b70fSSteffen Görtz qtest_writel(qts, NRF51_FLASH_BASE + i * 4, i); 2247743b70fSSteffen Görtz g_assert_cmpuint(qtest_readl(qts, NRF51_FLASH_BASE + i * 4), ==, i); 2257743b70fSSteffen Görtz } 2267743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); 2277743b70fSSteffen Görtz 2287743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02); 2297743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEALL, 0x01); 2307743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); 2317743b70fSSteffen Görtz 2327743b70fSSteffen Görtz for (i = 0; i < FLASH_SIZE / 4; i++) { 2337743b70fSSteffen Görtz g_assert_cmpuint(qtest_readl(qts, NRF51_FLASH_BASE + i * 4), 2347743b70fSSteffen Görtz ==, 0xFFFFFFFF); 2357743b70fSSteffen Görtz } 2367743b70fSSteffen Görtz 2377743b70fSSteffen Görtz /* Erase UICR */ 2387743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02); 2397743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEUICR, 0x01); 2407743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); 2417743b70fSSteffen Görtz 2427743b70fSSteffen Görtz for (i = 0; i < NRF51_UICR_SIZE / 4; i++) { 2437743b70fSSteffen Görtz g_assert_cmpuint(qtest_readl(qts, NRF51_UICR_BASE + i * 4), 2447743b70fSSteffen Görtz ==, 0xFFFFFFFF); 2457743b70fSSteffen Görtz } 2467743b70fSSteffen Görtz 2477743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x01); 2487743b70fSSteffen Görtz for (i = 0; i < NRF51_UICR_SIZE / 4; i++) { 2497743b70fSSteffen Görtz qtest_writel(qts, NRF51_UICR_BASE + i * 4, i); 2507743b70fSSteffen Görtz g_assert_cmpuint(qtest_readl(qts, NRF51_UICR_BASE + i * 4), ==, i); 2517743b70fSSteffen Görtz } 2527743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); 2537743b70fSSteffen Görtz 2547743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x02); 2557743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_ERASEUICR, 0x01); 2567743b70fSSteffen Görtz qtest_writel(qts, NRF51_NVMC_BASE + NRF51_NVMC_CONFIG, 0x00); 2577743b70fSSteffen Görtz 2587743b70fSSteffen Görtz for (i = 0; i < NRF51_UICR_SIZE / 4; i++) { 2597743b70fSSteffen Görtz g_assert_cmpuint(qtest_readl(qts, NRF51_UICR_BASE + i * 4), 2607743b70fSSteffen Görtz ==, 0xFFFFFFFF); 2617743b70fSSteffen Görtz } 2627743b70fSSteffen Görtz 2637743b70fSSteffen Görtz qtest_quit(qts); 2647743b70fSSteffen Görtz } 2657743b70fSSteffen Görtz 26617ff8e18SSteffen Görtz static void test_nrf51_gpio(void) 26717ff8e18SSteffen Görtz { 26817ff8e18SSteffen Görtz size_t i; 26917ff8e18SSteffen Görtz uint32_t actual, expected; 27017ff8e18SSteffen Görtz 27117ff8e18SSteffen Görtz struct { 27217ff8e18SSteffen Görtz hwaddr addr; 27317ff8e18SSteffen Görtz uint32_t expected; 27417ff8e18SSteffen Görtz } const reset_state[] = { 27517ff8e18SSteffen Görtz {NRF51_GPIO_REG_OUT, 0x00000000}, {NRF51_GPIO_REG_OUTSET, 0x00000000}, 27617ff8e18SSteffen Görtz {NRF51_GPIO_REG_OUTCLR, 0x00000000}, {NRF51_GPIO_REG_IN, 0x00000000}, 27717ff8e18SSteffen Görtz {NRF51_GPIO_REG_DIR, 0x00000000}, {NRF51_GPIO_REG_DIRSET, 0x00000000}, 27817ff8e18SSteffen Görtz {NRF51_GPIO_REG_DIRCLR, 0x00000000} 27917ff8e18SSteffen Görtz }; 28017ff8e18SSteffen Görtz 2817cf19e73SJulia Suvorova QTestState *qts = qtest_init("-M microbit"); 2827cf19e73SJulia Suvorova 28317ff8e18SSteffen Görtz /* Check reset state */ 28417ff8e18SSteffen Görtz for (i = 0; i < ARRAY_SIZE(reset_state); i++) { 28517ff8e18SSteffen Görtz expected = reset_state[i].expected; 2867cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + reset_state[i].addr); 28717ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, expected); 28817ff8e18SSteffen Görtz } 28917ff8e18SSteffen Görtz 29017ff8e18SSteffen Görtz for (i = 0; i < NRF51_GPIO_PINS; i++) { 29117ff8e18SSteffen Görtz expected = 0x00000002; 2927cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + 2937cf19e73SJulia Suvorova NRF51_GPIO_REG_CNF_START + i * 4); 29417ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, expected); 29517ff8e18SSteffen Görtz } 29617ff8e18SSteffen Görtz 29717ff8e18SSteffen Görtz /* Check dir bit consistency between dir and cnf */ 29817ff8e18SSteffen Görtz /* Check set via DIRSET */ 29917ff8e18SSteffen Görtz expected = 0x80000001; 3007cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRSET, expected); 3017cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR); 30217ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, expected); 3037cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) 3047cf19e73SJulia Suvorova & 0x01; 30517ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x01); 3067cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01; 30717ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x01); 30817ff8e18SSteffen Görtz 30917ff8e18SSteffen Görtz /* Check clear via DIRCLR */ 3107cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRCLR, 0x80000001); 3117cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR); 31217ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x00000000); 3137cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) 3147cf19e73SJulia Suvorova & 0x01; 31517ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x00); 3167cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01; 31717ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x00); 31817ff8e18SSteffen Görtz 31917ff8e18SSteffen Görtz /* Check set via DIR */ 32017ff8e18SSteffen Görtz expected = 0x80000001; 3217cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, expected); 3227cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR); 32317ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, expected); 3247cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) 3257cf19e73SJulia Suvorova & 0x01; 32617ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x01); 3277cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01; 32817ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x01); 32917ff8e18SSteffen Görtz 33017ff8e18SSteffen Görtz /* Reset DIR */ 3317cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, 0x00000000); 33217ff8e18SSteffen Görtz 33317ff8e18SSteffen Görtz /* Check Input propagates */ 3347cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x00); 3357cf19e73SJulia Suvorova qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0); 3367cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; 33717ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x00); 3387cf19e73SJulia Suvorova qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 1); 3397cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; 34017ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x01); 3417cf19e73SJulia Suvorova qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, -1); 3427cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; 34317ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x01); 3447cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02); 34517ff8e18SSteffen Görtz 34617ff8e18SSteffen Görtz /* Check pull-up working */ 3477cf19e73SJulia Suvorova qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0); 3487cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000); 3497cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; 35017ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x00); 3517cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b1110); 3527cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; 35317ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x01); 3547cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02); 35517ff8e18SSteffen Görtz 35617ff8e18SSteffen Görtz /* Check pull-down working */ 3577cf19e73SJulia Suvorova qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 1); 3587cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000); 3597cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; 36017ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x01); 3617cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0110); 3627cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; 36317ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x00); 3647cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02); 3657cf19e73SJulia Suvorova qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, -1); 36617ff8e18SSteffen Görtz 36717ff8e18SSteffen Görtz /* Check Output propagates */ 3687cf19e73SJulia Suvorova qtest_irq_intercept_out(qts, "/machine/nrf51"); 3697cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0011); 3707cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01); 3717cf19e73SJulia Suvorova g_assert_true(qtest_get_irq(qts, 0)); 3727cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01); 3737cf19e73SJulia Suvorova g_assert_false(qtest_get_irq(qts, 0)); 37417ff8e18SSteffen Görtz 37517ff8e18SSteffen Görtz /* Check self-stimulation */ 3767cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01); 3777cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01); 3787cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; 37917ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x01); 38017ff8e18SSteffen Görtz 3817cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01); 3827cf19e73SJulia Suvorova actual = qtest_readl(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01; 38317ff8e18SSteffen Görtz g_assert_cmpuint(actual, ==, 0x00); 38417ff8e18SSteffen Görtz 38517ff8e18SSteffen Görtz /* 38617ff8e18SSteffen Görtz * Check short-circuit - generates an guest_error which must be checked 38717ff8e18SSteffen Görtz * manually as long as qtest can not scan qemu_log messages 38817ff8e18SSteffen Görtz */ 3897cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01); 3907cf19e73SJulia Suvorova qtest_writel(qts, NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01); 3917cf19e73SJulia Suvorova qtest_set_irq_in(qts, "/machine/nrf51", "unnamed-gpio-in", 0, 0); 3927cf19e73SJulia Suvorova 3937cf19e73SJulia Suvorova qtest_quit(qts); 39417ff8e18SSteffen Görtz } 39517ff8e18SSteffen Görtz 3967cf19e73SJulia Suvorova static void timer_task(QTestState *qts, hwaddr task) 3977ec543e4SSteffen Görtz { 3987cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + task, NRF51_TRIGGER_TASK); 3997ec543e4SSteffen Görtz } 4007ec543e4SSteffen Görtz 4017cf19e73SJulia Suvorova static void timer_clear_event(QTestState *qts, hwaddr event) 4027ec543e4SSteffen Görtz { 4037cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + event, NRF51_EVENT_CLEAR); 4047ec543e4SSteffen Görtz } 4057ec543e4SSteffen Görtz 4067cf19e73SJulia Suvorova static void timer_set_bitmode(QTestState *qts, uint8_t mode) 4077ec543e4SSteffen Görtz { 4087cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_BITMODE, mode); 4097ec543e4SSteffen Görtz } 4107ec543e4SSteffen Görtz 4117cf19e73SJulia Suvorova static void timer_set_prescaler(QTestState *qts, uint8_t prescaler) 4127ec543e4SSteffen Görtz { 4137cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_PRESCALER, prescaler); 4147ec543e4SSteffen Görtz } 4157ec543e4SSteffen Görtz 4167cf19e73SJulia Suvorova static void timer_set_cc(QTestState *qts, size_t idx, uint32_t value) 4177ec543e4SSteffen Görtz { 4187cf19e73SJulia Suvorova qtest_writel(qts, NRF51_TIMER_BASE + NRF51_TIMER_REG_CC0 + idx * 4, value); 4197ec543e4SSteffen Görtz } 4207ec543e4SSteffen Görtz 4217cf19e73SJulia Suvorova static void timer_assert_events(QTestState *qts, uint32_t ev0, uint32_t ev1, 4227cf19e73SJulia Suvorova uint32_t ev2, uint32_t ev3) 4237ec543e4SSteffen Görtz { 4247cf19e73SJulia Suvorova g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_0) 4257cf19e73SJulia Suvorova == ev0); 4267cf19e73SJulia Suvorova g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_1) 4277cf19e73SJulia Suvorova == ev1); 4287cf19e73SJulia Suvorova g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_2) 4297cf19e73SJulia Suvorova == ev2); 4307cf19e73SJulia Suvorova g_assert(qtest_readl(qts, NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_3) 4317cf19e73SJulia Suvorova == ev3); 4327ec543e4SSteffen Görtz } 4337ec543e4SSteffen Görtz 4347ec543e4SSteffen Görtz static void test_nrf51_timer(void) 4357ec543e4SSteffen Görtz { 4367ec543e4SSteffen Görtz uint32_t steps_to_overflow = 408; 4377cf19e73SJulia Suvorova QTestState *qts = qtest_init("-M microbit"); 4387ec543e4SSteffen Görtz 4397ec543e4SSteffen Görtz /* Compare Match */ 4407cf19e73SJulia Suvorova timer_task(qts, NRF51_TIMER_TASK_STOP); 4417cf19e73SJulia Suvorova timer_task(qts, NRF51_TIMER_TASK_CLEAR); 4427ec543e4SSteffen Görtz 4437cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_0); 4447cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_1); 4457cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_2); 4467cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_3); 4477ec543e4SSteffen Görtz 4487cf19e73SJulia Suvorova timer_set_bitmode(qts, NRF51_TIMER_WIDTH_16); /* 16 MHz Timer */ 4497cf19e73SJulia Suvorova timer_set_prescaler(qts, 0); 4507a21bee2SDaniel P. Berrangé /* Swept over, during the first step */ 4517cf19e73SJulia Suvorova timer_set_cc(qts, 0, 2); 4527a21bee2SDaniel P. Berrangé /* Barely miss, after the second step */ 4537cf19e73SJulia Suvorova timer_set_cc(qts, 1, 162); 4547a21bee2SDaniel P. Berrangé /* Spot on, after the third step */ 4557cf19e73SJulia Suvorova timer_set_cc(qts, 2, 480); 4567ec543e4SSteffen Görtz 4577cf19e73SJulia Suvorova timer_assert_events(qts, 0, 0, 0, 0); 4587ec543e4SSteffen Görtz 4597cf19e73SJulia Suvorova timer_task(qts, NRF51_TIMER_TASK_START); 4607cf19e73SJulia Suvorova qtest_clock_step(qts, 10000); 4617cf19e73SJulia Suvorova timer_assert_events(qts, 1, 0, 0, 0); 4627ec543e4SSteffen Görtz 4637ec543e4SSteffen Görtz /* Swept over on first overflow */ 4647cf19e73SJulia Suvorova timer_set_cc(qts, 3, 114); 4657ec543e4SSteffen Görtz 4667cf19e73SJulia Suvorova qtest_clock_step(qts, 10000); 4677cf19e73SJulia Suvorova timer_assert_events(qts, 1, 1, 0, 0); 4687ec543e4SSteffen Görtz 4697cf19e73SJulia Suvorova qtest_clock_step(qts, 10000); 4707cf19e73SJulia Suvorova timer_assert_events(qts, 1, 1, 1, 0); 4717ec543e4SSteffen Görtz 4727ec543e4SSteffen Görtz /* Wrap time until internal counter overflows */ 4737ec543e4SSteffen Görtz while (steps_to_overflow--) { 4747cf19e73SJulia Suvorova timer_assert_events(qts, 1, 1, 1, 0); 4757cf19e73SJulia Suvorova qtest_clock_step(qts, 10000); 4767ec543e4SSteffen Görtz } 4777ec543e4SSteffen Görtz 4787cf19e73SJulia Suvorova timer_assert_events(qts, 1, 1, 1, 1); 4797ec543e4SSteffen Görtz 4807cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_0); 4817cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_1); 4827cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_2); 4837cf19e73SJulia Suvorova timer_clear_event(qts, NRF51_TIMER_EVENT_COMPARE_3); 4847cf19e73SJulia Suvorova timer_assert_events(qts, 0, 0, 0, 0); 4857ec543e4SSteffen Görtz 4867cf19e73SJulia Suvorova timer_task(qts, NRF51_TIMER_TASK_STOP); 4877ec543e4SSteffen Görtz 4887ec543e4SSteffen Görtz /* Test Proposal: Stop/Shutdown */ 4897ec543e4SSteffen Görtz /* Test Proposal: Shortcut Compare -> Clear */ 4907ec543e4SSteffen Görtz /* Test Proposal: Shortcut Compare -> Stop */ 4917ec543e4SSteffen Görtz /* Test Proposal: Counter Mode */ 4927cf19e73SJulia Suvorova 4937cf19e73SJulia Suvorova qtest_quit(qts); 4947ec543e4SSteffen Görtz } 4957ec543e4SSteffen Görtz 49617ff8e18SSteffen Görtz int main(int argc, char **argv) 49717ff8e18SSteffen Görtz { 49817ff8e18SSteffen Görtz g_test_init(&argc, &argv, NULL); 49917ff8e18SSteffen Görtz 50046a6603bSJulia Suvorova qtest_add_func("/microbit/nrf51/uart", test_nrf51_uart); 50117ff8e18SSteffen Görtz qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio); 5027743b70fSSteffen Görtz qtest_add_func("/microbit/nrf51/nvmc", test_nrf51_nvmc); 5037ec543e4SSteffen Görtz qtest_add_func("/microbit/nrf51/timer", test_nrf51_timer); 504b36356f6SStefan Hajnoczi qtest_add_func("/microbit/microbit/i2c", test_microbit_i2c); 50517ff8e18SSteffen Görtz 5067cf19e73SJulia Suvorova return g_test_run(); 50717ff8e18SSteffen Görtz } 508